static HRESULT WINAPI WINTRUST_DefaultPolicy(CRYPT_PROVIDER_DATA *pProvData, DWORD dwStepError, DWORD dwRegPolicySettings, DWORD cSigner, PWTD_GENERIC_CHAIN_POLICY_SIGNER_INFO rgpSigner, void *pvPolicyArg) { DWORD i; CERT_CHAIN_POLICY_STATUS policyStatus = { sizeof(policyStatus), 0 }; for (i = 0; !policyStatus.dwError && i < cSigner; i++) { CERT_CHAIN_POLICY_PARA policyPara = { sizeof(policyPara), 0 }; if (dwRegPolicySettings & WTPF_IGNOREEXPIRATION) policyPara.dwFlags |= CERT_CHAIN_POLICY_IGNORE_NOT_TIME_VALID_FLAG | CERT_CHAIN_POLICY_IGNORE_CTL_NOT_TIME_VALID_FLAG | CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG; if (dwRegPolicySettings & WTPF_IGNOREREVOKATION) policyPara.dwFlags |= CERT_CHAIN_POLICY_IGNORE_END_REV_UNKNOWN_FLAG | CERT_CHAIN_POLICY_IGNORE_CTL_SIGNER_REV_UNKNOWN_FLAG | CERT_CHAIN_POLICY_IGNORE_CA_REV_UNKNOWN_FLAG | CERT_CHAIN_POLICY_IGNORE_ROOT_REV_UNKNOWN_FLAG; CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_BASE, rgpSigner[i].pChainContext, &policyPara, &policyStatus); } return policyStatus.dwError; }
/* Helper for windows_ssl_server_trust_first_credentials for validating * certificate using CryptoApi. Sets *OK_P to TRUE if base64 encoded ASCII_CERT * certificate considered as valid. */ static svn_error_t * windows_validate_certificate(svn_boolean_t *ok_p, const char *ascii_cert, apr_pool_t *pool) { PCCERT_CONTEXT cert_context = NULL; CERT_CHAIN_PARA chain_para; PCCERT_CHAIN_CONTEXT chain_context = NULL; *ok_p = FALSE; /* Parse the certificate into a context. */ cert_context = certcontext_from_base64(ascii_cert, pool); if (cert_context) { /* Retrieve the certificate chain of the certificate (a certificate without a valid root does not have a chain). */ memset(&chain_para, 0, sizeof(chain_para)); chain_para.cbSize = sizeof(chain_para); if (CertGetCertificateChain(NULL, cert_context, NULL, NULL, &chain_para, CERT_CHAIN_CACHE_END_CERT | CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT, NULL, &chain_context)) { CERT_CHAIN_POLICY_PARA policy_para; CERT_CHAIN_POLICY_STATUS policy_status; policy_para.cbSize = sizeof(policy_para); policy_para.dwFlags = 0; policy_para.pvExtraPolicyPara = NULL; policy_status.cbSize = sizeof(policy_status); if (CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chain_context, &policy_para, &policy_status)) { if (policy_status.dwError == S_OK) { /* Windows thinks the certificate is valid. */ *ok_p = TRUE; } } CertFreeCertificateChain(chain_context); } CertFreeCertificateContext(cert_context); } return SVN_NO_ERROR; }
bool CertificateVerifier::VerifyCertificate_( PCCERT_CONTEXT certificate, LPWSTR server_name,int &windows_error_code) const { windows_error_code = 0; LPSTR usage_identifier[] = { szOID_PKIX_KP_SERVER_AUTH, szOID_SERVER_GATED_CRYPTO, szOID_SGC_NETSCAPE }; CERT_CHAIN_PARA params = { sizeof( params ) }; params.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR; params.RequestedUsage.Usage.cUsageIdentifier = _countof( usage_identifier ); params.RequestedUsage.Usage.rgpszUsageIdentifier = usage_identifier; PCCERT_CHAIN_CONTEXT chain_context = 0; if (!CertGetCertificateChain(NULL, certificate, NULL, NULL, ¶ms, CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT, NULL, &chain_context)) { windows_error_code = GetLastError(); return false; } SSL_EXTRA_CERT_CHAIN_POLICY_PARA sslPolicy = { sizeof( sslPolicy ) }; sslPolicy.dwAuthType = AUTHTYPE_SERVER; sslPolicy.pwszServerName = server_name; CERT_CHAIN_POLICY_PARA policy = { sizeof( policy ) }; policy.pvExtraPolicyPara = &sslPolicy; CERT_CHAIN_POLICY_STATUS status = { sizeof( status ) }; BOOL policy_checked = CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chain_context, &policy, &status ); CertFreeCertificateChain( chain_context ); windows_error_code = status.dwError; bool certificate_ok = policy_checked && status.dwError == 0; return certificate_ok; }
/***************************************************************************** wmain *****************************************************************************/ DWORD __cdecl wmain( int argc, LPWSTR argv[] ) { HRESULT hr = S_OK; BOOL fSign = TRUE; LPCWSTR pwszInputFile = NULL; LPCWSTR pwszOutputFile = NULL; BYTE *pbInput = NULL; DWORD cbInput = 0; BYTE *pbOutput = NULL; DWORD cbOutput = 0; CERT_CHAIN_PARA ChainPara = {0}; CERT_CHAIN_POLICY_PARA ChainPolicy = {0}; CERT_CHAIN_POLICY_STATUS PolicyStatus = {0}; PCCERT_CHAIN_CONTEXT pChain = NULL; PCCERT_CONTEXT pSignerCert = NULL; HCERTSTORE hStoreHandle = NULL; LPCWSTR pwszStoreName = L"MY"; // by default LPCWSTR pwszCName = L"Test"; // by default LPCWSTR wszHashAlgName = L"SHA1"; int i; // // options // for( i=1; i<argc; i++ ) { if ( lstrcmpW (argv[i], L"/?") == 0 || lstrcmpW (argv[i], L"-?") == 0 ) { Usage( L"cms_sign.exe" ); goto CleanUp; } if( *argv[i] != L'-' ) break; if ( lstrcmpW (argv[i], L"-s") == 0 ) { if( i+1 >= argc ) { hr = E_INVALIDARG; goto CleanUp; } pwszStoreName = argv[++i]; } else if ( lstrcmpW (argv[i], L"-n") == 0 ) { if( i+1 >= argc ) { hr = E_INVALIDARG; goto CleanUp; } pwszCName = argv[++i]; } else if ( lstrcmpW (argv[i], L"-a") == 0 ) { if( i+1 >= argc ) { hr = E_INVALIDARG; goto CleanUp; } wszHashAlgName = argv[++i]; } } if( 0 == lstrcmpW (argv[i], L"SIGN")) { if( i+2 >= argc ) { hr = E_INVALIDARG; goto CleanUp; } fSign = TRUE; pwszInputFile = argv[++i]; pwszOutputFile = argv[++i]; } else if( 0 == lstrcmpW (argv[i], L"VERIFY")) { if( i+1 >= argc ) { hr = E_INVALIDARG; goto CleanUp; } fSign = FALSE; pwszInputFile = argv[++i]; } else { hr = E_INVALIDARG; goto CleanUp; } if( i != argc-1 ) { hr = E_INVALIDARG; goto CleanUp; } //------------------------------------------------------------------- // Open the certificate store to be searched. hStoreHandle = CertOpenStore( CERT_STORE_PROV_SYSTEM, // the store provider type 0, // the encoding type is not needed NULL, // use the default HCRYPTPROV CERT_SYSTEM_STORE_CURRENT_USER, // set the store location in a // registry location pwszStoreName ); // the store name if( NULL == hStoreHandle ) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto CleanUp; } // // Load file // hr = HrLoadFile( pwszInputFile, &pbInput, &cbInput ); if( FAILED(hr) ) { wprintf( L"Unable to read file: %s\n", pwszInputFile ); goto CleanUp; } if( fSign ) { //------------------------------------------------------------------- // Sign Message PCCRYPT_OID_INFO pOidInfo = NULL; CRYPT_SIGN_MESSAGE_PARA SigParams = {0}; // Create the MessageArray and the MessageSizeArray. const BYTE* MessageArray[] = {pbInput}; DWORD MessageSizeArray[] = {cbInput}; // // Get a certificate that has the specified Subject Name // pSignerCert = CertFindCertificateInStore( hStoreHandle, X509_ASN_ENCODING , // Use X509_ASN_ENCODING 0, // No dwFlags needed CERT_FIND_SUBJECT_STR, // Find a certificate with a // subject that matches the // string in the next parameter pwszCName, // The Unicode string to be found // in a certificate's subject NULL); // NULL for the first call to the // function; In all subsequent // calls, it is the last pointer // returned by the function if( NULL == pSignerCert ) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto CleanUp; } // // Build a chain in order to include certs to the message // if( !CertGetCertificateChain( NULL, // use the default chain engine pSignerCert, // pointer to the end certificate NULL, // use the default time NULL, // search no additional stores &ChainPara, // use AND logic and enhanced key usage // as indicated in the ChainPara // data structure CERT_CHAIN_REVOCATION_CHECK_END_CERT, NULL, // currently reserved &pChain )) // return a pointer to the chain created { hr = HRESULT_FROM_WIN32( GetLastError() ); goto CleanUp; } // // Verify that the chain complies with Base policy // ChainPolicy.cbSize = sizeof(CERT_CHAIN_POLICY_PARA); ChainPolicy.dwFlags = 0; PolicyStatus.cbSize = sizeof(CERT_CHAIN_POLICY_STATUS); ChainPolicy.pvExtraPolicyPara = NULL; if (!CertVerifyCertificateChainPolicy( CERT_CHAIN_POLICY_BASE, pChain, &ChainPolicy, &PolicyStatus)) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto CleanUp; } if( PolicyStatus.dwError != S_OK ) { ReportError( L"Base Policy Chain Status Failure:", PolicyStatus.dwError ); hr = PolicyStatus.dwError; } // Initialize the signature structure. SigParams.cbSize = sizeof(SigParams); SigParams.dwMsgEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING; SigParams.pSigningCert = pSignerCert; SigParams.cAuthAttr = 0; SigParams.dwInnerContentType = 0; SigParams.cMsgCrl = 0; SigParams.cUnauthAttr = 0; SigParams.dwFlags = 0; SigParams.pvHashAuxInfo = NULL; SigParams.rgAuthAttr = NULL; // // Addd max of 8 certs to the message // PCCERT_CONTEXT rgpMsgCert[8] = {NULL}; SigParams.rgpMsgCert = rgpMsgCert; for( SigParams.cMsgCert=0; SigParams.cMsgCert<pChain->rgpChain[0]->cElement && SigParams.cMsgCert<8; SigParams.cMsgCert++ ) { rgpMsgCert[SigParams.cMsgCert] = pChain->rgpChain[0]->rgpElement[SigParams.cMsgCert]->pCertContext; } // // Find OID // pOidInfo = CryptFindOIDInfo( CRYPT_OID_INFO_NAME_KEY, (void*)wszHashAlgName, CRYPT_HASH_ALG_OID_GROUP_ID ); if( NULL == pOidInfo ) { hr = CRYPT_E_UNKNOWN_ALGO; goto CleanUp; } SigParams.HashAlgorithm.pszObjId = (LPSTR)pOidInfo->pszOID; // First, get the size of the signed BLOB. if( !CryptSignMessage( &SigParams, FALSE, 1, MessageArray, &cbInput, NULL, &cbOutput )) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto CleanUp; } // Allocate memory for the signed BLOB. pbOutput = (BYTE*)LocalAlloc( LPTR, cbOutput ); if( NULL == pbOutput ) { hr = HRESULT_FROM_WIN32( ERROR_OUTOFMEMORY ); goto CleanUp; } // Get the signed message BLOB. if( !CryptSignMessage( &SigParams, FALSE, 1, MessageArray, MessageSizeArray, pbOutput, &cbOutput )) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto CleanUp; } hr = HrSaveFile( pwszOutputFile, pbOutput, cbOutput ); if( FAILED(hr) ) { wprintf( L"Unable to save file: %s\n", pwszOutputFile ); goto CleanUp; } wprintf( L"Successfully signed message using CryptSignMessage.\n"); } else { //------------------------------------------------------------------- // Verify signed message CRYPT_VERIFY_MESSAGE_PARA VerifyParams = {0}; VerifyParams.cbSize = sizeof(VerifyParams); VerifyParams.dwMsgAndCertEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING; VerifyParams.hCryptProv = 0; VerifyParams.pfnGetSignerCertificate = NULL; VerifyParams.pvGetArg = NULL; // First, call CryptVerifyMessageSignature to get the length // of the buffer needed to hold the decoded message. if( !CryptVerifyMessageSignature( &VerifyParams, 0, pbInput, cbInput, NULL, &cbOutput, NULL)) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto CleanUp; } pbOutput = (BYTE*)LocalAlloc( LPTR, cbOutput ); if( NULL == pbOutput ) { hr = HRESULT_FROM_WIN32( ERROR_OUTOFMEMORY ); goto CleanUp; } //--------------------------------------------------------------- // Call CryptVerifyMessageSignature again to verify the signature // and, if successful, copy the decoded message into the buffer. if( !CryptVerifyMessageSignature( &VerifyParams, 0, pbInput, cbInput, pbOutput, &cbOutput, &pSignerCert)) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto CleanUp; } wprintf( L"Successfully verified signed message using CryptVerifyMessageSignature.\n"); // // Build a chain in order to verify certificate trust // // // Instruction : Create a certificate store from the CMS message and provide as a parameter to // CertGetCertificateChain. This will ensure that all additional certificates from // the CMS message are used in chain building // Otherwise chain will be build using the local stores only. // if( !CertGetCertificateChain( NULL, // use the default chain engine pSignerCert, // pointer to the end certificate NULL, // use the default time NULL, // search no additional stores &ChainPara, // use AND logic and enhanced key usage // as indicated in the ChainPara // data structure CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT, NULL, // currently reserved &pChain )) // return a pointer to the chain created { hr = HRESULT_FROM_WIN32( GetLastError() ); goto CleanUp; } // // Verify that the chain complies with Base policy // ChainPolicy.cbSize = sizeof(CERT_CHAIN_POLICY_PARA); ChainPolicy.dwFlags = 0; PolicyStatus.cbSize = sizeof(CERT_CHAIN_POLICY_STATUS); ChainPolicy.pvExtraPolicyPara = NULL; if (!CertVerifyCertificateChainPolicy( CERT_CHAIN_POLICY_BASE, pChain, &ChainPolicy, &PolicyStatus)) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto CleanUp; } if( PolicyStatus.dwError != S_OK ) { ReportError( L"Base Policy Chain Status Failure:", PolicyStatus.dwError ); hr = PolicyStatus.dwError; } } hr = S_OK; //------------------------------------------------------------------- // Clean up memory. CleanUp: if( NULL != pbInput ) { LocalFree(pbInput); } if( NULL != pbOutput ) { LocalFree(pbOutput); } if( NULL != pChain ) { CertFreeCertificateChain(pChain); } if( NULL != pSignerCert ) { CertFreeCertificateContext(pSignerCert); } if( NULL != hStoreHandle) { CertCloseStore( hStoreHandle, 0 ); } if( FAILED( hr )) { ReportError( NULL, hr ); } return (DWORD)hr; } // End of main
/* * 'sspi_verify_certificate()' - Verify a server certificate */ static DWORD /* 0 - Error code (0 == No error) */ sspi_verify_certificate(PCCERT_CONTEXT serverCert, /* I - Server certificate */ const CHAR *serverName, /* I - Server name */ DWORD dwCertFlags) /* I - Verification flags */ { HTTPSPolicyCallbackData httpsPolicy; /* HTTPS Policy Struct */ CERT_CHAIN_POLICY_PARA policyPara; /* Cert chain policy parameters */ CERT_CHAIN_POLICY_STATUS policyStatus; /* Cert chain policy status */ CERT_CHAIN_PARA chainPara; /* Used for searching and matching criteria */ PCCERT_CHAIN_CONTEXT chainContext = NULL; /* Certificate chain */ PWSTR serverNameUnicode = NULL; /* Unicode server name */ LPSTR rgszUsages[] = { szOID_PKIX_KP_SERVER_AUTH, szOID_SERVER_GATED_CRYPTO, szOID_SGC_NETSCAPE }; /* How are we using this certificate? */ DWORD cUsages = sizeof(rgszUsages) / sizeof(LPSTR); /* Number of ites in rgszUsages */ DWORD count; /* 32 bit count variable */ DWORD status; /* Return value */ if (!serverCert) { status = SEC_E_WRONG_PRINCIPAL; goto cleanup; } /* * Convert server name to unicode. */ if (!serverName || (strlen(serverName) == 0)) { status = SEC_E_WRONG_PRINCIPAL; goto cleanup; } count = MultiByteToWideChar(CP_ACP, 0, serverName, -1, NULL, 0); serverNameUnicode = LocalAlloc(LMEM_FIXED, count * sizeof(WCHAR)); if (!serverNameUnicode) { status = SEC_E_INSUFFICIENT_MEMORY; goto cleanup; } count = MultiByteToWideChar(CP_ACP, 0, serverName, -1, serverNameUnicode, count); if (count == 0) { status = SEC_E_WRONG_PRINCIPAL; goto cleanup; } /* * Build certificate chain. */ ZeroMemory(&chainPara, sizeof(chainPara)); chainPara.cbSize = sizeof(chainPara); chainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR; chainPara.RequestedUsage.Usage.cUsageIdentifier = cUsages; chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = rgszUsages; if (!CertGetCertificateChain(NULL, serverCert, NULL, serverCert->hCertStore, &chainPara, 0, NULL, &chainContext)) { status = GetLastError(); DEBUG_printf(("CertGetCertificateChain returned 0x%x\n", status)); goto cleanup; } /* * Validate certificate chain. */ ZeroMemory(&httpsPolicy, sizeof(HTTPSPolicyCallbackData)); httpsPolicy.cbStruct = sizeof(HTTPSPolicyCallbackData); httpsPolicy.dwAuthType = AUTHTYPE_SERVER; httpsPolicy.fdwChecks = dwCertFlags; httpsPolicy.pwszServerName = serverNameUnicode; memset(&policyPara, 0, sizeof(policyPara)); policyPara.cbSize = sizeof(policyPara); policyPara.pvExtraPolicyPara = &httpsPolicy; memset(&policyStatus, 0, sizeof(policyStatus)); policyStatus.cbSize = sizeof(policyStatus); if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chainContext, &policyPara, &policyStatus)) { status = GetLastError(); DEBUG_printf(("CertVerifyCertificateChainPolicy returned %d", status)); goto cleanup; } if (policyStatus.dwError) { status = policyStatus.dwError; goto cleanup; } status = SEC_E_OK; cleanup: if (chainContext) CertFreeCertificateChain(chainContext); if (serverNameUnicode) LocalFree(serverNameUnicode); return (status); }
static bool VerifyCertificate(SslHandle *ssl, PCSTR pszServerName, DWORD dwCertFlags) { static LPSTR rgszUsages[] = { szOID_PKIX_KP_SERVER_AUTH, szOID_SERVER_GATED_CRYPTO, szOID_SGC_NETSCAPE }; CERT_CHAIN_PARA ChainPara = { 0 }; HTTPSPolicyCallbackData polHttps = { 0 }; CERT_CHAIN_POLICY_PARA PolicyPara = { 0 }; CERT_CHAIN_POLICY_STATUS PolicyStatus = { 0 }; PCCERT_CHAIN_CONTEXT pChainContext = NULL; PCCERT_CONTEXT pServerCert = NULL; DWORD scRet; PWSTR pwszServerName = mir_a2u(pszServerName); scRet = g_pSSPI->QueryContextAttributes(&ssl->hContext, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &pServerCert); if (scRet != SEC_E_OK) goto cleanup; if (pServerCert == NULL) { scRet = SEC_E_WRONG_PRINCIPAL; goto cleanup; } ChainPara.cbSize = sizeof(ChainPara); ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR; ChainPara.RequestedUsage.Usage.cUsageIdentifier = _countof(rgszUsages); ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = rgszUsages; if (!CertGetCertificateChain(NULL, pServerCert, NULL, pServerCert->hCertStore, &ChainPara, 0, NULL, &pChainContext)) { scRet = GetLastError(); goto cleanup; } polHttps.cbStruct = sizeof(HTTPSPolicyCallbackData); polHttps.dwAuthType = AUTHTYPE_SERVER; polHttps.fdwChecks = dwCertFlags; polHttps.pwszServerName = pwszServerName; PolicyPara.cbSize = sizeof(PolicyPara); PolicyPara.pvExtraPolicyPara = &polHttps; PolicyStatus.cbSize = sizeof(PolicyStatus); if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, pChainContext, &PolicyPara, &PolicyStatus)) { scRet = GetLastError(); goto cleanup; } if (PolicyStatus.dwError) { scRet = PolicyStatus.dwError; goto cleanup; } scRet = SEC_E_OK; cleanup: if (pChainContext) CertFreeCertificateChain(pChainContext); if (pServerCert) CertFreeCertificateContext(pServerCert); mir_free(pwszServerName); ReportSslError(scRet, __LINE__, true); return scRet == SEC_E_OK; }
HRESULT WINAPI SoftpubAuthenticode(CRYPT_PROVIDER_DATA *data) { BOOL ret; CERT_CHAIN_POLICY_STATUS policyStatus = { sizeof(policyStatus), 0 }; TRACE("(%p)\n", data); if (data->pWintrustData->dwUIChoice != WTD_UI_NONE) FIXME("unimplemented for UI choice %d\n", data->pWintrustData->dwUIChoice); if (!data->csSigners) { ret = FALSE; policyStatus.dwError = TRUST_E_NOSIGNATURE; } else { DWORD i; ret = TRUE; for (i = 0; ret && i < data->csSigners; i++) { BYTE hash[20]; DWORD size = sizeof(hash); /* First make sure cert isn't disallowed */ if ((ret = CertGetCertificateContextProperty( data->pasSigners[i].pasCertChain[0].pCert, CERT_SIGNATURE_HASH_PROP_ID, hash, &size))) { static const WCHAR disallowedW[] = { 'D','i','s','a','l','l','o','w','e','d',0 }; HCERTSTORE disallowed = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, X509_ASN_ENCODING, 0, CERT_SYSTEM_STORE_CURRENT_USER, disallowedW); if (disallowed) { PCCERT_CONTEXT found = CertFindCertificateInStore( disallowed, X509_ASN_ENCODING, 0, CERT_FIND_SIGNATURE_HASH, hash, NULL); if (found) { /* Disallowed! Can't verify it. */ policyStatus.dwError = TRUST_E_SUBJECT_NOT_TRUSTED; ret = FALSE; CertFreeCertificateContext(found); } CertCloseStore(disallowed, 0); } } if (ret) { CERT_CHAIN_POLICY_PARA policyPara = { sizeof(policyPara), 0 }; if (data->dwRegPolicySettings & WTPF_TRUSTTEST) policyPara.dwFlags |= CERT_CHAIN_POLICY_TRUST_TESTROOT_FLAG; if (data->dwRegPolicySettings & WTPF_TESTCANBEVALID) policyPara.dwFlags |= CERT_CHAIN_POLICY_ALLOW_TESTROOT_FLAG; if (data->dwRegPolicySettings & WTPF_IGNOREEXPIRATION) policyPara.dwFlags |= CERT_CHAIN_POLICY_IGNORE_NOT_TIME_VALID_FLAG | CERT_CHAIN_POLICY_IGNORE_CTL_NOT_TIME_VALID_FLAG | CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG; if (data->dwRegPolicySettings & WTPF_IGNOREREVOKATION) policyPara.dwFlags |= CERT_CHAIN_POLICY_IGNORE_END_REV_UNKNOWN_FLAG | CERT_CHAIN_POLICY_IGNORE_CTL_SIGNER_REV_UNKNOWN_FLAG | CERT_CHAIN_POLICY_IGNORE_CA_REV_UNKNOWN_FLAG | CERT_CHAIN_POLICY_IGNORE_ROOT_REV_UNKNOWN_FLAG; CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_AUTHENTICODE, data->pasSigners[i].pChainContext, &policyPara, &policyStatus); if (policyStatus.dwError != NO_ERROR) ret = FALSE; } } } if (!ret) data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_POLICYPROV] = policyStatus.dwError; TRACE("returning %d (%08x)\n", ret ? S_OK : S_FALSE, data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_POLICYPROV]); return ret ? S_OK : S_FALSE; }
/* Helper function to trace the signing cert to a trusted CA root * in the Windows Certificate Store. */ static int checkCertCryptoAPI(const GTPublicationsFile *publications_file) { int res = GT_UNKNOWN_ERROR; unsigned char *cert_der = NULL; size_t cert_der_len; PCCERT_CONTEXT pCertContext = NULL; PCCERT_CHAIN_CONTEXT pChainContext = NULL; CERT_ENHKEY_USAGE enhkeyUsage; CERT_USAGE_MATCH certUsage; CERT_CHAIN_PARA chainPara; CERT_CHAIN_POLICY_PARA policyPara; CERT_CHAIN_POLICY_STATUS policyStatus; char tmp_name[256]; res = GTPublicationsFile_getSigningCert(publications_file, &cert_der, &cert_der_len); if (res != GT_OK) { goto cleanup; } /* Create a certificate context based on the above certificate. */ pCertContext = CertCreateCertificateContext( X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, cert_der, cert_der_len); if (pCertContext == NULL) { res = GT_CRYPTO_FAILURE; goto cleanup; } #ifdef MAGIC_EMAIL CertGetNameStringA(pCertContext, CERT_NAME_EMAIL_TYPE, 0, NULL, tmp_name, sizeof(tmp_name)); if (strcmp(tmp_name, MAGIC_EMAIL) != 0) { return GT_INVALID_SIGNATURE; } #endif /* Get the certificate chain of our certificate. */ enhkeyUsage.cUsageIdentifier = 0; enhkeyUsage.rgpszUsageIdentifier = NULL; certUsage.dwType = USAGE_MATCH_TYPE_AND; certUsage.Usage = enhkeyUsage; chainPara.cbSize = sizeof(CERT_CHAIN_PARA); chainPara.RequestedUsage = certUsage; if (!CertGetCertificateChain(NULL, pCertContext, NULL, NULL, &chainPara, 0, NULL, &pChainContext)) { res = GT_CRYPTO_FAILURE; goto cleanup; } if (pChainContext->TrustStatus.dwErrorStatus != CERT_TRUST_NO_ERROR) { res = GT_CERT_NOT_TRUSTED; goto cleanup; } /* Verify certificate chain. */ policyPara.cbSize = sizeof(CERT_CHAIN_POLICY_PARA); policyPara.dwFlags = 0; policyPara.pvExtraPolicyPara = NULL; if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_BASE, pChainContext, &policyPara, &policyStatus)) { res = GT_CRYPTO_FAILURE; goto cleanup; } if (policyStatus.dwError) { res = GT_CERT_NOT_TRUSTED; goto cleanup; } res = GT_OK; cleanup: GT_free(cert_der); if (pChainContext != NULL) { CertFreeCertificateChain(pChainContext); } if (pCertContext != NULL) { CertFreeCertificateContext(pCertContext); } return res; }
static int KSI_PKITruststore_verifyCertificate(const KSI_PKITruststore *pki, const PCCERT_CONTEXT cert){ int res = KSI_UNKNOWN_ERROR; KSI_CTX *ctx = NULL; CERT_ENHKEY_USAGE enhkeyUsage; CERT_USAGE_MATCH certUsage; CERT_CHAIN_PARA chainPara; PCCERT_CHAIN_CONTEXT pChainContext = NULL; CERT_CHAIN_POLICY_PARA policyPara; CERT_CHAIN_POLICY_STATUS policyStatus; char buf[1024]; if (pki == NULL || cert == NULL){ res = KSI_INVALID_ARGUMENT; goto cleanup; } ctx = pki->ctx; KSI_ERR_clearErrors(ctx); /* Get the certificate chain of certificate under verification. */ /*OID List for certificate trust list extensions*/ enhkeyUsage.cUsageIdentifier = 0; enhkeyUsage.rgpszUsageIdentifier = NULL; /*Criteria for identifying issuer certificate for chain building*/ certUsage.dwType = USAGE_MATCH_TYPE_AND; certUsage.Usage = enhkeyUsage; /*Searching and matching criteria for chain building*/ chainPara.cbSize = sizeof(CERT_CHAIN_PARA); chainPara.RequestedUsage = certUsage; /*Use CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL for no automatic cert store update by windows. It is useful when there is need to remove default cert from system store*/ /*Build Certificate Chain from top to root certificate*/ if (!CertGetCertificateChain(NULL, cert, NULL, pki->collectionStore, &chainPara, 0, NULL, &pChainContext)) { KSI_LOG_debug(pki->ctx, "%s", getMSError(GetLastError(), buf, sizeof(buf))); KSI_pushError(ctx, res = KSI_CRYPTO_FAILURE, "Unable to get PKI certificate chain"); goto cleanup; } //TODO: debugging // printCertChain(pChainContext); /*TODO: REMOVE*/ /*If chain is based on untrusted root, determine if it's in pki->collectionStore. If it is, enable chain verification to trust untrusted roots*/ if (pChainContext->TrustStatus.dwErrorStatus&CERT_TRUST_IS_UNTRUSTED_ROOT){ KSI_LOG_debug(ctx, "CryptoAPI: Root certificate is not present under Windows 'Trusted Root Certification Authorities'."); KSI_LOG_debug(ctx, "CryptoAPI: Searching if it is present under PKI Trust Store from files."); if (isUntrustedRootCertInStore(pki, pChainContext)){ policyPara.dwFlags = CERT_CHAIN_POLICY_ALLOW_UNKNOWN_CA_FLAG; KSI_LOG_debug(ctx, "CryptoAPI: Certificate is present. Allow untrusted root certificates"); } else{ policyPara.dwFlags = 0; KSI_LOG_debug(ctx, "CryptoAPI: Certificate is not present."); } } else if (pChainContext->TrustStatus.dwErrorStatus != CERT_TRUST_NO_ERROR) { KSI_LOG_debug(ctx, "%s", getCertificateChainErrorStr(pChainContext)); KSI_pushError(ctx, res = KSI_PKI_CERTIFICATE_NOT_TRUSTED, getCertificateChainErrorStr(pChainContext)); goto cleanup; } else{ policyPara.dwFlags = 0; } /* Verify certificate chain. */ policyPara.cbSize = sizeof(CERT_CHAIN_POLICY_PARA); policyPara.pvExtraPolicyPara = 0; if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_BASE, pChainContext, &policyPara, &policyStatus)) { KSI_LOG_debug(pki->ctx, "%s", getMSError(GetLastError(), buf, sizeof(buf))); KSI_pushError(ctx, res = KSI_CRYPTO_FAILURE, NULL); goto cleanup; } if (policyStatus.dwError) { KSI_LOG_debug(ctx, "CryptoAPI: PKI chain policy error %X.", policyStatus.dwError); KSI_pushError(ctx, res = KSI_PKI_CERTIFICATE_NOT_TRUSTED, NULL); goto cleanup; } res = KSI_OK; cleanup: if (pChainContext) CertFreeCertificateChain(pChainContext); return res; }
static SSLSTREAM *ssl_start (TCPSTREAM *tstream,char *host,unsigned long flags) { SECURITY_STATUS e; ULONG a; TimeStamp t; SecBuffer ibuf[2],obuf[1]; SecBufferDesc ibufs,obufs; SCHANNEL_CRED tlscred; CERT_CONTEXT *cert; CERT_CHAIN_PARA chparam; CERT_CHAIN_CONTEXT *chain; SSL_EXTRA_CERT_CHAIN_POLICY_PARA policy; CERT_CHAIN_POLICY_PARA polparam; CERT_CHAIN_POLICY_STATUS status; char tmp[MAILTMPLEN],certname[256]; char *reason = NIL; ULONG req = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM | ISC_REQ_EXTENDED_ERROR | ISC_REQ_MANUAL_CRED_VALIDATION; LPSTR usage[] = { szOID_PKIX_KP_SERVER_AUTH, szOID_SERVER_GATED_CRYPTO, szOID_SGC_NETSCAPE }; PWSTR whost = NIL; char *buf = (char *) fs_get (ssltsz); unsigned long size = 0; sslcertificatequery_t scq = (sslcertificatequery_t) mail_parameters (NIL,GET_SSLCERTIFICATEQUERY,NIL); sslfailure_t sf = (sslfailure_t) mail_parameters (NIL,GET_SSLFAILURE,NIL); SSLSTREAM *stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0, sizeof (SSLSTREAM)); stream->tcpstream = tstream; /* bind TCP stream */ /* initialize TLS credential */ memset (&tlscred,0,sizeof (SCHANNEL_CRED)); tlscred.dwVersion = SCHANNEL_CRED_VERSION; tlscred.grbitEnabledProtocols = SP_PROT_TLS1; /* acquire credentials */ if (AcquireCredentialsHandle (NIL,UNISP_NAME,SECPKG_CRED_OUTBOUND,NIL,(flags & NET_TLSCLIENT) ? &tlscred : NIL,NIL,NIL,&stream->cred,&t) != SEC_E_OK) reason = "Acquire credentials handle failed"; else while (!reason) { /* negotiate security context */ /* initialize buffers */ ibuf[0].cbBuffer = size; ibuf[0].pvBuffer = buf; ibuf[1].cbBuffer = 0; ibuf[1].pvBuffer = NIL; obuf[0].cbBuffer = 0; obuf[0].pvBuffer = NIL; ibuf[0].BufferType = obuf[0].BufferType = SECBUFFER_TOKEN; ibuf[1].BufferType = SECBUFFER_EMPTY; /* initialize buffer descriptors */ ibufs.ulVersion = obufs.ulVersion = SECBUFFER_VERSION; ibufs.cBuffers = 2; obufs.cBuffers = 1; ibufs.pBuffers = ibuf; obufs.pBuffers = obuf; /* negotiate security */ e = InitializeSecurityContext (&stream->cred,size ? &stream->context : NIL,host,req,0, SECURITY_NETWORK_DREP,size? &ibufs:NIL,0,&stream->context,&obufs,&a,&t); /* have an output buffer we need to send? */ if (obuf[0].pvBuffer && obuf[0].cbBuffer) { if (!tcp_sout (stream->tcpstream,obuf[0].pvBuffer,obuf[0].cbBuffer)) reason = "Unexpected TCP output disconnect"; /* free the buffer */ FreeContextBuffer (obuf[0].pvBuffer); } if (!reason) switch (e) { /* negotiation state */ case SEC_I_INCOMPLETE_CREDENTIALS: break; /* server wants client auth */ case SEC_I_CONTINUE_NEEDED: if (size) { /* continue, read any data? */ /* yes, anything regurgiated back to us? */ if (ibuf[1].BufferType == SECBUFFER_EXTRA) { /* yes, set this as the new data */ memmove (buf,buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer); size = ibuf[1].cbBuffer; break; } size = 0; /* otherwise, read more stuff from server */ } case SEC_E_INCOMPLETE_MESSAGE: /* need to read more data from server */ if (!tcp_getdata (stream->tcpstream)) reason = "Unexpected TCP input disconnect"; else { memcpy (buf+size,stream->tcpstream->iptr,stream->tcpstream->ictr); size += stream->tcpstream->ictr; /* empty it from TCP's buffers */ stream->tcpstream->iptr += stream->tcpstream->ictr; stream->tcpstream->ictr = 0; } break; case SEC_E_OK: /* success, any data to be regurgitated? */ if (ibuf[1].BufferType == SECBUFFER_EXTRA) { /* yes, set this as the new data */ memmove (stream->tcpstream->iptr = stream->tcpstream->ibuf, buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer); stream->tcpstream->ictr = ibuf[1].cbBuffer; } if (!(flags & NET_NOVALIDATECERT)) { /* need validation, make wchar of host */ if (!((size = MultiByteToWideChar (CP_ACP,0,host,-1,NIL,0)) && (whost = (PWSTR) fs_get (size*sizeof (WCHAR))) && MultiByteToWideChar (CP_ACP,0,host,-1,whost,size))) fatal ("Can't make wchar of host name!"); /* get certificate */ if ((QueryContextAttributes (&stream->context,SECPKG_ATTR_REMOTE_CERT_CONTEXT,&cert) != SEC_E_OK) || !cert) { reason = "*Unable to get certificate"; strcpy (certname,"<no certificate>"); } else { /* get certificate subject name */ CertNameToStr (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &cert->pCertInfo->Subject,CERT_X500_NAME_STR, certname,255); /* build certificate chain */ memset (&chparam,0,sizeof (chparam)); chparam.cbSize = sizeof (chparam); chparam.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR; chparam.RequestedUsage.Usage.rgpszUsageIdentifier = usage; chparam.RequestedUsage.Usage.cUsageIdentifier = sizeof (usage) / sizeof (LPSTR); if (!CertGetCertificateChain (NIL,cert,NIL,cert->hCertStore,&chparam,NIL,NIL,&chain)) reason = ssl_analyze_status (GetLastError (),tmp); else { /* validate certificate chain */ memset (&policy,0,sizeof (SSL_EXTRA_CERT_CHAIN_POLICY_PARA)); policy.cbStruct = sizeof (SSL_EXTRA_CERT_CHAIN_POLICY_PARA); policy.dwAuthType = AUTHTYPE_SERVER; policy.fdwChecks = NIL; policy.pwszServerName = whost; memset (&polparam,0,sizeof (polparam)); polparam.cbSize = sizeof (polparam); polparam.pvExtraPolicyPara = &policy; memset (&status,0,sizeof (status)); status.cbSize = sizeof (status); if (!CertVerifyCertificateChainPolicy (CERT_CHAIN_POLICY_SSL,chain,&polparam,&status)) reason = ssl_analyze_status (GetLastError (),tmp); else if (status.dwError) reason = ssl_analyze_status (status.dwError,tmp); CertFreeCertificateChain (chain); } } if (whost) fs_give ((void **) &whost); if (reason) { /* got an error? */ /* application callback */ if (scq) reason = (*scq) ((*reason == '*') ? reason + 1 : reason, host,certname) ? NIL : ""; else if (*certname) { /* error message to return via mm_log() */ sprintf (buf,"*%.128s: %.255s", (*reason == '*') ? reason + 1 : reason,certname); reason = buf; } } } if (reason || (reason = ssl_analyze_status (QueryContextAttributes (&stream->context,SECPKG_ATTR_STREAM_SIZES,&stream->sizes),buf))) break; /* error in certificate or getting sizes */ fs_give ((void **) &buf); /* flush temporary buffer */ /* make maximum-sized buffers */ stream->bufsize = stream->sizes.cbHeader + stream->sizes.cbMaximumMessage + stream->sizes.cbTrailer; if (stream->sizes.cbMaximumMessage < SSLBUFLEN) fatal ("cbMaximumMessage is less than SSLBUFLEN!"); else if (stream->sizes.cbMaximumMessage < 16384) { sprintf (tmp,"WINDOWS BUG: cbMaximumMessage = %ld, should be 16384", (long) stream->sizes.cbMaximumMessage); mm_log (tmp,NIL); } stream->ibuf = (char *) fs_get (stream->bufsize); stream->obuf = (char *) fs_get (stream->bufsize); return stream; default: reason = ssl_analyze_status (e,buf); } } ssl_close (stream); /* failed to do SSL */ stream = NIL; /* no stream returned */ switch (*reason) { /* analyze reason */ case '*': /* certificate failure */ ++reason; /* skip over certificate failure indication */ /* pass to error callback */ if (sf) (*sf) (host,reason,flags); else { /* no error callback, build error message */ sprintf (tmp,"Certificate failure for %.80s: %.512s",host,reason); mm_log (tmp,ERROR); } case '\0': /* user answered no to certificate callback */ if (flags & NET_TRYSSL) /* return dummy stream to stop tryssl */ stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0, sizeof (SSLSTREAM)); break; default: /* non-certificate failure */ if (flags & NET_TRYSSL); /* no error output if tryssl */ /* pass to error callback */ else if (sf) (*sf) (host,reason,flags); else { /* no error callback, build error message */ sprintf (tmp,"TLS/SSL failure for %.80s: %.512s",host,reason); mm_log (tmp,ERROR); } break; } fs_give ((void **) &buf); /* flush temporary buffer */ return stream; }
/* sqVerifyCert: Verify the validity of the remote certificate */ static int sqVerifyCert(sqSSL *ssl, int isServer) { SECURITY_STATUS ret; PCCERT_CONTEXT certHandle = NULL; PCCERT_CHAIN_CONTEXT chainContext = NULL; CERT_CHAIN_PARA chainPara; SSL_EXTRA_CERT_CHAIN_POLICY_PARA epp; CERT_CHAIN_POLICY_PARA policyPara; CERT_CHAIN_POLICY_STATUS policyStatus; static LPSTR serverUsage[] = { szOID_PKIX_KP_SERVER_AUTH, szOID_SERVER_GATED_CRYPTO, szOID_SGC_NETSCAPE }; static LPSTR clientUsage[] = { szOID_PKIX_KP_CLIENT_AUTH }; ret = QueryContextAttributes(&ssl->sslCtxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&certHandle); /* No credentials were provided */ if(ret == SEC_E_NO_CREDENTIALS) { ssl->certFlags = SQSSL_NO_CERTIFICATE; return 1; } memset(&chainPara, 0, sizeof(chainPara)); chainPara.cbSize = sizeof(chainPara); chainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR; if(!isServer) { chainPara.RequestedUsage.Usage.cUsageIdentifier = 3; chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = serverUsage; } else { chainPara.RequestedUsage.Usage.cUsageIdentifier = 1; chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = clientUsage; } if(!CertGetCertificateChain(NULL, certHandle, NULL, certHandle->hCertStore, &chainPara, 0, NULL, &chainContext)) { CertFreeCertificateContext(certHandle); ssl->certFlags = SQSSL_OTHER_ISSUE; goto done; } memset(&epp, 0, sizeof(epp)); epp.cbSize = sizeof(epp); epp.dwAuthType = AUTHTYPE_SERVER; epp.fdwChecks = 0; epp.pwszServerName = NULL; memset(&policyPara, 0, sizeof(policyPara)); policyPara.cbSize = sizeof(policyPara); policyPara.dwFlags = 0; policyPara.pvExtraPolicyPara = &epp; memset(&policyStatus, 0, sizeof(policyStatus)); policyStatus.cbSize = sizeof(policyStatus); /* We loop here CertVerifyCertificateChainPolicy() returns only a single error even if there is more than one issue with the cert. */ ssl->certFlags = 0; while(true) { if (!CertVerifyCertificateChainPolicy( CERT_CHAIN_POLICY_SSL, chainContext, &policyPara, &policyStatus)) { ssl->certFlags |= SQSSL_OTHER_ISSUE; goto done; } switch(policyStatus.dwError) { case SEC_E_OK: goto done; case CERT_E_UNTRUSTEDROOT: if(ssl->certFlags & SQSSL_UNTRUSTED_ROOT) goto done; ssl->certFlags |= SQSSL_UNTRUSTED_ROOT; epp.fdwChecks |= 0x00000100; /* SECURITY_FLAG_IGNORE_UNKNOWN_CA */ break; case CERT_E_EXPIRED: if(ssl->certFlags & SQSSL_CERT_EXPIRED) goto done; ssl->certFlags |= SQSSL_CERT_EXPIRED; epp.fdwChecks |= 0x00002000; /* SECURITY_FLAG_IGNORE_CERT_DATE_INVALID */ break; case CERT_E_WRONG_USAGE: if(ssl->certFlags & SQSSL_WRONG_USAGE) goto done; ssl->certFlags |= SQSSL_WRONG_USAGE; epp.fdwChecks |= 0x00000200; /* SECURITY_FLAG_IGNORE_WRONG_USAGE */ case CERT_E_REVOKED: if(ssl->certFlags & SQSSL_CERT_REVOKED) goto done; ssl->certFlags |= SQSSL_CERT_REVOKED; epp.fdwChecks |= 0x00000080; /* SECURITY_FLAG_IGNORE_REVOCATION */ break; default: ssl->certFlags |= SQSSL_OTHER_ISSUE; goto done; } } done: CertFreeCertificateChain(chainContext); CertFreeCertificateContext(certHandle); return 1; }
// Return an indication of whether a certificate is trusted by asking Windows to validate the // trust chain (basically asking is the certificate issuer trusted) HRESULT CertTrusted(PCCERT_CONTEXT pCertContext) { HTTPSPolicyCallbackData polHttps; CERT_CHAIN_POLICY_PARA PolicyPara; CERT_CHAIN_POLICY_STATUS PolicyStatus; CERT_CHAIN_PARA ChainPara; PCCERT_CHAIN_CONTEXT pChainContext = NULL; HRESULT Status; LPSTR rgszUsages[] = { szOID_PKIX_KP_CLIENT_AUTH, szOID_SERVER_GATED_CRYPTO, szOID_SGC_NETSCAPE }; DWORD cUsages = _countof(rgszUsages); // Build certificate chain. ZeroMemory(&ChainPara, sizeof(ChainPara)); ChainPara.cbSize = sizeof(ChainPara); ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR; ChainPara.RequestedUsage.Usage.cUsageIdentifier = cUsages; ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = rgszUsages; if (!CertGetCertificateChain(NULL, pCertContext, NULL, pCertContext->hCertStore, &ChainPara, 0, NULL, &pChainContext)) { Status = GetLastError(); DebugMsg("Error %#x returned by CertGetCertificateChain!", Status); goto cleanup; } // Validate certificate chain. ZeroMemory(&polHttps, sizeof(HTTPSPolicyCallbackData)); polHttps.cbStruct = sizeof(HTTPSPolicyCallbackData); polHttps.dwAuthType = AUTHTYPE_SERVER; polHttps.fdwChecks = 0; // dwCertFlags; polHttps.pwszServerName = NULL; // ServerName - checked elsewhere ZeroMemory(&PolicyPara, sizeof(PolicyPara)); PolicyPara.cbSize = sizeof(PolicyPara); PolicyPara.pvExtraPolicyPara = &polHttps; ZeroMemory(&PolicyStatus, sizeof(PolicyStatus)); PolicyStatus.cbSize = sizeof(PolicyStatus); if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, pChainContext, &PolicyPara, &PolicyStatus)) { Status = HRESULT_FROM_WIN32(GetLastError()); DebugMsg("Error %#x returned by CertVerifyCertificateChainPolicy!", Status); goto cleanup; } if (PolicyStatus.dwError) { Status = S_FALSE; //DisplayWinVerifyTrustError(PolicyStatus.dwError); goto cleanup; } Status = SEC_E_OK; cleanup: if (pChainContext) CertFreeCertificateChain(pChainContext); return Status; }
SECURITY_STATUS SchannelContext::validateServerCertificate() { SchannelCertificate::ref pServerCert = boost::dynamic_pointer_cast<SchannelCertificate>( getPeerCertificate() ); if (!pServerCert) return SEC_E_WRONG_PRINCIPAL; const LPSTR usage[] = { szOID_PKIX_KP_SERVER_AUTH, szOID_SERVER_GATED_CRYPTO, szOID_SGC_NETSCAPE }; CERT_CHAIN_PARA chainParams = {0}; chainParams.cbSize = sizeof(chainParams); chainParams.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR; chainParams.RequestedUsage.Usage.cUsageIdentifier = ARRAYSIZE(usage); chainParams.RequestedUsage.Usage.rgpszUsageIdentifier = const_cast<LPSTR*>(usage); DWORD chainFlags = CERT_CHAIN_CACHE_END_CERT | CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT; ScopedCertChainContext pChainContext; BOOL success = CertGetCertificateChain( NULL, // Use the chain engine for the current user (assumes a user is logged in) pServerCert->getCertContext(), NULL, NULL, &chainParams, chainFlags, NULL, pChainContext.Reset()); if (!success) return GetLastError(); SSL_EXTRA_CERT_CHAIN_POLICY_PARA sslChainPolicy = {0}; sslChainPolicy.cbSize = sizeof(sslChainPolicy); sslChainPolicy.dwAuthType = AUTHTYPE_SERVER; sslChainPolicy.fdwChecks = SECURITY_FLAG_IGNORE_CERT_CN_INVALID; // Swiften checks the server name for us. Is this the correct way to disable server name checking? sslChainPolicy.pwszServerName = NULL; CERT_CHAIN_POLICY_PARA certChainPolicy = {0}; certChainPolicy.cbSize = sizeof(certChainPolicy); certChainPolicy.dwFlags = CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG; // Swiften checks the server name for us. Is this the correct way to disable server name checking? certChainPolicy.pvExtraPolicyPara = &sslChainPolicy; CERT_CHAIN_POLICY_STATUS certChainPolicyStatus = {0}; certChainPolicyStatus.cbSize = sizeof(certChainPolicyStatus); // Verify the chain if (!CertVerifyCertificateChainPolicy( CERT_CHAIN_POLICY_SSL, pChainContext, &certChainPolicy, &certChainPolicyStatus)) { return GetLastError(); } if (certChainPolicyStatus.dwError != S_OK) return certChainPolicyStatus.dwError; return S_OK; }
static DWORD netconn_verify_cert(netconn_t *conn, PCCERT_CONTEXT cert, HCERTSTORE store) { BOOL ret; CERT_CHAIN_PARA chainPara = { sizeof(chainPara), { 0 } }; PCCERT_CHAIN_CONTEXT chain; char oid_server_auth[] = szOID_PKIX_KP_SERVER_AUTH; char *server_auth[] = { oid_server_auth }; DWORD err = ERROR_SUCCESS, errors; static const DWORD supportedErrors = CERT_TRUST_IS_NOT_TIME_VALID | CERT_TRUST_IS_UNTRUSTED_ROOT | CERT_TRUST_IS_PARTIAL_CHAIN | CERT_TRUST_IS_NOT_VALID_FOR_USAGE; TRACE("verifying %s\n", debugstr_w(conn->server->name)); chainPara.RequestedUsage.Usage.cUsageIdentifier = 1; chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = server_auth; if (!(ret = CertGetCertificateChain(NULL, cert, NULL, store, &chainPara, 0, NULL, &chain))) { TRACE("failed\n"); return GetLastError(); } errors = chain->TrustStatus.dwErrorStatus; do { /* This seems strange, but that's what tests show */ if(errors & CERT_TRUST_IS_PARTIAL_CHAIN) { WARN("ERROR_INTERNET_SEC_CERT_REV_FAILED\n"); err = ERROR_INTERNET_SEC_CERT_REV_FAILED; if(conn->mask_errors) conn->security_flags |= _SECURITY_FLAG_CERT_REV_FAILED; if(!(conn->security_flags & SECURITY_FLAG_IGNORE_REVOCATION)) break; } if (chain->TrustStatus.dwErrorStatus & ~supportedErrors) { WARN("error status %x\n", chain->TrustStatus.dwErrorStatus & ~supportedErrors); err = conn->mask_errors && err ? ERROR_INTERNET_SEC_CERT_ERRORS : ERROR_INTERNET_SEC_INVALID_CERT; errors &= supportedErrors; if(!conn->mask_errors) break; WARN("unknown error flags\n"); } if(errors & CERT_TRUST_IS_NOT_TIME_VALID) { WARN("CERT_TRUST_IS_NOT_TIME_VALID\n"); if(!(conn->security_flags & SECURITY_FLAG_IGNORE_CERT_DATE_INVALID)) { err = conn->mask_errors && err ? ERROR_INTERNET_SEC_CERT_ERRORS : ERROR_INTERNET_SEC_CERT_DATE_INVALID; if(!conn->mask_errors) break; conn->security_flags |= _SECURITY_FLAG_CERT_INVALID_DATE; } errors &= ~CERT_TRUST_IS_NOT_TIME_VALID; } if(errors & CERT_TRUST_IS_UNTRUSTED_ROOT) { WARN("CERT_TRUST_IS_UNTRUSTED_ROOT\n"); if(!(conn->security_flags & SECURITY_FLAG_IGNORE_UNKNOWN_CA)) { err = conn->mask_errors && err ? ERROR_INTERNET_SEC_CERT_ERRORS : ERROR_INTERNET_INVALID_CA; if(!conn->mask_errors) break; conn->security_flags |= _SECURITY_FLAG_CERT_INVALID_CA; } errors &= ~CERT_TRUST_IS_UNTRUSTED_ROOT; } if(errors & CERT_TRUST_IS_PARTIAL_CHAIN) { WARN("CERT_TRUST_IS_PARTIAL_CHAIN\n"); if(!(conn->security_flags & SECURITY_FLAG_IGNORE_UNKNOWN_CA)) { err = conn->mask_errors && err ? ERROR_INTERNET_SEC_CERT_ERRORS : ERROR_INTERNET_INVALID_CA; if(!conn->mask_errors) break; conn->security_flags |= _SECURITY_FLAG_CERT_INVALID_CA; } errors &= ~CERT_TRUST_IS_PARTIAL_CHAIN; } if(errors & CERT_TRUST_IS_NOT_VALID_FOR_USAGE) { WARN("CERT_TRUST_IS_NOT_VALID_FOR_USAGE\n"); if(!(conn->security_flags & SECURITY_FLAG_IGNORE_WRONG_USAGE)) { err = conn->mask_errors && err ? ERROR_INTERNET_SEC_CERT_ERRORS : ERROR_INTERNET_SEC_INVALID_CERT; if(!conn->mask_errors) break; WARN("CERT_TRUST_IS_NOT_VALID_FOR_USAGE, unknown error flags\n"); } errors &= ~CERT_TRUST_IS_NOT_VALID_FOR_USAGE; } if(err == ERROR_INTERNET_SEC_CERT_REV_FAILED) { assert(conn->security_flags & SECURITY_FLAG_IGNORE_REVOCATION); err = ERROR_SUCCESS; } }while(0); if(!err || conn->mask_errors) { CERT_CHAIN_POLICY_PARA policyPara; SSL_EXTRA_CERT_CHAIN_POLICY_PARA sslExtraPolicyPara; CERT_CHAIN_POLICY_STATUS policyStatus; CERT_CHAIN_CONTEXT chainCopy; /* Clear chain->TrustStatus.dwErrorStatus so * CertVerifyCertificateChainPolicy will verify additional checks * rather than stopping with an existing, ignored error. */ memcpy(&chainCopy, chain, sizeof(chainCopy)); chainCopy.TrustStatus.dwErrorStatus = 0; sslExtraPolicyPara.u.cbSize = sizeof(sslExtraPolicyPara); sslExtraPolicyPara.dwAuthType = AUTHTYPE_SERVER; sslExtraPolicyPara.pwszServerName = conn->server->name; sslExtraPolicyPara.fdwChecks = conn->security_flags; policyPara.cbSize = sizeof(policyPara); policyPara.dwFlags = 0; policyPara.pvExtraPolicyPara = &sslExtraPolicyPara; ret = CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, &chainCopy, &policyPara, &policyStatus); /* Any error in the policy status indicates that the * policy couldn't be verified. */ if(ret) { if(policyStatus.dwError == CERT_E_CN_NO_MATCH) { WARN("CERT_E_CN_NO_MATCH\n"); if(conn->mask_errors) conn->security_flags |= _SECURITY_FLAG_CERT_INVALID_CN; err = conn->mask_errors && err ? ERROR_INTERNET_SEC_CERT_ERRORS : ERROR_INTERNET_SEC_CERT_CN_INVALID; }else if(policyStatus.dwError) { WARN("policyStatus.dwError %x\n", policyStatus.dwError); if(conn->mask_errors) WARN("unknown error flags for policy status %x\n", policyStatus.dwError); err = conn->mask_errors && err ? ERROR_INTERNET_SEC_CERT_ERRORS : ERROR_INTERNET_SEC_INVALID_CERT; } }else { err = GetLastError(); } } if(err) { WARN("failed %u\n", err); CertFreeCertificateChain(chain); if(conn->server->cert_chain) { CertFreeCertificateChain(conn->server->cert_chain); conn->server->cert_chain = NULL; } if(conn->mask_errors) conn->server->security_flags |= conn->security_flags & _SECURITY_ERROR_FLAGS_MASK; return err; } /* FIXME: Reuse cached chain */ if(conn->server->cert_chain) CertFreeCertificateChain(chain); else conn->server->cert_chain = chain; return ERROR_SUCCESS; }
static DWORD netconn_verify_cert( PCCERT_CONTEXT cert, HCERTSTORE store, WCHAR *server ) { BOOL ret; CERT_CHAIN_PARA chainPara = { sizeof(chainPara), { 0 } }; PCCERT_CHAIN_CONTEXT chain; char oid_server_auth[] = szOID_PKIX_KP_SERVER_AUTH; char *server_auth[] = { oid_server_auth }; DWORD err = ERROR_SUCCESS; TRACE("verifying %s\n", debugstr_w( server )); chainPara.RequestedUsage.Usage.cUsageIdentifier = 1; chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = server_auth; if ((ret = CertGetCertificateChain( NULL, cert, NULL, store, &chainPara, 0, NULL, &chain ))) { if (chain->TrustStatus.dwErrorStatus) { if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_TIME_VALID) err = ERROR_WINHTTP_SECURE_CERT_DATE_INVALID; else if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_UNTRUSTED_ROOT) err = ERROR_WINHTTP_SECURE_INVALID_CA; else if ((chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_OFFLINE_REVOCATION) || (chain->TrustStatus.dwErrorStatus & CERT_TRUST_REVOCATION_STATUS_UNKNOWN)) err = ERROR_WINHTTP_SECURE_CERT_REV_FAILED; else if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED) err = ERROR_WINHTTP_SECURE_CERT_REVOKED; else if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_VALID_FOR_USAGE) err = ERROR_WINHTTP_SECURE_CERT_WRONG_USAGE; else err = ERROR_WINHTTP_SECURE_INVALID_CERT; } else { CERT_CHAIN_POLICY_PARA policyPara; SSL_EXTRA_CERT_CHAIN_POLICY_PARA sslExtraPolicyPara; CERT_CHAIN_POLICY_STATUS policyStatus; sslExtraPolicyPara.u.cbSize = sizeof(sslExtraPolicyPara); sslExtraPolicyPara.dwAuthType = AUTHTYPE_SERVER; sslExtraPolicyPara.pwszServerName = server; policyPara.cbSize = sizeof(policyPara); policyPara.dwFlags = 0; policyPara.pvExtraPolicyPara = &sslExtraPolicyPara; ret = CertVerifyCertificateChainPolicy( CERT_CHAIN_POLICY_SSL, chain, &policyPara, &policyStatus ); /* Any error in the policy status indicates that the * policy couldn't be verified. */ if (ret && policyStatus.dwError) { if (policyStatus.dwError == CERT_E_CN_NO_MATCH) err = ERROR_WINHTTP_SECURE_CERT_CN_INVALID; else err = ERROR_WINHTTP_SECURE_INVALID_CERT; } } CertFreeCertificateChain( chain ); } else err = ERROR_WINHTTP_SECURE_CHANNEL_ERROR; TRACE("returning %08x\n", err); return err; }
static DWORD netconn_verify_cert( PCCERT_CONTEXT cert, HCERTSTORE store, WCHAR *server, DWORD security_flags ) { BOOL ret; CERT_CHAIN_PARA chainPara = { sizeof(chainPara), { 0 } }; PCCERT_CHAIN_CONTEXT chain; char oid_server_auth[] = szOID_PKIX_KP_SERVER_AUTH; char *server_auth[] = { oid_server_auth }; DWORD err = ERROR_SUCCESS; TRACE("verifying %s\n", debugstr_w( server )); chainPara.RequestedUsage.Usage.cUsageIdentifier = 1; chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = server_auth; if ((ret = CertGetCertificateChain( NULL, cert, NULL, store, &chainPara, CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT, NULL, &chain ))) { if (chain->TrustStatus.dwErrorStatus) { static const DWORD supportedErrors = CERT_TRUST_IS_NOT_TIME_VALID | CERT_TRUST_IS_UNTRUSTED_ROOT | CERT_TRUST_IS_NOT_VALID_FOR_USAGE; if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_TIME_VALID) { if (!(security_flags & SECURITY_FLAG_IGNORE_CERT_DATE_INVALID)) err = ERROR_WINHTTP_SECURE_CERT_DATE_INVALID; } else if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_UNTRUSTED_ROOT) { if (!(security_flags & SECURITY_FLAG_IGNORE_UNKNOWN_CA)) err = ERROR_WINHTTP_SECURE_INVALID_CA; } else if ((chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_OFFLINE_REVOCATION) || (chain->TrustStatus.dwErrorStatus & CERT_TRUST_REVOCATION_STATUS_UNKNOWN)) err = ERROR_WINHTTP_SECURE_CERT_REV_FAILED; else if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED) err = ERROR_WINHTTP_SECURE_CERT_REVOKED; else if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_VALID_FOR_USAGE) { if (!(security_flags & SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE)) err = ERROR_WINHTTP_SECURE_CERT_WRONG_USAGE; } else if (chain->TrustStatus.dwErrorStatus & ~supportedErrors) err = ERROR_WINHTTP_SECURE_INVALID_CERT; } if (!err) { CERT_CHAIN_POLICY_PARA policyPara; SSL_EXTRA_CERT_CHAIN_POLICY_PARA sslExtraPolicyPara; CERT_CHAIN_POLICY_STATUS policyStatus; CERT_CHAIN_CONTEXT chainCopy; /* Clear chain->TrustStatus.dwErrorStatus so * CertVerifyCertificateChainPolicy will verify additional checks * rather than stopping with an existing, ignored error. */ memcpy(&chainCopy, chain, sizeof(chainCopy)); chainCopy.TrustStatus.dwErrorStatus = 0; sslExtraPolicyPara.u.cbSize = sizeof(sslExtraPolicyPara); sslExtraPolicyPara.dwAuthType = AUTHTYPE_SERVER; sslExtraPolicyPara.pwszServerName = server; sslExtraPolicyPara.fdwChecks = security_flags; policyPara.cbSize = sizeof(policyPara); policyPara.dwFlags = 0; policyPara.pvExtraPolicyPara = &sslExtraPolicyPara; ret = CertVerifyCertificateChainPolicy( CERT_CHAIN_POLICY_SSL, &chainCopy, &policyPara, &policyStatus ); /* Any error in the policy status indicates that the * policy couldn't be verified. */ if (ret && policyStatus.dwError) { if (policyStatus.dwError == CERT_E_CN_NO_MATCH) err = ERROR_WINHTTP_SECURE_CERT_CN_INVALID; else err = ERROR_WINHTTP_SECURE_INVALID_CERT; } } CertFreeCertificateChain( chain ); } else err = ERROR_WINHTTP_SECURE_CHANNEL_ERROR; TRACE("returning %08x\n", err); return err; }
/***************************************************************************** wmain *****************************************************************************/ DWORD __cdecl wmain( int argc, LPWSTR argv[] ) { HRESULT hr = S_OK; int i = 0; BOOL fPeerTrust = FALSE; DWORD dwChainFlags = CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT; LPCWSTR wsCertFile = NULL; LPCWSTR wsStoreFile = NULL; PCCERT_CONTEXT pCert = NULL; HCERTSTORE hStore = NULL; HCERTCHAINENGINE hChainEngine = NULL; PCCERT_CHAIN_CONTEXT pChainContext = NULL; CERT_ENHKEY_USAGE EnhkeyUsage = {0}; CERT_USAGE_MATCH CertUsage = {0}; CERT_CHAIN_PARA ChainPara = {0}; CERT_CHAIN_POLICY_PARA ChainPolicy = {0}; CERT_CHAIN_POLICY_STATUS PolicyStatus = {0}; CERT_CHAIN_ENGINE_CONFIG EngineConfig = {0}; //--------------------------------------------------------- // Initialize data structures for chain building. EnhkeyUsage.cUsageIdentifier = 0; EnhkeyUsage.rgpszUsageIdentifier=NULL; CertUsage.dwType = USAGE_MATCH_TYPE_AND; CertUsage.Usage = EnhkeyUsage; ChainPara.cbSize = sizeof(ChainPara); ChainPara.RequestedUsage=CertUsage; ChainPolicy.cbSize = sizeof(ChainPolicy); PolicyStatus.cbSize = sizeof(PolicyStatus); EngineConfig.cbSize = sizeof(EngineConfig); EngineConfig.dwUrlRetrievalTimeout = 0; // // options // for( i=1; i<argc; i++ ) { if ( lstrcmpW (argv[i], L"/?") == 0 || lstrcmpW (argv[i], L"-?") == 0 ) { Usage(argv[0]); goto CleanUp; } if( *argv[i] != L'-' ) break; if ( lstrcmpW (argv[i], L"-fc") == 0 ) { if( i+1 >= argc ) { goto InvalidCommandLine; } dwChainFlags = (DWORD)wcstoul( argv[++i], NULL, 0 ); } else if ( lstrcmpW (argv[i], L"-fe") == 0 ) { if( i+1 >= argc ) { goto InvalidCommandLine; } EngineConfig.dwFlags = (DWORD)wcstoul( argv[++i], NULL, 0 ); } else if ( lstrcmpW (argv[i], L"-p") == 0 ) { fPeerTrust = TRUE; } else { goto InvalidCommandLine; } } if( i >= argc ) { goto InvalidCommandLine; } wsStoreFile = argv[i++]; if( i < argc ) { wsCertFile = argv[i]; } hStore = CertOpenStore( CERT_STORE_PROV_FILENAME_W, X509_ASN_ENCODING, NULL, CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, wsStoreFile ); if( NULL == hStore ) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto CleanUp; } if( NULL != wsCertFile && 0 != *wsCertFile ) { if( !CryptQueryObject( CERT_QUERY_OBJECT_FILE, wsCertFile, CERT_QUERY_CONTENT_FLAG_CERT | CERT_QUERY_CONTENT_SERIALIZED_CERT , CERT_QUERY_FORMAT_FLAG_ALL, 0, // dwFlags, 0, // pdwMsgAndCertEncodingType, 0, // pdwContentType, 0, // pdwFormatType, 0, // phCertStore, 0, // phMsg, (const void**)&pCert )) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto CleanUp; } } else { pCert = CertFindCertificateInStore( hStore, X509_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, NULL ); if( NULL == pCert ) { hr = CRYPT_E_NOT_FOUND; goto CleanUp; } } if( fPeerTrust ) { EngineConfig.hExclusiveTrustedPeople = hStore; // Exclusive peer trust dwChainFlags |= CERT_CHAIN_ENABLE_PEER_TRUST; } else { EngineConfig.hExclusiveRoot = hStore; // Exclusive root } //--------------------------------------------------------- // Create chain engine. if( !CertCreateCertificateChainEngine( &EngineConfig, &hChainEngine )) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto CleanUp; } //------------------------------------------------------------------- // Build a chain using CertGetCertificateChain if( !CertGetCertificateChain( hChainEngine, pCert, // pointer to the end certificate NULL, // use the default time NULL, // search no additional stores &ChainPara, // use AND logic and enhanced key usage // as indicated in the ChainPara // data structure dwChainFlags, NULL, // currently reserved &pChainContext )) // return a pointer to the chain created { hr = HRESULT_FROM_WIN32( GetLastError() ); goto CleanUp; } //--------------------------------------------------------------- // Verify that the chain complies with policy if( !CertVerifyCertificateChainPolicy( CERT_CHAIN_POLICY_BASE, // use the base policy pChainContext, // pointer to the chain &ChainPolicy, &PolicyStatus )) // return a pointer to the policy status { hr = HRESULT_FROM_WIN32( GetLastError() ); goto CleanUp; } if( PolicyStatus.dwError != S_OK ) { hr = PolicyStatus.dwError; // Instruction: If the PolicyStatus.dwError is CRYPT_E_NO_REVOCATION_CHECK or CRYPT_E_REVOCATION_OFFLINE, it indicates errors in obtaining // revocation information. These can be ignored since the retrieval of revocation information depends on network availability goto CleanUp; } wprintf( L"CertVerifyCertificateChainPolicy succeeded.\n" ); hr = S_OK; // // END // goto CleanUp; // // Invalid Command Line // InvalidCommandLine: if( i < argc ) { wprintf( L"Invalid command line '%s'\n", argv[i] ); } else Usage(argv[0]); hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); CleanUp: if( FAILED(hr) ) { ReportError( NULL, hr ); } if( NULL != pChainContext ) { CertFreeCertificateChain( pChainContext ); } if( NULL != hChainEngine ) { CertFreeCertificateChainEngine( hChainEngine ); } if( NULL != pCert ) { CertFreeCertificateContext( pCert ); } if( NULL != hStore ) { CertCloseStore( hStore, 0 ); } return (DWORD)hr; } // end main