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