From: msweet Date: Thu, 17 Jul 2014 21:21:21 +0000 (+0000) Subject: Save work on SSPI certificate functions for validation and info. X-Git-Tag: v2.2b1~556 X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fcups.git;a=commitdiff_plain;h=17eecbf1d82fc87361012c11a5d288763707aaf9;hp=e32497ad0cbacd5abf9458556b6f2b73959c1e66 Save work on SSPI certificate functions for validation and info. git-svn-id: svn+ssh://src.apple.com/svn/cups/cups.org/trunk@12044 a1ca3aef-8c08-0410-bb20-df032aa958be --- diff --git a/cups/http-private.h b/cups/http-private.h index 7fdb5fd5d..694cc84af 100644 --- a/cups/http-private.h +++ b/cups/http-private.h @@ -222,13 +222,12 @@ typedef struct _http_sspi_s /**** SSPI/SSL data structure ****/ int readBufferUsed; /* Bytes used in buffer */ BYTE *writeBuffer; /* Data pre-encryption */ int writeBufferLength; /* Length of write buffer */ - DWORD certFlags; /* Cert verification flags */ PCCERT_CONTEXT localCert, /* Local certificate */ remoteCert; /* Remote (peer's) certificate */ char error[256]; /* Most recent error message */ } _http_sspi_t; typedef _http_sspi_t *http_tls_t; -typedef void *http_tls_credentials_t; +typedef PCCERT_CONTEXT http_tls_credentials_t; # else /* diff --git a/cups/tls-sspi.c b/cups/tls-sspi.c index 26823d9a7..fcebb7ee4 100644 --- a/cups/tls-sspi.c +++ b/cups/tls-sspi.c @@ -48,6 +48,7 @@ static _http_sspi_t *http_sspi_alloc(void); static int http_sspi_client(http_t *http, const char *hostname); +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); @@ -147,9 +148,7 @@ http_tls_credentials_t /* O - Internal credentials */ _httpCreateCredentials( cups_array_t *credentials) /* I - Array of credentials */ { - (void)credentials; - - return (NULL); + return (http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials))); } @@ -164,10 +163,47 @@ httpCredentialsAreValidForName( 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))) + 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 (1); + return (valid); } @@ -182,68 +218,32 @@ httpCredentialsGetTrust( 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); } @@ -259,9 +259,30 @@ 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 */ - return (INT_MAX); + 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); + + CertFreeCertificateContext(cert); + } + + return (expiration_date); } @@ -277,6 +298,11 @@ httpCredentialsString( 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) @@ -285,39 +311,39 @@ httpCredentialsString( 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) - { - CFStringGetCString(cf_name, name, (CFIndex)sizeof(name), kCFStringEncodingUTF8); - CFRelease(cf_name); - } - else - strlcpy(name, "unknown", sizeof(name)); + 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); - expiration = (time_t)(SecCertificateNotValidAfter(secCert) + kCFAbsoluteTimeIntervalSince1970); + if (!CertNameToStr(X509_ASN_ENCODING, cert->pCertInfo->Subject, CERT_SIMPLE_NAME_STR, cert_name, sizeof(cert_name))) + 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)); @@ -335,6 +361,8 @@ _httpFreeCredentials( { if (!credentials) return; + + CertFreeCertificateContext(credentials); } @@ -1333,18 +1361,6 @@ http_sspi_client(http_t *http, /* I - Client connection */ return (-1); } -#if 0 - /* TODO: Move this out for opt-in server cert validation, like other platforms. */ - scRet = http_sspi_verify(sspi->remoteCert, hostname, sspi->certFlags); - - if (scRet != SEC_E_OK) - { - DEBUG_printf(("http_sspi_client: sspi_verify_certificate failed: %s", http_sspi_strerror(sspi, scRet))); - ret = -1; - goto cleanup; - } -#endif // 0 - /* * Find out how big the header/trailer will be: */ @@ -1362,6 +1378,21 @@ http_sspi_client(http_t *http, /* I - Client connection */ } +/* + * '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. */ @@ -2071,36 +2102,6 @@ http_sspi_verify( } -#if 0 -/* - * '_sspiSetAllowsAnyRoot()' - Set the client cert policy for untrusted root certs - */ -void -_sspiSetAllowsAnyRoot(_http_sspi_t *sspi, - /* I - SSPI data */ - BOOL allow) - /* I - Allow any root */ -{ - sspi->certFlags = (allow) ? sspi->certFlags | SECURITY_FLAG_IGNORE_UNKNOWN_CA : - sspi->certFlags & ~SECURITY_FLAG_IGNORE_UNKNOWN_CA; -} - - -/* - * '_sspiSetAllowsExpiredCerts()' - Set the client cert policy for expired root certs - */ -void -_sspiSetAllowsExpiredCerts(_http_sspi_t *sspi, - /* I - SSPI data */ - BOOL allow) - /* I - Allow expired certs */ -{ - sspi->certFlags = (allow) ? sspi->certFlags | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID : - sspi->certFlags & ~SECURITY_FLAG_IGNORE_CERT_DATE_INVALID; -} -#endif // 0 - - /* * End of "$Id$". */ diff --git a/xcode/CUPS.xcodeproj/project.pbxproj b/xcode/CUPS.xcodeproj/project.pbxproj index 6914ff670..bff5aa036 100644 --- a/xcode/CUPS.xcodeproj/project.pbxproj +++ b/xcode/CUPS.xcodeproj/project.pbxproj @@ -1181,7 +1181,6 @@ /* Begin PBXFileReference section */ 270B267D17F5C06700C8A3A9 /* tls-darwin.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "tls-darwin.c"; path = "../cups/tls-darwin.c"; sourceTree = ""; }; 270B267E17F5C06700C8A3A9 /* tls-gnutls.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "tls-gnutls.c"; path = "../cups/tls-gnutls.c"; sourceTree = ""; }; - 270B268017F5C5D600C8A3A9 /* sspi-private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "sspi-private.h"; path = "../cups/sspi-private.h"; sourceTree = ""; }; 270B268117F5C5D600C8A3A9 /* tls-sspi.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "tls-sspi.c"; path = "../cups/tls-sspi.c"; sourceTree = ""; }; 270CCDA7135E3C9E00007BE2 /* testmime */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testmime; sourceTree = BUILT_PRODUCTS_DIR; }; 270CCDBB135E3D3E00007BE2 /* testmime.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = testmime.c; path = ../scheduler/testmime.c; sourceTree = ""; }; @@ -2069,7 +2068,6 @@ 270B267D17F5C06700C8A3A9 /* tls-darwin.c */, 270B267E17F5C06700C8A3A9 /* tls-gnutls.c */, 270B268117F5C5D600C8A3A9 /* tls-sspi.c */, - 270B268017F5C5D600C8A3A9 /* sspi-private.h */, 72220F06133305BB00FCA411 /* transcode.c */, 72220F08133305BB00FCA411 /* usersys.c */, 72220F09133305BB00FCA411 /* util.c */,