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); }
/*********************************************************************** * 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); }
/***************************************************************************** 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