xref: /aosp_15_r20/external/curl/lib/vtls/schannel_verify.c (revision 6236dae45794135f37c4eb022389c904c8b0090d)
1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker  *                                  _   _ ____  _
3*6236dae4SAndroid Build Coastguard Worker  *  Project                     ___| | | |  _ \| |
4*6236dae4SAndroid Build Coastguard Worker  *                             / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker  *                            | (__| |_| |  _ <| |___
6*6236dae4SAndroid Build Coastguard Worker  *                             \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker  *
8*6236dae4SAndroid Build Coastguard Worker  * Copyright (C) Marc Hoersken, <[email protected]>
9*6236dae4SAndroid Build Coastguard Worker  * Copyright (C) Mark Salisbury, <[email protected]>
10*6236dae4SAndroid Build Coastguard Worker  * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
11*6236dae4SAndroid Build Coastguard Worker  *
12*6236dae4SAndroid Build Coastguard Worker  * This software is licensed as described in the file COPYING, which
13*6236dae4SAndroid Build Coastguard Worker  * you should have received as part of this distribution. The terms
14*6236dae4SAndroid Build Coastguard Worker  * are also available at https://curl.se/docs/copyright.html.
15*6236dae4SAndroid Build Coastguard Worker  *
16*6236dae4SAndroid Build Coastguard Worker  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
17*6236dae4SAndroid Build Coastguard Worker  * copies of the Software, and permit persons to whom the Software is
18*6236dae4SAndroid Build Coastguard Worker  * furnished to do so, under the terms of the COPYING file.
19*6236dae4SAndroid Build Coastguard Worker  *
20*6236dae4SAndroid Build Coastguard Worker  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21*6236dae4SAndroid Build Coastguard Worker  * KIND, either express or implied.
22*6236dae4SAndroid Build Coastguard Worker  *
23*6236dae4SAndroid Build Coastguard Worker  * SPDX-License-Identifier: curl
24*6236dae4SAndroid Build Coastguard Worker  *
25*6236dae4SAndroid Build Coastguard Worker  ***************************************************************************/
26*6236dae4SAndroid Build Coastguard Worker 
27*6236dae4SAndroid Build Coastguard Worker /*
28*6236dae4SAndroid Build Coastguard Worker  * Source file for Schannel-specific certificate verification. This code should
29*6236dae4SAndroid Build Coastguard Worker  * only be invoked by code in schannel.c.
30*6236dae4SAndroid Build Coastguard Worker  */
31*6236dae4SAndroid Build Coastguard Worker 
32*6236dae4SAndroid Build Coastguard Worker #include "curl_setup.h"
33*6236dae4SAndroid Build Coastguard Worker 
34*6236dae4SAndroid Build Coastguard Worker #ifdef USE_SCHANNEL
35*6236dae4SAndroid Build Coastguard Worker #ifndef USE_WINDOWS_SSPI
36*6236dae4SAndroid Build Coastguard Worker #  error "cannot compile SCHANNEL support without SSPI."
37*6236dae4SAndroid Build Coastguard Worker #endif
38*6236dae4SAndroid Build Coastguard Worker 
39*6236dae4SAndroid Build Coastguard Worker #include "schannel.h"
40*6236dae4SAndroid Build Coastguard Worker #include "schannel_int.h"
41*6236dae4SAndroid Build Coastguard Worker 
42*6236dae4SAndroid Build Coastguard Worker #include "inet_pton.h"
43*6236dae4SAndroid Build Coastguard Worker #include "vtls.h"
44*6236dae4SAndroid Build Coastguard Worker #include "vtls_int.h"
45*6236dae4SAndroid Build Coastguard Worker #include "sendf.h"
46*6236dae4SAndroid Build Coastguard Worker #include "strerror.h"
47*6236dae4SAndroid Build Coastguard Worker #include "curl_multibyte.h"
48*6236dae4SAndroid Build Coastguard Worker #include "curl_printf.h"
49*6236dae4SAndroid Build Coastguard Worker #include "hostcheck.h"
50*6236dae4SAndroid Build Coastguard Worker #include "version_win32.h"
51*6236dae4SAndroid Build Coastguard Worker 
52*6236dae4SAndroid Build Coastguard Worker /* The last #include file should be: */
53*6236dae4SAndroid Build Coastguard Worker #include "curl_memory.h"
54*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h"
55*6236dae4SAndroid Build Coastguard Worker 
56*6236dae4SAndroid Build Coastguard Worker #define BACKEND ((struct schannel_ssl_backend_data *)connssl->backend)
57*6236dae4SAndroid Build Coastguard Worker 
58*6236dae4SAndroid Build Coastguard Worker #ifdef HAS_MANUAL_VERIFY_API
59*6236dae4SAndroid Build Coastguard Worker 
60*6236dae4SAndroid Build Coastguard Worker #define MAX_CAFILE_SIZE 1048576 /* 1 MiB */
61*6236dae4SAndroid Build Coastguard Worker #define BEGIN_CERT "-----BEGIN CERTIFICATE-----"
62*6236dae4SAndroid Build Coastguard Worker #define END_CERT "\n-----END CERTIFICATE-----"
63*6236dae4SAndroid Build Coastguard Worker 
64*6236dae4SAndroid Build Coastguard Worker struct cert_chain_engine_config_win7 {
65*6236dae4SAndroid Build Coastguard Worker   DWORD cbSize;
66*6236dae4SAndroid Build Coastguard Worker   HCERTSTORE hRestrictedRoot;
67*6236dae4SAndroid Build Coastguard Worker   HCERTSTORE hRestrictedTrust;
68*6236dae4SAndroid Build Coastguard Worker   HCERTSTORE hRestrictedOther;
69*6236dae4SAndroid Build Coastguard Worker   DWORD cAdditionalStore;
70*6236dae4SAndroid Build Coastguard Worker   HCERTSTORE *rghAdditionalStore;
71*6236dae4SAndroid Build Coastguard Worker   DWORD dwFlags;
72*6236dae4SAndroid Build Coastguard Worker   DWORD dwUrlRetrievalTimeout;
73*6236dae4SAndroid Build Coastguard Worker   DWORD MaximumCachedCertificates;
74*6236dae4SAndroid Build Coastguard Worker   DWORD CycleDetectionModulus;
75*6236dae4SAndroid Build Coastguard Worker   HCERTSTORE hExclusiveRoot;
76*6236dae4SAndroid Build Coastguard Worker   HCERTSTORE hExclusiveTrustedPeople;
77*6236dae4SAndroid Build Coastguard Worker };
78*6236dae4SAndroid Build Coastguard Worker 
is_cr_or_lf(char c)79*6236dae4SAndroid Build Coastguard Worker static int is_cr_or_lf(char c)
80*6236dae4SAndroid Build Coastguard Worker {
81*6236dae4SAndroid Build Coastguard Worker   return c == '\r' || c == '\n';
82*6236dae4SAndroid Build Coastguard Worker }
83*6236dae4SAndroid Build Coastguard Worker 
84*6236dae4SAndroid Build Coastguard Worker /* Search the substring needle,needlelen into string haystack,haystacklen
85*6236dae4SAndroid Build Coastguard Worker  * Strings do not need to be terminated by a '\0'.
86*6236dae4SAndroid Build Coastguard Worker  * Similar of macOS/Linux memmem (not available on Visual Studio).
87*6236dae4SAndroid Build Coastguard Worker  * Return position of beginning of first occurrence or NULL if not found
88*6236dae4SAndroid Build Coastguard Worker  */
c_memmem(const void * haystack,size_t haystacklen,const void * needle,size_t needlelen)89*6236dae4SAndroid Build Coastguard Worker static const char *c_memmem(const void *haystack, size_t haystacklen,
90*6236dae4SAndroid Build Coastguard Worker                             const void *needle, size_t needlelen)
91*6236dae4SAndroid Build Coastguard Worker {
92*6236dae4SAndroid Build Coastguard Worker   const char *p;
93*6236dae4SAndroid Build Coastguard Worker   char first;
94*6236dae4SAndroid Build Coastguard Worker   const char *str_limit = (const char *)haystack + haystacklen;
95*6236dae4SAndroid Build Coastguard Worker   if(!needlelen || needlelen > haystacklen)
96*6236dae4SAndroid Build Coastguard Worker     return NULL;
97*6236dae4SAndroid Build Coastguard Worker   first = *(const char *)needle;
98*6236dae4SAndroid Build Coastguard Worker   for(p = (const char *)haystack; p <= (str_limit - needlelen); p++)
99*6236dae4SAndroid Build Coastguard Worker     if(((*p) == first) && (memcmp(p, needle, needlelen) == 0))
100*6236dae4SAndroid Build Coastguard Worker       return p;
101*6236dae4SAndroid Build Coastguard Worker 
102*6236dae4SAndroid Build Coastguard Worker   return NULL;
103*6236dae4SAndroid Build Coastguard Worker }
104*6236dae4SAndroid Build Coastguard Worker 
add_certs_data_to_store(HCERTSTORE trust_store,const char * ca_buffer,size_t ca_buffer_size,const char * ca_file_text,struct Curl_easy * data)105*6236dae4SAndroid Build Coastguard Worker static CURLcode add_certs_data_to_store(HCERTSTORE trust_store,
106*6236dae4SAndroid Build Coastguard Worker                                         const char *ca_buffer,
107*6236dae4SAndroid Build Coastguard Worker                                         size_t ca_buffer_size,
108*6236dae4SAndroid Build Coastguard Worker                                         const char *ca_file_text,
109*6236dae4SAndroid Build Coastguard Worker                                         struct Curl_easy *data)
110*6236dae4SAndroid Build Coastguard Worker {
111*6236dae4SAndroid Build Coastguard Worker   const size_t begin_cert_len = strlen(BEGIN_CERT);
112*6236dae4SAndroid Build Coastguard Worker   const size_t end_cert_len = strlen(END_CERT);
113*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
114*6236dae4SAndroid Build Coastguard Worker   int num_certs = 0;
115*6236dae4SAndroid Build Coastguard Worker   bool more_certs = 1;
116*6236dae4SAndroid Build Coastguard Worker   const char *current_ca_file_ptr = ca_buffer;
117*6236dae4SAndroid Build Coastguard Worker   const char *ca_buffer_limit = ca_buffer + ca_buffer_size;
118*6236dae4SAndroid Build Coastguard Worker 
119*6236dae4SAndroid Build Coastguard Worker   while(more_certs && (current_ca_file_ptr < ca_buffer_limit)) {
120*6236dae4SAndroid Build Coastguard Worker     const char *begin_cert_ptr = c_memmem(current_ca_file_ptr,
121*6236dae4SAndroid Build Coastguard Worker                                           ca_buffer_limit-current_ca_file_ptr,
122*6236dae4SAndroid Build Coastguard Worker                                           BEGIN_CERT,
123*6236dae4SAndroid Build Coastguard Worker                                           begin_cert_len);
124*6236dae4SAndroid Build Coastguard Worker     if(!begin_cert_ptr || !is_cr_or_lf(begin_cert_ptr[begin_cert_len])) {
125*6236dae4SAndroid Build Coastguard Worker       more_certs = 0;
126*6236dae4SAndroid Build Coastguard Worker     }
127*6236dae4SAndroid Build Coastguard Worker     else {
128*6236dae4SAndroid Build Coastguard Worker       const char *end_cert_ptr = c_memmem(begin_cert_ptr,
129*6236dae4SAndroid Build Coastguard Worker                                           ca_buffer_limit-begin_cert_ptr,
130*6236dae4SAndroid Build Coastguard Worker                                           END_CERT,
131*6236dae4SAndroid Build Coastguard Worker                                           end_cert_len);
132*6236dae4SAndroid Build Coastguard Worker       if(!end_cert_ptr) {
133*6236dae4SAndroid Build Coastguard Worker         failf(data,
134*6236dae4SAndroid Build Coastguard Worker               "schannel: CA file '%s' is not correctly formatted",
135*6236dae4SAndroid Build Coastguard Worker               ca_file_text);
136*6236dae4SAndroid Build Coastguard Worker         result = CURLE_SSL_CACERT_BADFILE;
137*6236dae4SAndroid Build Coastguard Worker         more_certs = 0;
138*6236dae4SAndroid Build Coastguard Worker       }
139*6236dae4SAndroid Build Coastguard Worker       else {
140*6236dae4SAndroid Build Coastguard Worker         CERT_BLOB cert_blob;
141*6236dae4SAndroid Build Coastguard Worker         CERT_CONTEXT *cert_context = NULL;
142*6236dae4SAndroid Build Coastguard Worker         BOOL add_cert_result = FALSE;
143*6236dae4SAndroid Build Coastguard Worker         DWORD actual_content_type = 0;
144*6236dae4SAndroid Build Coastguard Worker         DWORD cert_size = (DWORD)
145*6236dae4SAndroid Build Coastguard Worker           ((end_cert_ptr + end_cert_len) - begin_cert_ptr);
146*6236dae4SAndroid Build Coastguard Worker 
147*6236dae4SAndroid Build Coastguard Worker         cert_blob.pbData = (BYTE *)begin_cert_ptr;
148*6236dae4SAndroid Build Coastguard Worker         cert_blob.cbData = cert_size;
149*6236dae4SAndroid Build Coastguard Worker         if(!CryptQueryObject(CERT_QUERY_OBJECT_BLOB,
150*6236dae4SAndroid Build Coastguard Worker                              &cert_blob,
151*6236dae4SAndroid Build Coastguard Worker                              CERT_QUERY_CONTENT_FLAG_CERT,
152*6236dae4SAndroid Build Coastguard Worker                              CERT_QUERY_FORMAT_FLAG_ALL,
153*6236dae4SAndroid Build Coastguard Worker                              0,
154*6236dae4SAndroid Build Coastguard Worker                              NULL,
155*6236dae4SAndroid Build Coastguard Worker                              &actual_content_type,
156*6236dae4SAndroid Build Coastguard Worker                              NULL,
157*6236dae4SAndroid Build Coastguard Worker                              NULL,
158*6236dae4SAndroid Build Coastguard Worker                              NULL,
159*6236dae4SAndroid Build Coastguard Worker                              (const void **)&cert_context)) {
160*6236dae4SAndroid Build Coastguard Worker           char buffer[STRERROR_LEN];
161*6236dae4SAndroid Build Coastguard Worker           failf(data,
162*6236dae4SAndroid Build Coastguard Worker                 "schannel: failed to extract certificate from CA file "
163*6236dae4SAndroid Build Coastguard Worker                 "'%s': %s",
164*6236dae4SAndroid Build Coastguard Worker                 ca_file_text,
165*6236dae4SAndroid Build Coastguard Worker                 Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
166*6236dae4SAndroid Build Coastguard Worker           result = CURLE_SSL_CACERT_BADFILE;
167*6236dae4SAndroid Build Coastguard Worker           more_certs = 0;
168*6236dae4SAndroid Build Coastguard Worker         }
169*6236dae4SAndroid Build Coastguard Worker         else {
170*6236dae4SAndroid Build Coastguard Worker           current_ca_file_ptr = begin_cert_ptr + cert_size;
171*6236dae4SAndroid Build Coastguard Worker 
172*6236dae4SAndroid Build Coastguard Worker           /* Sanity check that the cert_context object is the right type */
173*6236dae4SAndroid Build Coastguard Worker           if(CERT_QUERY_CONTENT_CERT != actual_content_type) {
174*6236dae4SAndroid Build Coastguard Worker             failf(data,
175*6236dae4SAndroid Build Coastguard Worker                   "schannel: unexpected content type '%lu' when extracting "
176*6236dae4SAndroid Build Coastguard Worker                   "certificate from CA file '%s'",
177*6236dae4SAndroid Build Coastguard Worker                   actual_content_type, ca_file_text);
178*6236dae4SAndroid Build Coastguard Worker             result = CURLE_SSL_CACERT_BADFILE;
179*6236dae4SAndroid Build Coastguard Worker             more_certs = 0;
180*6236dae4SAndroid Build Coastguard Worker           }
181*6236dae4SAndroid Build Coastguard Worker           else {
182*6236dae4SAndroid Build Coastguard Worker             add_cert_result =
183*6236dae4SAndroid Build Coastguard Worker               CertAddCertificateContextToStore(trust_store,
184*6236dae4SAndroid Build Coastguard Worker                                                cert_context,
185*6236dae4SAndroid Build Coastguard Worker                                                CERT_STORE_ADD_ALWAYS,
186*6236dae4SAndroid Build Coastguard Worker                                                NULL);
187*6236dae4SAndroid Build Coastguard Worker             CertFreeCertificateContext(cert_context);
188*6236dae4SAndroid Build Coastguard Worker             if(!add_cert_result) {
189*6236dae4SAndroid Build Coastguard Worker               char buffer[STRERROR_LEN];
190*6236dae4SAndroid Build Coastguard Worker               failf(data,
191*6236dae4SAndroid Build Coastguard Worker                     "schannel: failed to add certificate from CA file '%s' "
192*6236dae4SAndroid Build Coastguard Worker                     "to certificate store: %s",
193*6236dae4SAndroid Build Coastguard Worker                     ca_file_text,
194*6236dae4SAndroid Build Coastguard Worker                     Curl_winapi_strerror(GetLastError(), buffer,
195*6236dae4SAndroid Build Coastguard Worker                                          sizeof(buffer)));
196*6236dae4SAndroid Build Coastguard Worker               result = CURLE_SSL_CACERT_BADFILE;
197*6236dae4SAndroid Build Coastguard Worker               more_certs = 0;
198*6236dae4SAndroid Build Coastguard Worker             }
199*6236dae4SAndroid Build Coastguard Worker             else {
200*6236dae4SAndroid Build Coastguard Worker               num_certs++;
201*6236dae4SAndroid Build Coastguard Worker             }
202*6236dae4SAndroid Build Coastguard Worker           }
203*6236dae4SAndroid Build Coastguard Worker         }
204*6236dae4SAndroid Build Coastguard Worker       }
205*6236dae4SAndroid Build Coastguard Worker     }
206*6236dae4SAndroid Build Coastguard Worker   }
207*6236dae4SAndroid Build Coastguard Worker 
208*6236dae4SAndroid Build Coastguard Worker   if(result == CURLE_OK) {
209*6236dae4SAndroid Build Coastguard Worker     if(!num_certs) {
210*6236dae4SAndroid Build Coastguard Worker       infof(data,
211*6236dae4SAndroid Build Coastguard Worker             "schannel: did not add any certificates from CA file '%s'",
212*6236dae4SAndroid Build Coastguard Worker             ca_file_text);
213*6236dae4SAndroid Build Coastguard Worker     }
214*6236dae4SAndroid Build Coastguard Worker     else {
215*6236dae4SAndroid Build Coastguard Worker       infof(data,
216*6236dae4SAndroid Build Coastguard Worker             "schannel: added %d certificate(s) from CA file '%s'",
217*6236dae4SAndroid Build Coastguard Worker             num_certs, ca_file_text);
218*6236dae4SAndroid Build Coastguard Worker     }
219*6236dae4SAndroid Build Coastguard Worker   }
220*6236dae4SAndroid Build Coastguard Worker   return result;
221*6236dae4SAndroid Build Coastguard Worker }
222*6236dae4SAndroid Build Coastguard Worker 
add_certs_file_to_store(HCERTSTORE trust_store,const char * ca_file,struct Curl_easy * data)223*6236dae4SAndroid Build Coastguard Worker static CURLcode add_certs_file_to_store(HCERTSTORE trust_store,
224*6236dae4SAndroid Build Coastguard Worker                                         const char *ca_file,
225*6236dae4SAndroid Build Coastguard Worker                                         struct Curl_easy *data)
226*6236dae4SAndroid Build Coastguard Worker {
227*6236dae4SAndroid Build Coastguard Worker   CURLcode result;
228*6236dae4SAndroid Build Coastguard Worker   HANDLE ca_file_handle = INVALID_HANDLE_VALUE;
229*6236dae4SAndroid Build Coastguard Worker   LARGE_INTEGER file_size;
230*6236dae4SAndroid Build Coastguard Worker   char *ca_file_buffer = NULL;
231*6236dae4SAndroid Build Coastguard Worker   TCHAR *ca_file_tstr = NULL;
232*6236dae4SAndroid Build Coastguard Worker   size_t ca_file_bufsize = 0;
233*6236dae4SAndroid Build Coastguard Worker   DWORD total_bytes_read = 0;
234*6236dae4SAndroid Build Coastguard Worker 
235*6236dae4SAndroid Build Coastguard Worker   ca_file_tstr = curlx_convert_UTF8_to_tchar((char *)ca_file);
236*6236dae4SAndroid Build Coastguard Worker   if(!ca_file_tstr) {
237*6236dae4SAndroid Build Coastguard Worker     char buffer[STRERROR_LEN];
238*6236dae4SAndroid Build Coastguard Worker     failf(data,
239*6236dae4SAndroid Build Coastguard Worker           "schannel: invalid path name for CA file '%s': %s",
240*6236dae4SAndroid Build Coastguard Worker           ca_file,
241*6236dae4SAndroid Build Coastguard Worker           Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
242*6236dae4SAndroid Build Coastguard Worker     result = CURLE_SSL_CACERT_BADFILE;
243*6236dae4SAndroid Build Coastguard Worker     goto cleanup;
244*6236dae4SAndroid Build Coastguard Worker   }
245*6236dae4SAndroid Build Coastguard Worker 
246*6236dae4SAndroid Build Coastguard Worker   /*
247*6236dae4SAndroid Build Coastguard Worker    * Read the CA file completely into memory before parsing it. This
248*6236dae4SAndroid Build Coastguard Worker    * optimizes for the common case where the CA file will be relatively
249*6236dae4SAndroid Build Coastguard Worker    * small ( < 1 MiB ).
250*6236dae4SAndroid Build Coastguard Worker    */
251*6236dae4SAndroid Build Coastguard Worker   ca_file_handle = CreateFile(ca_file_tstr,
252*6236dae4SAndroid Build Coastguard Worker                               GENERIC_READ,
253*6236dae4SAndroid Build Coastguard Worker                               FILE_SHARE_READ,
254*6236dae4SAndroid Build Coastguard Worker                               NULL,
255*6236dae4SAndroid Build Coastguard Worker                               OPEN_EXISTING,
256*6236dae4SAndroid Build Coastguard Worker                               FILE_ATTRIBUTE_NORMAL,
257*6236dae4SAndroid Build Coastguard Worker                               NULL);
258*6236dae4SAndroid Build Coastguard Worker   if(ca_file_handle == INVALID_HANDLE_VALUE) {
259*6236dae4SAndroid Build Coastguard Worker     char buffer[STRERROR_LEN];
260*6236dae4SAndroid Build Coastguard Worker     failf(data,
261*6236dae4SAndroid Build Coastguard Worker           "schannel: failed to open CA file '%s': %s",
262*6236dae4SAndroid Build Coastguard Worker           ca_file,
263*6236dae4SAndroid Build Coastguard Worker           Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
264*6236dae4SAndroid Build Coastguard Worker     result = CURLE_SSL_CACERT_BADFILE;
265*6236dae4SAndroid Build Coastguard Worker     goto cleanup;
266*6236dae4SAndroid Build Coastguard Worker   }
267*6236dae4SAndroid Build Coastguard Worker 
268*6236dae4SAndroid Build Coastguard Worker   if(!GetFileSizeEx(ca_file_handle, &file_size)) {
269*6236dae4SAndroid Build Coastguard Worker     char buffer[STRERROR_LEN];
270*6236dae4SAndroid Build Coastguard Worker     failf(data,
271*6236dae4SAndroid Build Coastguard Worker           "schannel: failed to determine size of CA file '%s': %s",
272*6236dae4SAndroid Build Coastguard Worker           ca_file,
273*6236dae4SAndroid Build Coastguard Worker           Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
274*6236dae4SAndroid Build Coastguard Worker     result = CURLE_SSL_CACERT_BADFILE;
275*6236dae4SAndroid Build Coastguard Worker     goto cleanup;
276*6236dae4SAndroid Build Coastguard Worker   }
277*6236dae4SAndroid Build Coastguard Worker 
278*6236dae4SAndroid Build Coastguard Worker   if(file_size.QuadPart > MAX_CAFILE_SIZE) {
279*6236dae4SAndroid Build Coastguard Worker     failf(data,
280*6236dae4SAndroid Build Coastguard Worker           "schannel: CA file exceeds max size of %u bytes",
281*6236dae4SAndroid Build Coastguard Worker           MAX_CAFILE_SIZE);
282*6236dae4SAndroid Build Coastguard Worker     result = CURLE_SSL_CACERT_BADFILE;
283*6236dae4SAndroid Build Coastguard Worker     goto cleanup;
284*6236dae4SAndroid Build Coastguard Worker   }
285*6236dae4SAndroid Build Coastguard Worker 
286*6236dae4SAndroid Build Coastguard Worker   ca_file_bufsize = (size_t)file_size.QuadPart;
287*6236dae4SAndroid Build Coastguard Worker   ca_file_buffer = (char *)malloc(ca_file_bufsize + 1);
288*6236dae4SAndroid Build Coastguard Worker   if(!ca_file_buffer) {
289*6236dae4SAndroid Build Coastguard Worker     result = CURLE_OUT_OF_MEMORY;
290*6236dae4SAndroid Build Coastguard Worker     goto cleanup;
291*6236dae4SAndroid Build Coastguard Worker   }
292*6236dae4SAndroid Build Coastguard Worker 
293*6236dae4SAndroid Build Coastguard Worker   while(total_bytes_read < ca_file_bufsize) {
294*6236dae4SAndroid Build Coastguard Worker     DWORD bytes_to_read = (DWORD)(ca_file_bufsize - total_bytes_read);
295*6236dae4SAndroid Build Coastguard Worker     DWORD bytes_read = 0;
296*6236dae4SAndroid Build Coastguard Worker 
297*6236dae4SAndroid Build Coastguard Worker     if(!ReadFile(ca_file_handle, ca_file_buffer + total_bytes_read,
298*6236dae4SAndroid Build Coastguard Worker                  bytes_to_read, &bytes_read, NULL)) {
299*6236dae4SAndroid Build Coastguard Worker       char buffer[STRERROR_LEN];
300*6236dae4SAndroid Build Coastguard Worker       failf(data,
301*6236dae4SAndroid Build Coastguard Worker             "schannel: failed to read from CA file '%s': %s",
302*6236dae4SAndroid Build Coastguard Worker             ca_file,
303*6236dae4SAndroid Build Coastguard Worker             Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
304*6236dae4SAndroid Build Coastguard Worker       result = CURLE_SSL_CACERT_BADFILE;
305*6236dae4SAndroid Build Coastguard Worker       goto cleanup;
306*6236dae4SAndroid Build Coastguard Worker     }
307*6236dae4SAndroid Build Coastguard Worker     if(bytes_read == 0) {
308*6236dae4SAndroid Build Coastguard Worker       /* Premature EOF -- adjust the bufsize to the new value */
309*6236dae4SAndroid Build Coastguard Worker       ca_file_bufsize = total_bytes_read;
310*6236dae4SAndroid Build Coastguard Worker     }
311*6236dae4SAndroid Build Coastguard Worker     else {
312*6236dae4SAndroid Build Coastguard Worker       total_bytes_read += bytes_read;
313*6236dae4SAndroid Build Coastguard Worker     }
314*6236dae4SAndroid Build Coastguard Worker   }
315*6236dae4SAndroid Build Coastguard Worker 
316*6236dae4SAndroid Build Coastguard Worker   /* Null terminate the buffer */
317*6236dae4SAndroid Build Coastguard Worker   ca_file_buffer[ca_file_bufsize] = '\0';
318*6236dae4SAndroid Build Coastguard Worker 
319*6236dae4SAndroid Build Coastguard Worker   result = add_certs_data_to_store(trust_store,
320*6236dae4SAndroid Build Coastguard Worker                                    ca_file_buffer, ca_file_bufsize,
321*6236dae4SAndroid Build Coastguard Worker                                    ca_file,
322*6236dae4SAndroid Build Coastguard Worker                                    data);
323*6236dae4SAndroid Build Coastguard Worker 
324*6236dae4SAndroid Build Coastguard Worker cleanup:
325*6236dae4SAndroid Build Coastguard Worker   if(ca_file_handle != INVALID_HANDLE_VALUE) {
326*6236dae4SAndroid Build Coastguard Worker     CloseHandle(ca_file_handle);
327*6236dae4SAndroid Build Coastguard Worker   }
328*6236dae4SAndroid Build Coastguard Worker   Curl_safefree(ca_file_buffer);
329*6236dae4SAndroid Build Coastguard Worker   curlx_unicodefree(ca_file_tstr);
330*6236dae4SAndroid Build Coastguard Worker 
331*6236dae4SAndroid Build Coastguard Worker   return result;
332*6236dae4SAndroid Build Coastguard Worker }
333*6236dae4SAndroid Build Coastguard Worker 
334*6236dae4SAndroid Build Coastguard Worker #endif /* HAS_MANUAL_VERIFY_API */
335*6236dae4SAndroid Build Coastguard Worker 
336*6236dae4SAndroid Build Coastguard Worker /*
337*6236dae4SAndroid Build Coastguard Worker  * Returns the number of characters necessary to populate all the host_names.
338*6236dae4SAndroid Build Coastguard Worker  * If host_names is not NULL, populate it with all the hostnames. Each string
339*6236dae4SAndroid Build Coastguard Worker  * in the host_names is null-terminated and the last string is double
340*6236dae4SAndroid Build Coastguard Worker  * null-terminated. If no DNS names are found, a single null-terminated empty
341*6236dae4SAndroid Build Coastguard Worker  * string is returned.
342*6236dae4SAndroid Build Coastguard Worker  */
cert_get_name_string(struct Curl_easy * data,CERT_CONTEXT * cert_context,LPTSTR host_names,DWORD length,PCERT_ALT_NAME_INFO alt_name_info,BOOL Win8_compat)343*6236dae4SAndroid Build Coastguard Worker static DWORD cert_get_name_string(struct Curl_easy *data,
344*6236dae4SAndroid Build Coastguard Worker                                   CERT_CONTEXT *cert_context,
345*6236dae4SAndroid Build Coastguard Worker                                   LPTSTR host_names,
346*6236dae4SAndroid Build Coastguard Worker                                   DWORD length,
347*6236dae4SAndroid Build Coastguard Worker                                   PCERT_ALT_NAME_INFO alt_name_info,
348*6236dae4SAndroid Build Coastguard Worker                                   BOOL Win8_compat)
349*6236dae4SAndroid Build Coastguard Worker {
350*6236dae4SAndroid Build Coastguard Worker   DWORD actual_length = 0;
351*6236dae4SAndroid Build Coastguard Worker #if defined(CURL_WINDOWS_UWP)
352*6236dae4SAndroid Build Coastguard Worker   (void)data;
353*6236dae4SAndroid Build Coastguard Worker   (void)cert_context;
354*6236dae4SAndroid Build Coastguard Worker   (void)host_names;
355*6236dae4SAndroid Build Coastguard Worker   (void)length;
356*6236dae4SAndroid Build Coastguard Worker   (void)alt_name_info;
357*6236dae4SAndroid Build Coastguard Worker   (void)Win8_compat;
358*6236dae4SAndroid Build Coastguard Worker #else
359*6236dae4SAndroid Build Coastguard Worker   BOOL compute_content = FALSE;
360*6236dae4SAndroid Build Coastguard Worker   LPTSTR current_pos = NULL;
361*6236dae4SAndroid Build Coastguard Worker   DWORD i;
362*6236dae4SAndroid Build Coastguard Worker 
363*6236dae4SAndroid Build Coastguard Worker #ifdef CERT_NAME_SEARCH_ALL_NAMES_FLAG
364*6236dae4SAndroid Build Coastguard Worker   /* CERT_NAME_SEARCH_ALL_NAMES_FLAG is available from Windows 8 onwards. */
365*6236dae4SAndroid Build Coastguard Worker   if(Win8_compat) {
366*6236dae4SAndroid Build Coastguard Worker     /* CertGetNameString will provide the 8-bit character string without
367*6236dae4SAndroid Build Coastguard Worker      * any decoding */
368*6236dae4SAndroid Build Coastguard Worker     DWORD name_flags =
369*6236dae4SAndroid Build Coastguard Worker       CERT_NAME_DISABLE_IE4_UTF8_FLAG | CERT_NAME_SEARCH_ALL_NAMES_FLAG;
370*6236dae4SAndroid Build Coastguard Worker     actual_length = CertGetNameString(cert_context,
371*6236dae4SAndroid Build Coastguard Worker                                       CERT_NAME_DNS_TYPE,
372*6236dae4SAndroid Build Coastguard Worker                                       name_flags,
373*6236dae4SAndroid Build Coastguard Worker                                       NULL,
374*6236dae4SAndroid Build Coastguard Worker                                       host_names,
375*6236dae4SAndroid Build Coastguard Worker                                       length);
376*6236dae4SAndroid Build Coastguard Worker     return actual_length;
377*6236dae4SAndroid Build Coastguard Worker   }
378*6236dae4SAndroid Build Coastguard Worker #else
379*6236dae4SAndroid Build Coastguard Worker   (void)cert_context;
380*6236dae4SAndroid Build Coastguard Worker   (void)Win8_compat;
381*6236dae4SAndroid Build Coastguard Worker #endif
382*6236dae4SAndroid Build Coastguard Worker 
383*6236dae4SAndroid Build Coastguard Worker   compute_content = host_names != NULL && length != 0;
384*6236dae4SAndroid Build Coastguard Worker 
385*6236dae4SAndroid Build Coastguard Worker   /* Initialize default return values. */
386*6236dae4SAndroid Build Coastguard Worker   actual_length = 1;
387*6236dae4SAndroid Build Coastguard Worker   if(compute_content) {
388*6236dae4SAndroid Build Coastguard Worker     *host_names = '\0';
389*6236dae4SAndroid Build Coastguard Worker   }
390*6236dae4SAndroid Build Coastguard Worker 
391*6236dae4SAndroid Build Coastguard Worker   current_pos = host_names;
392*6236dae4SAndroid Build Coastguard Worker 
393*6236dae4SAndroid Build Coastguard Worker   /* Iterate over the alternate names and populate host_names. */
394*6236dae4SAndroid Build Coastguard Worker   for(i = 0; i < alt_name_info->cAltEntry; i++) {
395*6236dae4SAndroid Build Coastguard Worker     const CERT_ALT_NAME_ENTRY *entry = &alt_name_info->rgAltEntry[i];
396*6236dae4SAndroid Build Coastguard Worker     wchar_t *dns_w = NULL;
397*6236dae4SAndroid Build Coastguard Worker     size_t current_length = 0;
398*6236dae4SAndroid Build Coastguard Worker 
399*6236dae4SAndroid Build Coastguard Worker     if(entry->dwAltNameChoice != CERT_ALT_NAME_DNS_NAME) {
400*6236dae4SAndroid Build Coastguard Worker       continue;
401*6236dae4SAndroid Build Coastguard Worker     }
402*6236dae4SAndroid Build Coastguard Worker     if(!entry->pwszDNSName) {
403*6236dae4SAndroid Build Coastguard Worker       infof(data, "schannel: Empty DNS name.");
404*6236dae4SAndroid Build Coastguard Worker       continue;
405*6236dae4SAndroid Build Coastguard Worker     }
406*6236dae4SAndroid Build Coastguard Worker     current_length = wcslen(entry->pwszDNSName) + 1;
407*6236dae4SAndroid Build Coastguard Worker     if(!compute_content) {
408*6236dae4SAndroid Build Coastguard Worker       actual_length += (DWORD)current_length;
409*6236dae4SAndroid Build Coastguard Worker       continue;
410*6236dae4SAndroid Build Coastguard Worker     }
411*6236dae4SAndroid Build Coastguard Worker     /* Sanity check to prevent buffer overrun. */
412*6236dae4SAndroid Build Coastguard Worker     if((actual_length + current_length) > length) {
413*6236dae4SAndroid Build Coastguard Worker       failf(data, "schannel: Not enough memory to list all hostnames.");
414*6236dae4SAndroid Build Coastguard Worker       break;
415*6236dae4SAndroid Build Coastguard Worker     }
416*6236dae4SAndroid Build Coastguard Worker     dns_w = entry->pwszDNSName;
417*6236dae4SAndroid Build Coastguard Worker     /* pwszDNSName is in ia5 string format and hence does not contain any
418*6236dae4SAndroid Build Coastguard Worker      * non-ASCII characters. */
419*6236dae4SAndroid Build Coastguard Worker     while(*dns_w != '\0') {
420*6236dae4SAndroid Build Coastguard Worker       *current_pos++ = (TCHAR)(*dns_w++);
421*6236dae4SAndroid Build Coastguard Worker     }
422*6236dae4SAndroid Build Coastguard Worker     *current_pos++ = '\0';
423*6236dae4SAndroid Build Coastguard Worker     actual_length += (DWORD)current_length;
424*6236dae4SAndroid Build Coastguard Worker   }
425*6236dae4SAndroid Build Coastguard Worker   if(compute_content) {
426*6236dae4SAndroid Build Coastguard Worker     /* Last string has double null-terminator. */
427*6236dae4SAndroid Build Coastguard Worker     *current_pos = '\0';
428*6236dae4SAndroid Build Coastguard Worker   }
429*6236dae4SAndroid Build Coastguard Worker #endif
430*6236dae4SAndroid Build Coastguard Worker   return actual_length;
431*6236dae4SAndroid Build Coastguard Worker }
432*6236dae4SAndroid Build Coastguard Worker 
433*6236dae4SAndroid Build Coastguard Worker /*
434*6236dae4SAndroid Build Coastguard Worker * Returns TRUE if the hostname is a numeric IPv4/IPv6 Address,
435*6236dae4SAndroid Build Coastguard Worker * and populates the buffer with IPv4/IPv6 info.
436*6236dae4SAndroid Build Coastguard Worker */
437*6236dae4SAndroid Build Coastguard Worker 
get_num_host_info(struct num_ip_data * ip_blob,LPCSTR hostname)438*6236dae4SAndroid Build Coastguard Worker static bool get_num_host_info(struct num_ip_data *ip_blob,
439*6236dae4SAndroid Build Coastguard Worker                               LPCSTR hostname)
440*6236dae4SAndroid Build Coastguard Worker {
441*6236dae4SAndroid Build Coastguard Worker   struct in_addr ia;
442*6236dae4SAndroid Build Coastguard Worker   struct in6_addr ia6;
443*6236dae4SAndroid Build Coastguard Worker   bool result = FALSE;
444*6236dae4SAndroid Build Coastguard Worker 
445*6236dae4SAndroid Build Coastguard Worker   int res = Curl_inet_pton(AF_INET, hostname, &ia);
446*6236dae4SAndroid Build Coastguard Worker   if(res) {
447*6236dae4SAndroid Build Coastguard Worker     ip_blob->size = sizeof(struct in_addr);
448*6236dae4SAndroid Build Coastguard Worker     memcpy(&ip_blob->bData.ia, &ia, sizeof(struct in_addr));
449*6236dae4SAndroid Build Coastguard Worker     result = TRUE;
450*6236dae4SAndroid Build Coastguard Worker   }
451*6236dae4SAndroid Build Coastguard Worker   else {
452*6236dae4SAndroid Build Coastguard Worker     res = Curl_inet_pton(AF_INET6, hostname, &ia6);
453*6236dae4SAndroid Build Coastguard Worker     if(res) {
454*6236dae4SAndroid Build Coastguard Worker       ip_blob->size = sizeof(struct in6_addr);
455*6236dae4SAndroid Build Coastguard Worker       memcpy(&ip_blob->bData.ia6, &ia6, sizeof(struct in6_addr));
456*6236dae4SAndroid Build Coastguard Worker       result = TRUE;
457*6236dae4SAndroid Build Coastguard Worker     }
458*6236dae4SAndroid Build Coastguard Worker   }
459*6236dae4SAndroid Build Coastguard Worker   return result;
460*6236dae4SAndroid Build Coastguard Worker }
461*6236dae4SAndroid Build Coastguard Worker 
get_alt_name_info(struct Curl_easy * data,PCCERT_CONTEXT ctx,PCERT_ALT_NAME_INFO * alt_name_info,LPDWORD alt_name_info_size)462*6236dae4SAndroid Build Coastguard Worker static bool get_alt_name_info(struct Curl_easy *data,
463*6236dae4SAndroid Build Coastguard Worker                               PCCERT_CONTEXT ctx,
464*6236dae4SAndroid Build Coastguard Worker                               PCERT_ALT_NAME_INFO *alt_name_info,
465*6236dae4SAndroid Build Coastguard Worker                               LPDWORD alt_name_info_size)
466*6236dae4SAndroid Build Coastguard Worker {
467*6236dae4SAndroid Build Coastguard Worker   bool result = FALSE;
468*6236dae4SAndroid Build Coastguard Worker #if defined(CURL_WINDOWS_UWP)
469*6236dae4SAndroid Build Coastguard Worker   (void)data;
470*6236dae4SAndroid Build Coastguard Worker   (void)ctx;
471*6236dae4SAndroid Build Coastguard Worker   (void)alt_name_info;
472*6236dae4SAndroid Build Coastguard Worker   (void)alt_name_info_size;
473*6236dae4SAndroid Build Coastguard Worker #else
474*6236dae4SAndroid Build Coastguard Worker   PCERT_INFO cert_info = NULL;
475*6236dae4SAndroid Build Coastguard Worker   PCERT_EXTENSION extension = NULL;
476*6236dae4SAndroid Build Coastguard Worker   CRYPT_DECODE_PARA decode_para = { sizeof(CRYPT_DECODE_PARA), NULL, NULL };
477*6236dae4SAndroid Build Coastguard Worker 
478*6236dae4SAndroid Build Coastguard Worker   if(!ctx) {
479*6236dae4SAndroid Build Coastguard Worker     failf(data, "schannel: Null certificate context.");
480*6236dae4SAndroid Build Coastguard Worker     return result;
481*6236dae4SAndroid Build Coastguard Worker   }
482*6236dae4SAndroid Build Coastguard Worker 
483*6236dae4SAndroid Build Coastguard Worker   cert_info = ctx->pCertInfo;
484*6236dae4SAndroid Build Coastguard Worker   if(!cert_info) {
485*6236dae4SAndroid Build Coastguard Worker     failf(data, "schannel: Null certificate info.");
486*6236dae4SAndroid Build Coastguard Worker     return result;
487*6236dae4SAndroid Build Coastguard Worker   }
488*6236dae4SAndroid Build Coastguard Worker 
489*6236dae4SAndroid Build Coastguard Worker   extension = CertFindExtension(szOID_SUBJECT_ALT_NAME2,
490*6236dae4SAndroid Build Coastguard Worker                                 cert_info->cExtension,
491*6236dae4SAndroid Build Coastguard Worker                                 cert_info->rgExtension);
492*6236dae4SAndroid Build Coastguard Worker   if(!extension) {
493*6236dae4SAndroid Build Coastguard Worker     failf(data, "schannel: CertFindExtension() returned no extension.");
494*6236dae4SAndroid Build Coastguard Worker     return result;
495*6236dae4SAndroid Build Coastguard Worker   }
496*6236dae4SAndroid Build Coastguard Worker 
497*6236dae4SAndroid Build Coastguard Worker   if(!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
498*6236dae4SAndroid Build Coastguard Worker                           szOID_SUBJECT_ALT_NAME2,
499*6236dae4SAndroid Build Coastguard Worker                           extension->Value.pbData,
500*6236dae4SAndroid Build Coastguard Worker                           extension->Value.cbData,
501*6236dae4SAndroid Build Coastguard Worker                           CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG,
502*6236dae4SAndroid Build Coastguard Worker                           &decode_para,
503*6236dae4SAndroid Build Coastguard Worker                           alt_name_info,
504*6236dae4SAndroid Build Coastguard Worker                           alt_name_info_size)) {
505*6236dae4SAndroid Build Coastguard Worker     failf(data,
506*6236dae4SAndroid Build Coastguard Worker           "schannel: CryptDecodeObjectEx() returned no alternate name "
507*6236dae4SAndroid Build Coastguard Worker           "information.");
508*6236dae4SAndroid Build Coastguard Worker     return result;
509*6236dae4SAndroid Build Coastguard Worker   }
510*6236dae4SAndroid Build Coastguard Worker   result = TRUE;
511*6236dae4SAndroid Build Coastguard Worker #endif
512*6236dae4SAndroid Build Coastguard Worker   return result;
513*6236dae4SAndroid Build Coastguard Worker }
514*6236dae4SAndroid Build Coastguard Worker 
515*6236dae4SAndroid Build Coastguard Worker /* Verify the server's hostname */
Curl_verify_host(struct Curl_cfilter * cf,struct Curl_easy * data)516*6236dae4SAndroid Build Coastguard Worker CURLcode Curl_verify_host(struct Curl_cfilter *cf,
517*6236dae4SAndroid Build Coastguard Worker                           struct Curl_easy *data)
518*6236dae4SAndroid Build Coastguard Worker {
519*6236dae4SAndroid Build Coastguard Worker   struct ssl_connect_data *connssl = cf->ctx;
520*6236dae4SAndroid Build Coastguard Worker   SECURITY_STATUS sspi_status;
521*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_PEER_FAILED_VERIFICATION;
522*6236dae4SAndroid Build Coastguard Worker   CERT_CONTEXT *pCertContextServer = NULL;
523*6236dae4SAndroid Build Coastguard Worker   TCHAR *cert_hostname_buff = NULL;
524*6236dae4SAndroid Build Coastguard Worker   size_t cert_hostname_buff_index = 0;
525*6236dae4SAndroid Build Coastguard Worker   const char *conn_hostname = connssl->peer.hostname;
526*6236dae4SAndroid Build Coastguard Worker   size_t hostlen = strlen(conn_hostname);
527*6236dae4SAndroid Build Coastguard Worker   DWORD len = 0;
528*6236dae4SAndroid Build Coastguard Worker   DWORD actual_len = 0;
529*6236dae4SAndroid Build Coastguard Worker   PCERT_ALT_NAME_INFO alt_name_info = NULL;
530*6236dae4SAndroid Build Coastguard Worker   DWORD alt_name_info_size = 0;
531*6236dae4SAndroid Build Coastguard Worker   struct num_ip_data ip_blob = { 0 };
532*6236dae4SAndroid Build Coastguard Worker   bool Win8_compat;
533*6236dae4SAndroid Build Coastguard Worker   struct num_ip_data *p = &ip_blob;
534*6236dae4SAndroid Build Coastguard Worker   DWORD i;
535*6236dae4SAndroid Build Coastguard Worker 
536*6236dae4SAndroid Build Coastguard Worker   sspi_status =
537*6236dae4SAndroid Build Coastguard Worker     Curl_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
538*6236dae4SAndroid Build Coastguard Worker                                      SECPKG_ATTR_REMOTE_CERT_CONTEXT,
539*6236dae4SAndroid Build Coastguard Worker                                      &pCertContextServer);
540*6236dae4SAndroid Build Coastguard Worker 
541*6236dae4SAndroid Build Coastguard Worker   if((sspi_status != SEC_E_OK) || !pCertContextServer) {
542*6236dae4SAndroid Build Coastguard Worker     char buffer[STRERROR_LEN];
543*6236dae4SAndroid Build Coastguard Worker     failf(data, "schannel: Failed to read remote certificate context: %s",
544*6236dae4SAndroid Build Coastguard Worker           Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
545*6236dae4SAndroid Build Coastguard Worker     goto cleanup;
546*6236dae4SAndroid Build Coastguard Worker   }
547*6236dae4SAndroid Build Coastguard Worker 
548*6236dae4SAndroid Build Coastguard Worker   Win8_compat = curlx_verify_windows_version(6, 2, 0, PLATFORM_WINNT,
549*6236dae4SAndroid Build Coastguard Worker                                              VERSION_GREATER_THAN_EQUAL);
550*6236dae4SAndroid Build Coastguard Worker   if(get_num_host_info(p, conn_hostname) || !Win8_compat) {
551*6236dae4SAndroid Build Coastguard Worker     if(!get_alt_name_info(data, pCertContextServer,
552*6236dae4SAndroid Build Coastguard Worker                           &alt_name_info, &alt_name_info_size)) {
553*6236dae4SAndroid Build Coastguard Worker       goto cleanup;
554*6236dae4SAndroid Build Coastguard Worker     }
555*6236dae4SAndroid Build Coastguard Worker   }
556*6236dae4SAndroid Build Coastguard Worker 
557*6236dae4SAndroid Build Coastguard Worker   if(p->size) {
558*6236dae4SAndroid Build Coastguard Worker     for(i = 0; i < alt_name_info->cAltEntry; ++i) {
559*6236dae4SAndroid Build Coastguard Worker       PCERT_ALT_NAME_ENTRY entry = &alt_name_info->rgAltEntry[i];
560*6236dae4SAndroid Build Coastguard Worker       if(entry->dwAltNameChoice == CERT_ALT_NAME_IP_ADDRESS) {
561*6236dae4SAndroid Build Coastguard Worker         if(entry->IPAddress.cbData == p->size) {
562*6236dae4SAndroid Build Coastguard Worker           if(!memcmp(entry->IPAddress.pbData, &p->bData,
563*6236dae4SAndroid Build Coastguard Worker                      entry->IPAddress.cbData)) {
564*6236dae4SAndroid Build Coastguard Worker             result = CURLE_OK;
565*6236dae4SAndroid Build Coastguard Worker             infof(data,
566*6236dae4SAndroid Build Coastguard Worker              "schannel: connection hostname (%s) matched cert's IP address!",
567*6236dae4SAndroid Build Coastguard Worker              conn_hostname);
568*6236dae4SAndroid Build Coastguard Worker             break;
569*6236dae4SAndroid Build Coastguard Worker           }
570*6236dae4SAndroid Build Coastguard Worker         }
571*6236dae4SAndroid Build Coastguard Worker       }
572*6236dae4SAndroid Build Coastguard Worker     }
573*6236dae4SAndroid Build Coastguard Worker   }
574*6236dae4SAndroid Build Coastguard Worker 
575*6236dae4SAndroid Build Coastguard Worker   else {
576*6236dae4SAndroid Build Coastguard Worker     /* Determine the size of the string needed for the cert hostname */
577*6236dae4SAndroid Build Coastguard Worker     len = cert_get_name_string(data, pCertContextServer,
578*6236dae4SAndroid Build Coastguard Worker                                NULL, 0, alt_name_info, Win8_compat);
579*6236dae4SAndroid Build Coastguard Worker     if(len == 0) {
580*6236dae4SAndroid Build Coastguard Worker       failf(data,
581*6236dae4SAndroid Build Coastguard Worker             "schannel: CertGetNameString() returned no "
582*6236dae4SAndroid Build Coastguard Worker             "certificate name information");
583*6236dae4SAndroid Build Coastguard Worker       goto cleanup;
584*6236dae4SAndroid Build Coastguard Worker     }
585*6236dae4SAndroid Build Coastguard Worker 
586*6236dae4SAndroid Build Coastguard Worker     /* CertGetNameString guarantees that the returned name will not contain
587*6236dae4SAndroid Build Coastguard Worker      * embedded null bytes. This appears to be undocumented behavior.
588*6236dae4SAndroid Build Coastguard Worker      */
589*6236dae4SAndroid Build Coastguard Worker     cert_hostname_buff = (LPTSTR)malloc(len * sizeof(TCHAR));
590*6236dae4SAndroid Build Coastguard Worker     if(!cert_hostname_buff) {
591*6236dae4SAndroid Build Coastguard Worker       result = CURLE_OUT_OF_MEMORY;
592*6236dae4SAndroid Build Coastguard Worker       goto cleanup;
593*6236dae4SAndroid Build Coastguard Worker     }
594*6236dae4SAndroid Build Coastguard Worker     actual_len = cert_get_name_string(data, pCertContextServer,
595*6236dae4SAndroid Build Coastguard Worker                  (LPTSTR)cert_hostname_buff, len, alt_name_info, Win8_compat);
596*6236dae4SAndroid Build Coastguard Worker 
597*6236dae4SAndroid Build Coastguard Worker     /* Sanity check */
598*6236dae4SAndroid Build Coastguard Worker     if(actual_len != len) {
599*6236dae4SAndroid Build Coastguard Worker       failf(data,
600*6236dae4SAndroid Build Coastguard Worker       "schannel: CertGetNameString() returned certificate "
601*6236dae4SAndroid Build Coastguard Worker       "name information of unexpected size");
602*6236dae4SAndroid Build Coastguard Worker       goto cleanup;
603*6236dae4SAndroid Build Coastguard Worker     }
604*6236dae4SAndroid Build Coastguard Worker 
605*6236dae4SAndroid Build Coastguard Worker     /* cert_hostname_buff contains all DNS names, where each name is
606*6236dae4SAndroid Build Coastguard Worker      * null-terminated and the last DNS name is double null-terminated. Due to
607*6236dae4SAndroid Build Coastguard Worker      * this encoding, use the length of the buffer to iterate over all names.
608*6236dae4SAndroid Build Coastguard Worker      */
609*6236dae4SAndroid Build Coastguard Worker     while(cert_hostname_buff_index < len &&
610*6236dae4SAndroid Build Coastguard Worker           cert_hostname_buff[cert_hostname_buff_index] != TEXT('\0') &&
611*6236dae4SAndroid Build Coastguard Worker           result == CURLE_PEER_FAILED_VERIFICATION) {
612*6236dae4SAndroid Build Coastguard Worker 
613*6236dae4SAndroid Build Coastguard Worker       char *cert_hostname;
614*6236dae4SAndroid Build Coastguard Worker 
615*6236dae4SAndroid Build Coastguard Worker       /* Comparing the cert name and the connection hostname encoded as UTF-8
616*6236dae4SAndroid Build Coastguard Worker        * is acceptable since both values are assumed to use ASCII
617*6236dae4SAndroid Build Coastguard Worker        * (or some equivalent) encoding
618*6236dae4SAndroid Build Coastguard Worker        */
619*6236dae4SAndroid Build Coastguard Worker       cert_hostname = curlx_convert_tchar_to_UTF8(
620*6236dae4SAndroid Build Coastguard Worker       &cert_hostname_buff[cert_hostname_buff_index]);
621*6236dae4SAndroid Build Coastguard Worker       if(!cert_hostname) {
622*6236dae4SAndroid Build Coastguard Worker         result = CURLE_OUT_OF_MEMORY;
623*6236dae4SAndroid Build Coastguard Worker       }
624*6236dae4SAndroid Build Coastguard Worker       else {
625*6236dae4SAndroid Build Coastguard Worker         if(Curl_cert_hostcheck(cert_hostname, strlen(cert_hostname),
626*6236dae4SAndroid Build Coastguard Worker                                conn_hostname, hostlen)) {
627*6236dae4SAndroid Build Coastguard Worker           infof(data,
628*6236dae4SAndroid Build Coastguard Worker                 "schannel: connection hostname (%s) validated "
629*6236dae4SAndroid Build Coastguard Worker                 "against certificate name (%s)",
630*6236dae4SAndroid Build Coastguard Worker                 conn_hostname, cert_hostname);
631*6236dae4SAndroid Build Coastguard Worker           result = CURLE_OK;
632*6236dae4SAndroid Build Coastguard Worker         }
633*6236dae4SAndroid Build Coastguard Worker         else {
634*6236dae4SAndroid Build Coastguard Worker           size_t cert_hostname_len;
635*6236dae4SAndroid Build Coastguard Worker 
636*6236dae4SAndroid Build Coastguard Worker           infof(data,
637*6236dae4SAndroid Build Coastguard Worker                 "schannel: connection hostname (%s) did not match "
638*6236dae4SAndroid Build Coastguard Worker                 "against certificate name (%s)",
639*6236dae4SAndroid Build Coastguard Worker                 conn_hostname, cert_hostname);
640*6236dae4SAndroid Build Coastguard Worker 
641*6236dae4SAndroid Build Coastguard Worker           cert_hostname_len =
642*6236dae4SAndroid Build Coastguard Worker             _tcslen(&cert_hostname_buff[cert_hostname_buff_index]);
643*6236dae4SAndroid Build Coastguard Worker 
644*6236dae4SAndroid Build Coastguard Worker           /* Move on to next cert name */
645*6236dae4SAndroid Build Coastguard Worker           cert_hostname_buff_index += cert_hostname_len + 1;
646*6236dae4SAndroid Build Coastguard Worker 
647*6236dae4SAndroid Build Coastguard Worker           result = CURLE_PEER_FAILED_VERIFICATION;
648*6236dae4SAndroid Build Coastguard Worker         }
649*6236dae4SAndroid Build Coastguard Worker         curlx_unicodefree(cert_hostname);
650*6236dae4SAndroid Build Coastguard Worker       }
651*6236dae4SAndroid Build Coastguard Worker     }
652*6236dae4SAndroid Build Coastguard Worker 
653*6236dae4SAndroid Build Coastguard Worker     if(result == CURLE_PEER_FAILED_VERIFICATION) {
654*6236dae4SAndroid Build Coastguard Worker       failf(data,
655*6236dae4SAndroid Build Coastguard Worker             "schannel: CertGetNameString() failed to match "
656*6236dae4SAndroid Build Coastguard Worker             "connection hostname (%s) against server certificate names",
657*6236dae4SAndroid Build Coastguard Worker             conn_hostname);
658*6236dae4SAndroid Build Coastguard Worker     }
659*6236dae4SAndroid Build Coastguard Worker     else if(result != CURLE_OK)
660*6236dae4SAndroid Build Coastguard Worker       failf(data, "schannel: server certificate name verification failed");
661*6236dae4SAndroid Build Coastguard Worker   }
662*6236dae4SAndroid Build Coastguard Worker 
663*6236dae4SAndroid Build Coastguard Worker cleanup:
664*6236dae4SAndroid Build Coastguard Worker   Curl_safefree(cert_hostname_buff);
665*6236dae4SAndroid Build Coastguard Worker 
666*6236dae4SAndroid Build Coastguard Worker   if(pCertContextServer)
667*6236dae4SAndroid Build Coastguard Worker     CertFreeCertificateContext(pCertContextServer);
668*6236dae4SAndroid Build Coastguard Worker 
669*6236dae4SAndroid Build Coastguard Worker   return result;
670*6236dae4SAndroid Build Coastguard Worker }
671*6236dae4SAndroid Build Coastguard Worker 
672*6236dae4SAndroid Build Coastguard Worker #ifdef HAS_MANUAL_VERIFY_API
673*6236dae4SAndroid Build Coastguard Worker /* Verify the server's certificate and hostname */
Curl_verify_certificate(struct Curl_cfilter * cf,struct Curl_easy * data)674*6236dae4SAndroid Build Coastguard Worker CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
675*6236dae4SAndroid Build Coastguard Worker                                  struct Curl_easy *data)
676*6236dae4SAndroid Build Coastguard Worker {
677*6236dae4SAndroid Build Coastguard Worker   struct ssl_connect_data *connssl = cf->ctx;
678*6236dae4SAndroid Build Coastguard Worker   struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
679*6236dae4SAndroid Build Coastguard Worker   struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
680*6236dae4SAndroid Build Coastguard Worker   SECURITY_STATUS sspi_status;
681*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
682*6236dae4SAndroid Build Coastguard Worker   CERT_CONTEXT *pCertContextServer = NULL;
683*6236dae4SAndroid Build Coastguard Worker   const CERT_CHAIN_CONTEXT *pChainContext = NULL;
684*6236dae4SAndroid Build Coastguard Worker   HCERTCHAINENGINE cert_chain_engine = NULL;
685*6236dae4SAndroid Build Coastguard Worker   HCERTSTORE trust_store = NULL;
686*6236dae4SAndroid Build Coastguard Worker   HCERTSTORE own_trust_store = NULL;
687*6236dae4SAndroid Build Coastguard Worker 
688*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(BACKEND);
689*6236dae4SAndroid Build Coastguard Worker 
690*6236dae4SAndroid Build Coastguard Worker   sspi_status =
691*6236dae4SAndroid Build Coastguard Worker     Curl_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
692*6236dae4SAndroid Build Coastguard Worker                                      SECPKG_ATTR_REMOTE_CERT_CONTEXT,
693*6236dae4SAndroid Build Coastguard Worker                                      &pCertContextServer);
694*6236dae4SAndroid Build Coastguard Worker 
695*6236dae4SAndroid Build Coastguard Worker   if((sspi_status != SEC_E_OK) || !pCertContextServer) {
696*6236dae4SAndroid Build Coastguard Worker     char buffer[STRERROR_LEN];
697*6236dae4SAndroid Build Coastguard Worker     failf(data, "schannel: Failed to read remote certificate context: %s",
698*6236dae4SAndroid Build Coastguard Worker           Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
699*6236dae4SAndroid Build Coastguard Worker     result = CURLE_PEER_FAILED_VERIFICATION;
700*6236dae4SAndroid Build Coastguard Worker   }
701*6236dae4SAndroid Build Coastguard Worker 
702*6236dae4SAndroid Build Coastguard Worker   if(result == CURLE_OK &&
703*6236dae4SAndroid Build Coastguard Worker       (conn_config->CAfile || conn_config->ca_info_blob) &&
704*6236dae4SAndroid Build Coastguard Worker       BACKEND->use_manual_cred_validation) {
705*6236dae4SAndroid Build Coastguard Worker     /*
706*6236dae4SAndroid Build Coastguard Worker      * Create a chain engine that uses the certificates in the CA file as
707*6236dae4SAndroid Build Coastguard Worker      * trusted certificates. This is only supported on Windows 7+.
708*6236dae4SAndroid Build Coastguard Worker      */
709*6236dae4SAndroid Build Coastguard Worker 
710*6236dae4SAndroid Build Coastguard Worker     if(curlx_verify_windows_version(6, 1, 0, PLATFORM_WINNT,
711*6236dae4SAndroid Build Coastguard Worker                                     VERSION_LESS_THAN)) {
712*6236dae4SAndroid Build Coastguard Worker       failf(data, "schannel: this version of Windows is too old to support "
713*6236dae4SAndroid Build Coastguard Worker             "certificate verification via CA bundle file.");
714*6236dae4SAndroid Build Coastguard Worker       result = CURLE_SSL_CACERT_BADFILE;
715*6236dae4SAndroid Build Coastguard Worker     }
716*6236dae4SAndroid Build Coastguard Worker     else {
717*6236dae4SAndroid Build Coastguard Worker       /* try cache */
718*6236dae4SAndroid Build Coastguard Worker       trust_store = Curl_schannel_get_cached_cert_store(cf, data);
719*6236dae4SAndroid Build Coastguard Worker 
720*6236dae4SAndroid Build Coastguard Worker       if(trust_store) {
721*6236dae4SAndroid Build Coastguard Worker         infof(data, "schannel: reusing certificate store from cache");
722*6236dae4SAndroid Build Coastguard Worker       }
723*6236dae4SAndroid Build Coastguard Worker       else {
724*6236dae4SAndroid Build Coastguard Worker         /* Open the certificate store */
725*6236dae4SAndroid Build Coastguard Worker         trust_store = CertOpenStore(CERT_STORE_PROV_MEMORY,
726*6236dae4SAndroid Build Coastguard Worker                                     0,
727*6236dae4SAndroid Build Coastguard Worker                                     (HCRYPTPROV)NULL,
728*6236dae4SAndroid Build Coastguard Worker                                     CERT_STORE_CREATE_NEW_FLAG,
729*6236dae4SAndroid Build Coastguard Worker                                     NULL);
730*6236dae4SAndroid Build Coastguard Worker         if(!trust_store) {
731*6236dae4SAndroid Build Coastguard Worker           char buffer[STRERROR_LEN];
732*6236dae4SAndroid Build Coastguard Worker           failf(data, "schannel: failed to create certificate store: %s",
733*6236dae4SAndroid Build Coastguard Worker                 Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
734*6236dae4SAndroid Build Coastguard Worker           result = CURLE_SSL_CACERT_BADFILE;
735*6236dae4SAndroid Build Coastguard Worker         }
736*6236dae4SAndroid Build Coastguard Worker         else {
737*6236dae4SAndroid Build Coastguard Worker           const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
738*6236dae4SAndroid Build Coastguard Worker           own_trust_store = trust_store;
739*6236dae4SAndroid Build Coastguard Worker 
740*6236dae4SAndroid Build Coastguard Worker           if(ca_info_blob) {
741*6236dae4SAndroid Build Coastguard Worker             result = add_certs_data_to_store(trust_store,
742*6236dae4SAndroid Build Coastguard Worker                                               (const char *)ca_info_blob->data,
743*6236dae4SAndroid Build Coastguard Worker                                               ca_info_blob->len,
744*6236dae4SAndroid Build Coastguard Worker                                               "(memory blob)",
745*6236dae4SAndroid Build Coastguard Worker                                               data);
746*6236dae4SAndroid Build Coastguard Worker           }
747*6236dae4SAndroid Build Coastguard Worker           else {
748*6236dae4SAndroid Build Coastguard Worker             result = add_certs_file_to_store(trust_store,
749*6236dae4SAndroid Build Coastguard Worker                                               conn_config->CAfile,
750*6236dae4SAndroid Build Coastguard Worker                                               data);
751*6236dae4SAndroid Build Coastguard Worker           }
752*6236dae4SAndroid Build Coastguard Worker           if(result == CURLE_OK) {
753*6236dae4SAndroid Build Coastguard Worker             if(Curl_schannel_set_cached_cert_store(cf, data, trust_store)) {
754*6236dae4SAndroid Build Coastguard Worker               own_trust_store = NULL;
755*6236dae4SAndroid Build Coastguard Worker             }
756*6236dae4SAndroid Build Coastguard Worker           }
757*6236dae4SAndroid Build Coastguard Worker         }
758*6236dae4SAndroid Build Coastguard Worker       }
759*6236dae4SAndroid Build Coastguard Worker     }
760*6236dae4SAndroid Build Coastguard Worker 
761*6236dae4SAndroid Build Coastguard Worker     if(result == CURLE_OK) {
762*6236dae4SAndroid Build Coastguard Worker       struct cert_chain_engine_config_win7 engine_config;
763*6236dae4SAndroid Build Coastguard Worker       BOOL create_engine_result;
764*6236dae4SAndroid Build Coastguard Worker 
765*6236dae4SAndroid Build Coastguard Worker       memset(&engine_config, 0, sizeof(engine_config));
766*6236dae4SAndroid Build Coastguard Worker       engine_config.cbSize = sizeof(engine_config);
767*6236dae4SAndroid Build Coastguard Worker       engine_config.hExclusiveRoot = trust_store;
768*6236dae4SAndroid Build Coastguard Worker 
769*6236dae4SAndroid Build Coastguard Worker       /* CertCreateCertificateChainEngine will check the expected size of the
770*6236dae4SAndroid Build Coastguard Worker        * CERT_CHAIN_ENGINE_CONFIG structure and fail if the specified size
771*6236dae4SAndroid Build Coastguard Worker        * does not match the expected size. When this occurs, it indicates that
772*6236dae4SAndroid Build Coastguard Worker        * CAINFO is not supported on the version of Windows in use.
773*6236dae4SAndroid Build Coastguard Worker        */
774*6236dae4SAndroid Build Coastguard Worker       create_engine_result =
775*6236dae4SAndroid Build Coastguard Worker         CertCreateCertificateChainEngine(
776*6236dae4SAndroid Build Coastguard Worker           (CERT_CHAIN_ENGINE_CONFIG *)&engine_config, &cert_chain_engine);
777*6236dae4SAndroid Build Coastguard Worker       if(!create_engine_result) {
778*6236dae4SAndroid Build Coastguard Worker         char buffer[STRERROR_LEN];
779*6236dae4SAndroid Build Coastguard Worker         failf(data,
780*6236dae4SAndroid Build Coastguard Worker               "schannel: failed to create certificate chain engine: %s",
781*6236dae4SAndroid Build Coastguard Worker               Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
782*6236dae4SAndroid Build Coastguard Worker         result = CURLE_SSL_CACERT_BADFILE;
783*6236dae4SAndroid Build Coastguard Worker       }
784*6236dae4SAndroid Build Coastguard Worker     }
785*6236dae4SAndroid Build Coastguard Worker   }
786*6236dae4SAndroid Build Coastguard Worker 
787*6236dae4SAndroid Build Coastguard Worker   if(result == CURLE_OK) {
788*6236dae4SAndroid Build Coastguard Worker     CERT_CHAIN_PARA ChainPara;
789*6236dae4SAndroid Build Coastguard Worker 
790*6236dae4SAndroid Build Coastguard Worker     memset(&ChainPara, 0, sizeof(ChainPara));
791*6236dae4SAndroid Build Coastguard Worker     ChainPara.cbSize = sizeof(ChainPara);
792*6236dae4SAndroid Build Coastguard Worker 
793*6236dae4SAndroid Build Coastguard Worker     if(!CertGetCertificateChain(cert_chain_engine,
794*6236dae4SAndroid Build Coastguard Worker                                 pCertContextServer,
795*6236dae4SAndroid Build Coastguard Worker                                 NULL,
796*6236dae4SAndroid Build Coastguard Worker                                 pCertContextServer->hCertStore,
797*6236dae4SAndroid Build Coastguard Worker                                 &ChainPara,
798*6236dae4SAndroid Build Coastguard Worker                                 (ssl_config->no_revoke ? 0 :
799*6236dae4SAndroid Build Coastguard Worker                                  CERT_CHAIN_REVOCATION_CHECK_CHAIN),
800*6236dae4SAndroid Build Coastguard Worker                                 NULL,
801*6236dae4SAndroid Build Coastguard Worker                                 &pChainContext)) {
802*6236dae4SAndroid Build Coastguard Worker       char buffer[STRERROR_LEN];
803*6236dae4SAndroid Build Coastguard Worker       failf(data, "schannel: CertGetCertificateChain failed: %s",
804*6236dae4SAndroid Build Coastguard Worker             Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
805*6236dae4SAndroid Build Coastguard Worker       pChainContext = NULL;
806*6236dae4SAndroid Build Coastguard Worker       result = CURLE_PEER_FAILED_VERIFICATION;
807*6236dae4SAndroid Build Coastguard Worker     }
808*6236dae4SAndroid Build Coastguard Worker 
809*6236dae4SAndroid Build Coastguard Worker     if(result == CURLE_OK) {
810*6236dae4SAndroid Build Coastguard Worker       CERT_SIMPLE_CHAIN *pSimpleChain = pChainContext->rgpChain[0];
811*6236dae4SAndroid Build Coastguard Worker       DWORD dwTrustErrorMask = ~(DWORD)(CERT_TRUST_IS_NOT_TIME_NESTED);
812*6236dae4SAndroid Build Coastguard Worker       dwTrustErrorMask &= pSimpleChain->TrustStatus.dwErrorStatus;
813*6236dae4SAndroid Build Coastguard Worker 
814*6236dae4SAndroid Build Coastguard Worker       if(data->set.ssl.revoke_best_effort) {
815*6236dae4SAndroid Build Coastguard Worker         /* Ignore errors when root certificates are missing the revocation
816*6236dae4SAndroid Build Coastguard Worker          * list URL, or when the list could not be downloaded because the
817*6236dae4SAndroid Build Coastguard Worker          * server is currently unreachable. */
818*6236dae4SAndroid Build Coastguard Worker         dwTrustErrorMask &= ~(DWORD)(CERT_TRUST_REVOCATION_STATUS_UNKNOWN |
819*6236dae4SAndroid Build Coastguard Worker           CERT_TRUST_IS_OFFLINE_REVOCATION);
820*6236dae4SAndroid Build Coastguard Worker       }
821*6236dae4SAndroid Build Coastguard Worker 
822*6236dae4SAndroid Build Coastguard Worker       if(dwTrustErrorMask) {
823*6236dae4SAndroid Build Coastguard Worker         if(dwTrustErrorMask & CERT_TRUST_IS_REVOKED)
824*6236dae4SAndroid Build Coastguard Worker           failf(data, "schannel: CertGetCertificateChain trust error"
825*6236dae4SAndroid Build Coastguard Worker                 " CERT_TRUST_IS_REVOKED");
826*6236dae4SAndroid Build Coastguard Worker         else if(dwTrustErrorMask & CERT_TRUST_IS_PARTIAL_CHAIN)
827*6236dae4SAndroid Build Coastguard Worker           failf(data, "schannel: CertGetCertificateChain trust error"
828*6236dae4SAndroid Build Coastguard Worker                 " CERT_TRUST_IS_PARTIAL_CHAIN");
829*6236dae4SAndroid Build Coastguard Worker         else if(dwTrustErrorMask & CERT_TRUST_IS_UNTRUSTED_ROOT)
830*6236dae4SAndroid Build Coastguard Worker           failf(data, "schannel: CertGetCertificateChain trust error"
831*6236dae4SAndroid Build Coastguard Worker                 " CERT_TRUST_IS_UNTRUSTED_ROOT");
832*6236dae4SAndroid Build Coastguard Worker         else if(dwTrustErrorMask & CERT_TRUST_IS_NOT_TIME_VALID)
833*6236dae4SAndroid Build Coastguard Worker           failf(data, "schannel: CertGetCertificateChain trust error"
834*6236dae4SAndroid Build Coastguard Worker                 " CERT_TRUST_IS_NOT_TIME_VALID");
835*6236dae4SAndroid Build Coastguard Worker         else if(dwTrustErrorMask & CERT_TRUST_REVOCATION_STATUS_UNKNOWN)
836*6236dae4SAndroid Build Coastguard Worker           failf(data, "schannel: CertGetCertificateChain trust error"
837*6236dae4SAndroid Build Coastguard Worker                 " CERT_TRUST_REVOCATION_STATUS_UNKNOWN");
838*6236dae4SAndroid Build Coastguard Worker         else
839*6236dae4SAndroid Build Coastguard Worker           failf(data, "schannel: CertGetCertificateChain error mask: 0x%08lx",
840*6236dae4SAndroid Build Coastguard Worker                 dwTrustErrorMask);
841*6236dae4SAndroid Build Coastguard Worker         result = CURLE_PEER_FAILED_VERIFICATION;
842*6236dae4SAndroid Build Coastguard Worker       }
843*6236dae4SAndroid Build Coastguard Worker     }
844*6236dae4SAndroid Build Coastguard Worker   }
845*6236dae4SAndroid Build Coastguard Worker 
846*6236dae4SAndroid Build Coastguard Worker   if(result == CURLE_OK) {
847*6236dae4SAndroid Build Coastguard Worker     if(conn_config->verifyhost) {
848*6236dae4SAndroid Build Coastguard Worker       result = Curl_verify_host(cf, data);
849*6236dae4SAndroid Build Coastguard Worker     }
850*6236dae4SAndroid Build Coastguard Worker   }
851*6236dae4SAndroid Build Coastguard Worker 
852*6236dae4SAndroid Build Coastguard Worker   if(cert_chain_engine) {
853*6236dae4SAndroid Build Coastguard Worker     CertFreeCertificateChainEngine(cert_chain_engine);
854*6236dae4SAndroid Build Coastguard Worker   }
855*6236dae4SAndroid Build Coastguard Worker 
856*6236dae4SAndroid Build Coastguard Worker   if(own_trust_store) {
857*6236dae4SAndroid Build Coastguard Worker     CertCloseStore(own_trust_store, 0);
858*6236dae4SAndroid Build Coastguard Worker   }
859*6236dae4SAndroid Build Coastguard Worker 
860*6236dae4SAndroid Build Coastguard Worker   if(pChainContext)
861*6236dae4SAndroid Build Coastguard Worker     CertFreeCertificateChain(pChainContext);
862*6236dae4SAndroid Build Coastguard Worker 
863*6236dae4SAndroid Build Coastguard Worker   if(pCertContextServer)
864*6236dae4SAndroid Build Coastguard Worker     CertFreeCertificateContext(pCertContextServer);
865*6236dae4SAndroid Build Coastguard Worker 
866*6236dae4SAndroid Build Coastguard Worker   return result;
867*6236dae4SAndroid Build Coastguard Worker }
868*6236dae4SAndroid Build Coastguard Worker 
869*6236dae4SAndroid Build Coastguard Worker #endif /* HAS_MANUAL_VERIFY_API */
870*6236dae4SAndroid Build Coastguard Worker #endif /* USE_SCHANNEL */
871