DWORD WinVerifySslCert(const QByteArray& cert) { DWORD errorStatus = -1; PCCERT_CONTEXT certContext = CertCreateCertificateContext(X509_ASN_ENCODING, reinterpret_cast<const BYTE*>(cert.constData()), cert.size()); if (!certContext) { return errorStatus; } LPSTR usage[] = { szOID_PKIX_KP_SERVER_AUTH, szOID_SERVER_GATED_CRYPTO, szOID_SGC_NETSCAPE }; CERT_CHAIN_PARA chainParameter; memset(&chainParameter, 0, sizeof(CERT_CHAIN_PARA)); chainParameter.cbSize = sizeof(CERT_CHAIN_PARA); chainParameter.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR; chainParameter.RequestedUsage.Usage.cUsageIdentifier = ARRAYSIZE(usage); chainParameter.RequestedUsage.Usage.rgpszUsageIdentifier = usage; PCCERT_CHAIN_CONTEXT chainContext = NULL; CertGetCertificateChain(NULL, certContext, NULL, NULL, &chainParameter, 0, NULL, &chainContext); if (chainContext) { errorStatus = chainContext->TrustStatus.dwErrorStatus; CertFreeCertificateChain(chainContext); } CertFreeCertificateContext(certContext); return errorStatus; }
DWORD VerifyCertificate(PCCERT_CONTEXT pCert,DWORD *CheckResult) { CERT_CHAIN_PARA ChainPara; PCCERT_CHAIN_CONTEXT Chain=NULL; ChainPara.cbSize=sizeof(ChainPara); ChainPara.RequestedUsage.dwType=USAGE_MATCH_TYPE_AND; ChainPara.RequestedUsage.Usage.cUsageIdentifier=0; ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier=NULL; //ChainPara.RequestedIssuancePolicy=NULL; //ChainPara.fCheckRevocationFreshnessTime=FALSE; //ChainPara.dwUrlRetrievalTimeout=0; if(!CertGetCertificateChain( NULL, pCert, NULL, NULL,//? &ChainPara, CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT, NULL, &Chain)) return CSP_GetLastError(); *CheckResult=Chain->TrustStatus.dwErrorStatus; if(Chain) CertFreeCertificateChain(Chain); return 0; }
HRESULT WINAPI SoftpubCleanup(CRYPT_PROVIDER_DATA *data) { DWORD i, j; for (i = 0; i < data->csSigners; i++) { for (j = 0; j < data->pasSigners[i].csCertChain; j++) CertFreeCertificateContext(data->pasSigners[i].pasCertChain[j].pCert); data->psPfns->pfnFree(data->pasSigners[i].pasCertChain); data->psPfns->pfnFree(data->pasSigners[i].psSigner); CertFreeCertificateChain(data->pasSigners[i].pChainContext); } data->psPfns->pfnFree(data->pasSigners); for (i = 0; i < data->chStores; i++) CertCloseStore(data->pahStores[i], 0); data->psPfns->pfnFree(data->pahStores); if (data->u.pPDSip) { data->psPfns->pfnFree(data->u.pPDSip->pSip); data->psPfns->pfnFree(data->u.pPDSip->pCATSip); data->psPfns->pfnFree(data->u.pPDSip->psSipSubjectInfo); data->psPfns->pfnFree(data->u.pPDSip->psSipCATSubjectInfo); data->psPfns->pfnFree(data->u.pPDSip->psIndirectData); } CryptMsgClose(data->hMsg); if (data->fOpenedFile) CloseHandle(data->pWintrustData->u.pFile->hFile); return S_OK; }
SECURITY_STATUS SSL_SOCKET :: Verify(PCCERT_CONTEXT px) { if (px == 0) return SEC_E_WRONG_PRINCIPAL; // Time int iRc = CertVerifyTimeValidity(NULL,px->pCertInfo); if (iRc != 0) return SEC_E_CERT_EXPIRED; // Chain CERT_CHAIN_PARA ChainPara = {0}; PCCERT_CHAIN_CONTEXT pChainContext = NULL; ChainPara.cbSize = sizeof(ChainPara); if (!CertGetCertificateChain(0,px,0,0,&ChainPara,0,0,&pChainContext)) return SEC_E_INVALID_TOKEN; /* ZeroMemory(&polHttps, sizeof(HTTPSPolicyCallbackData)); polHttps.cbStruct = sizeof(HTTPSPolicyCallbackData); polHttps.dwAuthType = AUTHTYPE_SERVER; polHttps.fdwChecks = dwCertFlags; polHttps.pwszServerName = pwszServerName; memset(&PolicyPara, 0, sizeof(PolicyPara)); PolicyPara.cbSize = sizeof(PolicyPara); PolicyPara.pvExtraPolicyPara = &polHttps; memset(&PolicyStatus, 0, sizeof(PolicyStatus)); PolicyStatus.cbSize = sizeof(PolicyStatus); if (!CertVerifyCertificateChainPolicy( CERT_CHAIN_POLICY_SSL, pChainContext, &PolicyPara, &PolicyStatus)) { Status = ::GetLastError(); SetLastError(Status); break; } */ PCCERT_CONTEXT j[2]; j[0] = px; CERT_REVOCATION_STATUS cs = {0}; cs.cbSize = sizeof(cs); SECURITY_STATUS ss = CertVerifyRevocation(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,CERT_CONTEXT_REVOCATION_TYPE, 1,(void**)j,0,0,&cs); if (pChainContext) CertFreeCertificateChain(pChainContext); return ss; }
static void check_and_store_certs(HCERTSTORE from, HCERTSTORE to) { DWORD root_count = 0; CERT_CHAIN_ENGINE_CONFIG chainEngineConfig = { sizeof(chainEngineConfig), 0 }; HCERTCHAINENGINE engine; TRACE("\n"); CertDuplicateStore(to); engine = CRYPT_CreateChainEngine(to, &chainEngineConfig); if (engine) { PCCERT_CONTEXT cert = NULL; do { cert = CertEnumCertificatesInStore(from, cert); if (cert) { CERT_CHAIN_PARA chainPara = { sizeof(chainPara), { 0 } }; PCCERT_CHAIN_CONTEXT chain; BOOL ret = CertGetCertificateChain(engine, cert, NULL, from, &chainPara, 0, NULL, &chain); if (!ret) TRACE("rejecting %s: %s\n", get_cert_common_name(cert), "chain creation failed"); else { /* The only allowed error is CERT_TRUST_IS_UNTRUSTED_ROOT */ if (chain->TrustStatus.dwErrorStatus & ~CERT_TRUST_IS_UNTRUSTED_ROOT) TRACE("rejecting %s: %s\n", get_cert_common_name(cert), trust_status_to_str(chain->TrustStatus.dwErrorStatus & ~CERT_TRUST_IS_UNTRUSTED_ROOT)); else { DWORD i, j; for (i = 0; i < chain->cChain; i++) for (j = 0; j < chain->rgpChain[i]->cElement; j++) if (CertAddCertificateContextToStore(to, chain->rgpChain[i]->rgpElement[j]->pCertContext, CERT_STORE_ADD_NEW, NULL)) root_count++; } CertFreeCertificateChain(chain); } } } while (cert); CertFreeCertificateChainEngine(engine); } TRACE("Added %d root certificates\n", root_count); }
/* 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
static void testCertTrust(SAFE_PROVIDER_FUNCTIONS *funcs, GUID *actionID) { CRYPT_PROVIDER_DATA data = { 0 }; CRYPT_PROVIDER_SGNR sgnr = { sizeof(sgnr), { 0 } }; HRESULT ret; data.padwTrustStepErrors = funcs->pfnAlloc(TRUSTERROR_MAX_STEPS * sizeof(DWORD)); if (!data.padwTrustStepErrors) { skip("pfnAlloc failed\n"); return; } ret = funcs->pfnCertificateTrust(&data); ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret); ok(data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV] == TRUST_E_NOSIGNATURE, "Expected TRUST_E_NOSIGNATURE, got %08x\n", data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV]); ret = funcs->pfnAddSgnr2Chain(&data, FALSE, 0, &sgnr); if (ret) { PCCERT_CONTEXT cert; /* An empty signer "succeeds," even though there's no cert */ ret = funcs->pfnCertificateTrust(&data); ok(ret == S_OK, "Expected S_OK, got %08x\n", ret); cert = CertCreateCertificateContext(X509_ASN_ENCODING, selfSignedCert, sizeof(selfSignedCert)); if (cert) { WINTRUST_DATA wintrust_data = { 0 }; ret = funcs->pfnAddCert2Chain(&data, 0, FALSE, 0, cert); /* If pWintrustData isn't set, crashes attempting to access * pWintrustData->fdwRevocationChecks */ data.pWintrustData = &wintrust_data; /* If psPfns isn't set, crashes attempting to access * psPfns->pfnCertCheckPolicy */ data.psPfns = (CRYPT_PROVIDER_FUNCTIONS *)funcs; ret = funcs->pfnCertificateTrust(&data); ok(ret == S_OK, "Expected S_OK, got %08x\n", ret); ok(data.csSigners == 1, "Unexpected number of signers %d\n", data.csSigners); ok(data.pasSigners[0].pChainContext != NULL, "Expected a certificate chain\n"); ok(data.pasSigners[0].csCertChain == 1, "Unexpected number of chain elements %d\n", data.pasSigners[0].csCertChain); /* pasSigners and pasSigners[0].pasCertChain are guaranteed to be * initialized, see tests for pfnAddSgnr2Chain and pfnAddCert2Chain */ ok(!data.pasSigners[0].pasCertChain[0].fTrustedRoot, "Didn't expect cert to be trusted\n"); ok(data.pasSigners[0].pasCertChain[0].fSelfSigned, "Expected cert to be self-signed\n"); ok(data.pasSigners[0].pasCertChain[0].dwConfidence == (CERT_CONFIDENCE_SIG | CERT_CONFIDENCE_TIMENEST), "Expected CERT_CONFIDENCE_SIG | CERT_CONFIDENCE_TIMENEST, got %08x\n", data.pasSigners[0].pasCertChain[0].dwConfidence); CertFreeCertificateContext( data.pasSigners[0].pasCertChain[0].pCert); CertFreeCertificateChain(data.pasSigners[0].pChainContext); CertFreeCertificateContext(cert); } } }
/* * '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); }
int CryptoAPI_verify_certificate(X509 *x509) { int ret = -1; int len; unsigned char *buf = NULL; PCCERT_CONTEXT pCertContext = NULL; PCCERT_CHAIN_CONTEXT pChainContext = NULL; CERT_ENHKEY_USAGE EnhkeyUsage; CERT_USAGE_MATCH CertUsage; CERT_CHAIN_PARA ChainPara; /* Convert from internal X509 format to DER */ len = i2d_X509(x509, &buf); if (len < 0) { SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_ASN1_LIB); goto err; } #ifdef __MINGW32_VERSION /* MinGW w32api is incomplete when it comes to CryptoAPI, as per version 3.1 * anyway. This is a hack around that problem. */ if (crypt32dll == NULL) { crypt32dll = LoadLibrary("crypt32"); if (crypt32dll == NULL) { CRYPTOAPIerr(CRYPTOAPI_F_LOAD_LIBRARY); goto err; } } if (CertCreateCertificateContext == NULL) { CertCreateCertificateContext = GetProcAddress(crypt32dll, "CertCreateCertificateContext"); if (CertCreateCertificateContext == NULL) { CRYPTOAPIerr(CRYPTOAPI_F_GET_PROC_ADDRESS); goto err; } } #endif /* Create a certificate context based on the above certificate */ pCertContext = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, buf, len); if (pCertContext == NULL) { CRYPTOAPIerr(CRYPTOAPI_F_CERT_CREATE_CERT_CONTEXT); goto err; } /* Create an empty issuer list */ EnhkeyUsage.cUsageIdentifier = 0; EnhkeyUsage.rgpszUsageIdentifier = NULL; CertUsage.dwType = USAGE_MATCH_TYPE_AND; CertUsage.Usage = EnhkeyUsage; /* Searching and matching criteria to be used when building the chain */ ChainPara.cbSize = sizeof(CERT_CHAIN_PARA); ChainPara.RequestedUsage = CertUsage; /* Get the certificate chain of our certificate */ if (!CertGetCertificateChain(NULL, pCertContext, NULL, NULL, &ChainPara, 0, NULL, &pChainContext)) { CRYPTOAPIerr(CRYPTOAPI_F_CERT_GET_CERT_CHAIN); goto err; } /* return 1 when the certificate is trusted, 0 when it's not; -1 on error */ ret = (pChainContext->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR); err: if (buf) OPENSSL_free(buf); if (pChainContext) CertFreeCertificateChain(pChainContext); if (pCertContext) CertFreeCertificateContext(pCertContext); return ret; }
/* 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 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; }
// 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; }
int sserver_auth_protocol_connect(const struct protocol_interface *protocol, const char *auth_string) { CScramble scramble; char *tmp; int certonly; char *client_version = NULL; char keyfile[256]; const char *hostname = NULL; if (!strcmp (auth_string, "BEGIN SSL VERIFICATION REQUEST")) sserver_protocol_interface.verify_only = 1; else if (!strcmp (auth_string, "BEGIN SSL AUTH REQUEST")) sserver_protocol_interface.verify_only = 0; else return CVSPROTO_NOTME; write(current_server()->out_fd,SSERVER_INIT_STRING,sizeof(SSERVER_INIT_STRING)-1); if(!CGlobalSettings::GetGlobalValue("cvsnt","PServer","CertificatesOnly",keyfile,sizeof(keyfile))) certonly = atoi(keyfile); if(!CGlobalSettings::GetGlobalValue("cvsnt","PServer","ServerDnsName",keyfile,sizeof(keyfile))) hostname = keyfile; if(!ServerAuthenticate(hostname)) return CVSPROTO_AUTHFAIL; QueryContextAttributes(&contextHandle,SECPKG_ATTR_STREAM_SIZES,&secSizes); g_sslBufferInPos=g_sslBufferOutPos=0; g_sslBufferInLen=g_sslBufferOutLen=0; set_encrypted_channel(1); /* Error must go through us now */ PCERT_CONTEXT sc; PCCERT_CHAIN_CONTEXT pcc; CERT_SIMPLE_CHAIN *psc; CERT_CHAIN_PARA para = { sizeof(CERT_CHAIN_PARA) }; DWORD trust,rc; BOOL cert = FALSE; rc = QueryContextAttributes(&contextHandle,SECPKG_ATTR_REMOTE_CERT_CONTEXT,&sc); if(rc && rc!=SEC_E_NO_CREDENTIALS) server_error(1,"Couldn't get client certificate"); if(rc!=SEC_E_NO_CREDENTIALS) /* The client doesn't have to send us a cert. as cvs uses passwords normally */ { if(!CertGetCertificateChain(NULL, sc, NULL, NULL, ¶, 0, NULL, &pcc)) server_error(1,"Couldn't get client certificate chain"); psc = pcc->rgpChain[0]; trust = psc->TrustStatus.dwErrorStatus; if (trust) { if (trust & (CERT_TRUST_IS_PARTIAL_CHAIN | CERT_TRUST_IS_UNTRUSTED_ROOT)) server_error(1,"Client sent self signed certificate"); else if (trust & (CERT_TRUST_IS_NOT_TIME_VALID)) server_error(1,"Client certificate expired"); else server_error(1,"Client certificate verification failed - %08x",trust); } CertFreeCertificateChain(pcc); FreeContextBuffer(sc); cert = TRUE; } /* Get the three important pieces of information in order. */ /* See above comment about error handling. */ /* get version, if sent. 1.0 clients didn't have this handshake so we have to handle that. */ server_getline (protocol, &client_version, MAX_PATH); if(strncmp(client_version,"SSERVER-CLIENT ",15)) { sserver_protocol_interface.auth_repository = client_version; client_version = NULL; } else server_getline (protocol, &sserver_protocol_interface.auth_repository, MAX_PATH); server_getline (protocol, &sserver_protocol_interface.auth_username, MAX_PATH); server_getline (protocol, &sserver_protocol_interface.auth_password, MAX_PATH); if(client_version) free(client_version); client_version = NULL; /* ... and make sure the protocol ends on the right foot. */ /* See above comment about error handling. */ server_getline(protocol, &tmp, MAX_PATH); if (strcmp (tmp, sserver_protocol_interface.verify_only ? "END SSL VERIFICATION REQUEST" : "END SSL AUTH REQUEST") != 0) { server_printf ("bad auth protocol end: %s\n", tmp); free(tmp); return CVSPROTO_FAIL; } strcpy(sserver_protocol_interface.auth_password, scramble.Unscramble(sserver_protocol_interface.auth_password)); free(tmp); switch(certonly) { case 0: break; case 1: if(!cert) { server_error(0,"E Login requires a valid client certificate.\n"); return CVSPROTO_AUTHFAIL; } free(sserver_protocol_interface.auth_password); sserver_protocol_interface.auth_password = NULL; break; case 2: if(!cert) { server_error(0,"E Login requires a valid client certificate.\n"); return CVSPROTO_AUTHFAIL; } break; }; return CVSPROTO_SUCCESS; }
/***************************************************************************** HrSign Creates XML signature *****************************************************************************/ HRESULT HrSign( LPCWSTR wszFileOut, const SIGN_PARA *pPara, ULONG argc, LPWSTR argv[] ) { HCRYPTXML hSig = NULL; HCRYPTXML hRef = NULL; HRESULT hr = S_FALSE; ULONG i; const CRYPT_XML_ALGORITHM_INFO* pAlgInfo = NULL; PCCERT_CHAIN_CONTEXT pChainContext = NULL; HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProvOrNCryptKey = NULL; // No release DWORD dwKeySpec = 0; PCCERT_CONTEXT pCert = NULL; // No release CRYPT_XML_STATUS Status = {0}; ULONG cTransform = 0; CRYPT_XML_ALGORITHM *pTransform = NULL; const CRYPT_XML_REFERENCE *pRef = NULL; CRYPT_XML_DATA_PROVIDER DataProvider = {0}; CRYPT_XML_PROPERTY Properties[] = { { // // This property is required for Enveloped or Enveloping signatures // CRYPT_XML_PROPERTY_SIGNATURE_LOCATION, NULL, sizeof(LPCWSTR) }, }; ULONG cProperties = 0; CRYPT_XML_BLOB Encoded = { CRYPT_XML_CHARSET_AUTO, 0, NULL }; CRYPT_XML_ALGORITHM xmlAlg_CanonicalizationMethod = { sizeof( CRYPT_XML_ALGORITHM ), (LPWSTR)pPara->wszCanonicalizationMethod, CRYPT_XML_CHARSET_AUTO, 0, NULL }; CRYPT_XML_ALGORITHM xmlAlg_SignatureMethod = { sizeof( CRYPT_XML_ALGORITHM ), NULL, CRYPT_XML_CHARSET_AUTO, 0, NULL }; CRYPT_XML_ALGORITHM xmlAlg_DigestMethod = { sizeof( CRYPT_XML_ALGORITHM ), NULL, CRYPT_XML_CHARSET_AUTO, 0, NULL }; CRYPT_XML_ALGORITHM xmlAlg_Enveloped = { sizeof( CRYPT_XML_ALGORITHM ), wszURI_XMLNS_TRANSFORM_ENVELOPED, CRYPT_XML_CHARSET_AUTO, 0, NULL }; HANDLE hFile = INVALID_HANDLE_VALUE; // // Create the output file. // This handle will be used by HrWriteXmlToFileCallback and must be closed // at the exit. // hFile = CreateFile( wszFileOut, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if( INVALID_HANDLE_VALUE == hFile ) { hr = HRESULT_FROM_WIN32( GetLastError() ); wprintf( L"ERROR: Unable to create file: '%s'.\r\n", wszFileOut ); goto CleanUp; } // // Find the signing certificate // hr = HrGetSignerKeyAndChain( pPara->wszSubject, &pChainContext, &hCryptProvOrNCryptKey, &dwKeySpec ); if( FAILED(hr) ) { wprintf( L"ERROR: 0x%08x - Unable to get signing certificate.\r\n", hr ); goto CleanUp; } // // Determine the Digest Method // { pAlgInfo = CryptXmlFindAlgorithmInfo( CRYPT_XML_ALGORITHM_INFO_FIND_BY_CNG_ALGID, pPara->wszHashAlgName, CRYPT_XML_GROUP_ID_HASH, 0 ); if( NULL == pAlgInfo ) { hr = CRYPT_XML_E_ALGORITHM; goto CleanUp; } xmlAlg_DigestMethod.wszAlgorithm = pAlgInfo->wszAlgorithmURI; } // // Determine the Signature Method // pCert = pChainContext->rgpChain[0]->rgpElement[0]->pCertContext; { PCCRYPT_OID_INFO pOIDInfo = NULL; LPCWSTR pwszCNGAlgid[2] = {0}; // // First, find the Public Key algorithm name // pOIDInfo = CryptFindOIDInfo( CRYPT_OID_INFO_OID_KEY, pCert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, CRYPT_PUBKEY_ALG_OID_GROUP_ID ); if( NULL == pOIDInfo || NULL == pOIDInfo->pwszCNGAlgid ) { hr = CRYPT_XML_E_ALGORITHM; goto CleanUp; } // // Second, find XML DigSig URI that corresponds to // combined HASH and Public Key algorithm names. // pwszCNGAlgid[0] = pPara->wszHashAlgName; pwszCNGAlgid[1] = pOIDInfo->pwszCNGAlgid; pAlgInfo = CryptXmlFindAlgorithmInfo( CRYPT_XML_ALGORITHM_INFO_FIND_BY_CNG_SIGN_ALGID, pwszCNGAlgid, CRYPT_XML_GROUP_ID_SIGN, 0 ); if( NULL == pAlgInfo ) { hr = CRYPT_XML_E_ALGORITHM; goto CleanUp; } xmlAlg_SignatureMethod.wszAlgorithm = pAlgInfo->wszAlgorithmURI; } // // Load input XML file. This must be provided for Enveloped or Enveloping signature // if( NULL != pPara->wszFileIn ) { hr = HrLoadFile( pPara->wszFileIn, &Encoded.pbData, &Encoded.cbData ); if( FAILED(hr) ) { goto CleanUp; } } // // Create the document context // if( NULL != pPara->wszSignatureLocation && 0 != *pPara->wszSignatureLocation ) { // The <Signature> element will be added into this location Properties[0].pvValue = &pPara->wszSignatureLocation; cProperties++; } hr = CryptXmlOpenToEncode( NULL, // No custom transforms 0, pPara->wszSignatureId, Properties, cProperties, (Encoded.cbData > 0 ) ? &Encoded : NULL, &hSig ); if( FAILED(hr) ) { goto CleanUp; } // // Create references // for( i=0; i<argc; i++ ) { DWORD dwReferenceFlags = 0; LPCWSTR wsRefId = NULL; LPCWSTR wsUri = NULL; if( L'#' != *argv[i] ) { wprintf( L"ERROR: Invalid reference: %s.\r\n", argv[i] ); hr = E_INVALIDARG; goto CleanUp; } wsUri = argv[i]; if( 0 == wsUri[1] && 1==argc ) { // // Special case for Enveloped // The URI must be "" // wsUri = L""; cTransform = 1; pTransform = &xmlAlg_Enveloped; } else if( i+1 < argc ) { // // Check if external file is specified // if( L'#' != *argv[i+1] ) { i++; wsRefId = wsUri+1; wsUri = argv[i]; } cTransform = 0; pTransform = NULL; } hr = CryptXmlCreateReference( hSig, // Parent dwReferenceFlags, // Flags wsRefId, wsUri, NULL, &xmlAlg_DigestMethod, cTransform, pTransform, &hRef ); if( FAILED(hr) ) { goto CleanUp; } hr = CryptXmlGetStatus( hRef, &Status ); if( FAILED(hr) ) { goto CleanUp; } if( 0 != ( Status.dwErrorStatus & CRYPT_XML_STATUS_ERROR_NOT_RESOLVED )) { // // Resolve the external references only. // The internal references will be resolved by CryptXml during CryptXmlSign // if( 0 == ( Status.dwInfoStatus & CRYPT_XML_STATUS_INTERNAL_REFERENCE )) { hr = CryptXmlGetReference( hRef, &pRef ); if( FAILED(hr) ) { goto CleanUp; } hr = HrSampleResolveExternalXmlReference( pRef->wszUri, &DataProvider ); if( FAILED(hr) ) { goto CleanUp; } if( NULL == DataProvider.pfnRead ) { // // Unable to open file for reading // hr = CRYPT_XML_E_UNRESOLVED_REFERENCE; goto CleanUp; } // // Digest the reference // hr = CryptXmlDigestReference( hRef, 0, &DataProvider ); if( FAILED(hr) ) { goto CleanUp; } // // Provider must be released by the callee, which is CryptXmlDigestReference // ZeroMemory( &DataProvider, sizeof DataProvider ); } } } { // // Sign // DWORD dwSignFlags = 0; CRYPT_XML_KEYINFO_PARAM KeyInfoParam = {0}; CERT_BLOB rgCertificate[8] = {0}; DWORD c; // // Include the chain up to the Root // for( c=0; c<pChainContext->rgpChain[0]->cElement-1 && c<ARRAYSIZE(rgCertificate); c++ ) { rgCertificate[c].pbData = pChainContext->rgpChain[0]->rgpElement[c]->pCertContext->pbCertEncoded; rgCertificate[c].cbData = pChainContext->rgpChain[0]->rgpElement[c]->pCertContext->cbCertEncoded; } KeyInfoParam.cCertificate = c; KeyInfoParam.rgCertificate = rgCertificate; KeyInfoParam.wszId = pPara->wszKeyInfoId; if( pPara->fKV ) { dwSignFlags |= CRYPT_XML_SIGN_ADD_KEYVALUE; } hr = CryptXmlSign( hSig, hCryptProvOrNCryptKey, dwKeySpec, dwSignFlags, CRYPT_XML_KEYINFO_SPEC_PARAM, &KeyInfoParam, &xmlAlg_SignatureMethod, &xmlAlg_CanonicalizationMethod ); if( FAILED(hr) ) { wprintf( L"FAIL: 0x%08x CryptXmlSign\r\n", hr ); goto CleanUp; } wprintf( L"Successfully signed and created signature.\r\n" ); } { // // Encode the Signature to file // static BOOL fTRUE = TRUE; CRYPT_XML_PROPERTY rgEncodeProperty[] = { { // // This property is used to produce the declaration at the top of XML. // <?xml version="1.0" encoding="utf-8" standalone="yes"?> // CRYPT_XML_PROPERTY_DOC_DECLARATION, &fTRUE, sizeof(fTRUE) }, }; hr = CryptXmlEncode( hSig, CRYPT_XML_CHARSET_UTF8, rgEncodeProperty, ARRAYSIZE(rgEncodeProperty), hFile, HrWriteXmlToFileCallback ); if( FAILED(hr) ) { goto CleanUp; } wprintf( L"Successfully encoded signature to '%s'.\r\n", wszFileOut ); } CleanUp: if( INVALID_HANDLE_VALUE != hFile ) { CloseHandle( hFile ); } if( NULL != Encoded.pbData ) { LocalFree( Encoded.pbData ); } if( NULL != pChainContext ) { CertFreeCertificateChain(pChainContext); } if( NULL != hSig ) { CryptXmlClose( hSig ); } return hr; }
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; }
int sserver_connect(const struct protocol_interface *protocol, int verify_only) { char crypt_password[64]; char server_version[128]; char tmp_keyname[256]; const char *begin_request = "BEGIN SSL AUTH REQUEST"; const char *end_request = "END SSL AUTH REQUEST"; const char *username = NULL; const char *cert = current_server()->current_root->optional_3; int l; int sserver_version = 0; int strict = 0; CScramble scramble; bool send_client_version = false; if(current_server()->current_root->optional_1) { sserver_version = atoi(current_server()->current_root->optional_1); if(sserver_version != 0 && sserver_version != 1) { server_error(0,"version must be one of:"); server_error(0,"0 - All CVSNT-type servers"); server_error(0,"1 - Unix server using Corey Minards' sserver patches"); server_error(1,"Please specify a valid value"); } } if(!CGlobalSettings::GetUserValue("cvsnt","sserver","StrictChecking",server_version,sizeof(server_version))) { strict = atoi(server_version); } if(!cert && !CGlobalSettings::GetUserValue("cvsnt","sserver","ClientCert",tmp_keyname,sizeof(tmp_keyname))) { cert = tmp_keyname; } if(current_server()->current_root->optional_2) strict = atoi(current_server()->current_root->optional_2); if(sserver_version == 1) /* Old sserver */ { begin_request = verify_only?"BEGIN SSL VERIFICATION REQUEST":"BEGIN SSL REQUEST"; end_request = verify_only?"END SSL VERIFICATION REQUEST":"END SSL REQUEST"; } else if(verify_only) { begin_request = "BEGIN SSL VERIFICATION REQUEST"; end_request = "END SSL VERIFICATION REQUEST"; } username = get_username(current_server()->current_root); if(!username || !current_server()->current_root->hostname || !current_server()->current_root->directory) return CVSPROTO_BADPARMS; if(tcp_connect(current_server()->current_root)) return CVSPROTO_FAIL; if(current_server()->current_root->password) strncpy(crypt_password,scramble.Scramble(current_server()->current_root->password),sizeof(crypt_password)); else { if(sserver_get_user_password(username,current_server()->current_root->hostname,current_server()->current_root->port,current_server()->current_root->directory,crypt_password,sizeof(crypt_password))) { /* Using null password - trace something out here */ server_error(0,"Using an empty password; you may need to do 'cvs login' with a real password\n"); strncpy(crypt_password,scramble.Scramble(""),sizeof(crypt_password)); } } if(sserver_version == 0) /* Pre-CVSNT had no version check */ { if(tcp_printf("%s\n",begin_request)<0) return CVSPROTO_FAIL; for(;;) { *server_version='\0'; if((l=tcp_readline(server_version,sizeof(server_version))<0)) return CVSPROTO_FAIL; if(*server_version) break; #ifdef _WIN32 Sleep(10); #else usleep(10); #endif } if(strncmp(server_version,"SSERVER ",8)) { server_error(0,"%s\n",server_version); return CVSPROTO_FAIL; } if(strncmp(server_version+8,"1.0 ",4)) send_client_version = true; } if(!ClientAuthenticate(cert,current_server()->current_root->hostname)) return CVSPROTO_AUTHFAIL; QueryContextAttributes(&contextHandle,SECPKG_ATTR_STREAM_SIZES,&secSizes); PCERT_CONTEXT sc; PCCERT_CHAIN_CONTEXT pcc; CERT_SIMPLE_CHAIN *psc; CERT_CHAIN_PARA para = { sizeof(CERT_CHAIN_PARA) }; DWORD trust,rc; rc = QueryContextAttributes(&contextHandle,SECPKG_ATTR_REMOTE_CERT_CONTEXT,&sc); if(rc) server_error(1,"Couldn't get server certificate"); if(!CertGetCertificateChain(NULL, sc, NULL, NULL, ¶, 0, NULL, &pcc)) server_error(1,"Couldn't get server certificate chain"); psc = pcc->rgpChain[0]; trust = psc->TrustStatus.dwErrorStatus; if (trust) { if (trust & (CERT_TRUST_IS_PARTIAL_CHAIN | CERT_TRUST_IS_UNTRUSTED_ROOT)) ; // Seld signed else if (trust & (CERT_TRUST_IS_NOT_TIME_VALID)) server_error(1,"Server certificate expired"); else server_error(1,"Server certificate verification failed - %08x",trust); } if(strict) { char certname[256]; CertGetNameString(sc, CERT_NAME_DNS_TYPE, 0, NULL, certname, sizeof(certname)); if(strcasecmp(certname,current_server()->current_root->hostname)) server_error(1, "Certificate CommonName '%s' does not match server name '%s'\n",certname,current_server()->current_root->hostname); } CertFreeCertificateChain(pcc); FreeContextBuffer(sc); g_sslBufferInPos=g_sslBufferOutPos=0; g_sslBufferInLen=g_sslBufferOutLen=0; if(sserver_version == 1) { if(sserver_printf("%s\n",begin_request)<0) return CVSPROTO_FAIL; } // For server versions 1.1+ send CLIENT_VERSION_STRING if(send_client_version && sserver_printf(SSERVER_CLIENT_VERSION_STRING)<0) return CVSPROTO_FAIL; if(sserver_printf("%s\n%s\n",current_server()->current_root->directory,username)<0) return CVSPROTO_FAIL; if(sserver_printf("%s\n",crypt_password)<0) return CVSPROTO_FAIL; if(sserver_printf("%s\n",end_request)<0) return CVSPROTO_FAIL; return CVSPROTO_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 CURLcode verify_certificate(struct connectdata *conn, int sockindex) { SECURITY_STATUS status; struct SessionHandle *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; CURLcode result = CURLE_OK; CERT_CONTEXT *pCertContextServer = NULL; const CERT_CHAIN_CONTEXT *pChainContext = NULL; status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &pCertContextServer); if((status != SEC_E_OK) || (pCertContextServer == NULL)) { failf(data, "schannel: Failed to read remote certificate context: %s", Curl_sspi_strerror(conn, status)); result = CURLE_PEER_FAILED_VERIFICATION; } if(result == CURLE_OK) { CERT_CHAIN_PARA ChainPara; memset(&ChainPara, 0, sizeof(ChainPara)); ChainPara.cbSize = sizeof(ChainPara); if(!CertGetCertificateChain(NULL, pCertContextServer, NULL, pCertContextServer->hCertStore, &ChainPara, 0, NULL, &pChainContext)) { failf(data, "schannel: CertGetCertificateChain failed: %s", Curl_sspi_strerror(conn, GetLastError())); pChainContext = NULL; result = CURLE_PEER_FAILED_VERIFICATION; } if(result == CURLE_OK) { CERT_SIMPLE_CHAIN *pSimpleChain = pChainContext->rgpChain[0]; DWORD dwTrustErrorMask = ~(DWORD)(CERT_TRUST_IS_NOT_TIME_NESTED| CERT_TRUST_REVOCATION_STATUS_UNKNOWN); dwTrustErrorMask &= pSimpleChain->TrustStatus.dwErrorStatus; if(dwTrustErrorMask) { if(dwTrustErrorMask & CERT_TRUST_IS_PARTIAL_CHAIN) failf(data, "schannel: CertGetCertificateChain trust error" " CERT_TRUST_IS_PARTIAL_CHAIN"); if(dwTrustErrorMask & CERT_TRUST_IS_UNTRUSTED_ROOT) failf(data, "schannel: CertGetCertificateChain trust error" " CERT_TRUST_IS_UNTRUSTED_ROOT"); if(dwTrustErrorMask & CERT_TRUST_IS_NOT_TIME_VALID) failf(data, "schannel: CertGetCertificateChain trust error" " CERT_TRUST_IS_NOT_TIME_VALID"); failf(data, "schannel: CertGetCertificateChain error mask: 0x%08x", dwTrustErrorMask); result = CURLE_PEER_FAILED_VERIFICATION; } } } if(result == CURLE_OK) { if(data->set.ssl.verifyhost) { TCHAR cert_hostname_buff[128]; xcharp_u hostname; xcharp_u cert_hostname; DWORD len; cert_hostname.const_tchar_ptr = cert_hostname_buff; hostname.tchar_ptr = Curl_convert_UTF8_to_tchar(conn->host.name); len = CertGetNameString(pCertContextServer, CERT_NAME_DNS_TYPE, 0, NULL, cert_hostname.tchar_ptr, 128); if(len > 0 && *cert_hostname.tchar_ptr == '*') { /* this is a wildcard cert. try matching the last len - 1 chars */ int hostname_len = strlen(conn->host.name); cert_hostname.tchar_ptr++; if(_tcsicmp(cert_hostname.const_tchar_ptr, hostname.const_tchar_ptr + hostname_len - len + 2) != 0) result = CURLE_PEER_FAILED_VERIFICATION; } else if(len == 0 || _tcsicmp(hostname.const_tchar_ptr, cert_hostname.const_tchar_ptr) != 0) { result = CURLE_PEER_FAILED_VERIFICATION; } if(result == CURLE_PEER_FAILED_VERIFICATION) { char *_cert_hostname; _cert_hostname = Curl_convert_tchar_to_UTF8(cert_hostname.tchar_ptr); failf(data, "schannel: CertGetNameString() certificate hostname " "(%s) did not match connection (%s)", _cert_hostname, conn->host.name); Curl_unicodefree(_cert_hostname); } Curl_unicodefree(hostname.tchar_ptr); } } if(pChainContext) CertFreeCertificateChain(pChainContext); if(pCertContextServer) CertFreeCertificateContext(pCertContextServer); return result; }
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; }
/*********************************************************************** * CertTrustFinalPolicy (CRYPTDLG.@) */ HRESULT WINAPI CertTrustFinalPolicy(CRYPT_PROVIDER_DATA *data) { BOOL ret; DWORD err = S_OK; CERT_VERIFY_CERTIFICATE_TRUST *pCert = CRYPTDLG_GetVerifyData(data); TRACE("(%p)\n", data); if (data->pWintrustData->dwUIChoice != WTD_UI_NONE) FIXME("unimplemented for UI choice %d\n", data->pWintrustData->dwUIChoice); if (pCert) { DWORD flags = 0; CERT_CHAIN_PARA chainPara; HCERTCHAINENGINE engine; memset(&chainPara, 0, sizeof(chainPara)); chainPara.cbSize = sizeof(chainPara); if (CRYPTDLG_CheckOnlineCRL()) flags |= CERT_CHAIN_REVOCATION_CHECK_END_CERT; engine = CRYPTDLG_MakeEngine(pCert); GetSystemTimeAsFileTime(&data->sftSystemTime); ret = CRYPTDLG_IsCertAllowed(pCert->pccert); if (ret) { PCCERT_CHAIN_CONTEXT chain; ret = CertGetCertificateChain(engine, pCert->pccert, &data->sftSystemTime, NULL, &chainPara, flags, NULL, &chain); if (ret) { if (chain->cChain != 1) { FIXME("unimplemented for more than 1 simple chain\n"); err = TRUST_E_SUBJECT_FORM_UNKNOWN; ret = FALSE; } else if ((ret = CRYPTDLG_CopyChain(data, chain))) { if (CertVerifyTimeValidity(&data->sftSystemTime, pCert->pccert->pCertInfo)) { ret = FALSE; err = CERT_E_EXPIRED; } } else err = TRUST_E_SYSTEM_ERROR; CertFreeCertificateChain(chain); } else err = TRUST_E_SUBJECT_NOT_TRUSTED; } CertFreeCertificateChainEngine(engine); } else { ret = FALSE; err = TRUST_E_NOSIGNATURE; } /* Oddly, native doesn't set the error in the trust step error location, * probably because this action is more advisory than anything else. * Instead it stores it as the final error, but the function "succeeds" in * any case. */ if (!ret) data->dwFinalError = err; TRACE("returning %d (%08x)\n", S_OK, data->dwFinalError); return S_OK; }
static void check_and_store_certs(HCERTSTORE from, HCERTSTORE to) { DWORD root_count = 0; CERT_CHAIN_ENGINE_CONFIG chainEngineConfig = { sizeof(chainEngineConfig), 0 }; HCERTCHAINENGINE engine; TRACE("\n"); CertDuplicateStore(to); engine = CRYPT_CreateChainEngine(to, CERT_SYSTEM_STORE_CURRENT_USER, &chainEngineConfig); if (engine) { PCCERT_CONTEXT cert = NULL; do { cert = CertEnumCertificatesInStore(from, cert); if (cert) { CERT_CHAIN_PARA chainPara = { sizeof(chainPara), { 0 } }; PCCERT_CHAIN_CONTEXT chain; BOOL ret; ret = CertGetCertificateChain(engine, cert, NULL, from, &chainPara, CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL, NULL, &chain); if (!ret) TRACE("rejecting %s: %s\n", get_cert_common_name(cert), "chain creation failed"); else { DWORD allowedErrors = CERT_TRUST_IS_UNTRUSTED_ROOT | CERT_TRUST_IS_NOT_VALID_FOR_USAGE | CERT_TRUST_INVALID_BASIC_CONSTRAINTS | CERT_TRUST_IS_NOT_TIME_VALID; /* The certificate chain verification only allows certain * invalid CA certs if they're installed locally: CA * certs missing the key usage extension, and CA certs * missing the basic constraints extension. Of course * there's a chicken and egg problem: we have to accept * them here in order for them to be accepted later. * Expired, locally installed certs are also allowed here, * because we don't know (yet) what date will be checked * for an item signed by one of these certs. * Thus, accept certs with any of the allowed errors. */ if (chain->TrustStatus.dwErrorStatus & ~allowedErrors) TRACE("rejecting %s: %s\n", get_cert_common_name(cert), trust_status_to_str(chain->TrustStatus.dwErrorStatus & ~CERT_TRUST_IS_UNTRUSTED_ROOT)); else { DWORD i, j; for (i = 0; i < chain->cChain; i++) for (j = 0; j < chain->rgpChain[i]->cElement; j++) if (CertAddCertificateContextToStore(to, chain->rgpChain[i]->rgpElement[j]->pCertContext, CERT_STORE_ADD_NEW, NULL)) root_count++; } CertFreeCertificateChain(chain); } } } while (cert); CertFreeCertificateChainEngine(engine); } TRACE("Added %d root certificates\n", root_count); }
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