xref: /aosp_15_r20/external/libcups/cups/tls-sspi.c (revision 5e7646d21f1134fb0638875d812ef646c12ab91e)
1*5e7646d2SAndroid Build Coastguard Worker /*
2*5e7646d2SAndroid Build Coastguard Worker  * TLS support for CUPS on Windows using the Security Support Provider
3*5e7646d2SAndroid Build Coastguard Worker  * Interface (SSPI).
4*5e7646d2SAndroid Build Coastguard Worker  *
5*5e7646d2SAndroid Build Coastguard Worker  * Copyright 2010-2018 by Apple Inc.
6*5e7646d2SAndroid Build Coastguard Worker  *
7*5e7646d2SAndroid Build Coastguard Worker  * Licensed under Apache License v2.0.  See the file "LICENSE" for more information.
8*5e7646d2SAndroid Build Coastguard Worker  */
9*5e7646d2SAndroid Build Coastguard Worker 
10*5e7646d2SAndroid Build Coastguard Worker /**** This file is included from tls.c ****/
11*5e7646d2SAndroid Build Coastguard Worker 
12*5e7646d2SAndroid Build Coastguard Worker /*
13*5e7646d2SAndroid Build Coastguard Worker  * Include necessary headers...
14*5e7646d2SAndroid Build Coastguard Worker  */
15*5e7646d2SAndroid Build Coastguard Worker 
16*5e7646d2SAndroid Build Coastguard Worker #include "debug-private.h"
17*5e7646d2SAndroid Build Coastguard Worker 
18*5e7646d2SAndroid Build Coastguard Worker 
19*5e7646d2SAndroid Build Coastguard Worker /*
20*5e7646d2SAndroid Build Coastguard Worker  * Include necessary libraries...
21*5e7646d2SAndroid Build Coastguard Worker  */
22*5e7646d2SAndroid Build Coastguard Worker 
23*5e7646d2SAndroid Build Coastguard Worker #pragma comment(lib, "Crypt32.lib")
24*5e7646d2SAndroid Build Coastguard Worker #pragma comment(lib, "Secur32.lib")
25*5e7646d2SAndroid Build Coastguard Worker #pragma comment(lib, "Ws2_32.lib")
26*5e7646d2SAndroid Build Coastguard Worker 
27*5e7646d2SAndroid Build Coastguard Worker 
28*5e7646d2SAndroid Build Coastguard Worker /*
29*5e7646d2SAndroid Build Coastguard Worker  * Constants...
30*5e7646d2SAndroid Build Coastguard Worker  */
31*5e7646d2SAndroid Build Coastguard Worker 
32*5e7646d2SAndroid Build Coastguard Worker #ifndef SECURITY_FLAG_IGNORE_UNKNOWN_CA
33*5e7646d2SAndroid Build Coastguard Worker #  define SECURITY_FLAG_IGNORE_UNKNOWN_CA         0x00000100 /* Untrusted root */
34*5e7646d2SAndroid Build Coastguard Worker #endif /* SECURITY_FLAG_IGNORE_UNKNOWN_CA */
35*5e7646d2SAndroid Build Coastguard Worker 
36*5e7646d2SAndroid Build Coastguard Worker #ifndef SECURITY_FLAG_IGNORE_CERT_CN_INVALID
37*5e7646d2SAndroid Build Coastguard Worker #  define SECURITY_FLAG_IGNORE_CERT_CN_INVALID	  0x00001000 /* Common name does not match */
38*5e7646d2SAndroid Build Coastguard Worker #endif /* !SECURITY_FLAG_IGNORE_CERT_CN_INVALID */
39*5e7646d2SAndroid Build Coastguard Worker 
40*5e7646d2SAndroid Build Coastguard Worker #ifndef SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
41*5e7646d2SAndroid Build Coastguard Worker #  define SECURITY_FLAG_IGNORE_CERT_DATE_INVALID  0x00002000 /* Expired X509 Cert. */
42*5e7646d2SAndroid Build Coastguard Worker #endif /* !SECURITY_FLAG_IGNORE_CERT_DATE_INVALID */
43*5e7646d2SAndroid Build Coastguard Worker 
44*5e7646d2SAndroid Build Coastguard Worker 
45*5e7646d2SAndroid Build Coastguard Worker /*
46*5e7646d2SAndroid Build Coastguard Worker  * Local globals...
47*5e7646d2SAndroid Build Coastguard Worker  */
48*5e7646d2SAndroid Build Coastguard Worker 
49*5e7646d2SAndroid Build Coastguard Worker static int		tls_options = -1,/* Options for TLS connections */
50*5e7646d2SAndroid Build Coastguard Worker 			tls_min_version = _HTTP_TLS_1_0,
51*5e7646d2SAndroid Build Coastguard Worker 			tls_max_version = _HTTP_TLS_MAX;
52*5e7646d2SAndroid Build Coastguard Worker 
53*5e7646d2SAndroid Build Coastguard Worker 
54*5e7646d2SAndroid Build Coastguard Worker /*
55*5e7646d2SAndroid Build Coastguard Worker  * Local functions...
56*5e7646d2SAndroid Build Coastguard Worker  */
57*5e7646d2SAndroid Build Coastguard Worker 
58*5e7646d2SAndroid Build Coastguard Worker static _http_sspi_t *http_sspi_alloc(void);
59*5e7646d2SAndroid Build Coastguard Worker static int	http_sspi_client(http_t *http, const char *hostname);
60*5e7646d2SAndroid Build Coastguard Worker static PCCERT_CONTEXT http_sspi_create_credential(http_credential_t *cred);
61*5e7646d2SAndroid Build Coastguard Worker static BOOL	http_sspi_find_credentials(http_t *http, const LPWSTR containerName, const char *common_name);
62*5e7646d2SAndroid Build Coastguard Worker static void	http_sspi_free(_http_sspi_t *sspi);
63*5e7646d2SAndroid Build Coastguard Worker static BOOL	http_sspi_make_credentials(_http_sspi_t *sspi, const LPWSTR containerName, const char *common_name, _http_mode_t mode, int years);
64*5e7646d2SAndroid Build Coastguard Worker static int	http_sspi_server(http_t *http, const char *hostname);
65*5e7646d2SAndroid Build Coastguard Worker static void	http_sspi_set_allows_any_root(_http_sspi_t *sspi, BOOL allow);
66*5e7646d2SAndroid Build Coastguard Worker static void	http_sspi_set_allows_expired_certs(_http_sspi_t *sspi, BOOL allow);
67*5e7646d2SAndroid Build Coastguard Worker static const char *http_sspi_strerror(char *buffer, size_t bufsize, DWORD code);
68*5e7646d2SAndroid Build Coastguard Worker static DWORD	http_sspi_verify(PCCERT_CONTEXT cert, const char *common_name, DWORD dwCertFlags);
69*5e7646d2SAndroid Build Coastguard Worker 
70*5e7646d2SAndroid Build Coastguard Worker 
71*5e7646d2SAndroid Build Coastguard Worker /*
72*5e7646d2SAndroid Build Coastguard Worker  * 'cupsMakeServerCredentials()' - Make a self-signed certificate and private key pair.
73*5e7646d2SAndroid Build Coastguard Worker  *
74*5e7646d2SAndroid Build Coastguard Worker  * @since CUPS 2.0/OS 10.10@
75*5e7646d2SAndroid Build Coastguard Worker  */
76*5e7646d2SAndroid Build Coastguard Worker 
77*5e7646d2SAndroid Build Coastguard Worker int					/* O - 1 on success, 0 on failure */
cupsMakeServerCredentials(const char * path,const char * common_name,int num_alt_names,const char ** alt_names,time_t expiration_date)78*5e7646d2SAndroid Build Coastguard Worker cupsMakeServerCredentials(
79*5e7646d2SAndroid Build Coastguard Worker     const char *path,			/* I - Keychain path or @code NULL@ for default */
80*5e7646d2SAndroid Build Coastguard Worker     const char *common_name,		/* I - Common name */
81*5e7646d2SAndroid Build Coastguard Worker     int        num_alt_names,		/* I - Number of subject alternate names */
82*5e7646d2SAndroid Build Coastguard Worker     const char **alt_names,		/* I - Subject Alternate Names */
83*5e7646d2SAndroid Build Coastguard Worker     time_t     expiration_date)		/* I - Expiration date */
84*5e7646d2SAndroid Build Coastguard Worker {
85*5e7646d2SAndroid Build Coastguard Worker   _http_sspi_t	*sspi;			/* SSPI data */
86*5e7646d2SAndroid Build Coastguard Worker   int		ret;			/* Return value */
87*5e7646d2SAndroid Build Coastguard Worker 
88*5e7646d2SAndroid Build Coastguard Worker 
89*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("cupsMakeServerCredentials(path=\"%s\", common_name=\"%s\", num_alt_names=%d, alt_names=%p, expiration_date=%d)", path, common_name, num_alt_names, alt_names, (int)expiration_date));
90*5e7646d2SAndroid Build Coastguard Worker 
91*5e7646d2SAndroid Build Coastguard Worker   (void)path;
92*5e7646d2SAndroid Build Coastguard Worker   (void)num_alt_names;
93*5e7646d2SAndroid Build Coastguard Worker   (void)alt_names;
94*5e7646d2SAndroid Build Coastguard Worker 
95*5e7646d2SAndroid Build Coastguard Worker   sspi = http_sspi_alloc();
96*5e7646d2SAndroid Build Coastguard Worker   ret  = http_sspi_make_credentials(sspi, L"ServerContainer", common_name, _HTTP_MODE_SERVER, (int)((expiration_date - time(NULL) + 86399) / 86400 / 365));
97*5e7646d2SAndroid Build Coastguard Worker 
98*5e7646d2SAndroid Build Coastguard Worker   http_sspi_free(sspi);
99*5e7646d2SAndroid Build Coastguard Worker 
100*5e7646d2SAndroid Build Coastguard Worker   return (ret);
101*5e7646d2SAndroid Build Coastguard Worker }
102*5e7646d2SAndroid Build Coastguard Worker 
103*5e7646d2SAndroid Build Coastguard Worker 
104*5e7646d2SAndroid Build Coastguard Worker /*
105*5e7646d2SAndroid Build Coastguard Worker  * 'cupsSetServerCredentials()' - Set the default server credentials.
106*5e7646d2SAndroid Build Coastguard Worker  *
107*5e7646d2SAndroid Build Coastguard Worker  * Note: The server credentials are used by all threads in the running process.
108*5e7646d2SAndroid Build Coastguard Worker  * This function is threadsafe.
109*5e7646d2SAndroid Build Coastguard Worker  *
110*5e7646d2SAndroid Build Coastguard Worker  * @since CUPS 2.0/OS 10.10@
111*5e7646d2SAndroid Build Coastguard Worker  */
112*5e7646d2SAndroid Build Coastguard Worker 
113*5e7646d2SAndroid Build Coastguard Worker int					/* O - 1 on success, 0 on failure */
cupsSetServerCredentials(const char * path,const char * common_name,int auto_create)114*5e7646d2SAndroid Build Coastguard Worker cupsSetServerCredentials(
115*5e7646d2SAndroid Build Coastguard Worker     const char *path,			/* I - Keychain path or @code NULL@ for default */
116*5e7646d2SAndroid Build Coastguard Worker     const char *common_name,		/* I - Default common name for server */
117*5e7646d2SAndroid Build Coastguard Worker     int        auto_create)		/* I - 1 = automatically create self-signed certificates */
118*5e7646d2SAndroid Build Coastguard Worker {
119*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("cupsSetServerCredentials(path=\"%s\", common_name=\"%s\", auto_create=%d)", path, common_name, auto_create));
120*5e7646d2SAndroid Build Coastguard Worker 
121*5e7646d2SAndroid Build Coastguard Worker   (void)path;
122*5e7646d2SAndroid Build Coastguard Worker   (void)common_name;
123*5e7646d2SAndroid Build Coastguard Worker   (void)auto_create;
124*5e7646d2SAndroid Build Coastguard Worker 
125*5e7646d2SAndroid Build Coastguard Worker   return (0);
126*5e7646d2SAndroid Build Coastguard Worker }
127*5e7646d2SAndroid Build Coastguard Worker 
128*5e7646d2SAndroid Build Coastguard Worker 
129*5e7646d2SAndroid Build Coastguard Worker /*
130*5e7646d2SAndroid Build Coastguard Worker  * 'httpCopyCredentials()' - Copy the credentials associated with the peer in
131*5e7646d2SAndroid Build Coastguard Worker  *                           an encrypted connection.
132*5e7646d2SAndroid Build Coastguard Worker  *
133*5e7646d2SAndroid Build Coastguard Worker  * @since CUPS 1.5/macOS 10.7@
134*5e7646d2SAndroid Build Coastguard Worker  */
135*5e7646d2SAndroid Build Coastguard Worker 
136*5e7646d2SAndroid Build Coastguard Worker int					/* O - Status of call (0 = success) */
httpCopyCredentials(http_t * http,cups_array_t ** credentials)137*5e7646d2SAndroid Build Coastguard Worker httpCopyCredentials(
138*5e7646d2SAndroid Build Coastguard Worker     http_t	 *http,			/* I - Connection to server */
139*5e7646d2SAndroid Build Coastguard Worker     cups_array_t **credentials)		/* O - Array of credentials */
140*5e7646d2SAndroid Build Coastguard Worker {
141*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("httpCopyCredentials(http=%p, credentials=%p)", http, credentials));
142*5e7646d2SAndroid Build Coastguard Worker 
143*5e7646d2SAndroid Build Coastguard Worker   if (!http || !http->tls || !http->tls->remoteCert || !credentials)
144*5e7646d2SAndroid Build Coastguard Worker   {
145*5e7646d2SAndroid Build Coastguard Worker     if (credentials)
146*5e7646d2SAndroid Build Coastguard Worker       *credentials = NULL;
147*5e7646d2SAndroid Build Coastguard Worker 
148*5e7646d2SAndroid Build Coastguard Worker     return (-1);
149*5e7646d2SAndroid Build Coastguard Worker   }
150*5e7646d2SAndroid Build Coastguard Worker 
151*5e7646d2SAndroid Build Coastguard Worker   *credentials = cupsArrayNew(NULL, NULL);
152*5e7646d2SAndroid Build Coastguard Worker   httpAddCredential(*credentials, http->tls->remoteCert->pbCertEncoded, http->tls->remoteCert->cbCertEncoded);
153*5e7646d2SAndroid Build Coastguard Worker 
154*5e7646d2SAndroid Build Coastguard Worker   return (0);
155*5e7646d2SAndroid Build Coastguard Worker }
156*5e7646d2SAndroid Build Coastguard Worker 
157*5e7646d2SAndroid Build Coastguard Worker 
158*5e7646d2SAndroid Build Coastguard Worker /*
159*5e7646d2SAndroid Build Coastguard Worker  * '_httpCreateCredentials()' - Create credentials in the internal format.
160*5e7646d2SAndroid Build Coastguard Worker  */
161*5e7646d2SAndroid Build Coastguard Worker 
162*5e7646d2SAndroid Build Coastguard Worker http_tls_credentials_t			/* O - Internal credentials */
_httpCreateCredentials(cups_array_t * credentials)163*5e7646d2SAndroid Build Coastguard Worker _httpCreateCredentials(
164*5e7646d2SAndroid Build Coastguard Worker     cups_array_t *credentials)		/* I - Array of credentials */
165*5e7646d2SAndroid Build Coastguard Worker {
166*5e7646d2SAndroid Build Coastguard Worker   return (http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials)));
167*5e7646d2SAndroid Build Coastguard Worker }
168*5e7646d2SAndroid Build Coastguard Worker 
169*5e7646d2SAndroid Build Coastguard Worker 
170*5e7646d2SAndroid Build Coastguard Worker /*
171*5e7646d2SAndroid Build Coastguard Worker  * 'httpCredentialsAreValidForName()' - Return whether the credentials are valid for the given name.
172*5e7646d2SAndroid Build Coastguard Worker  *
173*5e7646d2SAndroid Build Coastguard Worker  * @since CUPS 2.0/OS 10.10@
174*5e7646d2SAndroid Build Coastguard Worker  */
175*5e7646d2SAndroid Build Coastguard Worker 
176*5e7646d2SAndroid Build Coastguard Worker int					/* O - 1 if valid, 0 otherwise */
httpCredentialsAreValidForName(cups_array_t * credentials,const char * common_name)177*5e7646d2SAndroid Build Coastguard Worker httpCredentialsAreValidForName(
178*5e7646d2SAndroid Build Coastguard Worker     cups_array_t *credentials,		/* I - Credentials */
179*5e7646d2SAndroid Build Coastguard Worker     const char   *common_name)		/* I - Name to check */
180*5e7646d2SAndroid Build Coastguard Worker {
181*5e7646d2SAndroid Build Coastguard Worker   int		valid = 1;		/* Valid name? */
182*5e7646d2SAndroid Build Coastguard Worker   PCCERT_CONTEXT cert = http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials));
183*5e7646d2SAndroid Build Coastguard Worker 					/* Certificate */
184*5e7646d2SAndroid Build Coastguard Worker   char		cert_name[1024];	/* Name from certificate */
185*5e7646d2SAndroid Build Coastguard Worker 
186*5e7646d2SAndroid Build Coastguard Worker 
187*5e7646d2SAndroid Build Coastguard Worker   if (cert)
188*5e7646d2SAndroid Build Coastguard Worker   {
189*5e7646d2SAndroid Build Coastguard Worker     if (CertNameToStrA(X509_ASN_ENCODING, &(cert->pCertInfo->Subject), CERT_SIMPLE_NAME_STR, cert_name, sizeof(cert_name)))
190*5e7646d2SAndroid Build Coastguard Worker     {
191*5e7646d2SAndroid Build Coastguard Worker      /*
192*5e7646d2SAndroid Build Coastguard Worker       * Extract common name at end...
193*5e7646d2SAndroid Build Coastguard Worker       */
194*5e7646d2SAndroid Build Coastguard Worker 
195*5e7646d2SAndroid Build Coastguard Worker       char  *ptr = strrchr(cert_name, ',');
196*5e7646d2SAndroid Build Coastguard Worker       if (ptr && ptr[1])
197*5e7646d2SAndroid Build Coastguard Worker         _cups_strcpy(cert_name, ptr + 2);
198*5e7646d2SAndroid Build Coastguard Worker     }
199*5e7646d2SAndroid Build Coastguard Worker     else
200*5e7646d2SAndroid Build Coastguard Worker       strlcpy(cert_name, "unknown", sizeof(cert_name));
201*5e7646d2SAndroid Build Coastguard Worker 
202*5e7646d2SAndroid Build Coastguard Worker     CertFreeCertificateContext(cert);
203*5e7646d2SAndroid Build Coastguard Worker   }
204*5e7646d2SAndroid Build Coastguard Worker   else
205*5e7646d2SAndroid Build Coastguard Worker     strlcpy(cert_name, "unknown", sizeof(cert_name));
206*5e7646d2SAndroid Build Coastguard Worker 
207*5e7646d2SAndroid Build Coastguard Worker  /*
208*5e7646d2SAndroid Build Coastguard Worker   * Compare the common names...
209*5e7646d2SAndroid Build Coastguard Worker   */
210*5e7646d2SAndroid Build Coastguard Worker 
211*5e7646d2SAndroid Build Coastguard Worker   if (_cups_strcasecmp(common_name, cert_name))
212*5e7646d2SAndroid Build Coastguard Worker   {
213*5e7646d2SAndroid Build Coastguard Worker    /*
214*5e7646d2SAndroid Build Coastguard Worker     * Not an exact match for the common name, check for wildcard certs...
215*5e7646d2SAndroid Build Coastguard Worker     */
216*5e7646d2SAndroid Build Coastguard Worker 
217*5e7646d2SAndroid Build Coastguard Worker     const char	*domain = strchr(common_name, '.');
218*5e7646d2SAndroid Build Coastguard Worker 					/* Domain in common name */
219*5e7646d2SAndroid Build Coastguard Worker 
220*5e7646d2SAndroid Build Coastguard Worker     if (strncmp(cert_name, "*.", 2) || !domain || _cups_strcasecmp(domain, cert_name + 1))
221*5e7646d2SAndroid Build Coastguard Worker     {
222*5e7646d2SAndroid Build Coastguard Worker      /*
223*5e7646d2SAndroid Build Coastguard Worker       * Not a wildcard match.
224*5e7646d2SAndroid Build Coastguard Worker       */
225*5e7646d2SAndroid Build Coastguard Worker 
226*5e7646d2SAndroid Build Coastguard Worker       /* TODO: Check subject alternate names */
227*5e7646d2SAndroid Build Coastguard Worker       valid = 0;
228*5e7646d2SAndroid Build Coastguard Worker     }
229*5e7646d2SAndroid Build Coastguard Worker   }
230*5e7646d2SAndroid Build Coastguard Worker 
231*5e7646d2SAndroid Build Coastguard Worker   return (valid);
232*5e7646d2SAndroid Build Coastguard Worker }
233*5e7646d2SAndroid Build Coastguard Worker 
234*5e7646d2SAndroid Build Coastguard Worker 
235*5e7646d2SAndroid Build Coastguard Worker /*
236*5e7646d2SAndroid Build Coastguard Worker  * 'httpCredentialsGetTrust()' - Return the trust of credentials.
237*5e7646d2SAndroid Build Coastguard Worker  *
238*5e7646d2SAndroid Build Coastguard Worker  * @since CUPS 2.0/OS 10.10@
239*5e7646d2SAndroid Build Coastguard Worker  */
240*5e7646d2SAndroid Build Coastguard Worker 
241*5e7646d2SAndroid Build Coastguard Worker http_trust_t				/* O - Level of trust */
httpCredentialsGetTrust(cups_array_t * credentials,const char * common_name)242*5e7646d2SAndroid Build Coastguard Worker httpCredentialsGetTrust(
243*5e7646d2SAndroid Build Coastguard Worker     cups_array_t *credentials,		/* I - Credentials */
244*5e7646d2SAndroid Build Coastguard Worker     const char   *common_name)		/* I - Common name for trust lookup */
245*5e7646d2SAndroid Build Coastguard Worker {
246*5e7646d2SAndroid Build Coastguard Worker   http_trust_t	trust = HTTP_TRUST_OK;	/* Level of trust */
247*5e7646d2SAndroid Build Coastguard Worker   PCCERT_CONTEXT cert = NULL;		/* Certificate to validate */
248*5e7646d2SAndroid Build Coastguard Worker   DWORD		certFlags = 0;		/* Cert verification flags */
249*5e7646d2SAndroid Build Coastguard Worker   _cups_globals_t *cg = _cupsGlobals();	/* Per-thread global data */
250*5e7646d2SAndroid Build Coastguard Worker 
251*5e7646d2SAndroid Build Coastguard Worker 
252*5e7646d2SAndroid Build Coastguard Worker   if (!common_name)
253*5e7646d2SAndroid Build Coastguard Worker     return (HTTP_TRUST_UNKNOWN);
254*5e7646d2SAndroid Build Coastguard Worker 
255*5e7646d2SAndroid Build Coastguard Worker   cert = http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials));
256*5e7646d2SAndroid Build Coastguard Worker   if (!cert)
257*5e7646d2SAndroid Build Coastguard Worker     return (HTTP_TRUST_UNKNOWN);
258*5e7646d2SAndroid Build Coastguard Worker 
259*5e7646d2SAndroid Build Coastguard Worker   if (cg->any_root < 0)
260*5e7646d2SAndroid Build Coastguard Worker     _cupsSetDefaults();
261*5e7646d2SAndroid Build Coastguard Worker 
262*5e7646d2SAndroid Build Coastguard Worker   if (cg->any_root)
263*5e7646d2SAndroid Build Coastguard Worker     certFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA;
264*5e7646d2SAndroid Build Coastguard Worker 
265*5e7646d2SAndroid Build Coastguard Worker   if (cg->expired_certs)
266*5e7646d2SAndroid Build Coastguard Worker     certFlags |= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
267*5e7646d2SAndroid Build Coastguard Worker 
268*5e7646d2SAndroid Build Coastguard Worker   if (!cg->validate_certs)
269*5e7646d2SAndroid Build Coastguard Worker     certFlags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID;
270*5e7646d2SAndroid Build Coastguard Worker 
271*5e7646d2SAndroid Build Coastguard Worker   if (http_sspi_verify(cert, common_name, certFlags) != SEC_E_OK)
272*5e7646d2SAndroid Build Coastguard Worker     trust = HTTP_TRUST_INVALID;
273*5e7646d2SAndroid Build Coastguard Worker 
274*5e7646d2SAndroid Build Coastguard Worker   CertFreeCertificateContext(cert);
275*5e7646d2SAndroid Build Coastguard Worker 
276*5e7646d2SAndroid Build Coastguard Worker   return (trust);
277*5e7646d2SAndroid Build Coastguard Worker }
278*5e7646d2SAndroid Build Coastguard Worker 
279*5e7646d2SAndroid Build Coastguard Worker 
280*5e7646d2SAndroid Build Coastguard Worker /*
281*5e7646d2SAndroid Build Coastguard Worker  * 'httpCredentialsGetExpiration()' - Return the expiration date of the credentials.
282*5e7646d2SAndroid Build Coastguard Worker  *
283*5e7646d2SAndroid Build Coastguard Worker  * @since CUPS 2.0/OS 10.10@
284*5e7646d2SAndroid Build Coastguard Worker  */
285*5e7646d2SAndroid Build Coastguard Worker 
286*5e7646d2SAndroid Build Coastguard Worker time_t					/* O - Expiration date of credentials */
httpCredentialsGetExpiration(cups_array_t * credentials)287*5e7646d2SAndroid Build Coastguard Worker httpCredentialsGetExpiration(
288*5e7646d2SAndroid Build Coastguard Worker     cups_array_t *credentials)		/* I - Credentials */
289*5e7646d2SAndroid Build Coastguard Worker {
290*5e7646d2SAndroid Build Coastguard Worker   time_t	expiration_date = 0;	/* Expiration data of credentials */
291*5e7646d2SAndroid Build Coastguard Worker   PCCERT_CONTEXT cert = http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials));
292*5e7646d2SAndroid Build Coastguard Worker 					/* Certificate */
293*5e7646d2SAndroid Build Coastguard Worker 
294*5e7646d2SAndroid Build Coastguard Worker   if (cert)
295*5e7646d2SAndroid Build Coastguard Worker   {
296*5e7646d2SAndroid Build Coastguard Worker     SYSTEMTIME	systime;		/* System time */
297*5e7646d2SAndroid Build Coastguard Worker     struct tm	tm;			/* UNIX date/time */
298*5e7646d2SAndroid Build Coastguard Worker 
299*5e7646d2SAndroid Build Coastguard Worker     FileTimeToSystemTime(&(cert->pCertInfo->NotAfter), &systime);
300*5e7646d2SAndroid Build Coastguard Worker 
301*5e7646d2SAndroid Build Coastguard Worker     tm.tm_year = systime.wYear - 1900;
302*5e7646d2SAndroid Build Coastguard Worker     tm.tm_mon  = systime.wMonth - 1;
303*5e7646d2SAndroid Build Coastguard Worker     tm.tm_mday = systime.wDay;
304*5e7646d2SAndroid Build Coastguard Worker     tm.tm_hour = systime.wHour;
305*5e7646d2SAndroid Build Coastguard Worker     tm.tm_min  = systime.wMinute;
306*5e7646d2SAndroid Build Coastguard Worker     tm.tm_sec  = systime.wSecond;
307*5e7646d2SAndroid Build Coastguard Worker 
308*5e7646d2SAndroid Build Coastguard Worker     expiration_date = mktime(&tm);
309*5e7646d2SAndroid Build Coastguard Worker 
310*5e7646d2SAndroid Build Coastguard Worker     CertFreeCertificateContext(cert);
311*5e7646d2SAndroid Build Coastguard Worker   }
312*5e7646d2SAndroid Build Coastguard Worker 
313*5e7646d2SAndroid Build Coastguard Worker   return (expiration_date);
314*5e7646d2SAndroid Build Coastguard Worker }
315*5e7646d2SAndroid Build Coastguard Worker 
316*5e7646d2SAndroid Build Coastguard Worker 
317*5e7646d2SAndroid Build Coastguard Worker /*
318*5e7646d2SAndroid Build Coastguard Worker  * 'httpCredentialsString()' - Return a string representing the credentials.
319*5e7646d2SAndroid Build Coastguard Worker  *
320*5e7646d2SAndroid Build Coastguard Worker  * @since CUPS 2.0/OS 10.10@
321*5e7646d2SAndroid Build Coastguard Worker  */
322*5e7646d2SAndroid Build Coastguard Worker 
323*5e7646d2SAndroid Build Coastguard Worker size_t					/* O - Total size of credentials string */
httpCredentialsString(cups_array_t * credentials,char * buffer,size_t bufsize)324*5e7646d2SAndroid Build Coastguard Worker httpCredentialsString(
325*5e7646d2SAndroid Build Coastguard Worker     cups_array_t *credentials,		/* I - Credentials */
326*5e7646d2SAndroid Build Coastguard Worker     char         *buffer,		/* I - Buffer or @code NULL@ */
327*5e7646d2SAndroid Build Coastguard Worker     size_t       bufsize)		/* I - Size of buffer */
328*5e7646d2SAndroid Build Coastguard Worker {
329*5e7646d2SAndroid Build Coastguard Worker   http_credential_t	*first = (http_credential_t *)cupsArrayFirst(credentials);
330*5e7646d2SAndroid Build Coastguard Worker 					/* First certificate */
331*5e7646d2SAndroid Build Coastguard Worker   PCCERT_CONTEXT 	cert;		/* Certificate */
332*5e7646d2SAndroid Build Coastguard Worker 
333*5e7646d2SAndroid Build Coastguard Worker 
334*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("httpCredentialsString(credentials=%p, buffer=%p, bufsize=" CUPS_LLFMT ")", credentials, buffer, CUPS_LLCAST bufsize));
335*5e7646d2SAndroid Build Coastguard Worker 
336*5e7646d2SAndroid Build Coastguard Worker   if (!buffer)
337*5e7646d2SAndroid Build Coastguard Worker     return (0);
338*5e7646d2SAndroid Build Coastguard Worker 
339*5e7646d2SAndroid Build Coastguard Worker   if (buffer && bufsize > 0)
340*5e7646d2SAndroid Build Coastguard Worker     *buffer = '\0';
341*5e7646d2SAndroid Build Coastguard Worker 
342*5e7646d2SAndroid Build Coastguard Worker   cert = http_sspi_create_credential(first);
343*5e7646d2SAndroid Build Coastguard Worker 
344*5e7646d2SAndroid Build Coastguard Worker   if (cert)
345*5e7646d2SAndroid Build Coastguard Worker   {
346*5e7646d2SAndroid Build Coastguard Worker     char		cert_name[256];	/* Common name */
347*5e7646d2SAndroid Build Coastguard Worker     SYSTEMTIME		systime;	/* System time */
348*5e7646d2SAndroid Build Coastguard Worker     struct tm		tm;		/* UNIX date/time */
349*5e7646d2SAndroid Build Coastguard Worker     time_t		expiration;	/* Expiration date of cert */
350*5e7646d2SAndroid Build Coastguard Worker     unsigned char	md5_digest[16];	/* MD5 result */
351*5e7646d2SAndroid Build Coastguard Worker 
352*5e7646d2SAndroid Build Coastguard Worker     FileTimeToSystemTime(&(cert->pCertInfo->NotAfter), &systime);
353*5e7646d2SAndroid Build Coastguard Worker 
354*5e7646d2SAndroid Build Coastguard Worker     tm.tm_year = systime.wYear - 1900;
355*5e7646d2SAndroid Build Coastguard Worker     tm.tm_mon  = systime.wMonth - 1;
356*5e7646d2SAndroid Build Coastguard Worker     tm.tm_mday = systime.wDay;
357*5e7646d2SAndroid Build Coastguard Worker     tm.tm_hour = systime.wHour;
358*5e7646d2SAndroid Build Coastguard Worker     tm.tm_min  = systime.wMinute;
359*5e7646d2SAndroid Build Coastguard Worker     tm.tm_sec  = systime.wSecond;
360*5e7646d2SAndroid Build Coastguard Worker 
361*5e7646d2SAndroid Build Coastguard Worker     expiration = mktime(&tm);
362*5e7646d2SAndroid Build Coastguard Worker 
363*5e7646d2SAndroid Build Coastguard Worker     if (CertNameToStrA(X509_ASN_ENCODING, &(cert->pCertInfo->Subject), CERT_SIMPLE_NAME_STR, cert_name, sizeof(cert_name)))
364*5e7646d2SAndroid Build Coastguard Worker     {
365*5e7646d2SAndroid Build Coastguard Worker      /*
366*5e7646d2SAndroid Build Coastguard Worker       * Extract common name at end...
367*5e7646d2SAndroid Build Coastguard Worker       */
368*5e7646d2SAndroid Build Coastguard Worker 
369*5e7646d2SAndroid Build Coastguard Worker       char  *ptr = strrchr(cert_name, ',');
370*5e7646d2SAndroid Build Coastguard Worker       if (ptr && ptr[1])
371*5e7646d2SAndroid Build Coastguard Worker         _cups_strcpy(cert_name, ptr + 2);
372*5e7646d2SAndroid Build Coastguard Worker     }
373*5e7646d2SAndroid Build Coastguard Worker     else
374*5e7646d2SAndroid Build Coastguard Worker       strlcpy(cert_name, "unknown", sizeof(cert_name));
375*5e7646d2SAndroid Build Coastguard Worker 
376*5e7646d2SAndroid Build Coastguard Worker     cupsHashData("md5", first->data, first->datalen, md5_digest, sizeof(md5_digest));
377*5e7646d2SAndroid Build Coastguard Worker 
378*5e7646d2SAndroid Build Coastguard Worker     snprintf(buffer, bufsize, "%s / %s / %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", cert_name, httpGetDateString(expiration), md5_digest[0], md5_digest[1], md5_digest[2], md5_digest[3], md5_digest[4], md5_digest[5], md5_digest[6], md5_digest[7], md5_digest[8], md5_digest[9], md5_digest[10], md5_digest[11], md5_digest[12], md5_digest[13], md5_digest[14], md5_digest[15]);
379*5e7646d2SAndroid Build Coastguard Worker 
380*5e7646d2SAndroid Build Coastguard Worker     CertFreeCertificateContext(cert);
381*5e7646d2SAndroid Build Coastguard Worker   }
382*5e7646d2SAndroid Build Coastguard Worker 
383*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("1httpCredentialsString: Returning \"%s\".", buffer));
384*5e7646d2SAndroid Build Coastguard Worker 
385*5e7646d2SAndroid Build Coastguard Worker   return (strlen(buffer));
386*5e7646d2SAndroid Build Coastguard Worker }
387*5e7646d2SAndroid Build Coastguard Worker 
388*5e7646d2SAndroid Build Coastguard Worker 
389*5e7646d2SAndroid Build Coastguard Worker /*
390*5e7646d2SAndroid Build Coastguard Worker  * '_httpFreeCredentials()' - Free internal credentials.
391*5e7646d2SAndroid Build Coastguard Worker  */
392*5e7646d2SAndroid Build Coastguard Worker 
393*5e7646d2SAndroid Build Coastguard Worker void
_httpFreeCredentials(http_tls_credentials_t credentials)394*5e7646d2SAndroid Build Coastguard Worker _httpFreeCredentials(
395*5e7646d2SAndroid Build Coastguard Worker     http_tls_credentials_t credentials)	/* I - Internal credentials */
396*5e7646d2SAndroid Build Coastguard Worker {
397*5e7646d2SAndroid Build Coastguard Worker   if (!credentials)
398*5e7646d2SAndroid Build Coastguard Worker     return;
399*5e7646d2SAndroid Build Coastguard Worker 
400*5e7646d2SAndroid Build Coastguard Worker   CertFreeCertificateContext(credentials);
401*5e7646d2SAndroid Build Coastguard Worker }
402*5e7646d2SAndroid Build Coastguard Worker 
403*5e7646d2SAndroid Build Coastguard Worker 
404*5e7646d2SAndroid Build Coastguard Worker /*
405*5e7646d2SAndroid Build Coastguard Worker  * 'httpLoadCredentials()' - Load X.509 credentials from a keychain file.
406*5e7646d2SAndroid Build Coastguard Worker  *
407*5e7646d2SAndroid Build Coastguard Worker  * @since CUPS 2.0/OS 10.10@
408*5e7646d2SAndroid Build Coastguard Worker  */
409*5e7646d2SAndroid Build Coastguard Worker 
410*5e7646d2SAndroid Build Coastguard Worker int					/* O - 0 on success, -1 on error */
httpLoadCredentials(const char * path,cups_array_t ** credentials,const char * common_name)411*5e7646d2SAndroid Build Coastguard Worker httpLoadCredentials(
412*5e7646d2SAndroid Build Coastguard Worker     const char   *path,			/* I  - Keychain path or @code NULL@ for default */
413*5e7646d2SAndroid Build Coastguard Worker     cups_array_t **credentials,		/* IO - Credentials */
414*5e7646d2SAndroid Build Coastguard Worker     const char   *common_name)		/* I  - Common name for credentials */
415*5e7646d2SAndroid Build Coastguard Worker {
416*5e7646d2SAndroid Build Coastguard Worker   HCERTSTORE	store = NULL;		/* Certificate store */
417*5e7646d2SAndroid Build Coastguard Worker   PCCERT_CONTEXT storedContext = NULL;	/* Context created from the store */
418*5e7646d2SAndroid Build Coastguard Worker   DWORD		dwSize = 0; 		/* 32 bit size */
419*5e7646d2SAndroid Build Coastguard Worker   PBYTE		p = NULL;		/* Temporary storage */
420*5e7646d2SAndroid Build Coastguard Worker   HCRYPTPROV	hProv = (HCRYPTPROV)NULL;
421*5e7646d2SAndroid Build Coastguard Worker 					/* Handle to a CSP */
422*5e7646d2SAndroid Build Coastguard Worker   CERT_NAME_BLOB sib;			/* Arbitrary array of bytes */
423*5e7646d2SAndroid Build Coastguard Worker #ifdef DEBUG
424*5e7646d2SAndroid Build Coastguard Worker   char		error[1024];		/* Error message buffer */
425*5e7646d2SAndroid Build Coastguard Worker #endif /* DEBUG */
426*5e7646d2SAndroid Build Coastguard Worker 
427*5e7646d2SAndroid Build Coastguard Worker 
428*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("httpLoadCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path, credentials, common_name));
429*5e7646d2SAndroid Build Coastguard Worker 
430*5e7646d2SAndroid Build Coastguard Worker   (void)path;
431*5e7646d2SAndroid Build Coastguard Worker 
432*5e7646d2SAndroid Build Coastguard Worker   if (credentials)
433*5e7646d2SAndroid Build Coastguard Worker   {
434*5e7646d2SAndroid Build Coastguard Worker     *credentials = NULL;
435*5e7646d2SAndroid Build Coastguard Worker   }
436*5e7646d2SAndroid Build Coastguard Worker   else
437*5e7646d2SAndroid Build Coastguard Worker   {
438*5e7646d2SAndroid Build Coastguard Worker     DEBUG_puts("1httpLoadCredentials: NULL credentials pointer, returning -1.");
439*5e7646d2SAndroid Build Coastguard Worker     return (-1);
440*5e7646d2SAndroid Build Coastguard Worker   }
441*5e7646d2SAndroid Build Coastguard Worker 
442*5e7646d2SAndroid Build Coastguard Worker   if (!common_name)
443*5e7646d2SAndroid Build Coastguard Worker   {
444*5e7646d2SAndroid Build Coastguard Worker     DEBUG_puts("1httpLoadCredentials: Bad common name, returning -1.");
445*5e7646d2SAndroid Build Coastguard Worker     return (-1);
446*5e7646d2SAndroid Build Coastguard Worker   }
447*5e7646d2SAndroid Build Coastguard Worker 
448*5e7646d2SAndroid Build Coastguard Worker   if (!CryptAcquireContextW(&hProv, L"RememberedContainer", MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET))
449*5e7646d2SAndroid Build Coastguard Worker   {
450*5e7646d2SAndroid Build Coastguard Worker     if (GetLastError() == NTE_EXISTS)
451*5e7646d2SAndroid Build Coastguard Worker     {
452*5e7646d2SAndroid Build Coastguard Worker       if (!CryptAcquireContextW(&hProv, L"RememberedContainer", MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
453*5e7646d2SAndroid Build Coastguard Worker       {
454*5e7646d2SAndroid Build Coastguard Worker         DEBUG_printf(("1httpLoadCredentials: CryptAcquireContext failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
455*5e7646d2SAndroid Build Coastguard Worker         goto cleanup;
456*5e7646d2SAndroid Build Coastguard Worker       }
457*5e7646d2SAndroid Build Coastguard Worker     }
458*5e7646d2SAndroid Build Coastguard Worker   }
459*5e7646d2SAndroid Build Coastguard Worker 
460*5e7646d2SAndroid Build Coastguard Worker   store = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING, hProv, CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_NO_CRYPT_RELEASE_FLAG | CERT_STORE_OPEN_EXISTING_FLAG, L"MY");
461*5e7646d2SAndroid Build Coastguard Worker 
462*5e7646d2SAndroid Build Coastguard Worker   if (!store)
463*5e7646d2SAndroid Build Coastguard Worker   {
464*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("1httpLoadCredentials: CertOpenSystemStore failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
465*5e7646d2SAndroid Build Coastguard Worker     goto cleanup;
466*5e7646d2SAndroid Build Coastguard Worker   }
467*5e7646d2SAndroid Build Coastguard Worker 
468*5e7646d2SAndroid Build Coastguard Worker   dwSize = 0;
469*5e7646d2SAndroid Build Coastguard Worker 
470*5e7646d2SAndroid Build Coastguard Worker   if (!CertStrToNameA(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL))
471*5e7646d2SAndroid Build Coastguard Worker   {
472*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("1httpLoadCredentials: CertStrToName failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
473*5e7646d2SAndroid Build Coastguard Worker     goto cleanup;
474*5e7646d2SAndroid Build Coastguard Worker   }
475*5e7646d2SAndroid Build Coastguard Worker 
476*5e7646d2SAndroid Build Coastguard Worker   p = (PBYTE)malloc(dwSize);
477*5e7646d2SAndroid Build Coastguard Worker 
478*5e7646d2SAndroid Build Coastguard Worker   if (!p)
479*5e7646d2SAndroid Build Coastguard Worker   {
480*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("1httpLoadCredentials: malloc failed for %d bytes.", dwSize));
481*5e7646d2SAndroid Build Coastguard Worker     goto cleanup;
482*5e7646d2SAndroid Build Coastguard Worker   }
483*5e7646d2SAndroid Build Coastguard Worker 
484*5e7646d2SAndroid Build Coastguard Worker   if (!CertStrToNameA(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL))
485*5e7646d2SAndroid Build Coastguard Worker   {
486*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("1httpLoadCredentials: CertStrToName failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
487*5e7646d2SAndroid Build Coastguard Worker     goto cleanup;
488*5e7646d2SAndroid Build Coastguard Worker   }
489*5e7646d2SAndroid Build Coastguard Worker 
490*5e7646d2SAndroid Build Coastguard Worker   sib.cbData = dwSize;
491*5e7646d2SAndroid Build Coastguard Worker   sib.pbData = p;
492*5e7646d2SAndroid Build Coastguard Worker 
493*5e7646d2SAndroid Build Coastguard Worker   storedContext = CertFindCertificateInStore(store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_NAME, &sib, NULL);
494*5e7646d2SAndroid Build Coastguard Worker 
495*5e7646d2SAndroid Build Coastguard Worker   if (!storedContext)
496*5e7646d2SAndroid Build Coastguard Worker   {
497*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("1httpLoadCredentials: Unable to find credentials for \"%s\".", common_name));
498*5e7646d2SAndroid Build Coastguard Worker     goto cleanup;
499*5e7646d2SAndroid Build Coastguard Worker   }
500*5e7646d2SAndroid Build Coastguard Worker 
501*5e7646d2SAndroid Build Coastguard Worker   *credentials = cupsArrayNew(NULL, NULL);
502*5e7646d2SAndroid Build Coastguard Worker   httpAddCredential(*credentials, storedContext->pbCertEncoded, storedContext->cbCertEncoded);
503*5e7646d2SAndroid Build Coastguard Worker 
504*5e7646d2SAndroid Build Coastguard Worker cleanup:
505*5e7646d2SAndroid Build Coastguard Worker 
506*5e7646d2SAndroid Build Coastguard Worker  /*
507*5e7646d2SAndroid Build Coastguard Worker   * Cleanup
508*5e7646d2SAndroid Build Coastguard Worker   */
509*5e7646d2SAndroid Build Coastguard Worker 
510*5e7646d2SAndroid Build Coastguard Worker   if (storedContext)
511*5e7646d2SAndroid Build Coastguard Worker     CertFreeCertificateContext(storedContext);
512*5e7646d2SAndroid Build Coastguard Worker 
513*5e7646d2SAndroid Build Coastguard Worker   if (p)
514*5e7646d2SAndroid Build Coastguard Worker     free(p);
515*5e7646d2SAndroid Build Coastguard Worker 
516*5e7646d2SAndroid Build Coastguard Worker   if (store)
517*5e7646d2SAndroid Build Coastguard Worker     CertCloseStore(store, 0);
518*5e7646d2SAndroid Build Coastguard Worker 
519*5e7646d2SAndroid Build Coastguard Worker   if (hProv)
520*5e7646d2SAndroid Build Coastguard Worker     CryptReleaseContext(hProv, 0);
521*5e7646d2SAndroid Build Coastguard Worker 
522*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("1httpLoadCredentials: Returning %d.", *credentials ? 0 : -1));
523*5e7646d2SAndroid Build Coastguard Worker 
524*5e7646d2SAndroid Build Coastguard Worker   return (*credentials ? 0 : -1);
525*5e7646d2SAndroid Build Coastguard Worker }
526*5e7646d2SAndroid Build Coastguard Worker 
527*5e7646d2SAndroid Build Coastguard Worker 
528*5e7646d2SAndroid Build Coastguard Worker /*
529*5e7646d2SAndroid Build Coastguard Worker  * 'httpSaveCredentials()' - Save X.509 credentials to a keychain file.
530*5e7646d2SAndroid Build Coastguard Worker  *
531*5e7646d2SAndroid Build Coastguard Worker  * @since CUPS 2.0/OS 10.10@
532*5e7646d2SAndroid Build Coastguard Worker  */
533*5e7646d2SAndroid Build Coastguard Worker 
534*5e7646d2SAndroid Build Coastguard Worker int					/* O - -1 on error, 0 on success */
httpSaveCredentials(const char * path,cups_array_t * credentials,const char * common_name)535*5e7646d2SAndroid Build Coastguard Worker httpSaveCredentials(
536*5e7646d2SAndroid Build Coastguard Worker     const char   *path,			/* I - Keychain path or @code NULL@ for default */
537*5e7646d2SAndroid Build Coastguard Worker     cups_array_t *credentials,		/* I - Credentials */
538*5e7646d2SAndroid Build Coastguard Worker     const char   *common_name)		/* I - Common name for credentials */
539*5e7646d2SAndroid Build Coastguard Worker {
540*5e7646d2SAndroid Build Coastguard Worker   HCERTSTORE	store = NULL;		/* Certificate store */
541*5e7646d2SAndroid Build Coastguard Worker   PCCERT_CONTEXT storedContext = NULL;	/* Context created from the store */
542*5e7646d2SAndroid Build Coastguard Worker   PCCERT_CONTEXT createdContext = NULL;	/* Context created by us */
543*5e7646d2SAndroid Build Coastguard Worker   DWORD		dwSize = 0; 		/* 32 bit size */
544*5e7646d2SAndroid Build Coastguard Worker   PBYTE		p = NULL;		/* Temporary storage */
545*5e7646d2SAndroid Build Coastguard Worker   HCRYPTPROV	hProv = (HCRYPTPROV)NULL;
546*5e7646d2SAndroid Build Coastguard Worker 					/* Handle to a CSP */
547*5e7646d2SAndroid Build Coastguard Worker   CRYPT_KEY_PROV_INFO ckp;		/* Handle to crypto key */
548*5e7646d2SAndroid Build Coastguard Worker   int		ret = -1;		/* Return value */
549*5e7646d2SAndroid Build Coastguard Worker #ifdef DEBUG
550*5e7646d2SAndroid Build Coastguard Worker   char		error[1024];		/* Error message buffer */
551*5e7646d2SAndroid Build Coastguard Worker #endif /* DEBUG */
552*5e7646d2SAndroid Build Coastguard Worker 
553*5e7646d2SAndroid Build Coastguard Worker 
554*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("httpSaveCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path, credentials, common_name));
555*5e7646d2SAndroid Build Coastguard Worker 
556*5e7646d2SAndroid Build Coastguard Worker   (void)path;
557*5e7646d2SAndroid Build Coastguard Worker 
558*5e7646d2SAndroid Build Coastguard Worker   if (!common_name)
559*5e7646d2SAndroid Build Coastguard Worker   {
560*5e7646d2SAndroid Build Coastguard Worker     DEBUG_puts("1httpSaveCredentials: Bad common name, returning -1.");
561*5e7646d2SAndroid Build Coastguard Worker     return (-1);
562*5e7646d2SAndroid Build Coastguard Worker   }
563*5e7646d2SAndroid Build Coastguard Worker 
564*5e7646d2SAndroid Build Coastguard Worker   createdContext = http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials));
565*5e7646d2SAndroid Build Coastguard Worker   if (!createdContext)
566*5e7646d2SAndroid Build Coastguard Worker   {
567*5e7646d2SAndroid Build Coastguard Worker     DEBUG_puts("1httpSaveCredentials: Bad credentials, returning -1.");
568*5e7646d2SAndroid Build Coastguard Worker     return (-1);
569*5e7646d2SAndroid Build Coastguard Worker   }
570*5e7646d2SAndroid Build Coastguard Worker 
571*5e7646d2SAndroid Build Coastguard Worker   if (!CryptAcquireContextW(&hProv, L"RememberedContainer", MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET))
572*5e7646d2SAndroid Build Coastguard Worker   {
573*5e7646d2SAndroid Build Coastguard Worker     if (GetLastError() == NTE_EXISTS)
574*5e7646d2SAndroid Build Coastguard Worker     {
575*5e7646d2SAndroid Build Coastguard Worker       if (!CryptAcquireContextW(&hProv, L"RememberedContainer", MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
576*5e7646d2SAndroid Build Coastguard Worker       {
577*5e7646d2SAndroid Build Coastguard Worker         DEBUG_printf(("1httpSaveCredentials: CryptAcquireContext failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
578*5e7646d2SAndroid Build Coastguard Worker         goto cleanup;
579*5e7646d2SAndroid Build Coastguard Worker       }
580*5e7646d2SAndroid Build Coastguard Worker     }
581*5e7646d2SAndroid Build Coastguard Worker   }
582*5e7646d2SAndroid Build Coastguard Worker 
583*5e7646d2SAndroid Build Coastguard Worker   store = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING, hProv, CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_NO_CRYPT_RELEASE_FLAG | CERT_STORE_OPEN_EXISTING_FLAG, L"MY");
584*5e7646d2SAndroid Build Coastguard Worker 
585*5e7646d2SAndroid Build Coastguard Worker   if (!store)
586*5e7646d2SAndroid Build Coastguard Worker   {
587*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("1httpSaveCredentials: CertOpenSystemStore failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
588*5e7646d2SAndroid Build Coastguard Worker     goto cleanup;
589*5e7646d2SAndroid Build Coastguard Worker   }
590*5e7646d2SAndroid Build Coastguard Worker 
591*5e7646d2SAndroid Build Coastguard Worker   dwSize = 0;
592*5e7646d2SAndroid Build Coastguard Worker 
593*5e7646d2SAndroid Build Coastguard Worker   if (!CertStrToNameA(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL))
594*5e7646d2SAndroid Build Coastguard Worker   {
595*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("1httpSaveCredentials: CertStrToName failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
596*5e7646d2SAndroid Build Coastguard Worker     goto cleanup;
597*5e7646d2SAndroid Build Coastguard Worker   }
598*5e7646d2SAndroid Build Coastguard Worker 
599*5e7646d2SAndroid Build Coastguard Worker   p = (PBYTE)malloc(dwSize);
600*5e7646d2SAndroid Build Coastguard Worker 
601*5e7646d2SAndroid Build Coastguard Worker   if (!p)
602*5e7646d2SAndroid Build Coastguard Worker   {
603*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("1httpSaveCredentials: malloc failed for %d bytes.", dwSize));
604*5e7646d2SAndroid Build Coastguard Worker     goto cleanup;
605*5e7646d2SAndroid Build Coastguard Worker   }
606*5e7646d2SAndroid Build Coastguard Worker 
607*5e7646d2SAndroid Build Coastguard Worker   if (!CertStrToNameA(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL))
608*5e7646d2SAndroid Build Coastguard Worker   {
609*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("1httpSaveCredentials: CertStrToName failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
610*5e7646d2SAndroid Build Coastguard Worker     goto cleanup;
611*5e7646d2SAndroid Build Coastguard Worker   }
612*5e7646d2SAndroid Build Coastguard Worker 
613*5e7646d2SAndroid Build Coastguard Worker  /*
614*5e7646d2SAndroid Build Coastguard Worker   * Add the created context to the named store, and associate it with the named
615*5e7646d2SAndroid Build Coastguard Worker   * container...
616*5e7646d2SAndroid Build Coastguard Worker   */
617*5e7646d2SAndroid Build Coastguard Worker 
618*5e7646d2SAndroid Build Coastguard Worker   if (!CertAddCertificateContextToStore(store, createdContext, CERT_STORE_ADD_REPLACE_EXISTING, &storedContext))
619*5e7646d2SAndroid Build Coastguard Worker   {
620*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("1httpSaveCredentials: CertAddCertificateContextToStore failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
621*5e7646d2SAndroid Build Coastguard Worker     goto cleanup;
622*5e7646d2SAndroid Build Coastguard Worker   }
623*5e7646d2SAndroid Build Coastguard Worker 
624*5e7646d2SAndroid Build Coastguard Worker   ZeroMemory(&ckp, sizeof(ckp));
625*5e7646d2SAndroid Build Coastguard Worker   ckp.pwszContainerName = L"RememberedContainer";
626*5e7646d2SAndroid Build Coastguard Worker   ckp.pwszProvName      = MS_DEF_PROV_W;
627*5e7646d2SAndroid Build Coastguard Worker   ckp.dwProvType        = PROV_RSA_FULL;
628*5e7646d2SAndroid Build Coastguard Worker   ckp.dwFlags           = CRYPT_MACHINE_KEYSET;
629*5e7646d2SAndroid Build Coastguard Worker   ckp.dwKeySpec         = AT_KEYEXCHANGE;
630*5e7646d2SAndroid Build Coastguard Worker 
631*5e7646d2SAndroid Build Coastguard Worker   if (!CertSetCertificateContextProperty(storedContext, CERT_KEY_PROV_INFO_PROP_ID, 0, &ckp))
632*5e7646d2SAndroid Build Coastguard Worker   {
633*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("1httpSaveCredentials: CertSetCertificateContextProperty failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
634*5e7646d2SAndroid Build Coastguard Worker     goto cleanup;
635*5e7646d2SAndroid Build Coastguard Worker   }
636*5e7646d2SAndroid Build Coastguard Worker 
637*5e7646d2SAndroid Build Coastguard Worker   ret = 0;
638*5e7646d2SAndroid Build Coastguard Worker 
639*5e7646d2SAndroid Build Coastguard Worker cleanup:
640*5e7646d2SAndroid Build Coastguard Worker 
641*5e7646d2SAndroid Build Coastguard Worker  /*
642*5e7646d2SAndroid Build Coastguard Worker   * Cleanup
643*5e7646d2SAndroid Build Coastguard Worker   */
644*5e7646d2SAndroid Build Coastguard Worker 
645*5e7646d2SAndroid Build Coastguard Worker   if (createdContext)
646*5e7646d2SAndroid Build Coastguard Worker     CertFreeCertificateContext(createdContext);
647*5e7646d2SAndroid Build Coastguard Worker 
648*5e7646d2SAndroid Build Coastguard Worker   if (storedContext)
649*5e7646d2SAndroid Build Coastguard Worker     CertFreeCertificateContext(storedContext);
650*5e7646d2SAndroid Build Coastguard Worker 
651*5e7646d2SAndroid Build Coastguard Worker   if (p)
652*5e7646d2SAndroid Build Coastguard Worker     free(p);
653*5e7646d2SAndroid Build Coastguard Worker 
654*5e7646d2SAndroid Build Coastguard Worker   if (store)
655*5e7646d2SAndroid Build Coastguard Worker     CertCloseStore(store, 0);
656*5e7646d2SAndroid Build Coastguard Worker 
657*5e7646d2SAndroid Build Coastguard Worker   if (hProv)
658*5e7646d2SAndroid Build Coastguard Worker     CryptReleaseContext(hProv, 0);
659*5e7646d2SAndroid Build Coastguard Worker 
660*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("1httpSaveCredentials: Returning %d.", ret));
661*5e7646d2SAndroid Build Coastguard Worker   return (ret);
662*5e7646d2SAndroid Build Coastguard Worker }
663*5e7646d2SAndroid Build Coastguard Worker 
664*5e7646d2SAndroid Build Coastguard Worker 
665*5e7646d2SAndroid Build Coastguard Worker /*
666*5e7646d2SAndroid Build Coastguard Worker  * '_httpTLSInitialize()' - Initialize the TLS stack.
667*5e7646d2SAndroid Build Coastguard Worker  */
668*5e7646d2SAndroid Build Coastguard Worker 
669*5e7646d2SAndroid Build Coastguard Worker void
_httpTLSInitialize(void)670*5e7646d2SAndroid Build Coastguard Worker _httpTLSInitialize(void)
671*5e7646d2SAndroid Build Coastguard Worker {
672*5e7646d2SAndroid Build Coastguard Worker  /*
673*5e7646d2SAndroid Build Coastguard Worker   * Nothing to do...
674*5e7646d2SAndroid Build Coastguard Worker   */
675*5e7646d2SAndroid Build Coastguard Worker }
676*5e7646d2SAndroid Build Coastguard Worker 
677*5e7646d2SAndroid Build Coastguard Worker 
678*5e7646d2SAndroid Build Coastguard Worker /*
679*5e7646d2SAndroid Build Coastguard Worker  * '_httpTLSPending()' - Return the number of pending TLS-encrypted bytes.
680*5e7646d2SAndroid Build Coastguard Worker  */
681*5e7646d2SAndroid Build Coastguard Worker 
682*5e7646d2SAndroid Build Coastguard Worker size_t					/* O - Bytes available */
_httpTLSPending(http_t * http)683*5e7646d2SAndroid Build Coastguard Worker _httpTLSPending(http_t *http)		/* I - HTTP connection */
684*5e7646d2SAndroid Build Coastguard Worker {
685*5e7646d2SAndroid Build Coastguard Worker   if (http->tls)
686*5e7646d2SAndroid Build Coastguard Worker     return (http->tls->readBufferUsed);
687*5e7646d2SAndroid Build Coastguard Worker   else
688*5e7646d2SAndroid Build Coastguard Worker     return (0);
689*5e7646d2SAndroid Build Coastguard Worker }
690*5e7646d2SAndroid Build Coastguard Worker 
691*5e7646d2SAndroid Build Coastguard Worker 
692*5e7646d2SAndroid Build Coastguard Worker /*
693*5e7646d2SAndroid Build Coastguard Worker  * '_httpTLSRead()' - Read from a SSL/TLS connection.
694*5e7646d2SAndroid Build Coastguard Worker  */
695*5e7646d2SAndroid Build Coastguard Worker 
696*5e7646d2SAndroid Build Coastguard Worker int					/* O - Bytes read */
_httpTLSRead(http_t * http,char * buf,int len)697*5e7646d2SAndroid Build Coastguard Worker _httpTLSRead(http_t *http,		/* I - HTTP connection */
698*5e7646d2SAndroid Build Coastguard Worker 	     char   *buf,		/* I - Buffer to store data */
699*5e7646d2SAndroid Build Coastguard Worker 	     int    len)		/* I - Length of buffer */
700*5e7646d2SAndroid Build Coastguard Worker {
701*5e7646d2SAndroid Build Coastguard Worker   int		i;			/* Looping var */
702*5e7646d2SAndroid Build Coastguard Worker   _http_sspi_t	*sspi = http->tls;	/* SSPI data */
703*5e7646d2SAndroid Build Coastguard Worker   SecBufferDesc	message;		/* Array of SecBuffer struct */
704*5e7646d2SAndroid Build Coastguard Worker   SecBuffer	buffers[4] = { 0 };	/* Security package buffer */
705*5e7646d2SAndroid Build Coastguard Worker   int		num = 0;		/* Return value */
706*5e7646d2SAndroid Build Coastguard Worker   PSecBuffer	pDataBuffer;		/* Data buffer */
707*5e7646d2SAndroid Build Coastguard Worker   PSecBuffer	pExtraBuffer;		/* Excess data buffer */
708*5e7646d2SAndroid Build Coastguard Worker   SECURITY_STATUS scRet;		/* SSPI status */
709*5e7646d2SAndroid Build Coastguard Worker 
710*5e7646d2SAndroid Build Coastguard Worker 
711*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("4_httpTLSRead(http=%p, buf=%p, len=%d)", http, buf, len));
712*5e7646d2SAndroid Build Coastguard Worker 
713*5e7646d2SAndroid Build Coastguard Worker  /*
714*5e7646d2SAndroid Build Coastguard Worker   * If there are bytes that have already been decrypted and have not yet been
715*5e7646d2SAndroid Build Coastguard Worker   * read, return those...
716*5e7646d2SAndroid Build Coastguard Worker   */
717*5e7646d2SAndroid Build Coastguard Worker 
718*5e7646d2SAndroid Build Coastguard Worker   if (sspi->readBufferUsed > 0)
719*5e7646d2SAndroid Build Coastguard Worker   {
720*5e7646d2SAndroid Build Coastguard Worker     int bytesToCopy = min(sspi->readBufferUsed, len);
721*5e7646d2SAndroid Build Coastguard Worker 					/* Number of bytes to copy */
722*5e7646d2SAndroid Build Coastguard Worker 
723*5e7646d2SAndroid Build Coastguard Worker     memcpy(buf, sspi->readBuffer, bytesToCopy);
724*5e7646d2SAndroid Build Coastguard Worker     sspi->readBufferUsed -= bytesToCopy;
725*5e7646d2SAndroid Build Coastguard Worker 
726*5e7646d2SAndroid Build Coastguard Worker     if (sspi->readBufferUsed > 0)
727*5e7646d2SAndroid Build Coastguard Worker       memmove(sspi->readBuffer, sspi->readBuffer + bytesToCopy, sspi->readBufferUsed);
728*5e7646d2SAndroid Build Coastguard Worker 
729*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("5_httpTLSRead: Returning %d bytes previously decrypted.", bytesToCopy));
730*5e7646d2SAndroid Build Coastguard Worker 
731*5e7646d2SAndroid Build Coastguard Worker     return (bytesToCopy);
732*5e7646d2SAndroid Build Coastguard Worker   }
733*5e7646d2SAndroid Build Coastguard Worker 
734*5e7646d2SAndroid Build Coastguard Worker  /*
735*5e7646d2SAndroid Build Coastguard Worker   * Initialize security buffer structs
736*5e7646d2SAndroid Build Coastguard Worker   */
737*5e7646d2SAndroid Build Coastguard Worker 
738*5e7646d2SAndroid Build Coastguard Worker   message.ulVersion = SECBUFFER_VERSION;
739*5e7646d2SAndroid Build Coastguard Worker   message.cBuffers  = 4;
740*5e7646d2SAndroid Build Coastguard Worker   message.pBuffers  = buffers;
741*5e7646d2SAndroid Build Coastguard Worker 
742*5e7646d2SAndroid Build Coastguard Worker   do
743*5e7646d2SAndroid Build Coastguard Worker   {
744*5e7646d2SAndroid Build Coastguard Worker    /*
745*5e7646d2SAndroid Build Coastguard Worker     * If there is not enough space in the buffer, then increase its size...
746*5e7646d2SAndroid Build Coastguard Worker     */
747*5e7646d2SAndroid Build Coastguard Worker 
748*5e7646d2SAndroid Build Coastguard Worker     if (sspi->decryptBufferLength <= sspi->decryptBufferUsed)
749*5e7646d2SAndroid Build Coastguard Worker     {
750*5e7646d2SAndroid Build Coastguard Worker       BYTE *temp;			/* New buffer */
751*5e7646d2SAndroid Build Coastguard Worker 
752*5e7646d2SAndroid Build Coastguard Worker       if (sspi->decryptBufferLength >= 262144)
753*5e7646d2SAndroid Build Coastguard Worker       {
754*5e7646d2SAndroid Build Coastguard Worker 	WSASetLastError(E_OUTOFMEMORY);
755*5e7646d2SAndroid Build Coastguard Worker         DEBUG_puts("_httpTLSRead: Decryption buffer too large (>256k)");
756*5e7646d2SAndroid Build Coastguard Worker 	return (-1);
757*5e7646d2SAndroid Build Coastguard Worker       }
758*5e7646d2SAndroid Build Coastguard Worker 
759*5e7646d2SAndroid Build Coastguard Worker       if ((temp = realloc(sspi->decryptBuffer, sspi->decryptBufferLength + 4096)) == NULL)
760*5e7646d2SAndroid Build Coastguard Worker       {
761*5e7646d2SAndroid Build Coastguard Worker 	DEBUG_printf(("_httpTLSRead: Unable to allocate %d byte decryption buffer.", sspi->decryptBufferLength + 4096));
762*5e7646d2SAndroid Build Coastguard Worker 	WSASetLastError(E_OUTOFMEMORY);
763*5e7646d2SAndroid Build Coastguard Worker 	return (-1);
764*5e7646d2SAndroid Build Coastguard Worker       }
765*5e7646d2SAndroid Build Coastguard Worker 
766*5e7646d2SAndroid Build Coastguard Worker       sspi->decryptBufferLength += 4096;
767*5e7646d2SAndroid Build Coastguard Worker       sspi->decryptBuffer       = temp;
768*5e7646d2SAndroid Build Coastguard Worker 
769*5e7646d2SAndroid Build Coastguard Worker       DEBUG_printf(("_httpTLSRead: Resized decryption buffer to %d bytes.", sspi->decryptBufferLength));
770*5e7646d2SAndroid Build Coastguard Worker     }
771*5e7646d2SAndroid Build Coastguard Worker 
772*5e7646d2SAndroid Build Coastguard Worker     buffers[0].pvBuffer	  = sspi->decryptBuffer;
773*5e7646d2SAndroid Build Coastguard Worker     buffers[0].cbBuffer	  = (unsigned long)sspi->decryptBufferUsed;
774*5e7646d2SAndroid Build Coastguard Worker     buffers[0].BufferType = SECBUFFER_DATA;
775*5e7646d2SAndroid Build Coastguard Worker     buffers[1].BufferType = SECBUFFER_EMPTY;
776*5e7646d2SAndroid Build Coastguard Worker     buffers[2].BufferType = SECBUFFER_EMPTY;
777*5e7646d2SAndroid Build Coastguard Worker     buffers[3].BufferType = SECBUFFER_EMPTY;
778*5e7646d2SAndroid Build Coastguard Worker 
779*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("5_httpTLSRead: decryptBufferUsed=%d", sspi->decryptBufferUsed));
780*5e7646d2SAndroid Build Coastguard Worker 
781*5e7646d2SAndroid Build Coastguard Worker     scRet = DecryptMessage(&sspi->context, &message, 0, NULL);
782*5e7646d2SAndroid Build Coastguard Worker 
783*5e7646d2SAndroid Build Coastguard Worker     if (scRet == SEC_E_INCOMPLETE_MESSAGE)
784*5e7646d2SAndroid Build Coastguard Worker     {
785*5e7646d2SAndroid Build Coastguard Worker       num = recv(http->fd, sspi->decryptBuffer + sspi->decryptBufferUsed, (int)(sspi->decryptBufferLength - sspi->decryptBufferUsed), 0);
786*5e7646d2SAndroid Build Coastguard Worker       if (num < 0)
787*5e7646d2SAndroid Build Coastguard Worker       {
788*5e7646d2SAndroid Build Coastguard Worker 	DEBUG_printf(("5_httpTLSRead: recv failed: %d", WSAGetLastError()));
789*5e7646d2SAndroid Build Coastguard Worker 	return (-1);
790*5e7646d2SAndroid Build Coastguard Worker       }
791*5e7646d2SAndroid Build Coastguard Worker       else if (num == 0)
792*5e7646d2SAndroid Build Coastguard Worker       {
793*5e7646d2SAndroid Build Coastguard Worker 	DEBUG_puts("5_httpTLSRead: Server disconnected.");
794*5e7646d2SAndroid Build Coastguard Worker 	return (0);
795*5e7646d2SAndroid Build Coastguard Worker       }
796*5e7646d2SAndroid Build Coastguard Worker 
797*5e7646d2SAndroid Build Coastguard Worker       DEBUG_printf(("5_httpTLSRead: Read %d bytes into decryption buffer.", num));
798*5e7646d2SAndroid Build Coastguard Worker 
799*5e7646d2SAndroid Build Coastguard Worker       sspi->decryptBufferUsed += num;
800*5e7646d2SAndroid Build Coastguard Worker     }
801*5e7646d2SAndroid Build Coastguard Worker   }
802*5e7646d2SAndroid Build Coastguard Worker   while (scRet == SEC_E_INCOMPLETE_MESSAGE);
803*5e7646d2SAndroid Build Coastguard Worker 
804*5e7646d2SAndroid Build Coastguard Worker   if (scRet == SEC_I_CONTEXT_EXPIRED)
805*5e7646d2SAndroid Build Coastguard Worker   {
806*5e7646d2SAndroid Build Coastguard Worker     DEBUG_puts("5_httpTLSRead: Context expired.");
807*5e7646d2SAndroid Build Coastguard Worker     WSASetLastError(WSAECONNRESET);
808*5e7646d2SAndroid Build Coastguard Worker     return (-1);
809*5e7646d2SAndroid Build Coastguard Worker   }
810*5e7646d2SAndroid Build Coastguard Worker   else if (scRet != SEC_E_OK)
811*5e7646d2SAndroid Build Coastguard Worker   {
812*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("5_httpTLSRead: DecryptMessage failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
813*5e7646d2SAndroid Build Coastguard Worker     WSASetLastError(WSASYSCALLFAILURE);
814*5e7646d2SAndroid Build Coastguard Worker     return (-1);
815*5e7646d2SAndroid Build Coastguard Worker   }
816*5e7646d2SAndroid Build Coastguard Worker 
817*5e7646d2SAndroid Build Coastguard Worker  /*
818*5e7646d2SAndroid Build Coastguard Worker   * The decryption worked.  Now, locate data buffer.
819*5e7646d2SAndroid Build Coastguard Worker   */
820*5e7646d2SAndroid Build Coastguard Worker 
821*5e7646d2SAndroid Build Coastguard Worker   pDataBuffer  = NULL;
822*5e7646d2SAndroid Build Coastguard Worker   pExtraBuffer = NULL;
823*5e7646d2SAndroid Build Coastguard Worker 
824*5e7646d2SAndroid Build Coastguard Worker   for (i = 1; i < 4; i++)
825*5e7646d2SAndroid Build Coastguard Worker   {
826*5e7646d2SAndroid Build Coastguard Worker     if (buffers[i].BufferType == SECBUFFER_DATA)
827*5e7646d2SAndroid Build Coastguard Worker       pDataBuffer = &buffers[i];
828*5e7646d2SAndroid Build Coastguard Worker     else if (!pExtraBuffer && (buffers[i].BufferType == SECBUFFER_EXTRA))
829*5e7646d2SAndroid Build Coastguard Worker       pExtraBuffer = &buffers[i];
830*5e7646d2SAndroid Build Coastguard Worker   }
831*5e7646d2SAndroid Build Coastguard Worker 
832*5e7646d2SAndroid Build Coastguard Worker  /*
833*5e7646d2SAndroid Build Coastguard Worker   * If a data buffer is found, then copy the decrypted bytes to the passed-in
834*5e7646d2SAndroid Build Coastguard Worker   * buffer...
835*5e7646d2SAndroid Build Coastguard Worker   */
836*5e7646d2SAndroid Build Coastguard Worker 
837*5e7646d2SAndroid Build Coastguard Worker   if (pDataBuffer)
838*5e7646d2SAndroid Build Coastguard Worker   {
839*5e7646d2SAndroid Build Coastguard Worker     int bytesToCopy = min((int)pDataBuffer->cbBuffer, len);
840*5e7646d2SAndroid Build Coastguard Worker 				      /* Number of bytes to copy into buf */
841*5e7646d2SAndroid Build Coastguard Worker     int bytesToSave = pDataBuffer->cbBuffer - bytesToCopy;
842*5e7646d2SAndroid Build Coastguard Worker 				      /* Number of bytes to save in our read buffer */
843*5e7646d2SAndroid Build Coastguard Worker 
844*5e7646d2SAndroid Build Coastguard Worker     if (bytesToCopy)
845*5e7646d2SAndroid Build Coastguard Worker       memcpy(buf, pDataBuffer->pvBuffer, bytesToCopy);
846*5e7646d2SAndroid Build Coastguard Worker 
847*5e7646d2SAndroid Build Coastguard Worker    /*
848*5e7646d2SAndroid Build Coastguard Worker     * If there are more decrypted bytes than can be copied to the passed in
849*5e7646d2SAndroid Build Coastguard Worker     * buffer, then save them...
850*5e7646d2SAndroid Build Coastguard Worker     */
851*5e7646d2SAndroid Build Coastguard Worker 
852*5e7646d2SAndroid Build Coastguard Worker     if (bytesToSave)
853*5e7646d2SAndroid Build Coastguard Worker     {
854*5e7646d2SAndroid Build Coastguard Worker       if ((sspi->readBufferLength - sspi->readBufferUsed) < bytesToSave)
855*5e7646d2SAndroid Build Coastguard Worker       {
856*5e7646d2SAndroid Build Coastguard Worker         BYTE *temp;			/* New buffer pointer */
857*5e7646d2SAndroid Build Coastguard Worker 
858*5e7646d2SAndroid Build Coastguard Worker         if ((temp = realloc(sspi->readBuffer, sspi->readBufferUsed + bytesToSave)) == NULL)
859*5e7646d2SAndroid Build Coastguard Worker 	{
860*5e7646d2SAndroid Build Coastguard Worker 	  DEBUG_printf(("_httpTLSRead: Unable to allocate %d bytes.", sspi->readBufferUsed + bytesToSave));
861*5e7646d2SAndroid Build Coastguard Worker 	  WSASetLastError(E_OUTOFMEMORY);
862*5e7646d2SAndroid Build Coastguard Worker 	  return (-1);
863*5e7646d2SAndroid Build Coastguard Worker 	}
864*5e7646d2SAndroid Build Coastguard Worker 
865*5e7646d2SAndroid Build Coastguard Worker 	sspi->readBufferLength = sspi->readBufferUsed + bytesToSave;
866*5e7646d2SAndroid Build Coastguard Worker 	sspi->readBuffer       = temp;
867*5e7646d2SAndroid Build Coastguard Worker       }
868*5e7646d2SAndroid Build Coastguard Worker 
869*5e7646d2SAndroid Build Coastguard Worker       memcpy(((BYTE *)sspi->readBuffer) + sspi->readBufferUsed, ((BYTE *)pDataBuffer->pvBuffer) + bytesToCopy, bytesToSave);
870*5e7646d2SAndroid Build Coastguard Worker 
871*5e7646d2SAndroid Build Coastguard Worker       sspi->readBufferUsed += bytesToSave;
872*5e7646d2SAndroid Build Coastguard Worker     }
873*5e7646d2SAndroid Build Coastguard Worker 
874*5e7646d2SAndroid Build Coastguard Worker     num = bytesToCopy;
875*5e7646d2SAndroid Build Coastguard Worker   }
876*5e7646d2SAndroid Build Coastguard Worker   else
877*5e7646d2SAndroid Build Coastguard Worker   {
878*5e7646d2SAndroid Build Coastguard Worker     DEBUG_puts("_httpTLSRead: Unable to find data buffer.");
879*5e7646d2SAndroid Build Coastguard Worker     WSASetLastError(WSASYSCALLFAILURE);
880*5e7646d2SAndroid Build Coastguard Worker     return (-1);
881*5e7646d2SAndroid Build Coastguard Worker   }
882*5e7646d2SAndroid Build Coastguard Worker 
883*5e7646d2SAndroid Build Coastguard Worker  /*
884*5e7646d2SAndroid Build Coastguard Worker   * If the decryption process left extra bytes, then save those back in
885*5e7646d2SAndroid Build Coastguard Worker   * decryptBuffer.  They will be processed the next time through the loop.
886*5e7646d2SAndroid Build Coastguard Worker   */
887*5e7646d2SAndroid Build Coastguard Worker 
888*5e7646d2SAndroid Build Coastguard Worker   if (pExtraBuffer)
889*5e7646d2SAndroid Build Coastguard Worker   {
890*5e7646d2SAndroid Build Coastguard Worker     memmove(sspi->decryptBuffer, pExtraBuffer->pvBuffer, pExtraBuffer->cbBuffer);
891*5e7646d2SAndroid Build Coastguard Worker     sspi->decryptBufferUsed = pExtraBuffer->cbBuffer;
892*5e7646d2SAndroid Build Coastguard Worker   }
893*5e7646d2SAndroid Build Coastguard Worker   else
894*5e7646d2SAndroid Build Coastguard Worker   {
895*5e7646d2SAndroid Build Coastguard Worker     sspi->decryptBufferUsed = 0;
896*5e7646d2SAndroid Build Coastguard Worker   }
897*5e7646d2SAndroid Build Coastguard Worker 
898*5e7646d2SAndroid Build Coastguard Worker   return (num);
899*5e7646d2SAndroid Build Coastguard Worker }
900*5e7646d2SAndroid Build Coastguard Worker 
901*5e7646d2SAndroid Build Coastguard Worker 
902*5e7646d2SAndroid Build Coastguard Worker /*
903*5e7646d2SAndroid Build Coastguard Worker  * '_httpTLSSetOptions()' - Set TLS protocol and cipher suite options.
904*5e7646d2SAndroid Build Coastguard Worker  */
905*5e7646d2SAndroid Build Coastguard Worker 
906*5e7646d2SAndroid Build Coastguard Worker void
_httpTLSSetOptions(int options,int min_version,int max_version)907*5e7646d2SAndroid Build Coastguard Worker _httpTLSSetOptions(int options,		/* I - Options */
908*5e7646d2SAndroid Build Coastguard Worker                    int min_version,	/* I - Minimum TLS version */
909*5e7646d2SAndroid Build Coastguard Worker                    int max_version)	/* I - Maximum TLS version */
910*5e7646d2SAndroid Build Coastguard Worker {
911*5e7646d2SAndroid Build Coastguard Worker   if (!(options & _HTTP_TLS_SET_DEFAULT) || tls_options < 0)
912*5e7646d2SAndroid Build Coastguard Worker   {
913*5e7646d2SAndroid Build Coastguard Worker     tls_options     = options;
914*5e7646d2SAndroid Build Coastguard Worker     tls_min_version = min_version;
915*5e7646d2SAndroid Build Coastguard Worker     tls_max_version = max_version;
916*5e7646d2SAndroid Build Coastguard Worker   }
917*5e7646d2SAndroid Build Coastguard Worker }
918*5e7646d2SAndroid Build Coastguard Worker 
919*5e7646d2SAndroid Build Coastguard Worker 
920*5e7646d2SAndroid Build Coastguard Worker /*
921*5e7646d2SAndroid Build Coastguard Worker  * '_httpTLSStart()' - Set up SSL/TLS support on a connection.
922*5e7646d2SAndroid Build Coastguard Worker  */
923*5e7646d2SAndroid Build Coastguard Worker 
924*5e7646d2SAndroid Build Coastguard Worker int					/* O - 0 on success, -1 on failure */
_httpTLSStart(http_t * http)925*5e7646d2SAndroid Build Coastguard Worker _httpTLSStart(http_t *http)		/* I - HTTP connection */
926*5e7646d2SAndroid Build Coastguard Worker {
927*5e7646d2SAndroid Build Coastguard Worker   char	hostname[256],			/* Hostname */
928*5e7646d2SAndroid Build Coastguard Worker 	*hostptr;			/* Pointer into hostname */
929*5e7646d2SAndroid Build Coastguard Worker 
930*5e7646d2SAndroid Build Coastguard Worker 
931*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("3_httpTLSStart(http=%p)", http));
932*5e7646d2SAndroid Build Coastguard Worker 
933*5e7646d2SAndroid Build Coastguard Worker   if (tls_options < 0)
934*5e7646d2SAndroid Build Coastguard Worker   {
935*5e7646d2SAndroid Build Coastguard Worker     DEBUG_puts("4_httpTLSStart: Setting defaults.");
936*5e7646d2SAndroid Build Coastguard Worker     _cupsSetDefaults();
937*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("4_httpTLSStart: tls_options=%x", tls_options));
938*5e7646d2SAndroid Build Coastguard Worker   }
939*5e7646d2SAndroid Build Coastguard Worker 
940*5e7646d2SAndroid Build Coastguard Worker   if ((http->tls = http_sspi_alloc()) == NULL)
941*5e7646d2SAndroid Build Coastguard Worker     return (-1);
942*5e7646d2SAndroid Build Coastguard Worker 
943*5e7646d2SAndroid Build Coastguard Worker   if (http->mode == _HTTP_MODE_CLIENT)
944*5e7646d2SAndroid Build Coastguard Worker   {
945*5e7646d2SAndroid Build Coastguard Worker    /*
946*5e7646d2SAndroid Build Coastguard Worker     * Client: determine hostname...
947*5e7646d2SAndroid Build Coastguard Worker     */
948*5e7646d2SAndroid Build Coastguard Worker 
949*5e7646d2SAndroid Build Coastguard Worker     if (httpAddrLocalhost(http->hostaddr))
950*5e7646d2SAndroid Build Coastguard Worker     {
951*5e7646d2SAndroid Build Coastguard Worker       strlcpy(hostname, "localhost", sizeof(hostname));
952*5e7646d2SAndroid Build Coastguard Worker     }
953*5e7646d2SAndroid Build Coastguard Worker     else
954*5e7646d2SAndroid Build Coastguard Worker     {
955*5e7646d2SAndroid Build Coastguard Worker      /*
956*5e7646d2SAndroid Build Coastguard Worker       * Otherwise make sure the hostname we have does not end in a trailing dot.
957*5e7646d2SAndroid Build Coastguard Worker       */
958*5e7646d2SAndroid Build Coastguard Worker 
959*5e7646d2SAndroid Build Coastguard Worker       strlcpy(hostname, http->hostname, sizeof(hostname));
960*5e7646d2SAndroid Build Coastguard Worker       if ((hostptr = hostname + strlen(hostname) - 1) >= hostname &&
961*5e7646d2SAndroid Build Coastguard Worker 	  *hostptr == '.')
962*5e7646d2SAndroid Build Coastguard Worker 	*hostptr = '\0';
963*5e7646d2SAndroid Build Coastguard Worker     }
964*5e7646d2SAndroid Build Coastguard Worker 
965*5e7646d2SAndroid Build Coastguard Worker     return (http_sspi_client(http, hostname));
966*5e7646d2SAndroid Build Coastguard Worker   }
967*5e7646d2SAndroid Build Coastguard Worker   else
968*5e7646d2SAndroid Build Coastguard Worker   {
969*5e7646d2SAndroid Build Coastguard Worker    /*
970*5e7646d2SAndroid Build Coastguard Worker     * Server: determine hostname to use...
971*5e7646d2SAndroid Build Coastguard Worker     */
972*5e7646d2SAndroid Build Coastguard Worker 
973*5e7646d2SAndroid Build Coastguard Worker     if (http->fields[HTTP_FIELD_HOST])
974*5e7646d2SAndroid Build Coastguard Worker     {
975*5e7646d2SAndroid Build Coastguard Worker      /*
976*5e7646d2SAndroid Build Coastguard Worker       * Use hostname for TLS upgrade...
977*5e7646d2SAndroid Build Coastguard Worker       */
978*5e7646d2SAndroid Build Coastguard Worker 
979*5e7646d2SAndroid Build Coastguard Worker       strlcpy(hostname, http->fields[HTTP_FIELD_HOST], sizeof(hostname));
980*5e7646d2SAndroid Build Coastguard Worker     }
981*5e7646d2SAndroid Build Coastguard Worker     else
982*5e7646d2SAndroid Build Coastguard Worker     {
983*5e7646d2SAndroid Build Coastguard Worker      /*
984*5e7646d2SAndroid Build Coastguard Worker       * Resolve hostname from connection address...
985*5e7646d2SAndroid Build Coastguard Worker       */
986*5e7646d2SAndroid Build Coastguard Worker 
987*5e7646d2SAndroid Build Coastguard Worker       http_addr_t	addr;		/* Connection address */
988*5e7646d2SAndroid Build Coastguard Worker       socklen_t		addrlen;	/* Length of address */
989*5e7646d2SAndroid Build Coastguard Worker 
990*5e7646d2SAndroid Build Coastguard Worker       addrlen = sizeof(addr);
991*5e7646d2SAndroid Build Coastguard Worker       if (getsockname(http->fd, (struct sockaddr *)&addr, &addrlen))
992*5e7646d2SAndroid Build Coastguard Worker       {
993*5e7646d2SAndroid Build Coastguard Worker 	DEBUG_printf(("4_httpTLSStart: Unable to get socket address: %s", strerror(errno)));
994*5e7646d2SAndroid Build Coastguard Worker 	hostname[0] = '\0';
995*5e7646d2SAndroid Build Coastguard Worker       }
996*5e7646d2SAndroid Build Coastguard Worker       else if (httpAddrLocalhost(&addr))
997*5e7646d2SAndroid Build Coastguard Worker 	hostname[0] = '\0';
998*5e7646d2SAndroid Build Coastguard Worker       else
999*5e7646d2SAndroid Build Coastguard Worker       {
1000*5e7646d2SAndroid Build Coastguard Worker 	httpAddrLookup(&addr, hostname, sizeof(hostname));
1001*5e7646d2SAndroid Build Coastguard Worker         DEBUG_printf(("4_httpTLSStart: Resolved socket address to \"%s\".", hostname));
1002*5e7646d2SAndroid Build Coastguard Worker       }
1003*5e7646d2SAndroid Build Coastguard Worker     }
1004*5e7646d2SAndroid Build Coastguard Worker 
1005*5e7646d2SAndroid Build Coastguard Worker     return (http_sspi_server(http, hostname));
1006*5e7646d2SAndroid Build Coastguard Worker   }
1007*5e7646d2SAndroid Build Coastguard Worker }
1008*5e7646d2SAndroid Build Coastguard Worker 
1009*5e7646d2SAndroid Build Coastguard Worker 
1010*5e7646d2SAndroid Build Coastguard Worker /*
1011*5e7646d2SAndroid Build Coastguard Worker  * '_httpTLSStop()' - Shut down SSL/TLS on a connection.
1012*5e7646d2SAndroid Build Coastguard Worker  */
1013*5e7646d2SAndroid Build Coastguard Worker 
1014*5e7646d2SAndroid Build Coastguard Worker void
_httpTLSStop(http_t * http)1015*5e7646d2SAndroid Build Coastguard Worker _httpTLSStop(http_t *http)		/* I - HTTP connection */
1016*5e7646d2SAndroid Build Coastguard Worker {
1017*5e7646d2SAndroid Build Coastguard Worker   _http_sspi_t	*sspi = http->tls;	/* SSPI data */
1018*5e7646d2SAndroid Build Coastguard Worker 
1019*5e7646d2SAndroid Build Coastguard Worker 
1020*5e7646d2SAndroid Build Coastguard Worker   if (sspi->contextInitialized && http->fd >= 0)
1021*5e7646d2SAndroid Build Coastguard Worker   {
1022*5e7646d2SAndroid Build Coastguard Worker     SecBufferDesc	message;	/* Array of SecBuffer struct */
1023*5e7646d2SAndroid Build Coastguard Worker     SecBuffer		buffers[1] = { 0 };
1024*5e7646d2SAndroid Build Coastguard Worker 					/* Security package buffer */
1025*5e7646d2SAndroid Build Coastguard Worker     DWORD		dwType;		/* Type */
1026*5e7646d2SAndroid Build Coastguard Worker     DWORD		status;		/* Status */
1027*5e7646d2SAndroid Build Coastguard Worker 
1028*5e7646d2SAndroid Build Coastguard Worker   /*
1029*5e7646d2SAndroid Build Coastguard Worker    * Notify schannel that we are about to close the connection.
1030*5e7646d2SAndroid Build Coastguard Worker    */
1031*5e7646d2SAndroid Build Coastguard Worker 
1032*5e7646d2SAndroid Build Coastguard Worker    dwType = SCHANNEL_SHUTDOWN;
1033*5e7646d2SAndroid Build Coastguard Worker 
1034*5e7646d2SAndroid Build Coastguard Worker    buffers[0].pvBuffer   = &dwType;
1035*5e7646d2SAndroid Build Coastguard Worker    buffers[0].BufferType = SECBUFFER_TOKEN;
1036*5e7646d2SAndroid Build Coastguard Worker    buffers[0].cbBuffer   = sizeof(dwType);
1037*5e7646d2SAndroid Build Coastguard Worker 
1038*5e7646d2SAndroid Build Coastguard Worker    message.cBuffers  = 1;
1039*5e7646d2SAndroid Build Coastguard Worker    message.pBuffers  = buffers;
1040*5e7646d2SAndroid Build Coastguard Worker    message.ulVersion = SECBUFFER_VERSION;
1041*5e7646d2SAndroid Build Coastguard Worker 
1042*5e7646d2SAndroid Build Coastguard Worker    status = ApplyControlToken(&sspi->context, &message);
1043*5e7646d2SAndroid Build Coastguard Worker 
1044*5e7646d2SAndroid Build Coastguard Worker    if (SUCCEEDED(status))
1045*5e7646d2SAndroid Build Coastguard Worker    {
1046*5e7646d2SAndroid Build Coastguard Worker      PBYTE	pbMessage;		/* Message buffer */
1047*5e7646d2SAndroid Build Coastguard Worker      DWORD	cbMessage;		/* Message buffer count */
1048*5e7646d2SAndroid Build Coastguard Worker      DWORD	cbData;			/* Data count */
1049*5e7646d2SAndroid Build Coastguard Worker      DWORD	dwSSPIFlags;		/* SSL attributes we requested */
1050*5e7646d2SAndroid Build Coastguard Worker      DWORD	dwSSPIOutFlags;		/* SSL attributes we received */
1051*5e7646d2SAndroid Build Coastguard Worker      TimeStamp	tsExpiry;		/* Time stamp */
1052*5e7646d2SAndroid Build Coastguard Worker 
1053*5e7646d2SAndroid Build Coastguard Worker      dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT     |
1054*5e7646d2SAndroid Build Coastguard Worker                    ASC_REQ_REPLAY_DETECT       |
1055*5e7646d2SAndroid Build Coastguard Worker                    ASC_REQ_CONFIDENTIALITY     |
1056*5e7646d2SAndroid Build Coastguard Worker                    ASC_REQ_EXTENDED_ERROR      |
1057*5e7646d2SAndroid Build Coastguard Worker                    ASC_REQ_ALLOCATE_MEMORY     |
1058*5e7646d2SAndroid Build Coastguard Worker                    ASC_REQ_STREAM;
1059*5e7646d2SAndroid Build Coastguard Worker 
1060*5e7646d2SAndroid Build Coastguard Worker      buffers[0].pvBuffer   = NULL;
1061*5e7646d2SAndroid Build Coastguard Worker      buffers[0].BufferType = SECBUFFER_TOKEN;
1062*5e7646d2SAndroid Build Coastguard Worker      buffers[0].cbBuffer   = 0;
1063*5e7646d2SAndroid Build Coastguard Worker 
1064*5e7646d2SAndroid Build Coastguard Worker      message.cBuffers  = 1;
1065*5e7646d2SAndroid Build Coastguard Worker      message.pBuffers  = buffers;
1066*5e7646d2SAndroid Build Coastguard Worker      message.ulVersion = SECBUFFER_VERSION;
1067*5e7646d2SAndroid Build Coastguard Worker 
1068*5e7646d2SAndroid Build Coastguard Worker      status = AcceptSecurityContext(&sspi->creds, &sspi->context, NULL,
1069*5e7646d2SAndroid Build Coastguard Worker                                     dwSSPIFlags, SECURITY_NATIVE_DREP, NULL,
1070*5e7646d2SAndroid Build Coastguard Worker                                     &message, &dwSSPIOutFlags, &tsExpiry);
1071*5e7646d2SAndroid Build Coastguard Worker 
1072*5e7646d2SAndroid Build Coastguard Worker       if (SUCCEEDED(status))
1073*5e7646d2SAndroid Build Coastguard Worker       {
1074*5e7646d2SAndroid Build Coastguard Worker         pbMessage = buffers[0].pvBuffer;
1075*5e7646d2SAndroid Build Coastguard Worker         cbMessage = buffers[0].cbBuffer;
1076*5e7646d2SAndroid Build Coastguard Worker 
1077*5e7646d2SAndroid Build Coastguard Worker        /*
1078*5e7646d2SAndroid Build Coastguard Worker         * Send the close notify message to the client.
1079*5e7646d2SAndroid Build Coastguard Worker         */
1080*5e7646d2SAndroid Build Coastguard Worker 
1081*5e7646d2SAndroid Build Coastguard Worker         if (pbMessage && cbMessage)
1082*5e7646d2SAndroid Build Coastguard Worker         {
1083*5e7646d2SAndroid Build Coastguard Worker           cbData = send(http->fd, pbMessage, cbMessage, 0);
1084*5e7646d2SAndroid Build Coastguard Worker           if ((cbData == SOCKET_ERROR) || (cbData == 0))
1085*5e7646d2SAndroid Build Coastguard Worker           {
1086*5e7646d2SAndroid Build Coastguard Worker             status = WSAGetLastError();
1087*5e7646d2SAndroid Build Coastguard Worker             DEBUG_printf(("_httpTLSStop: sending close notify failed: %d", status));
1088*5e7646d2SAndroid Build Coastguard Worker           }
1089*5e7646d2SAndroid Build Coastguard Worker           else
1090*5e7646d2SAndroid Build Coastguard Worker           {
1091*5e7646d2SAndroid Build Coastguard Worker             FreeContextBuffer(pbMessage);
1092*5e7646d2SAndroid Build Coastguard Worker           }
1093*5e7646d2SAndroid Build Coastguard Worker         }
1094*5e7646d2SAndroid Build Coastguard Worker       }
1095*5e7646d2SAndroid Build Coastguard Worker       else
1096*5e7646d2SAndroid Build Coastguard Worker       {
1097*5e7646d2SAndroid Build Coastguard Worker         DEBUG_printf(("_httpTLSStop: AcceptSecurityContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), status)));
1098*5e7646d2SAndroid Build Coastguard Worker       }
1099*5e7646d2SAndroid Build Coastguard Worker     }
1100*5e7646d2SAndroid Build Coastguard Worker     else
1101*5e7646d2SAndroid Build Coastguard Worker     {
1102*5e7646d2SAndroid Build Coastguard Worker       DEBUG_printf(("_httpTLSStop: ApplyControlToken failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), status)));
1103*5e7646d2SAndroid Build Coastguard Worker     }
1104*5e7646d2SAndroid Build Coastguard Worker   }
1105*5e7646d2SAndroid Build Coastguard Worker 
1106*5e7646d2SAndroid Build Coastguard Worker   http_sspi_free(sspi);
1107*5e7646d2SAndroid Build Coastguard Worker 
1108*5e7646d2SAndroid Build Coastguard Worker   http->tls = NULL;
1109*5e7646d2SAndroid Build Coastguard Worker }
1110*5e7646d2SAndroid Build Coastguard Worker 
1111*5e7646d2SAndroid Build Coastguard Worker 
1112*5e7646d2SAndroid Build Coastguard Worker /*
1113*5e7646d2SAndroid Build Coastguard Worker  * '_httpTLSWrite()' - Write to a SSL/TLS connection.
1114*5e7646d2SAndroid Build Coastguard Worker  */
1115*5e7646d2SAndroid Build Coastguard Worker 
1116*5e7646d2SAndroid Build Coastguard Worker int					/* O - Bytes written */
_httpTLSWrite(http_t * http,const char * buf,int len)1117*5e7646d2SAndroid Build Coastguard Worker _httpTLSWrite(http_t     *http,		/* I - HTTP connection */
1118*5e7646d2SAndroid Build Coastguard Worker 	      const char *buf,		/* I - Buffer holding data */
1119*5e7646d2SAndroid Build Coastguard Worker 	      int        len)		/* I - Length of buffer */
1120*5e7646d2SAndroid Build Coastguard Worker {
1121*5e7646d2SAndroid Build Coastguard Worker   _http_sspi_t	*sspi = http->tls;	/* SSPI data */
1122*5e7646d2SAndroid Build Coastguard Worker   SecBufferDesc	message;		/* Array of SecBuffer struct */
1123*5e7646d2SAndroid Build Coastguard Worker   SecBuffer	buffers[4] = { 0 };	/* Security package buffer */
1124*5e7646d2SAndroid Build Coastguard Worker   int		bufferLen;		/* Buffer length */
1125*5e7646d2SAndroid Build Coastguard Worker   int		bytesLeft;		/* Bytes left to write */
1126*5e7646d2SAndroid Build Coastguard Worker   const char	*bufptr;		/* Pointer into buffer */
1127*5e7646d2SAndroid Build Coastguard Worker   int		num = 0;		/* Return value */
1128*5e7646d2SAndroid Build Coastguard Worker 
1129*5e7646d2SAndroid Build Coastguard Worker 
1130*5e7646d2SAndroid Build Coastguard Worker   bufferLen = sspi->streamSizes.cbMaximumMessage + sspi->streamSizes.cbHeader + sspi->streamSizes.cbTrailer;
1131*5e7646d2SAndroid Build Coastguard Worker 
1132*5e7646d2SAndroid Build Coastguard Worker   if (bufferLen > sspi->writeBufferLength)
1133*5e7646d2SAndroid Build Coastguard Worker   {
1134*5e7646d2SAndroid Build Coastguard Worker     BYTE *temp;				/* New buffer pointer */
1135*5e7646d2SAndroid Build Coastguard Worker 
1136*5e7646d2SAndroid Build Coastguard Worker     if ((temp = (BYTE *)realloc(sspi->writeBuffer, bufferLen)) == NULL)
1137*5e7646d2SAndroid Build Coastguard Worker     {
1138*5e7646d2SAndroid Build Coastguard Worker       DEBUG_printf(("_httpTLSWrite: Unable to allocate buffer of %d bytes.", bufferLen));
1139*5e7646d2SAndroid Build Coastguard Worker       WSASetLastError(E_OUTOFMEMORY);
1140*5e7646d2SAndroid Build Coastguard Worker       return (-1);
1141*5e7646d2SAndroid Build Coastguard Worker     }
1142*5e7646d2SAndroid Build Coastguard Worker 
1143*5e7646d2SAndroid Build Coastguard Worker     sspi->writeBuffer       = temp;
1144*5e7646d2SAndroid Build Coastguard Worker     sspi->writeBufferLength = bufferLen;
1145*5e7646d2SAndroid Build Coastguard Worker   }
1146*5e7646d2SAndroid Build Coastguard Worker 
1147*5e7646d2SAndroid Build Coastguard Worker   bytesLeft = len;
1148*5e7646d2SAndroid Build Coastguard Worker   bufptr    = buf;
1149*5e7646d2SAndroid Build Coastguard Worker 
1150*5e7646d2SAndroid Build Coastguard Worker   while (bytesLeft)
1151*5e7646d2SAndroid Build Coastguard Worker   {
1152*5e7646d2SAndroid Build Coastguard Worker     int chunk = min((int)sspi->streamSizes.cbMaximumMessage, bytesLeft);
1153*5e7646d2SAndroid Build Coastguard Worker 					/* Size of data to write */
1154*5e7646d2SAndroid Build Coastguard Worker     SECURITY_STATUS scRet;		/* SSPI status */
1155*5e7646d2SAndroid Build Coastguard Worker 
1156*5e7646d2SAndroid Build Coastguard Worker    /*
1157*5e7646d2SAndroid Build Coastguard Worker     * Copy user data into the buffer, starting just past the header...
1158*5e7646d2SAndroid Build Coastguard Worker     */
1159*5e7646d2SAndroid Build Coastguard Worker 
1160*5e7646d2SAndroid Build Coastguard Worker     memcpy(sspi->writeBuffer + sspi->streamSizes.cbHeader, bufptr, chunk);
1161*5e7646d2SAndroid Build Coastguard Worker 
1162*5e7646d2SAndroid Build Coastguard Worker    /*
1163*5e7646d2SAndroid Build Coastguard Worker     * Setup the SSPI buffers
1164*5e7646d2SAndroid Build Coastguard Worker     */
1165*5e7646d2SAndroid Build Coastguard Worker 
1166*5e7646d2SAndroid Build Coastguard Worker     message.ulVersion = SECBUFFER_VERSION;
1167*5e7646d2SAndroid Build Coastguard Worker     message.cBuffers  = 4;
1168*5e7646d2SAndroid Build Coastguard Worker     message.pBuffers  = buffers;
1169*5e7646d2SAndroid Build Coastguard Worker 
1170*5e7646d2SAndroid Build Coastguard Worker     buffers[0].pvBuffer   = sspi->writeBuffer;
1171*5e7646d2SAndroid Build Coastguard Worker     buffers[0].cbBuffer   = sspi->streamSizes.cbHeader;
1172*5e7646d2SAndroid Build Coastguard Worker     buffers[0].BufferType = SECBUFFER_STREAM_HEADER;
1173*5e7646d2SAndroid Build Coastguard Worker     buffers[1].pvBuffer   = sspi->writeBuffer + sspi->streamSizes.cbHeader;
1174*5e7646d2SAndroid Build Coastguard Worker     buffers[1].cbBuffer   = (unsigned long) chunk;
1175*5e7646d2SAndroid Build Coastguard Worker     buffers[1].BufferType = SECBUFFER_DATA;
1176*5e7646d2SAndroid Build Coastguard Worker     buffers[2].pvBuffer   = sspi->writeBuffer + sspi->streamSizes.cbHeader + chunk;
1177*5e7646d2SAndroid Build Coastguard Worker     buffers[2].cbBuffer   = sspi->streamSizes.cbTrailer;
1178*5e7646d2SAndroid Build Coastguard Worker     buffers[2].BufferType = SECBUFFER_STREAM_TRAILER;
1179*5e7646d2SAndroid Build Coastguard Worker     buffers[3].BufferType = SECBUFFER_EMPTY;
1180*5e7646d2SAndroid Build Coastguard Worker 
1181*5e7646d2SAndroid Build Coastguard Worker    /*
1182*5e7646d2SAndroid Build Coastguard Worker     * Encrypt the data
1183*5e7646d2SAndroid Build Coastguard Worker     */
1184*5e7646d2SAndroid Build Coastguard Worker 
1185*5e7646d2SAndroid Build Coastguard Worker     scRet = EncryptMessage(&sspi->context, 0, &message, 0);
1186*5e7646d2SAndroid Build Coastguard Worker 
1187*5e7646d2SAndroid Build Coastguard Worker     if (FAILED(scRet))
1188*5e7646d2SAndroid Build Coastguard Worker     {
1189*5e7646d2SAndroid Build Coastguard Worker       DEBUG_printf(("_httpTLSWrite: EncryptMessage failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
1190*5e7646d2SAndroid Build Coastguard Worker       WSASetLastError(WSASYSCALLFAILURE);
1191*5e7646d2SAndroid Build Coastguard Worker       return (-1);
1192*5e7646d2SAndroid Build Coastguard Worker     }
1193*5e7646d2SAndroid Build Coastguard Worker 
1194*5e7646d2SAndroid Build Coastguard Worker    /*
1195*5e7646d2SAndroid Build Coastguard Worker     * Send the data. Remember the size of the total data to send is the size
1196*5e7646d2SAndroid Build Coastguard Worker     * of the header, the size of the data the caller passed in and the size
1197*5e7646d2SAndroid Build Coastguard Worker     * of the trailer...
1198*5e7646d2SAndroid Build Coastguard Worker     */
1199*5e7646d2SAndroid Build Coastguard Worker 
1200*5e7646d2SAndroid Build Coastguard Worker     num = send(http->fd, sspi->writeBuffer, buffers[0].cbBuffer + buffers[1].cbBuffer + buffers[2].cbBuffer, 0);
1201*5e7646d2SAndroid Build Coastguard Worker 
1202*5e7646d2SAndroid Build Coastguard Worker     if (num <= 0)
1203*5e7646d2SAndroid Build Coastguard Worker     {
1204*5e7646d2SAndroid Build Coastguard Worker       DEBUG_printf(("_httpTLSWrite: send failed: %ld", WSAGetLastError()));
1205*5e7646d2SAndroid Build Coastguard Worker       return (num);
1206*5e7646d2SAndroid Build Coastguard Worker     }
1207*5e7646d2SAndroid Build Coastguard Worker 
1208*5e7646d2SAndroid Build Coastguard Worker     bytesLeft -= chunk;
1209*5e7646d2SAndroid Build Coastguard Worker     bufptr    += chunk;
1210*5e7646d2SAndroid Build Coastguard Worker   }
1211*5e7646d2SAndroid Build Coastguard Worker 
1212*5e7646d2SAndroid Build Coastguard Worker   return (len);
1213*5e7646d2SAndroid Build Coastguard Worker }
1214*5e7646d2SAndroid Build Coastguard Worker 
1215*5e7646d2SAndroid Build Coastguard Worker 
1216*5e7646d2SAndroid Build Coastguard Worker #if 0
1217*5e7646d2SAndroid Build Coastguard Worker /*
1218*5e7646d2SAndroid Build Coastguard Worker  * 'http_setup_ssl()' - Set up SSL/TLS support on a connection.
1219*5e7646d2SAndroid Build Coastguard Worker  */
1220*5e7646d2SAndroid Build Coastguard Worker 
1221*5e7646d2SAndroid Build Coastguard Worker static int				/* O - 0 on success, -1 on failure */
1222*5e7646d2SAndroid Build Coastguard Worker http_setup_ssl(http_t *http)		/* I - Connection to server */
1223*5e7646d2SAndroid Build Coastguard Worker {
1224*5e7646d2SAndroid Build Coastguard Worker   char			hostname[256],	/* Hostname */
1225*5e7646d2SAndroid Build Coastguard Worker 			*hostptr;	/* Pointer into hostname */
1226*5e7646d2SAndroid Build Coastguard Worker 
1227*5e7646d2SAndroid Build Coastguard Worker   TCHAR			username[256];	/* Username returned from GetUserName() */
1228*5e7646d2SAndroid Build Coastguard Worker   TCHAR			commonName[256];/* Common name for certificate */
1229*5e7646d2SAndroid Build Coastguard Worker   DWORD			dwSize;		/* 32 bit size */
1230*5e7646d2SAndroid Build Coastguard Worker 
1231*5e7646d2SAndroid Build Coastguard Worker 
1232*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("7http_setup_ssl(http=%p)", http));
1233*5e7646d2SAndroid Build Coastguard Worker 
1234*5e7646d2SAndroid Build Coastguard Worker  /*
1235*5e7646d2SAndroid Build Coastguard Worker   * Get the hostname to use for SSL...
1236*5e7646d2SAndroid Build Coastguard Worker   */
1237*5e7646d2SAndroid Build Coastguard Worker 
1238*5e7646d2SAndroid Build Coastguard Worker   if (httpAddrLocalhost(http->hostaddr))
1239*5e7646d2SAndroid Build Coastguard Worker   {
1240*5e7646d2SAndroid Build Coastguard Worker     strlcpy(hostname, "localhost", sizeof(hostname));
1241*5e7646d2SAndroid Build Coastguard Worker   }
1242*5e7646d2SAndroid Build Coastguard Worker   else
1243*5e7646d2SAndroid Build Coastguard Worker   {
1244*5e7646d2SAndroid Build Coastguard Worker    /*
1245*5e7646d2SAndroid Build Coastguard Worker     * Otherwise make sure the hostname we have does not end in a trailing dot.
1246*5e7646d2SAndroid Build Coastguard Worker     */
1247*5e7646d2SAndroid Build Coastguard Worker 
1248*5e7646d2SAndroid Build Coastguard Worker     strlcpy(hostname, http->hostname, sizeof(hostname));
1249*5e7646d2SAndroid Build Coastguard Worker     if ((hostptr = hostname + strlen(hostname) - 1) >= hostname &&
1250*5e7646d2SAndroid Build Coastguard Worker         *hostptr == '.')
1251*5e7646d2SAndroid Build Coastguard Worker       *hostptr = '\0';
1252*5e7646d2SAndroid Build Coastguard Worker   }
1253*5e7646d2SAndroid Build Coastguard Worker 
1254*5e7646d2SAndroid Build Coastguard Worker   http->tls = http_sspi_alloc();
1255*5e7646d2SAndroid Build Coastguard Worker 
1256*5e7646d2SAndroid Build Coastguard Worker   if (!http->tls)
1257*5e7646d2SAndroid Build Coastguard Worker   {
1258*5e7646d2SAndroid Build Coastguard Worker     _cupsSetHTTPError(HTTP_STATUS_ERROR);
1259*5e7646d2SAndroid Build Coastguard Worker     return (-1);
1260*5e7646d2SAndroid Build Coastguard Worker   }
1261*5e7646d2SAndroid Build Coastguard Worker 
1262*5e7646d2SAndroid Build Coastguard Worker   dwSize          = sizeof(username) / sizeof(TCHAR);
1263*5e7646d2SAndroid Build Coastguard Worker   GetUserName(username, &dwSize);
1264*5e7646d2SAndroid Build Coastguard Worker   _sntprintf_s(commonName, sizeof(commonName) / sizeof(TCHAR),
1265*5e7646d2SAndroid Build Coastguard Worker                sizeof(commonName) / sizeof(TCHAR), TEXT("CN=%s"), username);
1266*5e7646d2SAndroid Build Coastguard Worker 
1267*5e7646d2SAndroid Build Coastguard Worker   if (!_sspiGetCredentials(http->tls, L"ClientContainer",
1268*5e7646d2SAndroid Build Coastguard Worker                            commonName, FALSE))
1269*5e7646d2SAndroid Build Coastguard Worker   {
1270*5e7646d2SAndroid Build Coastguard Worker     _sspiFree(http->tls);
1271*5e7646d2SAndroid Build Coastguard Worker     http->tls = NULL;
1272*5e7646d2SAndroid Build Coastguard Worker 
1273*5e7646d2SAndroid Build Coastguard Worker     http->error  = EIO;
1274*5e7646d2SAndroid Build Coastguard Worker     http->status = HTTP_STATUS_ERROR;
1275*5e7646d2SAndroid Build Coastguard Worker 
1276*5e7646d2SAndroid Build Coastguard Worker     _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI,
1277*5e7646d2SAndroid Build Coastguard Worker                   _("Unable to establish a secure connection to host."), 1);
1278*5e7646d2SAndroid Build Coastguard Worker 
1279*5e7646d2SAndroid Build Coastguard Worker     return (-1);
1280*5e7646d2SAndroid Build Coastguard Worker   }
1281*5e7646d2SAndroid Build Coastguard Worker 
1282*5e7646d2SAndroid Build Coastguard Worker   _sspiSetAllowsAnyRoot(http->tls, TRUE);
1283*5e7646d2SAndroid Build Coastguard Worker   _sspiSetAllowsExpiredCerts(http->tls, TRUE);
1284*5e7646d2SAndroid Build Coastguard Worker 
1285*5e7646d2SAndroid Build Coastguard Worker   if (!_sspiConnect(http->tls, hostname))
1286*5e7646d2SAndroid Build Coastguard Worker   {
1287*5e7646d2SAndroid Build Coastguard Worker     _sspiFree(http->tls);
1288*5e7646d2SAndroid Build Coastguard Worker     http->tls = NULL;
1289*5e7646d2SAndroid Build Coastguard Worker 
1290*5e7646d2SAndroid Build Coastguard Worker     http->error  = EIO;
1291*5e7646d2SAndroid Build Coastguard Worker     http->status = HTTP_STATUS_ERROR;
1292*5e7646d2SAndroid Build Coastguard Worker 
1293*5e7646d2SAndroid Build Coastguard Worker     _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI,
1294*5e7646d2SAndroid Build Coastguard Worker                   _("Unable to establish a secure connection to host."), 1);
1295*5e7646d2SAndroid Build Coastguard Worker 
1296*5e7646d2SAndroid Build Coastguard Worker     return (-1);
1297*5e7646d2SAndroid Build Coastguard Worker   }
1298*5e7646d2SAndroid Build Coastguard Worker 
1299*5e7646d2SAndroid Build Coastguard Worker   return (0);
1300*5e7646d2SAndroid Build Coastguard Worker }
1301*5e7646d2SAndroid Build Coastguard Worker #endif // 0
1302*5e7646d2SAndroid Build Coastguard Worker 
1303*5e7646d2SAndroid Build Coastguard Worker 
1304*5e7646d2SAndroid Build Coastguard Worker /*
1305*5e7646d2SAndroid Build Coastguard Worker  * 'http_sspi_alloc()' - Allocate SSPI object.
1306*5e7646d2SAndroid Build Coastguard Worker  */
1307*5e7646d2SAndroid Build Coastguard Worker 
1308*5e7646d2SAndroid Build Coastguard Worker static _http_sspi_t *			/* O  - New SSPI/SSL object */
http_sspi_alloc(void)1309*5e7646d2SAndroid Build Coastguard Worker http_sspi_alloc(void)
1310*5e7646d2SAndroid Build Coastguard Worker {
1311*5e7646d2SAndroid Build Coastguard Worker   return ((_http_sspi_t *)calloc(sizeof(_http_sspi_t), 1));
1312*5e7646d2SAndroid Build Coastguard Worker }
1313*5e7646d2SAndroid Build Coastguard Worker 
1314*5e7646d2SAndroid Build Coastguard Worker 
1315*5e7646d2SAndroid Build Coastguard Worker /*
1316*5e7646d2SAndroid Build Coastguard Worker  * 'http_sspi_client()' - Negotiate a TLS connection as a client.
1317*5e7646d2SAndroid Build Coastguard Worker  */
1318*5e7646d2SAndroid Build Coastguard Worker 
1319*5e7646d2SAndroid Build Coastguard Worker static int				/* O - 0 on success, -1 on failure */
http_sspi_client(http_t * http,const char * hostname)1320*5e7646d2SAndroid Build Coastguard Worker http_sspi_client(http_t     *http,	/* I - Client connection */
1321*5e7646d2SAndroid Build Coastguard Worker                  const char *hostname)	/* I - Server hostname */
1322*5e7646d2SAndroid Build Coastguard Worker {
1323*5e7646d2SAndroid Build Coastguard Worker   _http_sspi_t	*sspi = http->tls;	/* SSPI data */
1324*5e7646d2SAndroid Build Coastguard Worker   DWORD		dwSize;			/* Size for buffer */
1325*5e7646d2SAndroid Build Coastguard Worker   DWORD		dwSSPIFlags;		/* SSL connection attributes we want */
1326*5e7646d2SAndroid Build Coastguard Worker   DWORD		dwSSPIOutFlags;		/* SSL connection attributes we got */
1327*5e7646d2SAndroid Build Coastguard Worker   TimeStamp	tsExpiry;		/* Time stamp */
1328*5e7646d2SAndroid Build Coastguard Worker   SECURITY_STATUS scRet;		/* Status */
1329*5e7646d2SAndroid Build Coastguard Worker   int		cbData;			/* Data count */
1330*5e7646d2SAndroid Build Coastguard Worker   SecBufferDesc	inBuffer;		/* Array of SecBuffer structs */
1331*5e7646d2SAndroid Build Coastguard Worker   SecBuffer	inBuffers[2];		/* Security package buffer */
1332*5e7646d2SAndroid Build Coastguard Worker   SecBufferDesc	outBuffer;		/* Array of SecBuffer structs */
1333*5e7646d2SAndroid Build Coastguard Worker   SecBuffer	outBuffers[1];		/* Security package buffer */
1334*5e7646d2SAndroid Build Coastguard Worker   int		ret = 0;		/* Return value */
1335*5e7646d2SAndroid Build Coastguard Worker 
1336*5e7646d2SAndroid Build Coastguard Worker 
1337*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("4http_sspi_client(http=%p, hostname=\"%s\")", http, hostname));
1338*5e7646d2SAndroid Build Coastguard Worker 
1339*5e7646d2SAndroid Build Coastguard Worker   dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT   |
1340*5e7646d2SAndroid Build Coastguard Worker                 ISC_REQ_REPLAY_DETECT     |
1341*5e7646d2SAndroid Build Coastguard Worker                 ISC_REQ_CONFIDENTIALITY   |
1342*5e7646d2SAndroid Build Coastguard Worker                 ISC_RET_EXTENDED_ERROR    |
1343*5e7646d2SAndroid Build Coastguard Worker                 ISC_REQ_ALLOCATE_MEMORY   |
1344*5e7646d2SAndroid Build Coastguard Worker                 ISC_REQ_STREAM;
1345*5e7646d2SAndroid Build Coastguard Worker 
1346*5e7646d2SAndroid Build Coastguard Worker  /*
1347*5e7646d2SAndroid Build Coastguard Worker   * Lookup the client certificate...
1348*5e7646d2SAndroid Build Coastguard Worker   */
1349*5e7646d2SAndroid Build Coastguard Worker 
1350*5e7646d2SAndroid Build Coastguard Worker   if (!http_sspi_find_credentials(http, L"ClientContainer", NULL))
1351*5e7646d2SAndroid Build Coastguard Worker   {
1352*5e7646d2SAndroid Build Coastguard Worker     DEBUG_puts("5http_sspi_client: Unable to get client credentials.");
1353*5e7646d2SAndroid Build Coastguard Worker     return (-1);
1354*5e7646d2SAndroid Build Coastguard Worker   }
1355*5e7646d2SAndroid Build Coastguard Worker 
1356*5e7646d2SAndroid Build Coastguard Worker  /*
1357*5e7646d2SAndroid Build Coastguard Worker   * Initiate a ClientHello message and generate a token.
1358*5e7646d2SAndroid Build Coastguard Worker   */
1359*5e7646d2SAndroid Build Coastguard Worker 
1360*5e7646d2SAndroid Build Coastguard Worker   outBuffers[0].pvBuffer   = NULL;
1361*5e7646d2SAndroid Build Coastguard Worker   outBuffers[0].BufferType = SECBUFFER_TOKEN;
1362*5e7646d2SAndroid Build Coastguard Worker   outBuffers[0].cbBuffer   = 0;
1363*5e7646d2SAndroid Build Coastguard Worker 
1364*5e7646d2SAndroid Build Coastguard Worker   outBuffer.cBuffers  = 1;
1365*5e7646d2SAndroid Build Coastguard Worker   outBuffer.pBuffers  = outBuffers;
1366*5e7646d2SAndroid Build Coastguard Worker   outBuffer.ulVersion = SECBUFFER_VERSION;
1367*5e7646d2SAndroid Build Coastguard Worker 
1368*5e7646d2SAndroid Build Coastguard Worker   scRet = InitializeSecurityContext(&sspi->creds, NULL, TEXT(""), dwSSPIFlags, 0, SECURITY_NATIVE_DREP, NULL, 0, &sspi->context, &outBuffer, &dwSSPIOutFlags, &tsExpiry);
1369*5e7646d2SAndroid Build Coastguard Worker 
1370*5e7646d2SAndroid Build Coastguard Worker   if (scRet != SEC_I_CONTINUE_NEEDED)
1371*5e7646d2SAndroid Build Coastguard Worker   {
1372*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("5http_sspi_client: InitializeSecurityContext(1) failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
1373*5e7646d2SAndroid Build Coastguard Worker     return (-1);
1374*5e7646d2SAndroid Build Coastguard Worker   }
1375*5e7646d2SAndroid Build Coastguard Worker 
1376*5e7646d2SAndroid Build Coastguard Worker  /*
1377*5e7646d2SAndroid Build Coastguard Worker   * Send response to server if there is one.
1378*5e7646d2SAndroid Build Coastguard Worker   */
1379*5e7646d2SAndroid Build Coastguard Worker 
1380*5e7646d2SAndroid Build Coastguard Worker   if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer)
1381*5e7646d2SAndroid Build Coastguard Worker   {
1382*5e7646d2SAndroid Build Coastguard Worker     if ((cbData = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0)) <= 0)
1383*5e7646d2SAndroid Build Coastguard Worker     {
1384*5e7646d2SAndroid Build Coastguard Worker       DEBUG_printf(("5http_sspi_client: send failed: %d", WSAGetLastError()));
1385*5e7646d2SAndroid Build Coastguard Worker       FreeContextBuffer(outBuffers[0].pvBuffer);
1386*5e7646d2SAndroid Build Coastguard Worker       DeleteSecurityContext(&sspi->context);
1387*5e7646d2SAndroid Build Coastguard Worker       return (-1);
1388*5e7646d2SAndroid Build Coastguard Worker     }
1389*5e7646d2SAndroid Build Coastguard Worker 
1390*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("5http_sspi_client: %d bytes of handshake data sent.", cbData));
1391*5e7646d2SAndroid Build Coastguard Worker 
1392*5e7646d2SAndroid Build Coastguard Worker     FreeContextBuffer(outBuffers[0].pvBuffer);
1393*5e7646d2SAndroid Build Coastguard Worker     outBuffers[0].pvBuffer = NULL;
1394*5e7646d2SAndroid Build Coastguard Worker   }
1395*5e7646d2SAndroid Build Coastguard Worker 
1396*5e7646d2SAndroid Build Coastguard Worker   dwSSPIFlags = ISC_REQ_MANUAL_CRED_VALIDATION |
1397*5e7646d2SAndroid Build Coastguard Worker 		ISC_REQ_SEQUENCE_DETECT        |
1398*5e7646d2SAndroid Build Coastguard Worker                 ISC_REQ_REPLAY_DETECT          |
1399*5e7646d2SAndroid Build Coastguard Worker                 ISC_REQ_CONFIDENTIALITY        |
1400*5e7646d2SAndroid Build Coastguard Worker                 ISC_RET_EXTENDED_ERROR         |
1401*5e7646d2SAndroid Build Coastguard Worker                 ISC_REQ_ALLOCATE_MEMORY        |
1402*5e7646d2SAndroid Build Coastguard Worker                 ISC_REQ_STREAM;
1403*5e7646d2SAndroid Build Coastguard Worker 
1404*5e7646d2SAndroid Build Coastguard Worker   sspi->decryptBufferUsed = 0;
1405*5e7646d2SAndroid Build Coastguard Worker 
1406*5e7646d2SAndroid Build Coastguard Worker  /*
1407*5e7646d2SAndroid Build Coastguard Worker   * Loop until the handshake is finished or an error occurs.
1408*5e7646d2SAndroid Build Coastguard Worker   */
1409*5e7646d2SAndroid Build Coastguard Worker 
1410*5e7646d2SAndroid Build Coastguard Worker   scRet = SEC_I_CONTINUE_NEEDED;
1411*5e7646d2SAndroid Build Coastguard Worker 
1412*5e7646d2SAndroid Build Coastguard Worker   while(scRet == SEC_I_CONTINUE_NEEDED        ||
1413*5e7646d2SAndroid Build Coastguard Worker         scRet == SEC_E_INCOMPLETE_MESSAGE     ||
1414*5e7646d2SAndroid Build Coastguard Worker         scRet == SEC_I_INCOMPLETE_CREDENTIALS)
1415*5e7646d2SAndroid Build Coastguard Worker   {
1416*5e7646d2SAndroid Build Coastguard Worker     if (sspi->decryptBufferUsed == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE)
1417*5e7646d2SAndroid Build Coastguard Worker     {
1418*5e7646d2SAndroid Build Coastguard Worker       if (sspi->decryptBufferLength <= sspi->decryptBufferUsed)
1419*5e7646d2SAndroid Build Coastguard Worker       {
1420*5e7646d2SAndroid Build Coastguard Worker 	BYTE *temp;			/* New buffer */
1421*5e7646d2SAndroid Build Coastguard Worker 
1422*5e7646d2SAndroid Build Coastguard Worker 	if (sspi->decryptBufferLength >= 262144)
1423*5e7646d2SAndroid Build Coastguard Worker 	{
1424*5e7646d2SAndroid Build Coastguard Worker 	  WSASetLastError(E_OUTOFMEMORY);
1425*5e7646d2SAndroid Build Coastguard Worker 	  DEBUG_puts("5http_sspi_client: Decryption buffer too large (>256k)");
1426*5e7646d2SAndroid Build Coastguard Worker 	  return (-1);
1427*5e7646d2SAndroid Build Coastguard Worker 	}
1428*5e7646d2SAndroid Build Coastguard Worker 
1429*5e7646d2SAndroid Build Coastguard Worker 	if ((temp = realloc(sspi->decryptBuffer, sspi->decryptBufferLength + 4096)) == NULL)
1430*5e7646d2SAndroid Build Coastguard Worker 	{
1431*5e7646d2SAndroid Build Coastguard Worker 	  DEBUG_printf(("5http_sspi_client: Unable to allocate %d byte buffer.", sspi->decryptBufferLength + 4096));
1432*5e7646d2SAndroid Build Coastguard Worker 	  WSASetLastError(E_OUTOFMEMORY);
1433*5e7646d2SAndroid Build Coastguard Worker 	  return (-1);
1434*5e7646d2SAndroid Build Coastguard Worker 	}
1435*5e7646d2SAndroid Build Coastguard Worker 
1436*5e7646d2SAndroid Build Coastguard Worker 	sspi->decryptBufferLength += 4096;
1437*5e7646d2SAndroid Build Coastguard Worker 	sspi->decryptBuffer       = temp;
1438*5e7646d2SAndroid Build Coastguard Worker       }
1439*5e7646d2SAndroid Build Coastguard Worker 
1440*5e7646d2SAndroid Build Coastguard Worker       cbData = recv(http->fd, sspi->decryptBuffer + sspi->decryptBufferUsed, (int)(sspi->decryptBufferLength - sspi->decryptBufferUsed), 0);
1441*5e7646d2SAndroid Build Coastguard Worker 
1442*5e7646d2SAndroid Build Coastguard Worker       if (cbData < 0)
1443*5e7646d2SAndroid Build Coastguard Worker       {
1444*5e7646d2SAndroid Build Coastguard Worker         DEBUG_printf(("5http_sspi_client: recv failed: %d", WSAGetLastError()));
1445*5e7646d2SAndroid Build Coastguard Worker         return (-1);
1446*5e7646d2SAndroid Build Coastguard Worker       }
1447*5e7646d2SAndroid Build Coastguard Worker       else if (cbData == 0)
1448*5e7646d2SAndroid Build Coastguard Worker       {
1449*5e7646d2SAndroid Build Coastguard Worker         DEBUG_printf(("5http_sspi_client: Server unexpectedly disconnected."));
1450*5e7646d2SAndroid Build Coastguard Worker         return (-1);
1451*5e7646d2SAndroid Build Coastguard Worker       }
1452*5e7646d2SAndroid Build Coastguard Worker 
1453*5e7646d2SAndroid Build Coastguard Worker       DEBUG_printf(("5http_sspi_client: %d bytes of handshake data received", cbData));
1454*5e7646d2SAndroid Build Coastguard Worker 
1455*5e7646d2SAndroid Build Coastguard Worker       sspi->decryptBufferUsed += cbData;
1456*5e7646d2SAndroid Build Coastguard Worker     }
1457*5e7646d2SAndroid Build Coastguard Worker 
1458*5e7646d2SAndroid Build Coastguard Worker    /*
1459*5e7646d2SAndroid Build Coastguard Worker     * Set up the input buffers. Buffer 0 is used to pass in data received from
1460*5e7646d2SAndroid Build Coastguard Worker     * the server.  Schannel will consume some or all of this.  Leftover data
1461*5e7646d2SAndroid Build Coastguard Worker     * (if any) will be placed in buffer 1 and given a buffer type of
1462*5e7646d2SAndroid Build Coastguard Worker     * SECBUFFER_EXTRA.
1463*5e7646d2SAndroid Build Coastguard Worker     */
1464*5e7646d2SAndroid Build Coastguard Worker 
1465*5e7646d2SAndroid Build Coastguard Worker     inBuffers[0].pvBuffer   = sspi->decryptBuffer;
1466*5e7646d2SAndroid Build Coastguard Worker     inBuffers[0].cbBuffer   = (unsigned long)sspi->decryptBufferUsed;
1467*5e7646d2SAndroid Build Coastguard Worker     inBuffers[0].BufferType = SECBUFFER_TOKEN;
1468*5e7646d2SAndroid Build Coastguard Worker 
1469*5e7646d2SAndroid Build Coastguard Worker     inBuffers[1].pvBuffer   = NULL;
1470*5e7646d2SAndroid Build Coastguard Worker     inBuffers[1].cbBuffer   = 0;
1471*5e7646d2SAndroid Build Coastguard Worker     inBuffers[1].BufferType = SECBUFFER_EMPTY;
1472*5e7646d2SAndroid Build Coastguard Worker 
1473*5e7646d2SAndroid Build Coastguard Worker     inBuffer.cBuffers       = 2;
1474*5e7646d2SAndroid Build Coastguard Worker     inBuffer.pBuffers       = inBuffers;
1475*5e7646d2SAndroid Build Coastguard Worker     inBuffer.ulVersion      = SECBUFFER_VERSION;
1476*5e7646d2SAndroid Build Coastguard Worker 
1477*5e7646d2SAndroid Build Coastguard Worker    /*
1478*5e7646d2SAndroid Build Coastguard Worker     * Set up the output buffers. These are initialized to NULL so as to make it
1479*5e7646d2SAndroid Build Coastguard Worker     * less likely we'll attempt to free random garbage later.
1480*5e7646d2SAndroid Build Coastguard Worker     */
1481*5e7646d2SAndroid Build Coastguard Worker 
1482*5e7646d2SAndroid Build Coastguard Worker     outBuffers[0].pvBuffer   = NULL;
1483*5e7646d2SAndroid Build Coastguard Worker     outBuffers[0].BufferType = SECBUFFER_TOKEN;
1484*5e7646d2SAndroid Build Coastguard Worker     outBuffers[0].cbBuffer   = 0;
1485*5e7646d2SAndroid Build Coastguard Worker 
1486*5e7646d2SAndroid Build Coastguard Worker     outBuffer.cBuffers       = 1;
1487*5e7646d2SAndroid Build Coastguard Worker     outBuffer.pBuffers       = outBuffers;
1488*5e7646d2SAndroid Build Coastguard Worker     outBuffer.ulVersion      = SECBUFFER_VERSION;
1489*5e7646d2SAndroid Build Coastguard Worker 
1490*5e7646d2SAndroid Build Coastguard Worker    /*
1491*5e7646d2SAndroid Build Coastguard Worker     * Call InitializeSecurityContext.
1492*5e7646d2SAndroid Build Coastguard Worker     */
1493*5e7646d2SAndroid Build Coastguard Worker 
1494*5e7646d2SAndroid Build Coastguard Worker     scRet = InitializeSecurityContext(&sspi->creds, &sspi->context, NULL, dwSSPIFlags, 0, SECURITY_NATIVE_DREP, &inBuffer, 0, NULL, &outBuffer, &dwSSPIOutFlags, &tsExpiry);
1495*5e7646d2SAndroid Build Coastguard Worker 
1496*5e7646d2SAndroid Build Coastguard Worker    /*
1497*5e7646d2SAndroid Build Coastguard Worker     * If InitializeSecurityContext was successful (or if the error was one of
1498*5e7646d2SAndroid Build Coastguard Worker     * the special extended ones), send the contents of the output buffer to the
1499*5e7646d2SAndroid Build Coastguard Worker     * server.
1500*5e7646d2SAndroid Build Coastguard Worker     */
1501*5e7646d2SAndroid Build Coastguard Worker 
1502*5e7646d2SAndroid Build Coastguard Worker     if (scRet == SEC_E_OK                ||
1503*5e7646d2SAndroid Build Coastguard Worker         scRet == SEC_I_CONTINUE_NEEDED   ||
1504*5e7646d2SAndroid Build Coastguard Worker         FAILED(scRet) && (dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR))
1505*5e7646d2SAndroid Build Coastguard Worker     {
1506*5e7646d2SAndroid Build Coastguard Worker       if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer)
1507*5e7646d2SAndroid Build Coastguard Worker       {
1508*5e7646d2SAndroid Build Coastguard Worker         cbData = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0);
1509*5e7646d2SAndroid Build Coastguard Worker 
1510*5e7646d2SAndroid Build Coastguard Worker         if (cbData <= 0)
1511*5e7646d2SAndroid Build Coastguard Worker         {
1512*5e7646d2SAndroid Build Coastguard Worker           DEBUG_printf(("5http_sspi_client: send failed: %d", WSAGetLastError()));
1513*5e7646d2SAndroid Build Coastguard Worker           FreeContextBuffer(outBuffers[0].pvBuffer);
1514*5e7646d2SAndroid Build Coastguard Worker           DeleteSecurityContext(&sspi->context);
1515*5e7646d2SAndroid Build Coastguard Worker           return (-1);
1516*5e7646d2SAndroid Build Coastguard Worker         }
1517*5e7646d2SAndroid Build Coastguard Worker 
1518*5e7646d2SAndroid Build Coastguard Worker         DEBUG_printf(("5http_sspi_client: %d bytes of handshake data sent.", cbData));
1519*5e7646d2SAndroid Build Coastguard Worker 
1520*5e7646d2SAndroid Build Coastguard Worker        /*
1521*5e7646d2SAndroid Build Coastguard Worker         * Free output buffer.
1522*5e7646d2SAndroid Build Coastguard Worker         */
1523*5e7646d2SAndroid Build Coastguard Worker 
1524*5e7646d2SAndroid Build Coastguard Worker         FreeContextBuffer(outBuffers[0].pvBuffer);
1525*5e7646d2SAndroid Build Coastguard Worker         outBuffers[0].pvBuffer = NULL;
1526*5e7646d2SAndroid Build Coastguard Worker       }
1527*5e7646d2SAndroid Build Coastguard Worker     }
1528*5e7646d2SAndroid Build Coastguard Worker 
1529*5e7646d2SAndroid Build Coastguard Worker    /*
1530*5e7646d2SAndroid Build Coastguard Worker     * If InitializeSecurityContext returned SEC_E_INCOMPLETE_MESSAGE, then we
1531*5e7646d2SAndroid Build Coastguard Worker     * need to read more data from the server and try again.
1532*5e7646d2SAndroid Build Coastguard Worker     */
1533*5e7646d2SAndroid Build Coastguard Worker 
1534*5e7646d2SAndroid Build Coastguard Worker     if (scRet == SEC_E_INCOMPLETE_MESSAGE)
1535*5e7646d2SAndroid Build Coastguard Worker       continue;
1536*5e7646d2SAndroid Build Coastguard Worker 
1537*5e7646d2SAndroid Build Coastguard Worker    /*
1538*5e7646d2SAndroid Build Coastguard Worker     * If InitializeSecurityContext returned SEC_E_OK, then the handshake
1539*5e7646d2SAndroid Build Coastguard Worker     * completed successfully.
1540*5e7646d2SAndroid Build Coastguard Worker     */
1541*5e7646d2SAndroid Build Coastguard Worker 
1542*5e7646d2SAndroid Build Coastguard Worker     if (scRet == SEC_E_OK)
1543*5e7646d2SAndroid Build Coastguard Worker     {
1544*5e7646d2SAndroid Build Coastguard Worker      /*
1545*5e7646d2SAndroid Build Coastguard Worker       * If the "extra" buffer contains data, this is encrypted application
1546*5e7646d2SAndroid Build Coastguard Worker       * protocol layer stuff. It needs to be saved. The application layer will
1547*5e7646d2SAndroid Build Coastguard Worker       * later decrypt it with DecryptMessage.
1548*5e7646d2SAndroid Build Coastguard Worker       */
1549*5e7646d2SAndroid Build Coastguard Worker 
1550*5e7646d2SAndroid Build Coastguard Worker       DEBUG_puts("5http_sspi_client: Handshake was successful.");
1551*5e7646d2SAndroid Build Coastguard Worker 
1552*5e7646d2SAndroid Build Coastguard Worker       if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
1553*5e7646d2SAndroid Build Coastguard Worker       {
1554*5e7646d2SAndroid Build Coastguard Worker         memmove(sspi->decryptBuffer, sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer, inBuffers[1].cbBuffer);
1555*5e7646d2SAndroid Build Coastguard Worker 
1556*5e7646d2SAndroid Build Coastguard Worker         sspi->decryptBufferUsed = inBuffers[1].cbBuffer;
1557*5e7646d2SAndroid Build Coastguard Worker 
1558*5e7646d2SAndroid Build Coastguard Worker         DEBUG_printf(("5http_sspi_client: %d bytes of app data was bundled with handshake data", sspi->decryptBufferUsed));
1559*5e7646d2SAndroid Build Coastguard Worker       }
1560*5e7646d2SAndroid Build Coastguard Worker       else
1561*5e7646d2SAndroid Build Coastguard Worker         sspi->decryptBufferUsed = 0;
1562*5e7646d2SAndroid Build Coastguard Worker 
1563*5e7646d2SAndroid Build Coastguard Worker      /*
1564*5e7646d2SAndroid Build Coastguard Worker       * Bail out to quit
1565*5e7646d2SAndroid Build Coastguard Worker       */
1566*5e7646d2SAndroid Build Coastguard Worker 
1567*5e7646d2SAndroid Build Coastguard Worker       break;
1568*5e7646d2SAndroid Build Coastguard Worker     }
1569*5e7646d2SAndroid Build Coastguard Worker 
1570*5e7646d2SAndroid Build Coastguard Worker    /*
1571*5e7646d2SAndroid Build Coastguard Worker     * Check for fatal error.
1572*5e7646d2SAndroid Build Coastguard Worker     */
1573*5e7646d2SAndroid Build Coastguard Worker 
1574*5e7646d2SAndroid Build Coastguard Worker     if (FAILED(scRet))
1575*5e7646d2SAndroid Build Coastguard Worker     {
1576*5e7646d2SAndroid Build Coastguard Worker       DEBUG_printf(("5http_sspi_client: InitializeSecurityContext(2) failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
1577*5e7646d2SAndroid Build Coastguard Worker       ret = -1;
1578*5e7646d2SAndroid Build Coastguard Worker       break;
1579*5e7646d2SAndroid Build Coastguard Worker     }
1580*5e7646d2SAndroid Build Coastguard Worker 
1581*5e7646d2SAndroid Build Coastguard Worker    /*
1582*5e7646d2SAndroid Build Coastguard Worker     * If InitializeSecurityContext returned SEC_I_INCOMPLETE_CREDENTIALS,
1583*5e7646d2SAndroid Build Coastguard Worker     * then the server just requested client authentication.
1584*5e7646d2SAndroid Build Coastguard Worker     */
1585*5e7646d2SAndroid Build Coastguard Worker 
1586*5e7646d2SAndroid Build Coastguard Worker     if (scRet == SEC_I_INCOMPLETE_CREDENTIALS)
1587*5e7646d2SAndroid Build Coastguard Worker     {
1588*5e7646d2SAndroid Build Coastguard Worker      /*
1589*5e7646d2SAndroid Build Coastguard Worker       * Unimplemented
1590*5e7646d2SAndroid Build Coastguard Worker       */
1591*5e7646d2SAndroid Build Coastguard Worker 
1592*5e7646d2SAndroid Build Coastguard Worker       DEBUG_printf(("5http_sspi_client: server requested client credentials."));
1593*5e7646d2SAndroid Build Coastguard Worker       ret = -1;
1594*5e7646d2SAndroid Build Coastguard Worker       break;
1595*5e7646d2SAndroid Build Coastguard Worker     }
1596*5e7646d2SAndroid Build Coastguard Worker 
1597*5e7646d2SAndroid Build Coastguard Worker    /*
1598*5e7646d2SAndroid Build Coastguard Worker     * Copy any leftover data from the "extra" buffer, and go around again.
1599*5e7646d2SAndroid Build Coastguard Worker     */
1600*5e7646d2SAndroid Build Coastguard Worker 
1601*5e7646d2SAndroid Build Coastguard Worker     if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
1602*5e7646d2SAndroid Build Coastguard Worker     {
1603*5e7646d2SAndroid Build Coastguard Worker       memmove(sspi->decryptBuffer, sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer, inBuffers[1].cbBuffer);
1604*5e7646d2SAndroid Build Coastguard Worker 
1605*5e7646d2SAndroid Build Coastguard Worker       sspi->decryptBufferUsed = inBuffers[1].cbBuffer;
1606*5e7646d2SAndroid Build Coastguard Worker     }
1607*5e7646d2SAndroid Build Coastguard Worker     else
1608*5e7646d2SAndroid Build Coastguard Worker     {
1609*5e7646d2SAndroid Build Coastguard Worker       sspi->decryptBufferUsed = 0;
1610*5e7646d2SAndroid Build Coastguard Worker     }
1611*5e7646d2SAndroid Build Coastguard Worker   }
1612*5e7646d2SAndroid Build Coastguard Worker 
1613*5e7646d2SAndroid Build Coastguard Worker   if (!ret)
1614*5e7646d2SAndroid Build Coastguard Worker   {
1615*5e7646d2SAndroid Build Coastguard Worker    /*
1616*5e7646d2SAndroid Build Coastguard Worker     * Success!  Get the server cert
1617*5e7646d2SAndroid Build Coastguard Worker     */
1618*5e7646d2SAndroid Build Coastguard Worker 
1619*5e7646d2SAndroid Build Coastguard Worker     sspi->contextInitialized = TRUE;
1620*5e7646d2SAndroid Build Coastguard Worker 
1621*5e7646d2SAndroid Build Coastguard Worker     scRet = QueryContextAttributes(&sspi->context, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (VOID *)&(sspi->remoteCert));
1622*5e7646d2SAndroid Build Coastguard Worker 
1623*5e7646d2SAndroid Build Coastguard Worker     if (scRet != SEC_E_OK)
1624*5e7646d2SAndroid Build Coastguard Worker     {
1625*5e7646d2SAndroid Build Coastguard Worker       DEBUG_printf(("5http_sspi_client: QueryContextAttributes failed(SECPKG_ATTR_REMOTE_CERT_CONTEXT): %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
1626*5e7646d2SAndroid Build Coastguard Worker       return (-1);
1627*5e7646d2SAndroid Build Coastguard Worker     }
1628*5e7646d2SAndroid Build Coastguard Worker 
1629*5e7646d2SAndroid Build Coastguard Worker    /*
1630*5e7646d2SAndroid Build Coastguard Worker     * Find out how big the header/trailer will be:
1631*5e7646d2SAndroid Build Coastguard Worker     */
1632*5e7646d2SAndroid Build Coastguard Worker 
1633*5e7646d2SAndroid Build Coastguard Worker     scRet = QueryContextAttributes(&sspi->context, SECPKG_ATTR_STREAM_SIZES, &sspi->streamSizes);
1634*5e7646d2SAndroid Build Coastguard Worker 
1635*5e7646d2SAndroid Build Coastguard Worker     if (scRet != SEC_E_OK)
1636*5e7646d2SAndroid Build Coastguard Worker     {
1637*5e7646d2SAndroid Build Coastguard Worker       DEBUG_printf(("5http_sspi_client: QueryContextAttributes failed(SECPKG_ATTR_STREAM_SIZES): %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
1638*5e7646d2SAndroid Build Coastguard Worker       ret = -1;
1639*5e7646d2SAndroid Build Coastguard Worker     }
1640*5e7646d2SAndroid Build Coastguard Worker   }
1641*5e7646d2SAndroid Build Coastguard Worker 
1642*5e7646d2SAndroid Build Coastguard Worker   return (ret);
1643*5e7646d2SAndroid Build Coastguard Worker }
1644*5e7646d2SAndroid Build Coastguard Worker 
1645*5e7646d2SAndroid Build Coastguard Worker 
1646*5e7646d2SAndroid Build Coastguard Worker /*
1647*5e7646d2SAndroid Build Coastguard Worker  * 'http_sspi_create_credential()' - Create an SSPI certificate context.
1648*5e7646d2SAndroid Build Coastguard Worker  */
1649*5e7646d2SAndroid Build Coastguard Worker 
1650*5e7646d2SAndroid Build Coastguard Worker static PCCERT_CONTEXT			/* O - Certificate context */
http_sspi_create_credential(http_credential_t * cred)1651*5e7646d2SAndroid Build Coastguard Worker http_sspi_create_credential(
1652*5e7646d2SAndroid Build Coastguard Worker     http_credential_t *cred)		/* I - Credential */
1653*5e7646d2SAndroid Build Coastguard Worker {
1654*5e7646d2SAndroid Build Coastguard Worker   if (cred)
1655*5e7646d2SAndroid Build Coastguard Worker     return (CertCreateCertificateContext(X509_ASN_ENCODING, cred->data, cred->datalen));
1656*5e7646d2SAndroid Build Coastguard Worker   else
1657*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
1658*5e7646d2SAndroid Build Coastguard Worker }
1659*5e7646d2SAndroid Build Coastguard Worker 
1660*5e7646d2SAndroid Build Coastguard Worker 
1661*5e7646d2SAndroid Build Coastguard Worker /*
1662*5e7646d2SAndroid Build Coastguard Worker  * 'http_sspi_find_credentials()' - Retrieve a TLS certificate from the system store.
1663*5e7646d2SAndroid Build Coastguard Worker  */
1664*5e7646d2SAndroid Build Coastguard Worker 
1665*5e7646d2SAndroid Build Coastguard Worker static BOOL				/* O - 1 on success, 0 on failure */
http_sspi_find_credentials(http_t * http,const LPWSTR container,const char * common_name)1666*5e7646d2SAndroid Build Coastguard Worker http_sspi_find_credentials(
1667*5e7646d2SAndroid Build Coastguard Worker     http_t       *http,			/* I - HTTP connection */
1668*5e7646d2SAndroid Build Coastguard Worker     const LPWSTR container,		/* I - Cert container name */
1669*5e7646d2SAndroid Build Coastguard Worker     const char   *common_name)		/* I - Common name of certificate */
1670*5e7646d2SAndroid Build Coastguard Worker {
1671*5e7646d2SAndroid Build Coastguard Worker   _http_sspi_t	*sspi = http->tls;	/* SSPI data */
1672*5e7646d2SAndroid Build Coastguard Worker   HCERTSTORE	store = NULL;		/* Certificate store */
1673*5e7646d2SAndroid Build Coastguard Worker   PCCERT_CONTEXT storedContext = NULL;	/* Context created from the store */
1674*5e7646d2SAndroid Build Coastguard Worker   DWORD		dwSize = 0; 		/* 32 bit size */
1675*5e7646d2SAndroid Build Coastguard Worker   PBYTE		p = NULL;		/* Temporary storage */
1676*5e7646d2SAndroid Build Coastguard Worker   HCRYPTPROV	hProv = (HCRYPTPROV)NULL;
1677*5e7646d2SAndroid Build Coastguard Worker 					/* Handle to a CSP */
1678*5e7646d2SAndroid Build Coastguard Worker   CERT_NAME_BLOB sib;			/* Arbitrary array of bytes */
1679*5e7646d2SAndroid Build Coastguard Worker   SCHANNEL_CRED	SchannelCred;		/* Schannel credential data */
1680*5e7646d2SAndroid Build Coastguard Worker   TimeStamp	tsExpiry;		/* Time stamp */
1681*5e7646d2SAndroid Build Coastguard Worker   SECURITY_STATUS Status;		/* Status */
1682*5e7646d2SAndroid Build Coastguard Worker   BOOL		ok = TRUE;		/* Return value */
1683*5e7646d2SAndroid Build Coastguard Worker 
1684*5e7646d2SAndroid Build Coastguard Worker 
1685*5e7646d2SAndroid Build Coastguard Worker   if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET))
1686*5e7646d2SAndroid Build Coastguard Worker   {
1687*5e7646d2SAndroid Build Coastguard Worker     if (GetLastError() == NTE_EXISTS)
1688*5e7646d2SAndroid Build Coastguard Worker     {
1689*5e7646d2SAndroid Build Coastguard Worker       if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
1690*5e7646d2SAndroid Build Coastguard Worker       {
1691*5e7646d2SAndroid Build Coastguard Worker         DEBUG_printf(("5http_sspi_find_credentials: CryptAcquireContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
1692*5e7646d2SAndroid Build Coastguard Worker         ok = FALSE;
1693*5e7646d2SAndroid Build Coastguard Worker         goto cleanup;
1694*5e7646d2SAndroid Build Coastguard Worker       }
1695*5e7646d2SAndroid Build Coastguard Worker     }
1696*5e7646d2SAndroid Build Coastguard Worker   }
1697*5e7646d2SAndroid Build Coastguard Worker 
1698*5e7646d2SAndroid Build Coastguard Worker   store = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING, hProv, CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_NO_CRYPT_RELEASE_FLAG | CERT_STORE_OPEN_EXISTING_FLAG, L"MY");
1699*5e7646d2SAndroid Build Coastguard Worker 
1700*5e7646d2SAndroid Build Coastguard Worker   if (!store)
1701*5e7646d2SAndroid Build Coastguard Worker   {
1702*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("5http_sspi_find_credentials: CertOpenSystemStore failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
1703*5e7646d2SAndroid Build Coastguard Worker     ok = FALSE;
1704*5e7646d2SAndroid Build Coastguard Worker     goto cleanup;
1705*5e7646d2SAndroid Build Coastguard Worker   }
1706*5e7646d2SAndroid Build Coastguard Worker 
1707*5e7646d2SAndroid Build Coastguard Worker   if (common_name)
1708*5e7646d2SAndroid Build Coastguard Worker   {
1709*5e7646d2SAndroid Build Coastguard Worker     dwSize = 0;
1710*5e7646d2SAndroid Build Coastguard Worker 
1711*5e7646d2SAndroid Build Coastguard Worker     if (!CertStrToNameA(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL))
1712*5e7646d2SAndroid Build Coastguard Worker     {
1713*5e7646d2SAndroid Build Coastguard Worker       DEBUG_printf(("5http_sspi_find_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
1714*5e7646d2SAndroid Build Coastguard Worker       ok = FALSE;
1715*5e7646d2SAndroid Build Coastguard Worker       goto cleanup;
1716*5e7646d2SAndroid Build Coastguard Worker     }
1717*5e7646d2SAndroid Build Coastguard Worker 
1718*5e7646d2SAndroid Build Coastguard Worker     p = (PBYTE)malloc(dwSize);
1719*5e7646d2SAndroid Build Coastguard Worker 
1720*5e7646d2SAndroid Build Coastguard Worker     if (!p)
1721*5e7646d2SAndroid Build Coastguard Worker     {
1722*5e7646d2SAndroid Build Coastguard Worker       DEBUG_printf(("5http_sspi_find_credentials: malloc failed for %d bytes.", dwSize));
1723*5e7646d2SAndroid Build Coastguard Worker       ok = FALSE;
1724*5e7646d2SAndroid Build Coastguard Worker       goto cleanup;
1725*5e7646d2SAndroid Build Coastguard Worker     }
1726*5e7646d2SAndroid Build Coastguard Worker 
1727*5e7646d2SAndroid Build Coastguard Worker     if (!CertStrToNameA(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL))
1728*5e7646d2SAndroid Build Coastguard Worker     {
1729*5e7646d2SAndroid Build Coastguard Worker       DEBUG_printf(("5http_sspi_find_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
1730*5e7646d2SAndroid Build Coastguard Worker       ok = FALSE;
1731*5e7646d2SAndroid Build Coastguard Worker       goto cleanup;
1732*5e7646d2SAndroid Build Coastguard Worker     }
1733*5e7646d2SAndroid Build Coastguard Worker 
1734*5e7646d2SAndroid Build Coastguard Worker     sib.cbData = dwSize;
1735*5e7646d2SAndroid Build Coastguard Worker     sib.pbData = p;
1736*5e7646d2SAndroid Build Coastguard Worker 
1737*5e7646d2SAndroid Build Coastguard Worker     storedContext = CertFindCertificateInStore(store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_NAME, &sib, NULL);
1738*5e7646d2SAndroid Build Coastguard Worker 
1739*5e7646d2SAndroid Build Coastguard Worker     if (!storedContext)
1740*5e7646d2SAndroid Build Coastguard Worker     {
1741*5e7646d2SAndroid Build Coastguard Worker       DEBUG_printf(("5http_sspi_find_credentials: Unable to find credentials for \"%s\".", common_name));
1742*5e7646d2SAndroid Build Coastguard Worker       ok = FALSE;
1743*5e7646d2SAndroid Build Coastguard Worker       goto cleanup;
1744*5e7646d2SAndroid Build Coastguard Worker     }
1745*5e7646d2SAndroid Build Coastguard Worker   }
1746*5e7646d2SAndroid Build Coastguard Worker 
1747*5e7646d2SAndroid Build Coastguard Worker   ZeroMemory(&SchannelCred, sizeof(SchannelCred));
1748*5e7646d2SAndroid Build Coastguard Worker 
1749*5e7646d2SAndroid Build Coastguard Worker   SchannelCred.dwVersion = SCHANNEL_CRED_VERSION;
1750*5e7646d2SAndroid Build Coastguard Worker 
1751*5e7646d2SAndroid Build Coastguard Worker   if (common_name)
1752*5e7646d2SAndroid Build Coastguard Worker   {
1753*5e7646d2SAndroid Build Coastguard Worker     SchannelCred.cCreds = 1;
1754*5e7646d2SAndroid Build Coastguard Worker     SchannelCred.paCred = &storedContext;
1755*5e7646d2SAndroid Build Coastguard Worker   }
1756*5e7646d2SAndroid Build Coastguard Worker 
1757*5e7646d2SAndroid Build Coastguard Worker  /*
1758*5e7646d2SAndroid Build Coastguard Worker   * Set supported protocols (can also be overriden in the registry...)
1759*5e7646d2SAndroid Build Coastguard Worker   */
1760*5e7646d2SAndroid Build Coastguard Worker 
1761*5e7646d2SAndroid Build Coastguard Worker #ifdef SP_PROT_TLS1_2_SERVER
1762*5e7646d2SAndroid Build Coastguard Worker   if (http->mode == _HTTP_MODE_SERVER)
1763*5e7646d2SAndroid Build Coastguard Worker   {
1764*5e7646d2SAndroid Build Coastguard Worker     if (tls_min_version > _HTTP_TLS_1_1)
1765*5e7646d2SAndroid Build Coastguard Worker       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER;
1766*5e7646d2SAndroid Build Coastguard Worker     else if (tls_min_version > _HTTP_TLS_1_0)
1767*5e7646d2SAndroid Build Coastguard Worker       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER;
1768*5e7646d2SAndroid Build Coastguard Worker     else if (tls_min_version == _HTTP_TLS_SSL3)
1769*5e7646d2SAndroid Build Coastguard Worker       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_0_SERVER | SP_PROT_SSL3_SERVER;
1770*5e7646d2SAndroid Build Coastguard Worker     else
1771*5e7646d2SAndroid Build Coastguard Worker       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_0_SERVER;
1772*5e7646d2SAndroid Build Coastguard Worker   }
1773*5e7646d2SAndroid Build Coastguard Worker   else
1774*5e7646d2SAndroid Build Coastguard Worker   {
1775*5e7646d2SAndroid Build Coastguard Worker     if (tls_min_version > _HTTP_TLS_1_1)
1776*5e7646d2SAndroid Build Coastguard Worker       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT;
1777*5e7646d2SAndroid Build Coastguard Worker     else if (tls_min_version > _HTTP_TLS_1_0)
1778*5e7646d2SAndroid Build Coastguard Worker       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT;
1779*5e7646d2SAndroid Build Coastguard Worker     else if (tls_min_version == _HTTP_TLS_SSL3)
1780*5e7646d2SAndroid Build Coastguard Worker       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_0_CLIENT | SP_PROT_SSL3_CLIENT;
1781*5e7646d2SAndroid Build Coastguard Worker     else
1782*5e7646d2SAndroid Build Coastguard Worker       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_0_CLIENT;
1783*5e7646d2SAndroid Build Coastguard Worker   }
1784*5e7646d2SAndroid Build Coastguard Worker 
1785*5e7646d2SAndroid Build Coastguard Worker #else
1786*5e7646d2SAndroid Build Coastguard Worker   if (http->mode == _HTTP_MODE_SERVER)
1787*5e7646d2SAndroid Build Coastguard Worker   {
1788*5e7646d2SAndroid Build Coastguard Worker     if (tls_min_version == _HTTP_TLS_SSL3)
1789*5e7646d2SAndroid Build Coastguard Worker       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_SERVER | SP_PROT_SSL3_SERVER;
1790*5e7646d2SAndroid Build Coastguard Worker     else
1791*5e7646d2SAndroid Build Coastguard Worker       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_SERVER;
1792*5e7646d2SAndroid Build Coastguard Worker   }
1793*5e7646d2SAndroid Build Coastguard Worker   else
1794*5e7646d2SAndroid Build Coastguard Worker   {
1795*5e7646d2SAndroid Build Coastguard Worker     if (tls_min_version == _HTTP_TLS_SSL3)
1796*5e7646d2SAndroid Build Coastguard Worker       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT | SP_PROT_SSL3_CLIENT;
1797*5e7646d2SAndroid Build Coastguard Worker     else
1798*5e7646d2SAndroid Build Coastguard Worker       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT;
1799*5e7646d2SAndroid Build Coastguard Worker   }
1800*5e7646d2SAndroid Build Coastguard Worker #endif /* SP_PROT_TLS1_2_SERVER */
1801*5e7646d2SAndroid Build Coastguard Worker 
1802*5e7646d2SAndroid Build Coastguard Worker   /* TODO: Support _HTTP_TLS_ALLOW_RC4, _HTTP_TLS_ALLOW_DH, and _HTTP_TLS_DENY_CBC options; right now we'll rely on Windows registry to enable/disable RC4/DH/CBC... */
1803*5e7646d2SAndroid Build Coastguard Worker 
1804*5e7646d2SAndroid Build Coastguard Worker  /*
1805*5e7646d2SAndroid Build Coastguard Worker   * Create an SSPI credential.
1806*5e7646d2SAndroid Build Coastguard Worker   */
1807*5e7646d2SAndroid Build Coastguard Worker 
1808*5e7646d2SAndroid Build Coastguard Worker   Status = AcquireCredentialsHandle(NULL, UNISP_NAME, http->mode == _HTTP_MODE_SERVER ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND, NULL, &SchannelCred, NULL, NULL, &sspi->creds, &tsExpiry);
1809*5e7646d2SAndroid Build Coastguard Worker   if (Status != SEC_E_OK)
1810*5e7646d2SAndroid Build Coastguard Worker   {
1811*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("5http_sspi_find_credentials: AcquireCredentialsHandle failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), Status)));
1812*5e7646d2SAndroid Build Coastguard Worker     ok = FALSE;
1813*5e7646d2SAndroid Build Coastguard Worker     goto cleanup;
1814*5e7646d2SAndroid Build Coastguard Worker   }
1815*5e7646d2SAndroid Build Coastguard Worker 
1816*5e7646d2SAndroid Build Coastguard Worker cleanup:
1817*5e7646d2SAndroid Build Coastguard Worker 
1818*5e7646d2SAndroid Build Coastguard Worker  /*
1819*5e7646d2SAndroid Build Coastguard Worker   * Cleanup
1820*5e7646d2SAndroid Build Coastguard Worker   */
1821*5e7646d2SAndroid Build Coastguard Worker 
1822*5e7646d2SAndroid Build Coastguard Worker   if (storedContext)
1823*5e7646d2SAndroid Build Coastguard Worker     CertFreeCertificateContext(storedContext);
1824*5e7646d2SAndroid Build Coastguard Worker 
1825*5e7646d2SAndroid Build Coastguard Worker   if (p)
1826*5e7646d2SAndroid Build Coastguard Worker     free(p);
1827*5e7646d2SAndroid Build Coastguard Worker 
1828*5e7646d2SAndroid Build Coastguard Worker   if (store)
1829*5e7646d2SAndroid Build Coastguard Worker     CertCloseStore(store, 0);
1830*5e7646d2SAndroid Build Coastguard Worker 
1831*5e7646d2SAndroid Build Coastguard Worker   if (hProv)
1832*5e7646d2SAndroid Build Coastguard Worker     CryptReleaseContext(hProv, 0);
1833*5e7646d2SAndroid Build Coastguard Worker 
1834*5e7646d2SAndroid Build Coastguard Worker   return (ok);
1835*5e7646d2SAndroid Build Coastguard Worker }
1836*5e7646d2SAndroid Build Coastguard Worker 
1837*5e7646d2SAndroid Build Coastguard Worker 
1838*5e7646d2SAndroid Build Coastguard Worker /*
1839*5e7646d2SAndroid Build Coastguard Worker  * 'http_sspi_free()' - Close a connection and free resources.
1840*5e7646d2SAndroid Build Coastguard Worker  */
1841*5e7646d2SAndroid Build Coastguard Worker 
1842*5e7646d2SAndroid Build Coastguard Worker static void
http_sspi_free(_http_sspi_t * sspi)1843*5e7646d2SAndroid Build Coastguard Worker http_sspi_free(_http_sspi_t *sspi)	/* I - SSPI data */
1844*5e7646d2SAndroid Build Coastguard Worker {
1845*5e7646d2SAndroid Build Coastguard Worker   if (!sspi)
1846*5e7646d2SAndroid Build Coastguard Worker     return;
1847*5e7646d2SAndroid Build Coastguard Worker 
1848*5e7646d2SAndroid Build Coastguard Worker   if (sspi->contextInitialized)
1849*5e7646d2SAndroid Build Coastguard Worker     DeleteSecurityContext(&sspi->context);
1850*5e7646d2SAndroid Build Coastguard Worker 
1851*5e7646d2SAndroid Build Coastguard Worker   if (sspi->decryptBuffer)
1852*5e7646d2SAndroid Build Coastguard Worker     free(sspi->decryptBuffer);
1853*5e7646d2SAndroid Build Coastguard Worker 
1854*5e7646d2SAndroid Build Coastguard Worker   if (sspi->readBuffer)
1855*5e7646d2SAndroid Build Coastguard Worker     free(sspi->readBuffer);
1856*5e7646d2SAndroid Build Coastguard Worker 
1857*5e7646d2SAndroid Build Coastguard Worker   if (sspi->writeBuffer)
1858*5e7646d2SAndroid Build Coastguard Worker     free(sspi->writeBuffer);
1859*5e7646d2SAndroid Build Coastguard Worker 
1860*5e7646d2SAndroid Build Coastguard Worker   if (sspi->localCert)
1861*5e7646d2SAndroid Build Coastguard Worker     CertFreeCertificateContext(sspi->localCert);
1862*5e7646d2SAndroid Build Coastguard Worker 
1863*5e7646d2SAndroid Build Coastguard Worker   if (sspi->remoteCert)
1864*5e7646d2SAndroid Build Coastguard Worker     CertFreeCertificateContext(sspi->remoteCert);
1865*5e7646d2SAndroid Build Coastguard Worker 
1866*5e7646d2SAndroid Build Coastguard Worker   free(sspi);
1867*5e7646d2SAndroid Build Coastguard Worker }
1868*5e7646d2SAndroid Build Coastguard Worker 
1869*5e7646d2SAndroid Build Coastguard Worker 
1870*5e7646d2SAndroid Build Coastguard Worker /*
1871*5e7646d2SAndroid Build Coastguard Worker  * 'http_sspi_make_credentials()' - Create a TLS certificate in the system store.
1872*5e7646d2SAndroid Build Coastguard Worker  */
1873*5e7646d2SAndroid Build Coastguard Worker 
1874*5e7646d2SAndroid Build Coastguard Worker static BOOL				/* O - 1 on success, 0 on failure */
http_sspi_make_credentials(_http_sspi_t * sspi,const LPWSTR container,const char * common_name,_http_mode_t mode,int years)1875*5e7646d2SAndroid Build Coastguard Worker http_sspi_make_credentials(
1876*5e7646d2SAndroid Build Coastguard Worker     _http_sspi_t *sspi,			/* I - SSPI data */
1877*5e7646d2SAndroid Build Coastguard Worker     const LPWSTR container,		/* I - Cert container name */
1878*5e7646d2SAndroid Build Coastguard Worker     const char   *common_name,		/* I - Common name of certificate */
1879*5e7646d2SAndroid Build Coastguard Worker     _http_mode_t mode,			/* I - Client or server? */
1880*5e7646d2SAndroid Build Coastguard Worker     int          years)			/* I - Years until expiration */
1881*5e7646d2SAndroid Build Coastguard Worker {
1882*5e7646d2SAndroid Build Coastguard Worker   HCERTSTORE	store = NULL;		/* Certificate store */
1883*5e7646d2SAndroid Build Coastguard Worker   PCCERT_CONTEXT storedContext = NULL;	/* Context created from the store */
1884*5e7646d2SAndroid Build Coastguard Worker   PCCERT_CONTEXT createdContext = NULL;	/* Context created by us */
1885*5e7646d2SAndroid Build Coastguard Worker   DWORD		dwSize = 0; 		/* 32 bit size */
1886*5e7646d2SAndroid Build Coastguard Worker   PBYTE		p = NULL;		/* Temporary storage */
1887*5e7646d2SAndroid Build Coastguard Worker   HCRYPTPROV	hProv = (HCRYPTPROV)NULL;
1888*5e7646d2SAndroid Build Coastguard Worker 					/* Handle to a CSP */
1889*5e7646d2SAndroid Build Coastguard Worker   CERT_NAME_BLOB sib;			/* Arbitrary array of bytes */
1890*5e7646d2SAndroid Build Coastguard Worker   SCHANNEL_CRED	SchannelCred;		/* Schannel credential data */
1891*5e7646d2SAndroid Build Coastguard Worker   TimeStamp	tsExpiry;		/* Time stamp */
1892*5e7646d2SAndroid Build Coastguard Worker   SECURITY_STATUS Status;		/* Status */
1893*5e7646d2SAndroid Build Coastguard Worker   HCRYPTKEY	hKey = (HCRYPTKEY)NULL;	/* Handle to crypto key */
1894*5e7646d2SAndroid Build Coastguard Worker   CRYPT_KEY_PROV_INFO kpi;		/* Key container info */
1895*5e7646d2SAndroid Build Coastguard Worker   SYSTEMTIME	et;			/* System time */
1896*5e7646d2SAndroid Build Coastguard Worker   CERT_EXTENSIONS exts;			/* Array of cert extensions */
1897*5e7646d2SAndroid Build Coastguard Worker   CRYPT_KEY_PROV_INFO ckp;		/* Handle to crypto key */
1898*5e7646d2SAndroid Build Coastguard Worker   BOOL		ok = TRUE;		/* Return value */
1899*5e7646d2SAndroid Build Coastguard Worker 
1900*5e7646d2SAndroid Build Coastguard Worker 
1901*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("4http_sspi_make_credentials(sspi=%p, container=%p, common_name=\"%s\", mode=%d, years=%d)", sspi, container, common_name, mode, years));
1902*5e7646d2SAndroid Build Coastguard Worker 
1903*5e7646d2SAndroid Build Coastguard Worker   if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET))
1904*5e7646d2SAndroid Build Coastguard Worker   {
1905*5e7646d2SAndroid Build Coastguard Worker     if (GetLastError() == NTE_EXISTS)
1906*5e7646d2SAndroid Build Coastguard Worker     {
1907*5e7646d2SAndroid Build Coastguard Worker       if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
1908*5e7646d2SAndroid Build Coastguard Worker       {
1909*5e7646d2SAndroid Build Coastguard Worker         DEBUG_printf(("5http_sspi_make_credentials: CryptAcquireContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
1910*5e7646d2SAndroid Build Coastguard Worker         ok = FALSE;
1911*5e7646d2SAndroid Build Coastguard Worker         goto cleanup;
1912*5e7646d2SAndroid Build Coastguard Worker       }
1913*5e7646d2SAndroid Build Coastguard Worker     }
1914*5e7646d2SAndroid Build Coastguard Worker   }
1915*5e7646d2SAndroid Build Coastguard Worker 
1916*5e7646d2SAndroid Build Coastguard Worker   store = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING, hProv, CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_NO_CRYPT_RELEASE_FLAG | CERT_STORE_OPEN_EXISTING_FLAG, L"MY");
1917*5e7646d2SAndroid Build Coastguard Worker 
1918*5e7646d2SAndroid Build Coastguard Worker   if (!store)
1919*5e7646d2SAndroid Build Coastguard Worker   {
1920*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("5http_sspi_make_credentials: CertOpenSystemStore failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
1921*5e7646d2SAndroid Build Coastguard Worker     ok = FALSE;
1922*5e7646d2SAndroid Build Coastguard Worker     goto cleanup;
1923*5e7646d2SAndroid Build Coastguard Worker   }
1924*5e7646d2SAndroid Build Coastguard Worker 
1925*5e7646d2SAndroid Build Coastguard Worker   dwSize = 0;
1926*5e7646d2SAndroid Build Coastguard Worker 
1927*5e7646d2SAndroid Build Coastguard Worker   if (!CertStrToNameA(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL))
1928*5e7646d2SAndroid Build Coastguard Worker   {
1929*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("5http_sspi_make_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
1930*5e7646d2SAndroid Build Coastguard Worker     ok = FALSE;
1931*5e7646d2SAndroid Build Coastguard Worker     goto cleanup;
1932*5e7646d2SAndroid Build Coastguard Worker   }
1933*5e7646d2SAndroid Build Coastguard Worker 
1934*5e7646d2SAndroid Build Coastguard Worker   p = (PBYTE)malloc(dwSize);
1935*5e7646d2SAndroid Build Coastguard Worker 
1936*5e7646d2SAndroid Build Coastguard Worker   if (!p)
1937*5e7646d2SAndroid Build Coastguard Worker   {
1938*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("5http_sspi_make_credentials: malloc failed for %d bytes", dwSize));
1939*5e7646d2SAndroid Build Coastguard Worker     ok = FALSE;
1940*5e7646d2SAndroid Build Coastguard Worker     goto cleanup;
1941*5e7646d2SAndroid Build Coastguard Worker   }
1942*5e7646d2SAndroid Build Coastguard Worker 
1943*5e7646d2SAndroid Build Coastguard Worker   if (!CertStrToNameA(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL))
1944*5e7646d2SAndroid Build Coastguard Worker   {
1945*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("5http_sspi_make_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
1946*5e7646d2SAndroid Build Coastguard Worker     ok = FALSE;
1947*5e7646d2SAndroid Build Coastguard Worker     goto cleanup;
1948*5e7646d2SAndroid Build Coastguard Worker   }
1949*5e7646d2SAndroid Build Coastguard Worker 
1950*5e7646d2SAndroid Build Coastguard Worker  /*
1951*5e7646d2SAndroid Build Coastguard Worker   * Create a private key and self-signed certificate...
1952*5e7646d2SAndroid Build Coastguard Worker   */
1953*5e7646d2SAndroid Build Coastguard Worker 
1954*5e7646d2SAndroid Build Coastguard Worker   if (!CryptGenKey(hProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE, &hKey))
1955*5e7646d2SAndroid Build Coastguard Worker   {
1956*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("5http_sspi_make_credentials: CryptGenKey failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
1957*5e7646d2SAndroid Build Coastguard Worker     ok = FALSE;
1958*5e7646d2SAndroid Build Coastguard Worker     goto cleanup;
1959*5e7646d2SAndroid Build Coastguard Worker   }
1960*5e7646d2SAndroid Build Coastguard Worker 
1961*5e7646d2SAndroid Build Coastguard Worker   ZeroMemory(&kpi, sizeof(kpi));
1962*5e7646d2SAndroid Build Coastguard Worker   kpi.pwszContainerName = (LPWSTR)container;
1963*5e7646d2SAndroid Build Coastguard Worker   kpi.pwszProvName      = MS_DEF_PROV_W;
1964*5e7646d2SAndroid Build Coastguard Worker   kpi.dwProvType        = PROV_RSA_FULL;
1965*5e7646d2SAndroid Build Coastguard Worker   kpi.dwFlags           = CERT_SET_KEY_CONTEXT_PROP_ID;
1966*5e7646d2SAndroid Build Coastguard Worker   kpi.dwKeySpec         = AT_KEYEXCHANGE;
1967*5e7646d2SAndroid Build Coastguard Worker 
1968*5e7646d2SAndroid Build Coastguard Worker   GetSystemTime(&et);
1969*5e7646d2SAndroid Build Coastguard Worker   et.wYear += years;
1970*5e7646d2SAndroid Build Coastguard Worker   if (et.wMonth == 2 && et.wDay == 29)
1971*5e7646d2SAndroid Build Coastguard Worker     et.wDay = 28;			/* Avoid Feb 29th due to leap years */
1972*5e7646d2SAndroid Build Coastguard Worker 
1973*5e7646d2SAndroid Build Coastguard Worker   ZeroMemory(&exts, sizeof(exts));
1974*5e7646d2SAndroid Build Coastguard Worker 
1975*5e7646d2SAndroid Build Coastguard Worker   createdContext = CertCreateSelfSignCertificate(hProv, &sib, 0, &kpi, NULL, NULL, &et, &exts);
1976*5e7646d2SAndroid Build Coastguard Worker 
1977*5e7646d2SAndroid Build Coastguard Worker   if (!createdContext)
1978*5e7646d2SAndroid Build Coastguard Worker   {
1979*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("5http_sspi_make_credentials: CertCreateSelfSignCertificate failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
1980*5e7646d2SAndroid Build Coastguard Worker     ok = FALSE;
1981*5e7646d2SAndroid Build Coastguard Worker     goto cleanup;
1982*5e7646d2SAndroid Build Coastguard Worker   }
1983*5e7646d2SAndroid Build Coastguard Worker 
1984*5e7646d2SAndroid Build Coastguard Worker  /*
1985*5e7646d2SAndroid Build Coastguard Worker   * Add the created context to the named store, and associate it with the named
1986*5e7646d2SAndroid Build Coastguard Worker   * container...
1987*5e7646d2SAndroid Build Coastguard Worker   */
1988*5e7646d2SAndroid Build Coastguard Worker 
1989*5e7646d2SAndroid Build Coastguard Worker   if (!CertAddCertificateContextToStore(store, createdContext, CERT_STORE_ADD_REPLACE_EXISTING, &storedContext))
1990*5e7646d2SAndroid Build Coastguard Worker   {
1991*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("5http_sspi_make_credentials: CertAddCertificateContextToStore failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
1992*5e7646d2SAndroid Build Coastguard Worker     ok = FALSE;
1993*5e7646d2SAndroid Build Coastguard Worker     goto cleanup;
1994*5e7646d2SAndroid Build Coastguard Worker   }
1995*5e7646d2SAndroid Build Coastguard Worker 
1996*5e7646d2SAndroid Build Coastguard Worker   ZeroMemory(&ckp, sizeof(ckp));
1997*5e7646d2SAndroid Build Coastguard Worker   ckp.pwszContainerName = (LPWSTR) container;
1998*5e7646d2SAndroid Build Coastguard Worker   ckp.pwszProvName      = MS_DEF_PROV_W;
1999*5e7646d2SAndroid Build Coastguard Worker   ckp.dwProvType        = PROV_RSA_FULL;
2000*5e7646d2SAndroid Build Coastguard Worker   ckp.dwFlags           = CRYPT_MACHINE_KEYSET;
2001*5e7646d2SAndroid Build Coastguard Worker   ckp.dwKeySpec         = AT_KEYEXCHANGE;
2002*5e7646d2SAndroid Build Coastguard Worker 
2003*5e7646d2SAndroid Build Coastguard Worker   if (!CertSetCertificateContextProperty(storedContext, CERT_KEY_PROV_INFO_PROP_ID, 0, &ckp))
2004*5e7646d2SAndroid Build Coastguard Worker   {
2005*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("5http_sspi_make_credentials: CertSetCertificateContextProperty failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
2006*5e7646d2SAndroid Build Coastguard Worker     ok = FALSE;
2007*5e7646d2SAndroid Build Coastguard Worker     goto cleanup;
2008*5e7646d2SAndroid Build Coastguard Worker   }
2009*5e7646d2SAndroid Build Coastguard Worker 
2010*5e7646d2SAndroid Build Coastguard Worker  /*
2011*5e7646d2SAndroid Build Coastguard Worker   * Get a handle to use the certificate...
2012*5e7646d2SAndroid Build Coastguard Worker   */
2013*5e7646d2SAndroid Build Coastguard Worker 
2014*5e7646d2SAndroid Build Coastguard Worker   ZeroMemory(&SchannelCred, sizeof(SchannelCred));
2015*5e7646d2SAndroid Build Coastguard Worker 
2016*5e7646d2SAndroid Build Coastguard Worker   SchannelCred.dwVersion = SCHANNEL_CRED_VERSION;
2017*5e7646d2SAndroid Build Coastguard Worker   SchannelCred.cCreds    = 1;
2018*5e7646d2SAndroid Build Coastguard Worker   SchannelCred.paCred    = &storedContext;
2019*5e7646d2SAndroid Build Coastguard Worker 
2020*5e7646d2SAndroid Build Coastguard Worker  /*
2021*5e7646d2SAndroid Build Coastguard Worker   * Create an SSPI credential.
2022*5e7646d2SAndroid Build Coastguard Worker   */
2023*5e7646d2SAndroid Build Coastguard Worker 
2024*5e7646d2SAndroid Build Coastguard Worker   Status = AcquireCredentialsHandle(NULL, UNISP_NAME, mode == _HTTP_MODE_SERVER ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND, NULL, &SchannelCred, NULL, NULL, &sspi->creds, &tsExpiry);
2025*5e7646d2SAndroid Build Coastguard Worker   if (Status != SEC_E_OK)
2026*5e7646d2SAndroid Build Coastguard Worker   {
2027*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("5http_sspi_make_credentials: AcquireCredentialsHandle failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), Status)));
2028*5e7646d2SAndroid Build Coastguard Worker     ok = FALSE;
2029*5e7646d2SAndroid Build Coastguard Worker     goto cleanup;
2030*5e7646d2SAndroid Build Coastguard Worker   }
2031*5e7646d2SAndroid Build Coastguard Worker 
2032*5e7646d2SAndroid Build Coastguard Worker cleanup:
2033*5e7646d2SAndroid Build Coastguard Worker 
2034*5e7646d2SAndroid Build Coastguard Worker  /*
2035*5e7646d2SAndroid Build Coastguard Worker   * Cleanup
2036*5e7646d2SAndroid Build Coastguard Worker   */
2037*5e7646d2SAndroid Build Coastguard Worker 
2038*5e7646d2SAndroid Build Coastguard Worker   if (hKey)
2039*5e7646d2SAndroid Build Coastguard Worker     CryptDestroyKey(hKey);
2040*5e7646d2SAndroid Build Coastguard Worker 
2041*5e7646d2SAndroid Build Coastguard Worker   if (createdContext)
2042*5e7646d2SAndroid Build Coastguard Worker     CertFreeCertificateContext(createdContext);
2043*5e7646d2SAndroid Build Coastguard Worker 
2044*5e7646d2SAndroid Build Coastguard Worker   if (storedContext)
2045*5e7646d2SAndroid Build Coastguard Worker     CertFreeCertificateContext(storedContext);
2046*5e7646d2SAndroid Build Coastguard Worker 
2047*5e7646d2SAndroid Build Coastguard Worker   if (p)
2048*5e7646d2SAndroid Build Coastguard Worker     free(p);
2049*5e7646d2SAndroid Build Coastguard Worker 
2050*5e7646d2SAndroid Build Coastguard Worker   if (store)
2051*5e7646d2SAndroid Build Coastguard Worker     CertCloseStore(store, 0);
2052*5e7646d2SAndroid Build Coastguard Worker 
2053*5e7646d2SAndroid Build Coastguard Worker   if (hProv)
2054*5e7646d2SAndroid Build Coastguard Worker     CryptReleaseContext(hProv, 0);
2055*5e7646d2SAndroid Build Coastguard Worker 
2056*5e7646d2SAndroid Build Coastguard Worker   return (ok);
2057*5e7646d2SAndroid Build Coastguard Worker }
2058*5e7646d2SAndroid Build Coastguard Worker 
2059*5e7646d2SAndroid Build Coastguard Worker 
2060*5e7646d2SAndroid Build Coastguard Worker /*
2061*5e7646d2SAndroid Build Coastguard Worker  * 'http_sspi_server()' - Negotiate a TLS connection as a server.
2062*5e7646d2SAndroid Build Coastguard Worker  */
2063*5e7646d2SAndroid Build Coastguard Worker 
2064*5e7646d2SAndroid Build Coastguard Worker static int				/* O - 0 on success, -1 on failure */
http_sspi_server(http_t * http,const char * hostname)2065*5e7646d2SAndroid Build Coastguard Worker http_sspi_server(http_t     *http,	/* I - HTTP connection */
2066*5e7646d2SAndroid Build Coastguard Worker                  const char *hostname)	/* I - Hostname of server */
2067*5e7646d2SAndroid Build Coastguard Worker {
2068*5e7646d2SAndroid Build Coastguard Worker   _http_sspi_t	*sspi = http->tls;	/* I - SSPI data */
2069*5e7646d2SAndroid Build Coastguard Worker   char		common_name[512];	/* Common name for cert */
2070*5e7646d2SAndroid Build Coastguard Worker   DWORD		dwSSPIFlags;		/* SSL connection attributes we want */
2071*5e7646d2SAndroid Build Coastguard Worker   DWORD		dwSSPIOutFlags;		/* SSL connection attributes we got */
2072*5e7646d2SAndroid Build Coastguard Worker   TimeStamp	tsExpiry;		/* Time stamp */
2073*5e7646d2SAndroid Build Coastguard Worker   SECURITY_STATUS scRet;		/* SSPI Status */
2074*5e7646d2SAndroid Build Coastguard Worker   SecBufferDesc	inBuffer;		/* Array of SecBuffer structs */
2075*5e7646d2SAndroid Build Coastguard Worker   SecBuffer	inBuffers[2];		/* Security package buffer */
2076*5e7646d2SAndroid Build Coastguard Worker   SecBufferDesc	outBuffer;		/* Array of SecBuffer structs */
2077*5e7646d2SAndroid Build Coastguard Worker   SecBuffer	outBuffers[1];		/* Security package buffer */
2078*5e7646d2SAndroid Build Coastguard Worker   int		num = 0;		/* 32 bit status value */
2079*5e7646d2SAndroid Build Coastguard Worker   BOOL		fInitContext = TRUE;	/* Has the context been init'd? */
2080*5e7646d2SAndroid Build Coastguard Worker   int		ret = 0;		/* Return value */
2081*5e7646d2SAndroid Build Coastguard Worker 
2082*5e7646d2SAndroid Build Coastguard Worker 
2083*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("4http_sspi_server(http=%p, hostname=\"%s\")", http, hostname));
2084*5e7646d2SAndroid Build Coastguard Worker 
2085*5e7646d2SAndroid Build Coastguard Worker   dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT  |
2086*5e7646d2SAndroid Build Coastguard Worker                 ASC_REQ_REPLAY_DETECT    |
2087*5e7646d2SAndroid Build Coastguard Worker                 ASC_REQ_CONFIDENTIALITY  |
2088*5e7646d2SAndroid Build Coastguard Worker                 ASC_REQ_EXTENDED_ERROR   |
2089*5e7646d2SAndroid Build Coastguard Worker                 ASC_REQ_ALLOCATE_MEMORY  |
2090*5e7646d2SAndroid Build Coastguard Worker                 ASC_REQ_STREAM;
2091*5e7646d2SAndroid Build Coastguard Worker 
2092*5e7646d2SAndroid Build Coastguard Worker   sspi->decryptBufferUsed = 0;
2093*5e7646d2SAndroid Build Coastguard Worker 
2094*5e7646d2SAndroid Build Coastguard Worker  /*
2095*5e7646d2SAndroid Build Coastguard Worker   * Lookup the server certificate...
2096*5e7646d2SAndroid Build Coastguard Worker   */
2097*5e7646d2SAndroid Build Coastguard Worker 
2098*5e7646d2SAndroid Build Coastguard Worker   snprintf(common_name, sizeof(common_name), "CN=%s", hostname);
2099*5e7646d2SAndroid Build Coastguard Worker 
2100*5e7646d2SAndroid Build Coastguard Worker   if (!http_sspi_find_credentials(http, L"ServerContainer", common_name))
2101*5e7646d2SAndroid Build Coastguard Worker     if (!http_sspi_make_credentials(http->tls, L"ServerContainer", common_name, _HTTP_MODE_SERVER, 10))
2102*5e7646d2SAndroid Build Coastguard Worker     {
2103*5e7646d2SAndroid Build Coastguard Worker       DEBUG_puts("5http_sspi_server: Unable to get server credentials.");
2104*5e7646d2SAndroid Build Coastguard Worker       return (-1);
2105*5e7646d2SAndroid Build Coastguard Worker     }
2106*5e7646d2SAndroid Build Coastguard Worker 
2107*5e7646d2SAndroid Build Coastguard Worker  /*
2108*5e7646d2SAndroid Build Coastguard Worker   * Set OutBuffer for AcceptSecurityContext call
2109*5e7646d2SAndroid Build Coastguard Worker   */
2110*5e7646d2SAndroid Build Coastguard Worker 
2111*5e7646d2SAndroid Build Coastguard Worker   outBuffer.cBuffers  = 1;
2112*5e7646d2SAndroid Build Coastguard Worker   outBuffer.pBuffers  = outBuffers;
2113*5e7646d2SAndroid Build Coastguard Worker   outBuffer.ulVersion = SECBUFFER_VERSION;
2114*5e7646d2SAndroid Build Coastguard Worker 
2115*5e7646d2SAndroid Build Coastguard Worker   scRet = SEC_I_CONTINUE_NEEDED;
2116*5e7646d2SAndroid Build Coastguard Worker 
2117*5e7646d2SAndroid Build Coastguard Worker   while (scRet == SEC_I_CONTINUE_NEEDED    ||
2118*5e7646d2SAndroid Build Coastguard Worker          scRet == SEC_E_INCOMPLETE_MESSAGE ||
2119*5e7646d2SAndroid Build Coastguard Worker          scRet == SEC_I_INCOMPLETE_CREDENTIALS)
2120*5e7646d2SAndroid Build Coastguard Worker   {
2121*5e7646d2SAndroid Build Coastguard Worker     if (sspi->decryptBufferUsed == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE)
2122*5e7646d2SAndroid Build Coastguard Worker     {
2123*5e7646d2SAndroid Build Coastguard Worker       if (sspi->decryptBufferLength <= sspi->decryptBufferUsed)
2124*5e7646d2SAndroid Build Coastguard Worker       {
2125*5e7646d2SAndroid Build Coastguard Worker 	BYTE *temp;			/* New buffer */
2126*5e7646d2SAndroid Build Coastguard Worker 
2127*5e7646d2SAndroid Build Coastguard Worker 	if (sspi->decryptBufferLength >= 262144)
2128*5e7646d2SAndroid Build Coastguard Worker 	{
2129*5e7646d2SAndroid Build Coastguard Worker 	  WSASetLastError(E_OUTOFMEMORY);
2130*5e7646d2SAndroid Build Coastguard Worker 	  DEBUG_puts("5http_sspi_server: Decryption buffer too large (>256k)");
2131*5e7646d2SAndroid Build Coastguard Worker 	  return (-1);
2132*5e7646d2SAndroid Build Coastguard Worker 	}
2133*5e7646d2SAndroid Build Coastguard Worker 
2134*5e7646d2SAndroid Build Coastguard Worker 	if ((temp = realloc(sspi->decryptBuffer, sspi->decryptBufferLength + 4096)) == NULL)
2135*5e7646d2SAndroid Build Coastguard Worker 	{
2136*5e7646d2SAndroid Build Coastguard Worker 	  DEBUG_printf(("5http_sspi_server: Unable to allocate %d byte buffer.", sspi->decryptBufferLength + 4096));
2137*5e7646d2SAndroid Build Coastguard Worker 	  WSASetLastError(E_OUTOFMEMORY);
2138*5e7646d2SAndroid Build Coastguard Worker 	  return (-1);
2139*5e7646d2SAndroid Build Coastguard Worker 	}
2140*5e7646d2SAndroid Build Coastguard Worker 
2141*5e7646d2SAndroid Build Coastguard Worker 	sspi->decryptBufferLength += 4096;
2142*5e7646d2SAndroid Build Coastguard Worker 	sspi->decryptBuffer       = temp;
2143*5e7646d2SAndroid Build Coastguard Worker       }
2144*5e7646d2SAndroid Build Coastguard Worker 
2145*5e7646d2SAndroid Build Coastguard Worker       for (;;)
2146*5e7646d2SAndroid Build Coastguard Worker       {
2147*5e7646d2SAndroid Build Coastguard Worker         num = recv(http->fd, sspi->decryptBuffer + sspi->decryptBufferUsed, (int)(sspi->decryptBufferLength - sspi->decryptBufferUsed), 0);
2148*5e7646d2SAndroid Build Coastguard Worker 
2149*5e7646d2SAndroid Build Coastguard Worker         if (num == -1 && WSAGetLastError() == WSAEWOULDBLOCK)
2150*5e7646d2SAndroid Build Coastguard Worker           Sleep(1);
2151*5e7646d2SAndroid Build Coastguard Worker         else
2152*5e7646d2SAndroid Build Coastguard Worker           break;
2153*5e7646d2SAndroid Build Coastguard Worker       }
2154*5e7646d2SAndroid Build Coastguard Worker 
2155*5e7646d2SAndroid Build Coastguard Worker       if (num < 0)
2156*5e7646d2SAndroid Build Coastguard Worker       {
2157*5e7646d2SAndroid Build Coastguard Worker         DEBUG_printf(("5http_sspi_server: recv failed: %d", WSAGetLastError()));
2158*5e7646d2SAndroid Build Coastguard Worker         return (-1);
2159*5e7646d2SAndroid Build Coastguard Worker       }
2160*5e7646d2SAndroid Build Coastguard Worker       else if (num == 0)
2161*5e7646d2SAndroid Build Coastguard Worker       {
2162*5e7646d2SAndroid Build Coastguard Worker         DEBUG_puts("5http_sspi_server: client disconnected");
2163*5e7646d2SAndroid Build Coastguard Worker         return (-1);
2164*5e7646d2SAndroid Build Coastguard Worker       }
2165*5e7646d2SAndroid Build Coastguard Worker 
2166*5e7646d2SAndroid Build Coastguard Worker       DEBUG_printf(("5http_sspi_server: received %d (handshake) bytes from client.", num));
2167*5e7646d2SAndroid Build Coastguard Worker       sspi->decryptBufferUsed += num;
2168*5e7646d2SAndroid Build Coastguard Worker     }
2169*5e7646d2SAndroid Build Coastguard Worker 
2170*5e7646d2SAndroid Build Coastguard Worker    /*
2171*5e7646d2SAndroid Build Coastguard Worker     * InBuffers[1] is for getting extra data that SSPI/SCHANNEL doesn't process
2172*5e7646d2SAndroid Build Coastguard Worker     * on this run around the loop.
2173*5e7646d2SAndroid Build Coastguard Worker     */
2174*5e7646d2SAndroid Build Coastguard Worker 
2175*5e7646d2SAndroid Build Coastguard Worker     inBuffers[0].pvBuffer   = sspi->decryptBuffer;
2176*5e7646d2SAndroid Build Coastguard Worker     inBuffers[0].cbBuffer   = (unsigned long)sspi->decryptBufferUsed;
2177*5e7646d2SAndroid Build Coastguard Worker     inBuffers[0].BufferType = SECBUFFER_TOKEN;
2178*5e7646d2SAndroid Build Coastguard Worker 
2179*5e7646d2SAndroid Build Coastguard Worker     inBuffers[1].pvBuffer   = NULL;
2180*5e7646d2SAndroid Build Coastguard Worker     inBuffers[1].cbBuffer   = 0;
2181*5e7646d2SAndroid Build Coastguard Worker     inBuffers[1].BufferType = SECBUFFER_EMPTY;
2182*5e7646d2SAndroid Build Coastguard Worker 
2183*5e7646d2SAndroid Build Coastguard Worker     inBuffer.cBuffers       = 2;
2184*5e7646d2SAndroid Build Coastguard Worker     inBuffer.pBuffers       = inBuffers;
2185*5e7646d2SAndroid Build Coastguard Worker     inBuffer.ulVersion      = SECBUFFER_VERSION;
2186*5e7646d2SAndroid Build Coastguard Worker 
2187*5e7646d2SAndroid Build Coastguard Worker    /*
2188*5e7646d2SAndroid Build Coastguard Worker     * Initialize these so if we fail, pvBuffer contains NULL, so we don't try to
2189*5e7646d2SAndroid Build Coastguard Worker     * free random garbage at the quit.
2190*5e7646d2SAndroid Build Coastguard Worker     */
2191*5e7646d2SAndroid Build Coastguard Worker 
2192*5e7646d2SAndroid Build Coastguard Worker     outBuffers[0].pvBuffer   = NULL;
2193*5e7646d2SAndroid Build Coastguard Worker     outBuffers[0].BufferType = SECBUFFER_TOKEN;
2194*5e7646d2SAndroid Build Coastguard Worker     outBuffers[0].cbBuffer   = 0;
2195*5e7646d2SAndroid Build Coastguard Worker 
2196*5e7646d2SAndroid Build Coastguard Worker     scRet = AcceptSecurityContext(&sspi->creds, (fInitContext?NULL:&sspi->context), &inBuffer, dwSSPIFlags, SECURITY_NATIVE_DREP, (fInitContext?&sspi->context:NULL), &outBuffer, &dwSSPIOutFlags, &tsExpiry);
2197*5e7646d2SAndroid Build Coastguard Worker 
2198*5e7646d2SAndroid Build Coastguard Worker     fInitContext = FALSE;
2199*5e7646d2SAndroid Build Coastguard Worker 
2200*5e7646d2SAndroid Build Coastguard Worker     if (scRet == SEC_E_OK              ||
2201*5e7646d2SAndroid Build Coastguard Worker         scRet == SEC_I_CONTINUE_NEEDED ||
2202*5e7646d2SAndroid Build Coastguard Worker         (FAILED(scRet) && ((dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR) != 0)))
2203*5e7646d2SAndroid Build Coastguard Worker     {
2204*5e7646d2SAndroid Build Coastguard Worker       if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer)
2205*5e7646d2SAndroid Build Coastguard Worker       {
2206*5e7646d2SAndroid Build Coastguard Worker        /*
2207*5e7646d2SAndroid Build Coastguard Worker         * Send response to server if there is one.
2208*5e7646d2SAndroid Build Coastguard Worker         */
2209*5e7646d2SAndroid Build Coastguard Worker 
2210*5e7646d2SAndroid Build Coastguard Worker         num = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0);
2211*5e7646d2SAndroid Build Coastguard Worker 
2212*5e7646d2SAndroid Build Coastguard Worker         if (num <= 0)
2213*5e7646d2SAndroid Build Coastguard Worker         {
2214*5e7646d2SAndroid Build Coastguard Worker           DEBUG_printf(("5http_sspi_server: handshake send failed: %d", WSAGetLastError()));
2215*5e7646d2SAndroid Build Coastguard Worker 	  return (-1);
2216*5e7646d2SAndroid Build Coastguard Worker         }
2217*5e7646d2SAndroid Build Coastguard Worker 
2218*5e7646d2SAndroid Build Coastguard Worker         DEBUG_printf(("5http_sspi_server: sent %d handshake bytes to client.", outBuffers[0].cbBuffer));
2219*5e7646d2SAndroid Build Coastguard Worker 
2220*5e7646d2SAndroid Build Coastguard Worker         FreeContextBuffer(outBuffers[0].pvBuffer);
2221*5e7646d2SAndroid Build Coastguard Worker         outBuffers[0].pvBuffer = NULL;
2222*5e7646d2SAndroid Build Coastguard Worker       }
2223*5e7646d2SAndroid Build Coastguard Worker     }
2224*5e7646d2SAndroid Build Coastguard Worker 
2225*5e7646d2SAndroid Build Coastguard Worker     if (scRet == SEC_E_OK)
2226*5e7646d2SAndroid Build Coastguard Worker     {
2227*5e7646d2SAndroid Build Coastguard Worker      /*
2228*5e7646d2SAndroid Build Coastguard Worker       * If there's extra data then save it for next time we go to decrypt.
2229*5e7646d2SAndroid Build Coastguard Worker       */
2230*5e7646d2SAndroid Build Coastguard Worker 
2231*5e7646d2SAndroid Build Coastguard Worker       if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
2232*5e7646d2SAndroid Build Coastguard Worker       {
2233*5e7646d2SAndroid Build Coastguard Worker         memcpy(sspi->decryptBuffer, (LPBYTE)(sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer), inBuffers[1].cbBuffer);
2234*5e7646d2SAndroid Build Coastguard Worker         sspi->decryptBufferUsed = inBuffers[1].cbBuffer;
2235*5e7646d2SAndroid Build Coastguard Worker       }
2236*5e7646d2SAndroid Build Coastguard Worker       else
2237*5e7646d2SAndroid Build Coastguard Worker       {
2238*5e7646d2SAndroid Build Coastguard Worker         sspi->decryptBufferUsed = 0;
2239*5e7646d2SAndroid Build Coastguard Worker       }
2240*5e7646d2SAndroid Build Coastguard Worker       break;
2241*5e7646d2SAndroid Build Coastguard Worker     }
2242*5e7646d2SAndroid Build Coastguard Worker     else if (FAILED(scRet) && scRet != SEC_E_INCOMPLETE_MESSAGE)
2243*5e7646d2SAndroid Build Coastguard Worker     {
2244*5e7646d2SAndroid Build Coastguard Worker       DEBUG_printf(("5http_sspi_server: AcceptSecurityContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
2245*5e7646d2SAndroid Build Coastguard Worker       ret = -1;
2246*5e7646d2SAndroid Build Coastguard Worker       break;
2247*5e7646d2SAndroid Build Coastguard Worker     }
2248*5e7646d2SAndroid Build Coastguard Worker 
2249*5e7646d2SAndroid Build Coastguard Worker     if (scRet != SEC_E_INCOMPLETE_MESSAGE &&
2250*5e7646d2SAndroid Build Coastguard Worker         scRet != SEC_I_INCOMPLETE_CREDENTIALS)
2251*5e7646d2SAndroid Build Coastguard Worker     {
2252*5e7646d2SAndroid Build Coastguard Worker       if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
2253*5e7646d2SAndroid Build Coastguard Worker       {
2254*5e7646d2SAndroid Build Coastguard Worker         memcpy(sspi->decryptBuffer, (LPBYTE)(sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer), inBuffers[1].cbBuffer);
2255*5e7646d2SAndroid Build Coastguard Worker         sspi->decryptBufferUsed = inBuffers[1].cbBuffer;
2256*5e7646d2SAndroid Build Coastguard Worker       }
2257*5e7646d2SAndroid Build Coastguard Worker       else
2258*5e7646d2SAndroid Build Coastguard Worker       {
2259*5e7646d2SAndroid Build Coastguard Worker         sspi->decryptBufferUsed = 0;
2260*5e7646d2SAndroid Build Coastguard Worker       }
2261*5e7646d2SAndroid Build Coastguard Worker     }
2262*5e7646d2SAndroid Build Coastguard Worker   }
2263*5e7646d2SAndroid Build Coastguard Worker 
2264*5e7646d2SAndroid Build Coastguard Worker   if (!ret)
2265*5e7646d2SAndroid Build Coastguard Worker   {
2266*5e7646d2SAndroid Build Coastguard Worker     sspi->contextInitialized = TRUE;
2267*5e7646d2SAndroid Build Coastguard Worker 
2268*5e7646d2SAndroid Build Coastguard Worker    /*
2269*5e7646d2SAndroid Build Coastguard Worker     * Find out how big the header will be:
2270*5e7646d2SAndroid Build Coastguard Worker     */
2271*5e7646d2SAndroid Build Coastguard Worker 
2272*5e7646d2SAndroid Build Coastguard Worker     scRet = QueryContextAttributes(&sspi->context, SECPKG_ATTR_STREAM_SIZES, &sspi->streamSizes);
2273*5e7646d2SAndroid Build Coastguard Worker 
2274*5e7646d2SAndroid Build Coastguard Worker     if (scRet != SEC_E_OK)
2275*5e7646d2SAndroid Build Coastguard Worker     {
2276*5e7646d2SAndroid Build Coastguard Worker       DEBUG_printf(("5http_sspi_server: QueryContextAttributes failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
2277*5e7646d2SAndroid Build Coastguard Worker       ret = -1;
2278*5e7646d2SAndroid Build Coastguard Worker     }
2279*5e7646d2SAndroid Build Coastguard Worker   }
2280*5e7646d2SAndroid Build Coastguard Worker 
2281*5e7646d2SAndroid Build Coastguard Worker   return (ret);
2282*5e7646d2SAndroid Build Coastguard Worker }
2283*5e7646d2SAndroid Build Coastguard Worker 
2284*5e7646d2SAndroid Build Coastguard Worker 
2285*5e7646d2SAndroid Build Coastguard Worker /*
2286*5e7646d2SAndroid Build Coastguard Worker  * 'http_sspi_strerror()' - Return a string for the specified error code.
2287*5e7646d2SAndroid Build Coastguard Worker  */
2288*5e7646d2SAndroid Build Coastguard Worker 
2289*5e7646d2SAndroid Build Coastguard Worker static const char *			/* O - String for error */
http_sspi_strerror(char * buffer,size_t bufsize,DWORD code)2290*5e7646d2SAndroid Build Coastguard Worker http_sspi_strerror(char   *buffer,	/* I - Error message buffer */
2291*5e7646d2SAndroid Build Coastguard Worker                    size_t bufsize,	/* I - Size of buffer */
2292*5e7646d2SAndroid Build Coastguard Worker                    DWORD  code)		/* I - Error code */
2293*5e7646d2SAndroid Build Coastguard Worker {
2294*5e7646d2SAndroid Build Coastguard Worker   if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, code, 0, buffer, bufsize, NULL))
2295*5e7646d2SAndroid Build Coastguard Worker   {
2296*5e7646d2SAndroid Build Coastguard Worker    /*
2297*5e7646d2SAndroid Build Coastguard Worker     * Strip trailing CR + LF...
2298*5e7646d2SAndroid Build Coastguard Worker     */
2299*5e7646d2SAndroid Build Coastguard Worker 
2300*5e7646d2SAndroid Build Coastguard Worker     char	*ptr;			/* Pointer into error message */
2301*5e7646d2SAndroid Build Coastguard Worker 
2302*5e7646d2SAndroid Build Coastguard Worker     for (ptr = buffer + strlen(buffer) - 1; ptr >= buffer; ptr --)
2303*5e7646d2SAndroid Build Coastguard Worker       if (*ptr == '\n' || *ptr == '\r')
2304*5e7646d2SAndroid Build Coastguard Worker         *ptr = '\0';
2305*5e7646d2SAndroid Build Coastguard Worker       else
2306*5e7646d2SAndroid Build Coastguard Worker         break;
2307*5e7646d2SAndroid Build Coastguard Worker   }
2308*5e7646d2SAndroid Build Coastguard Worker   else
2309*5e7646d2SAndroid Build Coastguard Worker     snprintf(buffer, bufsize, "Unknown error %x", code);
2310*5e7646d2SAndroid Build Coastguard Worker 
2311*5e7646d2SAndroid Build Coastguard Worker   return (buffer);
2312*5e7646d2SAndroid Build Coastguard Worker }
2313*5e7646d2SAndroid Build Coastguard Worker 
2314*5e7646d2SAndroid Build Coastguard Worker 
2315*5e7646d2SAndroid Build Coastguard Worker /*
2316*5e7646d2SAndroid Build Coastguard Worker  * 'http_sspi_verify()' - Verify a certificate.
2317*5e7646d2SAndroid Build Coastguard Worker  */
2318*5e7646d2SAndroid Build Coastguard Worker 
2319*5e7646d2SAndroid Build Coastguard Worker static DWORD				/* O - Error code (0 == No error) */
http_sspi_verify(PCCERT_CONTEXT cert,const char * common_name,DWORD dwCertFlags)2320*5e7646d2SAndroid Build Coastguard Worker http_sspi_verify(
2321*5e7646d2SAndroid Build Coastguard Worker     PCCERT_CONTEXT cert,		/* I - Server certificate */
2322*5e7646d2SAndroid Build Coastguard Worker     const char     *common_name,	/* I - Common name */
2323*5e7646d2SAndroid Build Coastguard Worker     DWORD          dwCertFlags)		/* I - Verification flags */
2324*5e7646d2SAndroid Build Coastguard Worker {
2325*5e7646d2SAndroid Build Coastguard Worker   HTTPSPolicyCallbackData httpsPolicy;	/* HTTPS Policy Struct */
2326*5e7646d2SAndroid Build Coastguard Worker   CERT_CHAIN_POLICY_PARA policyPara;	/* Cert chain policy parameters */
2327*5e7646d2SAndroid Build Coastguard Worker   CERT_CHAIN_POLICY_STATUS policyStatus;/* Cert chain policy status */
2328*5e7646d2SAndroid Build Coastguard Worker   CERT_CHAIN_PARA	chainPara;	/* Used for searching and matching criteria */
2329*5e7646d2SAndroid Build Coastguard Worker   PCCERT_CHAIN_CONTEXT	chainContext = NULL;
2330*5e7646d2SAndroid Build Coastguard Worker 					/* Certificate chain */
2331*5e7646d2SAndroid Build Coastguard Worker   PWSTR			commonNameUnicode = NULL;
2332*5e7646d2SAndroid Build Coastguard Worker 					/* Unicode common name */
2333*5e7646d2SAndroid Build Coastguard Worker   LPSTR			rgszUsages[] = { szOID_PKIX_KP_SERVER_AUTH,
2334*5e7646d2SAndroid Build Coastguard Worker                                          szOID_SERVER_GATED_CRYPTO,
2335*5e7646d2SAndroid Build Coastguard Worker                                          szOID_SGC_NETSCAPE };
2336*5e7646d2SAndroid Build Coastguard Worker 					/* How are we using this certificate? */
2337*5e7646d2SAndroid Build Coastguard Worker   DWORD			cUsages = sizeof(rgszUsages) / sizeof(LPSTR);
2338*5e7646d2SAndroid Build Coastguard Worker 					/* Number of ites in rgszUsages */
2339*5e7646d2SAndroid Build Coastguard Worker   DWORD			count;		/* 32 bit count variable */
2340*5e7646d2SAndroid Build Coastguard Worker   DWORD			status;		/* Return value */
2341*5e7646d2SAndroid Build Coastguard Worker #ifdef DEBUG
2342*5e7646d2SAndroid Build Coastguard Worker   char			error[1024];	/* Error message string */
2343*5e7646d2SAndroid Build Coastguard Worker #endif /* DEBUG */
2344*5e7646d2SAndroid Build Coastguard Worker 
2345*5e7646d2SAndroid Build Coastguard Worker 
2346*5e7646d2SAndroid Build Coastguard Worker   if (!cert)
2347*5e7646d2SAndroid Build Coastguard Worker     return (SEC_E_WRONG_PRINCIPAL);
2348*5e7646d2SAndroid Build Coastguard Worker 
2349*5e7646d2SAndroid Build Coastguard Worker  /*
2350*5e7646d2SAndroid Build Coastguard Worker   * Convert common name to Unicode.
2351*5e7646d2SAndroid Build Coastguard Worker   */
2352*5e7646d2SAndroid Build Coastguard Worker 
2353*5e7646d2SAndroid Build Coastguard Worker   if (!common_name || !*common_name)
2354*5e7646d2SAndroid Build Coastguard Worker     return (SEC_E_WRONG_PRINCIPAL);
2355*5e7646d2SAndroid Build Coastguard Worker 
2356*5e7646d2SAndroid Build Coastguard Worker   count             = MultiByteToWideChar(CP_ACP, 0, common_name, -1, NULL, 0);
2357*5e7646d2SAndroid Build Coastguard Worker   commonNameUnicode = LocalAlloc(LMEM_FIXED, count * sizeof(WCHAR));
2358*5e7646d2SAndroid Build Coastguard Worker   if (!commonNameUnicode)
2359*5e7646d2SAndroid Build Coastguard Worker     return (SEC_E_INSUFFICIENT_MEMORY);
2360*5e7646d2SAndroid Build Coastguard Worker 
2361*5e7646d2SAndroid Build Coastguard Worker   if (!MultiByteToWideChar(CP_ACP, 0, common_name, -1, commonNameUnicode, count))
2362*5e7646d2SAndroid Build Coastguard Worker   {
2363*5e7646d2SAndroid Build Coastguard Worker     LocalFree(commonNameUnicode);
2364*5e7646d2SAndroid Build Coastguard Worker     return (SEC_E_WRONG_PRINCIPAL);
2365*5e7646d2SAndroid Build Coastguard Worker   }
2366*5e7646d2SAndroid Build Coastguard Worker 
2367*5e7646d2SAndroid Build Coastguard Worker  /*
2368*5e7646d2SAndroid Build Coastguard Worker   * Build certificate chain.
2369*5e7646d2SAndroid Build Coastguard Worker   */
2370*5e7646d2SAndroid Build Coastguard Worker 
2371*5e7646d2SAndroid Build Coastguard Worker   ZeroMemory(&chainPara, sizeof(chainPara));
2372*5e7646d2SAndroid Build Coastguard Worker 
2373*5e7646d2SAndroid Build Coastguard Worker   chainPara.cbSize					= sizeof(chainPara);
2374*5e7646d2SAndroid Build Coastguard Worker   chainPara.RequestedUsage.dwType			= USAGE_MATCH_TYPE_OR;
2375*5e7646d2SAndroid Build Coastguard Worker   chainPara.RequestedUsage.Usage.cUsageIdentifier	= cUsages;
2376*5e7646d2SAndroid Build Coastguard Worker   chainPara.RequestedUsage.Usage.rgpszUsageIdentifier	= rgszUsages;
2377*5e7646d2SAndroid Build Coastguard Worker 
2378*5e7646d2SAndroid Build Coastguard Worker   if (!CertGetCertificateChain(NULL, cert, NULL, cert->hCertStore, &chainPara, 0, NULL, &chainContext))
2379*5e7646d2SAndroid Build Coastguard Worker   {
2380*5e7646d2SAndroid Build Coastguard Worker     status = GetLastError();
2381*5e7646d2SAndroid Build Coastguard Worker 
2382*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("CertGetCertificateChain returned: %s", http_sspi_strerror(error, sizeof(error), status)));
2383*5e7646d2SAndroid Build Coastguard Worker 
2384*5e7646d2SAndroid Build Coastguard Worker     LocalFree(commonNameUnicode);
2385*5e7646d2SAndroid Build Coastguard Worker     return (status);
2386*5e7646d2SAndroid Build Coastguard Worker   }
2387*5e7646d2SAndroid Build Coastguard Worker 
2388*5e7646d2SAndroid Build Coastguard Worker  /*
2389*5e7646d2SAndroid Build Coastguard Worker   * Validate certificate chain.
2390*5e7646d2SAndroid Build Coastguard Worker   */
2391*5e7646d2SAndroid Build Coastguard Worker 
2392*5e7646d2SAndroid Build Coastguard Worker   ZeroMemory(&httpsPolicy, sizeof(HTTPSPolicyCallbackData));
2393*5e7646d2SAndroid Build Coastguard Worker   httpsPolicy.cbStruct		= sizeof(HTTPSPolicyCallbackData);
2394*5e7646d2SAndroid Build Coastguard Worker   httpsPolicy.dwAuthType	= AUTHTYPE_SERVER;
2395*5e7646d2SAndroid Build Coastguard Worker   httpsPolicy.fdwChecks		= dwCertFlags;
2396*5e7646d2SAndroid Build Coastguard Worker   httpsPolicy.pwszServerName	= commonNameUnicode;
2397*5e7646d2SAndroid Build Coastguard Worker 
2398*5e7646d2SAndroid Build Coastguard Worker   memset(&policyPara, 0, sizeof(policyPara));
2399*5e7646d2SAndroid Build Coastguard Worker   policyPara.cbSize		= sizeof(policyPara);
2400*5e7646d2SAndroid Build Coastguard Worker   policyPara.pvExtraPolicyPara	= &httpsPolicy;
2401*5e7646d2SAndroid Build Coastguard Worker 
2402*5e7646d2SAndroid Build Coastguard Worker   memset(&policyStatus, 0, sizeof(policyStatus));
2403*5e7646d2SAndroid Build Coastguard Worker   policyStatus.cbSize = sizeof(policyStatus);
2404*5e7646d2SAndroid Build Coastguard Worker 
2405*5e7646d2SAndroid Build Coastguard Worker   if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chainContext, &policyPara, &policyStatus))
2406*5e7646d2SAndroid Build Coastguard Worker   {
2407*5e7646d2SAndroid Build Coastguard Worker     status = GetLastError();
2408*5e7646d2SAndroid Build Coastguard Worker 
2409*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("CertVerifyCertificateChainPolicy returned %s", http_sspi_strerror(error, sizeof(error), status)));
2410*5e7646d2SAndroid Build Coastguard Worker   }
2411*5e7646d2SAndroid Build Coastguard Worker   else if (policyStatus.dwError)
2412*5e7646d2SAndroid Build Coastguard Worker     status = policyStatus.dwError;
2413*5e7646d2SAndroid Build Coastguard Worker   else
2414*5e7646d2SAndroid Build Coastguard Worker     status = SEC_E_OK;
2415*5e7646d2SAndroid Build Coastguard Worker 
2416*5e7646d2SAndroid Build Coastguard Worker   if (chainContext)
2417*5e7646d2SAndroid Build Coastguard Worker     CertFreeCertificateChain(chainContext);
2418*5e7646d2SAndroid Build Coastguard Worker 
2419*5e7646d2SAndroid Build Coastguard Worker   if (commonNameUnicode)
2420*5e7646d2SAndroid Build Coastguard Worker     LocalFree(commonNameUnicode);
2421*5e7646d2SAndroid Build Coastguard Worker 
2422*5e7646d2SAndroid Build Coastguard Worker   return (status);
2423*5e7646d2SAndroid Build Coastguard Worker }
2424