static const char *get_cert_common_name(PCCERT_CONTEXT cert) { static char buf[1024]; const char *name = NULL; CERT_NAME_INFO *nameInfo; DWORD size; BOOL ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME, cert->pCertInfo->Subject.pbData, cert->pCertInfo->Subject.cbData, CRYPT_DECODE_NOCOPY_FLAG | CRYPT_DECODE_ALLOC_FLAG, NULL, &nameInfo, &size); if (ret) { PCERT_RDN_ATTR commonName = CertFindRDNAttr(szOID_COMMON_NAME, nameInfo); if (commonName) { CertRDNValueToStrA(commonName->dwValueType, &commonName->Value, buf, sizeof(buf)); name = buf; } LocalFree(nameInfo); } return name; }
static void test_findRDNAttr(void) { PCERT_RDN_ATTR ret; static CHAR oid[] = "1.2.3"; BYTE bin[] = { 0x16,0x09,'J','u','a','n',' ','L','a','n','g' }; CERT_RDN_ATTR attrs[] = { { oid, CERT_RDN_IA5_STRING, { sizeof bin, bin } }, }; CERT_RDN rdns[] = { { sizeof(attrs) / sizeof(attrs[0]), attrs }, }; CERT_NAME_INFO nameInfo = { sizeof(rdns) / sizeof(rdns[0]), rdns }; if (0) { /* crashes */ SetLastError(0xdeadbeef); CertFindRDNAttr(NULL, NULL); /* returns NULL, last error is ERROR_INVALID_PARAMETER * crashes on Vista */ SetLastError(0xdeadbeef); ret = CertFindRDNAttr(NULL, &nameInfo); 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 = CertFindRDNAttr("bogus", &nameInfo); 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 = CertFindRDNAttr("1.2.4", &nameInfo); 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 = CertFindRDNAttr("1.2.3", &nameInfo); ok(ret != NULL, "CertFindRDNAttr failed: %08x\n", GetLastError()); }
/* sqExtractPeerName: Extract the name from the cert of the remote peer. */ static int sqExtractPeerName(sqSSL *ssl) { SECURITY_STATUS ret; PCCERT_CONTEXT certHandle = NULL; PCERT_NAME_INFO certInfo = NULL; PCERT_RDN_ATTR certAttr = NULL; DWORD dwSize = 0; char tmpBuf[1024]; if(ssl->peerName) { free(ssl->peerName); ssl->peerName = NULL; } ret = QueryContextAttributes(&ssl->sslCtxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&certHandle); /* No credentials were provided; can't extract peer name */ if(ret == SEC_E_NO_CREDENTIALS) return 1; if(ret != SEC_E_OK) { if(ssl->loglevel) printf("sqExtractPeerName: QueryContextAttributes failed (code = %x)\n", ret); return 0; } /* Figure out the size of the blob */ if(!CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, X509_NAME, certHandle->pCertInfo->Subject.pbData, certHandle->pCertInfo->Subject.cbData, 0, NULL, &dwSize)) { if(ssl->loglevel) printf("sqExtractPeerName: CryptDecodeObject failed\n"); return 0; } /* Get the contents */ certInfo = alloca(dwSize); if(!CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, X509_NAME, certHandle->pCertInfo->Subject.pbData, certHandle->pCertInfo->Subject.cbData, 0, certInfo, &dwSize)) { if(ssl->loglevel) printf("sqExtractPeerName: CryptDecodeObject failed\n"); return 0; } /* Fetch the CN from the cert */ certAttr = CertFindRDNAttr(szOID_COMMON_NAME, certInfo); if(certAttr == NULL) return 0; /* Translate from RDN to string */ if(CertRDNValueToStr(CERT_RDN_PRINTABLE_STRING, &certAttr->Value, tmpBuf, sizeof(tmpBuf)) == 0) return 0; ssl->peerName = _strdup(tmpBuf); if(ssl->loglevel) printf("sqExtractPeerName: Peer name is %s\n", ssl->peerName); CertFreeCertificateContext(certHandle); return 1; }
static DWORD cert_get_name_from_rdn_attr(DWORD encodingType, const CERT_NAME_BLOB *name, LPCSTR oid, LPWSTR pszNameString, DWORD cchNameString) { CERT_NAME_INFO *nameInfo; DWORD bytes = 0, ret = 0; if (CryptDecodeObjectEx(encodingType, X509_NAME, name->pbData, name->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &nameInfo, &bytes)) { PCERT_RDN_ATTR nameAttr = CertFindRDNAttr(oid, nameInfo); if (nameAttr) ret = CertRDNValueToStrW(nameAttr->dwValueType, &nameAttr->Value, pszNameString, cchNameString); LocalFree(nameInfo); } return ret; }
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; }
DWORD WINAPI CertGetNameStringW(PCCERT_CONTEXT pCertContext, DWORD dwType, DWORD dwFlags, void *pvTypePara, LPWSTR pszNameString, DWORD cchNameString) { DWORD ret = 0; PCERT_NAME_BLOB name; LPCSTR altNameOID; TRACE("(%p, %d, %08x, %p, %p, %d)\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_EMAIL_TYPE: { CERT_ALT_NAME_INFO *info; PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext, altNameOID, CERT_ALT_NAME_RFC822_NAME, &info); if (entry) { if (!pszNameString) ret = strlenW(entry->u.pwszRfc822Name) + 1; else if (cchNameString) { ret = min(strlenW(entry->u.pwszRfc822Name), cchNameString - 1); memcpy(pszNameString, entry->u.pwszRfc822Name, ret * sizeof(WCHAR)); pszNameString[ret++] = 0; } } if (info) LocalFree(info); if (!ret) ret = cert_get_name_from_rdn_attr(pCertContext->dwCertEncodingType, name, szOID_RSA_emailAddr, pszNameString, cchNameString); break; } case CERT_NAME_RDN_TYPE: if (name->cbData) ret = CertNameToStrW(pCertContext->dwCertEncodingType, name, *(DWORD *)pvTypePara, pszNameString, cchNameString); else { CERT_ALT_NAME_INFO *info; PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext, altNameOID, CERT_ALT_NAME_DIRECTORY_NAME, &info); if (entry) ret = CertNameToStrW(pCertContext->dwCertEncodingType, &entry->u.DirectoryName, *(DWORD *)pvTypePara, pszNameString, cchNameString); if (info) LocalFree(info); } break; case CERT_NAME_ATTR_TYPE: ret = cert_get_name_from_rdn_attr(pCertContext->dwCertEncodingType, name, pvTypePara, pszNameString, cchNameString); if (!ret) { CERT_ALT_NAME_INFO *altInfo; PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext, altNameOID, CERT_ALT_NAME_DIRECTORY_NAME, &altInfo); if (entry) ret = cert_name_to_str_with_indent(X509_ASN_ENCODING, 0, &entry->u.DirectoryName, 0, pszNameString, cchNameString); if (altInfo) LocalFree(altInfo); } break; 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 *nameInfo = NULL; DWORD bytes = 0, i; if (CryptDecodeObjectEx(pCertContext->dwCertEncodingType, X509_NAME, name->pbData, name->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &nameInfo, &bytes)) { PCERT_RDN_ATTR nameAttr = NULL; for (i = 0; !nameAttr && i < sizeof(simpleAttributeOIDs) / sizeof(simpleAttributeOIDs[0]); i++) nameAttr = CertFindRDNAttr(simpleAttributeOIDs[i], nameInfo); if (nameAttr) ret = CertRDNValueToStrW(nameAttr->dwValueType, &nameAttr->Value, pszNameString, cchNameString); LocalFree(nameInfo); } if (!ret) { CERT_ALT_NAME_INFO *altInfo; PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext, altNameOID, CERT_ALT_NAME_RFC822_NAME, &altInfo); if (altInfo) { if (!entry && altInfo->cAltEntry) entry = &altInfo->rgAltEntry[0]; if (entry) { if (!pszNameString) ret = strlenW(entry->u.pwszRfc822Name) + 1; else if (cchNameString) { ret = min(strlenW(entry->u.pwszRfc822Name), cchNameString - 1); memcpy(pszNameString, entry->u.pwszRfc822Name, ret * sizeof(WCHAR)); pszNameString[ret++] = 0; } } LocalFree(altInfo); } } 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; } case CERT_NAME_DNS_TYPE: { CERT_ALT_NAME_INFO *info; PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext, altNameOID, CERT_ALT_NAME_DNS_NAME, &info); if (entry) { if (!pszNameString) ret = strlenW(entry->u.pwszDNSName) + 1; else if (cchNameString) { ret = min(strlenW(entry->u.pwszDNSName), cchNameString - 1); memcpy(pszNameString, entry->u.pwszDNSName, ret * sizeof(WCHAR)); pszNameString[ret++] = 0; } } if (info) LocalFree(info); if (!ret) ret = cert_get_name_from_rdn_attr(pCertContext->dwCertEncodingType, name, szOID_COMMON_NAME, pszNameString, cchNameString); break; } case CERT_NAME_URL_TYPE: { CERT_ALT_NAME_INFO *info; PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext, altNameOID, CERT_ALT_NAME_URL, &info); if (entry) { if (!pszNameString) ret = strlenW(entry->u.pwszURL) + 1; else if (cchNameString) { ret = min(strlenW(entry->u.pwszURL), cchNameString - 1); memcpy(pszNameString, entry->u.pwszURL, ret * sizeof(WCHAR)); pszNameString[ret++] = 0; } } if (info) LocalFree(info); break; } default: FIXME("unimplemented for type %d\n", dwType); ret = 0; } if (!ret) { if (!pszNameString) ret = 1; else if (cchNameString) { pszNameString[0] = 0; ret = 1; } } return ret; }
tstring Win32Certificate::getCertAttribute(const char * whichAttr) { PCCERT_CONTEXT pContext = getWin32Context(); // How much space do we need. DWORD cbNameInfo = 0; DWORD dwRet = CryptDecodeObject( X509_ASN_ENCODING, X509_NAME, pContext->pCertInfo->Subject.pbData, pContext->pCertInfo->Subject.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL, &cbNameInfo); DWORD dwErr = GetLastError(); RCF_VERIFY( dwRet, RCF::Exception( _RcfError_CryptoApiError("CryptDecodeObject()"), dwErr, RCF::RcfSubsystem_Os)); std::vector<char> vec(cbNameInfo); // Retrieve name info. dwRet = CryptDecodeObject(X509_ASN_ENCODING, X509_NAME, pContext->pCertInfo->Subject.pbData, pContext->pCertInfo->Subject.cbData, CRYPT_DECODE_NOCOPY_FLAG, &vec[0], &cbNameInfo); dwErr = GetLastError(); RCF_VERIFY( dwRet, RCF::Exception( _RcfError_CryptoApiError("CryptDecodeObject()"), dwErr, RCF::RcfSubsystem_Os)); PCERT_NAME_INFO pCertNameInfo = (PCERT_NAME_INFO) &vec[0]; PCERT_RDN_ATTR pCertAttr = CertFindRDNAttr(whichAttr, pCertNameInfo); if (pCertAttr) { DWORD cbLen = CertRDNValueToStr(pCertAttr->dwValueType, &pCertAttr->Value, NULL, 0); std::vector<TCHAR> vecAttr(cbLen); CertRDNValueToStr( pCertAttr->dwValueType, &pCertAttr->Value, &vecAttr[0], static_cast<DWORD>(vecAttr.size())); tstring attr(&vecAttr[0]); return attr; } return tstring(); }