2 * TLS support for CUPS on Windows using the Security Support Provider
5 * Copyright 2010-2018 by Apple Inc.
7 * These coded instructions, statements, and computer programs are the
8 * property of Apple Inc. and are protected by Federal copyright
9 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
10 * which should have been included with this file. If this file is
11 * missing or damaged, see the license at "http://www.cups.org/".
13 * This file is subject to the Apple OS-Developed Software exception.
16 /**** This file is included from tls.c ****/
19 * Include necessary headers...
22 #include "debug-private.h"
26 * Include necessary libraries...
29 #pragma comment(lib, "Crypt32.lib")
30 #pragma comment(lib, "Secur32.lib")
31 #pragma comment(lib, "Ws2_32.lib")
38 #ifndef SECURITY_FLAG_IGNORE_UNKNOWN_CA
39 # define SECURITY_FLAG_IGNORE_UNKNOWN_CA 0x00000100 /* Untrusted root */
40 #endif /* SECURITY_FLAG_IGNORE_UNKNOWN_CA */
42 #ifndef SECURITY_FLAG_IGNORE_CERT_CN_INVALID
43 # define SECURITY_FLAG_IGNORE_CERT_CN_INVALID 0x00001000 /* Common name does not match */
44 #endif /* !SECURITY_FLAG_IGNORE_CERT_CN_INVALID */
46 #ifndef SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
47 # define SECURITY_FLAG_IGNORE_CERT_DATE_INVALID 0x00002000 /* Expired X509 Cert. */
48 #endif /* !SECURITY_FLAG_IGNORE_CERT_DATE_INVALID */
55 static int tls_options
= -1,/* Options for TLS connections */
56 tls_min_version
= _HTTP_TLS_1_0
,
57 tls_max_version
= _HTTP_TLS_MAX
;
64 static _http_sspi_t
*http_sspi_alloc(void);
65 static int http_sspi_client(http_t
*http
, const char *hostname
);
66 static PCCERT_CONTEXT
http_sspi_create_credential(http_credential_t
*cred
);
67 static BOOL
http_sspi_find_credentials(http_t
*http
, const LPWSTR containerName
, const char *common_name
);
68 static void http_sspi_free(_http_sspi_t
*sspi
);
69 static BOOL
http_sspi_make_credentials(_http_sspi_t
*sspi
, const LPWSTR containerName
, const char *common_name
, _http_mode_t mode
, int years
);
70 static int http_sspi_server(http_t
*http
, const char *hostname
);
71 static void http_sspi_set_allows_any_root(_http_sspi_t
*sspi
, BOOL allow
);
72 static void http_sspi_set_allows_expired_certs(_http_sspi_t
*sspi
, BOOL allow
);
73 static const char *http_sspi_strerror(char *buffer
, size_t bufsize
, DWORD code
);
74 static DWORD
http_sspi_verify(PCCERT_CONTEXT cert
, const char *common_name
, DWORD dwCertFlags
);
78 * 'cupsMakeServerCredentials()' - Make a self-signed certificate and private key pair.
80 * @since CUPS 2.0/OS 10.10@
83 int /* O - 1 on success, 0 on failure */
84 cupsMakeServerCredentials(
85 const char *path
, /* I - Keychain path or @code NULL@ for default */
86 const char *common_name
, /* I - Common name */
87 int num_alt_names
, /* I - Number of subject alternate names */
88 const char **alt_names
, /* I - Subject Alternate Names */
89 time_t expiration_date
) /* I - Expiration date */
91 _http_sspi_t
*sspi
; /* SSPI data */
92 int ret
; /* Return value */
95 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
));
101 sspi
= http_sspi_alloc();
102 ret
= http_sspi_make_credentials(sspi
, L
"ServerContainer", common_name
, _HTTP_MODE_SERVER
, (int)((expiration_date
- time(NULL
) + 86399) / 86400 / 365));
104 http_sspi_free(sspi
);
111 * 'cupsSetServerCredentials()' - Set the default server credentials.
113 * Note: The server credentials are used by all threads in the running process.
114 * This function is threadsafe.
116 * @since CUPS 2.0/OS 10.10@
119 int /* O - 1 on success, 0 on failure */
120 cupsSetServerCredentials(
121 const char *path
, /* I - Keychain path or @code NULL@ for default */
122 const char *common_name
, /* I - Default common name for server */
123 int auto_create
) /* I - 1 = automatically create self-signed certificates */
125 DEBUG_printf(("cupsSetServerCredentials(path=\"%s\", common_name=\"%s\", auto_create=%d)", path
, common_name
, auto_create
));
136 * 'httpCopyCredentials()' - Copy the credentials associated with the peer in
137 * an encrypted connection.
139 * @since CUPS 1.5/macOS 10.7@
142 int /* O - Status of call (0 = success) */
144 http_t
*http
, /* I - Connection to server */
145 cups_array_t
**credentials
) /* O - Array of credentials */
147 DEBUG_printf(("httpCopyCredentials(http=%p, credentials=%p)", http
, credentials
));
149 if (!http
|| !http
->tls
|| !http
->tls
->remoteCert
|| !credentials
)
157 *credentials
= cupsArrayNew(NULL
, NULL
);
158 httpAddCredential(*credentials
, http
->tls
->remoteCert
->pbCertEncoded
, http
->tls
->remoteCert
->cbCertEncoded
);
165 * '_httpCreateCredentials()' - Create credentials in the internal format.
168 http_tls_credentials_t
/* O - Internal credentials */
169 _httpCreateCredentials(
170 cups_array_t
*credentials
) /* I - Array of credentials */
172 return (http_sspi_create_credential((http_credential_t
*)cupsArrayFirst(credentials
)));
177 * 'httpCredentialsAreValidForName()' - Return whether the credentials are valid for the given name.
179 * @since CUPS 2.0/OS 10.10@
182 int /* O - 1 if valid, 0 otherwise */
183 httpCredentialsAreValidForName(
184 cups_array_t
*credentials
, /* I - Credentials */
185 const char *common_name
) /* I - Name to check */
187 int valid
= 1; /* Valid name? */
188 PCCERT_CONTEXT cert
= http_sspi_create_credential((http_credential_t
*)cupsArrayFirst(credentials
));
190 char cert_name
[1024]; /* Name from certificate */
195 if (CertNameToStr(X509_ASN_ENCODING
, &(cert
->pCertInfo
->Subject
), CERT_SIMPLE_NAME_STR
, cert_name
, sizeof(cert_name
)))
198 * Extract common name at end...
201 char *ptr
= strrchr(cert_name
, ',');
203 _cups_strcpy(cert_name
, ptr
+ 2);
206 strlcpy(cert_name
, "unknown", sizeof(cert_name
));
208 CertFreeCertificateContext(cert
);
211 strlcpy(cert_name
, "unknown", sizeof(cert_name
));
214 * Compare the common names...
217 if (_cups_strcasecmp(common_name
, cert_name
))
220 * Not an exact match for the common name, check for wildcard certs...
223 const char *domain
= strchr(common_name
, '.');
224 /* Domain in common name */
226 if (strncmp(cert_name
, "*.", 2) || !domain
|| _cups_strcasecmp(domain
, cert_name
+ 1))
229 * Not a wildcard match.
232 /* TODO: Check subject alternate names */
242 * 'httpCredentialsGetTrust()' - Return the trust of credentials.
244 * @since CUPS 2.0/OS 10.10@
247 http_trust_t
/* O - Level of trust */
248 httpCredentialsGetTrust(
249 cups_array_t
*credentials
, /* I - Credentials */
250 const char *common_name
) /* I - Common name for trust lookup */
252 http_trust_t trust
= HTTP_TRUST_OK
; /* Level of trust */
253 PCCERT_CONTEXT cert
= NULL
; /* Certificate to validate */
254 DWORD certFlags
= 0; /* Cert verification flags */
255 _cups_globals_t
*cg
= _cupsGlobals(); /* Per-thread global data */
259 return (HTTP_TRUST_UNKNOWN
);
261 cert
= http_sspi_create_credential((http_credential_t
*)cupsArrayFirst(credentials
));
263 return (HTTP_TRUST_UNKNOWN
);
265 if (cg
->any_root
< 0)
269 certFlags
|= SECURITY_FLAG_IGNORE_UNKNOWN_CA
;
271 if (cg
->expired_certs
)
272 certFlags
|= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
;
274 if (!cg
->validate_certs
)
275 certFlags
|= SECURITY_FLAG_IGNORE_CERT_CN_INVALID
;
277 if (http_sspi_verify(cert
, common_name
, certFlags
) != SEC_E_OK
)
278 trust
= HTTP_TRUST_INVALID
;
280 CertFreeCertificateContext(cert
);
287 * 'httpCredentialsGetExpiration()' - Return the expiration date of the credentials.
289 * @since CUPS 2.0/OS 10.10@
292 time_t /* O - Expiration date of credentials */
293 httpCredentialsGetExpiration(
294 cups_array_t
*credentials
) /* I - Credentials */
296 time_t expiration_date
= 0; /* Expiration data of credentials */
297 PCCERT_CONTEXT cert
= http_sspi_create_credential((http_credential_t
*)cupsArrayFirst(credentials
));
302 SYSTEMTIME systime
; /* System time */
303 struct tm tm
; /* UNIX date/time */
305 FileTimeToSystemTime(&(cert
->pCertInfo
->NotAfter
), &systime
);
307 tm
.tm_year
= systime
.wYear
- 1900;
308 tm
.tm_mon
= systime
.wMonth
- 1;
309 tm
.tm_mday
= systime
.wDay
;
310 tm
.tm_hour
= systime
.wHour
;
311 tm
.tm_min
= systime
.wMinute
;
312 tm
.tm_sec
= systime
.wSecond
;
314 expiration_date
= mktime(&tm
);
316 CertFreeCertificateContext(cert
);
319 return (expiration_date
);
324 * 'httpCredentialsString()' - Return a string representing the credentials.
326 * @since CUPS 2.0/OS 10.10@
329 size_t /* O - Total size of credentials string */
330 httpCredentialsString(
331 cups_array_t
*credentials
, /* I - Credentials */
332 char *buffer
, /* I - Buffer or @code NULL@ */
333 size_t bufsize
) /* I - Size of buffer */
335 http_credential_t
*first
= (http_credential_t
*)cupsArrayFirst(credentials
);
336 /* First certificate */
337 PCCERT_CONTEXT cert
; /* Certificate */
340 DEBUG_printf(("httpCredentialsString(credentials=%p, buffer=%p, bufsize=" CUPS_LLFMT
")", credentials
, buffer
, CUPS_LLCAST bufsize
));
345 if (buffer
&& bufsize
> 0)
348 cert
= http_sspi_create_credential(first
);
352 char cert_name
[256]; /* Common name */
353 SYSTEMTIME systime
; /* System time */
354 struct tm tm
; /* UNIX date/time */
355 time_t expiration
; /* Expiration date of cert */
356 unsigned char md5_digest
[16]; /* MD5 result */
358 FileTimeToSystemTime(&(cert
->pCertInfo
->NotAfter
), &systime
);
360 tm
.tm_year
= systime
.wYear
- 1900;
361 tm
.tm_mon
= systime
.wMonth
- 1;
362 tm
.tm_mday
= systime
.wDay
;
363 tm
.tm_hour
= systime
.wHour
;
364 tm
.tm_min
= systime
.wMinute
;
365 tm
.tm_sec
= systime
.wSecond
;
367 expiration
= mktime(&tm
);
369 if (CertNameToStr(X509_ASN_ENCODING
, &(cert
->pCertInfo
->Subject
), CERT_SIMPLE_NAME_STR
, cert_name
, sizeof(cert_name
)))
372 * Extract common name at end...
375 char *ptr
= strrchr(cert_name
, ',');
377 _cups_strcpy(cert_name
, ptr
+ 2);
380 strlcpy(cert_name
, "unknown", sizeof(cert_name
));
382 cupsHashData("md5", first
->data
, first
->datalen
, md5_digest
, sizeof(md5_digest
));
384 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]);
386 CertFreeCertificateContext(cert
);
389 DEBUG_printf(("1httpCredentialsString: Returning \"%s\".", buffer
));
391 return (strlen(buffer
));
396 * '_httpFreeCredentials()' - Free internal credentials.
400 _httpFreeCredentials(
401 http_tls_credentials_t credentials
) /* I - Internal credentials */
406 CertFreeCertificateContext(credentials
);
411 * 'httpLoadCredentials()' - Load X.509 credentials from a keychain file.
413 * @since CUPS 2.0/OS 10.10@
416 int /* O - 0 on success, -1 on error */
418 const char *path
, /* I - Keychain path or @code NULL@ for default */
419 cups_array_t
**credentials
, /* IO - Credentials */
420 const char *common_name
) /* I - Common name for credentials */
422 HCERTSTORE store
= NULL
; /* Certificate store */
423 PCCERT_CONTEXT storedContext
= NULL
; /* Context created from the store */
424 DWORD dwSize
= 0; /* 32 bit size */
425 PBYTE p
= NULL
; /* Temporary storage */
426 HCRYPTPROV hProv
= (HCRYPTPROV
)NULL
;
427 /* Handle to a CSP */
428 CERT_NAME_BLOB sib
; /* Arbitrary array of bytes */
430 char error
[1024]; /* Error message buffer */
434 DEBUG_printf(("httpLoadCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path
, credentials
, common_name
));
444 DEBUG_puts("1httpLoadCredentials: NULL credentials pointer, returning -1.");
450 DEBUG_puts("1httpLoadCredentials: Bad common name, returning -1.");
454 if (!CryptAcquireContextW(&hProv
, L
"RememberedContainer", MS_DEF_PROV_W
, PROV_RSA_FULL
, CRYPT_NEWKEYSET
| CRYPT_MACHINE_KEYSET
))
456 if (GetLastError() == NTE_EXISTS
)
458 if (!CryptAcquireContextW(&hProv
, L
"RememberedContainer", MS_DEF_PROV_W
, PROV_RSA_FULL
, CRYPT_MACHINE_KEYSET
))
460 DEBUG_printf(("1httpLoadCredentials: CryptAcquireContext failed: %s", http_sspi_strerror(error
, sizeof(error
), GetLastError())));
466 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");
470 DEBUG_printf(("1httpLoadCredentials: CertOpenSystemStore failed: %s", http_sspi_strerror(error
, sizeof(error
), GetLastError())));
476 if (!CertStrToName(X509_ASN_ENCODING
, common_name
, CERT_OID_NAME_STR
, NULL
, NULL
, &dwSize
, NULL
))
478 DEBUG_printf(("1httpLoadCredentials: CertStrToName failed: %s", http_sspi_strerror(error
, sizeof(error
), GetLastError())));
482 p
= (PBYTE
)malloc(dwSize
);
486 DEBUG_printf(("1httpLoadCredentials: malloc failed for %d bytes.", dwSize
));
490 if (!CertStrToName(X509_ASN_ENCODING
, common_name
, CERT_OID_NAME_STR
, NULL
, p
, &dwSize
, NULL
))
492 DEBUG_printf(("1httpLoadCredentials: CertStrToName failed: %s", http_sspi_strerror(error
, sizeof(error
), GetLastError())));
499 storedContext
= CertFindCertificateInStore(store
, X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
, 0, CERT_FIND_SUBJECT_NAME
, &sib
, NULL
);
503 DEBUG_printf(("1httpLoadCredentials: Unable to find credentials for \"%s\".", common_name
));
507 *credentials
= cupsArrayNew(NULL
, NULL
);
508 httpAddCredential(*credentials
, storedContext
->pbCertEncoded
, storedContext
->cbCertEncoded
);
517 CertFreeCertificateContext(storedContext
);
523 CertCloseStore(store
, 0);
526 CryptReleaseContext(hProv
, 0);
528 DEBUG_printf(("1httpLoadCredentials: Returning %d.", *credentials
? 0 : -1));
530 return (*credentials
? 0 : -1);
535 * 'httpSaveCredentials()' - Save X.509 credentials to a keychain file.
537 * @since CUPS 2.0/OS 10.10@
540 int /* O - -1 on error, 0 on success */
542 const char *path
, /* I - Keychain path or @code NULL@ for default */
543 cups_array_t
*credentials
, /* I - Credentials */
544 const char *common_name
) /* I - Common name for credentials */
546 HCERTSTORE store
= NULL
; /* Certificate store */
547 PCCERT_CONTEXT storedContext
= NULL
; /* Context created from the store */
548 PCCERT_CONTEXT createdContext
= NULL
; /* Context created by us */
549 DWORD dwSize
= 0; /* 32 bit size */
550 PBYTE p
= NULL
; /* Temporary storage */
551 HCRYPTPROV hProv
= (HCRYPTPROV
)NULL
;
552 /* Handle to a CSP */
553 CRYPT_KEY_PROV_INFO ckp
; /* Handle to crypto key */
554 int ret
= -1; /* Return value */
556 char error
[1024]; /* Error message buffer */
560 DEBUG_printf(("httpSaveCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path
, credentials
, common_name
));
566 DEBUG_puts("1httpSaveCredentials: Bad common name, returning -1.");
570 createdContext
= http_sspi_create_credential((http_credential_t
*)cupsArrayFirst(credentials
));
573 DEBUG_puts("1httpSaveCredentials: Bad credentials, returning -1.");
577 if (!CryptAcquireContextW(&hProv
, L
"RememberedContainer", MS_DEF_PROV_W
, PROV_RSA_FULL
, CRYPT_NEWKEYSET
| CRYPT_MACHINE_KEYSET
))
579 if (GetLastError() == NTE_EXISTS
)
581 if (!CryptAcquireContextW(&hProv
, L
"RememberedContainer", MS_DEF_PROV_W
, PROV_RSA_FULL
, CRYPT_MACHINE_KEYSET
))
583 DEBUG_printf(("1httpSaveCredentials: CryptAcquireContext failed: %s", http_sspi_strerror(error
, sizeof(error
), GetLastError())));
589 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");
593 DEBUG_printf(("1httpSaveCredentials: CertOpenSystemStore failed: %s", http_sspi_strerror(error
, sizeof(error
), GetLastError())));
599 if (!CertStrToName(X509_ASN_ENCODING
, common_name
, CERT_OID_NAME_STR
, NULL
, NULL
, &dwSize
, NULL
))
601 DEBUG_printf(("1httpSaveCredentials: CertStrToName failed: %s", http_sspi_strerror(error
, sizeof(error
), GetLastError())));
605 p
= (PBYTE
)malloc(dwSize
);
609 DEBUG_printf(("1httpSaveCredentials: malloc failed for %d bytes.", dwSize
));
613 if (!CertStrToName(X509_ASN_ENCODING
, common_name
, CERT_OID_NAME_STR
, NULL
, p
, &dwSize
, NULL
))
615 DEBUG_printf(("1httpSaveCredentials: CertStrToName failed: %s", http_sspi_strerror(error
, sizeof(error
), GetLastError())));
620 * Add the created context to the named store, and associate it with the named
624 if (!CertAddCertificateContextToStore(store
, createdContext
, CERT_STORE_ADD_REPLACE_EXISTING
, &storedContext
))
626 DEBUG_printf(("1httpSaveCredentials: CertAddCertificateContextToStore failed: %s", http_sspi_strerror(error
, sizeof(error
), GetLastError())));
630 ZeroMemory(&ckp
, sizeof(ckp
));
631 ckp
.pwszContainerName
= L
"RememberedContainer";
632 ckp
.pwszProvName
= MS_DEF_PROV_W
;
633 ckp
.dwProvType
= PROV_RSA_FULL
;
634 ckp
.dwFlags
= CRYPT_MACHINE_KEYSET
;
635 ckp
.dwKeySpec
= AT_KEYEXCHANGE
;
637 if (!CertSetCertificateContextProperty(storedContext
, CERT_KEY_PROV_INFO_PROP_ID
, 0, &ckp
))
639 DEBUG_printf(("1httpSaveCredentials: CertSetCertificateContextProperty failed: %s", http_sspi_strerror(error
, sizeof(error
), GetLastError())));
652 CertFreeCertificateContext(createdContext
);
655 CertFreeCertificateContext(storedContext
);
661 CertCloseStore(store
, 0);
664 CryptReleaseContext(hProv
, 0);
666 DEBUG_printf(("1httpSaveCredentials: Returning %d.", ret
));
672 * '_httpTLSInitialize()' - Initialize the TLS stack.
676 _httpTLSInitialize(void)
685 * '_httpTLSPending()' - Return the number of pending TLS-encrypted bytes.
688 size_t /* O - Bytes available */
689 _httpTLSPending(http_t
*http
) /* I - HTTP connection */
692 return (http
->tls
->readBufferUsed
);
699 * '_httpTLSRead()' - Read from a SSL/TLS connection.
702 int /* O - Bytes read */
703 _httpTLSRead(http_t
*http
, /* I - HTTP connection */
704 char *buf
, /* I - Buffer to store data */
705 int len
) /* I - Length of buffer */
707 int i
; /* Looping var */
708 _http_sspi_t
*sspi
= http
->tls
; /* SSPI data */
709 SecBufferDesc message
; /* Array of SecBuffer struct */
710 SecBuffer buffers
[4] = { 0 }; /* Security package buffer */
711 int num
= 0; /* Return value */
712 PSecBuffer pDataBuffer
; /* Data buffer */
713 PSecBuffer pExtraBuffer
; /* Excess data buffer */
714 SECURITY_STATUS scRet
; /* SSPI status */
717 DEBUG_printf(("4_httpTLSRead(http=%p, buf=%p, len=%d)", http
, buf
, len
));
720 * If there are bytes that have already been decrypted and have not yet been
721 * read, return those...
724 if (sspi
->readBufferUsed
> 0)
726 int bytesToCopy
= min(sspi
->readBufferUsed
, len
);
727 /* Number of bytes to copy */
729 memcpy(buf
, sspi
->readBuffer
, bytesToCopy
);
730 sspi
->readBufferUsed
-= bytesToCopy
;
732 if (sspi
->readBufferUsed
> 0)
733 memmove(sspi
->readBuffer
, sspi
->readBuffer
+ bytesToCopy
, sspi
->readBufferUsed
);
735 DEBUG_printf(("5_httpTLSRead: Returning %d bytes previously decrypted.", bytesToCopy
));
737 return (bytesToCopy
);
741 * Initialize security buffer structs
744 message
.ulVersion
= SECBUFFER_VERSION
;
745 message
.cBuffers
= 4;
746 message
.pBuffers
= buffers
;
751 * If there is not enough space in the buffer, then increase its size...
754 if (sspi
->decryptBufferLength
<= sspi
->decryptBufferUsed
)
756 BYTE
*temp
; /* New buffer */
758 if (sspi
->decryptBufferLength
>= 262144)
760 WSASetLastError(E_OUTOFMEMORY
);
761 DEBUG_puts("_httpTLSRead: Decryption buffer too large (>256k)");
765 if ((temp
= realloc(sspi
->decryptBuffer
, sspi
->decryptBufferLength
+ 4096)) == NULL
)
767 DEBUG_printf(("_httpTLSRead: Unable to allocate %d byte decryption buffer.", sspi
->decryptBufferLength
+ 4096));
768 WSASetLastError(E_OUTOFMEMORY
);
772 sspi
->decryptBufferLength
+= 4096;
773 sspi
->decryptBuffer
= temp
;
775 DEBUG_printf(("_httpTLSRead: Resized decryption buffer to %d bytes.", sspi
->decryptBufferLength
));
778 buffers
[0].pvBuffer
= sspi
->decryptBuffer
;
779 buffers
[0].cbBuffer
= (unsigned long)sspi
->decryptBufferUsed
;
780 buffers
[0].BufferType
= SECBUFFER_DATA
;
781 buffers
[1].BufferType
= SECBUFFER_EMPTY
;
782 buffers
[2].BufferType
= SECBUFFER_EMPTY
;
783 buffers
[3].BufferType
= SECBUFFER_EMPTY
;
785 DEBUG_printf(("5_httpTLSRead: decryptBufferUsed=%d", sspi
->decryptBufferUsed
));
787 scRet
= DecryptMessage(&sspi
->context
, &message
, 0, NULL
);
789 if (scRet
== SEC_E_INCOMPLETE_MESSAGE
)
791 num
= recv(http
->fd
, sspi
->decryptBuffer
+ sspi
->decryptBufferUsed
, (int)(sspi
->decryptBufferLength
- sspi
->decryptBufferUsed
), 0);
794 DEBUG_printf(("5_httpTLSRead: recv failed: %d", WSAGetLastError()));
799 DEBUG_puts("5_httpTLSRead: Server disconnected.");
803 DEBUG_printf(("5_httpTLSRead: Read %d bytes into decryption buffer.", num
));
805 sspi
->decryptBufferUsed
+= num
;
808 while (scRet
== SEC_E_INCOMPLETE_MESSAGE
);
810 if (scRet
== SEC_I_CONTEXT_EXPIRED
)
812 DEBUG_puts("5_httpTLSRead: Context expired.");
813 WSASetLastError(WSAECONNRESET
);
816 else if (scRet
!= SEC_E_OK
)
818 DEBUG_printf(("5_httpTLSRead: DecryptMessage failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), scRet
)));
819 WSASetLastError(WSASYSCALLFAILURE
);
824 * The decryption worked. Now, locate data buffer.
830 for (i
= 1; i
< 4; i
++)
832 if (buffers
[i
].BufferType
== SECBUFFER_DATA
)
833 pDataBuffer
= &buffers
[i
];
834 else if (!pExtraBuffer
&& (buffers
[i
].BufferType
== SECBUFFER_EXTRA
))
835 pExtraBuffer
= &buffers
[i
];
839 * If a data buffer is found, then copy the decrypted bytes to the passed-in
845 int bytesToCopy
= min((int)pDataBuffer
->cbBuffer
, len
);
846 /* Number of bytes to copy into buf */
847 int bytesToSave
= pDataBuffer
->cbBuffer
- bytesToCopy
;
848 /* Number of bytes to save in our read buffer */
851 memcpy(buf
, pDataBuffer
->pvBuffer
, bytesToCopy
);
854 * If there are more decrypted bytes than can be copied to the passed in
855 * buffer, then save them...
860 if ((sspi
->readBufferLength
- sspi
->readBufferUsed
) < bytesToSave
)
862 BYTE
*temp
; /* New buffer pointer */
864 if ((temp
= realloc(sspi
->readBuffer
, sspi
->readBufferUsed
+ bytesToSave
)) == NULL
)
866 DEBUG_printf(("_httpTLSRead: Unable to allocate %d bytes.", sspi
->readBufferUsed
+ bytesToSave
));
867 WSASetLastError(E_OUTOFMEMORY
);
871 sspi
->readBufferLength
= sspi
->readBufferUsed
+ bytesToSave
;
872 sspi
->readBuffer
= temp
;
875 memcpy(((BYTE
*)sspi
->readBuffer
) + sspi
->readBufferUsed
, ((BYTE
*)pDataBuffer
->pvBuffer
) + bytesToCopy
, bytesToSave
);
877 sspi
->readBufferUsed
+= bytesToSave
;
884 DEBUG_puts("_httpTLSRead: Unable to find data buffer.");
885 WSASetLastError(WSASYSCALLFAILURE
);
890 * If the decryption process left extra bytes, then save those back in
891 * decryptBuffer. They will be processed the next time through the loop.
896 memmove(sspi
->decryptBuffer
, pExtraBuffer
->pvBuffer
, pExtraBuffer
->cbBuffer
);
897 sspi
->decryptBufferUsed
= pExtraBuffer
->cbBuffer
;
901 sspi
->decryptBufferUsed
= 0;
909 * '_httpTLSSetOptions()' - Set TLS protocol and cipher suite options.
913 _httpTLSSetOptions(int options
, /* I - Options */
914 int min_version
, /* I - Minimum TLS version */
915 int max_version
) /* I - Maximum TLS version */
917 if (!(options
& _HTTP_TLS_SET_DEFAULT
) || tls_options
< 0)
919 tls_options
= options
;
920 tls_min_version
= min_version
;
921 tls_max_version
= max_version
;
927 * '_httpTLSStart()' - Set up SSL/TLS support on a connection.
930 int /* O - 0 on success, -1 on failure */
931 _httpTLSStart(http_t
*http
) /* I - HTTP connection */
933 char hostname
[256], /* Hostname */
934 *hostptr
; /* Pointer into hostname */
937 DEBUG_printf(("3_httpTLSStart(http=%p)", http
));
941 DEBUG_puts("4_httpTLSStart: Setting defaults.");
943 DEBUG_printf(("4_httpTLSStart: tls_options=%x", tls_options
));
946 if ((http
->tls
= http_sspi_alloc()) == NULL
)
949 if (http
->mode
== _HTTP_MODE_CLIENT
)
952 * Client: determine hostname...
955 if (httpAddrLocalhost(http
->hostaddr
))
957 strlcpy(hostname
, "localhost", sizeof(hostname
));
962 * Otherwise make sure the hostname we have does not end in a trailing dot.
965 strlcpy(hostname
, http
->hostname
, sizeof(hostname
));
966 if ((hostptr
= hostname
+ strlen(hostname
) - 1) >= hostname
&&
971 return (http_sspi_client(http
, hostname
));
976 * Server: determine hostname to use...
979 if (http
->fields
[HTTP_FIELD_HOST
][0])
982 * Use hostname for TLS upgrade...
985 strlcpy(hostname
, http
->fields
[HTTP_FIELD_HOST
], sizeof(hostname
));
990 * Resolve hostname from connection address...
993 http_addr_t addr
; /* Connection address */
994 socklen_t addrlen
; /* Length of address */
996 addrlen
= sizeof(addr
);
997 if (getsockname(http
->fd
, (struct sockaddr
*)&addr
, &addrlen
))
999 DEBUG_printf(("4_httpTLSStart: Unable to get socket address: %s", strerror(errno
)));
1002 else if (httpAddrLocalhost(&addr
))
1006 httpAddrLookup(&addr
, hostname
, sizeof(hostname
));
1007 DEBUG_printf(("4_httpTLSStart: Resolved socket address to \"%s\".", hostname
));
1011 return (http_sspi_server(http
, hostname
));
1017 * '_httpTLSStop()' - Shut down SSL/TLS on a connection.
1021 _httpTLSStop(http_t
*http
) /* I - HTTP connection */
1023 _http_sspi_t
*sspi
= http
->tls
; /* SSPI data */
1026 if (sspi
->contextInitialized
&& http
->fd
>= 0)
1028 SecBufferDesc message
; /* Array of SecBuffer struct */
1029 SecBuffer buffers
[1] = { 0 };
1030 /* Security package buffer */
1031 DWORD dwType
; /* Type */
1032 DWORD status
; /* Status */
1035 * Notify schannel that we are about to close the connection.
1038 dwType
= SCHANNEL_SHUTDOWN
;
1040 buffers
[0].pvBuffer
= &dwType
;
1041 buffers
[0].BufferType
= SECBUFFER_TOKEN
;
1042 buffers
[0].cbBuffer
= sizeof(dwType
);
1044 message
.cBuffers
= 1;
1045 message
.pBuffers
= buffers
;
1046 message
.ulVersion
= SECBUFFER_VERSION
;
1048 status
= ApplyControlToken(&sspi
->context
, &message
);
1050 if (SUCCEEDED(status
))
1052 PBYTE pbMessage
; /* Message buffer */
1053 DWORD cbMessage
; /* Message buffer count */
1054 DWORD cbData
; /* Data count */
1055 DWORD dwSSPIFlags
; /* SSL attributes we requested */
1056 DWORD dwSSPIOutFlags
; /* SSL attributes we received */
1057 TimeStamp tsExpiry
; /* Time stamp */
1059 dwSSPIFlags
= ASC_REQ_SEQUENCE_DETECT
|
1060 ASC_REQ_REPLAY_DETECT
|
1061 ASC_REQ_CONFIDENTIALITY
|
1062 ASC_REQ_EXTENDED_ERROR
|
1063 ASC_REQ_ALLOCATE_MEMORY
|
1066 buffers
[0].pvBuffer
= NULL
;
1067 buffers
[0].BufferType
= SECBUFFER_TOKEN
;
1068 buffers
[0].cbBuffer
= 0;
1070 message
.cBuffers
= 1;
1071 message
.pBuffers
= buffers
;
1072 message
.ulVersion
= SECBUFFER_VERSION
;
1074 status
= AcceptSecurityContext(&sspi
->creds
, &sspi
->context
, NULL
,
1075 dwSSPIFlags
, SECURITY_NATIVE_DREP
, NULL
,
1076 &message
, &dwSSPIOutFlags
, &tsExpiry
);
1078 if (SUCCEEDED(status
))
1080 pbMessage
= buffers
[0].pvBuffer
;
1081 cbMessage
= buffers
[0].cbBuffer
;
1084 * Send the close notify message to the client.
1087 if (pbMessage
&& cbMessage
)
1089 cbData
= send(http
->fd
, pbMessage
, cbMessage
, 0);
1090 if ((cbData
== SOCKET_ERROR
) || (cbData
== 0))
1092 status
= WSAGetLastError();
1093 DEBUG_printf(("_httpTLSStop: sending close notify failed: %d", status
));
1097 FreeContextBuffer(pbMessage
);
1103 DEBUG_printf(("_httpTLSStop: AcceptSecurityContext failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), status
)));
1108 DEBUG_printf(("_httpTLSStop: ApplyControlToken failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), status
)));
1112 http_sspi_free(sspi
);
1119 * '_httpTLSWrite()' - Write to a SSL/TLS connection.
1122 int /* O - Bytes written */
1123 _httpTLSWrite(http_t
*http
, /* I - HTTP connection */
1124 const char *buf
, /* I - Buffer holding data */
1125 int len
) /* I - Length of buffer */
1127 _http_sspi_t
*sspi
= http
->tls
; /* SSPI data */
1128 SecBufferDesc message
; /* Array of SecBuffer struct */
1129 SecBuffer buffers
[4] = { 0 }; /* Security package buffer */
1130 int bufferLen
; /* Buffer length */
1131 int bytesLeft
; /* Bytes left to write */
1132 const char *bufptr
; /* Pointer into buffer */
1133 int num
= 0; /* Return value */
1136 bufferLen
= sspi
->streamSizes
.cbMaximumMessage
+ sspi
->streamSizes
.cbHeader
+ sspi
->streamSizes
.cbTrailer
;
1138 if (bufferLen
> sspi
->writeBufferLength
)
1140 BYTE
*temp
; /* New buffer pointer */
1142 if ((temp
= (BYTE
*)realloc(sspi
->writeBuffer
, bufferLen
)) == NULL
)
1144 DEBUG_printf(("_httpTLSWrite: Unable to allocate buffer of %d bytes.", bufferLen
));
1145 WSASetLastError(E_OUTOFMEMORY
);
1149 sspi
->writeBuffer
= temp
;
1150 sspi
->writeBufferLength
= bufferLen
;
1158 int chunk
= min((int)sspi
->streamSizes
.cbMaximumMessage
, bytesLeft
);
1159 /* Size of data to write */
1160 SECURITY_STATUS scRet
; /* SSPI status */
1163 * Copy user data into the buffer, starting just past the header...
1166 memcpy(sspi
->writeBuffer
+ sspi
->streamSizes
.cbHeader
, bufptr
, chunk
);
1169 * Setup the SSPI buffers
1172 message
.ulVersion
= SECBUFFER_VERSION
;
1173 message
.cBuffers
= 4;
1174 message
.pBuffers
= buffers
;
1176 buffers
[0].pvBuffer
= sspi
->writeBuffer
;
1177 buffers
[0].cbBuffer
= sspi
->streamSizes
.cbHeader
;
1178 buffers
[0].BufferType
= SECBUFFER_STREAM_HEADER
;
1179 buffers
[1].pvBuffer
= sspi
->writeBuffer
+ sspi
->streamSizes
.cbHeader
;
1180 buffers
[1].cbBuffer
= (unsigned long) chunk
;
1181 buffers
[1].BufferType
= SECBUFFER_DATA
;
1182 buffers
[2].pvBuffer
= sspi
->writeBuffer
+ sspi
->streamSizes
.cbHeader
+ chunk
;
1183 buffers
[2].cbBuffer
= sspi
->streamSizes
.cbTrailer
;
1184 buffers
[2].BufferType
= SECBUFFER_STREAM_TRAILER
;
1185 buffers
[3].BufferType
= SECBUFFER_EMPTY
;
1191 scRet
= EncryptMessage(&sspi
->context
, 0, &message
, 0);
1195 DEBUG_printf(("_httpTLSWrite: EncryptMessage failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), scRet
)));
1196 WSASetLastError(WSASYSCALLFAILURE
);
1201 * Send the data. Remember the size of the total data to send is the size
1202 * of the header, the size of the data the caller passed in and the size
1206 num
= send(http
->fd
, sspi
->writeBuffer
, buffers
[0].cbBuffer
+ buffers
[1].cbBuffer
+ buffers
[2].cbBuffer
, 0);
1210 DEBUG_printf(("_httpTLSWrite: send failed: %ld", WSAGetLastError()));
1224 * 'http_setup_ssl()' - Set up SSL/TLS support on a connection.
1227 static int /* O - 0 on success, -1 on failure */
1228 http_setup_ssl(http_t
*http
) /* I - Connection to server */
1230 char hostname
[256], /* Hostname */
1231 *hostptr
; /* Pointer into hostname */
1233 TCHAR username
[256]; /* Username returned from GetUserName() */
1234 TCHAR commonName
[256];/* Common name for certificate */
1235 DWORD dwSize
; /* 32 bit size */
1238 DEBUG_printf(("7http_setup_ssl(http=%p)", http
));
1241 * Get the hostname to use for SSL...
1244 if (httpAddrLocalhost(http
->hostaddr
))
1246 strlcpy(hostname
, "localhost", sizeof(hostname
));
1251 * Otherwise make sure the hostname we have does not end in a trailing dot.
1254 strlcpy(hostname
, http
->hostname
, sizeof(hostname
));
1255 if ((hostptr
= hostname
+ strlen(hostname
) - 1) >= hostname
&&
1260 http
->tls
= http_sspi_alloc();
1264 _cupsSetHTTPError(HTTP_STATUS_ERROR
);
1268 dwSize
= sizeof(username
) / sizeof(TCHAR
);
1269 GetUserName(username
, &dwSize
);
1270 _sntprintf_s(commonName
, sizeof(commonName
) / sizeof(TCHAR
),
1271 sizeof(commonName
) / sizeof(TCHAR
), TEXT("CN=%s"), username
);
1273 if (!_sspiGetCredentials(http
->tls
, L
"ClientContainer",
1276 _sspiFree(http
->tls
);
1280 http
->status
= HTTP_STATUS_ERROR
;
1282 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI
,
1283 _("Unable to establish a secure connection to host."), 1);
1288 _sspiSetAllowsAnyRoot(http
->tls
, TRUE
);
1289 _sspiSetAllowsExpiredCerts(http
->tls
, TRUE
);
1291 if (!_sspiConnect(http
->tls
, hostname
))
1293 _sspiFree(http
->tls
);
1297 http
->status
= HTTP_STATUS_ERROR
;
1299 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI
,
1300 _("Unable to establish a secure connection to host."), 1);
1311 * 'http_sspi_alloc()' - Allocate SSPI object.
1314 static _http_sspi_t
* /* O - New SSPI/SSL object */
1315 http_sspi_alloc(void)
1317 return ((_http_sspi_t
*)calloc(sizeof(_http_sspi_t
), 1));
1322 * 'http_sspi_client()' - Negotiate a TLS connection as a client.
1325 static int /* O - 0 on success, -1 on failure */
1326 http_sspi_client(http_t
*http
, /* I - Client connection */
1327 const char *hostname
) /* I - Server hostname */
1329 _http_sspi_t
*sspi
= http
->tls
; /* SSPI data */
1330 DWORD dwSize
; /* Size for buffer */
1331 DWORD dwSSPIFlags
; /* SSL connection attributes we want */
1332 DWORD dwSSPIOutFlags
; /* SSL connection attributes we got */
1333 TimeStamp tsExpiry
; /* Time stamp */
1334 SECURITY_STATUS scRet
; /* Status */
1335 int cbData
; /* Data count */
1336 SecBufferDesc inBuffer
; /* Array of SecBuffer structs */
1337 SecBuffer inBuffers
[2]; /* Security package buffer */
1338 SecBufferDesc outBuffer
; /* Array of SecBuffer structs */
1339 SecBuffer outBuffers
[1]; /* Security package buffer */
1340 int ret
= 0; /* Return value */
1341 char username
[1024], /* Current username */
1342 common_name
[1024]; /* CN=username */
1345 DEBUG_printf(("4http_sspi_client(http=%p, hostname=\"%s\")", http
, hostname
));
1347 dwSSPIFlags
= ISC_REQ_SEQUENCE_DETECT
|
1348 ISC_REQ_REPLAY_DETECT
|
1349 ISC_REQ_CONFIDENTIALITY
|
1350 ISC_RET_EXTENDED_ERROR
|
1351 ISC_REQ_ALLOCATE_MEMORY
|
1355 * Lookup the client certificate...
1358 dwSize
= sizeof(username
);
1359 GetUserName(username
, &dwSize
);
1360 snprintf(common_name
, sizeof(common_name
), "CN=%s", username
);
1362 if (!http_sspi_find_credentials(http
, L
"ClientContainer", common_name
))
1363 if (!http_sspi_make_credentials(http
->tls
, L
"ClientContainer", common_name
, _HTTP_MODE_CLIENT
, 10))
1365 DEBUG_puts("5http_sspi_client: Unable to get client credentials.");
1370 * Initiate a ClientHello message and generate a token.
1373 outBuffers
[0].pvBuffer
= NULL
;
1374 outBuffers
[0].BufferType
= SECBUFFER_TOKEN
;
1375 outBuffers
[0].cbBuffer
= 0;
1377 outBuffer
.cBuffers
= 1;
1378 outBuffer
.pBuffers
= outBuffers
;
1379 outBuffer
.ulVersion
= SECBUFFER_VERSION
;
1381 scRet
= InitializeSecurityContext(&sspi
->creds
, NULL
, TEXT(""), dwSSPIFlags
, 0, SECURITY_NATIVE_DREP
, NULL
, 0, &sspi
->context
, &outBuffer
, &dwSSPIOutFlags
, &tsExpiry
);
1383 if (scRet
!= SEC_I_CONTINUE_NEEDED
)
1385 DEBUG_printf(("5http_sspi_client: InitializeSecurityContext(1) failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), scRet
)));
1390 * Send response to server if there is one.
1393 if (outBuffers
[0].cbBuffer
&& outBuffers
[0].pvBuffer
)
1395 if ((cbData
= send(http
->fd
, outBuffers
[0].pvBuffer
, outBuffers
[0].cbBuffer
, 0)) <= 0)
1397 DEBUG_printf(("5http_sspi_client: send failed: %d", WSAGetLastError()));
1398 FreeContextBuffer(outBuffers
[0].pvBuffer
);
1399 DeleteSecurityContext(&sspi
->context
);
1403 DEBUG_printf(("5http_sspi_client: %d bytes of handshake data sent.", cbData
));
1405 FreeContextBuffer(outBuffers
[0].pvBuffer
);
1406 outBuffers
[0].pvBuffer
= NULL
;
1409 dwSSPIFlags
= ISC_REQ_MANUAL_CRED_VALIDATION
|
1410 ISC_REQ_SEQUENCE_DETECT
|
1411 ISC_REQ_REPLAY_DETECT
|
1412 ISC_REQ_CONFIDENTIALITY
|
1413 ISC_RET_EXTENDED_ERROR
|
1414 ISC_REQ_ALLOCATE_MEMORY
|
1417 sspi
->decryptBufferUsed
= 0;
1420 * Loop until the handshake is finished or an error occurs.
1423 scRet
= SEC_I_CONTINUE_NEEDED
;
1425 while(scRet
== SEC_I_CONTINUE_NEEDED
||
1426 scRet
== SEC_E_INCOMPLETE_MESSAGE
||
1427 scRet
== SEC_I_INCOMPLETE_CREDENTIALS
)
1429 if (sspi
->decryptBufferUsed
== 0 || scRet
== SEC_E_INCOMPLETE_MESSAGE
)
1431 if (sspi
->decryptBufferLength
<= sspi
->decryptBufferUsed
)
1433 BYTE
*temp
; /* New buffer */
1435 if (sspi
->decryptBufferLength
>= 262144)
1437 WSASetLastError(E_OUTOFMEMORY
);
1438 DEBUG_puts("5http_sspi_client: Decryption buffer too large (>256k)");
1442 if ((temp
= realloc(sspi
->decryptBuffer
, sspi
->decryptBufferLength
+ 4096)) == NULL
)
1444 DEBUG_printf(("5http_sspi_client: Unable to allocate %d byte buffer.", sspi
->decryptBufferLength
+ 4096));
1445 WSASetLastError(E_OUTOFMEMORY
);
1449 sspi
->decryptBufferLength
+= 4096;
1450 sspi
->decryptBuffer
= temp
;
1453 cbData
= recv(http
->fd
, sspi
->decryptBuffer
+ sspi
->decryptBufferUsed
, (int)(sspi
->decryptBufferLength
- sspi
->decryptBufferUsed
), 0);
1457 DEBUG_printf(("5http_sspi_client: recv failed: %d", WSAGetLastError()));
1460 else if (cbData
== 0)
1462 DEBUG_printf(("5http_sspi_client: Server unexpectedly disconnected."));
1466 DEBUG_printf(("5http_sspi_client: %d bytes of handshake data received", cbData
));
1468 sspi
->decryptBufferUsed
+= cbData
;
1472 * Set up the input buffers. Buffer 0 is used to pass in data received from
1473 * the server. Schannel will consume some or all of this. Leftover data
1474 * (if any) will be placed in buffer 1 and given a buffer type of
1478 inBuffers
[0].pvBuffer
= sspi
->decryptBuffer
;
1479 inBuffers
[0].cbBuffer
= (unsigned long)sspi
->decryptBufferUsed
;
1480 inBuffers
[0].BufferType
= SECBUFFER_TOKEN
;
1482 inBuffers
[1].pvBuffer
= NULL
;
1483 inBuffers
[1].cbBuffer
= 0;
1484 inBuffers
[1].BufferType
= SECBUFFER_EMPTY
;
1486 inBuffer
.cBuffers
= 2;
1487 inBuffer
.pBuffers
= inBuffers
;
1488 inBuffer
.ulVersion
= SECBUFFER_VERSION
;
1491 * Set up the output buffers. These are initialized to NULL so as to make it
1492 * less likely we'll attempt to free random garbage later.
1495 outBuffers
[0].pvBuffer
= NULL
;
1496 outBuffers
[0].BufferType
= SECBUFFER_TOKEN
;
1497 outBuffers
[0].cbBuffer
= 0;
1499 outBuffer
.cBuffers
= 1;
1500 outBuffer
.pBuffers
= outBuffers
;
1501 outBuffer
.ulVersion
= SECBUFFER_VERSION
;
1504 * Call InitializeSecurityContext.
1507 scRet
= InitializeSecurityContext(&sspi
->creds
, &sspi
->context
, NULL
, dwSSPIFlags
, 0, SECURITY_NATIVE_DREP
, &inBuffer
, 0, NULL
, &outBuffer
, &dwSSPIOutFlags
, &tsExpiry
);
1510 * If InitializeSecurityContext was successful (or if the error was one of
1511 * the special extended ones), send the contents of the output buffer to the
1515 if (scRet
== SEC_E_OK
||
1516 scRet
== SEC_I_CONTINUE_NEEDED
||
1517 FAILED(scRet
) && (dwSSPIOutFlags
& ISC_RET_EXTENDED_ERROR
))
1519 if (outBuffers
[0].cbBuffer
&& outBuffers
[0].pvBuffer
)
1521 cbData
= send(http
->fd
, outBuffers
[0].pvBuffer
, outBuffers
[0].cbBuffer
, 0);
1525 DEBUG_printf(("5http_sspi_client: send failed: %d", WSAGetLastError()));
1526 FreeContextBuffer(outBuffers
[0].pvBuffer
);
1527 DeleteSecurityContext(&sspi
->context
);
1531 DEBUG_printf(("5http_sspi_client: %d bytes of handshake data sent.", cbData
));
1534 * Free output buffer.
1537 FreeContextBuffer(outBuffers
[0].pvBuffer
);
1538 outBuffers
[0].pvBuffer
= NULL
;
1543 * If InitializeSecurityContext returned SEC_E_INCOMPLETE_MESSAGE, then we
1544 * need to read more data from the server and try again.
1547 if (scRet
== SEC_E_INCOMPLETE_MESSAGE
)
1551 * If InitializeSecurityContext returned SEC_E_OK, then the handshake
1552 * completed successfully.
1555 if (scRet
== SEC_E_OK
)
1558 * If the "extra" buffer contains data, this is encrypted application
1559 * protocol layer stuff. It needs to be saved. The application layer will
1560 * later decrypt it with DecryptMessage.
1563 DEBUG_puts("5http_sspi_client: Handshake was successful.");
1565 if (inBuffers
[1].BufferType
== SECBUFFER_EXTRA
)
1567 memmove(sspi
->decryptBuffer
, sspi
->decryptBuffer
+ sspi
->decryptBufferUsed
- inBuffers
[1].cbBuffer
, inBuffers
[1].cbBuffer
);
1569 sspi
->decryptBufferUsed
= inBuffers
[1].cbBuffer
;
1571 DEBUG_printf(("5http_sspi_client: %d bytes of app data was bundled with handshake data", sspi
->decryptBufferUsed
));
1574 sspi
->decryptBufferUsed
= 0;
1584 * Check for fatal error.
1589 DEBUG_printf(("5http_sspi_client: InitializeSecurityContext(2) failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), scRet
)));
1595 * If InitializeSecurityContext returned SEC_I_INCOMPLETE_CREDENTIALS,
1596 * then the server just requested client authentication.
1599 if (scRet
== SEC_I_INCOMPLETE_CREDENTIALS
)
1605 DEBUG_printf(("5http_sspi_client: server requested client credentials."));
1611 * Copy any leftover data from the "extra" buffer, and go around again.
1614 if (inBuffers
[1].BufferType
== SECBUFFER_EXTRA
)
1616 memmove(sspi
->decryptBuffer
, sspi
->decryptBuffer
+ sspi
->decryptBufferUsed
- inBuffers
[1].cbBuffer
, inBuffers
[1].cbBuffer
);
1618 sspi
->decryptBufferUsed
= inBuffers
[1].cbBuffer
;
1622 sspi
->decryptBufferUsed
= 0;
1629 * Success! Get the server cert
1632 sspi
->contextInitialized
= TRUE
;
1634 scRet
= QueryContextAttributes(&sspi
->context
, SECPKG_ATTR_REMOTE_CERT_CONTEXT
, (VOID
*)&(sspi
->remoteCert
));
1636 if (scRet
!= SEC_E_OK
)
1638 DEBUG_printf(("5http_sspi_client: QueryContextAttributes failed(SECPKG_ATTR_REMOTE_CERT_CONTEXT): %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), scRet
)));
1643 * Find out how big the header/trailer will be:
1646 scRet
= QueryContextAttributes(&sspi
->context
, SECPKG_ATTR_STREAM_SIZES
, &sspi
->streamSizes
);
1648 if (scRet
!= SEC_E_OK
)
1650 DEBUG_printf(("5http_sspi_client: QueryContextAttributes failed(SECPKG_ATTR_STREAM_SIZES): %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), scRet
)));
1660 * 'http_sspi_create_credential()' - Create an SSPI certificate context.
1663 static PCCERT_CONTEXT
/* O - Certificate context */
1664 http_sspi_create_credential(
1665 http_credential_t
*cred
) /* I - Credential */
1668 return (CertCreateCertificateContext(X509_ASN_ENCODING
, cred
->data
, cred
->datalen
));
1675 * 'http_sspi_find_credentials()' - Retrieve a TLS certificate from the system store.
1678 static BOOL
/* O - 1 on success, 0 on failure */
1679 http_sspi_find_credentials(
1680 http_t
*http
, /* I - HTTP connection */
1681 const LPWSTR container
, /* I - Cert container name */
1682 const char *common_name
) /* I - Common name of certificate */
1684 _http_sspi_t
*sspi
= http
->tls
; /* SSPI data */
1685 HCERTSTORE store
= NULL
; /* Certificate store */
1686 PCCERT_CONTEXT storedContext
= NULL
; /* Context created from the store */
1687 DWORD dwSize
= 0; /* 32 bit size */
1688 PBYTE p
= NULL
; /* Temporary storage */
1689 HCRYPTPROV hProv
= (HCRYPTPROV
)NULL
;
1690 /* Handle to a CSP */
1691 CERT_NAME_BLOB sib
; /* Arbitrary array of bytes */
1692 SCHANNEL_CRED SchannelCred
; /* Schannel credential data */
1693 TimeStamp tsExpiry
; /* Time stamp */
1694 SECURITY_STATUS Status
; /* Status */
1695 BOOL ok
= TRUE
; /* Return value */
1698 if (!CryptAcquireContextW(&hProv
, (LPWSTR
)container
, MS_DEF_PROV_W
, PROV_RSA_FULL
, CRYPT_NEWKEYSET
| CRYPT_MACHINE_KEYSET
))
1700 if (GetLastError() == NTE_EXISTS
)
1702 if (!CryptAcquireContextW(&hProv
, (LPWSTR
)container
, MS_DEF_PROV_W
, PROV_RSA_FULL
, CRYPT_MACHINE_KEYSET
))
1704 DEBUG_printf(("5http_sspi_find_credentials: CryptAcquireContext failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), GetLastError())));
1711 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");
1715 DEBUG_printf(("5http_sspi_find_credentials: CertOpenSystemStore failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), GetLastError())));
1722 if (!CertStrToName(X509_ASN_ENCODING
, common_name
, CERT_OID_NAME_STR
, NULL
, NULL
, &dwSize
, NULL
))
1724 DEBUG_printf(("5http_sspi_find_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), GetLastError())));
1729 p
= (PBYTE
)malloc(dwSize
);
1733 DEBUG_printf(("5http_sspi_find_credentials: malloc failed for %d bytes.", dwSize
));
1738 if (!CertStrToName(X509_ASN_ENCODING
, common_name
, CERT_OID_NAME_STR
, NULL
, p
, &dwSize
, NULL
))
1740 DEBUG_printf(("5http_sspi_find_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), GetLastError())));
1745 sib
.cbData
= dwSize
;
1748 storedContext
= CertFindCertificateInStore(store
, X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
, 0, CERT_FIND_SUBJECT_NAME
, &sib
, NULL
);
1752 DEBUG_printf(("5http_sspi_find_credentials: Unable to find credentials for \"%s\".", common_name
));
1757 ZeroMemory(&SchannelCred
, sizeof(SchannelCred
));
1759 SchannelCred
.dwVersion
= SCHANNEL_CRED_VERSION
;
1760 SchannelCred
.cCreds
= 1;
1761 SchannelCred
.paCred
= &storedContext
;
1764 * Set supported protocols (can also be overriden in the registry...)
1767 #ifdef SP_PROT_TLS1_2_SERVER
1768 if (http
->mode
== _HTTP_MODE_SERVER
)
1770 if (tls_min_version
== _HTTP_TLS_SSL3
)
1771 SchannelCred
.grbitEnabledProtocols
= SP_PROT_TLS1_2_SERVER
| SP_PROT_TLS1_1_SERVER
| SP_PROT_TLS1_0_SERVER
| SP_PROT_SSL3_SERVER
;
1772 else if (tls_min_version
== _HTTP_TLS_1_0
)
1773 SchannelCred
.grbitEnabledProtocols
= SP_PROT_TLS1_2_SERVER
| SP_PROT_TLS1_1_SERVER
| SP_PROT_TLS1_0_SERVER
;
1774 else if (tls_min_version
== _HTTP_TLS_1_1
)
1775 SchannelCred
.grbitEnabledProtocols
= SP_PROT_TLS1_2_SERVER
| SP_PROT_TLS1_1_SERVER
;
1777 SchannelCred
.grbitEnabledProtocols
= SP_PROT_TLS1_2_SERVER
;
1781 if (tls_min_version
== _HTTP_TLS_SSL3
)
1782 SchannelCred
.grbitEnabledProtocols
= SP_PROT_TLS1_2_CLIENT
| SP_PROT_TLS1_1_CLIENT
| SP_PROT_TLS1_0_CLIENT
| SP_PROT_SSL3_CLIENT
;
1783 else if (tls_min_version
== _HTTP_TLS_1_0
)
1784 SchannelCred
.grbitEnabledProtocols
= SP_PROT_TLS1_2_CLIENT
| SP_PROT_TLS1_1_CLIENT
| SP_PROT_TLS1_0_CLIENT
;
1785 else if (tls_min_version
== _HTTP_TLS_1_1
)
1786 SchannelCred
.grbitEnabledProtocols
= SP_PROT_TLS1_2_CLIENT
| SP_PROT_TLS1_1_CLIENT
;
1788 SchannelCred
.grbitEnabledProtocols
= SP_PROT_TLS1_2_CLIENT
;
1792 if (http
->mode
== _HTTP_MODE_SERVER
)
1794 if (tls_min_version
== _HTTP_TLS_SSL3
)
1795 SchannelCred
.grbitEnabledProtocols
= SP_PROT_TLS1_SERVER
| SP_PROT_SSL3_SERVER
;
1797 SchannelCred
.grbitEnabledProtocols
= SP_PROT_TLS1_SERVER
;
1801 if (tls_min_version
== _HTTP_TLS_SSL3
)
1802 SchannelCred
.grbitEnabledProtocols
= SP_PROT_TLS1_CLIENT
| SP_PROT_SSL3_CLIENT
;
1804 SchannelCred
.grbitEnabledProtocols
= SP_PROT_TLS1_CLIENT
;
1806 #endif /* SP_PROT_TLS1_2_SERVER */
1808 /* 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... */
1811 * Create an SSPI credential.
1814 Status
= AcquireCredentialsHandle(NULL
, UNISP_NAME
, http
->mode
== _HTTP_MODE_SERVER
? SECPKG_CRED_INBOUND
: SECPKG_CRED_OUTBOUND
, NULL
, &SchannelCred
, NULL
, NULL
, &sspi
->creds
, &tsExpiry
);
1815 if (Status
!= SEC_E_OK
)
1817 DEBUG_printf(("5http_sspi_find_credentials: AcquireCredentialsHandle failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), Status
)));
1829 CertFreeCertificateContext(storedContext
);
1835 CertCloseStore(store
, 0);
1838 CryptReleaseContext(hProv
, 0);
1845 * 'http_sspi_free()' - Close a connection and free resources.
1849 http_sspi_free(_http_sspi_t
*sspi
) /* I - SSPI data */
1854 if (sspi
->contextInitialized
)
1855 DeleteSecurityContext(&sspi
->context
);
1857 if (sspi
->decryptBuffer
)
1858 free(sspi
->decryptBuffer
);
1860 if (sspi
->readBuffer
)
1861 free(sspi
->readBuffer
);
1863 if (sspi
->writeBuffer
)
1864 free(sspi
->writeBuffer
);
1866 if (sspi
->localCert
)
1867 CertFreeCertificateContext(sspi
->localCert
);
1869 if (sspi
->remoteCert
)
1870 CertFreeCertificateContext(sspi
->remoteCert
);
1877 * 'http_sspi_make_credentials()' - Create a TLS certificate in the system store.
1880 static BOOL
/* O - 1 on success, 0 on failure */
1881 http_sspi_make_credentials(
1882 _http_sspi_t
*sspi
, /* I - SSPI data */
1883 const LPWSTR container
, /* I - Cert container name */
1884 const char *common_name
, /* I - Common name of certificate */
1885 _http_mode_t mode
, /* I - Client or server? */
1886 int years
) /* I - Years until expiration */
1888 HCERTSTORE store
= NULL
; /* Certificate store */
1889 PCCERT_CONTEXT storedContext
= NULL
; /* Context created from the store */
1890 PCCERT_CONTEXT createdContext
= NULL
; /* Context created by us */
1891 DWORD dwSize
= 0; /* 32 bit size */
1892 PBYTE p
= NULL
; /* Temporary storage */
1893 HCRYPTPROV hProv
= (HCRYPTPROV
)NULL
;
1894 /* Handle to a CSP */
1895 CERT_NAME_BLOB sib
; /* Arbitrary array of bytes */
1896 SCHANNEL_CRED SchannelCred
; /* Schannel credential data */
1897 TimeStamp tsExpiry
; /* Time stamp */
1898 SECURITY_STATUS Status
; /* Status */
1899 HCRYPTKEY hKey
= (HCRYPTKEY
)NULL
; /* Handle to crypto key */
1900 CRYPT_KEY_PROV_INFO kpi
; /* Key container info */
1901 SYSTEMTIME et
; /* System time */
1902 CERT_EXTENSIONS exts
; /* Array of cert extensions */
1903 CRYPT_KEY_PROV_INFO ckp
; /* Handle to crypto key */
1904 BOOL ok
= TRUE
; /* Return value */
1907 DEBUG_printf(("4http_sspi_make_credentials(sspi=%p, container=%p, common_name=\"%s\", mode=%d, years=%d)", sspi
, container
, common_name
, mode
, years
));
1909 if (!CryptAcquireContextW(&hProv
, (LPWSTR
)container
, MS_DEF_PROV_W
, PROV_RSA_FULL
, CRYPT_NEWKEYSET
| CRYPT_MACHINE_KEYSET
))
1911 if (GetLastError() == NTE_EXISTS
)
1913 if (!CryptAcquireContextW(&hProv
, (LPWSTR
)container
, MS_DEF_PROV_W
, PROV_RSA_FULL
, CRYPT_MACHINE_KEYSET
))
1915 DEBUG_printf(("5http_sspi_make_credentials: CryptAcquireContext failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), GetLastError())));
1922 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");
1926 DEBUG_printf(("5http_sspi_make_credentials: CertOpenSystemStore failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), GetLastError())));
1933 if (!CertStrToName(X509_ASN_ENCODING
, common_name
, CERT_OID_NAME_STR
, NULL
, NULL
, &dwSize
, NULL
))
1935 DEBUG_printf(("5http_sspi_make_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), GetLastError())));
1940 p
= (PBYTE
)malloc(dwSize
);
1944 DEBUG_printf(("5http_sspi_make_credentials: malloc failed for %d bytes", dwSize
));
1949 if (!CertStrToName(X509_ASN_ENCODING
, common_name
, CERT_OID_NAME_STR
, NULL
, p
, &dwSize
, NULL
))
1951 DEBUG_printf(("5http_sspi_make_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), GetLastError())));
1957 * Create a private key and self-signed certificate...
1960 if (!CryptGenKey(hProv
, AT_KEYEXCHANGE
, CRYPT_EXPORTABLE
, &hKey
))
1962 DEBUG_printf(("5http_sspi_make_credentials: CryptGenKey failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), GetLastError())));
1967 ZeroMemory(&kpi
, sizeof(kpi
));
1968 kpi
.pwszContainerName
= (LPWSTR
)container
;
1969 kpi
.pwszProvName
= MS_DEF_PROV_W
;
1970 kpi
.dwProvType
= PROV_RSA_FULL
;
1971 kpi
.dwFlags
= CERT_SET_KEY_CONTEXT_PROP_ID
;
1972 kpi
.dwKeySpec
= AT_KEYEXCHANGE
;
1977 ZeroMemory(&exts
, sizeof(exts
));
1979 createdContext
= CertCreateSelfSignCertificate(hProv
, &sib
, 0, &kpi
, NULL
, NULL
, &et
, &exts
);
1981 if (!createdContext
)
1983 DEBUG_printf(("5http_sspi_make_credentials: CertCreateSelfSignCertificate failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), GetLastError())));
1989 * Add the created context to the named store, and associate it with the named
1993 if (!CertAddCertificateContextToStore(store
, createdContext
, CERT_STORE_ADD_REPLACE_EXISTING
, &storedContext
))
1995 DEBUG_printf(("5http_sspi_make_credentials: CertAddCertificateContextToStore failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), GetLastError())));
2000 ZeroMemory(&ckp
, sizeof(ckp
));
2001 ckp
.pwszContainerName
= (LPWSTR
) container
;
2002 ckp
.pwszProvName
= MS_DEF_PROV_W
;
2003 ckp
.dwProvType
= PROV_RSA_FULL
;
2004 ckp
.dwFlags
= CRYPT_MACHINE_KEYSET
;
2005 ckp
.dwKeySpec
= AT_KEYEXCHANGE
;
2007 if (!CertSetCertificateContextProperty(storedContext
, CERT_KEY_PROV_INFO_PROP_ID
, 0, &ckp
))
2009 DEBUG_printf(("5http_sspi_make_credentials: CertSetCertificateContextProperty failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), GetLastError())));
2015 * Get a handle to use the certificate...
2018 ZeroMemory(&SchannelCred
, sizeof(SchannelCred
));
2020 SchannelCred
.dwVersion
= SCHANNEL_CRED_VERSION
;
2021 SchannelCred
.cCreds
= 1;
2022 SchannelCred
.paCred
= &storedContext
;
2025 * SSPI doesn't seem to like it if grbitEnabledProtocols is set for a client.
2028 if (mode
== _HTTP_MODE_SERVER
)
2029 SchannelCred
.grbitEnabledProtocols
= SP_PROT_SSL3TLS1
;
2032 * Create an SSPI credential.
2035 Status
= AcquireCredentialsHandle(NULL
, UNISP_NAME
, mode
== _HTTP_MODE_SERVER
? SECPKG_CRED_INBOUND
: SECPKG_CRED_OUTBOUND
, NULL
, &SchannelCred
, NULL
, NULL
, &sspi
->creds
, &tsExpiry
);
2036 if (Status
!= SEC_E_OK
)
2038 DEBUG_printf(("5http_sspi_make_credentials: AcquireCredentialsHandle failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), Status
)));
2050 CryptDestroyKey(hKey
);
2053 CertFreeCertificateContext(createdContext
);
2056 CertFreeCertificateContext(storedContext
);
2062 CertCloseStore(store
, 0);
2065 CryptReleaseContext(hProv
, 0);
2072 * 'http_sspi_server()' - Negotiate a TLS connection as a server.
2075 static int /* O - 0 on success, -1 on failure */
2076 http_sspi_server(http_t
*http
, /* I - HTTP connection */
2077 const char *hostname
) /* I - Hostname of server */
2079 _http_sspi_t
*sspi
= http
->tls
; /* I - SSPI data */
2080 char common_name
[512]; /* Common name for cert */
2081 DWORD dwSSPIFlags
; /* SSL connection attributes we want */
2082 DWORD dwSSPIOutFlags
; /* SSL connection attributes we got */
2083 TimeStamp tsExpiry
; /* Time stamp */
2084 SECURITY_STATUS scRet
; /* SSPI Status */
2085 SecBufferDesc inBuffer
; /* Array of SecBuffer structs */
2086 SecBuffer inBuffers
[2]; /* Security package buffer */
2087 SecBufferDesc outBuffer
; /* Array of SecBuffer structs */
2088 SecBuffer outBuffers
[1]; /* Security package buffer */
2089 int num
= 0; /* 32 bit status value */
2090 BOOL fInitContext
= TRUE
; /* Has the context been init'd? */
2091 int ret
= 0; /* Return value */
2094 DEBUG_printf(("4http_sspi_server(http=%p, hostname=\"%s\")", http
, hostname
));
2096 dwSSPIFlags
= ASC_REQ_SEQUENCE_DETECT
|
2097 ASC_REQ_REPLAY_DETECT
|
2098 ASC_REQ_CONFIDENTIALITY
|
2099 ASC_REQ_EXTENDED_ERROR
|
2100 ASC_REQ_ALLOCATE_MEMORY
|
2103 sspi
->decryptBufferUsed
= 0;
2106 * Lookup the server certificate...
2109 snprintf(common_name
, sizeof(common_name
), "CN=%s", hostname
);
2111 if (!http_sspi_find_credentials(http
, L
"ServerContainer", common_name
))
2112 if (!http_sspi_make_credentials(http
->tls
, L
"ServerContainer", common_name
, _HTTP_MODE_SERVER
, 10))
2114 DEBUG_puts("5http_sspi_server: Unable to get server credentials.");
2119 * Set OutBuffer for AcceptSecurityContext call
2122 outBuffer
.cBuffers
= 1;
2123 outBuffer
.pBuffers
= outBuffers
;
2124 outBuffer
.ulVersion
= SECBUFFER_VERSION
;
2126 scRet
= SEC_I_CONTINUE_NEEDED
;
2128 while (scRet
== SEC_I_CONTINUE_NEEDED
||
2129 scRet
== SEC_E_INCOMPLETE_MESSAGE
||
2130 scRet
== SEC_I_INCOMPLETE_CREDENTIALS
)
2132 if (sspi
->decryptBufferUsed
== 0 || scRet
== SEC_E_INCOMPLETE_MESSAGE
)
2134 if (sspi
->decryptBufferLength
<= sspi
->decryptBufferUsed
)
2136 BYTE
*temp
; /* New buffer */
2138 if (sspi
->decryptBufferLength
>= 262144)
2140 WSASetLastError(E_OUTOFMEMORY
);
2141 DEBUG_puts("5http_sspi_server: Decryption buffer too large (>256k)");
2145 if ((temp
= realloc(sspi
->decryptBuffer
, sspi
->decryptBufferLength
+ 4096)) == NULL
)
2147 DEBUG_printf(("5http_sspi_server: Unable to allocate %d byte buffer.", sspi
->decryptBufferLength
+ 4096));
2148 WSASetLastError(E_OUTOFMEMORY
);
2152 sspi
->decryptBufferLength
+= 4096;
2153 sspi
->decryptBuffer
= temp
;
2158 num
= recv(http
->fd
, sspi
->decryptBuffer
+ sspi
->decryptBufferUsed
, (int)(sspi
->decryptBufferLength
- sspi
->decryptBufferUsed
), 0);
2160 if (num
== -1 && WSAGetLastError() == WSAEWOULDBLOCK
)
2168 DEBUG_printf(("5http_sspi_server: recv failed: %d", WSAGetLastError()));
2173 DEBUG_puts("5http_sspi_server: client disconnected");
2177 DEBUG_printf(("5http_sspi_server: received %d (handshake) bytes from client.", num
));
2178 sspi
->decryptBufferUsed
+= num
;
2182 * InBuffers[1] is for getting extra data that SSPI/SCHANNEL doesn't process
2183 * on this run around the loop.
2186 inBuffers
[0].pvBuffer
= sspi
->decryptBuffer
;
2187 inBuffers
[0].cbBuffer
= (unsigned long)sspi
->decryptBufferUsed
;
2188 inBuffers
[0].BufferType
= SECBUFFER_TOKEN
;
2190 inBuffers
[1].pvBuffer
= NULL
;
2191 inBuffers
[1].cbBuffer
= 0;
2192 inBuffers
[1].BufferType
= SECBUFFER_EMPTY
;
2194 inBuffer
.cBuffers
= 2;
2195 inBuffer
.pBuffers
= inBuffers
;
2196 inBuffer
.ulVersion
= SECBUFFER_VERSION
;
2199 * Initialize these so if we fail, pvBuffer contains NULL, so we don't try to
2200 * free random garbage at the quit.
2203 outBuffers
[0].pvBuffer
= NULL
;
2204 outBuffers
[0].BufferType
= SECBUFFER_TOKEN
;
2205 outBuffers
[0].cbBuffer
= 0;
2207 scRet
= AcceptSecurityContext(&sspi
->creds
, (fInitContext
?NULL
:&sspi
->context
), &inBuffer
, dwSSPIFlags
, SECURITY_NATIVE_DREP
, (fInitContext
?&sspi
->context
:NULL
), &outBuffer
, &dwSSPIOutFlags
, &tsExpiry
);
2209 fInitContext
= FALSE
;
2211 if (scRet
== SEC_E_OK
||
2212 scRet
== SEC_I_CONTINUE_NEEDED
||
2213 (FAILED(scRet
) && ((dwSSPIOutFlags
& ISC_RET_EXTENDED_ERROR
) != 0)))
2215 if (outBuffers
[0].cbBuffer
&& outBuffers
[0].pvBuffer
)
2218 * Send response to server if there is one.
2221 num
= send(http
->fd
, outBuffers
[0].pvBuffer
, outBuffers
[0].cbBuffer
, 0);
2225 DEBUG_printf(("5http_sspi_server: handshake send failed: %d", WSAGetLastError()));
2229 DEBUG_printf(("5http_sspi_server: sent %d handshake bytes to client.", outBuffers
[0].cbBuffer
));
2231 FreeContextBuffer(outBuffers
[0].pvBuffer
);
2232 outBuffers
[0].pvBuffer
= NULL
;
2236 if (scRet
== SEC_E_OK
)
2239 * If there's extra data then save it for next time we go to decrypt.
2242 if (inBuffers
[1].BufferType
== SECBUFFER_EXTRA
)
2244 memcpy(sspi
->decryptBuffer
, (LPBYTE
)(sspi
->decryptBuffer
+ sspi
->decryptBufferUsed
- inBuffers
[1].cbBuffer
), inBuffers
[1].cbBuffer
);
2245 sspi
->decryptBufferUsed
= inBuffers
[1].cbBuffer
;
2249 sspi
->decryptBufferUsed
= 0;
2253 else if (FAILED(scRet
) && scRet
!= SEC_E_INCOMPLETE_MESSAGE
)
2255 DEBUG_printf(("5http_sspi_server: AcceptSecurityContext failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), scRet
)));
2260 if (scRet
!= SEC_E_INCOMPLETE_MESSAGE
&&
2261 scRet
!= SEC_I_INCOMPLETE_CREDENTIALS
)
2263 if (inBuffers
[1].BufferType
== SECBUFFER_EXTRA
)
2265 memcpy(sspi
->decryptBuffer
, (LPBYTE
)(sspi
->decryptBuffer
+ sspi
->decryptBufferUsed
- inBuffers
[1].cbBuffer
), inBuffers
[1].cbBuffer
);
2266 sspi
->decryptBufferUsed
= inBuffers
[1].cbBuffer
;
2270 sspi
->decryptBufferUsed
= 0;
2277 sspi
->contextInitialized
= TRUE
;
2280 * Find out how big the header will be:
2283 scRet
= QueryContextAttributes(&sspi
->context
, SECPKG_ATTR_STREAM_SIZES
, &sspi
->streamSizes
);
2285 if (scRet
!= SEC_E_OK
)
2287 DEBUG_printf(("5http_sspi_server: QueryContextAttributes failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), scRet
)));
2297 * 'http_sspi_strerror()' - Return a string for the specified error code.
2300 static const char * /* O - String for error */
2301 http_sspi_strerror(char *buffer
, /* I - Error message buffer */
2302 size_t bufsize
, /* I - Size of buffer */
2303 DWORD code
) /* I - Error code */
2305 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, code
, 0, buffer
, bufsize
, NULL
))
2308 * Strip trailing CR + LF...
2311 char *ptr
; /* Pointer into error message */
2313 for (ptr
= buffer
+ strlen(buffer
) - 1; ptr
>= buffer
; ptr
--)
2314 if (*ptr
== '\n' || *ptr
== '\r')
2320 snprintf(buffer
, bufsize
, "Unknown error %x", code
);
2327 * 'http_sspi_verify()' - Verify a certificate.
2330 static DWORD
/* O - Error code (0 == No error) */
2332 PCCERT_CONTEXT cert
, /* I - Server certificate */
2333 const char *common_name
, /* I - Common name */
2334 DWORD dwCertFlags
) /* I - Verification flags */
2336 HTTPSPolicyCallbackData httpsPolicy
; /* HTTPS Policy Struct */
2337 CERT_CHAIN_POLICY_PARA policyPara
; /* Cert chain policy parameters */
2338 CERT_CHAIN_POLICY_STATUS policyStatus
;/* Cert chain policy status */
2339 CERT_CHAIN_PARA chainPara
; /* Used for searching and matching criteria */
2340 PCCERT_CHAIN_CONTEXT chainContext
= NULL
;
2341 /* Certificate chain */
2342 PWSTR commonNameUnicode
= NULL
;
2343 /* Unicode common name */
2344 LPSTR rgszUsages
[] = { szOID_PKIX_KP_SERVER_AUTH
,
2345 szOID_SERVER_GATED_CRYPTO
,
2346 szOID_SGC_NETSCAPE
};
2347 /* How are we using this certificate? */
2348 DWORD cUsages
= sizeof(rgszUsages
) / sizeof(LPSTR
);
2349 /* Number of ites in rgszUsages */
2350 DWORD count
; /* 32 bit count variable */
2351 DWORD status
; /* Return value */
2353 char error
[1024]; /* Error message string */
2358 return (SEC_E_WRONG_PRINCIPAL
);
2361 * Convert common name to Unicode.
2364 if (!common_name
|| !*common_name
)
2365 return (SEC_E_WRONG_PRINCIPAL
);
2367 count
= MultiByteToWideChar(CP_ACP
, 0, common_name
, -1, NULL
, 0);
2368 commonNameUnicode
= LocalAlloc(LMEM_FIXED
, count
* sizeof(WCHAR
));
2369 if (!commonNameUnicode
)
2370 return (SEC_E_INSUFFICIENT_MEMORY
);
2372 if (!MultiByteToWideChar(CP_ACP
, 0, common_name
, -1, commonNameUnicode
, count
))
2374 LocalFree(commonNameUnicode
);
2375 return (SEC_E_WRONG_PRINCIPAL
);
2379 * Build certificate chain.
2382 ZeroMemory(&chainPara
, sizeof(chainPara
));
2384 chainPara
.cbSize
= sizeof(chainPara
);
2385 chainPara
.RequestedUsage
.dwType
= USAGE_MATCH_TYPE_OR
;
2386 chainPara
.RequestedUsage
.Usage
.cUsageIdentifier
= cUsages
;
2387 chainPara
.RequestedUsage
.Usage
.rgpszUsageIdentifier
= rgszUsages
;
2389 if (!CertGetCertificateChain(NULL
, cert
, NULL
, cert
->hCertStore
, &chainPara
, 0, NULL
, &chainContext
))
2391 status
= GetLastError();
2393 DEBUG_printf(("CertGetCertificateChain returned: %s", http_sspi_strerror(error
, sizeof(error
), status
)));
2395 LocalFree(commonNameUnicode
);
2400 * Validate certificate chain.
2403 ZeroMemory(&httpsPolicy
, sizeof(HTTPSPolicyCallbackData
));
2404 httpsPolicy
.cbStruct
= sizeof(HTTPSPolicyCallbackData
);
2405 httpsPolicy
.dwAuthType
= AUTHTYPE_SERVER
;
2406 httpsPolicy
.fdwChecks
= dwCertFlags
;
2407 httpsPolicy
.pwszServerName
= commonNameUnicode
;
2409 memset(&policyPara
, 0, sizeof(policyPara
));
2410 policyPara
.cbSize
= sizeof(policyPara
);
2411 policyPara
.pvExtraPolicyPara
= &httpsPolicy
;
2413 memset(&policyStatus
, 0, sizeof(policyStatus
));
2414 policyStatus
.cbSize
= sizeof(policyStatus
);
2416 if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL
, chainContext
, &policyPara
, &policyStatus
))
2418 status
= GetLastError();
2420 DEBUG_printf(("CertVerifyCertificateChainPolicy returned %s", http_sspi_strerror(error
, sizeof(error
), status
)));
2422 else if (policyStatus
.dwError
)
2423 status
= policyStatus
.dwError
;
2428 CertFreeCertificateChain(chainContext
);
2430 if (commonNameUnicode
)
2431 LocalFree(commonNameUnicode
);