/*
* "$Id$"
*
- * TLS support for CUPS on Windows using SSPI.
+ * TLS support for CUPS on Windows using the Security Support Provider
+ * Interface (SSPI).
*
* Copyright 2010-2014 by Apple Inc.
*
* This file is subject to the Apple OS-Developed Software exception.
*/
+/**** This file is included from tls.c ****/
+
/*
* Include necessary headers...
*/
# define SECURITY_FLAG_IGNORE_UNKNOWN_CA 0x00000100 /* Untrusted root */
#endif /* SECURITY_FLAG_IGNORE_UNKNOWN_CA */
+#ifndef SECURITY_FLAG_IGNORE_CERT_CN_INVALID
+# define SECURITY_FLAG_IGNORE_CERT_CN_INVALID 0x00001000 /* Common name does not match */
+#endif /* !SECURITY_FLAG_IGNORE_CERT_CN_INVALID */
+
#ifndef SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
# define SECURITY_FLAG_IGNORE_CERT_DATE_INVALID 0x00002000 /* Expired X509 Cert. */
#endif /* !SECURITY_FLAG_IGNORE_CERT_DATE_INVALID */
+
+/*
+ * Local globals...
+ */
+
+static int tls_options = 0;/* Options for TLS connections */
+
+
/*
* Local functions...
*/
static _http_sspi_t *http_sspi_alloc(void);
static int http_sspi_client(http_t *http, const char *hostname);
-static void http_sspi_free(_http_sspi_t *conn);
-static BOOL http_sspi_get_credentials(_http_sspi_t *conn, const LPWSTR containerName, const TCHAR *commonName, BOOL server);
+static PCCERT_CONTEXT http_sspi_create_credential(http_credential_t *cred);
+static BOOL http_sspi_find_credentials(http_t *http, const LPWSTR containerName, const char *common_name);
+static void http_sspi_free(_http_sspi_t *sspi);
+static BOOL http_sspi_make_credentials(_http_sspi_t *sspi, const LPWSTR containerName, const char *common_name, _http_mode_t mode, int years);
static int http_sspi_server(http_t *http, const char *hostname);
-static void http_sspi_set_allows_any_root(_http_sspi_t *conn, BOOL allow);
-static void http_sspi_set_allows_expired_certs(_http_sspi_t *conn, BOOL allow);
+static void http_sspi_set_allows_any_root(_http_sspi_t *sspi, BOOL allow);
+static void http_sspi_set_allows_expired_certs(_http_sspi_t *sspi, BOOL allow);
+static const char *http_sspi_strerror(char *buffer, size_t bufsize, DWORD code);
static DWORD http_sspi_verify(PCCERT_CONTEXT cert, const char *common_name, DWORD dwCertFlags);
/*
* 'cupsMakeServerCredentials()' - Make a self-signed certificate and private key pair.
*
- * @since CUPS 2.0@
+ * @since CUPS 2.0/OS 10.10@
*/
int /* O - 1 on success, 0 on failure */
const char **alt_names, /* I - Subject Alternate Names */
time_t expiration_date) /* I - Expiration date */
{
+ _http_sspi_t *sspi; /* SSPI data */
+ int ret; /* Return value */
+
+
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));
(void)path;
- (void)common_name;
(void)num_alt_names;
(void)alt_names;
- (void)expiration_date;
- return (0);
+ sspi = http_sspi_alloc();
+ ret = http_sspi_make_credentials(sspi, L"ServerContainer", common_name, _HTTP_MODE_SERVER, (int)((expiration_date - time(NULL) + 86399) / 86400 / 365));
+
+ http_sspi_free(sspi);
+
+ return (ret);
}
* Note: The server credentials are used by all threads in the running process.
* This function is threadsafe.
*
- * @since CUPS 2.0@
+ * @since CUPS 2.0/OS 10.10@
*/
int /* O - 1 on success, 0 on failure */
{
DEBUG_printf(("httpCopyCredentials(http=%p, credentials=%p)", http, credentials));
- (void)http;
+ if (!http || !http->tls || !http->tls->remoteCert || !credentials)
+ {
+ if (credentials)
+ *credentials = NULL;
- if (credentials)
- *credentials = NULL;
+ return (-1);
+ }
+
+ *credentials = cupsArrayNew(NULL, NULL);
+ httpAddCredential(*credentials, http->tls->remoteCert->pbCertEncoded, http->tls->remoteCert->cbCertEncoded);
- return (-1);
+ return (0);
}
_httpCreateCredentials(
cups_array_t *credentials) /* I - Array of credentials */
{
- (void)credentials;
-
- return (NULL);
+ return (http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials)));
}
/*
* 'httpCredentialsAreValidForName()' - Return whether the credentials are valid for the given name.
*
- * @since CUPS 2.0@
+ * @since CUPS 2.0/OS 10.10@
*/
int /* O - 1 if valid, 0 otherwise */
cups_array_t *credentials, /* I - Credentials */
const char *common_name) /* I - Name to check */
{
- (void)credentials;
- (void)common_name;
+ int valid = 1; /* Valid name? */
+ PCCERT_CONTEXT cert = http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials));
+ /* Certificate */
+ char cert_name[1024]; /* Name from certificate */
+
+
+ if (cert)
+ {
+ if (CertNameToStr(X509_ASN_ENCODING, &(cert->pCertInfo->Subject), CERT_SIMPLE_NAME_STR, cert_name, sizeof(cert_name)))
+ {
+ /*
+ * Extract common name at end...
+ */
- return (1);
+ char *ptr = strrchr(cert_name, ',');
+ if (ptr && ptr[1])
+ _cups_strcpy(cert_name, ptr + 2);
+ }
+ else
+ strlcpy(cert_name, "unknown", sizeof(cert_name));
+
+ CertFreeCertificateContext(cert);
+ }
+ else
+ strlcpy(cert_name, "unknown", sizeof(cert_name));
+
+ /*
+ * Compare the common names...
+ */
+
+ if (_cups_strcasecmp(common_name, cert_name))
+ {
+ /*
+ * Not an exact match for the common name, check for wildcard certs...
+ */
+
+ const char *domain = strchr(common_name, '.');
+ /* Domain in common name */
+
+ if (strncmp(cert_name, "*.", 2) || !domain || _cups_strcasecmp(domain, cert_name + 1))
+ {
+ /*
+ * Not a wildcard match.
+ */
+
+ /* TODO: Check subject alternate names */
+ valid = 0;
+ }
+ }
+
+ return (valid);
}
/*
* 'httpCredentialsGetTrust()' - Return the trust of credentials.
*
- * @since CUPS 2.0@
+ * @since CUPS 2.0/OS 10.10@
*/
http_trust_t /* O - Level of trust */
cups_array_t *credentials, /* I - Credentials */
const char *common_name) /* I - Common name for trust lookup */
{
- http_trust_t trust = HTTP_TRUST_OK;
- /* Trusted? */
- cups_array_t *tcreds = NULL; /* Trusted credentials */
- _cups_globals_t *cg = _cupsGlobals();
- /* Per-thread globals */
+ http_trust_t trust = HTTP_TRUST_OK; /* Level of trust */
+ PCCERT_CONTEXT cert = NULL; /* Certificate to validate */
+ DWORD certFlags = 0; /* Cert verification flags */
+ _cups_globals_t *cg = _cupsGlobals(); /* Per-thread global data */
if (!common_name)
return (HTTP_TRUST_UNKNOWN);
- /*
- * Look this common name up in the default keychains...
- */
-
- httpLoadCredentials(NULL, &tcreds, common_name);
-
- if (tcreds)
- {
- char credentials_str[1024], /* String for incoming credentials */
- tcreds_str[1024]; /* String for saved credentials */
-
- httpCredentialsString(credentials, credentials_str, sizeof(credentials_str));
- httpCredentialsString(tcreds, tcreds_str, sizeof(tcreds_str));
-
- if (strcmp(credentials_str, tcreds_str))
- {
- /*
- * Credentials don't match, let's look at the expiration date of the new
- * credentials and allow if the new ones have a later expiration...
- */
-
- if (httpCredentialsGetExpiration(credentials) <= httpCredentialsGetExpiration(tcreds) ||
- !httpCredentialsAreValidForName(credentials, common_name))
- {
- /*
- * Either the new credentials are not newly issued, or the common name
- * does not match the issued certificate...
- */
+ cert = http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials));
+ if (!cert)
+ return (HTTP_TRUST_UNKNOWN);
- trust = HTTP_TRUST_INVALID;
- }
- else if (httpCredentialsGetExpiration(tcreds) < time(NULL))
- {
- /*
- * Save the renewed credentials...
- */
+ if (cg->any_root)
+ certFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA;
- trust = HTTP_TRUST_RENEWED;
+ if (cg->expired_certs)
+ certFlags |= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
- httpSaveCredentials(NULL, credentials, common_name);
- }
- }
+ if (!cg->validate_certs)
+ certFlags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID;
- httpFreeCredentials(tcreds);
- }
- else if (cg->validate_certs && !httpCredentialsAreValidForName(credentials, common_name))
+ if (http_sspi_verify(cert, common_name, certFlags) != SEC_E_OK)
trust = HTTP_TRUST_INVALID;
- if (!cg->expired_certs && time(NULL) > httpCredentialsGetExpiration(credentials))
- trust = HTTP_TRUST_EXPIRED;
- else if (!cg->any_root && cupsArrayCount(credentials) == 1)
- trust = HTTP_TRUST_INVALID;
+ CertFreeCertificateContext(cert);
return (trust);
}
/*
* 'httpCredentialsGetExpiration()' - Return the expiration date of the credentials.
*
- * @since CUPS 2.0@
+ * @since CUPS 2.0/OS 10.10@
*/
time_t /* O - Expiration date of credentials */
httpCredentialsGetExpiration(
cups_array_t *credentials) /* I - Credentials */
{
- (void)credentials;
+ time_t expiration_date = 0; /* Expiration data of credentials */
+ PCCERT_CONTEXT cert = http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials));
+ /* Certificate */
+
+ if (cert)
+ {
+ SYSTEMTIME systime; /* System time */
+ struct tm tm; /* UNIX date/time */
+
+ FileTimeToSystemTime(&(cert->pCertInfo->NotAfter), &systime);
+
+ tm.tm_year = systime.wYear - 1900;
+ tm.tm_mon = systime.wMonth - 1;
+ tm.tm_mday = systime.wDay;
+ tm.tm_hour = systime.wHour;
+ tm.tm_min = systime.wMinute;
+ tm.tm_sec = systime.wSecond;
+
+ expiration_date = mktime(&tm);
- return (INT_MAX);
+ CertFreeCertificateContext(cert);
+ }
+
+ return (expiration_date);
}
/*
* 'httpCredentialsString()' - Return a string representing the credentials.
*
- * @since CUPS 2.0@
+ * @since CUPS 2.0/OS 10.10@
*/
size_t /* O - Total size of credentials string */
char *buffer, /* I - Buffer or @code NULL@ */
size_t bufsize) /* I - Size of buffer */
{
+ http_credential_t *first = (http_credential_t *)cupsArrayFirst(credentials);
+ /* First certificate */
+ PCCERT_CONTEXT cert; /* Certificate */
+
+
DEBUG_printf(("httpCredentialsString(credentials=%p, buffer=%p, bufsize=" CUPS_LLFMT ")", credentials, buffer, CUPS_LLCAST bufsize));
if (!buffer)
if (buffer && bufsize > 0)
*buffer = '\0';
-#if 0
- http_credential_t *first; /* First certificate */
- SecCertificateRef secCert; /* Certificate reference */
-
+ cert = http_sspi_create_credential(first);
- if ((first = (http_credential_t *)cupsArrayFirst(credentials)) != NULL &&
- (secCert = http_cdsa_create_credential(first)) != NULL)
+ if (cert)
{
- CFStringRef cf_name; /* CF common name string */
- char name[256]; /* Common name associated with cert */
+ char cert_name[256]; /* Common name */
+ SYSTEMTIME systime; /* System time */
+ struct tm tm; /* UNIX date/time */
time_t expiration; /* Expiration date of cert */
_cups_md5_state_t md5_state; /* MD5 state */
unsigned char md5_digest[16]; /* MD5 result */
- if ((cf_name = SecCertificateCopySubjectSummary(secCert)) != NULL)
+ FileTimeToSystemTime(&(cert->pCertInfo->NotAfter), &systime);
+
+ tm.tm_year = systime.wYear - 1900;
+ tm.tm_mon = systime.wMonth - 1;
+ tm.tm_mday = systime.wDay;
+ tm.tm_hour = systime.wHour;
+ tm.tm_min = systime.wMinute;
+ tm.tm_sec = systime.wSecond;
+
+ expiration = mktime(&tm);
+
+ if (CertNameToStr(X509_ASN_ENCODING, &(cert->pCertInfo->Subject), CERT_SIMPLE_NAME_STR, cert_name, sizeof(cert_name)))
{
- CFStringGetCString(cf_name, name, (CFIndex)sizeof(name), kCFStringEncodingUTF8);
- CFRelease(cf_name);
+ /*
+ * Extract common name at end...
+ */
+
+ char *ptr = strrchr(cert_name, ',');
+ if (ptr && ptr[1])
+ _cups_strcpy(cert_name, ptr + 2);
}
else
- strlcpy(name, "unknown", sizeof(name));
-
- expiration = (time_t)(SecCertificateNotValidAfter(secCert) + kCFAbsoluteTimeIntervalSince1970);
+ strlcpy(cert_name, "unknown", sizeof(cert_name));
_cupsMD5Init(&md5_state);
_cupsMD5Append(&md5_state, first->data, (int)first->datalen);
_cupsMD5Finish(&md5_state, md5_digest);
- snprintf(buffer, bufsize, "%s / %s / %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", 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]);
+ 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]);
- CFRelease(secCert);
+ CertFreeCertificateContext(cert);
}
-#endif /* 0 */
DEBUG_printf(("1httpCredentialsString: Returning \"%s\".", buffer));
{
if (!credentials)
return;
+
+ CertFreeCertificateContext(credentials);
}
/*
* 'httpLoadCredentials()' - Load X.509 credentials from a keychain file.
*
- * @since CUPS 2.0@
+ * @since CUPS 2.0/OS 10.10@
*/
int /* O - 0 on success, -1 on error */
cups_array_t **credentials, /* IO - Credentials */
const char *common_name) /* I - Common name for credentials */
{
+ HCERTSTORE store = NULL; /* Certificate store */
+ PCCERT_CONTEXT storedContext = NULL; /* Context created from the store */
+ DWORD dwSize = 0; /* 32 bit size */
+ PBYTE p = NULL; /* Temporary storage */
+ HCRYPTPROV hProv = (HCRYPTPROV)NULL;
+ /* Handle to a CSP */
+ CERT_NAME_BLOB sib; /* Arbitrary array of bytes */
+#ifdef DEBUG
+ char error[1024]; /* Error message buffer */
+#endif /* DEBUG */
+
+
DEBUG_printf(("httpLoadCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path, credentials, common_name));
(void)path;
- (void)common_name;
if (credentials)
+ {
*credentials = NULL;
+ }
+ else
+ {
+ DEBUG_puts("1httpLoadCredentials: NULL credentials pointer, returning -1.");
+ return (-1);
+ }
+
+ if (!common_name)
+ {
+ DEBUG_puts("1httpLoadCredentials: Bad common name, returning -1.");
+ return (-1);
+ }
+
+ if (!CryptAcquireContextW(&hProv, L"RememberedContainer", MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET))
+ {
+ if (GetLastError() == NTE_EXISTS)
+ {
+ if (!CryptAcquireContextW(&hProv, L"RememberedContainer", MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
+ {
+ DEBUG_printf(("1httpLoadCredentials: CryptAcquireContext failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
+ goto cleanup;
+ }
+ }
+ }
+
+ 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");
+
+ if (!store)
+ {
+ DEBUG_printf(("1httpLoadCredentials: CertOpenSystemStore failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
+ goto cleanup;
+ }
+
+ dwSize = 0;
+
+ if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL))
+ {
+ DEBUG_printf(("1httpLoadCredentials: CertStrToName failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
+ goto cleanup;
+ }
+
+ p = (PBYTE)malloc(dwSize);
+
+ if (!p)
+ {
+ DEBUG_printf(("1httpLoadCredentials: malloc failed for %d bytes.", dwSize));
+ goto cleanup;
+ }
+
+ if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL))
+ {
+ DEBUG_printf(("1httpLoadCredentials: CertStrToName failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
+ goto cleanup;
+ }
+
+ sib.cbData = dwSize;
+ sib.pbData = p;
+
+ storedContext = CertFindCertificateInStore(store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_NAME, &sib, NULL);
+
+ if (!storedContext)
+ {
+ DEBUG_printf(("1httpLoadCredentials: Unable to find credentials for \"%s\".", common_name));
+ goto cleanup;
+ }
+
+ *credentials = cupsArrayNew(NULL, NULL);
+ httpAddCredential(*credentials, storedContext->pbCertEncoded, storedContext->cbCertEncoded);
+
+cleanup:
+
+ /*
+ * Cleanup
+ */
+
+ if (storedContext)
+ CertFreeCertificateContext(storedContext);
+
+ if (p)
+ free(p);
+
+ if (store)
+ CertCloseStore(store, 0);
+
+ if (hProv)
+ CryptReleaseContext(hProv, 0);
DEBUG_printf(("1httpLoadCredentials: Returning %d.", *credentials ? 0 : -1));
/*
* 'httpSaveCredentials()' - Save X.509 credentials to a keychain file.
*
- * @since CUPS 2.0@
+ * @since CUPS 2.0/OS 10.10@
*/
int /* O - -1 on error, 0 on success */
cups_array_t *credentials, /* I - Credentials */
const char *common_name) /* I - Common name for credentials */
{
+ HCERTSTORE store = NULL; /* Certificate store */
+ PCCERT_CONTEXT storedContext = NULL; /* Context created from the store */
+ PCCERT_CONTEXT createdContext = NULL; /* Context created by us */
+ DWORD dwSize = 0; /* 32 bit size */
+ PBYTE p = NULL; /* Temporary storage */
+ HCRYPTPROV hProv = (HCRYPTPROV)NULL;
+ /* Handle to a CSP */
+ CRYPT_KEY_PROV_INFO ckp; /* Handle to crypto key */
+ int ret = -1; /* Return value */
+#ifdef DEBUG
+ char error[1024]; /* Error message buffer */
+#endif /* DEBUG */
+
+
DEBUG_printf(("httpSaveCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path, credentials, common_name));
(void)path;
- (void)credentials;
- (void)common_name;
- DEBUG_printf(("1httpSaveCredentials: Returning %d.", -1));
- return (-1);
+ if (!common_name)
+ {
+ DEBUG_puts("1httpSaveCredentials: Bad common name, returning -1.");
+ return (-1);
+ }
+
+ createdContext = http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials));
+ if (!createdContext)
+ {
+ DEBUG_puts("1httpSaveCredentials: Bad credentials, returning -1.");
+ return (-1);
+ }
+
+ if (!CryptAcquireContextW(&hProv, L"RememberedContainer", MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET))
+ {
+ if (GetLastError() == NTE_EXISTS)
+ {
+ if (!CryptAcquireContextW(&hProv, L"RememberedContainer", MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
+ {
+ DEBUG_printf(("1httpSaveCredentials: CryptAcquireContext failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
+ goto cleanup;
+ }
+ }
+ }
+
+ 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");
+
+ if (!store)
+ {
+ DEBUG_printf(("1httpSaveCredentials: CertOpenSystemStore failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
+ goto cleanup;
+ }
+
+ dwSize = 0;
+
+ if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL))
+ {
+ DEBUG_printf(("1httpSaveCredentials: CertStrToName failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
+ goto cleanup;
+ }
+
+ p = (PBYTE)malloc(dwSize);
+
+ if (!p)
+ {
+ DEBUG_printf(("1httpSaveCredentials: malloc failed for %d bytes.", dwSize));
+ goto cleanup;
+ }
+
+ if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL))
+ {
+ DEBUG_printf(("1httpSaveCredentials: CertStrToName failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
+ goto cleanup;
+ }
+
+ /*
+ * Add the created context to the named store, and associate it with the named
+ * container...
+ */
+
+ if (!CertAddCertificateContextToStore(store, createdContext, CERT_STORE_ADD_REPLACE_EXISTING, &storedContext))
+ {
+ DEBUG_printf(("1httpSaveCredentials: CertAddCertificateContextToStore failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
+ goto cleanup;
+ }
+
+ ZeroMemory(&ckp, sizeof(ckp));
+ ckp.pwszContainerName = L"RememberedContainer";
+ ckp.pwszProvName = MS_DEF_PROV_W;
+ ckp.dwProvType = PROV_RSA_FULL;
+ ckp.dwFlags = CRYPT_MACHINE_KEYSET;
+ ckp.dwKeySpec = AT_KEYEXCHANGE;
+
+ if (!CertSetCertificateContextProperty(storedContext, CERT_KEY_PROV_INFO_PROP_ID, 0, &ckp))
+ {
+ DEBUG_printf(("1httpSaveCredentials: CertSetCertificateContextProperty failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+
+ /*
+ * Cleanup
+ */
+
+ if (createdContext)
+ CertFreeCertificateContext(createdContext);
+
+ if (storedContext)
+ CertFreeCertificateContext(storedContext);
+
+ if (p)
+ free(p);
+
+ if (store)
+ CertCloseStore(store, 0);
+
+ if (hProv)
+ CryptReleaseContext(hProv, 0);
+
+ DEBUG_printf(("1httpSaveCredentials: Returning %d.", ret));
+ return (ret);
}
int len) /* I - Length of buffer */
{
int i; /* Looping var */
- _http_sspi_t *conn = http->tls; /* SSPI data */
+ _http_sspi_t *sspi = http->tls; /* SSPI data */
SecBufferDesc message; /* Array of SecBuffer struct */
SecBuffer buffers[4] = { 0 }; /* Security package buffer */
int num = 0; /* Return value */
SECURITY_STATUS scRet; /* SSPI status */
- if (!conn)
- {
- WSASetLastError(WSAEINVAL);
- return (-1);
- }
+ DEBUG_printf(("4_httpTLSRead(http=%p, buf=%p, len=%d)", http, buf, len));
/*
* If there are bytes that have already been decrypted and have not yet been
* read, return those...
*/
- if (conn->readBufferUsed > 0)
+ if (sspi->readBufferUsed > 0)
{
- int bytesToCopy = min(conn->readBufferUsed, len);
+ int bytesToCopy = min(sspi->readBufferUsed, len);
/* Number of bytes to copy */
- memcpy(buf, conn->readBuffer, bytesToCopy);
- conn->readBufferUsed -= bytesToCopy;
+ memcpy(buf, sspi->readBuffer, bytesToCopy);
+ sspi->readBufferUsed -= bytesToCopy;
+
+ if (sspi->readBufferUsed > 0)
+ memmove(sspi->readBuffer, sspi->readBuffer + bytesToCopy, sspi->readBufferUsed);
- if (conn->readBufferUsed > 0)
- memmove(conn->readBuffer, conn->readBuffer + bytesToCopy, conn->readBufferUsed);
+ DEBUG_printf(("5_httpTLSRead: Returning %d bytes previously decrypted.", bytesToCopy));
return (bytesToCopy);
}
*/
message.ulVersion = SECBUFFER_VERSION;
- message.cBuffers = 4;
- message.pBuffers = buffers;
+ message.cBuffers = 4;
+ message.pBuffers = buffers;
do
{
* If there is not enough space in the buffer, then increase its size...
*/
- if (conn->decryptBufferLength <= conn->decryptBufferUsed)
+ if (sspi->decryptBufferLength <= sspi->decryptBufferUsed)
{
BYTE *temp; /* New buffer */
- if (conn->decryptBufferLength >= 262144)
+ if (sspi->decryptBufferLength >= 262144)
{
WSASetLastError(E_OUTOFMEMORY);
DEBUG_puts("_httpTLSRead: Decryption buffer too large (>256k)");
return (-1);
}
- if ((temp = realloc(conn->decryptBuffer, conn->decryptBufferLength + 4096)) == NULL)
+ if ((temp = realloc(sspi->decryptBuffer, sspi->decryptBufferLength + 4096)) == NULL)
{
- DEBUG_printf(("_httpTLSRead: Unable to allocate %d byte buffer.", conn->decryptBufferLength + 4096));
+ DEBUG_printf(("_httpTLSRead: Unable to allocate %d byte decryption buffer.", sspi->decryptBufferLength + 4096));
WSASetLastError(E_OUTOFMEMORY);
return (-1);
}
- conn->decryptBufferLength += 4096;
- conn->decryptBuffer = temp;
+ sspi->decryptBufferLength += 4096;
+ sspi->decryptBuffer = temp;
+
+ DEBUG_printf(("_httpTLSRead: Resized decryption buffer to %d bytes.", sspi->decryptBufferLength));
}
- buffers[0].pvBuffer = conn->decryptBuffer;
- buffers[0].cbBuffer = (unsigned long) conn->decryptBufferUsed;
+ buffers[0].pvBuffer = sspi->decryptBuffer;
+ buffers[0].cbBuffer = (unsigned long)sspi->decryptBufferUsed;
buffers[0].BufferType = SECBUFFER_DATA;
buffers[1].BufferType = SECBUFFER_EMPTY;
buffers[2].BufferType = SECBUFFER_EMPTY;
buffers[3].BufferType = SECBUFFER_EMPTY;
- scRet = DecryptMessage(&conn->context, &message, 0, NULL);
+ DEBUG_printf(("5_httpTLSRead: decryptBufferUsed=%d", sspi->decryptBufferUsed));
+
+ scRet = DecryptMessage(&sspi->context, &message, 0, NULL);
if (scRet == SEC_E_INCOMPLETE_MESSAGE)
{
- num = recv(http->fd, conn->decryptBuffer + conn->decryptBufferUsed, (int)(conn->decryptBufferLength - conn->decryptBufferUsed), 0);
+ num = recv(http->fd, sspi->decryptBuffer + sspi->decryptBufferUsed, (int)(sspi->decryptBufferLength - sspi->decryptBufferUsed), 0);
if (num < 0)
{
- DEBUG_printf(("_httpTLSRead: recv failed: %d", WSAGetLastError()));
+ DEBUG_printf(("5_httpTLSRead: recv failed: %d", WSAGetLastError()));
return (-1);
}
else if (num == 0)
{
- DEBUG_puts("_httpTLSRead: Server disconnected.");
+ DEBUG_puts("5_httpTLSRead: Server disconnected.");
return (0);
}
- conn->decryptBufferUsed += num;
+ DEBUG_printf(("5_httpTLSRead: Read %d bytes into decryption buffer.", num));
+
+ sspi->decryptBufferUsed += num;
}
}
while (scRet == SEC_E_INCOMPLETE_MESSAGE);
if (scRet == SEC_I_CONTEXT_EXPIRED)
{
- DEBUG_puts("_httpTLSRead: Context expired.");
+ DEBUG_puts("5_httpTLSRead: Context expired.");
WSASetLastError(WSAECONNRESET);
return (-1);
}
else if (scRet != SEC_E_OK)
{
- DEBUG_printf(("_httpTLSRead: DecryptMessage failed: %lx", scRet));
+ DEBUG_printf(("5_httpTLSRead: DecryptMessage failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
WSASetLastError(WSASYSCALLFAILURE);
return (-1);
}
if (bytesToSave)
{
- if ((conn->readBufferLength - conn->readBufferUsed) < bytesToSave)
+ if ((sspi->readBufferLength - sspi->readBufferUsed) < bytesToSave)
{
BYTE *temp; /* New buffer pointer */
- if ((temp = realloc(conn->readBuffer, conn->readBufferUsed + bytesToSave)) == NULL)
+ if ((temp = realloc(sspi->readBuffer, sspi->readBufferUsed + bytesToSave)) == NULL)
{
- DEBUG_printf(("_httpTLSRead: Unable to allocate %d bytes.", conn->readBufferUsed + bytesToSave));
+ DEBUG_printf(("_httpTLSRead: Unable to allocate %d bytes.", sspi->readBufferUsed + bytesToSave));
WSASetLastError(E_OUTOFMEMORY);
return (-1);
}
- conn->readBufferLength = conn->readBufferUsed + bytesToSave;
- conn->readBuffer = temp;
+ sspi->readBufferLength = sspi->readBufferUsed + bytesToSave;
+ sspi->readBuffer = temp;
}
- memcpy(((BYTE *)conn->readBuffer) + conn->readBufferUsed, ((BYTE *)pDataBuffer->pvBuffer) + bytesToCopy, bytesToSave);
+ memcpy(((BYTE *)sspi->readBuffer) + sspi->readBufferUsed, ((BYTE *)pDataBuffer->pvBuffer) + bytesToCopy, bytesToSave);
- conn->readBufferUsed += bytesToSave;
+ sspi->readBufferUsed += bytesToSave;
}
- return (bytesToCopy);
+ num = bytesToCopy;
}
else
{
if (pExtraBuffer)
{
- memmove(conn->decryptBuffer, pExtraBuffer->pvBuffer, pExtraBuffer->cbBuffer);
- conn->decryptBufferUsed = pExtraBuffer->cbBuffer;
+ memmove(sspi->decryptBuffer, pExtraBuffer->pvBuffer, pExtraBuffer->cbBuffer);
+ sspi->decryptBufferUsed = pExtraBuffer->cbBuffer;
}
else
{
- conn->decryptBufferUsed = 0;
+ sspi->decryptBufferUsed = 0;
}
- return (0);
+ return (num);
+}
+
+
+/*
+ * '_httpTLSSetOptions()' - Set TLS protocol and cipher suite options.
+ */
+
+void
+_httpTLSSetOptions(int options) /* I - Options */
+{
+ tls_options = options;
}
void
_httpTLSStop(http_t *http) /* I - HTTP connection */
{
- _http_sspi_t *conn = http->tls; /* SSPI data */
+ _http_sspi_t *sspi = http->tls; /* SSPI data */
- if (conn->contextInitialized && http->fd >= 0)
+ if (sspi->contextInitialized && http->fd >= 0)
{
SecBufferDesc message; /* Array of SecBuffer struct */
SecBuffer buffers[1] = { 0 };
message.pBuffers = buffers;
message.ulVersion = SECBUFFER_VERSION;
- status = ApplyControlToken(&conn->context, &message);
+ status = ApplyControlToken(&sspi->context, &message);
if (SUCCEEDED(status))
{
message.pBuffers = buffers;
message.ulVersion = SECBUFFER_VERSION;
- status = AcceptSecurityContext(&conn->creds, &conn->context, NULL,
+ status = AcceptSecurityContext(&sspi->creds, &sspi->context, NULL,
dwSSPIFlags, SECURITY_NATIVE_DREP, NULL,
&message, &dwSSPIOutFlags, &tsExpiry);
}
else
{
- DEBUG_printf(("_httpTLSStop: AcceptSecurityContext failed: %x", status));
+ DEBUG_printf(("_httpTLSStop: AcceptSecurityContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), status)));
}
}
else
{
- DEBUG_printf(("_httpTLSStop: ApplyControlToken failed: %x", status));
+ DEBUG_printf(("_httpTLSStop: ApplyControlToken failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), status)));
}
}
- http_sspi_free(conn);
+ http_sspi_free(sspi);
http->tls = NULL;
}
const char *buf, /* I - Buffer holding data */
int len) /* I - Length of buffer */
{
- _http_sspi_t *conn = http->tls; /* SSPI data */
+ _http_sspi_t *sspi = http->tls; /* SSPI data */
SecBufferDesc message; /* Array of SecBuffer struct */
SecBuffer buffers[4] = { 0 }; /* Security package buffer */
int bufferLen; /* Buffer length */
int num = 0; /* Return value */
- bufferLen = conn->streamSizes.cbMaximumMessage + conn->streamSizes.cbHeader + conn->streamSizes.cbTrailer;
+ bufferLen = sspi->streamSizes.cbMaximumMessage + sspi->streamSizes.cbHeader + sspi->streamSizes.cbTrailer;
- if (bufferLen > conn->writeBufferLength)
+ if (bufferLen > sspi->writeBufferLength)
{
BYTE *temp; /* New buffer pointer */
- if ((temp = (BYTE *)realloc(conn->writeBuffer, bufferLen)) == NULL)
+ if ((temp = (BYTE *)realloc(sspi->writeBuffer, bufferLen)) == NULL)
{
DEBUG_printf(("_httpTLSWrite: Unable to allocate buffer of %d bytes.", bufferLen));
WSASetLastError(E_OUTOFMEMORY);
return (-1);
}
- conn->writeBuffer = temp;
- conn->writeBufferLength = bufferLen;
+ sspi->writeBuffer = temp;
+ sspi->writeBufferLength = bufferLen;
}
bytesLeft = len;
while (bytesLeft)
{
- int chunk = min((int)conn->streamSizes.cbMaximumMessage, bytesLeft);
+ int chunk = min((int)sspi->streamSizes.cbMaximumMessage, bytesLeft);
/* Size of data to write */
SECURITY_STATUS scRet; /* SSPI status */
* Copy user data into the buffer, starting just past the header...
*/
- memcpy(conn->writeBuffer + conn->streamSizes.cbHeader, bufptr, chunk);
+ memcpy(sspi->writeBuffer + sspi->streamSizes.cbHeader, bufptr, chunk);
/*
* Setup the SSPI buffers
message.cBuffers = 4;
message.pBuffers = buffers;
- buffers[0].pvBuffer = conn->writeBuffer;
- buffers[0].cbBuffer = conn->streamSizes.cbHeader;
+ buffers[0].pvBuffer = sspi->writeBuffer;
+ buffers[0].cbBuffer = sspi->streamSizes.cbHeader;
buffers[0].BufferType = SECBUFFER_STREAM_HEADER;
- buffers[1].pvBuffer = conn->writeBuffer + conn->streamSizes.cbHeader;
+ buffers[1].pvBuffer = sspi->writeBuffer + sspi->streamSizes.cbHeader;
buffers[1].cbBuffer = (unsigned long) chunk;
buffers[1].BufferType = SECBUFFER_DATA;
- buffers[2].pvBuffer = conn->writeBuffer + conn->streamSizes.cbHeader + chunk;
- buffers[2].cbBuffer = conn->streamSizes.cbTrailer;
+ buffers[2].pvBuffer = sspi->writeBuffer + sspi->streamSizes.cbHeader + chunk;
+ buffers[2].cbBuffer = sspi->streamSizes.cbTrailer;
buffers[2].BufferType = SECBUFFER_STREAM_TRAILER;
buffers[3].BufferType = SECBUFFER_EMPTY;
* Encrypt the data
*/
- scRet = EncryptMessage(&conn->context, 0, &message, 0);
+ scRet = EncryptMessage(&sspi->context, 0, &message, 0);
if (FAILED(scRet))
{
- DEBUG_printf(("_httpTLSWrite: EncryptMessage failed: %x", scRet));
+ DEBUG_printf(("_httpTLSWrite: EncryptMessage failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
WSASetLastError(WSASYSCALLFAILURE);
return (-1);
}
* of the trailer...
*/
- num = send(http->fd, conn->writeBuffer, buffers[0].cbBuffer + buffers[1].cbBuffer + buffers[2].cbBuffer, 0);
+ num = send(http->fd, sspi->writeBuffer, buffers[0].cbBuffer + buffers[1].cbBuffer + buffers[2].cbBuffer, 0);
if (num <= 0)
{
static _http_sspi_t * /* O - New SSPI/SSL object */
http_sspi_alloc(void)
{
- _http_sspi_t *conn = calloc(sizeof(_http_sspi_t), 1);
-
- return (conn);
+ return ((_http_sspi_t *)calloc(sizeof(_http_sspi_t), 1));
}
http_sspi_client(http_t *http, /* I - Client connection */
const char *hostname) /* I - Server hostname */
{
- _http_sspi_t *conn = http->tls; /* SSPI data */
+ _http_sspi_t *sspi = http->tls; /* SSPI data */
+ DWORD dwSize; /* Size for buffer */
DWORD dwSSPIFlags; /* SSL connection attributes we want */
DWORD dwSSPIOutFlags; /* SSL connection attributes we got */
TimeStamp tsExpiry; /* Time stamp */
SecBufferDesc outBuffer; /* Array of SecBuffer structs */
SecBuffer outBuffers[1]; /* Security package buffer */
int ret = 0; /* Return value */
+ char username[1024], /* Current username */
+ common_name[1024]; /* CN=username */
- DEBUG_printf(("http_sspi_client(http=%p, hostname=\"%s\")", http, hostname));
+ DEBUG_printf(("4http_sspi_client(http=%p, hostname=\"%s\")", http, hostname));
dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT |
ISC_REQ_REPLAY_DETECT |
ISC_REQ_ALLOCATE_MEMORY |
ISC_REQ_STREAM;
+ /*
+ * Lookup the client certificate...
+ */
+
+ dwSize = sizeof(username);
+ GetUserName(username, &dwSize);
+ snprintf(common_name, sizeof(common_name), "CN=%s", username);
+
+ if (!http_sspi_find_credentials(http, L"ClientContainer", common_name))
+ if (!http_sspi_make_credentials(http->tls, L"ClientContainer", common_name, _HTTP_MODE_CLIENT, 10))
+ {
+ DEBUG_puts("5http_sspi_client: Unable to get client credentials.");
+ return (-1);
+ }
+
/*
* Initiate a ClientHello message and generate a token.
*/
outBuffer.pBuffers = outBuffers;
outBuffer.ulVersion = SECBUFFER_VERSION;
- scRet = InitializeSecurityContext(&conn->creds, NULL, TEXT(""), dwSSPIFlags, 0, SECURITY_NATIVE_DREP, NULL, 0, &conn->context, &outBuffer, &dwSSPIOutFlags, &tsExpiry);
+ scRet = InitializeSecurityContext(&sspi->creds, NULL, TEXT(""), dwSSPIFlags, 0, SECURITY_NATIVE_DREP, NULL, 0, &sspi->context, &outBuffer, &dwSSPIOutFlags, &tsExpiry);
if (scRet != SEC_I_CONTINUE_NEEDED)
{
- DEBUG_printf(("http_sspi_client: InitializeSecurityContext(1) failed: %x", scRet));
+ DEBUG_printf(("5http_sspi_client: InitializeSecurityContext(1) failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
return (-1);
}
{
if ((cbData = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0)) <= 0)
{
- DEBUG_printf(("http_sspi_client: send failed: %d", WSAGetLastError()));
+ DEBUG_printf(("5http_sspi_client: send failed: %d", WSAGetLastError()));
FreeContextBuffer(outBuffers[0].pvBuffer);
- DeleteSecurityContext(&conn->context);
+ DeleteSecurityContext(&sspi->context);
return (-1);
}
- DEBUG_printf(("http_sspi_client: %d bytes of handshake data sent.", cbData));
+ DEBUG_printf(("5http_sspi_client: %d bytes of handshake data sent.", cbData));
FreeContextBuffer(outBuffers[0].pvBuffer);
outBuffers[0].pvBuffer = NULL;
ISC_REQ_ALLOCATE_MEMORY |
ISC_REQ_STREAM;
- conn->decryptBufferUsed = 0;
+ sspi->decryptBufferUsed = 0;
/*
* Loop until the handshake is finished or an error occurs.
scRet == SEC_E_INCOMPLETE_MESSAGE ||
scRet == SEC_I_INCOMPLETE_CREDENTIALS)
{
- if (conn->decryptBufferUsed == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE)
+ if (sspi->decryptBufferUsed == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE)
{
- if (conn->decryptBufferLength <= conn->decryptBufferUsed)
+ if (sspi->decryptBufferLength <= sspi->decryptBufferUsed)
{
BYTE *temp; /* New buffer */
- if (conn->decryptBufferLength >= 262144)
+ if (sspi->decryptBufferLength >= 262144)
{
WSASetLastError(E_OUTOFMEMORY);
- DEBUG_puts("http_sspi_client: Decryption buffer too large (>256k)");
+ DEBUG_puts("5http_sspi_client: Decryption buffer too large (>256k)");
return (-1);
}
- if ((temp = realloc(conn->decryptBuffer, conn->decryptBufferLength + 4096)) == NULL)
+ if ((temp = realloc(sspi->decryptBuffer, sspi->decryptBufferLength + 4096)) == NULL)
{
- DEBUG_printf(("http_sspi_client: Unable to allocate %d byte buffer.", conn->decryptBufferLength + 4096));
+ DEBUG_printf(("5http_sspi_client: Unable to allocate %d byte buffer.", sspi->decryptBufferLength + 4096));
WSASetLastError(E_OUTOFMEMORY);
return (-1);
}
- conn->decryptBufferLength += 4096;
- conn->decryptBuffer = temp;
+ sspi->decryptBufferLength += 4096;
+ sspi->decryptBuffer = temp;
}
- cbData = recv(http->fd, conn->decryptBuffer + conn->decryptBufferUsed, (int)(conn->decryptBufferLength - conn->decryptBufferUsed), 0);
+ cbData = recv(http->fd, sspi->decryptBuffer + sspi->decryptBufferUsed, (int)(sspi->decryptBufferLength - sspi->decryptBufferUsed), 0);
if (cbData < 0)
{
- DEBUG_printf(("http_sspi_client: recv failed: %d", WSAGetLastError()));
+ DEBUG_printf(("5http_sspi_client: recv failed: %d", WSAGetLastError()));
return (-1);
}
else if (cbData == 0)
{
- DEBUG_printf(("http_sspi_client: Server unexpectedly disconnected."));
+ DEBUG_printf(("5http_sspi_client: Server unexpectedly disconnected."));
return (-1);
}
- DEBUG_printf(("http_sspi_client: %d bytes of handshake data received", cbData));
+ DEBUG_printf(("5http_sspi_client: %d bytes of handshake data received", cbData));
- conn->decryptBufferUsed += cbData;
+ sspi->decryptBufferUsed += cbData;
}
/*
* SECBUFFER_EXTRA.
*/
- inBuffers[0].pvBuffer = conn->decryptBuffer;
- inBuffers[0].cbBuffer = (unsigned long)conn->decryptBufferUsed;
+ inBuffers[0].pvBuffer = sspi->decryptBuffer;
+ inBuffers[0].cbBuffer = (unsigned long)sspi->decryptBufferUsed;
inBuffers[0].BufferType = SECBUFFER_TOKEN;
inBuffers[1].pvBuffer = NULL;
* Call InitializeSecurityContext.
*/
- scRet = InitializeSecurityContext(&conn->creds, &conn->context, NULL, dwSSPIFlags, 0, SECURITY_NATIVE_DREP, &inBuffer, 0, NULL, &outBuffer, &dwSSPIOutFlags, &tsExpiry);
+ scRet = InitializeSecurityContext(&sspi->creds, &sspi->context, NULL, dwSSPIFlags, 0, SECURITY_NATIVE_DREP, &inBuffer, 0, NULL, &outBuffer, &dwSSPIOutFlags, &tsExpiry);
/*
* If InitializeSecurityContext was successful (or if the error was one of
if (cbData <= 0)
{
- DEBUG_printf(("http_sspi_client: send failed: %d", WSAGetLastError()));
+ DEBUG_printf(("5http_sspi_client: send failed: %d", WSAGetLastError()));
FreeContextBuffer(outBuffers[0].pvBuffer);
- DeleteSecurityContext(&conn->context);
+ DeleteSecurityContext(&sspi->context);
return (-1);
}
- DEBUG_printf(("http_sspi_client: %d bytes of handshake data sent.", cbData));
+ DEBUG_printf(("5http_sspi_client: %d bytes of handshake data sent.", cbData));
/*
* Free output buffer.
* later decrypt it with DecryptMessage.
*/
- DEBUG_puts("http_sspi_client: Handshake was successful.");
+ DEBUG_puts("5http_sspi_client: Handshake was successful.");
if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
{
- memmove(conn->decryptBuffer, conn->decryptBuffer + conn->decryptBufferUsed - inBuffers[1].cbBuffer, inBuffers[1].cbBuffer);
+ memmove(sspi->decryptBuffer, sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer, inBuffers[1].cbBuffer);
- conn->decryptBufferUsed = inBuffers[1].cbBuffer;
+ sspi->decryptBufferUsed = inBuffers[1].cbBuffer;
- DEBUG_printf(("http_sspi_client: %d bytes of app data was bundled with handshake data", conn->decryptBufferUsed));
+ DEBUG_printf(("5http_sspi_client: %d bytes of app data was bundled with handshake data", sspi->decryptBufferUsed));
}
else
- conn->decryptBufferUsed = 0;
+ sspi->decryptBufferUsed = 0;
/*
* Bail out to quit
if (FAILED(scRet))
{
- DEBUG_printf(("http_sspi_client: InitializeSecurityContext(2) failed: %x", scRet));
+ DEBUG_printf(("5http_sspi_client: InitializeSecurityContext(2) failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
ret = -1;
break;
}
* Unimplemented
*/
- DEBUG_printf(("http_sspi_client: server requested client credentials."));
+ DEBUG_printf(("5http_sspi_client: server requested client credentials."));
ret = -1;
break;
}
if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
{
- memmove(conn->decryptBuffer, conn->decryptBuffer + conn->decryptBufferUsed - inBuffers[1].cbBuffer, inBuffers[1].cbBuffer);
+ memmove(sspi->decryptBuffer, sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer, inBuffers[1].cbBuffer);
- conn->decryptBufferUsed = inBuffers[1].cbBuffer;
+ sspi->decryptBufferUsed = inBuffers[1].cbBuffer;
}
else
{
- conn->decryptBufferUsed = 0;
+ sspi->decryptBufferUsed = 0;
}
}
* Success! Get the server cert
*/
- conn->contextInitialized = TRUE;
+ sspi->contextInitialized = TRUE;
- scRet = QueryContextAttributes(&conn->context, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (VOID *)&(conn->remoteCert));
+ scRet = QueryContextAttributes(&sspi->context, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (VOID *)&(sspi->remoteCert));
if (scRet != SEC_E_OK)
{
- DEBUG_printf(("http_sspi_client: QueryContextAttributes failed(SECPKG_ATTR_REMOTE_CERT_CONTEXT): %x", scRet));
+ DEBUG_printf(("5http_sspi_client: QueryContextAttributes failed(SECPKG_ATTR_REMOTE_CERT_CONTEXT): %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
return (-1);
}
-#if 0
- /* TODO: Move this out for opt-in server cert validation, like other platforms. */
- scRet = http_sspi_verify(conn->remoteCert, hostname, conn->certFlags);
-
- if (scRet != SEC_E_OK)
- {
- DEBUG_printf(("http_sspi_client: sspi_verify_certificate failed: %x", scRet));
- ret = -1;
- goto cleanup;
- }
-#endif // 0
-
/*
* Find out how big the header/trailer will be:
*/
- scRet = QueryContextAttributes(&conn->context, SECPKG_ATTR_STREAM_SIZES, &conn->streamSizes);
+ scRet = QueryContextAttributes(&sspi->context, SECPKG_ATTR_STREAM_SIZES, &sspi->streamSizes);
if (scRet != SEC_E_OK)
{
- DEBUG_printf(("http_sspi_client: QueryContextAttributes failed(SECPKG_ATTR_STREAM_SIZES): %x", scRet));
+ DEBUG_printf(("5http_sspi_client: QueryContextAttributes failed(SECPKG_ATTR_STREAM_SIZES): %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
ret = -1;
}
}
}
+/*
+ * 'http_sspi_create_credential()' - Create an SSPI certificate context.
+ */
+
+static PCCERT_CONTEXT /* O - Certificate context */
+http_sspi_create_credential(
+ http_credential_t *cred) /* I - Credential */
+{
+ if (cred)
+ return (CertCreateCertificateContext(X509_ASN_ENCODING, cred->data, cred->datalen));
+ else
+ return (NULL);
+}
+
+
+/*
+ * 'http_sspi_find_credentials()' - Retrieve a TLS certificate from the system store.
+ */
+
+static BOOL /* O - 1 on success, 0 on failure */
+http_sspi_find_credentials(
+ http_t *http, /* I - HTTP connection */
+ const LPWSTR container, /* I - Cert container name */
+ const char *common_name) /* I - Common name of certificate */
+{
+ _http_sspi_t *sspi = http->tls; /* SSPI data */
+ HCERTSTORE store = NULL; /* Certificate store */
+ PCCERT_CONTEXT storedContext = NULL; /* Context created from the store */
+ DWORD dwSize = 0; /* 32 bit size */
+ PBYTE p = NULL; /* Temporary storage */
+ HCRYPTPROV hProv = (HCRYPTPROV)NULL;
+ /* Handle to a CSP */
+ CERT_NAME_BLOB sib; /* Arbitrary array of bytes */
+ SCHANNEL_CRED SchannelCred; /* Schannel credential data */
+ TimeStamp tsExpiry; /* Time stamp */
+ SECURITY_STATUS Status; /* Status */
+ BOOL ok = TRUE; /* Return value */
+
+
+ if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET))
+ {
+ if (GetLastError() == NTE_EXISTS)
+ {
+ if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
+ {
+ DEBUG_printf(("5http_sspi_find_credentials: CryptAcquireContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
+ ok = FALSE;
+ goto cleanup;
+ }
+ }
+ }
+
+ 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");
+
+ if (!store)
+ {
+ DEBUG_printf(("5http_sspi_find_credentials: CertOpenSystemStore failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ dwSize = 0;
+
+ if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL))
+ {
+ DEBUG_printf(("5http_sspi_find_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ p = (PBYTE)malloc(dwSize);
+
+ if (!p)
+ {
+ DEBUG_printf(("5http_sspi_find_credentials: malloc failed for %d bytes.", dwSize));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL))
+ {
+ DEBUG_printf(("5http_sspi_find_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ sib.cbData = dwSize;
+ sib.pbData = p;
+
+ storedContext = CertFindCertificateInStore(store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_NAME, &sib, NULL);
+
+ if (!storedContext)
+ {
+ DEBUG_printf(("5http_sspi_find_credentials: Unable to find credentials for \"%s\".", common_name));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ ZeroMemory(&SchannelCred, sizeof(SchannelCred));
+
+ SchannelCred.dwVersion = SCHANNEL_CRED_VERSION;
+ SchannelCred.cCreds = 1;
+ SchannelCred.paCred = &storedContext;
+
+ /*
+ * Set supported protocols (can also be overriden in the registry...)
+ */
+
+#ifdef SP_PROT_TLS1_2_SERVER
+ if (http->mode == _HTTP_MODE_SERVER)
+ {
+ if (tls_options & _HTTP_TLS_ALLOW_SSL3)
+ SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_0_SERVER | SP_PROT_SSL3_SERVER;
+ else
+ SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_0_SERVER;
+ }
+ else
+ {
+ if (tls_options & _HTTP_TLS_ALLOW_SSL3)
+ SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_0_CLIENT | SP_PROT_SSL3_CLIENT;
+ else
+ SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_0_CLIENT;
+ }
+
+#else
+ if (http->mode == _HTTP_MODE_SERVER)
+ {
+ if (tls_options & _HTTP_TLS_ALLOW_SSL3)
+ SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_SERVER | SP_PROT_SSL3_SERVER;
+ else
+ SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_SERVER;
+ }
+ else
+ {
+ if (tls_options & _HTTP_TLS_ALLOW_SSL3)
+ SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT | SP_PROT_SSL3_CLIENT;
+ else
+ SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT;
+ }
+#endif /* SP_PROT_TLS1_2_SERVER */
+
+ /* TODO: Support _HTTP_TLS_ALLOW_RC4 option; right now we'll rely on Windows registry to enable/disable RC4... */
+
+ /*
+ * Create an SSPI credential.
+ */
+
+ Status = AcquireCredentialsHandle(NULL, UNISP_NAME, http->mode == _HTTP_MODE_SERVER ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND, NULL, &SchannelCred, NULL, NULL, &sspi->creds, &tsExpiry);
+ if (Status != SEC_E_OK)
+ {
+ DEBUG_printf(("5http_sspi_find_credentials: AcquireCredentialsHandle failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), Status)));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+cleanup:
+
+ /*
+ * Cleanup
+ */
+
+ if (storedContext)
+ CertFreeCertificateContext(storedContext);
+
+ if (p)
+ free(p);
+
+ if (store)
+ CertCloseStore(store, 0);
+
+ if (hProv)
+ CryptReleaseContext(hProv, 0);
+
+ return (ok);
+}
+
+
/*
* 'http_sspi_free()' - Close a connection and free resources.
*/
static void
-http_sspi_free(_http_sspi_t *conn) /* I - Client connection */
+http_sspi_free(_http_sspi_t *sspi) /* I - SSPI data */
{
- if (!conn)
+ if (!sspi)
return;
- if (conn->contextInitialized)
- DeleteSecurityContext(&conn->context);
+ if (sspi->contextInitialized)
+ DeleteSecurityContext(&sspi->context);
- if (conn->decryptBuffer)
- free(conn->decryptBuffer);
+ if (sspi->decryptBuffer)
+ free(sspi->decryptBuffer);
- if (conn->readBuffer)
- free(conn->readBuffer);
+ if (sspi->readBuffer)
+ free(sspi->readBuffer);
- if (conn->writeBuffer)
- free(conn->writeBuffer);
+ if (sspi->writeBuffer)
+ free(sspi->writeBuffer);
- if (conn->localCert)
- CertFreeCertificateContext(conn->localCert);
+ if (sspi->localCert)
+ CertFreeCertificateContext(sspi->localCert);
- if (conn->remoteCert)
- CertFreeCertificateContext(conn->remoteCert);
+ if (sspi->remoteCert)
+ CertFreeCertificateContext(sspi->remoteCert);
- free(conn);
+ free(sspi);
}
-#if 0
/*
- * '_sspiGetCredentials()' - Retrieve an SSL/TLS certificate from the system store
- * If one cannot be found, one is created.
+ * 'http_sspi_make_credentials()' - Create a TLS certificate in the system store.
*/
-BOOL /* O - 1 on success, 0 on failure */
-_sspiGetCredentials(_http_sspi_t *conn,
- /* I - Client connection */
- const LPWSTR container,
- /* I - Cert container name */
- const TCHAR *cn, /* I - Common name of certificate */
- BOOL isServer)
- /* I - Is caller a server? */
+
+static BOOL /* O - 1 on success, 0 on failure */
+http_sspi_make_credentials(
+ _http_sspi_t *sspi, /* I - SSPI data */
+ const LPWSTR container, /* I - Cert container name */
+ const char *common_name, /* I - Common name of certificate */
+ _http_mode_t mode, /* I - Client or server? */
+ int years) /* I - Years until expiration */
{
- HCERTSTORE store = NULL; /* Certificate store */
- PCCERT_CONTEXT storedContext = NULL;
- /* Context created from the store */
- PCCERT_CONTEXT createdContext = NULL;
- /* Context created by us */
- DWORD dwSize = 0; /* 32 bit size */
- PBYTE p = NULL; /* Temporary storage */
- HCRYPTPROV hProv = (HCRYPTPROV) NULL;
+ HCERTSTORE store = NULL; /* Certificate store */
+ PCCERT_CONTEXT storedContext = NULL; /* Context created from the store */
+ PCCERT_CONTEXT createdContext = NULL; /* Context created by us */
+ DWORD dwSize = 0; /* 32 bit size */
+ PBYTE p = NULL; /* Temporary storage */
+ HCRYPTPROV hProv = (HCRYPTPROV)NULL;
/* Handle to a CSP */
- CERT_NAME_BLOB sib; /* Arbitrary array of bytes */
- SCHANNEL_CRED SchannelCred; /* Schannel credential data */
- TimeStamp tsExpiry; /* Time stamp */
- SECURITY_STATUS Status; /* Status */
- HCRYPTKEY hKey = (HCRYPTKEY) NULL;
- /* Handle to crypto key */
- CRYPT_KEY_PROV_INFO kpi; /* Key container info */
- SYSTEMTIME et; /* System time */
- CERT_EXTENSIONS exts; /* Array of cert extensions */
- CRYPT_KEY_PROV_INFO ckp; /* Handle to crypto key */
- BOOL ok = TRUE; /* Return value */
-
- if (!conn)
- return (FALSE);
- if (!cn)
- return (FALSE);
-
- if (!CryptAcquireContextW(&hProv, (LPWSTR) container, MS_DEF_PROV_W,
- PROV_RSA_FULL,
- CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET))
+ CERT_NAME_BLOB sib; /* Arbitrary array of bytes */
+ SCHANNEL_CRED SchannelCred; /* Schannel credential data */
+ TimeStamp tsExpiry; /* Time stamp */
+ SECURITY_STATUS Status; /* Status */
+ HCRYPTKEY hKey = (HCRYPTKEY)NULL; /* Handle to crypto key */
+ CRYPT_KEY_PROV_INFO kpi; /* Key container info */
+ SYSTEMTIME et; /* System time */
+ CERT_EXTENSIONS exts; /* Array of cert extensions */
+ CRYPT_KEY_PROV_INFO ckp; /* Handle to crypto key */
+ BOOL ok = TRUE; /* Return value */
+
+
+ DEBUG_printf(("4http_sspi_make_credentials(sspi=%p, container=%p, common_name=\"%s\", mode=%d, years=%d)", sspi, container, common_name, mode, years));
+
+ if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET))
{
if (GetLastError() == NTE_EXISTS)
{
- if (!CryptAcquireContextW(&hProv, (LPWSTR) container, MS_DEF_PROV_W,
- PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
+ if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
{
- DEBUG_printf(("_sspiGetCredentials: CryptAcquireContext failed: %x\n",
- GetLastError()));
+ DEBUG_printf(("5http_sspi_make_credentials: CryptAcquireContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
ok = FALSE;
goto cleanup;
}
}
}
- 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");
+ 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");
if (!store)
{
- DEBUG_printf(("_sspiGetCredentials: CertOpenSystemStore failed: %x\n",
- GetLastError()));
+ DEBUG_printf(("5http_sspi_make_credentials: CertOpenSystemStore failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
ok = FALSE;
goto cleanup;
}
dwSize = 0;
- if (!CertStrToName(X509_ASN_ENCODING, cn, CERT_OID_NAME_STR,
- NULL, NULL, &dwSize, NULL))
+ if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL))
{
- DEBUG_printf(("_sspiGetCredentials: CertStrToName failed: %x\n",
- GetLastError()));
+ DEBUG_printf(("5http_sspi_make_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
ok = FALSE;
goto cleanup;
}
- p = (PBYTE) malloc(dwSize);
+ p = (PBYTE)malloc(dwSize);
if (!p)
{
- DEBUG_printf(("_sspiGetCredentials: malloc failed for %d bytes", dwSize));
+ DEBUG_printf(("5http_sspi_make_credentials: malloc failed for %d bytes", dwSize));
ok = FALSE;
goto cleanup;
}
- if (!CertStrToName(X509_ASN_ENCODING, cn, CERT_OID_NAME_STR, NULL,
- p, &dwSize, NULL))
+ if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL))
{
- DEBUG_printf(("_sspiGetCredentials: CertStrToName failed: %x",
- GetLastError()));
+ DEBUG_printf(("5http_sspi_make_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
ok = FALSE;
goto cleanup;
}
- sib.cbData = dwSize;
- sib.pbData = p;
-
- storedContext = CertFindCertificateInStore(store, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING,
- 0, CERT_FIND_SUBJECT_NAME, &sib, NULL);
+ /*
+ * Create a private key and self-signed certificate...
+ */
- if (!storedContext)
+ if (!CryptGenKey(hProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE, &hKey))
{
- /*
- * If we couldn't find the context, then we'll
- * create a new one
- */
- if (!CryptGenKey(hProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE, &hKey))
- {
- DEBUG_printf(("_sspiGetCredentials: CryptGenKey failed: %x",
- GetLastError()));
- ok = FALSE;
- goto cleanup;
- }
+ DEBUG_printf(("5http_sspi_make_credentials: CryptGenKey failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
+ ok = FALSE;
+ goto cleanup;
+ }
- ZeroMemory(&kpi, sizeof(kpi));
- kpi.pwszContainerName = (LPWSTR) container;
- kpi.pwszProvName = MS_DEF_PROV_W;
- kpi.dwProvType = PROV_RSA_FULL;
- kpi.dwFlags = CERT_SET_KEY_CONTEXT_PROP_ID;
- kpi.dwKeySpec = AT_KEYEXCHANGE;
+ ZeroMemory(&kpi, sizeof(kpi));
+ kpi.pwszContainerName = (LPWSTR)container;
+ kpi.pwszProvName = MS_DEF_PROV_W;
+ kpi.dwProvType = PROV_RSA_FULL;
+ kpi.dwFlags = CERT_SET_KEY_CONTEXT_PROP_ID;
+ kpi.dwKeySpec = AT_KEYEXCHANGE;
- GetSystemTime(&et);
- et.wYear += 10;
+ GetSystemTime(&et);
+ et.wYear += years;
- ZeroMemory(&exts, sizeof(exts));
+ ZeroMemory(&exts, sizeof(exts));
- createdContext = CertCreateSelfSignCertificate(hProv, &sib, 0, &kpi, NULL, NULL,
- &et, &exts);
+ createdContext = CertCreateSelfSignCertificate(hProv, &sib, 0, &kpi, NULL, NULL, &et, &exts);
- if (!createdContext)
- {
- DEBUG_printf(("_sspiGetCredentials: CertCreateSelfSignCertificate failed: %x",
- GetLastError()));
- ok = FALSE;
- goto cleanup;
- }
+ if (!createdContext)
+ {
+ DEBUG_printf(("5http_sspi_make_credentials: CertCreateSelfSignCertificate failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
+ ok = FALSE;
+ goto cleanup;
+ }
- if (!CertAddCertificateContextToStore(store, createdContext,
- CERT_STORE_ADD_REPLACE_EXISTING,
- &storedContext))
- {
- DEBUG_printf(("_sspiGetCredentials: CertAddCertificateContextToStore failed: %x",
- GetLastError()));
- ok = FALSE;
- goto cleanup;
- }
+ /*
+ * Add the created context to the named store, and associate it with the named
+ * container...
+ */
- ZeroMemory(&ckp, sizeof(ckp));
- ckp.pwszContainerName = (LPWSTR) container;
- ckp.pwszProvName = MS_DEF_PROV_W;
- ckp.dwProvType = PROV_RSA_FULL;
- ckp.dwFlags = CRYPT_MACHINE_KEYSET;
- ckp.dwKeySpec = AT_KEYEXCHANGE;
+ if (!CertAddCertificateContextToStore(store, createdContext, CERT_STORE_ADD_REPLACE_EXISTING, &storedContext))
+ {
+ DEBUG_printf(("5http_sspi_make_credentials: CertAddCertificateContextToStore failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
+ ok = FALSE;
+ goto cleanup;
+ }
- if (!CertSetCertificateContextProperty(storedContext,
- CERT_KEY_PROV_INFO_PROP_ID,
- 0, &ckp))
- {
- DEBUG_printf(("_sspiGetCredentials: CertSetCertificateContextProperty failed: %x",
- GetLastError()));
- ok = FALSE;
- goto cleanup;
- }
+ ZeroMemory(&ckp, sizeof(ckp));
+ ckp.pwszContainerName = (LPWSTR) container;
+ ckp.pwszProvName = MS_DEF_PROV_W;
+ ckp.dwProvType = PROV_RSA_FULL;
+ ckp.dwFlags = CRYPT_MACHINE_KEYSET;
+ ckp.dwKeySpec = AT_KEYEXCHANGE;
+
+ if (!CertSetCertificateContextProperty(storedContext, CERT_KEY_PROV_INFO_PROP_ID, 0, &ckp))
+ {
+ DEBUG_printf(("5http_sspi_make_credentials: CertSetCertificateContextProperty failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
+ ok = FALSE;
+ goto cleanup;
}
+ /*
+ * Get a handle to use the certificate...
+ */
+
ZeroMemory(&SchannelCred, sizeof(SchannelCred));
SchannelCred.dwVersion = SCHANNEL_CRED_VERSION;
- SchannelCred.cCreds = 1;
- SchannelCred.paCred = &storedContext;
+ SchannelCred.cCreds = 1;
+ SchannelCred.paCred = &storedContext;
/*
- * SSPI doesn't seem to like it if grbitEnabledProtocols
- * is set for a client
+ * SSPI doesn't seem to like it if grbitEnabledProtocols is set for a client.
*/
- if (isServer)
+
+ if (mode == _HTTP_MODE_SERVER)
SchannelCred.grbitEnabledProtocols = SP_PROT_SSL3TLS1;
/*
* Create an SSPI credential.
*/
- Status = AcquireCredentialsHandle(NULL, UNISP_NAME,
- isServer ? SECPKG_CRED_INBOUND:SECPKG_CRED_OUTBOUND,
- NULL, &SchannelCred, NULL, NULL, &conn->creds,
- &tsExpiry);
+
+ Status = AcquireCredentialsHandle(NULL, UNISP_NAME, mode == _HTTP_MODE_SERVER ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND, NULL, &SchannelCred, NULL, NULL, &sspi->creds, &tsExpiry);
if (Status != SEC_E_OK)
{
- DEBUG_printf(("_sspiGetCredentials: AcquireCredentialsHandle failed: %x", Status));
+ DEBUG_printf(("5http_sspi_make_credentials: AcquireCredentialsHandle failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), Status)));
ok = FALSE;
goto cleanup;
}
/*
* Cleanup
*/
+
if (hKey)
CryptDestroyKey(hKey);
return (ok);
}
-#endif // 0
/*
http_sspi_server(http_t *http, /* I - HTTP connection */
const char *hostname) /* I - Hostname of server */
{
- _http_sspi_t *conn = http->tls; /* I - SSPI data */
+ _http_sspi_t *sspi = http->tls; /* I - SSPI data */
+ char common_name[512]; /* Common name for cert */
DWORD dwSSPIFlags; /* SSL connection attributes we want */
DWORD dwSSPIOutFlags; /* SSL connection attributes we got */
TimeStamp tsExpiry; /* Time stamp */
int ret = 0; /* Return value */
- DEBUG_printf(("http_sspi_server(http=%p, hostname=\"%s\")", http, hostname));
+ DEBUG_printf(("4http_sspi_server(http=%p, hostname=\"%s\")", http, hostname));
dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT |
ASC_REQ_REPLAY_DETECT |
ASC_REQ_ALLOCATE_MEMORY |
ASC_REQ_STREAM;
- conn->decryptBufferUsed = 0;
+ sspi->decryptBufferUsed = 0;
+
+ /*
+ * Lookup the server certificate...
+ */
+
+ snprintf(common_name, sizeof(common_name), "CN=%s", hostname);
+
+ if (!http_sspi_find_credentials(http, L"ServerContainer", common_name))
+ if (!http_sspi_make_credentials(http->tls, L"ServerContainer", common_name, _HTTP_MODE_SERVER, 10))
+ {
+ DEBUG_puts("5http_sspi_server: Unable to get server credentials.");
+ return (-1);
+ }
/*
* Set OutBuffer for AcceptSecurityContext call
scRet == SEC_E_INCOMPLETE_MESSAGE ||
scRet == SEC_I_INCOMPLETE_CREDENTIALS)
{
- if (conn->decryptBufferUsed == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE)
+ if (sspi->decryptBufferUsed == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE)
{
- if (conn->decryptBufferLength <= conn->decryptBufferUsed)
+ if (sspi->decryptBufferLength <= sspi->decryptBufferUsed)
{
BYTE *temp; /* New buffer */
- if (conn->decryptBufferLength >= 262144)
+ if (sspi->decryptBufferLength >= 262144)
{
WSASetLastError(E_OUTOFMEMORY);
- DEBUG_puts("http_sspi_server: Decryption buffer too large (>256k)");
+ DEBUG_puts("5http_sspi_server: Decryption buffer too large (>256k)");
return (-1);
}
- if ((temp = realloc(conn->decryptBuffer, conn->decryptBufferLength + 4096)) == NULL)
+ if ((temp = realloc(sspi->decryptBuffer, sspi->decryptBufferLength + 4096)) == NULL)
{
- DEBUG_printf(("http_sspi_server: Unable to allocate %d byte buffer.", conn->decryptBufferLength + 4096));
+ DEBUG_printf(("5http_sspi_server: Unable to allocate %d byte buffer.", sspi->decryptBufferLength + 4096));
WSASetLastError(E_OUTOFMEMORY);
return (-1);
}
- conn->decryptBufferLength += 4096;
- conn->decryptBuffer = temp;
+ sspi->decryptBufferLength += 4096;
+ sspi->decryptBuffer = temp;
}
for (;;)
{
- num = recv(http->fd, conn->decryptBuffer + conn->decryptBufferUsed, (int)(conn->decryptBufferLength - conn->decryptBufferUsed), 0);
+ num = recv(http->fd, sspi->decryptBuffer + sspi->decryptBufferUsed, (int)(sspi->decryptBufferLength - sspi->decryptBufferUsed), 0);
if (num == -1 && WSAGetLastError() == WSAEWOULDBLOCK)
Sleep(1);
if (num < 0)
{
- DEBUG_printf(("http_sspi_server: recv failed: %d", WSAGetLastError()));
+ DEBUG_printf(("5http_sspi_server: recv failed: %d", WSAGetLastError()));
return (-1);
}
else if (num == 0)
{
- DEBUG_puts("http_sspi_server: client disconnected");
+ DEBUG_puts("5http_sspi_server: client disconnected");
return (-1);
}
- DEBUG_printf(("http_sspi_server: received %d (handshake) bytes from client.", num));
- conn->decryptBufferUsed += num;
+ DEBUG_printf(("5http_sspi_server: received %d (handshake) bytes from client.", num));
+ sspi->decryptBufferUsed += num;
}
/*
* on this run around the loop.
*/
- inBuffers[0].pvBuffer = conn->decryptBuffer;
- inBuffers[0].cbBuffer = (unsigned long)conn->decryptBufferUsed;
+ inBuffers[0].pvBuffer = sspi->decryptBuffer;
+ inBuffers[0].cbBuffer = (unsigned long)sspi->decryptBufferUsed;
inBuffers[0].BufferType = SECBUFFER_TOKEN;
inBuffers[1].pvBuffer = NULL;
outBuffers[0].BufferType = SECBUFFER_TOKEN;
outBuffers[0].cbBuffer = 0;
- scRet = AcceptSecurityContext(&conn->creds, (fInitContext?NULL:&conn->context), &inBuffer, dwSSPIFlags, SECURITY_NATIVE_DREP, (fInitContext?&conn->context:NULL), &outBuffer, &dwSSPIOutFlags, &tsExpiry);
+ scRet = AcceptSecurityContext(&sspi->creds, (fInitContext?NULL:&sspi->context), &inBuffer, dwSSPIFlags, SECURITY_NATIVE_DREP, (fInitContext?&sspi->context:NULL), &outBuffer, &dwSSPIOutFlags, &tsExpiry);
fInitContext = FALSE;
if (num <= 0)
{
- DEBUG_printf(("http_sspi_server: handshake send failed: %d", WSAGetLastError()));
+ DEBUG_printf(("5http_sspi_server: handshake send failed: %d", WSAGetLastError()));
return (-1);
}
- DEBUG_printf(("http_sspi_server: sent %d handshake bytes to client.", outBuffers[0].cbBuffer));
+ DEBUG_printf(("5http_sspi_server: sent %d handshake bytes to client.", outBuffers[0].cbBuffer));
FreeContextBuffer(outBuffers[0].pvBuffer);
outBuffers[0].pvBuffer = NULL;
if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
{
- memcpy(conn->decryptBuffer, (LPBYTE)(conn->decryptBuffer + conn->decryptBufferUsed - inBuffers[1].cbBuffer), inBuffers[1].cbBuffer);
- conn->decryptBufferUsed = inBuffers[1].cbBuffer;
+ memcpy(sspi->decryptBuffer, (LPBYTE)(sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer), inBuffers[1].cbBuffer);
+ sspi->decryptBufferUsed = inBuffers[1].cbBuffer;
}
else
{
- conn->decryptBufferUsed = 0;
+ sspi->decryptBufferUsed = 0;
}
break;
}
else if (FAILED(scRet) && scRet != SEC_E_INCOMPLETE_MESSAGE)
{
- DEBUG_printf(("http_sspi_server: AcceptSecurityContext failed: %x", scRet));
+ DEBUG_printf(("5http_sspi_server: AcceptSecurityContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
ret = -1;
break;
}
{
if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
{
- memcpy(conn->decryptBuffer, (LPBYTE)(conn->decryptBuffer + conn->decryptBufferUsed - inBuffers[1].cbBuffer), inBuffers[1].cbBuffer);
- conn->decryptBufferUsed = inBuffers[1].cbBuffer;
+ memcpy(sspi->decryptBuffer, (LPBYTE)(sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer), inBuffers[1].cbBuffer);
+ sspi->decryptBufferUsed = inBuffers[1].cbBuffer;
}
else
{
- conn->decryptBufferUsed = 0;
+ sspi->decryptBufferUsed = 0;
}
}
}
if (!ret)
{
- conn->contextInitialized = TRUE;
+ sspi->contextInitialized = TRUE;
/*
* Find out how big the header will be:
*/
- scRet = QueryContextAttributes(&conn->context, SECPKG_ATTR_STREAM_SIZES, &conn->streamSizes);
+ scRet = QueryContextAttributes(&sspi->context, SECPKG_ATTR_STREAM_SIZES, &sspi->streamSizes);
if (scRet != SEC_E_OK)
{
- DEBUG_printf(("http_sspi_server: QueryContextAttributes failed: %x", scRet));
+ DEBUG_printf(("5http_sspi_server: QueryContextAttributes failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
ret = -1;
}
}
}
-#if 0
/*
- * '_sspiSetAllowsAnyRoot()' - Set the client cert policy for untrusted root certs
+ * 'http_sspi_strerror()' - Return a string for the specified error code.
*/
-void
-_sspiSetAllowsAnyRoot(_http_sspi_t *conn,
- /* I - Client connection */
- BOOL allow)
- /* I - Allow any root */
+
+static const char * /* O - String for error */
+http_sspi_strerror(char *buffer, /* I - Error message buffer */
+ size_t bufsize, /* I - Size of buffer */
+ DWORD code) /* I - Error code */
{
- conn->certFlags = (allow) ? conn->certFlags | SECURITY_FLAG_IGNORE_UNKNOWN_CA :
- conn->certFlags & ~SECURITY_FLAG_IGNORE_UNKNOWN_CA;
-}
+ if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, code, 0, buffer, bufsize, NULL))
+ {
+ /*
+ * Strip trailing CR + LF...
+ */
+ char *ptr; /* Pointer into error message */
-/*
- * '_sspiSetAllowsExpiredCerts()' - Set the client cert policy for expired root certs
- */
-void
-_sspiSetAllowsExpiredCerts(_http_sspi_t *conn,
- /* I - Client connection */
- BOOL allow)
- /* I - Allow expired certs */
-{
- conn->certFlags = (allow) ? conn->certFlags | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID :
- conn->certFlags & ~SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
+ for (ptr = buffer + strlen(buffer) - 1; ptr >= buffer; ptr --)
+ if (*ptr == '\n' || *ptr == '\r')
+ *ptr = '\0';
+ else
+ break;
+ }
+ else
+ snprintf(buffer, bufsize, "Unknown error %x", code);
+
+ return (buffer);
}
/* Number of ites in rgszUsages */
DWORD count; /* 32 bit count variable */
DWORD status; /* Return value */
+#ifdef DEBUG
+ char error[1024]; /* Error message string */
+#endif /* DEBUG */
if (!cert)
if (!CertGetCertificateChain(NULL, cert, NULL, cert->hCertStore, &chainPara, 0, NULL, &chainContext))
{
status = GetLastError();
- DEBUG_printf(("CertGetCertificateChain returned 0x%x\n", status));
+
+ DEBUG_printf(("CertGetCertificateChain returned: %s", http_sspi_strerror(error, sizeof(error), status)));
LocalFree(commonNameUnicode);
return (status);
if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chainContext, &policyPara, &policyStatus))
{
status = GetLastError();
- DEBUG_printf(("CertVerifyCertificateChainPolicy returned %d", status));
+
+ DEBUG_printf(("CertVerifyCertificateChainPolicy returned %s", http_sspi_strerror(error, sizeof(error), status)));
}
else if (policyStatus.dwError)
status = policyStatus.dwError;
return (status);
}
-#endif // 0
/*