BOOL WINAPI CertIsValidCRLForCertificate(PCCERT_CONTEXT pCert, PCCRL_CONTEXT pCrl, DWORD dwFlags, void *pvReserved) { PCERT_EXTENSION ext; BOOL ret; TRACE("(%p, %p, %08x, %p)\n", pCert, pCrl, dwFlags, pvReserved); if (!pCert) return TRUE; if ((ext = CertFindExtension(szOID_ISSUING_DIST_POINT, pCrl->pCrlInfo->cExtension, pCrl->pCrlInfo->rgExtension))) { CRL_ISSUING_DIST_POINT *idp; DWORD size; if ((ret = CryptDecodeObjectEx(pCrl->dwCertEncodingType, X509_ISSUING_DIST_POINT, ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &idp, &size))) { if ((ext = CertFindExtension(szOID_CRL_DIST_POINTS, pCert->pCertInfo->cExtension, pCert->pCertInfo->rgExtension))) { CRL_DIST_POINTS_INFO *distPoints; if ((ret = CryptDecodeObjectEx(pCert->dwCertEncodingType, X509_CRL_DIST_POINTS, ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &distPoints, &size))) { DWORD i; ret = FALSE; for (i = 0; !ret && i < distPoints->cDistPoint; i++) ret = match_dist_point_with_issuing_dist_point( &distPoints->rgDistPoint[i], idp); if (!ret) SetLastError(CRYPT_E_NO_MATCH); LocalFree(distPoints); } } else { /* no CRL dist points extension in cert, can't match the CRL * (which has an issuing dist point extension) */ ret = FALSE; SetLastError(CRYPT_E_NO_MATCH); } LocalFree(idp); } } else ret = TRUE; return ret; }
/* Searches cert's extensions for the alternate name extension with OID * altNameOID, and if found, searches it for the alternate name type entryType. * If found, returns a pointer to the entry, otherwise returns NULL. * Regardless of whether an entry of the desired type is found, if the * alternate name extension is present, sets *info to the decoded alternate * name extension, which you must free using LocalFree. * The return value is a pointer within *info, so don't free *info before * you're done with the return value. */ static PCERT_ALT_NAME_ENTRY cert_find_alt_name_entry(PCCERT_CONTEXT cert, LPCSTR altNameOID, DWORD entryType, PCERT_ALT_NAME_INFO *info) { PCERT_ALT_NAME_ENTRY entry = NULL; PCERT_EXTENSION ext = CertFindExtension(altNameOID, cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension); if (ext) { DWORD bytes = 0; if (CryptDecodeObjectEx(cert->dwCertEncodingType, X509_ALTERNATE_NAME, ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, info, &bytes)) { DWORD i; for (i = 0; !entry && i < (*info)->cAltEntry; i++) if ((*info)->rgAltEntry[i].dwAltNameChoice == entryType) entry = &(*info)->rgAltEntry[i]; } } else *info = NULL; return entry; }
static void test_findExtension(void) { PCERT_EXTENSION ret; static CHAR oid[] = "1.2.3"; BYTE blobbin[] = {0x02,0x01,0x01}; CERT_EXTENSION ext = { oid, TRUE, { sizeof blobbin, blobbin } }; /* returns NULL, last error not set */ SetLastError(0xdeadbeef); ret = CertFindExtension(NULL, 0, NULL); ok(ret == NULL, "Expected failure\n"); ok(GetLastError() == 0xdeadbeef, "Last error was set to %08x\n", GetLastError()); if (0) { /* crashes */ SetLastError(0xdeadbeef); CertFindExtension(NULL, 1, NULL); /* returns NULL, last error is ERROR_INVALID_PARAMETER * crashes on Vista */ SetLastError(0xdeadbeef); ret = CertFindExtension(NULL, 1, &ext); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d (%08x)\n", GetLastError(), GetLastError()); } /* returns NULL, last error not set */ SetLastError(0xdeadbeef); ret = CertFindExtension("bogus", 1, &ext); ok(ret == NULL, "Expected failure\n"); ok(GetLastError() == 0xdeadbeef, "Last error was set to %08x\n", GetLastError()); /* returns NULL, last error not set */ SetLastError(0xdeadbeef); ret = CertFindExtension("1.2.4", 1, &ext); ok(ret == NULL, "Expected failure\n"); ok(GetLastError() == 0xdeadbeef, "Last error was set to %08x\n", GetLastError()); /* succeeds, last error not set */ SetLastError(0xdeadbeef); ret = CertFindExtension("1.2.3", 1, &ext); ok(ret != NULL, "CertFindExtension failed: %08x\n", GetLastError()); }
DWORD WINAPI CertGetNameStringW(PCCERT_CONTEXT pCertContext, DWORD dwType, DWORD dwFlags, void *pvTypePara, LPWSTR pszNameString, DWORD cchNameString) { DWORD ret; PCERT_NAME_BLOB name; LPCSTR altNameOID; TRACE("(%p, %ld, %08lx, %p, %p, %ld)\n", pCertContext, dwType, dwFlags, pvTypePara, pszNameString, cchNameString); if (dwFlags & CERT_NAME_ISSUER_FLAG) { name = &pCertContext->pCertInfo->Issuer; altNameOID = szOID_ISSUER_ALT_NAME; } else { name = &pCertContext->pCertInfo->Subject; altNameOID = szOID_SUBJECT_ALT_NAME; } switch (dwType) { case CERT_NAME_SIMPLE_DISPLAY_TYPE: { static const LPCSTR simpleAttributeOIDs[] = { szOID_COMMON_NAME, szOID_ORGANIZATIONAL_UNIT_NAME, szOID_ORGANIZATION_NAME, szOID_RSA_emailAddr }; CERT_NAME_INFO *info = NULL; PCERT_RDN_ATTR nameAttr = NULL; DWORD bytes = 0, i; if (CryptDecodeObjectEx(pCertContext->dwCertEncodingType, X509_NAME, name->pbData, name->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &bytes)) { for (i = 0; !nameAttr && i < sizeof(simpleAttributeOIDs) / sizeof(simpleAttributeOIDs[0]); i++) nameAttr = CertFindRDNAttr(simpleAttributeOIDs[i], info); } else ret = 0; if (!nameAttr) { PCERT_EXTENSION ext = CertFindExtension(altNameOID, pCertContext->pCertInfo->cExtension, pCertContext->pCertInfo->rgExtension); if (ext) { for (i = 0; !nameAttr && i < sizeof(simpleAttributeOIDs) / sizeof(simpleAttributeOIDs[0]); i++) nameAttr = CertFindRDNAttr(simpleAttributeOIDs[i], info); if (!nameAttr) { /* FIXME: gotta then look for a rfc822Name choice in ext. * Failing that, look for the first attribute. */ FIXME("CERT_NAME_SIMPLE_DISPLAY_TYPE: stub\n"); ret = 0; } } } ret = CertRDNValueToStrW(nameAttr->dwValueType, &nameAttr->Value, pszNameString, cchNameString); if (info) LocalFree(info); break; } case CERT_NAME_FRIENDLY_DISPLAY_TYPE: { DWORD cch = cchNameString; if (CertGetCertificateContextProperty(pCertContext, CERT_FRIENDLY_NAME_PROP_ID, pszNameString, &cch)) ret = cch; else ret = CertGetNameStringW(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, dwFlags, pvTypePara, pszNameString, cchNameString); break; } default: FIXME("unimplemented for type %ld\n", dwType); ret = 0; } return ret; }
static BOOL compare_crl_issued_by(PCCRL_CONTEXT pCrlContext, DWORD dwType, DWORD dwFlags, const void *pvPara) { BOOL ret; if (pvPara) { PCCERT_CONTEXT issuer = pvPara; ret = CertCompareCertificateName(issuer->dwCertEncodingType, &issuer->pCertInfo->Subject, &pCrlContext->pCrlInfo->Issuer); if (ret && (dwFlags & CRL_FIND_ISSUED_BY_SIGNATURE_FLAG)) ret = CryptVerifyCertificateSignatureEx(0, issuer->dwCertEncodingType, CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL, (void *)pCrlContext, CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, (void *)issuer, 0, NULL); if (ret && (dwFlags & CRL_FIND_ISSUED_BY_AKI_FLAG)) { PCERT_EXTENSION ext = CertFindExtension( szOID_AUTHORITY_KEY_IDENTIFIER2, pCrlContext->pCrlInfo->cExtension, pCrlContext->pCrlInfo->rgExtension); if (ext) { CERT_AUTHORITY_KEY_ID2_INFO *info; DWORD size; if ((ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_AUTHORITY_KEY_ID2, ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size))) { if (info->AuthorityCertIssuer.cAltEntry && info->AuthorityCertSerialNumber.cbData) { PCERT_ALT_NAME_ENTRY directoryName = NULL; DWORD i; for (i = 0; !directoryName && i < info->AuthorityCertIssuer.cAltEntry; i++) if (info->AuthorityCertIssuer.rgAltEntry[i]. dwAltNameChoice == CERT_ALT_NAME_DIRECTORY_NAME) directoryName = &info->AuthorityCertIssuer.rgAltEntry[i]; if (directoryName) { ret = CertCompareCertificateName( issuer->dwCertEncodingType, &issuer->pCertInfo->Subject, &directoryName->u.DirectoryName); if (ret) ret = CertCompareIntegerBlob( &issuer->pCertInfo->SerialNumber, &info->AuthorityCertSerialNumber); } else { FIXME("no supported name type in authority key id2\n"); ret = FALSE; } } else if (info->KeyId.cbData) { DWORD size; ret = CertGetCertificateContextProperty(issuer, CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size); if (ret && size == info->KeyId.cbData) { LPBYTE buf = CryptMemAlloc(size); if (buf) { CertGetCertificateContextProperty(issuer, CERT_KEY_IDENTIFIER_PROP_ID, buf, &size); ret = !memcmp(buf, info->KeyId.pbData, size); CryptMemFree(buf); } else ret = FALSE; } else ret = FALSE; } else { FIXME("unsupported value for AKI extension\n"); ret = FALSE; } LocalFree(info); } } /* else: a CRL without an AKI matches any cert */ } } else ret = TRUE; return ret; }
void SchannelCertificate::parse() { // // Subject name // DWORD requiredSize = CertNameToStr(X509_ASN_ENCODING, &m_cert->pCertInfo->Subject, CERT_OID_NAME_STR, NULL, 0); if (requiredSize > 1) { vector<char> rawSubjectName(requiredSize); CertNameToStr(X509_ASN_ENCODING, &m_cert->pCertInfo->Subject, CERT_OID_NAME_STR, &rawSubjectName[0], rawSubjectName.size()); m_subjectName = std::string(&rawSubjectName[0]); } // // Common name // // Note: We only pull out one common name from the cert. requiredSize = CertGetNameString(m_cert, CERT_NAME_ATTR_TYPE, 0, szOID_COMMON_NAME, NULL, 0); if (requiredSize > 1) { vector<char> rawCommonName(requiredSize); requiredSize = CertGetNameString(m_cert, CERT_NAME_ATTR_TYPE, 0, szOID_COMMON_NAME, &rawCommonName[0], rawCommonName.size()); m_commonNames.push_back( std::string(&rawCommonName[0]) ); } // // Subject alternative names // PCERT_EXTENSION pExtensions = CertFindExtension(szOID_SUBJECT_ALT_NAME2, m_cert->pCertInfo->cExtension, m_cert->pCertInfo->rgExtension); if (pExtensions) { CRYPT_DECODE_PARA decodePara = {0}; decodePara.cbSize = sizeof(decodePara); CERT_ALT_NAME_INFO* pAltNameInfo = NULL; DWORD altNameInfoSize = 0; BOOL status = CryptDecodeObjectEx( X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, szOID_SUBJECT_ALT_NAME2, pExtensions->Value.pbData, pExtensions->Value.cbData, CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, &decodePara, &pAltNameInfo, &altNameInfoSize); if (status && pAltNameInfo) { for (int i = 0; i < pAltNameInfo->cAltEntry; i++) { if (pAltNameInfo->rgAltEntry[i].dwAltNameChoice == CERT_ALT_NAME_DNS_NAME) addDNSName( wstrToStr( pAltNameInfo->rgAltEntry[i].pwszDNSName ) ); } } } // if (pExtensions) // { // vector<wchar_t> subjectAlt // CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, szOID_SUBJECT_ALT_NAME, pExtensions->Value->pbData, pExtensions->Value->cbData, ) // } // // // subjectAltNames // int subjectAltNameLoc = X509_get_ext_by_NID(cert.get(), NID_subject_alt_name, -1); // if(subjectAltNameLoc != -1) { // X509_EXTENSION* extension = X509_get_ext(cert.get(), subjectAltNameLoc); // std::shared_ptr<GENERAL_NAMES> generalNames(reinterpret_cast<GENERAL_NAMES*>(X509V3_EXT_d2i(extension)), GENERAL_NAMES_free); // std::shared_ptr<ASN1_OBJECT> xmppAddrObject(OBJ_txt2obj(ID_ON_XMPPADDR_OID, 1), ASN1_OBJECT_free); // std::shared_ptr<ASN1_OBJECT> dnsSRVObject(OBJ_txt2obj(ID_ON_DNSSRV_OID, 1), ASN1_OBJECT_free); // for (int i = 0; i < sk_GENERAL_NAME_num(generalNames.get()); ++i) { // GENERAL_NAME* generalName = sk_GENERAL_NAME_value(generalNames.get(), i); // if (generalName->type == GEN_OTHERNAME) { // OTHERNAME* otherName = generalName->d.otherName; // if (OBJ_cmp(otherName->type_id, xmppAddrObject.get()) == 0) { // // XmppAddr // if (otherName->value->type != V_ASN1_UTF8STRING) { // continue; // } // ASN1_UTF8STRING* xmppAddrValue = otherName->value->value.utf8string; // addXMPPAddress(ByteArray(ASN1_STRING_data(xmppAddrValue), ASN1_STRING_length(xmppAddrValue)).toString()); // } // else if (OBJ_cmp(otherName->type_id, dnsSRVObject.get()) == 0) { // // SRVName // if (otherName->value->type != V_ASN1_IA5STRING) { // continue; // } // ASN1_IA5STRING* srvNameValue = otherName->value->value.ia5string; // addSRVName(ByteArray(ASN1_STRING_data(srvNameValue), ASN1_STRING_length(srvNameValue)).toString()); // } // } // else if (generalName->type == GEN_DNS) { // // DNSName // addDNSName(ByteArray(ASN1_STRING_data(generalName->d.dNSName), ASN1_STRING_length(generalName->d.dNSName)).toString()); // } // } // } }
/*********************************************************************** * TrustIsCertificateSelfSigned (WINTRUST.@) */ BOOL WINAPI TrustIsCertificateSelfSigned( PCCERT_CONTEXT cert ) { PCERT_EXTENSION ext; DWORD size; BOOL ret; TRACE("%p\n", cert); if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER2, cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension))) { CERT_AUTHORITY_KEY_ID2_INFO *info; ret = CryptDecodeObjectEx(cert->dwCertEncodingType, X509_AUTHORITY_KEY_ID2, ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, &info, &size); if (ret) { if (info->AuthorityCertIssuer.cAltEntry && info->AuthorityCertSerialNumber.cbData) { PCERT_ALT_NAME_ENTRY directoryName = NULL; DWORD i; for (i = 0; !directoryName && i < info->AuthorityCertIssuer.cAltEntry; i++) if (info->AuthorityCertIssuer.rgAltEntry[i].dwAltNameChoice == CERT_ALT_NAME_DIRECTORY_NAME) directoryName = &info->AuthorityCertIssuer.rgAltEntry[i]; if (directoryName) { ret = CertCompareCertificateName(cert->dwCertEncodingType, &directoryName->u.DirectoryName, &cert->pCertInfo->Issuer) && CertCompareIntegerBlob(&info->AuthorityCertSerialNumber, &cert->pCertInfo->SerialNumber); } else { FIXME("no supported name type in authority key id2\n"); ret = FALSE; } } else if (info->KeyId.cbData) { ret = CertGetCertificateContextProperty(cert, CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size); if (ret && size == info->KeyId.cbData) { LPBYTE buf = CryptMemAlloc(size); if (buf) { CertGetCertificateContextProperty(cert, CERT_KEY_IDENTIFIER_PROP_ID, buf, &size); ret = !memcmp(buf, info->KeyId.pbData, size); CryptMemFree(buf); } else ret = FALSE; } else ret = FALSE; } LocalFree(info); } } else if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER, cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension))) { CERT_AUTHORITY_KEY_ID_INFO *info; ret = CryptDecodeObjectEx(cert->dwCertEncodingType, X509_AUTHORITY_KEY_ID, ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, &info, &size); if (ret) { if (info->CertIssuer.cbData && info->CertSerialNumber.cbData) { ret = CertCompareCertificateName(cert->dwCertEncodingType, &info->CertIssuer, &cert->pCertInfo->Issuer) && CertCompareIntegerBlob(&info->CertSerialNumber, &cert->pCertInfo->SerialNumber); } else if (info->KeyId.cbData) { ret = CertGetCertificateContextProperty(cert, CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size); if (ret && size == info->KeyId.cbData) { LPBYTE buf = CryptMemAlloc(size); if (buf) { CertGetCertificateContextProperty(cert, CERT_KEY_IDENTIFIER_PROP_ID, buf, &size); ret = !memcmp(buf, info->KeyId.pbData, size); CryptMemFree(buf); } else ret = FALSE; } else ret = FALSE; } else ret = FALSE; LocalFree(info); } } else ret = CertCompareCertificateName(cert->dwCertEncodingType, &cert->pCertInfo->Subject, &cert->pCertInfo->Issuer); return ret; }