DWORD StoreUserCert (PCCERT_CONTEXT pCertContext, unsigned char KeyUsageBits, CK_BYTE* cardSerialNumber, CK_ULONG cardSerialNumberLen) { unsigned long dwFlags = CERT_STORE_NO_CRYPT_RELEASE_FLAG; PCCERT_CONTEXT pDesiredCert = NULL; PCCERT_CONTEXT pPrevCert = NULL; DWORD dwRet = 0; wchar_t* pContainerName = NULL; size_t pContainerNameCharLen = cardSerialNumberLen+20; CK_CHAR_PTR pcardSerialNrString = NULL; wchar_t* pProviderName = NULL; CK_ULONG counter=0; HCERTSTORE hMyStore = CertOpenSystemStore((HCRYPTPROV_LEGACY)NULL, TEXT("MY")); CRYPT_KEY_PROV_INFO cryptKeyProvInfo; unsigned long dwPropId = CERT_KEY_PROV_INFO_PROP_ID; if (hMyStore == NULL) { dwRet = GetLastError(); printf("StoreUserCerts: Unable to open the system certificate store. Error code: %d.\n",dwRet); return dwRet; } // ---------------------------------------------------- // look if we already have a certificate with the same // subject (contains name and NNR) in the store // If the certificate is not found --> NULL // ---------------------------------------------------- do { if( NULL != (pDesiredCert = CertFindCertificateInStore(hMyStore, X509_ASN_ENCODING, 0, CERT_FIND_SUBJECT_NAME, &(pCertContext->pCertInfo->Subject) , pPrevCert))) { // ---------------------------------------------------- // If the certificates are identical and function // succeeds, the return value is nonzero, or TRUE. // ---------------------------------------------------- if(FALSE == CertCompareCertificate(X509_ASN_ENCODING,pCertContext->pCertInfo,pDesiredCert->pCertInfo) || !ProviderNameCorrect(pDesiredCert) ) { // ---------------------------------------------------- // certificates are not identical, but have the same // subject (contains name and NNR), // so we remove the one that was already in the store // ---------------------------------------------------- if(FALSE == CertDeleteCertificateFromStore(pDesiredCert)) { if (E_ACCESSDENIED == GetLastError()) { continue; } } pPrevCert = NULL; continue; } } pPrevCert = pDesiredCert; }while (NULL != pDesiredCert); // ---------------------------------------------------- // look if we already have the certificate in the store // If the certificate is not found --> NULL // ---------------------------------------------------- if( NULL != (pDesiredCert = CertFindCertificateInStore(hMyStore, X509_ASN_ENCODING, 0, CERT_FIND_EXISTING, pCertContext , NULL))) { // ---------------------------------------------------- // certificate is already in the store, then just return // ---------------------------------------------------- CertFreeCertificateContext(pDesiredCert); CertCloseStore (hMyStore, CERT_CLOSE_STORE_FORCE_FLAG); return 0; } pContainerName = (wchar_t*)malloc(sizeof(wchar_t) * (pContainerNameCharLen)); if(pContainerName == NULL) return E_OUTOFMEMORY; pcardSerialNrString = (CK_CHAR_PTR)malloc(cardSerialNumberLen*2 + 1); if(pcardSerialNrString == NULL) return E_OUTOFMEMORY; if(-1 == ByteArrayToString( &pcardSerialNrString, cardSerialNumberLen*2 + 1,cardSerialNumber ,cardSerialNumberLen)) return -1; if(pContainerName == NULL) { CertFreeCertificateContext(pDesiredCert); CertCloseStore (hMyStore, CERT_CLOSE_STORE_FORCE_FLAG); return -1; } if (UseMinidriver()) { if (KeyUsageBits & CERT_NON_REPUDIATION_KEY_USAGE) { swprintf_s(pContainerName,pContainerNameCharLen,L"NR_%hS",pcardSerialNrString); } else { swprintf_s(pContainerName,pContainerNameCharLen,L"DS_%hS",pcardSerialNrString); } cryptKeyProvInfo.pwszProvName = L"Microsoft Base Smart Card Crypto Provider"; cryptKeyProvInfo.dwKeySpec = AT_SIGNATURE; } else { if (KeyUsageBits & CERT_NON_REPUDIATION_KEY_USAGE) { swprintf_s(pContainerName,pContainerNameCharLen,L"Signature(%hS)",pcardSerialNrString); } else { swprintf_s(pContainerName,pContainerNameCharLen,L"Authentication(%hS)",pcardSerialNrString); } cryptKeyProvInfo.pwszProvName = L"Belgium Identity Card CSP"; cryptKeyProvInfo.dwKeySpec = AT_KEYEXCHANGE; } cryptKeyProvInfo.pwszContainerName = pContainerName; cryptKeyProvInfo.dwProvType = PROV_RSA_FULL; cryptKeyProvInfo.dwFlags = 0; cryptKeyProvInfo.cProvParam = 0; cryptKeyProvInfo.rgProvParam = NULL; /* // Set friendly names for the certificates DWORD dwsize = 0; dwsize = CertGetNameStringW(pCertContext, CERT_NAME_ATTR_TYPE, 0, szOID_COMMON_NAME, NULL, dwsize); auto_vec<WCHAR> pname(new WCHAR[dwsize]); dwsize = CertGetNameStringW(pCertContext, CERT_NAME_ATTR_TYPE, 0, szOID_COMMON_NAME, pname.get(), dwsize); CRYPT_DATA_BLOB tpFriendlyName = {0, 0}; tpFriendlyName.pbData = (BYTE *)pname.get(); tpFriendlyName.cbData = dwsize * sizeof(WCHAR); if (CertSetCertificateContextProperty( pCertContext, // A pointer to the certificate // where the propertiy will be set. CERT_FRIENDLY_NAME_PROP_ID, // An identifier of the property to be set. // In this case, CERT_KEY_PROV_INFO_PROP_ID // is to be set to provide a pointer with the // certificate to its associated private key // container. dwFlags, // The flag used in this case is // CERT_STORE_NO_CRYPT_RELEASE_FLAG // indicating that the cryptographic // context aquired should not // be released when the function finishes. &tpFriendlyName // A pointer to a data structure that holds // infomation on the private key container to // be associated with this certificate. )) */ // Set the property. if (CertSetCertificateContextProperty( pCertContext, // A pointer to the certificate where the property will be set. dwPropId, // An identifier of the property to be set. // In this case, CERT_KEY_PROV_INFO_PROP_ID is to be set to provide a pointer with the certificate to its associated private key container. dwFlags, // The flag used in this case is // CERT_STORE_NO_CRYPT_RELEASE_FLAG indicating that the cryptographic context acquired should not be released when the function finishes. &cryptKeyProvInfo // A pointer to a data structure that holds infomation on the private key container to be associated with this certificate. )) { if (KeyUsageBits & CERT_NON_REPUDIATION_KEY_USAGE) { CertAddEnhancedKeyUsageIdentifier (pCertContext, szOID_PKIX_KP_EMAIL_PROTECTION); } else { CertAddEnhancedKeyUsageIdentifier (pCertContext, szOID_PKIX_KP_EMAIL_PROTECTION); CertAddEnhancedKeyUsageIdentifier (pCertContext, szOID_PKIX_KP_CLIENT_AUTH); } if (CertAddCertificateContextToStore(hMyStore, pCertContext, CERT_STORE_ADD_REPLACE_EXISTING, NULL)) { printf("StoreUserCerts: Certificate context added to store."); dwRet = 0; } else { dwRet = GetLastError(); printf("StoreUserCerts: Unable to add certificate context to store. Error code: %d.",dwRet); } CertCloseStore (hMyStore, CERT_CLOSE_STORE_FORCE_FLAG); hMyStore = NULL; } if(pContainerName != NULL) free (pContainerName); return dwRet; }
my_bool ma_tls_connect(MARIADB_TLS *ctls) { my_bool blocking; MYSQL *mysql; SCHANNEL_CRED Cred; MARIADB_PVIO *pvio; my_bool rc= 1; SC_CTX *sctx; SECURITY_STATUS sRet; PCCERT_CONTEXT pRemoteCertContext = NULL, pLocalCertContext= NULL; ALG_ID AlgId[MAX_ALG_ID]= {0}; if (!ctls || !ctls->pvio) return 1;; pvio= ctls->pvio; sctx= (SC_CTX *)ctls->ssl; /* Set socket to blocking if not already set */ if (!(blocking= pvio->methods->is_blocking(pvio))) pvio->methods->blocking(pvio, TRUE, 0); mysql= pvio->mysql; if (ma_tls_set_client_certs(ctls)) goto end; ZeroMemory(&Cred, sizeof(SCHANNEL_CRED)); /* Set cipher */ if (mysql->options.ssl_cipher) { WORD validTokens = 0; char *token = strtok(mysql->options.ssl_cipher, ":"); while (token) { struct st_cipher_suite *valid; for (valid = valid_ciphers; valid && valid->aid; valid++) { if (!strcmp(token, valid->cipher)) { AlgId[validTokens++] = valid->aid; break; } } token = strtok(NULL, ":"); } } Cred.palgSupportedAlgs = (ALG_ID *)&AlgId; Cred.dwVersion= SCHANNEL_CRED_VERSION; if (mysql->options.extension) Cred.dwMinimumCipherStrength = MAX(128, mysql->options.extension->tls_cipher_strength); else Cred.dwMinimumCipherStrength = 128; Cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK | SCH_SEND_ROOT_CERT | SCH_CRED_NO_DEFAULT_CREDS | SCH_CRED_MANUAL_CRED_VALIDATION; if (sctx->client_cert_ctx) { Cred.cCreds = 1; Cred.paCred = &sctx->client_cert_ctx; } if (mysql->options.extension && mysql->options.extension->tls_version) { Cred.grbitEnabledProtocols= 0; if (strstr("TLSv1.0", mysql->options.extension->tls_version)) Cred.grbitEnabledProtocols|= SP_PROT_TLS1_0; if (strstr("TLSv1.1", mysql->options.extension->tls_version)) Cred.grbitEnabledProtocols|= SP_PROT_TLS1_1; if (strstr("TLSv1.2", mysql->options.extension->tls_version)) Cred.grbitEnabledProtocols|= SP_PROT_TLS1_2; } else Cred.grbitEnabledProtocols = SP_PROT_TLS1_0 | SP_PROT_TLS1_1 | SP_PROT_TLS1_2; if ((sRet= AcquireCredentialsHandleA(NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL, &Cred, NULL, NULL, &sctx->CredHdl, NULL)) != SEC_E_OK) { ma_schannel_set_sec_error(pvio, sRet); goto end; } sctx->FreeCredHdl= 1; if (ma_schannel_client_handshake(ctls) != SEC_E_OK) goto end; sRet= QueryContextAttributes(&sctx->ctxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pRemoteCertContext); if (sRet != SEC_E_OK) { ma_schannel_set_sec_error(pvio, sRet); goto end; } if (!ma_schannel_verify_certs(sctx, 0)) goto end; return 0; end: if (pRemoteCertContext) CertFreeCertificateContext(pRemoteCertContext); if (rc && sctx->IoBufferSize) LocalFree(sctx->IoBuffer); sctx->IoBufferSize= 0; if (sctx->client_cert_ctx) CertFreeCertificateContext(sctx->client_cert_ctx); sctx->client_cert_ctx= 0; return 1; }
static void test_getObjectUrl(void) { BOOL ret; DWORD urlArraySize = 0, infoSize = 0; PCCERT_CONTEXT cert; SetLastError(0xdeadbeef); ret = CryptGetObjectUrl(NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL); ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); /* Crash ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, NULL, 0, NULL, NULL, NULL, NULL, NULL); ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, NULL, 0, NULL, NULL, NULL, &infoSize, NULL); ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, NULL, 0, NULL, &urlArraySize, NULL, &infoSize, NULL); */ /* A cert with no CRL dist point extension fails.. */ cert = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert, sizeof(bigCert)); SetLastError(0xdeadbeef); ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, (void *)cert, 0, NULL, NULL, NULL, NULL, NULL); ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); CertFreeCertificateContext(cert); cert = CertCreateCertificateContext(X509_ASN_ENCODING, certWithIssuingDistPoint, sizeof(certWithIssuingDistPoint)); if (cert) { /* This cert has no AIA extension, so expect this to fail */ SetLastError(0xdeadbeef); ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, (void *)cert, 0, NULL, NULL, NULL, NULL, NULL); ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); SetLastError(0xdeadbeef); ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, (void *)cert, CRYPT_GET_URL_FROM_PROPERTY, NULL, NULL, NULL, NULL, NULL); ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); SetLastError(0xdeadbeef); ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, (void *)cert, CRYPT_GET_URL_FROM_EXTENSION, NULL, NULL, NULL, NULL, NULL); ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); /* It does have an issuing dist point extension, but that's not what * this is looking for (it wants a CRL dist points extension) */ SetLastError(0xdeadbeef); ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT, (void *)cert, 0, NULL, NULL, NULL, NULL, NULL); ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); SetLastError(0xdeadbeef); ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT, (void *)cert, CRYPT_GET_URL_FROM_PROPERTY, NULL, NULL, NULL, NULL, NULL); ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); SetLastError(0xdeadbeef); ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT, (void *)cert, CRYPT_GET_URL_FROM_EXTENSION, NULL, NULL, NULL, NULL, NULL); ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); CertFreeCertificateContext(cert); } cert = CertCreateCertificateContext(X509_ASN_ENCODING, certWithCRLDistPoint, sizeof(certWithCRLDistPoint)); if (cert) { PCRYPT_URL_ARRAY urlArray; /* This cert has no AIA extension, so expect this to fail */ SetLastError(0xdeadbeef); ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, (void *)cert, 0, NULL, NULL, NULL, NULL, NULL); ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); SetLastError(0xdeadbeef); ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, (void *)cert, CRYPT_GET_URL_FROM_PROPERTY, NULL, NULL, NULL, NULL, NULL); ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); SetLastError(0xdeadbeef); ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, (void *)cert, CRYPT_GET_URL_FROM_EXTENSION, NULL, NULL, NULL, NULL, NULL); ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); /* It does have a CRL dist points extension */ SetLastError(0xdeadbeef); ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT, (void *)cert, 0, NULL, NULL, NULL, NULL, NULL); ok(!ret && GetLastError() == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", GetLastError()); SetLastError(0xdeadbeef); ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT, (void *)cert, 0, NULL, NULL, NULL, &infoSize, NULL); ok(!ret && GetLastError() == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", GetLastError()); /* Can get it without specifying the location: */ ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT, (void *)cert, 0, NULL, &urlArraySize, NULL, NULL, NULL); ok(ret, "CryptGetObjectUrl failed: %08x\n", GetLastError()); urlArray = HeapAlloc(GetProcessHeap(), 0, urlArraySize); if (urlArray) { ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT, (void *)cert, 0, urlArray, &urlArraySize, NULL, NULL, NULL); ok(ret, "CryptGetObjectUrl failed: %08x\n", GetLastError()); if (ret) { LPWSTR pUrl = url; CRYPT_URL_ARRAY expectedUrl = { 1, &pUrl }; compareUrlArray(&expectedUrl, urlArray); } HeapFree(GetProcessHeap(), 0, urlArray); } /* or by specifying it's an extension: */ ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT, (void *)cert, CRYPT_GET_URL_FROM_EXTENSION, NULL, &urlArraySize, NULL, NULL, NULL); ok(ret, "CryptGetObjectUrl failed: %08x\n", GetLastError()); urlArray = HeapAlloc(GetProcessHeap(), 0, urlArraySize); if (urlArray) { ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT, (void *)cert, CRYPT_GET_URL_FROM_EXTENSION, urlArray, &urlArraySize, NULL, NULL, NULL); ok(ret, "CryptGetObjectUrl failed: %08x\n", GetLastError()); if (ret) { LPWSTR pUrl = url; CRYPT_URL_ARRAY expectedUrl = { 1, &pUrl }; compareUrlArray(&expectedUrl, urlArray); } HeapFree(GetProcessHeap(), 0, urlArray); } /* but it isn't contained in a property: */ SetLastError(0xdeadbeef); ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT, (void *)cert, CRYPT_GET_URL_FROM_PROPERTY, NULL, &urlArraySize, NULL, NULL, NULL); ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); CertFreeCertificateContext(cert); } }
BOOL netconn_secure_connect( netconn_t *conn, WCHAR *hostname, DWORD security_flags, CredHandle *cred_handle ) { SecBuffer out_buf = {0, SECBUFFER_TOKEN, NULL}, in_bufs[2] = {{0, SECBUFFER_TOKEN}, {0, SECBUFFER_EMPTY}}; SecBufferDesc out_desc = {SECBUFFER_VERSION, 1, &out_buf}, in_desc = {SECBUFFER_VERSION, 2, in_bufs}; BYTE *read_buf; SIZE_T read_buf_size = 2048; ULONG attrs = 0; CtxtHandle ctx; SSIZE_T size; const CERT_CONTEXT *cert; SECURITY_STATUS status; DWORD res = ERROR_SUCCESS; const DWORD isc_req_flags = ISC_REQ_ALLOCATE_MEMORY|ISC_REQ_USE_SESSION_KEY|ISC_REQ_CONFIDENTIALITY |ISC_REQ_SEQUENCE_DETECT|ISC_REQ_REPLAY_DETECT|ISC_REQ_MANUAL_CRED_VALIDATION; read_buf = heap_alloc(read_buf_size); if(!read_buf) return FALSE; status = InitializeSecurityContextW(cred_handle, NULL, hostname, isc_req_flags, 0, 0, NULL, 0, &ctx, &out_desc, &attrs, NULL); assert(status != SEC_E_OK); while(status == SEC_I_CONTINUE_NEEDED || status == SEC_E_INCOMPLETE_MESSAGE) { if(out_buf.cbBuffer) { assert(status == SEC_I_CONTINUE_NEEDED); TRACE("sending %u bytes\n", out_buf.cbBuffer); size = sock_send(conn->socket, out_buf.pvBuffer, out_buf.cbBuffer, 0); if(size != out_buf.cbBuffer) { ERR("send failed\n"); res = ERROR_WINHTTP_SECURE_CHANNEL_ERROR; break; } FreeContextBuffer(out_buf.pvBuffer); out_buf.pvBuffer = NULL; out_buf.cbBuffer = 0; } if(status == SEC_I_CONTINUE_NEEDED) { assert(in_bufs[1].cbBuffer < read_buf_size); memmove(read_buf, (BYTE*)in_bufs[0].pvBuffer+in_bufs[0].cbBuffer-in_bufs[1].cbBuffer, in_bufs[1].cbBuffer); in_bufs[0].cbBuffer = in_bufs[1].cbBuffer; in_bufs[1].BufferType = SECBUFFER_EMPTY; in_bufs[1].cbBuffer = 0; in_bufs[1].pvBuffer = NULL; } assert(in_bufs[0].BufferType == SECBUFFER_TOKEN); assert(in_bufs[1].BufferType == SECBUFFER_EMPTY); if(in_bufs[0].cbBuffer + 1024 > read_buf_size) { BYTE *new_read_buf; new_read_buf = heap_realloc(read_buf, read_buf_size + 1024); if(!new_read_buf) { status = E_OUTOFMEMORY; break; } in_bufs[0].pvBuffer = read_buf = new_read_buf; read_buf_size += 1024; } size = sock_recv(conn->socket, read_buf+in_bufs[0].cbBuffer, read_buf_size-in_bufs[0].cbBuffer, 0); if(size < 1) { status = ERROR_WINHTTP_SECURE_CHANNEL_ERROR; break; } TRACE("recv %lu bytes\n", size); in_bufs[0].cbBuffer += size; in_bufs[0].pvBuffer = read_buf; status = InitializeSecurityContextW(cred_handle, &ctx, hostname, isc_req_flags, 0, 0, &in_desc, 0, NULL, &out_desc, &attrs, NULL); TRACE("InitializeSecurityContext ret %08x\n", status); if(status == SEC_E_OK) { if(in_bufs[1].BufferType == SECBUFFER_EXTRA) FIXME("SECBUFFER_EXTRA not supported\n"); status = QueryContextAttributesW(&ctx, SECPKG_ATTR_STREAM_SIZES, &conn->ssl_sizes); if(status != SEC_E_OK) { WARN("Could not get sizes\n"); break; } status = QueryContextAttributesW(&ctx, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (void*)&cert); if(status == SEC_E_OK) { res = netconn_verify_cert(cert, hostname, security_flags); CertFreeCertificateContext(cert); if(res != ERROR_SUCCESS) { WARN("cert verify failed: %u\n", res); break; } }else { WARN("Could not get cert\n"); break; } conn->ssl_buf = heap_alloc(conn->ssl_sizes.cbHeader + conn->ssl_sizes.cbMaximumMessage + conn->ssl_sizes.cbTrailer); if(!conn->ssl_buf) { res = GetLastError(); break; } } } heap_free(read_buf); if(status != SEC_E_OK || res != ERROR_SUCCESS) { WARN("Failed to initialize security context failed: %08x\n", status); heap_free(conn->ssl_buf); conn->ssl_buf = NULL; DeleteSecurityContext(&ctx); set_last_error(res ? res : ERROR_WINHTTP_SECURE_CHANNEL_ERROR); return FALSE; } TRACE("established SSL connection\n"); conn->secure = TRUE; conn->ssl_ctx = ctx; return TRUE; }
static void test_retrieveObjectByUrl(void) { BOOL ret; char tmpfile[MAX_PATH * 2], *ptr, url[MAX_PATH + 8]; CRYPT_BLOB_ARRAY *pBlobArray; PCCERT_CONTEXT cert; PCCRL_CONTEXT crl; HCERTSTORE store; CRYPT_RETRIEVE_AUX_INFO aux = { 0 }; FILETIME ft = { 0 }; SetLastError(0xdeadbeef); ret = CryptRetrieveObjectByUrlA(NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL); ok(!ret && (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == E_INVALIDARG), "got 0x%x/%u (expected ERROR_INVALID_PARAMETER or E_INVALIDARG)\n", GetLastError(), GetLastError()); make_tmp_file(tmpfile); ptr = strchr(tmpfile, ':'); if (ptr) ptr += 2; /* skip colon and first slash */ else ptr = tmpfile; snprintf(url, sizeof(url), "file:///%s", ptr); do { ptr = strchr(url, '\\'); if (ptr) *ptr = '/'; } while (ptr); pBlobArray = (CRYPT_BLOB_ARRAY *)0xdeadbeef; ret = CryptRetrieveObjectByUrlA(url, NULL, 0, 0, (void **)&pBlobArray, NULL, NULL, NULL, NULL); if (!ret && GetLastError() == ERROR_NOT_SUPPORTED) { /* File URL support was apparently removed in Vista/Windows 2008 */ skip("File URLs not supported\n"); return; } ok(ret, "CryptRetrieveObjectByUrlA failed: %d\n", GetLastError()); ok(pBlobArray && pBlobArray != (CRYPT_BLOB_ARRAY *)0xdeadbeef, "Expected a valid pointer\n"); if (pBlobArray && pBlobArray != (CRYPT_BLOB_ARRAY *)0xdeadbeef) { ok(pBlobArray->cBlob == 1, "Expected 1 blob, got %d\n", pBlobArray->cBlob); ok(pBlobArray->rgBlob[0].cbData == sizeof(certWithCRLDistPoint), "Unexpected size %d\n", pBlobArray->rgBlob[0].cbData); CryptMemFree(pBlobArray); } cert = (PCCERT_CONTEXT)0xdeadbeef; ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CERTIFICATE, 0, 0, (void **)&cert, NULL, NULL, NULL, NULL); ok(cert && cert != (PCCERT_CONTEXT)0xdeadbeef, "Expected a cert\n"); if (cert && cert != (PCCERT_CONTEXT)0xdeadbeef) CertFreeCertificateContext(cert); crl = (PCCRL_CONTEXT)0xdeadbeef; SetLastError(0xdeadbeef); ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CRL, 0, 0, (void **)&crl, NULL, NULL, NULL, NULL); /* w2k3,XP, newer w2k: CRYPT_E_NO_MATCH, 95: OSS_DATA_ERROR */ ok(!ret && (GetLastError() == CRYPT_E_NO_MATCH || GetLastError() == CRYPT_E_ASN1_BADTAG || GetLastError() == OSS_DATA_ERROR), "got 0x%x/%u (expected CRYPT_E_NO_MATCH or CRYPT_E_ASN1_BADTAG or " "OSS_DATA_ERROR)\n", GetLastError(), GetLastError()); /* only newer versions of cryptnet do the cleanup */ if(!ret && GetLastError() != CRYPT_E_ASN1_BADTAG && GetLastError() != OSS_DATA_ERROR) { ok(crl == NULL, "Expected CRL to be NULL\n"); } if (crl && crl != (PCCRL_CONTEXT)0xdeadbeef) CertFreeCRLContext(crl); store = (HCERTSTORE)0xdeadbeef; ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CAPI2_ANY, 0, 0, &store, NULL, NULL, NULL, NULL); ok(ret, "CryptRetrieveObjectByUrlA failed: %d\n", GetLastError()); if (store && store != (HCERTSTORE)0xdeadbeef) { DWORD certs = 0; cert = NULL; do { cert = CertEnumCertificatesInStore(store, cert); if (cert) certs++; } while (cert); ok(certs == 1, "Expected 1 cert, got %d\n", certs); CertCloseStore(store, 0); } /* Are file URLs cached? */ cert = (PCCERT_CONTEXT)0xdeadbeef; ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CERTIFICATE, CRYPT_CACHE_ONLY_RETRIEVAL, 0, (void **)&cert, NULL, NULL, NULL, NULL); ok(ret, "CryptRetrieveObjectByUrlA failed: %08x\n", GetLastError()); if (cert && cert != (PCCERT_CONTEXT)0xdeadbeef) CertFreeCertificateContext(cert); cert = (PCCERT_CONTEXT)0xdeadbeef; ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CERTIFICATE, 0, 0, (void **)&cert, NULL, NULL, NULL, &aux); /* w2k: success, 9x: fail with E_INVALIDARG */ ok(ret || (GetLastError() == E_INVALIDARG), "got %u with 0x%x/%u (expected '!=0' or '0' with E_INVALIDARG)\n", ret, GetLastError(), GetLastError()); if (cert && cert != (PCCERT_CONTEXT)0xdeadbeef) CertFreeCertificateContext(cert); cert = (PCCERT_CONTEXT)0xdeadbeef; aux.cbSize = sizeof(aux); ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CERTIFICATE, 0, 0, (void **)&cert, NULL, NULL, NULL, &aux); /* w2k: success, 9x: fail with E_INVALIDARG */ ok(ret || (GetLastError() == E_INVALIDARG), "got %u with 0x%x/%u (expected '!=0' or '0' with E_INVALIDARG)\n", ret, GetLastError(), GetLastError()); if (!ret) { /* no more tests useful */ DeleteFileA(tmpfile); skip("no usable CertificateContext\n"); return; } aux.pLastSyncTime = &ft; ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CERTIFICATE, 0, 0, (void **)&cert, NULL, NULL, NULL, &aux); ok(ft.dwLowDateTime || ft.dwHighDateTime, "Expected last sync time to be set\n"); DeleteFileA(tmpfile); /* Okay, after being deleted, are file URLs still cached? */ SetLastError(0xdeadbeef); ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CERTIFICATE, CRYPT_CACHE_ONLY_RETRIEVAL, 0, (void **)&cert, NULL, NULL, NULL, NULL); ok(!ret && (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND), "Expected ERROR_FILE_NOT_FOUND or ERROR_PATH_NOT_FOUND, got %d\n", GetLastError()); }
void CAPICertificate::setUri (const std::string& capiUri) { valid_ = false; /* Syntax: "certstore:" <cert_store> ":" <hash> ":" <hash_of_cert> */ if (!boost::iequals(capiUri.substr(0, 10), "certstore:")) { return; } /* Substring of subject: uses "storename" */ std::string capiIdentity = capiUri.substr(10); std::string newCertStoreName; size_t pos = capiIdentity.find_first_of (':'); if (pos == std::string::npos) { /* Using the default certificate store */ newCertStoreName = "MY"; certName_ = capiIdentity; } else { newCertStoreName = capiIdentity.substr(0, pos); certName_ = capiIdentity.substr(pos + 1); } if (certStoreHandle_ != NULL) { if (newCertStoreName != certStore_) { CertCloseStore(certStoreHandle_, 0); certStoreHandle_ = NULL; } } if (certStoreHandle_ == NULL) { certStoreHandle_ = CertOpenSystemStore(0, newCertStoreName.c_str()); if (!certStoreHandle_) { return; } } certStore_ = newCertStoreName; PCCERT_CONTEXT certContext = findCertificateInStore (certStoreHandle_, certName_); if (!certContext) { return; } /* Now verify that we can have access to the corresponding private key */ DWORD len; CRYPT_KEY_PROV_INFO *pinfo; HCRYPTPROV hprov; HCRYPTKEY key; if (!CertGetCertificateContextProperty(certContext, CERT_KEY_PROV_INFO_PROP_ID, NULL, &len)) { CertFreeCertificateContext(certContext); return; } pinfo = static_cast<CRYPT_KEY_PROV_INFO *>(malloc(len)); if (!pinfo) { CertFreeCertificateContext(certContext); return; } if (!CertGetCertificateContextProperty(certContext, CERT_KEY_PROV_INFO_PROP_ID, pinfo, &len)) { CertFreeCertificateContext(certContext); free(pinfo); return; } CertFreeCertificateContext(certContext); // Now verify if we have access to the private key if (!CryptAcquireContextW(&hprov, pinfo->pwszContainerName, pinfo->pwszProvName, pinfo->dwProvType, 0)) { free(pinfo); return; } char smartCardReader[1024]; DWORD bufferLength = sizeof(smartCardReader); if (!CryptGetProvParam(hprov, PP_SMARTCARD_READER, (BYTE *)&smartCardReader, &bufferLength, 0)) { DWORD error = GetLastError(); smartCardReaderName_ = ""; } else { smartCardReaderName_ = smartCardReader; LONG result = SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &scardContext_); DEBUG_SCARD_STATUS("SCardEstablishContext", result); if (SCARD_S_SUCCESS == result) { // Initiate monitoring for smartcard ejection smartCardTimer_ = timerFactory_->createTimer(SMARTCARD_EJECTION_CHECK_FREQUENCY_MILLISECONDS); } else { ///Need to handle an error here } } if (!CryptGetUserKey(hprov, pinfo->dwKeySpec, &key)) { CryptReleaseContext(hprov, 0); free(pinfo); return; } CryptDestroyKey(key); CryptReleaseContext(hprov, 0); free(pinfo); if (smartCardTimer_) { smartCardTimer_->onTick.connect(boost::bind(&CAPICertificate::handleSmartCardTimerTick, this)); smartCardTimer_->start(); } valid_ = true; }
bool isCertificateValidated(const generic_string & fullFilePath, const generic_string & subjectName2check) { bool isOK = false; HCERTSTORE hStore = NULL; HCRYPTMSG hMsg = NULL; PCCERT_CONTEXT pCertContext = NULL; BOOL result; DWORD dwEncoding, dwContentType, dwFormatType; PCMSG_SIGNER_INFO pSignerInfo = NULL; DWORD dwSignerInfo; CERT_INFO CertInfo; LPTSTR szName = NULL; generic_string subjectName; try { // Get message handle and store handle from the signed file. result = CryptQueryObject(CERT_QUERY_OBJECT_FILE, fullFilePath.c_str(), CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, CERT_QUERY_FORMAT_FLAG_BINARY, 0, &dwEncoding, &dwContentType, &dwFormatType, &hStore, &hMsg, NULL); if (!result) { generic_string errorMessage = TEXT("Check certificate of ") + fullFilePath + TEXT(" : "); errorMessage += GetLastErrorAsString(GetLastError()); throw errorMessage; } // Get signer information size. result = CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &dwSignerInfo); if (!result) { generic_string errorMessage = TEXT("CryptMsgGetParam first call: "); errorMessage += GetLastErrorAsString(GetLastError()); throw errorMessage; } // Allocate memory for signer information. pSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSignerInfo); if (!pSignerInfo) { generic_string errorMessage = TEXT("CryptMsgGetParam memory allocation problem: "); errorMessage += GetLastErrorAsString(GetLastError()); throw errorMessage; } // Get Signer Information. result = CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, (PVOID)pSignerInfo, &dwSignerInfo); if (!result) { generic_string errorMessage = TEXT("CryptMsgGetParam: "); errorMessage += GetLastErrorAsString(GetLastError()); throw errorMessage; } // Search for the signer certificate in the temporary // certificate store. CertInfo.Issuer = pSignerInfo->Issuer; CertInfo.SerialNumber = pSignerInfo->SerialNumber; pCertContext = CertFindCertificateInStore(hStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_CERT, (PVOID)&CertInfo, NULL); if (not pCertContext) { generic_string errorMessage = TEXT("Certificate context: "); errorMessage += GetLastErrorAsString(GetLastError()); throw errorMessage; } DWORD dwData; // Get Subject name size. dwData = CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, NULL, 0); if (dwData <= 1) { throw generic_string(TEXT("Certificate checking error: getting data size problem.")); } // Allocate memory for subject name. szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR)); if (!szName) { throw generic_string(TEXT("Certificate checking error: memory allocation problem.")); } // Get subject name. if (CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, szName, dwData) <= 1) { throw generic_string(TEXT("Cannot get certificate info.")); } // check Subject name. subjectName = szName; if (subjectName != subjectName2check) { throw generic_string(TEXT("Certificate checking error: the certificate is not matched.")); } isOK = true; } catch (generic_string s) { // display error message MessageBox(NULL, s.c_str(), TEXT("Certificate checking"), MB_OK); } catch (...) { // Unknown error generic_string errorMessage = TEXT("Unknown exception occured. "); errorMessage += GetLastErrorAsString(GetLastError()); MessageBox(NULL, errorMessage.c_str(), TEXT("Certificate checking"), MB_OK); } // Clean up. if (pSignerInfo != NULL) LocalFree(pSignerInfo); if (pCertContext != NULL) CertFreeCertificateContext(pCertContext); if (hStore != NULL) CertCloseStore(hStore, 0); if (hMsg != NULL) CryptMsgClose(hMsg); if (szName != NULL) LocalFree(szName); return isOK; }
BOOL WINAPI CryptVerifyMessageSignature(PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara, DWORD dwSignerIndex, const BYTE* pbSignedBlob, DWORD cbSignedBlob, BYTE* pbDecoded, DWORD* pcbDecoded, PCCERT_CONTEXT* ppSignerCert) { BOOL ret = FALSE; HCRYPTMSG msg; TRACE("(%p, %d, %p, %d, %p, %p, %p)\n", pVerifyPara, dwSignerIndex, pbSignedBlob, cbSignedBlob, pbDecoded, pcbDecoded, ppSignerCert); if (ppSignerCert) *ppSignerCert = NULL; if (!pVerifyPara || pVerifyPara->cbSize != sizeof(CRYPT_VERIFY_MESSAGE_PARA) || GET_CMSG_ENCODING_TYPE(pVerifyPara->dwMsgAndCertEncodingType) != PKCS_7_ASN_ENCODING) { if(pcbDecoded) *pcbDecoded = 0; SetLastError(E_INVALIDARG); return FALSE; } msg = CryptMsgOpenToDecode(pVerifyPara->dwMsgAndCertEncodingType, 0, 0, pVerifyPara->hCryptProv, NULL, NULL); if (msg) { ret = CryptMsgUpdate(msg, pbSignedBlob, cbSignedBlob, TRUE); if (ret && pcbDecoded) ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, pbDecoded, pcbDecoded); if (ret) { CERT_INFO *certInfo = CRYPT_GetSignerCertInfoFromMsg(msg, dwSignerIndex); ret = FALSE; if (certInfo) { HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MSG, pVerifyPara->dwMsgAndCertEncodingType, pVerifyPara->hCryptProv, 0, msg); if (store) { PCCERT_CONTEXT cert = CRYPT_GetSignerCertificate( msg, pVerifyPara, certInfo, store); if (cert) { ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_SIGNATURE, cert->pCertInfo); if (ret && ppSignerCert) *ppSignerCert = cert; else CertFreeCertificateContext(cert); } CertCloseStore(store, 0); } } CryptMemFree(certInfo); } CryptMsgClose(msg); } if(!ret && pcbDecoded) *pcbDecoded = 0; TRACE("returning %d\n", ret); return ret; }
int SSL_CTX_use_CryptoAPI_certificate(SSL_CTX *ssl_ctx, const char *cert_prop) { HCERTSTORE cs; X509 *cert = NULL; RSA *rsa = NULL, *pub_rsa; CAPI_DATA *cd = calloc(1, sizeof(*cd)); RSA_METHOD *my_rsa_method = calloc(1, sizeof(*my_rsa_method)); if (cd == NULL || my_rsa_method == NULL) { SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_MALLOC_FAILURE); goto err; } /* search CURRENT_USER first, then LOCAL_MACHINE */ cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG, L"MY"); if (cs == NULL) { CRYPTOAPIerr(CRYPTOAPI_F_CERT_OPEN_SYSTEM_STORE); goto err; } cd->cert_context = find_certificate_in_store(cert_prop, cs); CertCloseStore(cs, 0); if (!cd->cert_context) { cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG, L"MY"); if (cs == NULL) { CRYPTOAPIerr(CRYPTOAPI_F_CERT_OPEN_SYSTEM_STORE); goto err; } cd->cert_context = find_certificate_in_store(cert_prop, cs); CertCloseStore(cs, 0); if (cd->cert_context == NULL) { CRYPTOAPIerr(CRYPTOAPI_F_CERT_FIND_CERTIFICATE_IN_STORE); goto err; } } /* cert_context->pbCertEncoded is the cert X509 DER encoded. */ cert = d2i_X509(NULL, (unsigned char **) &cd->cert_context->pbCertEncoded, cd->cert_context->cbCertEncoded); if (cert == NULL) { SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_ASN1_LIB); goto err; } /* set up stuff to use the private key */ #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 (CryptAcquireCertificatePrivateKey == NULL) { CryptAcquireCertificatePrivateKey = GetProcAddress(crypt32dll, "CryptAcquireCertificatePrivateKey"); if (CryptAcquireCertificatePrivateKey == NULL) { CRYPTOAPIerr(CRYPTOAPI_F_GET_PROC_ADDRESS); goto err; } } #endif if (!CryptAcquireCertificatePrivateKey(cd->cert_context, CRYPT_ACQUIRE_COMPARE_KEY_FLAG, NULL, &cd->crypt_prov, &cd->key_spec, &cd->free_crypt_prov)) { /* if we don't have a smart card reader here, and we try to access a * smart card certificate, we get: * "Error 1223: The operation was canceled by the user." */ CRYPTOAPIerr(CRYPTOAPI_F_CRYPT_ACQUIRE_CERTIFICATE_PRIVATE_KEY); goto err; } /* here we don't need to do CryptGetUserKey() or anything; all necessary key * info is in cd->cert_context, and then, in cd->crypt_prov. */ my_rsa_method->name = "Microsoft CryptoAPI RSA Method"; my_rsa_method->rsa_pub_enc = rsa_pub_enc; my_rsa_method->rsa_pub_dec = rsa_pub_dec; my_rsa_method->rsa_priv_enc = rsa_priv_enc; my_rsa_method->rsa_priv_dec = rsa_priv_dec; /* my_rsa_method->init = init; */ my_rsa_method->finish = finish; my_rsa_method->flags = RSA_METHOD_FLAG_NO_CHECK; my_rsa_method->app_data = (char *) cd; rsa = RSA_new(); if (rsa == NULL) { SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_MALLOC_FAILURE); goto err; } /* cert->cert_info->key->pkey is NULL until we call SSL_CTX_use_certificate(), * so we do it here then... */ if (!SSL_CTX_use_certificate(ssl_ctx, cert)) goto err; /* the public key */ pub_rsa = cert->cert_info->key->pkey->pkey.rsa; /* SSL_CTX_use_certificate() increased the reference count in 'cert', so * we decrease it here with X509_free(), or it will never be cleaned up. */ X509_free(cert); cert = NULL; /* I'm not sure about what we have to fill in in the RSA, trying out stuff... */ /* rsa->n indicates the key size */ rsa->n = BN_dup(pub_rsa->n); rsa->flags |= RSA_FLAG_EXT_PKEY; if (!RSA_set_method(rsa, my_rsa_method)) goto err; if (!SSL_CTX_use_RSAPrivateKey(ssl_ctx, rsa)) goto err; /* SSL_CTX_use_RSAPrivateKey() increased the reference count in 'rsa', so * we decrease it here with RSA_free(), or it will never be cleaned up. */ RSA_free(rsa); return 1; err: if (cert) X509_free(cert); if (rsa) RSA_free(rsa); else { if (my_rsa_method) free(my_rsa_method); if (cd) { if (cd->free_crypt_prov && cd->crypt_prov) CryptReleaseContext(cd->crypt_prov, 0); if (cd->cert_context) CertFreeCertificateContext(cd->cert_context); free(cd); } } return 0; }
DWORD ShowCertsDlg(LPCTSTR szProviderName, LPCTSTR szReaderName /* Can be NULL */ ) { HCRYPTPROV HMainCryptProv = NULL; BOOL bStatus = FALSE; LPTSTR szMainContainerName = NULL; CHAR szContainerName[1024]; DWORD dwContainerNameLen = sizeof(szContainerName); DWORD dwErr = 0; DWORD dwFlags = CRYPT_FIRST; PCCERT_CONTEXT pContextArray[128]; DWORD dwContextArrayLen = 0; HCRYPTPROV hProv = NULL; HCRYPTKEY hKey = NULL; LPBYTE pbCert = NULL; DWORD dwCertLen = 0; PCCERT_CONTEXT pCertContext = NULL; DWORD pKeySpecs[2] = { AT_KEYEXCHANGE, AT_SIGNATURE}; if (szReaderName) { size_t ulNameLen = _tcslen(szReaderName); szMainContainerName = (LPTSTR) LocalAlloc(0, (ulNameLen + 6) * sizeof(TCHAR)); if (!szMainContainerName) { return GetLastError(); } _stprintf(szMainContainerName, _T("\\\\.\\%s\\"), szReaderName); } bStatus = CryptAcquireContext(&HMainCryptProv,szMainContainerName,szProviderName,PROV_RSA_FULL,0); if (!bStatus) { dwErr = GetLastError(); goto end; } /* Enumerate all the containers */ while (CryptGetProvParam(HMainCryptProv,PP_ENUMCONTAINERS,(LPBYTE) szContainerName,&dwContainerNameLen,dwFlags) &&(dwContextArrayLen < 128)) { #ifndef _UNICODE if (CryptAcquireContext(&hProv, szContainerName, szProviderName, PROV_RSA_FULL, 0)) #else // convert the container name to unicode int wLen = MultiByteToWideChar(CP_ACP, 0, szContainerName, -1, NULL, 0); LPWSTR szWideContainerName = (LPWSTR) LocalAlloc(0, wLen * sizeof(WCHAR)); MultiByteToWideChar(CP_ACP, 0, szContainerName, -1, szWideContainerName, wLen); // Acquire a context on the current container if (CryptAcquireContext(&hProv,szWideContainerName,szProviderName,PROV_RSA_FULL,0)) #endif { // Loop over all the key specs for (int i = 0; i < 2; i++) { if (CryptGetUserKey(hProv,pKeySpecs[i],&hKey) ) { if (CryptGetKeyParam(hKey,KP_CERTIFICATE,NULL,&dwCertLen,0)) { pbCert = (LPBYTE) LocalAlloc(0, dwCertLen); if (!pbCert) { dwErr = GetLastError(); goto end; } if (CryptGetKeyParam(hKey,KP_CERTIFICATE,pbCert,&dwCertLen,0)) { pCertContext = CertCreateCertificateContext(X509_ASN_ENCODING|PKCS_7_ASN_ENCODING, pbCert,dwCertLen); if (pCertContext) { pContextArray[dwContextArrayLen++] = pCertContext; CRYPT_KEY_PROV_INFO ProvInfo; ProvInfo.pwszContainerName = szWideContainerName; ProvInfo.pwszProvName = L"Microsoft Base Smart Card Crypto Provider"; ProvInfo.dwProvType = PROV_RSA_FULL; ProvInfo.dwFlags = 0; ProvInfo.dwKeySpec = AT_SIGNATURE; ProvInfo.cProvParam = 0; ProvInfo.rgProvParam = NULL; CertSetCertificateContextProperty(pCertContext,CERT_KEY_PROV_INFO_PROP_ID, 0, &ProvInfo); HCERTSTORE dest = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_STORE_OPEN_EXISTING_FLAG | CERT_SYSTEM_STORE_CURRENT_USER,L"My"); if(CertAddCertificateContextToStore(dest, pCertContext,CERT_STORE_ADD_REPLACE_EXISTING, NULL)) { //char certName[1024]; //LPWSTR certName = (LPWSTR)new wchar_t[1024]; LPTSTR certName; int cbSize = CertNameToStrW(pCertContext->dwCertEncodingType, &(pCertContext->pCertInfo->Subject),CERT_X500_NAME_STR,NULL,0); certName = (LPTSTR)malloc(cbSize * sizeof(TCHAR)); if (CertNameToStrW(pCertContext->dwCertEncodingType, &(pCertContext->pCertInfo->Subject),CERT_X500_NAME_STR,certName,sizeof(certName))) { } printf("Installed certificate."); } else printf("Error while adding certificate to store"); } } LocalFree(pbCert); } CryptDestroyKey(hKey); hKey = NULL; } } CryptReleaseContext(hProv, 0); hProv = NULL; } #ifdef _UNICODE LocalFree(szWideContainerName); #endif // prepare parameters for the next loop dwContainerNameLen = sizeof(szContainerName); dwFlags = 0; } if (dwContextArrayLen == 0) printf("No certificate contexts found on card\n"); end: while (dwContextArrayLen--) { CertFreeCertificateContext(pContextArray[dwContextArrayLen]); } if (hKey) CryptDestroyKey(hKey); if (hProv) CryptReleaseContext(hProv, 0); if (szMainContainerName) LocalFree(szMainContainerName); if (HMainCryptProv) CryptReleaseContext(HMainCryptProv, 0); return dwErr; }
BOOL WINAPI CryptVerifyDetachedMessageSignature( PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara, DWORD dwSignerIndex, const BYTE *pbDetachedSignBlob, DWORD cbDetachedSignBlob, DWORD cToBeSigned, const BYTE *rgpbToBeSigned[], DWORD rgcbToBeSigned[], PCCERT_CONTEXT *ppSignerCert) { BOOL ret = FALSE; HCRYPTMSG msg; TRACE("(%p, %d, %p, %d, %d, %p, %p, %p)\n", pVerifyPara, dwSignerIndex, pbDetachedSignBlob, cbDetachedSignBlob, cToBeSigned, rgpbToBeSigned, rgcbToBeSigned, ppSignerCert); if (ppSignerCert) *ppSignerCert = NULL; if (!pVerifyPara || pVerifyPara->cbSize != sizeof(CRYPT_VERIFY_MESSAGE_PARA) || GET_CMSG_ENCODING_TYPE(pVerifyPara->dwMsgAndCertEncodingType) != PKCS_7_ASN_ENCODING) { SetLastError(E_INVALIDARG); return FALSE; } msg = CryptMsgOpenToDecode(pVerifyPara->dwMsgAndCertEncodingType, CMSG_DETACHED_FLAG, 0, pVerifyPara->hCryptProv, NULL, NULL); if (msg) { ret = CryptMsgUpdate(msg, pbDetachedSignBlob, cbDetachedSignBlob, TRUE); if (ret) { DWORD i; for (i = 0; ret && i < cToBeSigned; i++) ret = CryptMsgUpdate(msg, rgpbToBeSigned[i], rgcbToBeSigned[i], i == cToBeSigned - 1); } if (ret) { CERT_INFO *certInfo = CRYPT_GetSignerCertInfoFromMsg(msg, dwSignerIndex); ret = FALSE; if (certInfo) { HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MSG, pVerifyPara->dwMsgAndCertEncodingType, pVerifyPara->hCryptProv, 0, msg); if (store) { PCCERT_CONTEXT cert = CRYPT_GetSignerCertificate( msg, pVerifyPara, certInfo, store); if (cert) { ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_SIGNATURE, cert->pCertInfo); if (ret && ppSignerCert) *ppSignerCert = cert; else CertFreeCertificateContext(cert); } else SetLastError(CRYPT_E_NOT_FOUND); CertCloseStore(store, 0); } CryptMemFree(certInfo); } } CryptMsgClose(msg); } TRACE("returning %d\n", ret); return ret; }
// Select, and return a handle to a server certificate located by name // Usually used for a best guess at a certificate to be used as the SSL certificate for a server SECURITY_STATUS CertFindServerByName(PCCERT_CONTEXT & pCertContext, LPCTSTR pszSubjectName, boolean fUserStore) { HCERTSTORE hMyCertStore = NULL; TCHAR pszFriendlyNameString[128]; TCHAR pszNameString[128]; if (pszSubjectName == NULL || _tcslen(pszSubjectName) == 0) { DebugMsg("**** No subject name specified!"); return E_POINTER; } if (fUserStore) hMyCertStore = CertOpenSystemStore(NULL, _T("MY")); else { // Open the local machine certificate store. hMyCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING, NULL, CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_LOCAL_MACHINE, L"MY"); } if (!hMyCertStore) { int err = GetLastError(); if (err == ERROR_ACCESS_DENIED) DebugMsg("**** CertOpenStore failed with 'access denied'"); else DebugMsg("**** Error %d returned by CertOpenStore", err); return HRESULT_FROM_WIN32(err); } if (pCertContext) // The caller passed in a certificate context we no longer need, so free it CertFreeCertificateContext(pCertContext); pCertContext = NULL; char * serverauth = szOID_PKIX_KP_SERVER_AUTH; CERT_ENHKEY_USAGE eku; PCCERT_CONTEXT pCertContextSaved = NULL; eku.cUsageIdentifier = 1; eku.rgpszUsageIdentifier = &serverauth; // Find a server certificate. Note that this code just searches for a // certificate that has the required enhanced key usage for server authentication // it then selects the best one (ideally one that contains the server name // in the subject name). while (NULL != (pCertContext = CertFindCertificateInStore(hMyCertStore, X509_ASN_ENCODING, CERT_FIND_OPTIONAL_ENHKEY_USAGE_FLAG, CERT_FIND_ENHKEY_USAGE, &eku, pCertContext))) { //ShowCertInfo(pCertContext); if (!CertGetNameString(pCertContext, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL, pszFriendlyNameString, sizeof(pszFriendlyNameString))) { DebugMsg("CertGetNameString failed getting friendly name."); continue; } DebugMsg("Certificate '%S' is allowed to be used for server authentication.", ATL::CT2W(pszFriendlyNameString)); if (!CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, pszNameString, sizeof(pszNameString))) DebugMsg("CertGetNameString failed getting subject name."); else if (_tcscmp(pszNameString, pszSubjectName)) DebugMsg("Certificate has wrong subject name."); else if (CertCompareCertificateName(X509_ASN_ENCODING, &pCertContext->pCertInfo->Subject, &pCertContext->pCertInfo->Issuer)) { if (!pCertContextSaved) { DebugMsg("A self-signed certificate was found and saved in case it is needed."); pCertContextSaved = CertDuplicateCertificateContext(pCertContext); } } else { DebugMsg("Certificate is acceptable."); if (pCertContextSaved) // We have a saved self signed certificate context we no longer need, so free it CertFreeCertificateContext(pCertContextSaved); pCertContextSaved = NULL; break; } } if (pCertContextSaved && !pCertContext) { // We have a saved self-signed certificate and nothing better DebugMsg("A self-signed certificate was the best we had."); pCertContext = pCertContextSaved; pCertContextSaved = NULL; } if (!pCertContext) { DWORD LastError = GetLastError(); if (LastError == CRYPT_E_NOT_FOUND) { DebugMsg("**** CertFindCertificateInStore did not find a certificate, creating one"); pCertContext = CreateCertificate(true, pszSubjectName); if (!pCertContext) { LastError = GetLastError(); DebugMsg("**** Error 0x%x returned by CreateCertificate", LastError); std::cout << "Could not create certificate, are you running as administrator?" << std::endl; return HRESULT_FROM_WIN32(LastError); } } else { DebugMsg("**** Error 0x%x returned by CertFindCertificateInStore", LastError); return HRESULT_FROM_WIN32(LastError); } } return SEC_E_OK; }
BOOL CPublisherHelp::GetTimeStampSignerInfo(PCMSG_SIGNER_INFO pSignerInfo, PCMSG_SIGNER_INFO *pCounterSignerInfo) { PCCERT_CONTEXT pCertContext = NULL; BOOL fReturn = FALSE; BOOL fResult; DWORD dwSize; __try { *pCounterSignerInfo = NULL; // Loop through unathenticated attributes for // szOID_RSA_counterSign OID. for (DWORD n = 0; n < pSignerInfo->UnauthAttrs.cAttr; n++) { if (lstrcmpA(pSignerInfo->UnauthAttrs.rgAttr[n].pszObjId, szOID_RSA_counterSign) == 0) { // Get size of CMSG_SIGNER_INFO structure. fResult = CryptDecodeObject(ENCODING, PKCS7_SIGNER_INFO, pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].pbData, pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].cbData, 0, NULL, &dwSize); if (!fResult) { _tprintf(_T("CryptDecodeObject failed with %x\n"), GetLastError()); __leave; } // Allocate memory for CMSG_SIGNER_INFO. *pCounterSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSize); if (!*pCounterSignerInfo) { _tprintf(_T("Unable to allocate memory for timestamp info.\n")); __leave; } // Decode and get CMSG_SIGNER_INFO structure // for timestamp certificate. fResult = CryptDecodeObject(ENCODING, PKCS7_SIGNER_INFO, pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].pbData, pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].cbData, 0, (PVOID)*pCounterSignerInfo, &dwSize); if (!fResult) { _tprintf(_T("CryptDecodeObject failed with %x\n"), GetLastError()); __leave; } fReturn = TRUE; break; // Break from for loop. } } } __finally { // Clean up. if (pCertContext != NULL) CertFreeCertificateContext(pCertContext); } return fReturn; }
LPTSTR CPublisherHelp::GetSigningName(const WCHAR* szFileName){ HCERTSTORE hStore = NULL; HCRYPTMSG hMsg = NULL; PCCERT_CONTEXT pCertContext = NULL; BOOL fResult; DWORD dwEncoding, dwContentType, dwFormatType; PCMSG_SIGNER_INFO pSignerInfo = NULL; PCMSG_SIGNER_INFO pCounterSignerInfo = NULL; DWORD dwSignerInfo; CERT_INFO CertInfo; SPROG_PUBLISHERINFO ProgPubInfo; ZeroMemory(&ProgPubInfo, sizeof(ProgPubInfo)); __try{ fResult = CryptQueryObject(CERT_QUERY_OBJECT_FILE, szFileName, CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, CERT_QUERY_FORMAT_FLAG_BINARY, 0, &dwEncoding, &dwContentType, &dwFormatType, &hStore, &hMsg, NULL); if (!fResult) { return NULL; } // Get signer information size. fResult = CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &dwSignerInfo); if (!fResult) { return NULL; } pSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSignerInfo); if (!pSignerInfo) { return NULL; } // Get Signer Information. fResult = CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, (PVOID)pSignerInfo, &dwSignerInfo); if (!fResult) { return NULL; } // Get program name and publisher information from // signer info structure. if (GetProgAndPublisherInfo(pSignerInfo, &ProgPubInfo)) { } else{ return NULL; } // Search for the signer certificate in the temporary // certificate store. CertInfo.Issuer = pSignerInfo->Issuer; CertInfo.SerialNumber = pSignerInfo->SerialNumber; pCertContext = CertFindCertificateInStore(hStore, ENCODING, 0, CERT_FIND_SUBJECT_CERT, (PVOID)&CertInfo, NULL); if (!pCertContext) { return NULL; } // Print Signer certificate information. LPTSTR szName = NULL; DWORD dwData; // Get Subject name size. if (!(dwData = CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, NULL, 0))) { return NULL; } // Allocate memory for subject name. szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR)); if (!szName) { return NULL; } // Get subject name. if (!(CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, szName, dwData))) { return NULL; } // Print Subject Name. return szName; } __finally { if (ProgPubInfo.lpszProgramName != NULL) LocalFree(ProgPubInfo.lpszProgramName); if (ProgPubInfo.lpszPublisherLink != NULL) LocalFree(ProgPubInfo.lpszPublisherLink); if (ProgPubInfo.lpszMoreInfoLink != NULL) LocalFree(ProgPubInfo.lpszMoreInfoLink); if (pSignerInfo != NULL) LocalFree(pSignerInfo); if (pCounterSignerInfo != NULL) LocalFree(pCounterSignerInfo); if (pCertContext != NULL) CertFreeCertificateContext(pCertContext); if (hStore != NULL) CertCloseStore(hStore, 0); if (hMsg != NULL) CryptMsgClose(hMsg); } return NULL; }
SECURITY_STATUS schan_imp_get_session_peer_certificate(schan_imp_session session, HCERTSTORE store, PCCERT_CONTEXT *ret_cert) { struct mac_session* s = (struct mac_session*)session; SECURITY_STATUS ret = SEC_E_OK; PCCERT_CONTEXT cert = NULL; SecCertificateRef mac_cert; CFArrayRef cert_array; int status; CFIndex cnt, i; CFDataRef data; BOOL res; TRACE("(%p/%p, %p)\n", s, s->context, cert); #ifdef HAVE_SSLCOPYPEERCERTIFICATES status = SSLCopyPeerCertificates(s->context, &cert_array); #else status = SSLGetPeerCertificates(s->context, &cert_array); #endif if (status != noErr || !cert_array) { WARN("SSLCopyPeerCertificates failed: %d\n", status); return SEC_E_INTERNAL_ERROR; } cnt = CFArrayGetCount(cert_array); for (i=0; i < cnt; i++) { if (!(mac_cert = (SecCertificateRef)CFArrayGetValueAtIndex(cert_array, i)) || (SecKeychainItemExport(mac_cert, kSecFormatX509Cert, 0, NULL, &data) != noErr)) { WARN("Couldn't extract certificate data\n"); ret = SEC_E_INTERNAL_ERROR; break; } res = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, CFDataGetBytePtr(data), CFDataGetLength(data), CERT_STORE_ADD_REPLACE_EXISTING, i ? NULL : &cert); CFRelease(data); if (!res) { ret = GetLastError(); WARN("CertAddEncodedCertificateToStore failed: %x\n", ret); break; } } #ifndef HAVE_SSLCOPYPEERCERTIFICATES /* This is why SSLGetPeerCertificates was deprecated */ CFArrayApplyFunction(cert_array, CFRangeMake(0, CFArrayGetCount(cert_array)), schan_imp_cf_release, NULL); #endif CFRelease(cert_array); if (ret != SEC_E_OK) { if(cert) CertFreeCertificateContext(cert); return ret; } *ret_cert = cert; return SEC_E_OK; }
static sqInt sqSetupCert(sqSSL *ssl, char *certName, int server) { SCHANNEL_CRED sc_cred = { 0 }; SECURITY_STATUS ret; HCERTSTORE hStore; PCCERT_CONTEXT pContext = NULL; DWORD dwPropSize; WCHAR wFriendlyName[MAX_NAME_SIZE]; char bFriendlyName[MAX_NAME_SIZE]; if(certName) { hStore = CertOpenSystemStore(0, "MY"); if(!hStore) { if(ssl->loglevel) printf("sqSetupCert: CertOpenSystemStore failed\n"); return 0; } pContext = NULL; /* Enumerate the certificate store to find the cert with the given friendly name */ while(pContext = CertEnumCertificatesInStore(hStore, pContext)) { if(ssl->loglevel) printf("Checking certificate: "); dwPropSize = MAX_NAME_SIZE * sizeof(WCHAR); if(!CertGetCertificateContextProperty(pContext, CERT_FRIENDLY_NAME_PROP_ID, wFriendlyName, &dwPropSize)) { if(ssl->loglevel) printf("<no friendly name>"); continue; } if(!WideCharToMultiByte(CP_UTF8, 0, wFriendlyName, -1, bFriendlyName, MAX_NAME_SIZE, NULL, NULL)) { if(ssl->loglevel) printf("<utf-8 conversion failure>"); continue; } if(ssl->loglevel) printf("%s\n", bFriendlyName); if(strcmp(certName, bFriendlyName) == 0) break; } if(pContext == 0) { /* For compatibility with older versions of SqueakSSL, attempt to match against subject string */ pContext = CertFindCertificateInStore(hStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_STR_A, certName, NULL); } if(!pContext) { if(ssl->loglevel) printf("sqSetupCert: No suitable certificate found\n"); CertCloseStore(hStore, 0); return 0; } } sc_cred.dwVersion = SCHANNEL_CRED_VERSION; sc_cred.dwFlags = SCH_CRED_NO_DEFAULT_CREDS | SCH_CRED_MANUAL_CRED_VALIDATION; sc_cred.grbitEnabledProtocols = server ? SP_PROT_TLS1_SERVER | SP_PROT_SSL3_SERVER : 0; sc_cred.dwMinimumCipherStrength = 0; sc_cred.dwMaximumCipherStrength = 0; if(pContext) { sc_cred.cCreds = 1; sc_cred.paCred = &pContext; } else { sc_cred.cCreds = 0; } ret = AcquireCredentialsHandle(NULL, UNISP_NAME, server ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND, NULL, &sc_cred, NULL, NULL, &ssl->sslCred, NULL); if(ssl->loglevel) printf("AquireCredentialsHandle returned: %x\n", ret); if(pContext) { CertCloseStore(hStore, 0); CertFreeCertificateContext(pContext); } if (ret != SEC_E_OK) { if(ssl->loglevel) printf("AquireCredentialsHandle error: %x\n", ret); return 0; } return 1; }
PCCERT_CONTEXT DigiCrypt_ReadCertFromCard(void) { HCRYPTPROV hCryptProv; BYTE *pbData = NULL; HCRYPTKEY hKey; DWORD cbData = 0; DWORD dwKeyType=0, dwKeySpec = AT_SIGNATURE; DWORD dwErrCode=0; DWORD cspType=0; DWORD cspFlag=CRYPT_SILENT; char *psCspName = NULL; char *psKeyContainer; BOOL fRes = FALSE; PCCERT_CONTEXT pCertContext = NULL; CRYPT_KEY_PROV_INFO KeyProvInfo; LPWSTR wszContainerName=NULL; LPWSTR wszProvName=NULL; DWORD cchContainerName; DWORD cchCSPName; HCRYPTPROV hProv; DigiCrypt_ReleaseFirstAllowedCSP(); psCspName=DigiCrypt_GetFirstAllowedCSPNameNew(); //very dummy thing.. i check from csp creators why i should do so... if(!lstrcmp(psCspName,"EstEID Card CSP")) fRes = CryptAcquireContext(&hProv,"XXX",psCspName,2, CRYPT_SILENT); // end dummy// if (psCspName == NULL || strstr(psCspName,psData_Est_CSP_Name) == NULL) return(pCertContext); cspType=DigiCrypt_FindContext_GetCSPType(psCspName); psKeyContainer=DigiCrypt_GetDefaultKeyContainerName(psCspName); fRes = CryptAcquireContext(&hCryptProv,psKeyContainer,psCspName,cspType, CRYPT_SILENT); if (fRes == FALSE) return(pCertContext); // VS: use alsu auth keys if KEY_USAGE_CHECK=false dwKeySpec = ConfigItem_lookup_int("KEY_USAGE_CHECK", 1) ? AT_SIGNATURE : 0; fRes=CryptGetUserKey(hCryptProv, dwKeySpec, &hKey); if (fRes == TRUE) { fRes=CryptGetKeyParam(hKey, KP_CERTIFICATE, NULL, &cbData, 0); if (fRes == TRUE) { pbData = malloc(cbData); if (pbData == NULL) fRes = FALSE; } if (fRes == TRUE) fRes=CryptGetKeyParam(hKey, KP_CERTIFICATE, pbData, &cbData, 0); if (fRes == TRUE) { pCertContext = CertCreateCertificateContext(MY_ENCODING_TYPE,pbData,cbData); if (pCertContext != NULL) { wszContainerName=NULL; wszProvName=NULL; cchContainerName = (lstrlen(psKeyContainer) + 1) * sizeof(WCHAR); cchCSPName = (lstrlen(psCspName) + 1) * sizeof(WCHAR); wszContainerName = (LPWSTR) malloc(cchContainerName); wszProvName = (LPWSTR) malloc(cchCSPName); mbstowcs(wszContainerName, psKeyContainer,cchContainerName); mbstowcs(wszProvName, psCspName, cchCSPName); ZeroMemory((PVOID)&KeyProvInfo, sizeof(CRYPT_KEY_PROV_INFO)); KeyProvInfo.pwszContainerName = (LPWSTR) wszContainerName; KeyProvInfo.pwszProvName = (LPWSTR) wszProvName; KeyProvInfo.dwProvType = PROV_RSA_SIG; KeyProvInfo.dwFlags = 0; KeyProvInfo.dwKeySpec = dwKeyType; fRes = CertSetCertificateContextProperty(pCertContext,CERT_KEY_PROV_INFO_PROP_ID, 0, (const void *) &KeyProvInfo); if (wszContainerName != NULL) free(wszContainerName); if (wszProvName != NULL) free(wszProvName); } } } //if (pCertContext != NULL) // DigiCrypt_AddCertToStore(pCertContext); if (fRes == FALSE && pCertContext != NULL) { CertFreeCertificateContext(pCertContext); pCertContext = NULL; } if (pbData != NULL) free(pbData); if (hCryptProv != 0) CryptReleaseContext(hCryptProv, 0); return(pCertContext); }
/* 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; }
/***************************************************************************** wmain *****************************************************************************/ DWORD __cdecl wmain( int argc, LPWSTR argv[] ) { HRESULT hr = S_OK; HCERTSTORE hStore = NULL; PCCERT_CONTEXT pCert = NULL; PCCERT_CONTEXT pStoreCert = NULL; char szStoreProvider[ 256 ] = { "TestExt" }; // Store provider name LPWSTR pwszStoreProvider = NULL; // Store name LPWSTR pwszStoreName = L"TestStoreName"; LPWSTR pwszCertPath = NULL; int i; // // options // for( i=1; i<argc; i++ ) { if ( lstrcmpW (argv[i], L"/?") == 0 || lstrcmpW (argv[i], L"-?") == 0 ) { Usage( L"SampleStoreProvider.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"-p") == 0 ) { if( i+1 >= argc ) { hr = E_INVALIDARG; goto CleanUp; } pwszStoreProvider = argv[++i]; } } if( i >= argc ) { hr = E_INVALIDARG; goto CleanUp; } pwszCertPath = argv[i++]; // Load the certificate from the file passed in as cmd line parameter; if (!CryptQueryObject( CERT_QUERY_OBJECT_FILE, //dwObjectType pwszCertPath, //pvObject CERT_QUERY_CONTENT_FLAG_CERT, //dwExpectedContentTypeFlags CERT_QUERY_FORMAT_FLAG_ALL, //dwExpectedFormatTypeFlags 0, //dwFlags 0, //pdwMsgAndCertEncodingType 0, //pdwContentType 0, //pdwFormatType 0, //phCertStore 0, //phMsg (const void**)&pCert //ppvContext )) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto CleanUp; } // Open the store using the sample provider name if( NULL != pwszStoreProvider ) { if( 1 < WideCharToMultiByte( CP_ACP, WC_ERR_INVALID_CHARS, pwszStoreProvider, -1, szStoreProvider, sizeof(szStoreProvider), NULL, NULL )) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto CleanUp; } } hStore = CertOpenStore( szStoreProvider, // lpszStoreProvider X509_ASN_ENCODING, // dwMsgAndCertEncodingType NULL, // hCryptProv 0, // dwFlags (will create it if does not exists) (void*)pwszStoreName); // pvPara if (hStore == NULL) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto CleanUp; } // Add a certificate to store if(!CertAddCertificateContextToStore( hStore, // hCertStore pCert, // pCertContext CERT_STORE_ADD_REPLACE_EXISTING, // dwAddDisposition NULL // ppStoreContext )) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto CleanUp; } pStoreCert = CertFindCertificateInStore( hStore, // hCertStore X509_ASN_ENCODING, // dwCertEncodingType 0, // dwFindFlags CERT_FIND_EXISTING, // dwFindType pCert, // pvFindPara NULL // pPrevCertContext ); if (pStoreCert == NULL) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto CleanUp; } hr = S_OK; CleanUp: if( NULL != pCert ) CertFreeCertificateContext(pCert); if( NULL != pStoreCert ) CertFreeCertificateContext(pStoreCert); if( NULL != hStore ) CertCloseStore(hStore, 0); if( FAILED( hr )) { ReportError( NULL, hr ); } return (DWORD)hr; }
HRESULT WINAPI SoftpubAuthenticode(CRYPT_PROVIDER_DATA *data) { BOOL ret; CERT_CHAIN_POLICY_STATUS policyStatus = { sizeof(policyStatus), 0 }; TRACE("(%p)\n", data); if (data->pWintrustData->dwUIChoice != WTD_UI_NONE) FIXME("unimplemented for UI choice %d\n", data->pWintrustData->dwUIChoice); if (!data->csSigners) { ret = FALSE; policyStatus.dwError = TRUST_E_NOSIGNATURE; } else { DWORD i; ret = TRUE; for (i = 0; ret && i < data->csSigners; i++) { BYTE hash[20]; DWORD size = sizeof(hash); /* First make sure cert isn't disallowed */ if ((ret = CertGetCertificateContextProperty( data->pasSigners[i].pasCertChain[0].pCert, CERT_SIGNATURE_HASH_PROP_ID, hash, &size))) { static const WCHAR disallowedW[] = { 'D','i','s','a','l','l','o','w','e','d',0 }; HCERTSTORE disallowed = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, X509_ASN_ENCODING, 0, CERT_SYSTEM_STORE_CURRENT_USER, disallowedW); if (disallowed) { PCCERT_CONTEXT found = CertFindCertificateInStore( disallowed, X509_ASN_ENCODING, 0, CERT_FIND_SIGNATURE_HASH, hash, NULL); if (found) { /* Disallowed! Can't verify it. */ policyStatus.dwError = TRUST_E_SUBJECT_NOT_TRUSTED; ret = FALSE; CertFreeCertificateContext(found); } CertCloseStore(disallowed, 0); } } if (ret) { CERT_CHAIN_POLICY_PARA policyPara = { sizeof(policyPara), 0 }; if (data->dwRegPolicySettings & WTPF_TRUSTTEST) policyPara.dwFlags |= CERT_CHAIN_POLICY_TRUST_TESTROOT_FLAG; if (data->dwRegPolicySettings & WTPF_TESTCANBEVALID) policyPara.dwFlags |= CERT_CHAIN_POLICY_ALLOW_TESTROOT_FLAG; if (data->dwRegPolicySettings & WTPF_IGNOREEXPIRATION) policyPara.dwFlags |= CERT_CHAIN_POLICY_IGNORE_NOT_TIME_VALID_FLAG | CERT_CHAIN_POLICY_IGNORE_CTL_NOT_TIME_VALID_FLAG | CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG; if (data->dwRegPolicySettings & WTPF_IGNOREREVOKATION) policyPara.dwFlags |= CERT_CHAIN_POLICY_IGNORE_END_REV_UNKNOWN_FLAG | CERT_CHAIN_POLICY_IGNORE_CTL_SIGNER_REV_UNKNOWN_FLAG | CERT_CHAIN_POLICY_IGNORE_CA_REV_UNKNOWN_FLAG | CERT_CHAIN_POLICY_IGNORE_ROOT_REV_UNKNOWN_FLAG; CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_AUTHENTICODE, data->pasSigners[i].pChainContext, &policyPara, &policyStatus); if (policyStatus.dwError != NO_ERROR) ret = FALSE; } } } if (!ret) data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_POLICYPROV] = policyStatus.dwError; TRACE("returning %d (%08x)\n", ret ? S_OK : S_FALSE, data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_POLICYPROV]); return ret ? S_OK : S_FALSE; }
// handle WinHTTP callbacks (which can be in a worker thread context) VOID CALLBACK WinHttpIO::asynccallback(HINTERNET hInternet, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInformation, DWORD dwStatusInformationLength) { WinHttpContext* httpctx = (WinHttpContext*)dwContext; WinHttpIO* httpio = (WinHttpIO*)httpctx->httpio; if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING) { assert(!httpctx->req); if (httpctx->gzip) { inflateEnd(&httpctx->z); } delete httpctx; return; } httpio->lock(); HttpReq* req = httpctx->req; // request cancellations that occured after asynccallback() was entered are caught here if (!req) { httpio->unlock(); return; } switch (dwInternetStatus) { case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE: { DWORD size = *(DWORD*)lpvStatusInformation; if (!size) { if (debug) { if (req->binary) { cout << "[received " << req->bufpos << " bytes of raw data]" << endl; } else { cout << "Received: " << req->in.c_str() << endl; } } req->status = req->httpstatus == 200 ? REQ_SUCCESS : REQ_FAILURE; httpio->success = true; } else { char* ptr; if (httpctx->gzip) { m_off_t zprevsize = httpctx->zin.size(); httpctx->zin.resize(zprevsize + size); ptr = (char*)httpctx->zin.data() + zprevsize; } else { ptr = (char*)req->reserveput((unsigned*)&size); req->bufpos += size; } if (!WinHttpReadData(hInternet, ptr, size, NULL)) { httpio->cancel(req); } } httpio->httpevent(); break; } case WINHTTP_CALLBACK_STATUS_READ_COMPLETE: if (dwStatusInformationLength) { if (req->httpio) { req->httpio->lastdata = Waiter::ds; } if (httpctx->gzip) { httpctx->z.next_in = (Bytef*)lpvStatusInformation; httpctx->z.avail_in = dwStatusInformationLength; req->bufpos += httpctx->z.avail_out; int t = inflate(&httpctx->z, Z_SYNC_FLUSH); req->bufpos -= httpctx->z.avail_out; if ((char *)lpvStatusInformation + dwStatusInformationLength == httpctx->zin.data() + httpctx->zin.size()) { httpctx->zin.clear(); } if (t != Z_OK && (t != Z_STREAM_END || httpctx->z.avail_out)) { httpio->cancel(req); } } if (!WinHttpQueryDataAvailable(httpctx->hRequest, NULL)) { httpio->cancel(req); httpio->httpevent(); } } break; case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE: { DWORD statusCode; DWORD statusCodeSize = sizeof(statusCode); if (!WinHttpQueryHeaders(httpctx->hRequest, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &statusCode, &statusCodeSize, WINHTTP_NO_HEADER_INDEX)) { httpio->cancel(req); httpio->httpevent(); } else { req->httpstatus = statusCode; if (req->httpio) { req->httpio->lastdata = Waiter::ds; } if (!req->buf) { // obtain original content length - always present if gzip is in use DWORD contentLength; DWORD contentLengthSize = sizeof(contentLength); if (WinHttpQueryHeaders(httpctx->hRequest, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_NUMBER, L"Original-Content-Length", &contentLength, &contentLengthSize, WINHTTP_NO_HEADER_INDEX)) { req->setcontentlength(contentLength); // check for gzip content encoding WCHAR contentEncoding[16]; DWORD contentEncodingSize = sizeof(contentEncoding); httpctx->gzip = WinHttpQueryHeaders(httpctx->hRequest, WINHTTP_QUERY_CONTENT_ENCODING, WINHTTP_HEADER_NAME_BY_INDEX, &contentEncoding, &contentEncodingSize, WINHTTP_NO_HEADER_INDEX) && !wcscmp(contentEncoding, L"gzip"); if (httpctx->gzip) { httpctx->z.zalloc = Z_NULL; httpctx->z.zfree = Z_NULL; httpctx->z.opaque = Z_NULL; httpctx->z.avail_in = 0; httpctx->z.next_in = Z_NULL; inflateInit2(&httpctx->z, MAX_WBITS+16); req->in.resize(contentLength); httpctx->z.avail_out = contentLength; httpctx->z.next_out = (unsigned char*)req->in.data(); } } } if (!WinHttpQueryDataAvailable(httpctx->hRequest, NULL)) { httpio->cancel(req); httpio->httpevent(); } else if (httpio->waiter && httpio->noinetds) { httpio->inetstatus(true); } } break; } case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR: if (httpio->waiter && GetLastError() != ERROR_WINHTTP_TIMEOUT) { httpio->inetstatus(false); } // fall through case WINHTTP_CALLBACK_STATUS_SECURE_FAILURE: httpio->cancel(req); httpio->httpevent(); break; case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE: { PCCERT_CONTEXT cert; DWORD len = sizeof cert; if (WinHttpQueryOption(httpctx->hRequest, WINHTTP_OPTION_SERVER_CERT_CONTEXT, &cert, &len)) { CRYPT_BIT_BLOB* pkey = &cert->pCertInfo->SubjectPublicKeyInfo.PublicKey; // this is an SSL connection: verify public key to prevent MITM attacks if (pkey->cbData != 270 || (memcmp(pkey->pbData, "\x30\x82\x01\x0a\x02\x82\x01\x01\x00" APISSLMODULUS1 "\x02" APISSLEXPONENTSIZE APISSLEXPONENT, 270) && memcmp(pkey->pbData, "\x30\x82\x01\x0a\x02\x82\x01\x01\x00" APISSLMODULUS2 "\x02" APISSLEXPONENTSIZE APISSLEXPONENT, 270))) { CertFreeCertificateContext(cert); httpio->cancel(req); httpio->httpevent(); break; } CertFreeCertificateContext(cert); } } // fall through case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE: if (httpctx->postpos < httpctx->postlen) { unsigned pos = httpctx->postpos; unsigned t = httpctx->postlen - pos; if (t > HTTP_POST_CHUNK_SIZE) { t = HTTP_POST_CHUNK_SIZE; } httpctx->postpos += t; if (!WinHttpWriteData(httpctx->hRequest, (LPVOID)(httpctx->postdata + pos), t, NULL)) { req->httpio->cancel(req); } httpio->httpevent(); } else { if (!WinHttpReceiveResponse(httpctx->hRequest, NULL)) { httpio->cancel(req); httpio->httpevent(); } } } httpio->unlock(); }
// Read URL server LPSTR SoffidEssoManager::readURL (HINTERNET hSession, const wchar_t* host, int port, LPCWSTR path, BOOL allowUnknownCA, size_t *pSize) { BOOL bResults = FALSE; HINTERNET hConnect = NULL, hRequest = NULL; DWORD dwDownloaded = -1; BYTE *buffer = NULL; if (debug) { log("Connecting to %s:%d...\n", host, port); } hConnect = WinHttpConnect(hSession, host, port, 0); if (hConnect) { if (debug) { log("Performing request %s...\n", path); } hRequest = WinHttpOpenRequest(hConnect, L"GET", path, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE); } // Send a request. if (hRequest) { if (debug) log("Sending request ...\n"); WinHttpSetOption(hRequest, WINHTTP_OPTION_CLIENT_CERT_CONTEXT, NULL, 0); if (allowUnknownCA) { DWORD flags = SECURITY_FLAG_IGNORE_UNKNOWN_CA; WinHttpSetOption(hRequest, WINHTTP_OPTION_SECURITY_FLAGS, (LPVOID) &flags, sizeof flags); } bResults = WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0); } if (bResults && allowUnknownCA) { // Agreagar la CA ROOT PCERT_CONTEXT context; DWORD dwSize = sizeof context; BOOL result = WinHttpQueryOption(hRequest, WINHTTP_OPTION_SERVER_CERT_CONTEXT, &context, &dwSize); if (!result) { log("Cannot get context\n"); // notifyError(); } PCCERT_CONTEXT issuerContext = CertFindCertificateInStore(context->hCertStore, X509_ASN_ENCODING, 0, CERT_FIND_ISSUER_OF, context, NULL); HCERTSTORE systemStore = CertOpenStore((LPCSTR) 13, // CERT_STORE_PROV_SYSTEM_REGISTRY_W 0, (HCRYPTPROV) NULL, (2 << 16) | // CERT_SYSTEM_STORE_LOCAL_MACHINE 0x1000, // CERT_STORE_MAXIMUM_ALLOWED L"ROOT"); CertAddCertificateContextToStore(systemStore, issuerContext, 1 /*CERT_STORE_ADD_NEW*/, NULL); CertFreeCertificateContext(issuerContext); CertFreeCertificateContext(context); } // End the request. if (bResults) { if (debug) log("Waiting for response....\n"); bResults = WinHttpReceiveResponse(hRequest, NULL); } // Keep checking for data until there is nothing left. DWORD used = 0; if (bResults) { const DWORD chunk = 4096; DWORD allocated = 0; do { if (used + chunk > allocated) { allocated += chunk; buffer = (LPBYTE) realloc(buffer, allocated); } dwDownloaded = 0; if (!WinHttpReadData(hRequest, &buffer[used], chunk, &dwDownloaded)) dwDownloaded = -1; else used += dwDownloaded; } while (dwDownloaded > 0); buffer[used] = '\0'; } DWORD dw = GetLastError(); if (!bResults && debug) { if (dw == ERROR_WINHTTP_CANNOT_CONNECT) log("Error: Cannot connect\n"); else if (dw == ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED) log("Error: Client CERT required\n"); else if (dw == ERROR_WINHTTP_CONNECTION_ERROR) log("Error: Connection error\n"); else if (dw == ERROR_WINHTTP_INCORRECT_HANDLE_STATE) log("Error: ERROR_WINHTTP_INCORRECT_HANDLE_STATE\n"); else if (dw == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE) log("Error: ERROR_WINHTTP_INCORRECT_HANDLE_TYPE\n"); else if (dw == ERROR_WINHTTP_INTERNAL_ERROR) log("Error: ERROR_WINHTTP_INTERNAL_ERROR\n"); else if (dw == ERROR_WINHTTP_INVALID_URL) log("Error: ERROR_WINHTTP_INVALID_URL\n"); else if (dw == ERROR_WINHTTP_LOGIN_FAILURE) log("Error: ERROR_WINHTTP_LOGIN_FAILURE\n"); else if (dw == ERROR_WINHTTP_NAME_NOT_RESOLVED) log("Error: ERROR_WINHTTP_NAME_NOT_RESOLVED\n"); else if (dw == ERROR_WINHTTP_OPERATION_CANCELLED) log("Error: ERROR_WINHTTP_OPERATION_CANCELLED\n"); else if (dw == ERROR_WINHTTP_RESPONSE_DRAIN_OVERFLOW) log("Error: ERROR_WINHTTP_RESPONSE_DRAIN_OVERFLOW\n"); else if (dw == ERROR_WINHTTP_SECURE_FAILURE) log("Error: ERROR_WINHTTP_SECURE_FAILURE\n"); else if (dw == ERROR_WINHTTP_SHUTDOWN) log("Error: ERROR_WINHTTP_SHUTDOWN\n"); else if (dw == ERROR_WINHTTP_TIMEOUT) log("Error: ERROR_WINHTTP_TIMEOUT\n"); else if (dw == ERROR_WINHTTP_UNRECOGNIZED_SCHEME) log("Error: ERROR_WINHTTP_UNRECOGNIZED_SCHEME\n"); else if (dw == ERROR_NOT_ENOUGH_MEMORY) log("Error: ERROR_NOT_ENOUGH_MEMORY\n"); else if (dw == ERROR_INVALID_PARAMETER) log("Error: ERROR_INVALID_PARAMETER\n"); else if (dw == ERROR_WINHTTP_RESEND_REQUEST) log("Error: ERROR_WINHTTP_RESEND_REQUEST\n"); else if (dw != ERROR_SUCCESS) { log("Unkonwn error %d\n", dw); } // notifyError(); } // Close any open handles. if (hRequest) WinHttpCloseHandle(hRequest); if (hConnect) WinHttpCloseHandle(hConnect); if (hSession) WinHttpCloseHandle(hSession); SetLastError(dw); if (pSize != NULL) *pSize = used; return (LPSTR) buffer; }
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; }
/** The verbosity level. */ static unsigned g_cVerbosityLevel = 1; static const char *errorToString(DWORD dwErr) { switch (dwErr) { #define MY_CASE(a_uConst) case a_uConst: return #a_uConst; MY_CASE(CRYPT_E_MSG_ERROR); MY_CASE(CRYPT_E_UNKNOWN_ALGO); MY_CASE(CRYPT_E_OID_FORMAT); MY_CASE(CRYPT_E_INVALID_MSG_TYPE); MY_CASE(CRYPT_E_UNEXPECTED_ENCODING); MY_CASE(CRYPT_E_AUTH_ATTR_MISSING); MY_CASE(CRYPT_E_HASH_VALUE); MY_CASE(CRYPT_E_INVALID_INDEX); MY_CASE(CRYPT_E_ALREADY_DECRYPTED); MY_CASE(CRYPT_E_NOT_DECRYPTED); MY_CASE(CRYPT_E_RECIPIENT_NOT_FOUND); MY_CASE(CRYPT_E_CONTROL_TYPE); MY_CASE(CRYPT_E_ISSUER_SERIALNUMBER); MY_CASE(CRYPT_E_SIGNER_NOT_FOUND); MY_CASE(CRYPT_E_ATTRIBUTES_MISSING); MY_CASE(CRYPT_E_STREAM_MSG_NOT_READY); MY_CASE(CRYPT_E_STREAM_INSUFFICIENT_DATA); MY_CASE(CRYPT_I_NEW_PROTECTION_REQUIRED); MY_CASE(CRYPT_E_BAD_LEN); MY_CASE(CRYPT_E_BAD_ENCODE); MY_CASE(CRYPT_E_FILE_ERROR); MY_CASE(CRYPT_E_NOT_FOUND); MY_CASE(CRYPT_E_EXISTS); MY_CASE(CRYPT_E_NO_PROVIDER); MY_CASE(CRYPT_E_SELF_SIGNED); MY_CASE(CRYPT_E_DELETED_PREV); MY_CASE(CRYPT_E_NO_MATCH); MY_CASE(CRYPT_E_UNEXPECTED_MSG_TYPE); MY_CASE(CRYPT_E_NO_KEY_PROPERTY); MY_CASE(CRYPT_E_NO_DECRYPT_CERT); MY_CASE(CRYPT_E_BAD_MSG); MY_CASE(CRYPT_E_NO_SIGNER); MY_CASE(CRYPT_E_PENDING_CLOSE); MY_CASE(CRYPT_E_REVOKED); MY_CASE(CRYPT_E_NO_REVOCATION_DLL); MY_CASE(CRYPT_E_NO_REVOCATION_CHECK); MY_CASE(CRYPT_E_REVOCATION_OFFLINE); MY_CASE(CRYPT_E_NOT_IN_REVOCATION_DATABASE); MY_CASE(CRYPT_E_INVALID_NUMERIC_STRING); MY_CASE(CRYPT_E_INVALID_PRINTABLE_STRING); MY_CASE(CRYPT_E_INVALID_IA5_STRING); MY_CASE(CRYPT_E_INVALID_X500_STRING); MY_CASE(CRYPT_E_NOT_CHAR_STRING); MY_CASE(CRYPT_E_FILERESIZED); MY_CASE(CRYPT_E_SECURITY_SETTINGS); MY_CASE(CRYPT_E_NO_VERIFY_USAGE_DLL); MY_CASE(CRYPT_E_NO_VERIFY_USAGE_CHECK); MY_CASE(CRYPT_E_VERIFY_USAGE_OFFLINE); MY_CASE(CRYPT_E_NOT_IN_CTL); MY_CASE(CRYPT_E_NO_TRUSTED_SIGNER); MY_CASE(CRYPT_E_MISSING_PUBKEY_PARA); MY_CASE(CRYPT_E_OSS_ERROR); default: { PCRTCOMERRMSG pWinComMsg = RTErrCOMGet(dwErr); if (pWinComMsg) return pWinComMsg->pszDefine; static char s_szErr[32]; RTStrPrintf(s_szErr, sizeof(s_szErr), "%#x (%d)", dwErr, dwErr); return s_szErr; } } } #if 0 /* hacking */ static RTEXITCODE addToStore(const char *pszFilename, PCRTUTF16 pwszStore) { /* * Open the source. */ void *pvFile; size_t cbFile; int rc = RTFileReadAll(pszFilename, &pvFile, &cbFile); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTFileReadAll failed on '%s': %Rrc", pszFilename, rc); RTEXITCODE rcExit = RTEXITCODE_FAILURE; PCCERT_CONTEXT pCertCtx = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, (PBYTE)pvFile, (DWORD)cbFile); if (pCertCtx) { /* * Open the destination. */ HCERTSTORE hDstStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, NULL /* hCryptProv = default */, /*CERT_SYSTEM_STORE_LOCAL_MACHINE*/ CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, pwszStore); if (hDstStore != NULL) { #if 0 DWORD dwContextType; if (CertAddSerializedElementToStore(hDstStore, pCertCtx->pbCertEncoded, pCertCtx->cbCertEncoded, CERT_STORE_ADD_NEW, 0 /* dwFlags (reserved) */, CERT_STORE_ALL_CONTEXT_FLAG, &dwContextType, NULL)) { RTMsgInfo("Successfully added '%s' to the '%ls' store (ctx type %u)", pszFilename, pwszStore, dwContextType); rcExit = RTEXITCODE_SUCCESS; } else RTMsgError("CertAddSerializedElementToStore returned %s", errorToString(GetLastError())); #else if (CertAddCertificateContextToStore(hDstStore, pCertCtx, CERT_STORE_ADD_NEW, NULL)) { RTMsgInfo("Successfully added '%s' to the '%ls' store", pszFilename, pwszStore); rcExit = RTEXITCODE_SUCCESS; } else RTMsgError("CertAddCertificateContextToStore returned %s", errorToString(GetLastError())); #endif CertCloseStore(hDstStore, CERT_CLOSE_STORE_CHECK_FLAG); } else RTMsgError("CertOpenStore returned %s", errorToString(GetLastError())); CertFreeCertificateContext(pCertCtx); } else RTMsgError("CertCreateCertificateContext returned %s", errorToString(GetLastError())); RTFileReadAllFree(pvFile, cbFile); return rcExit; #if 0 CRYPT_DATA_BLOB Blob; Blob.cbData = (DWORD)cbData; Blob.pbData = (PBYTE)pvData; HCERTSTORE hSrcStore = PFXImportCertStore(&Blob, L"", ) #endif }
/* {{{ static int ma_tls_set_client_certs(MARIADB_TLS *ctls) */ static int ma_tls_set_client_certs(MARIADB_TLS *ctls) { MYSQL *mysql= ctls->pvio->mysql; char *certfile= mysql->options.ssl_cert, *keyfile= mysql->options.ssl_key, *cafile= mysql->options.ssl_ca; PCERT_CONTEXT ca_ctx= NULL; PCRL_CONTEXT crl_ctx = NULL; SC_CTX *sctx= (SC_CTX *)ctls->ssl; MARIADB_PVIO *pvio= ctls->pvio; if (cafile) { if (!(ca_ctx = ma_schannel_create_cert_context(pvio, cafile))) goto end; /* Add ca to in-memory certificate store */ if (CertAddCertificateContextToStore(ca_CertStore, ca_ctx, CERT_STORE_ADD_NEWER, NULL) != TRUE && GetLastError() != CRYPT_E_EXISTS) { ma_schannel_set_win_error(sctx->mysql); goto end; } ca_Check= 0; CertFreeCertificateContext(ca_ctx); } if (!certfile && keyfile) certfile= keyfile; if (!keyfile && certfile) keyfile= certfile; if (certfile && certfile[0]) if (!(sctx->client_cert_ctx = ma_schannel_create_cert_context(ctls->pvio, certfile))) goto end; if (sctx->client_cert_ctx && keyfile[0]) if (!ma_schannel_load_private_key(pvio, sctx->client_cert_ctx, keyfile)) goto end; if (mysql->options.extension && mysql->options.extension->ssl_crl) { if (!(crl_ctx= (CRL_CONTEXT *)ma_schannel_create_crl_context(pvio, mysql->options.extension->ssl_crl))) goto end; /* Add ca to in-memory certificate store */ if (CertAddCRLContextToStore(crl_CertStore, crl_ctx, CERT_STORE_ADD_NEWER, NULL) != TRUE && GetLastError() != CRYPT_E_EXISTS) { ma_schannel_set_win_error(sctx->mysql); goto end; } crl_Check = 1; CertFreeCertificateContext(ca_ctx); } return 0; end: if (ca_ctx) CertFreeCertificateContext(ca_ctx); if (sctx->client_cert_ctx) CertFreeCertificateContext(sctx->client_cert_ctx); if (crl_ctx) CertFreeCRLContext(crl_ctx); sctx->client_cert_ctx= NULL; return 1; }
/** * Removes a certificate, given by file, from a store * * @returns true on success, false on failure (error message written). * @param dwDst The destination, like * CERT_SYSTEM_STORE_LOCAL_MACHINE or * CERT_SYSTEM_STORE_CURRENT_USER. * @param pszStoreNm The store name. * @param pszCertFile The file containing the certificate to add. */ static bool removeCertFromStoreByFile(DWORD dwDst, const char *pszStoreNm, const char *pszCertFile) { /* * Read the certificate file first. */ PCCERT_CONTEXT pSrcCtx = NULL; HCERTSTORE hSrcStore = NULL; if (!readCertFile(pszCertFile, &pSrcCtx, &hSrcStore)) return false; WCHAR wszName[1024]; if (!CertGetNameStringW(pSrcCtx, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0 /*dwFlags*/, NULL /*pvTypePara*/, wszName, sizeof(wszName))) { RTMsgError("CertGetNameStringW(Subject) failed: %s\n", errorToString(GetLastError())); wszName[0] = '\0'; } /* * Open the destination store. */ bool fRc = false; HCERTSTORE hDstStore = openCertStore(dwDst, pszStoreNm); if (hDstStore) { if (pSrcCtx) { fRc = true; unsigned cDeleted = 0; PCCERT_CONTEXT pCurCtx = NULL; while ((pCurCtx = CertEnumCertificatesInStore(hDstStore, pCurCtx)) != NULL) { if (CertCompareCertificate(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, pCurCtx->pCertInfo, pSrcCtx->pCertInfo)) { if (g_cVerbosityLevel > 1) RTMsgInfo("Removing '%ls'...", wszName); PCCERT_CONTEXT pDeleteCtx = CertDuplicateCertificateContext(pCurCtx); if (pDeleteCtx) { if (CertDeleteCertificateFromStore(pDeleteCtx)) cDeleted++; else RTMsgError("CertDeleteFromStore('%ls') failed: %s\n", wszName, errorToString(GetLastError())); } else RTMsgError("CertDuplicateCertificateContext('%ls') failed: %s\n", wszName, errorToString(GetLastError())); } } if (!cDeleted) RTMsgInfo("Found no matching certificates to remove."); } else { RTMsgError("Path not implemented at line %d\n", __LINE__); } CertCloseStore(hDstStore, CERT_CLOSE_STORE_CHECK_FLAG); } if (pSrcCtx) CertFreeCertificateContext(pSrcCtx); if (hSrcStore) CertCloseStore(hSrcStore, CERT_CLOSE_STORE_CHECK_FLAG); return fRc; }
static void test_retrieveObjectByUrl(void) { BOOL ret; char tmpfile[MAX_PATH * 2], *ptr, url[MAX_PATH + 8]; CRYPT_BLOB_ARRAY *pBlobArray; PCCERT_CONTEXT cert; PCCRL_CONTEXT crl; HCERTSTORE store; CRYPT_RETRIEVE_AUX_INFO aux = { 0 }; FILETIME ft = { 0 }; SetLastError(0xdeadbeef); ret = CryptRetrieveObjectByUrlA(NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError()); make_tmp_file(tmpfile); ptr = strchr(tmpfile, ':'); if (ptr) ptr += 2; /* skip colon and first slash */ else ptr = tmpfile; snprintf(url, sizeof(url), "file:///%s", ptr); do { ptr = strchr(url, '\\'); if (ptr) *ptr = '/'; } while (ptr); pBlobArray = (CRYPT_BLOB_ARRAY *)0xdeadbeef; ret = CryptRetrieveObjectByUrlA(url, NULL, 0, 0, (void **)&pBlobArray, NULL, NULL, NULL, NULL); ok(ret, "CryptRetrieveObjectByUrlA failed: %d\n", GetLastError()); ok(pBlobArray && pBlobArray != (CRYPT_BLOB_ARRAY *)0xdeadbeef, "Expected a valid pointer\n"); if (pBlobArray && pBlobArray != (CRYPT_BLOB_ARRAY *)0xdeadbeef) { ok(pBlobArray->cBlob == 1, "Expected 1 blob, got %d\n", pBlobArray->cBlob); ok(pBlobArray->rgBlob[0].cbData == sizeof(certWithCRLDistPoint), "Unexpected size %d\n", pBlobArray->rgBlob[0].cbData); CryptMemFree(pBlobArray); } cert = (PCCERT_CONTEXT)0xdeadbeef; ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CERTIFICATE, 0, 0, (void **)&cert, NULL, NULL, NULL, NULL); ok(cert && cert != (PCCERT_CONTEXT)0xdeadbeef, "Expected a cert\n"); if (cert && cert != (PCCERT_CONTEXT)0xdeadbeef) CertFreeCertificateContext(cert); crl = (PCCRL_CONTEXT)0xdeadbeef; SetLastError(0xdeadbeef); ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CRL, 0, 0, (void **)&crl, NULL, NULL, NULL, NULL); ok(!ret && GetLastError() == CRYPT_E_NO_MATCH, "Expected CRYPT_E_NO_MATCH, got %08x\n", GetLastError()); ok(crl == NULL, "Expected CRL to be NULL\n"); if (crl && crl != (PCCRL_CONTEXT)0xdeadbeef) CertFreeCRLContext(crl); store = (HCERTSTORE)0xdeadbeef; ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CAPI2_ANY, 0, 0, (void **)&store, NULL, NULL, NULL, NULL); ok(ret, "CryptRetrieveObjectByUrlA failed: %d\n", GetLastError()); if (store && store != (HCERTSTORE)0xdeadbeef) { DWORD certs = 0; cert = NULL; do { cert = CertEnumCertificatesInStore(store, cert); if (cert) certs++; } while (cert); ok(certs == 1, "Expected 1 cert, got %d\n", certs); CertCloseStore(store, 0); } /* Are file URLs cached? */ ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CERTIFICATE, CRYPT_CACHE_ONLY_RETRIEVAL, 0, (void **)&cert, NULL, NULL, NULL, NULL); ok(ret, "CryptRetrieveObjectByUrlA failed: %08x\n", GetLastError()); if (cert && cert != (PCCERT_CONTEXT)0xdeadbeef) CertFreeCertificateContext(cert); ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CERTIFICATE, 0, 0, (void **)&cert, NULL, NULL, NULL, &aux); ok(ret, "CryptRetrieveObjectByUrlA failed: %08x\n", GetLastError()); if (cert && cert != (PCCERT_CONTEXT)0xdeadbeef) CertFreeCertificateContext(cert); aux.cbSize = sizeof(aux); ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CERTIFICATE, 0, 0, (void **)&cert, NULL, NULL, NULL, &aux); ok(ret, "CryptRetrieveObjectByUrlA failed: %08x\n", GetLastError()); aux.pLastSyncTime = &ft; ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CERTIFICATE, 0, 0, (void **)&cert, NULL, NULL, NULL, &aux); ok(ft.dwLowDateTime || ft.dwHighDateTime, "Expected last sync time to be set\n"); DeleteFileA(tmpfile); /* Okay, after being deleted, are file URLs still cached? */ SetLastError(0xdeadbeef); ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CERTIFICATE, CRYPT_CACHE_ONLY_RETRIEVAL, 0, (void **)&cert, NULL, NULL, NULL, NULL); ok(!ret && (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND), "Expected ERROR_FILE_NOT_FOUND or ERROR_PATH_NOT_FOUND, got %d\n", GetLastError()); }
static DWORD netcon_secure_connect_setup(netconn_t *connection, BOOL compat_mode) { SecBuffer out_buf = {0, SECBUFFER_TOKEN, NULL}, in_bufs[2] = {{0, SECBUFFER_TOKEN}, {0, SECBUFFER_EMPTY}}; SecBufferDesc out_desc = {SECBUFFER_VERSION, 1, &out_buf}, in_desc = {SECBUFFER_VERSION, 2, in_bufs}; SecHandle *cred = &cred_handle; BYTE *read_buf; SIZE_T read_buf_size = 2048; ULONG attrs = 0; CtxtHandle ctx; SSIZE_T size; int bits; const CERT_CONTEXT *cert; SECURITY_STATUS status; DWORD res = ERROR_SUCCESS; const DWORD isc_req_flags = ISC_REQ_ALLOCATE_MEMORY|ISC_REQ_USE_SESSION_KEY|ISC_REQ_CONFIDENTIALITY |ISC_REQ_SEQUENCE_DETECT|ISC_REQ_REPLAY_DETECT|ISC_REQ_MANUAL_CRED_VALIDATION; if(!ensure_cred_handle()) return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; if(compat_mode) { if(!have_compat_cred_handle) return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; cred = &compat_cred_handle; } read_buf = heap_alloc(read_buf_size); if(!read_buf) return ERROR_OUTOFMEMORY; status = InitializeSecurityContextW(cred, NULL, connection->server->name, isc_req_flags, 0, 0, NULL, 0, &ctx, &out_desc, &attrs, NULL); assert(status != SEC_E_OK); set_socket_blocking(connection, TRUE); while(status == SEC_I_CONTINUE_NEEDED || status == SEC_E_INCOMPLETE_MESSAGE) { if(out_buf.cbBuffer) { assert(status == SEC_I_CONTINUE_NEEDED); TRACE("sending %u bytes\n", out_buf.cbBuffer); size = sock_send(connection->socket, out_buf.pvBuffer, out_buf.cbBuffer, 0); if(size != out_buf.cbBuffer) { ERR("send failed\n"); status = ERROR_INTERNET_SECURITY_CHANNEL_ERROR; break; } FreeContextBuffer(out_buf.pvBuffer); out_buf.pvBuffer = NULL; out_buf.cbBuffer = 0; } if(status == SEC_I_CONTINUE_NEEDED) { assert(in_bufs[1].cbBuffer < read_buf_size); memmove(read_buf, (BYTE*)in_bufs[0].pvBuffer+in_bufs[0].cbBuffer-in_bufs[1].cbBuffer, in_bufs[1].cbBuffer); in_bufs[0].cbBuffer = in_bufs[1].cbBuffer; in_bufs[1].BufferType = SECBUFFER_EMPTY; in_bufs[1].cbBuffer = 0; in_bufs[1].pvBuffer = NULL; } assert(in_bufs[0].BufferType == SECBUFFER_TOKEN); assert(in_bufs[1].BufferType == SECBUFFER_EMPTY); if(in_bufs[0].cbBuffer + 1024 > read_buf_size) { BYTE *new_read_buf; new_read_buf = heap_realloc(read_buf, read_buf_size + 1024); if(!new_read_buf) { status = E_OUTOFMEMORY; break; } in_bufs[0].pvBuffer = read_buf = new_read_buf; read_buf_size += 1024; } size = sock_recv(connection->socket, read_buf+in_bufs[0].cbBuffer, read_buf_size-in_bufs[0].cbBuffer, 0); if(size < 1) { WARN("recv error\n"); res = ERROR_INTERNET_SECURITY_CHANNEL_ERROR; break; } TRACE("recv %lu bytes\n", size); in_bufs[0].cbBuffer += size; in_bufs[0].pvBuffer = read_buf; status = InitializeSecurityContextW(cred, &ctx, connection->server->name, isc_req_flags, 0, 0, &in_desc, 0, NULL, &out_desc, &attrs, NULL); TRACE("InitializeSecurityContext ret %08x\n", status); if(status == SEC_E_OK) { if(SecIsValidHandle(&connection->ssl_ctx)) DeleteSecurityContext(&connection->ssl_ctx); connection->ssl_ctx = ctx; if(in_bufs[1].BufferType == SECBUFFER_EXTRA) FIXME("SECBUFFER_EXTRA not supported\n"); status = QueryContextAttributesW(&ctx, SECPKG_ATTR_STREAM_SIZES, &connection->ssl_sizes); if(status != SEC_E_OK) { WARN("Could not get sizes\n"); break; } status = QueryContextAttributesW(&ctx, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (void*)&cert); if(status == SEC_E_OK) { res = netconn_verify_cert(connection, cert, cert->hCertStore); CertFreeCertificateContext(cert); if(res != ERROR_SUCCESS) { WARN("cert verify failed: %u\n", res); break; } }else { WARN("Could not get cert\n"); break; } connection->ssl_buf = heap_alloc(connection->ssl_sizes.cbHeader + connection->ssl_sizes.cbMaximumMessage + connection->ssl_sizes.cbTrailer); if(!connection->ssl_buf) { res = GetLastError(); break; } } } heap_free(read_buf); if(status != SEC_E_OK || res != ERROR_SUCCESS) { WARN("Failed to establish SSL connection: %08x (%u)\n", status, res); heap_free(connection->ssl_buf); connection->ssl_buf = NULL; return res ? res : ERROR_INTERNET_SECURITY_CHANNEL_ERROR; } TRACE("established SSL connection\n"); connection->secure = TRUE; connection->security_flags |= SECURITY_FLAG_SECURE; bits = NETCON_GetCipherStrength(connection); if (bits >= 128) connection->security_flags |= SECURITY_FLAG_STRENGTH_STRONG; else if (bits >= 56) connection->security_flags |= SECURITY_FLAG_STRENGTH_MEDIUM; else connection->security_flags |= SECURITY_FLAG_STRENGTH_WEAK; if(connection->mask_errors) connection->server->security_flags = connection->security_flags; return ERROR_SUCCESS; }
my_bool ma_schannel_verify_certs(SC_CTX *sctx, DWORD dwCertFlags) { SECURITY_STATUS sRet; DWORD flags; MARIADB_PVIO *pvio= sctx->mysql->net.pvio; PCCERT_CONTEXT pServerCert= NULL; PCCERT_CONTEXT ca_CTX = NULL; PCCRL_CONTEXT crl_CTX = NULL; my_bool is_Ok = 0; if ((sRet= QueryContextAttributes(&sctx->ctxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pServerCert)) != SEC_E_OK) { ma_schannel_set_sec_error(pvio, sRet); return 0; } if (ca_Check) { flags = CERT_STORE_SIGNATURE_FLAG | CERT_STORE_TIME_VALIDITY_FLAG; while ((ca_CTX = CertFindCertificateInStore(ca_CertStore, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 0, CERT_FIND_ANY, 0, ca_CTX)) && !is_Ok) { if (sRet = CertVerifySubjectCertificateContext(pServerCert, ca_CTX, &flags)) is_Ok = 1; } if (ca_CTX) CertFreeCertificateContext(ca_CTX); if (!is_Ok) { ma_schannel_set_win_error(pvio); return 0; } if (flags) { if ((flags & CERT_STORE_SIGNATURE_FLAG) != 0) pvio->set_error(sctx->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Certificate signature check failed"); else if ((flags & CERT_STORE_REVOCATION_FLAG) != 0) pvio->set_error(sctx->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "certificate was revoked"); else if ((flags & CERT_STORE_TIME_VALIDITY_FLAG) != 0) pvio->set_error(sctx->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "certificate has expired"); else pvio->set_error(sctx->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Unknown error during certificate validation"); return 0; } } /* Check if none of the certificates in the certificate chain have been revoked. */ if (crl_Check) { while ((crl_CTX = CertEnumCRLsInStore(crl_CertStore, crl_CTX))) { PCRL_INFO Info[1]; Info[0] = crl_CTX->pCrlInfo; if (!(CertVerifyCRLRevocation(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, pServerCert->pCertInfo, 1, Info))) { CertFreeCRLContext(crl_CTX); pvio->set_error(pvio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "CRL Revocation failed"); return 0; } } CertFreeCRLContext(crl_CTX); } return 1; }
Win32CertificatePtr Win32Certificate::findRootCertificate( Win32CertificateLocation certStoreLocation, Win32CertificateStore certStore) { std::wstring storeName; switch (certStore) { case Cs_AddressBook: storeName = L"AddressBook"; break; case Cs_AuthRoot: storeName = L"AuthRoot"; break; case Cs_CertificateAuthority: storeName = L"CA"; break; case Cs_Disallowed: storeName = L"Disallowed"; break; case Cs_My: storeName = L"MY"; break; case Cs_Root: storeName = L"Root"; break; case Cs_TrustedPeople: storeName = L"TrustedPeople"; break; case Cs_TrustedPublisher: storeName = L"TrustedPublisher"; break; default: RCF_ASSERT(0 && "Invalid certificate store value."); } DWORD dwFlags = 0; switch (certStoreLocation) { case Cl_CurrentUser: dwFlags = CERT_SYSTEM_STORE_CURRENT_USER; break; case Cl_LocalMachine: dwFlags = CERT_SYSTEM_STORE_LOCAL_MACHINE; break; default: RCF_ASSERT(0 && "Invalid certificate store location value."); } Win32CertificatePtr issuerCertPtr; HCERTSTORE hCertStore = CertOpenStore( (LPCSTR) CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING, 0, dwFlags, storeName.c_str()); DWORD dwErr = GetLastError(); RCF_VERIFY( hCertStore, Exception(_RcfError_ApiError("CertOpenStore()"), dwErr)); PCCERT_CONTEXT pSubjectContext = getWin32Context(); DWORD dwCertFlags = 0; PCCERT_CONTEXT pIssuerContext = NULL; pSubjectContext = CertDuplicateCertificateContext(pSubjectContext); if (pSubjectContext) { do { dwCertFlags = CERT_STORE_REVOCATION_FLAG | CERT_STORE_SIGNATURE_FLAG | CERT_STORE_TIME_VALIDITY_FLAG; pIssuerContext = CertGetIssuerCertificateFromStore( hCertStore, pSubjectContext, 0, &dwCertFlags); if (pIssuerContext) { CertFreeCertificateContext(pSubjectContext); pSubjectContext = pIssuerContext; if (dwCertFlags & CERT_STORE_NO_CRL_FLAG) { // No CRL list available. Proceed anyway. dwCertFlags &= ~(CERT_STORE_NO_CRL_FLAG | CERT_STORE_REVOCATION_FLAG); } if (dwCertFlags) { if ( dwCertFlags & CERT_STORE_TIME_VALIDITY_FLAG) { // Certificate is expired. // ... } break; } } else if (GetLastError() == CRYPT_E_SELF_SIGNED) { // Got the root certificate. issuerCertPtr.reset( new Win32Certificate(pSubjectContext) ); } } while (pIssuerContext); } CertCloseStore(hCertStore, 0); return issuerCertPtr; }