4 * TLS support for CUPS on Windows using SSPI.
6 * Copyright 2010-2014 by Apple Inc.
8 * These coded instructions, statements, and computer programs are the
9 * property of Apple Inc. and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
11 * which should have been included with this file. If this file is
12 * file is missing or damaged, see the license at "http://www.cups.org/".
14 * This file is subject to the Apple OS-Developed Software exception.
17 /**** This file is included from tls.c ****/
20 * Include necessary headers...
23 #include "debug-private.h"
27 * Include necessary libraries...
30 #pragma comment(lib, "Crypt32.lib")
31 #pragma comment(lib, "Secur32.lib")
32 #pragma comment(lib, "Ws2_32.lib")
39 #ifndef SECURITY_FLAG_IGNORE_UNKNOWN_CA
40 # define SECURITY_FLAG_IGNORE_UNKNOWN_CA 0x00000100 /* Untrusted root */
41 #endif /* SECURITY_FLAG_IGNORE_UNKNOWN_CA */
43 #ifndef SECURITY_FLAG_IGNORE_CERT_CN_INVALID
44 # define SECURITY_FLAG_IGNORE_CERT_CN_INVALID 0x00001000 /* Common name does not match */
45 #endif /* !SECURITY_FLAG_IGNORE_CERT_CN_INVALID */
47 #ifndef SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
48 # define SECURITY_FLAG_IGNORE_CERT_DATE_INVALID 0x00002000 /* Expired X509 Cert. */
49 #endif /* !SECURITY_FLAG_IGNORE_CERT_DATE_INVALID */
55 static _http_sspi_t
*http_sspi_alloc(void);
56 static int http_sspi_client(http_t
*http
, const char *hostname
);
57 static PCCERT_CONTEXT
http_sspi_create_credential(http_credential_t
*cred
);
58 static BOOL
http_sspi_find_credentials(http_t
*http
, const LPWSTR containerName
, const char *common_name
);
59 static void http_sspi_free(_http_sspi_t
*sspi
);
60 static BOOL
http_sspi_make_credentials(_http_sspi_t
*sspi
, const LPWSTR containerName
, const char *common_name
, _http_mode_t mode
, int years
);
61 static int http_sspi_server(http_t
*http
, const char *hostname
);
62 static void http_sspi_set_allows_any_root(_http_sspi_t
*sspi
, BOOL allow
);
63 static void http_sspi_set_allows_expired_certs(_http_sspi_t
*sspi
, BOOL allow
);
64 static const char *http_sspi_strerror(char *buffer
, size_t bufsize
, DWORD code
);
65 static DWORD
http_sspi_verify(PCCERT_CONTEXT cert
, const char *common_name
, DWORD dwCertFlags
);
69 * 'cupsMakeServerCredentials()' - Make a self-signed certificate and private key pair.
71 * @since CUPS 2.0/OS 10.10@
74 int /* O - 1 on success, 0 on failure */
75 cupsMakeServerCredentials(
76 const char *path
, /* I - Keychain path or @code NULL@ for default */
77 const char *common_name
, /* I - Common name */
78 int num_alt_names
, /* I - Number of subject alternate names */
79 const char **alt_names
, /* I - Subject Alternate Names */
80 time_t expiration_date
) /* I - Expiration date */
82 _http_sspi_t
*sspi
; /* SSPI data */
83 int ret
; /* Return value */
86 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
));
92 sspi
= http_sspi_alloc();
93 ret
= http_sspi_make_credentials(sspi
, L
"ServerContainer", common_name
, _HTTP_MODE_SERVER
, (int)((expiration_date
- time(NULL
) + 86399) / 86400 / 365));
102 * 'cupsSetServerCredentials()' - Set the default server credentials.
104 * Note: The server credentials are used by all threads in the running process.
105 * This function is threadsafe.
107 * @since CUPS 2.0/OS 10.10@
110 int /* O - 1 on success, 0 on failure */
111 cupsSetServerCredentials(
112 const char *path
, /* I - Keychain path or @code NULL@ for default */
113 const char *common_name
, /* I - Default common name for server */
114 int auto_create
) /* I - 1 = automatically create self-signed certificates */
116 DEBUG_printf(("cupsSetServerCredentials(path=\"%s\", common_name=\"%s\", auto_create=%d)", path
, common_name
, auto_create
));
127 * 'httpCopyCredentials()' - Copy the credentials associated with the peer in
128 * an encrypted connection.
130 * @since CUPS 1.5/OS X 10.7@
133 int /* O - Status of call (0 = success) */
135 http_t
*http
, /* I - Connection to server */
136 cups_array_t
**credentials
) /* O - Array of credentials */
138 DEBUG_printf(("httpCopyCredentials(http=%p, credentials=%p)", http
, credentials
));
140 if (!http
|| !http
->tls
|| !http
->tls
->remoteCert
|| !credentials
)
148 *credentials
= cupsArrayNew(NULL
, NULL
);
149 httpAddCredential(*credentials
, http
->tls
->remoteCert
->pbCertEncoded
, http
->tls
->remoteCert
->cbCertEncoded
);
156 * '_httpCreateCredentials()' - Create credentials in the internal format.
159 http_tls_credentials_t
/* O - Internal credentials */
160 _httpCreateCredentials(
161 cups_array_t
*credentials
) /* I - Array of credentials */
163 return (http_sspi_create_credential((http_credential_t
*)cupsArrayFirst(credentials
)));
168 * 'httpCredentialsAreValidForName()' - Return whether the credentials are valid for the given name.
170 * @since CUPS 2.0/OS 10.10@
173 int /* O - 1 if valid, 0 otherwise */
174 httpCredentialsAreValidForName(
175 cups_array_t
*credentials
, /* I - Credentials */
176 const char *common_name
) /* I - Name to check */
178 int valid
= 1; /* Valid name? */
179 PCCERT_CONTEXT cert
= http_sspi_create_credential((http_credential_t
*)cupsArrayFirst(credentials
));
181 char cert_name
[1024]; /* Name from certificate */
186 if (CertNameToStr(X509_ASN_ENCODING
, &(cert
->pCertInfo
->Subject
), CERT_SIMPLE_NAME_STR
, cert_name
, sizeof(cert_name
)))
189 * Extract common name at end...
192 char *ptr
= strrchr(cert_name
, ',');
194 _cups_strcpy(cert_name
, ptr
+ 2);
197 strlcpy(cert_name
, "unknown", sizeof(cert_name
));
199 CertFreeCertificateContext(cert
);
202 strlcpy(cert_name
, "unknown", sizeof(cert_name
));
205 * Compare the common names...
208 if (_cups_strcasecmp(common_name
, cert_name
))
211 * Not an exact match for the common name, check for wildcard certs...
214 const char *domain
= strchr(common_name
, '.');
215 /* Domain in common name */
217 if (strncmp(cert_name
, "*.", 2) || !domain
|| _cups_strcasecmp(domain
, cert_name
+ 1))
220 * Not a wildcard match.
223 /* TODO: Check subject alternate names */
233 * 'httpCredentialsGetTrust()' - Return the trust of credentials.
235 * @since CUPS 2.0/OS 10.10@
238 http_trust_t
/* O - Level of trust */
239 httpCredentialsGetTrust(
240 cups_array_t
*credentials
, /* I - Credentials */
241 const char *common_name
) /* I - Common name for trust lookup */
243 http_trust_t trust
= HTTP_TRUST_OK
; /* Level of trust */
244 PCCERT_CONTEXT cert
= NULL
; /* Certificate to validate */
245 DWORD certFlags
= 0; /* Cert verification flags */
246 _cups_globals_t
*cg
= _cupsGlobals(); /* Per-thread global data */
250 return (HTTP_TRUST_UNKNOWN
);
252 cert
= http_sspi_create_credential((http_credential_t
*)cupsArrayFirst(credentials
));
254 return (HTTP_TRUST_UNKNOWN
);
257 certFlags
|= SECURITY_FLAG_IGNORE_UNKNOWN_CA
;
259 if (cg
->expired_certs
)
260 certFlags
|= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
;
262 if (!cg
->validate_certs
)
263 certFlags
|= SECURITY_FLAG_IGNORE_CERT_CN_INVALID
;
265 if (http_sspi_verify(cert
, common_name
, certFlags
) != SEC_E_OK
)
266 trust
= HTTP_TRUST_INVALID
;
268 CertFreeCertificateContext(cert
);
275 * 'httpCredentialsGetExpiration()' - Return the expiration date of the credentials.
277 * @since CUPS 2.0/OS 10.10@
280 time_t /* O - Expiration date of credentials */
281 httpCredentialsGetExpiration(
282 cups_array_t
*credentials
) /* I - Credentials */
284 time_t expiration_date
= 0; /* Expiration data of credentials */
285 PCCERT_CONTEXT cert
= http_sspi_create_credential((http_credential_t
*)cupsArrayFirst(credentials
));
290 SYSTEMTIME systime
; /* System time */
291 struct tm tm
; /* UNIX date/time */
293 FileTimeToSystemTime(&(cert
->pCertInfo
->NotAfter
), &systime
);
295 tm
.tm_year
= systime
.wYear
- 1900;
296 tm
.tm_mon
= systime
.wMonth
- 1;
297 tm
.tm_mday
= systime
.wDay
;
298 tm
.tm_hour
= systime
.wHour
;
299 tm
.tm_min
= systime
.wMinute
;
300 tm
.tm_sec
= systime
.wSecond
;
302 expiration_date
= mktime(&tm
);
304 CertFreeCertificateContext(cert
);
307 return (expiration_date
);
312 * 'httpCredentialsString()' - Return a string representing the credentials.
314 * @since CUPS 2.0/OS 10.10@
317 size_t /* O - Total size of credentials string */
318 httpCredentialsString(
319 cups_array_t
*credentials
, /* I - Credentials */
320 char *buffer
, /* I - Buffer or @code NULL@ */
321 size_t bufsize
) /* I - Size of buffer */
323 http_credential_t
*first
= (http_credential_t
*)cupsArrayFirst(credentials
);
324 /* First certificate */
325 PCCERT_CONTEXT cert
; /* Certificate */
328 DEBUG_printf(("httpCredentialsString(credentials=%p, buffer=%p, bufsize=" CUPS_LLFMT
")", credentials
, buffer
, CUPS_LLCAST bufsize
));
333 if (buffer
&& bufsize
> 0)
336 cert
= http_sspi_create_credential(first
);
340 char cert_name
[256]; /* Common name */
341 SYSTEMTIME systime
; /* System time */
342 struct tm tm
; /* UNIX date/time */
343 time_t expiration
; /* Expiration date of cert */
344 _cups_md5_state_t md5_state
; /* MD5 state */
345 unsigned char md5_digest
[16]; /* MD5 result */
347 FileTimeToSystemTime(&(cert
->pCertInfo
->NotAfter
), &systime
);
349 tm
.tm_year
= systime
.wYear
- 1900;
350 tm
.tm_mon
= systime
.wMonth
- 1;
351 tm
.tm_mday
= systime
.wDay
;
352 tm
.tm_hour
= systime
.wHour
;
353 tm
.tm_min
= systime
.wMinute
;
354 tm
.tm_sec
= systime
.wSecond
;
356 expiration
= mktime(&tm
);
358 if (CertNameToStr(X509_ASN_ENCODING
, &(cert
->pCertInfo
->Subject
), CERT_SIMPLE_NAME_STR
, cert_name
, sizeof(cert_name
)))
361 * Extract common name at end...
364 char *ptr
= strrchr(cert_name
, ',');
366 _cups_strcpy(cert_name
, ptr
+ 2);
369 strlcpy(cert_name
, "unknown", sizeof(cert_name
));
371 _cupsMD5Init(&md5_state
);
372 _cupsMD5Append(&md5_state
, first
->data
, (int)first
->datalen
);
373 _cupsMD5Finish(&md5_state
, md5_digest
);
375 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]);
377 CertFreeCertificateContext(cert
);
380 DEBUG_printf(("1httpCredentialsString: Returning \"%s\".", buffer
));
382 return (strlen(buffer
));
387 * '_httpFreeCredentials()' - Free internal credentials.
391 _httpFreeCredentials(
392 http_tls_credentials_t credentials
) /* I - Internal credentials */
397 CertFreeCertificateContext(credentials
);
402 * 'httpLoadCredentials()' - Load X.509 credentials from a keychain file.
404 * @since CUPS 2.0/OS 10.10@
407 int /* O - 0 on success, -1 on error */
409 const char *path
, /* I - Keychain path or @code NULL@ for default */
410 cups_array_t
**credentials
, /* IO - Credentials */
411 const char *common_name
) /* I - Common name for credentials */
413 HCERTSTORE store
= NULL
; /* Certificate store */
414 PCCERT_CONTEXT storedContext
= NULL
; /* Context created from the store */
415 DWORD dwSize
= 0; /* 32 bit size */
416 PBYTE p
= NULL
; /* Temporary storage */
417 HCRYPTPROV hProv
= (HCRYPTPROV
)NULL
;
418 /* Handle to a CSP */
419 CERT_NAME_BLOB sib
; /* Arbitrary array of bytes */
421 char error
[1024]; /* Error message buffer */
425 DEBUG_printf(("httpLoadCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path
, credentials
, common_name
));
435 DEBUG_puts("1httpLoadCredentials: NULL credentials pointer, returning -1.");
441 DEBUG_puts("1httpLoadCredentials: Bad common name, returning -1.");
445 if (!CryptAcquireContextW(&hProv
, L
"RememberedContainer", MS_DEF_PROV_W
, PROV_RSA_FULL
, CRYPT_NEWKEYSET
| CRYPT_MACHINE_KEYSET
))
447 if (GetLastError() == NTE_EXISTS
)
449 if (!CryptAcquireContextW(&hProv
, L
"RememberedContainer", MS_DEF_PROV_W
, PROV_RSA_FULL
, CRYPT_MACHINE_KEYSET
))
451 DEBUG_printf(("1httpLoadCredentials: CryptAcquireContext failed: %s", http_sspi_strerror(error
, sizeof(error
), GetLastError())));
457 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 DEBUG_printf(("1httpLoadCredentials: CertOpenSystemStore failed: %s", http_sspi_strerror(error
, sizeof(error
), GetLastError())));
467 if (!CertStrToName(X509_ASN_ENCODING
, common_name
, CERT_OID_NAME_STR
, NULL
, NULL
, &dwSize
, NULL
))
469 DEBUG_printf(("1httpLoadCredentials: CertStrToName failed: %s", http_sspi_strerror(error
, sizeof(error
), GetLastError())));
473 p
= (PBYTE
)malloc(dwSize
);
477 DEBUG_printf(("1httpLoadCredentials: malloc failed for %d bytes.", dwSize
));
481 if (!CertStrToName(X509_ASN_ENCODING
, common_name
, CERT_OID_NAME_STR
, NULL
, p
, &dwSize
, NULL
))
483 DEBUG_printf(("1httpLoadCredentials: CertStrToName failed: %s", http_sspi_strerror(error
, sizeof(error
), GetLastError())));
490 storedContext
= CertFindCertificateInStore(store
, X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
, 0, CERT_FIND_SUBJECT_NAME
, &sib
, NULL
);
494 DEBUG_printf(("1httpLoadCredentials: Unable to find credentials for \"%s\".", common_name
));
498 *credentials
= cupsArrayNew(NULL
, NULL
);
499 httpAddCredential(*credentials
, storedContext
->pbCertEncoded
, storedContext
->cbCertEncoded
);
508 CertFreeCertificateContext(storedContext
);
514 CertCloseStore(store
, 0);
517 CryptReleaseContext(hProv
, 0);
519 DEBUG_printf(("1httpLoadCredentials: Returning %d.", *credentials
? 0 : -1));
521 return (*credentials
? 0 : -1);
526 * 'httpSaveCredentials()' - Save X.509 credentials to a keychain file.
528 * @since CUPS 2.0/OS 10.10@
531 int /* O - -1 on error, 0 on success */
533 const char *path
, /* I - Keychain path or @code NULL@ for default */
534 cups_array_t
*credentials
, /* I - Credentials */
535 const char *common_name
) /* I - Common name for credentials */
537 HCERTSTORE store
= NULL
; /* Certificate store */
538 PCCERT_CONTEXT storedContext
= NULL
; /* Context created from the store */
539 PCCERT_CONTEXT createdContext
= NULL
; /* Context created by us */
540 DWORD dwSize
= 0; /* 32 bit size */
541 PBYTE p
= NULL
; /* Temporary storage */
542 HCRYPTPROV hProv
= (HCRYPTPROV
)NULL
;
543 /* Handle to a CSP */
544 CRYPT_KEY_PROV_INFO ckp
; /* Handle to crypto key */
545 int ret
= -1; /* Return value */
547 char error
[1024]; /* Error message buffer */
551 DEBUG_printf(("httpSaveCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path
, credentials
, common_name
));
557 DEBUG_puts("1httpSaveCredentials: Bad common name, returning -1.");
561 createdContext
= http_sspi_create_credential((http_credential_t
*)cupsArrayFirst(credentials
));
564 DEBUG_puts("1httpSaveCredentials: Bad credentials, returning -1.");
568 if (!CryptAcquireContextW(&hProv
, L
"RememberedContainer", MS_DEF_PROV_W
, PROV_RSA_FULL
, CRYPT_NEWKEYSET
| CRYPT_MACHINE_KEYSET
))
570 if (GetLastError() == NTE_EXISTS
)
572 if (!CryptAcquireContextW(&hProv
, L
"RememberedContainer", MS_DEF_PROV_W
, PROV_RSA_FULL
, CRYPT_MACHINE_KEYSET
))
574 DEBUG_printf(("1httpSaveCredentials: CryptAcquireContext failed: %s", http_sspi_strerror(error
, sizeof(error
), GetLastError())));
580 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 DEBUG_printf(("1httpSaveCredentials: CertOpenSystemStore failed: %s", http_sspi_strerror(error
, sizeof(error
), GetLastError())));
590 if (!CertStrToName(X509_ASN_ENCODING
, common_name
, CERT_OID_NAME_STR
, NULL
, NULL
, &dwSize
, NULL
))
592 DEBUG_printf(("1httpSaveCredentials: CertStrToName failed: %s", http_sspi_strerror(error
, sizeof(error
), GetLastError())));
596 p
= (PBYTE
)malloc(dwSize
);
600 DEBUG_printf(("1httpSaveCredentials: malloc failed for %d bytes.", dwSize
));
604 if (!CertStrToName(X509_ASN_ENCODING
, common_name
, CERT_OID_NAME_STR
, NULL
, p
, &dwSize
, NULL
))
606 DEBUG_printf(("1httpSaveCredentials: CertStrToName failed: %s", http_sspi_strerror(error
, sizeof(error
), GetLastError())));
611 * Add the created context to the named store, and associate it with the named
615 if (!CertAddCertificateContextToStore(store
, createdContext
, CERT_STORE_ADD_REPLACE_EXISTING
, &storedContext
))
617 DEBUG_printf(("1httpSaveCredentials: CertAddCertificateContextToStore failed: %s", http_sspi_strerror(error
, sizeof(error
), GetLastError())));
621 ZeroMemory(&ckp
, sizeof(ckp
));
622 ckp
.pwszContainerName
= L
"RememberedContainer";
623 ckp
.pwszProvName
= MS_DEF_PROV_W
;
624 ckp
.dwProvType
= PROV_RSA_FULL
;
625 ckp
.dwFlags
= CRYPT_MACHINE_KEYSET
;
626 ckp
.dwKeySpec
= AT_KEYEXCHANGE
;
628 if (!CertSetCertificateContextProperty(storedContext
, CERT_KEY_PROV_INFO_PROP_ID
, 0, &ckp
))
630 DEBUG_printf(("1httpSaveCredentials: CertSetCertificateContextProperty failed: %s", http_sspi_strerror(error
, sizeof(error
), GetLastError())));
643 CertFreeCertificateContext(createdContext
);
646 CertFreeCertificateContext(storedContext
);
652 CertCloseStore(store
, 0);
655 CryptReleaseContext(hProv
, 0);
657 DEBUG_printf(("1httpSaveCredentials: Returning %d.", ret
));
663 * '_httpTLSInitialize()' - Initialize the TLS stack.
667 _httpTLSInitialize(void)
676 * '_httpTLSPending()' - Return the number of pending TLS-encrypted bytes.
679 size_t /* O - Bytes available */
680 _httpTLSPending(http_t
*http
) /* I - HTTP connection */
683 return (http
->tls
->readBufferUsed
);
690 * '_httpTLSRead()' - Read from a SSL/TLS connection.
693 int /* O - Bytes read */
694 _httpTLSRead(http_t
*http
, /* I - HTTP connection */
695 char *buf
, /* I - Buffer to store data */
696 int len
) /* I - Length of buffer */
698 int i
; /* Looping var */
699 _http_sspi_t
*sspi
= http
->tls
; /* SSPI data */
700 SecBufferDesc message
; /* Array of SecBuffer struct */
701 SecBuffer buffers
[4] = { 0 }; /* Security package buffer */
702 int num
= 0; /* Return value */
703 PSecBuffer pDataBuffer
; /* Data buffer */
704 PSecBuffer pExtraBuffer
; /* Excess data buffer */
705 SECURITY_STATUS scRet
; /* SSPI status */
708 DEBUG_printf(("4_httpTLSRead(http=%p, buf=%p, len=%d)", http
, buf
, len
));
711 * If there are bytes that have already been decrypted and have not yet been
712 * read, return those...
715 if (sspi
->readBufferUsed
> 0)
717 int bytesToCopy
= min(sspi
->readBufferUsed
, len
);
718 /* Number of bytes to copy */
720 memcpy(buf
, sspi
->readBuffer
, bytesToCopy
);
721 sspi
->readBufferUsed
-= bytesToCopy
;
723 if (sspi
->readBufferUsed
> 0)
724 memmove(sspi
->readBuffer
, sspi
->readBuffer
+ bytesToCopy
, sspi
->readBufferUsed
);
726 DEBUG_printf(("5_httpTLSRead: Returning %d bytes previously decrypted.", bytesToCopy
));
728 return (bytesToCopy
);
732 * Initialize security buffer structs
735 message
.ulVersion
= SECBUFFER_VERSION
;
736 message
.cBuffers
= 4;
737 message
.pBuffers
= buffers
;
742 * If there is not enough space in the buffer, then increase its size...
745 if (sspi
->decryptBufferLength
<= sspi
->decryptBufferUsed
)
747 BYTE
*temp
; /* New buffer */
749 if (sspi
->decryptBufferLength
>= 262144)
751 WSASetLastError(E_OUTOFMEMORY
);
752 DEBUG_puts("_httpTLSRead: Decryption buffer too large (>256k)");
756 if ((temp
= realloc(sspi
->decryptBuffer
, sspi
->decryptBufferLength
+ 4096)) == NULL
)
758 DEBUG_printf(("_httpTLSRead: Unable to allocate %d byte decryption buffer.", sspi
->decryptBufferLength
+ 4096));
759 WSASetLastError(E_OUTOFMEMORY
);
763 sspi
->decryptBufferLength
+= 4096;
764 sspi
->decryptBuffer
= temp
;
766 DEBUG_printf(("_httpTLSRead: Resized decryption buffer to %d bytes.", sspi
->decryptBufferLength
));
769 buffers
[0].pvBuffer
= sspi
->decryptBuffer
;
770 buffers
[0].cbBuffer
= (unsigned long)sspi
->decryptBufferUsed
;
771 buffers
[0].BufferType
= SECBUFFER_DATA
;
772 buffers
[1].BufferType
= SECBUFFER_EMPTY
;
773 buffers
[2].BufferType
= SECBUFFER_EMPTY
;
774 buffers
[3].BufferType
= SECBUFFER_EMPTY
;
776 DEBUG_printf(("5_httpTLSRead: decryptBufferUsed=%d", sspi
->decryptBufferUsed
));
778 scRet
= DecryptMessage(&sspi
->context
, &message
, 0, NULL
);
780 if (scRet
== SEC_E_INCOMPLETE_MESSAGE
)
782 num
= recv(http
->fd
, sspi
->decryptBuffer
+ sspi
->decryptBufferUsed
, (int)(sspi
->decryptBufferLength
- sspi
->decryptBufferUsed
), 0);
785 DEBUG_printf(("5_httpTLSRead: recv failed: %d", WSAGetLastError()));
790 DEBUG_puts("5_httpTLSRead: Server disconnected.");
794 DEBUG_printf(("5_httpTLSRead: Read %d bytes into decryption buffer.", num
));
796 sspi
->decryptBufferUsed
+= num
;
799 while (scRet
== SEC_E_INCOMPLETE_MESSAGE
);
801 if (scRet
== SEC_I_CONTEXT_EXPIRED
)
803 DEBUG_puts("5_httpTLSRead: Context expired.");
804 WSASetLastError(WSAECONNRESET
);
807 else if (scRet
!= SEC_E_OK
)
809 DEBUG_printf(("5_httpTLSRead: DecryptMessage failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), scRet
)));
810 WSASetLastError(WSASYSCALLFAILURE
);
815 * The decryption worked. Now, locate data buffer.
821 for (i
= 1; i
< 4; i
++)
823 if (buffers
[i
].BufferType
== SECBUFFER_DATA
)
824 pDataBuffer
= &buffers
[i
];
825 else if (!pExtraBuffer
&& (buffers
[i
].BufferType
== SECBUFFER_EXTRA
))
826 pExtraBuffer
= &buffers
[i
];
830 * If a data buffer is found, then copy the decrypted bytes to the passed-in
836 int bytesToCopy
= min((int)pDataBuffer
->cbBuffer
, len
);
837 /* Number of bytes to copy into buf */
838 int bytesToSave
= pDataBuffer
->cbBuffer
- bytesToCopy
;
839 /* Number of bytes to save in our read buffer */
842 memcpy(buf
, pDataBuffer
->pvBuffer
, bytesToCopy
);
845 * If there are more decrypted bytes than can be copied to the passed in
846 * buffer, then save them...
851 if ((sspi
->readBufferLength
- sspi
->readBufferUsed
) < bytesToSave
)
853 BYTE
*temp
; /* New buffer pointer */
855 if ((temp
= realloc(sspi
->readBuffer
, sspi
->readBufferUsed
+ bytesToSave
)) == NULL
)
857 DEBUG_printf(("_httpTLSRead: Unable to allocate %d bytes.", sspi
->readBufferUsed
+ bytesToSave
));
858 WSASetLastError(E_OUTOFMEMORY
);
862 sspi
->readBufferLength
= sspi
->readBufferUsed
+ bytesToSave
;
863 sspi
->readBuffer
= temp
;
866 memcpy(((BYTE
*)sspi
->readBuffer
) + sspi
->readBufferUsed
, ((BYTE
*)pDataBuffer
->pvBuffer
) + bytesToCopy
, bytesToSave
);
868 sspi
->readBufferUsed
+= bytesToSave
;
875 DEBUG_puts("_httpTLSRead: Unable to find data buffer.");
876 WSASetLastError(WSASYSCALLFAILURE
);
881 * If the decryption process left extra bytes, then save those back in
882 * decryptBuffer. They will be processed the next time through the loop.
887 memmove(sspi
->decryptBuffer
, pExtraBuffer
->pvBuffer
, pExtraBuffer
->cbBuffer
);
888 sspi
->decryptBufferUsed
= pExtraBuffer
->cbBuffer
;
892 sspi
->decryptBufferUsed
= 0;
900 * '_httpTLSStart()' - Set up SSL/TLS support on a connection.
903 int /* O - 0 on success, -1 on failure */
904 _httpTLSStart(http_t
*http
) /* I - HTTP connection */
906 char hostname
[256], /* Hostname */
907 *hostptr
; /* Pointer into hostname */
910 DEBUG_printf(("7_httpTLSStart(http=%p)", http
));
912 if ((http
->tls
= http_sspi_alloc()) == NULL
)
915 if (http
->mode
== _HTTP_MODE_CLIENT
)
918 * Client: determine hostname...
921 if (httpAddrLocalhost(http
->hostaddr
))
923 strlcpy(hostname
, "localhost", sizeof(hostname
));
928 * Otherwise make sure the hostname we have does not end in a trailing dot.
931 strlcpy(hostname
, http
->hostname
, sizeof(hostname
));
932 if ((hostptr
= hostname
+ strlen(hostname
) - 1) >= hostname
&&
937 return (http_sspi_client(http
, hostname
));
942 * Server: determine hostname to use...
945 if (http
->fields
[HTTP_FIELD_HOST
][0])
948 * Use hostname for TLS upgrade...
951 strlcpy(hostname
, http
->fields
[HTTP_FIELD_HOST
], sizeof(hostname
));
956 * Resolve hostname from connection address...
959 http_addr_t addr
; /* Connection address */
960 socklen_t addrlen
; /* Length of address */
962 addrlen
= sizeof(addr
);
963 if (getsockname(http
->fd
, (struct sockaddr
*)&addr
, &addrlen
))
965 DEBUG_printf(("4_httpTLSStart: Unable to get socket address: %s", strerror(errno
)));
968 else if (httpAddrLocalhost(&addr
))
972 httpAddrLookup(&addr
, hostname
, sizeof(hostname
));
973 DEBUG_printf(("4_httpTLSStart: Resolved socket address to \"%s\".", hostname
));
977 return (http_sspi_server(http
, hostname
));
983 * '_httpTLSStop()' - Shut down SSL/TLS on a connection.
987 _httpTLSStop(http_t
*http
) /* I - HTTP connection */
989 _http_sspi_t
*sspi
= http
->tls
; /* SSPI data */
992 if (sspi
->contextInitialized
&& http
->fd
>= 0)
994 SecBufferDesc message
; /* Array of SecBuffer struct */
995 SecBuffer buffers
[1] = { 0 };
996 /* Security package buffer */
997 DWORD dwType
; /* Type */
998 DWORD status
; /* Status */
1001 * Notify schannel that we are about to close the connection.
1004 dwType
= SCHANNEL_SHUTDOWN
;
1006 buffers
[0].pvBuffer
= &dwType
;
1007 buffers
[0].BufferType
= SECBUFFER_TOKEN
;
1008 buffers
[0].cbBuffer
= sizeof(dwType
);
1010 message
.cBuffers
= 1;
1011 message
.pBuffers
= buffers
;
1012 message
.ulVersion
= SECBUFFER_VERSION
;
1014 status
= ApplyControlToken(&sspi
->context
, &message
);
1016 if (SUCCEEDED(status
))
1018 PBYTE pbMessage
; /* Message buffer */
1019 DWORD cbMessage
; /* Message buffer count */
1020 DWORD cbData
; /* Data count */
1021 DWORD dwSSPIFlags
; /* SSL attributes we requested */
1022 DWORD dwSSPIOutFlags
; /* SSL attributes we received */
1023 TimeStamp tsExpiry
; /* Time stamp */
1025 dwSSPIFlags
= ASC_REQ_SEQUENCE_DETECT
|
1026 ASC_REQ_REPLAY_DETECT
|
1027 ASC_REQ_CONFIDENTIALITY
|
1028 ASC_REQ_EXTENDED_ERROR
|
1029 ASC_REQ_ALLOCATE_MEMORY
|
1032 buffers
[0].pvBuffer
= NULL
;
1033 buffers
[0].BufferType
= SECBUFFER_TOKEN
;
1034 buffers
[0].cbBuffer
= 0;
1036 message
.cBuffers
= 1;
1037 message
.pBuffers
= buffers
;
1038 message
.ulVersion
= SECBUFFER_VERSION
;
1040 status
= AcceptSecurityContext(&sspi
->creds
, &sspi
->context
, NULL
,
1041 dwSSPIFlags
, SECURITY_NATIVE_DREP
, NULL
,
1042 &message
, &dwSSPIOutFlags
, &tsExpiry
);
1044 if (SUCCEEDED(status
))
1046 pbMessage
= buffers
[0].pvBuffer
;
1047 cbMessage
= buffers
[0].cbBuffer
;
1050 * Send the close notify message to the client.
1053 if (pbMessage
&& cbMessage
)
1055 cbData
= send(http
->fd
, pbMessage
, cbMessage
, 0);
1056 if ((cbData
== SOCKET_ERROR
) || (cbData
== 0))
1058 status
= WSAGetLastError();
1059 DEBUG_printf(("_httpTLSStop: sending close notify failed: %d", status
));
1063 FreeContextBuffer(pbMessage
);
1069 DEBUG_printf(("_httpTLSStop: AcceptSecurityContext failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), status
)));
1074 DEBUG_printf(("_httpTLSStop: ApplyControlToken failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), status
)));
1078 http_sspi_free(sspi
);
1085 * '_httpTLSWrite()' - Write to a SSL/TLS connection.
1088 int /* O - Bytes written */
1089 _httpTLSWrite(http_t
*http
, /* I - HTTP connection */
1090 const char *buf
, /* I - Buffer holding data */
1091 int len
) /* I - Length of buffer */
1093 _http_sspi_t
*sspi
= http
->tls
; /* SSPI data */
1094 SecBufferDesc message
; /* Array of SecBuffer struct */
1095 SecBuffer buffers
[4] = { 0 }; /* Security package buffer */
1096 int bufferLen
; /* Buffer length */
1097 int bytesLeft
; /* Bytes left to write */
1098 const char *bufptr
; /* Pointer into buffer */
1099 int num
= 0; /* Return value */
1102 bufferLen
= sspi
->streamSizes
.cbMaximumMessage
+ sspi
->streamSizes
.cbHeader
+ sspi
->streamSizes
.cbTrailer
;
1104 if (bufferLen
> sspi
->writeBufferLength
)
1106 BYTE
*temp
; /* New buffer pointer */
1108 if ((temp
= (BYTE
*)realloc(sspi
->writeBuffer
, bufferLen
)) == NULL
)
1110 DEBUG_printf(("_httpTLSWrite: Unable to allocate buffer of %d bytes.", bufferLen
));
1111 WSASetLastError(E_OUTOFMEMORY
);
1115 sspi
->writeBuffer
= temp
;
1116 sspi
->writeBufferLength
= bufferLen
;
1124 int chunk
= min((int)sspi
->streamSizes
.cbMaximumMessage
, bytesLeft
);
1125 /* Size of data to write */
1126 SECURITY_STATUS scRet
; /* SSPI status */
1129 * Copy user data into the buffer, starting just past the header...
1132 memcpy(sspi
->writeBuffer
+ sspi
->streamSizes
.cbHeader
, bufptr
, chunk
);
1135 * Setup the SSPI buffers
1138 message
.ulVersion
= SECBUFFER_VERSION
;
1139 message
.cBuffers
= 4;
1140 message
.pBuffers
= buffers
;
1142 buffers
[0].pvBuffer
= sspi
->writeBuffer
;
1143 buffers
[0].cbBuffer
= sspi
->streamSizes
.cbHeader
;
1144 buffers
[0].BufferType
= SECBUFFER_STREAM_HEADER
;
1145 buffers
[1].pvBuffer
= sspi
->writeBuffer
+ sspi
->streamSizes
.cbHeader
;
1146 buffers
[1].cbBuffer
= (unsigned long) chunk
;
1147 buffers
[1].BufferType
= SECBUFFER_DATA
;
1148 buffers
[2].pvBuffer
= sspi
->writeBuffer
+ sspi
->streamSizes
.cbHeader
+ chunk
;
1149 buffers
[2].cbBuffer
= sspi
->streamSizes
.cbTrailer
;
1150 buffers
[2].BufferType
= SECBUFFER_STREAM_TRAILER
;
1151 buffers
[3].BufferType
= SECBUFFER_EMPTY
;
1157 scRet
= EncryptMessage(&sspi
->context
, 0, &message
, 0);
1161 DEBUG_printf(("_httpTLSWrite: EncryptMessage failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), scRet
)));
1162 WSASetLastError(WSASYSCALLFAILURE
);
1167 * Send the data. Remember the size of the total data to send is the size
1168 * of the header, the size of the data the caller passed in and the size
1172 num
= send(http
->fd
, sspi
->writeBuffer
, buffers
[0].cbBuffer
+ buffers
[1].cbBuffer
+ buffers
[2].cbBuffer
, 0);
1176 DEBUG_printf(("_httpTLSWrite: send failed: %ld", WSAGetLastError()));
1190 * 'http_setup_ssl()' - Set up SSL/TLS support on a connection.
1193 static int /* O - 0 on success, -1 on failure */
1194 http_setup_ssl(http_t
*http
) /* I - Connection to server */
1196 char hostname
[256], /* Hostname */
1197 *hostptr
; /* Pointer into hostname */
1199 TCHAR username
[256]; /* Username returned from GetUserName() */
1200 TCHAR commonName
[256];/* Common name for certificate */
1201 DWORD dwSize
; /* 32 bit size */
1204 DEBUG_printf(("7http_setup_ssl(http=%p)", http
));
1207 * Get the hostname to use for SSL...
1210 if (httpAddrLocalhost(http
->hostaddr
))
1212 strlcpy(hostname
, "localhost", sizeof(hostname
));
1217 * Otherwise make sure the hostname we have does not end in a trailing dot.
1220 strlcpy(hostname
, http
->hostname
, sizeof(hostname
));
1221 if ((hostptr
= hostname
+ strlen(hostname
) - 1) >= hostname
&&
1226 http
->tls
= http_sspi_alloc();
1230 _cupsSetHTTPError(HTTP_STATUS_ERROR
);
1234 dwSize
= sizeof(username
) / sizeof(TCHAR
);
1235 GetUserName(username
, &dwSize
);
1236 _sntprintf_s(commonName
, sizeof(commonName
) / sizeof(TCHAR
),
1237 sizeof(commonName
) / sizeof(TCHAR
), TEXT("CN=%s"), username
);
1239 if (!_sspiGetCredentials(http
->tls
, L
"ClientContainer",
1242 _sspiFree(http
->tls
);
1246 http
->status
= HTTP_STATUS_ERROR
;
1248 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI
,
1249 _("Unable to establish a secure connection to host."), 1);
1254 _sspiSetAllowsAnyRoot(http
->tls
, TRUE
);
1255 _sspiSetAllowsExpiredCerts(http
->tls
, TRUE
);
1257 if (!_sspiConnect(http
->tls
, hostname
))
1259 _sspiFree(http
->tls
);
1263 http
->status
= HTTP_STATUS_ERROR
;
1265 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI
,
1266 _("Unable to establish a secure connection to host."), 1);
1277 * 'http_sspi_alloc()' - Allocate SSPI object.
1280 static _http_sspi_t
* /* O - New SSPI/SSL object */
1281 http_sspi_alloc(void)
1283 return ((_http_sspi_t
*)calloc(sizeof(_http_sspi_t
), 1));
1288 * 'http_sspi_client()' - Negotiate a TLS connection as a client.
1291 static int /* O - 0 on success, -1 on failure */
1292 http_sspi_client(http_t
*http
, /* I - Client connection */
1293 const char *hostname
) /* I - Server hostname */
1295 _http_sspi_t
*sspi
= http
->tls
; /* SSPI data */
1296 DWORD dwSize
; /* Size for buffer */
1297 DWORD dwSSPIFlags
; /* SSL connection attributes we want */
1298 DWORD dwSSPIOutFlags
; /* SSL connection attributes we got */
1299 TimeStamp tsExpiry
; /* Time stamp */
1300 SECURITY_STATUS scRet
; /* Status */
1301 int cbData
; /* Data count */
1302 SecBufferDesc inBuffer
; /* Array of SecBuffer structs */
1303 SecBuffer inBuffers
[2]; /* Security package buffer */
1304 SecBufferDesc outBuffer
; /* Array of SecBuffer structs */
1305 SecBuffer outBuffers
[1]; /* Security package buffer */
1306 int ret
= 0; /* Return value */
1307 char username
[1024], /* Current username */
1308 common_name
[1024]; /* CN=username */
1311 DEBUG_printf(("4http_sspi_client(http=%p, hostname=\"%s\")", http
, hostname
));
1313 dwSSPIFlags
= ISC_REQ_SEQUENCE_DETECT
|
1314 ISC_REQ_REPLAY_DETECT
|
1315 ISC_REQ_CONFIDENTIALITY
|
1316 ISC_RET_EXTENDED_ERROR
|
1317 ISC_REQ_ALLOCATE_MEMORY
|
1321 * Lookup the client certificate...
1324 dwSize
= sizeof(username
);
1325 GetUserName(username
, &dwSize
);
1326 snprintf(common_name
, sizeof(common_name
), "CN=%s", username
);
1328 if (!http_sspi_find_credentials(http
, L
"ClientContainer", common_name
))
1329 if (!http_sspi_make_credentials(http
->tls
, L
"ClientContainer", common_name
, _HTTP_MODE_CLIENT
, 10))
1331 DEBUG_puts("5http_sspi_client: Unable to get client credentials.");
1336 * Initiate a ClientHello message and generate a token.
1339 outBuffers
[0].pvBuffer
= NULL
;
1340 outBuffers
[0].BufferType
= SECBUFFER_TOKEN
;
1341 outBuffers
[0].cbBuffer
= 0;
1343 outBuffer
.cBuffers
= 1;
1344 outBuffer
.pBuffers
= outBuffers
;
1345 outBuffer
.ulVersion
= SECBUFFER_VERSION
;
1347 scRet
= InitializeSecurityContext(&sspi
->creds
, NULL
, TEXT(""), dwSSPIFlags
, 0, SECURITY_NATIVE_DREP
, NULL
, 0, &sspi
->context
, &outBuffer
, &dwSSPIOutFlags
, &tsExpiry
);
1349 if (scRet
!= SEC_I_CONTINUE_NEEDED
)
1351 DEBUG_printf(("5http_sspi_client: InitializeSecurityContext(1) failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), scRet
)));
1356 * Send response to server if there is one.
1359 if (outBuffers
[0].cbBuffer
&& outBuffers
[0].pvBuffer
)
1361 if ((cbData
= send(http
->fd
, outBuffers
[0].pvBuffer
, outBuffers
[0].cbBuffer
, 0)) <= 0)
1363 DEBUG_printf(("5http_sspi_client: send failed: %d", WSAGetLastError()));
1364 FreeContextBuffer(outBuffers
[0].pvBuffer
);
1365 DeleteSecurityContext(&sspi
->context
);
1369 DEBUG_printf(("5http_sspi_client: %d bytes of handshake data sent.", cbData
));
1371 FreeContextBuffer(outBuffers
[0].pvBuffer
);
1372 outBuffers
[0].pvBuffer
= NULL
;
1375 dwSSPIFlags
= ISC_REQ_MANUAL_CRED_VALIDATION
|
1376 ISC_REQ_SEQUENCE_DETECT
|
1377 ISC_REQ_REPLAY_DETECT
|
1378 ISC_REQ_CONFIDENTIALITY
|
1379 ISC_RET_EXTENDED_ERROR
|
1380 ISC_REQ_ALLOCATE_MEMORY
|
1383 sspi
->decryptBufferUsed
= 0;
1386 * Loop until the handshake is finished or an error occurs.
1389 scRet
= SEC_I_CONTINUE_NEEDED
;
1391 while(scRet
== SEC_I_CONTINUE_NEEDED
||
1392 scRet
== SEC_E_INCOMPLETE_MESSAGE
||
1393 scRet
== SEC_I_INCOMPLETE_CREDENTIALS
)
1395 if (sspi
->decryptBufferUsed
== 0 || scRet
== SEC_E_INCOMPLETE_MESSAGE
)
1397 if (sspi
->decryptBufferLength
<= sspi
->decryptBufferUsed
)
1399 BYTE
*temp
; /* New buffer */
1401 if (sspi
->decryptBufferLength
>= 262144)
1403 WSASetLastError(E_OUTOFMEMORY
);
1404 DEBUG_puts("5http_sspi_client: Decryption buffer too large (>256k)");
1408 if ((temp
= realloc(sspi
->decryptBuffer
, sspi
->decryptBufferLength
+ 4096)) == NULL
)
1410 DEBUG_printf(("5http_sspi_client: Unable to allocate %d byte buffer.", sspi
->decryptBufferLength
+ 4096));
1411 WSASetLastError(E_OUTOFMEMORY
);
1415 sspi
->decryptBufferLength
+= 4096;
1416 sspi
->decryptBuffer
= temp
;
1419 cbData
= recv(http
->fd
, sspi
->decryptBuffer
+ sspi
->decryptBufferUsed
, (int)(sspi
->decryptBufferLength
- sspi
->decryptBufferUsed
), 0);
1423 DEBUG_printf(("5http_sspi_client: recv failed: %d", WSAGetLastError()));
1426 else if (cbData
== 0)
1428 DEBUG_printf(("5http_sspi_client: Server unexpectedly disconnected."));
1432 DEBUG_printf(("5http_sspi_client: %d bytes of handshake data received", cbData
));
1434 sspi
->decryptBufferUsed
+= cbData
;
1438 * Set up the input buffers. Buffer 0 is used to pass in data received from
1439 * the server. Schannel will consume some or all of this. Leftover data
1440 * (if any) will be placed in buffer 1 and given a buffer type of
1444 inBuffers
[0].pvBuffer
= sspi
->decryptBuffer
;
1445 inBuffers
[0].cbBuffer
= (unsigned long)sspi
->decryptBufferUsed
;
1446 inBuffers
[0].BufferType
= SECBUFFER_TOKEN
;
1448 inBuffers
[1].pvBuffer
= NULL
;
1449 inBuffers
[1].cbBuffer
= 0;
1450 inBuffers
[1].BufferType
= SECBUFFER_EMPTY
;
1452 inBuffer
.cBuffers
= 2;
1453 inBuffer
.pBuffers
= inBuffers
;
1454 inBuffer
.ulVersion
= SECBUFFER_VERSION
;
1457 * Set up the output buffers. These are initialized to NULL so as to make it
1458 * less likely we'll attempt to free random garbage later.
1461 outBuffers
[0].pvBuffer
= NULL
;
1462 outBuffers
[0].BufferType
= SECBUFFER_TOKEN
;
1463 outBuffers
[0].cbBuffer
= 0;
1465 outBuffer
.cBuffers
= 1;
1466 outBuffer
.pBuffers
= outBuffers
;
1467 outBuffer
.ulVersion
= SECBUFFER_VERSION
;
1470 * Call InitializeSecurityContext.
1473 scRet
= InitializeSecurityContext(&sspi
->creds
, &sspi
->context
, NULL
, dwSSPIFlags
, 0, SECURITY_NATIVE_DREP
, &inBuffer
, 0, NULL
, &outBuffer
, &dwSSPIOutFlags
, &tsExpiry
);
1476 * If InitializeSecurityContext was successful (or if the error was one of
1477 * the special extended ones), send the contents of the output buffer to the
1481 if (scRet
== SEC_E_OK
||
1482 scRet
== SEC_I_CONTINUE_NEEDED
||
1483 FAILED(scRet
) && (dwSSPIOutFlags
& ISC_RET_EXTENDED_ERROR
))
1485 if (outBuffers
[0].cbBuffer
&& outBuffers
[0].pvBuffer
)
1487 cbData
= send(http
->fd
, outBuffers
[0].pvBuffer
, outBuffers
[0].cbBuffer
, 0);
1491 DEBUG_printf(("5http_sspi_client: send failed: %d", WSAGetLastError()));
1492 FreeContextBuffer(outBuffers
[0].pvBuffer
);
1493 DeleteSecurityContext(&sspi
->context
);
1497 DEBUG_printf(("5http_sspi_client: %d bytes of handshake data sent.", cbData
));
1500 * Free output buffer.
1503 FreeContextBuffer(outBuffers
[0].pvBuffer
);
1504 outBuffers
[0].pvBuffer
= NULL
;
1509 * If InitializeSecurityContext returned SEC_E_INCOMPLETE_MESSAGE, then we
1510 * need to read more data from the server and try again.
1513 if (scRet
== SEC_E_INCOMPLETE_MESSAGE
)
1517 * If InitializeSecurityContext returned SEC_E_OK, then the handshake
1518 * completed successfully.
1521 if (scRet
== SEC_E_OK
)
1524 * If the "extra" buffer contains data, this is encrypted application
1525 * protocol layer stuff. It needs to be saved. The application layer will
1526 * later decrypt it with DecryptMessage.
1529 DEBUG_puts("5http_sspi_client: Handshake was successful.");
1531 if (inBuffers
[1].BufferType
== SECBUFFER_EXTRA
)
1533 memmove(sspi
->decryptBuffer
, sspi
->decryptBuffer
+ sspi
->decryptBufferUsed
- inBuffers
[1].cbBuffer
, inBuffers
[1].cbBuffer
);
1535 sspi
->decryptBufferUsed
= inBuffers
[1].cbBuffer
;
1537 DEBUG_printf(("5http_sspi_client: %d bytes of app data was bundled with handshake data", sspi
->decryptBufferUsed
));
1540 sspi
->decryptBufferUsed
= 0;
1550 * Check for fatal error.
1555 DEBUG_printf(("5http_sspi_client: InitializeSecurityContext(2) failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), scRet
)));
1561 * If InitializeSecurityContext returned SEC_I_INCOMPLETE_CREDENTIALS,
1562 * then the server just requested client authentication.
1565 if (scRet
== SEC_I_INCOMPLETE_CREDENTIALS
)
1571 DEBUG_printf(("5http_sspi_client: server requested client credentials."));
1577 * Copy any leftover data from the "extra" buffer, and go around again.
1580 if (inBuffers
[1].BufferType
== SECBUFFER_EXTRA
)
1582 memmove(sspi
->decryptBuffer
, sspi
->decryptBuffer
+ sspi
->decryptBufferUsed
- inBuffers
[1].cbBuffer
, inBuffers
[1].cbBuffer
);
1584 sspi
->decryptBufferUsed
= inBuffers
[1].cbBuffer
;
1588 sspi
->decryptBufferUsed
= 0;
1595 * Success! Get the server cert
1598 sspi
->contextInitialized
= TRUE
;
1600 scRet
= QueryContextAttributes(&sspi
->context
, SECPKG_ATTR_REMOTE_CERT_CONTEXT
, (VOID
*)&(sspi
->remoteCert
));
1602 if (scRet
!= SEC_E_OK
)
1604 DEBUG_printf(("5http_sspi_client: QueryContextAttributes failed(SECPKG_ATTR_REMOTE_CERT_CONTEXT): %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), scRet
)));
1609 * Find out how big the header/trailer will be:
1612 scRet
= QueryContextAttributes(&sspi
->context
, SECPKG_ATTR_STREAM_SIZES
, &sspi
->streamSizes
);
1614 if (scRet
!= SEC_E_OK
)
1616 DEBUG_printf(("5http_sspi_client: QueryContextAttributes failed(SECPKG_ATTR_STREAM_SIZES): %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), scRet
)));
1626 * 'http_sspi_create_credential()' - Create an SSPI certificate context.
1629 static PCCERT_CONTEXT
/* O - Certificate context */
1630 http_sspi_create_credential(
1631 http_credential_t
*cred
) /* I - Credential */
1634 return (CertCreateCertificateContext(X509_ASN_ENCODING
, cred
->data
, cred
->datalen
));
1641 * 'http_sspi_find_credentials()' - Retrieve a TLS certificate from the system store.
1644 static BOOL
/* O - 1 on success, 0 on failure */
1645 http_sspi_find_credentials(
1646 http_t
*http
, /* I - HTTP connection */
1647 const LPWSTR container
, /* I - Cert container name */
1648 const char *common_name
) /* I - Common name of certificate */
1650 _http_sspi_t
*sspi
= http
->tls
; /* SSPI data */
1651 HCERTSTORE store
= NULL
; /* Certificate store */
1652 PCCERT_CONTEXT storedContext
= NULL
; /* Context created from the store */
1653 DWORD dwSize
= 0; /* 32 bit size */
1654 PBYTE p
= NULL
; /* Temporary storage */
1655 HCRYPTPROV hProv
= (HCRYPTPROV
)NULL
;
1656 /* Handle to a CSP */
1657 CERT_NAME_BLOB sib
; /* Arbitrary array of bytes */
1658 SCHANNEL_CRED SchannelCred
; /* Schannel credential data */
1659 TimeStamp tsExpiry
; /* Time stamp */
1660 SECURITY_STATUS Status
; /* Status */
1661 BOOL ok
= TRUE
; /* Return value */
1664 if (!CryptAcquireContextW(&hProv
, (LPWSTR
)container
, MS_DEF_PROV_W
, PROV_RSA_FULL
, CRYPT_NEWKEYSET
| CRYPT_MACHINE_KEYSET
))
1666 if (GetLastError() == NTE_EXISTS
)
1668 if (!CryptAcquireContextW(&hProv
, (LPWSTR
)container
, MS_DEF_PROV_W
, PROV_RSA_FULL
, CRYPT_MACHINE_KEYSET
))
1670 DEBUG_printf(("5http_sspi_find_credentials: CryptAcquireContext failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), GetLastError())));
1677 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");
1681 DEBUG_printf(("5http_sspi_find_credentials: CertOpenSystemStore failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), GetLastError())));
1688 if (!CertStrToName(X509_ASN_ENCODING
, common_name
, CERT_OID_NAME_STR
, NULL
, NULL
, &dwSize
, NULL
))
1690 DEBUG_printf(("5http_sspi_find_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), GetLastError())));
1695 p
= (PBYTE
)malloc(dwSize
);
1699 DEBUG_printf(("5http_sspi_find_credentials: malloc failed for %d bytes.", dwSize
));
1704 if (!CertStrToName(X509_ASN_ENCODING
, common_name
, CERT_OID_NAME_STR
, NULL
, p
, &dwSize
, NULL
))
1706 DEBUG_printf(("5http_sspi_find_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), GetLastError())));
1711 sib
.cbData
= dwSize
;
1714 storedContext
= CertFindCertificateInStore(store
, X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
, 0, CERT_FIND_SUBJECT_NAME
, &sib
, NULL
);
1718 DEBUG_printf(("5http_sspi_find_credentials: Unable to find credentials for \"%s\".", common_name
));
1723 ZeroMemory(&SchannelCred
, sizeof(SchannelCred
));
1725 SchannelCred
.dwVersion
= SCHANNEL_CRED_VERSION
;
1726 SchannelCred
.cCreds
= 1;
1727 SchannelCred
.paCred
= &storedContext
;
1730 * SSPI doesn't seem to like it if grbitEnabledProtocols is set for a client.
1733 if (http
->mode
== _HTTP_MODE_SERVER
)
1734 SchannelCred
.grbitEnabledProtocols
= SP_PROT_SSL3TLS1
;
1737 * Create an SSPI credential.
1740 Status
= AcquireCredentialsHandle(NULL
, UNISP_NAME
, http
->mode
== _HTTP_MODE_SERVER
? SECPKG_CRED_INBOUND
: SECPKG_CRED_OUTBOUND
, NULL
, &SchannelCred
, NULL
, NULL
, &sspi
->creds
, &tsExpiry
);
1741 if (Status
!= SEC_E_OK
)
1743 DEBUG_printf(("5http_sspi_find_credentials: AcquireCredentialsHandle failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), Status
)));
1755 CertFreeCertificateContext(storedContext
);
1761 CertCloseStore(store
, 0);
1764 CryptReleaseContext(hProv
, 0);
1771 * 'http_sspi_free()' - Close a connection and free resources.
1775 http_sspi_free(_http_sspi_t
*sspi
) /* I - SSPI data */
1780 if (sspi
->contextInitialized
)
1781 DeleteSecurityContext(&sspi
->context
);
1783 if (sspi
->decryptBuffer
)
1784 free(sspi
->decryptBuffer
);
1786 if (sspi
->readBuffer
)
1787 free(sspi
->readBuffer
);
1789 if (sspi
->writeBuffer
)
1790 free(sspi
->writeBuffer
);
1792 if (sspi
->localCert
)
1793 CertFreeCertificateContext(sspi
->localCert
);
1795 if (sspi
->remoteCert
)
1796 CertFreeCertificateContext(sspi
->remoteCert
);
1803 * 'http_sspi_make_credentials()' - Create a TLS certificate in the system store.
1806 static BOOL
/* O - 1 on success, 0 on failure */
1807 http_sspi_make_credentials(
1808 _http_sspi_t
*sspi
, /* I - SSPI data */
1809 const LPWSTR container
, /* I - Cert container name */
1810 const char *common_name
, /* I - Common name of certificate */
1811 _http_mode_t mode
, /* I - Client or server? */
1812 int years
) /* I - Years until expiration */
1814 HCERTSTORE store
= NULL
; /* Certificate store */
1815 PCCERT_CONTEXT storedContext
= NULL
; /* Context created from the store */
1816 PCCERT_CONTEXT createdContext
= NULL
; /* Context created by us */
1817 DWORD dwSize
= 0; /* 32 bit size */
1818 PBYTE p
= NULL
; /* Temporary storage */
1819 HCRYPTPROV hProv
= (HCRYPTPROV
)NULL
;
1820 /* Handle to a CSP */
1821 CERT_NAME_BLOB sib
; /* Arbitrary array of bytes */
1822 SCHANNEL_CRED SchannelCred
; /* Schannel credential data */
1823 TimeStamp tsExpiry
; /* Time stamp */
1824 SECURITY_STATUS Status
; /* Status */
1825 HCRYPTKEY hKey
= (HCRYPTKEY
)NULL
; /* Handle to crypto key */
1826 CRYPT_KEY_PROV_INFO kpi
; /* Key container info */
1827 SYSTEMTIME et
; /* System time */
1828 CERT_EXTENSIONS exts
; /* Array of cert extensions */
1829 CRYPT_KEY_PROV_INFO ckp
; /* Handle to crypto key */
1830 BOOL ok
= TRUE
; /* Return value */
1833 DEBUG_printf(("4http_sspi_make_credentials(sspi=%p, container=%p, common_name=\"%s\", mode=%d, years=%d)", sspi
, container
, common_name
, mode
, years
));
1835 if (!CryptAcquireContextW(&hProv
, (LPWSTR
)container
, MS_DEF_PROV_W
, PROV_RSA_FULL
, CRYPT_NEWKEYSET
| CRYPT_MACHINE_KEYSET
))
1837 if (GetLastError() == NTE_EXISTS
)
1839 if (!CryptAcquireContextW(&hProv
, (LPWSTR
)container
, MS_DEF_PROV_W
, PROV_RSA_FULL
, CRYPT_MACHINE_KEYSET
))
1841 DEBUG_printf(("5http_sspi_make_credentials: CryptAcquireContext failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), GetLastError())));
1848 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");
1852 DEBUG_printf(("5http_sspi_make_credentials: CertOpenSystemStore failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), GetLastError())));
1859 if (!CertStrToName(X509_ASN_ENCODING
, common_name
, CERT_OID_NAME_STR
, NULL
, NULL
, &dwSize
, NULL
))
1861 DEBUG_printf(("5http_sspi_make_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), GetLastError())));
1866 p
= (PBYTE
)malloc(dwSize
);
1870 DEBUG_printf(("5http_sspi_make_credentials: malloc failed for %d bytes", dwSize
));
1875 if (!CertStrToName(X509_ASN_ENCODING
, common_name
, CERT_OID_NAME_STR
, NULL
, p
, &dwSize
, NULL
))
1877 DEBUG_printf(("5http_sspi_make_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), GetLastError())));
1883 * Create a private key and self-signed certificate...
1886 if (!CryptGenKey(hProv
, AT_KEYEXCHANGE
, CRYPT_EXPORTABLE
, &hKey
))
1888 DEBUG_printf(("5http_sspi_make_credentials: CryptGenKey failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), GetLastError())));
1893 ZeroMemory(&kpi
, sizeof(kpi
));
1894 kpi
.pwszContainerName
= (LPWSTR
)container
;
1895 kpi
.pwszProvName
= MS_DEF_PROV_W
;
1896 kpi
.dwProvType
= PROV_RSA_FULL
;
1897 kpi
.dwFlags
= CERT_SET_KEY_CONTEXT_PROP_ID
;
1898 kpi
.dwKeySpec
= AT_KEYEXCHANGE
;
1903 ZeroMemory(&exts
, sizeof(exts
));
1905 createdContext
= CertCreateSelfSignCertificate(hProv
, &sib
, 0, &kpi
, NULL
, NULL
, &et
, &exts
);
1907 if (!createdContext
)
1909 DEBUG_printf(("5http_sspi_make_credentials: CertCreateSelfSignCertificate failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), GetLastError())));
1915 * Add the created context to the named store, and associate it with the named
1919 if (!CertAddCertificateContextToStore(store
, createdContext
, CERT_STORE_ADD_REPLACE_EXISTING
, &storedContext
))
1921 DEBUG_printf(("5http_sspi_make_credentials: CertAddCertificateContextToStore failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), GetLastError())));
1926 ZeroMemory(&ckp
, sizeof(ckp
));
1927 ckp
.pwszContainerName
= (LPWSTR
) container
;
1928 ckp
.pwszProvName
= MS_DEF_PROV_W
;
1929 ckp
.dwProvType
= PROV_RSA_FULL
;
1930 ckp
.dwFlags
= CRYPT_MACHINE_KEYSET
;
1931 ckp
.dwKeySpec
= AT_KEYEXCHANGE
;
1933 if (!CertSetCertificateContextProperty(storedContext
, CERT_KEY_PROV_INFO_PROP_ID
, 0, &ckp
))
1935 DEBUG_printf(("5http_sspi_make_credentials: CertSetCertificateContextProperty failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), GetLastError())));
1941 * Get a handle to use the certificate...
1944 ZeroMemory(&SchannelCred
, sizeof(SchannelCred
));
1946 SchannelCred
.dwVersion
= SCHANNEL_CRED_VERSION
;
1947 SchannelCred
.cCreds
= 1;
1948 SchannelCred
.paCred
= &storedContext
;
1951 * SSPI doesn't seem to like it if grbitEnabledProtocols is set for a client.
1954 if (mode
== _HTTP_MODE_SERVER
)
1955 SchannelCred
.grbitEnabledProtocols
= SP_PROT_SSL3TLS1
;
1958 * Create an SSPI credential.
1961 Status
= AcquireCredentialsHandle(NULL
, UNISP_NAME
, mode
== _HTTP_MODE_SERVER
? SECPKG_CRED_INBOUND
: SECPKG_CRED_OUTBOUND
, NULL
, &SchannelCred
, NULL
, NULL
, &sspi
->creds
, &tsExpiry
);
1962 if (Status
!= SEC_E_OK
)
1964 DEBUG_printf(("5http_sspi_make_credentials: AcquireCredentialsHandle failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), Status
)));
1976 CryptDestroyKey(hKey
);
1979 CertFreeCertificateContext(createdContext
);
1982 CertFreeCertificateContext(storedContext
);
1988 CertCloseStore(store
, 0);
1991 CryptReleaseContext(hProv
, 0);
1998 * 'http_sspi_server()' - Negotiate a TLS connection as a server.
2001 static int /* O - 0 on success, -1 on failure */
2002 http_sspi_server(http_t
*http
, /* I - HTTP connection */
2003 const char *hostname
) /* I - Hostname of server */
2005 _http_sspi_t
*sspi
= http
->tls
; /* I - SSPI data */
2006 char common_name
[512]; /* Common name for cert */
2007 DWORD dwSSPIFlags
; /* SSL connection attributes we want */
2008 DWORD dwSSPIOutFlags
; /* SSL connection attributes we got */
2009 TimeStamp tsExpiry
; /* Time stamp */
2010 SECURITY_STATUS scRet
; /* SSPI Status */
2011 SecBufferDesc inBuffer
; /* Array of SecBuffer structs */
2012 SecBuffer inBuffers
[2]; /* Security package buffer */
2013 SecBufferDesc outBuffer
; /* Array of SecBuffer structs */
2014 SecBuffer outBuffers
[1]; /* Security package buffer */
2015 int num
= 0; /* 32 bit status value */
2016 BOOL fInitContext
= TRUE
; /* Has the context been init'd? */
2017 int ret
= 0; /* Return value */
2020 DEBUG_printf(("4http_sspi_server(http=%p, hostname=\"%s\")", http
, hostname
));
2022 dwSSPIFlags
= ASC_REQ_SEQUENCE_DETECT
|
2023 ASC_REQ_REPLAY_DETECT
|
2024 ASC_REQ_CONFIDENTIALITY
|
2025 ASC_REQ_EXTENDED_ERROR
|
2026 ASC_REQ_ALLOCATE_MEMORY
|
2029 sspi
->decryptBufferUsed
= 0;
2032 * Lookup the server certificate...
2035 snprintf(common_name
, sizeof(common_name
), "CN=%s", hostname
);
2037 if (!http_sspi_find_credentials(http
, L
"ServerContainer", common_name
))
2038 if (!http_sspi_make_credentials(http
->tls
, L
"ServerContainer", common_name
, _HTTP_MODE_SERVER
, 10))
2040 DEBUG_puts("5http_sspi_server: Unable to get server credentials.");
2045 * Set OutBuffer for AcceptSecurityContext call
2048 outBuffer
.cBuffers
= 1;
2049 outBuffer
.pBuffers
= outBuffers
;
2050 outBuffer
.ulVersion
= SECBUFFER_VERSION
;
2052 scRet
= SEC_I_CONTINUE_NEEDED
;
2054 while (scRet
== SEC_I_CONTINUE_NEEDED
||
2055 scRet
== SEC_E_INCOMPLETE_MESSAGE
||
2056 scRet
== SEC_I_INCOMPLETE_CREDENTIALS
)
2058 if (sspi
->decryptBufferUsed
== 0 || scRet
== SEC_E_INCOMPLETE_MESSAGE
)
2060 if (sspi
->decryptBufferLength
<= sspi
->decryptBufferUsed
)
2062 BYTE
*temp
; /* New buffer */
2064 if (sspi
->decryptBufferLength
>= 262144)
2066 WSASetLastError(E_OUTOFMEMORY
);
2067 DEBUG_puts("5http_sspi_server: Decryption buffer too large (>256k)");
2071 if ((temp
= realloc(sspi
->decryptBuffer
, sspi
->decryptBufferLength
+ 4096)) == NULL
)
2073 DEBUG_printf(("5http_sspi_server: Unable to allocate %d byte buffer.", sspi
->decryptBufferLength
+ 4096));
2074 WSASetLastError(E_OUTOFMEMORY
);
2078 sspi
->decryptBufferLength
+= 4096;
2079 sspi
->decryptBuffer
= temp
;
2084 num
= recv(http
->fd
, sspi
->decryptBuffer
+ sspi
->decryptBufferUsed
, (int)(sspi
->decryptBufferLength
- sspi
->decryptBufferUsed
), 0);
2086 if (num
== -1 && WSAGetLastError() == WSAEWOULDBLOCK
)
2094 DEBUG_printf(("5http_sspi_server: recv failed: %d", WSAGetLastError()));
2099 DEBUG_puts("5http_sspi_server: client disconnected");
2103 DEBUG_printf(("5http_sspi_server: received %d (handshake) bytes from client.", num
));
2104 sspi
->decryptBufferUsed
+= num
;
2108 * InBuffers[1] is for getting extra data that SSPI/SCHANNEL doesn't process
2109 * on this run around the loop.
2112 inBuffers
[0].pvBuffer
= sspi
->decryptBuffer
;
2113 inBuffers
[0].cbBuffer
= (unsigned long)sspi
->decryptBufferUsed
;
2114 inBuffers
[0].BufferType
= SECBUFFER_TOKEN
;
2116 inBuffers
[1].pvBuffer
= NULL
;
2117 inBuffers
[1].cbBuffer
= 0;
2118 inBuffers
[1].BufferType
= SECBUFFER_EMPTY
;
2120 inBuffer
.cBuffers
= 2;
2121 inBuffer
.pBuffers
= inBuffers
;
2122 inBuffer
.ulVersion
= SECBUFFER_VERSION
;
2125 * Initialize these so if we fail, pvBuffer contains NULL, so we don't try to
2126 * free random garbage at the quit.
2129 outBuffers
[0].pvBuffer
= NULL
;
2130 outBuffers
[0].BufferType
= SECBUFFER_TOKEN
;
2131 outBuffers
[0].cbBuffer
= 0;
2133 scRet
= AcceptSecurityContext(&sspi
->creds
, (fInitContext
?NULL
:&sspi
->context
), &inBuffer
, dwSSPIFlags
, SECURITY_NATIVE_DREP
, (fInitContext
?&sspi
->context
:NULL
), &outBuffer
, &dwSSPIOutFlags
, &tsExpiry
);
2135 fInitContext
= FALSE
;
2137 if (scRet
== SEC_E_OK
||
2138 scRet
== SEC_I_CONTINUE_NEEDED
||
2139 (FAILED(scRet
) && ((dwSSPIOutFlags
& ISC_RET_EXTENDED_ERROR
) != 0)))
2141 if (outBuffers
[0].cbBuffer
&& outBuffers
[0].pvBuffer
)
2144 * Send response to server if there is one.
2147 num
= send(http
->fd
, outBuffers
[0].pvBuffer
, outBuffers
[0].cbBuffer
, 0);
2151 DEBUG_printf(("5http_sspi_server: handshake send failed: %d", WSAGetLastError()));
2155 DEBUG_printf(("5http_sspi_server: sent %d handshake bytes to client.", outBuffers
[0].cbBuffer
));
2157 FreeContextBuffer(outBuffers
[0].pvBuffer
);
2158 outBuffers
[0].pvBuffer
= NULL
;
2162 if (scRet
== SEC_E_OK
)
2165 * If there's extra data then save it for next time we go to decrypt.
2168 if (inBuffers
[1].BufferType
== SECBUFFER_EXTRA
)
2170 memcpy(sspi
->decryptBuffer
, (LPBYTE
)(sspi
->decryptBuffer
+ sspi
->decryptBufferUsed
- inBuffers
[1].cbBuffer
), inBuffers
[1].cbBuffer
);
2171 sspi
->decryptBufferUsed
= inBuffers
[1].cbBuffer
;
2175 sspi
->decryptBufferUsed
= 0;
2179 else if (FAILED(scRet
) && scRet
!= SEC_E_INCOMPLETE_MESSAGE
)
2181 DEBUG_printf(("5http_sspi_server: AcceptSecurityContext failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), scRet
)));
2186 if (scRet
!= SEC_E_INCOMPLETE_MESSAGE
&&
2187 scRet
!= SEC_I_INCOMPLETE_CREDENTIALS
)
2189 if (inBuffers
[1].BufferType
== SECBUFFER_EXTRA
)
2191 memcpy(sspi
->decryptBuffer
, (LPBYTE
)(sspi
->decryptBuffer
+ sspi
->decryptBufferUsed
- inBuffers
[1].cbBuffer
), inBuffers
[1].cbBuffer
);
2192 sspi
->decryptBufferUsed
= inBuffers
[1].cbBuffer
;
2196 sspi
->decryptBufferUsed
= 0;
2203 sspi
->contextInitialized
= TRUE
;
2206 * Find out how big the header will be:
2209 scRet
= QueryContextAttributes(&sspi
->context
, SECPKG_ATTR_STREAM_SIZES
, &sspi
->streamSizes
);
2211 if (scRet
!= SEC_E_OK
)
2213 DEBUG_printf(("5http_sspi_server: QueryContextAttributes failed: %s", http_sspi_strerror(sspi
->error
, sizeof(sspi
->error
), scRet
)));
2223 * 'http_sspi_strerror()' - Return a string for the specified error code.
2226 static const char * /* O - String for error */
2227 http_sspi_strerror(char *buffer
, /* I - Error message buffer */
2228 size_t bufsize
, /* I - Size of buffer */
2229 DWORD code
) /* I - Error code */
2231 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, code
, 0, buffer
, bufsize
, NULL
))
2234 * Strip trailing CR + LF...
2237 char *ptr
; /* Pointer into error message */
2239 for (ptr
= buffer
+ strlen(buffer
) - 1; ptr
>= buffer
; ptr
--)
2240 if (*ptr
== '\n' || *ptr
== '\r')
2246 snprintf(buffer
, bufsize
, "Unknown error %x", code
);
2253 * 'http_sspi_verify()' - Verify a certificate.
2256 static DWORD
/* O - Error code (0 == No error) */
2258 PCCERT_CONTEXT cert
, /* I - Server certificate */
2259 const char *common_name
, /* I - Common name */
2260 DWORD dwCertFlags
) /* I - Verification flags */
2262 HTTPSPolicyCallbackData httpsPolicy
; /* HTTPS Policy Struct */
2263 CERT_CHAIN_POLICY_PARA policyPara
; /* Cert chain policy parameters */
2264 CERT_CHAIN_POLICY_STATUS policyStatus
;/* Cert chain policy status */
2265 CERT_CHAIN_PARA chainPara
; /* Used for searching and matching criteria */
2266 PCCERT_CHAIN_CONTEXT chainContext
= NULL
;
2267 /* Certificate chain */
2268 PWSTR commonNameUnicode
= NULL
;
2269 /* Unicode common name */
2270 LPSTR rgszUsages
[] = { szOID_PKIX_KP_SERVER_AUTH
,
2271 szOID_SERVER_GATED_CRYPTO
,
2272 szOID_SGC_NETSCAPE
};
2273 /* How are we using this certificate? */
2274 DWORD cUsages
= sizeof(rgszUsages
) / sizeof(LPSTR
);
2275 /* Number of ites in rgszUsages */
2276 DWORD count
; /* 32 bit count variable */
2277 DWORD status
; /* Return value */
2279 char error
[1024]; /* Error message string */
2284 return (SEC_E_WRONG_PRINCIPAL
);
2287 * Convert common name to Unicode.
2290 if (!common_name
|| !*common_name
)
2291 return (SEC_E_WRONG_PRINCIPAL
);
2293 count
= MultiByteToWideChar(CP_ACP
, 0, common_name
, -1, NULL
, 0);
2294 commonNameUnicode
= LocalAlloc(LMEM_FIXED
, count
* sizeof(WCHAR
));
2295 if (!commonNameUnicode
)
2296 return (SEC_E_INSUFFICIENT_MEMORY
);
2298 if (!MultiByteToWideChar(CP_ACP
, 0, common_name
, -1, commonNameUnicode
, count
))
2300 LocalFree(commonNameUnicode
);
2301 return (SEC_E_WRONG_PRINCIPAL
);
2305 * Build certificate chain.
2308 ZeroMemory(&chainPara
, sizeof(chainPara
));
2310 chainPara
.cbSize
= sizeof(chainPara
);
2311 chainPara
.RequestedUsage
.dwType
= USAGE_MATCH_TYPE_OR
;
2312 chainPara
.RequestedUsage
.Usage
.cUsageIdentifier
= cUsages
;
2313 chainPara
.RequestedUsage
.Usage
.rgpszUsageIdentifier
= rgszUsages
;
2315 if (!CertGetCertificateChain(NULL
, cert
, NULL
, cert
->hCertStore
, &chainPara
, 0, NULL
, &chainContext
))
2317 status
= GetLastError();
2319 DEBUG_printf(("CertGetCertificateChain returned: %s", http_sspi_strerror(error
, sizeof(error
), status
)));
2321 LocalFree(commonNameUnicode
);
2326 * Validate certificate chain.
2329 ZeroMemory(&httpsPolicy
, sizeof(HTTPSPolicyCallbackData
));
2330 httpsPolicy
.cbStruct
= sizeof(HTTPSPolicyCallbackData
);
2331 httpsPolicy
.dwAuthType
= AUTHTYPE_SERVER
;
2332 httpsPolicy
.fdwChecks
= dwCertFlags
;
2333 httpsPolicy
.pwszServerName
= commonNameUnicode
;
2335 memset(&policyPara
, 0, sizeof(policyPara
));
2336 policyPara
.cbSize
= sizeof(policyPara
);
2337 policyPara
.pvExtraPolicyPara
= &httpsPolicy
;
2339 memset(&policyStatus
, 0, sizeof(policyStatus
));
2340 policyStatus
.cbSize
= sizeof(policyStatus
);
2342 if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL
, chainContext
, &policyPara
, &policyStatus
))
2344 status
= GetLastError();
2346 DEBUG_printf(("CertVerifyCertificateChainPolicy returned %s", http_sspi_strerror(error
, sizeof(error
), status
)));
2348 else if (policyStatus
.dwError
)
2349 status
= policyStatus
.dwError
;
2354 CertFreeCertificateChain(chainContext
);
2356 if (commonNameUnicode
)
2357 LocalFree(commonNameUnicode
);