DWORD WINAPI CertNameToStrW(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName, DWORD dwStrType, LPWSTR psz, DWORD csz) { static const DWORD unsupportedFlags = CERT_NAME_STR_NO_QUOTING_FLAG | CERT_NAME_STR_REVERSE_FLAG | CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG; static const WCHAR commaSep[] = { ',',' ',0 }; static const WCHAR semiSep[] = { ';',' ',0 }; static const WCHAR crlfSep[] = { '\r','\n',0 }; static const WCHAR plusSep[] = { ' ','+',' ',0 }; static const WCHAR spaceSep[] = { ' ',0 }; DWORD ret = 0, bytes = 0; BOOL bRet; CERT_NAME_INFO *info; TRACE("(%d, %p, %08x, %p, %d)\n", dwCertEncodingType, pName, dwStrType, psz, csz); if (dwStrType & unsupportedFlags) FIXME("unsupported flags: %08x\n", dwStrType & unsupportedFlags); bRet = CryptDecodeObjectEx(dwCertEncodingType, X509_NAME, pName->pbData, pName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &bytes); if (bRet) { DWORD i, j, sepLen, rdnSepLen; LPCWSTR sep, rdnSep; if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG) sep = semiSep; else if (dwStrType & CERT_NAME_STR_CRLF_FLAG) sep = crlfSep; else sep = commaSep; sepLen = lstrlenW(sep); if (dwStrType & CERT_NAME_STR_NO_PLUS_FLAG) rdnSep = spaceSep; else rdnSep = plusSep; rdnSepLen = lstrlenW(rdnSep); for (i = 0; (!psz || ret < csz) && i < info->cRDN; i++) { for (j = 0; (!psz || ret < csz) && j < info->rgRDN[i].cRDNAttr; j++) { DWORD chars; LPCSTR prefixA = NULL; LPCWSTR prefixW = NULL; if ((dwStrType & 0x000000ff) == CERT_OID_NAME_STR) prefixA = info->rgRDN[i].rgRDNAttr[j].pszObjId; else if ((dwStrType & 0x000000ff) == CERT_X500_NAME_STR) { PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo( CRYPT_OID_INFO_OID_KEY, info->rgRDN[i].rgRDNAttr[j].pszObjId, CRYPT_RDN_ATTR_OID_GROUP_ID); if (oidInfo) prefixW = oidInfo->pwszName; else prefixA = info->rgRDN[i].rgRDNAttr[j].pszObjId; } if (prefixW) { /* - 1 is needed to account for the NULL terminator. */ chars = CRYPT_AddPrefixW(prefixW, psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0); ret += chars; csz -= chars; } else if (prefixA) { /* - 1 is needed to account for the NULL terminator. */ chars = CRYPT_AddPrefixAToW(prefixA, psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0); ret += chars; csz -= chars; } /* FIXME: handle quoting */ chars = CertRDNValueToStrW( info->rgRDN[i].rgRDNAttr[j].dwValueType, &info->rgRDN[i].rgRDNAttr[j].Value, psz ? psz + ret : NULL, psz ? csz - ret : 0); if (chars) ret += chars - 1; if (j < info->rgRDN[i].cRDNAttr - 1) { if (psz && ret < csz - rdnSepLen - 1) memcpy(psz + ret, rdnSep, rdnSepLen * sizeof(WCHAR)); ret += rdnSepLen; } } if (i < info->cRDN - 1) { if (psz && ret < csz - sepLen - 1) memcpy(psz + ret, sep, sepLen * sizeof(WCHAR)); ret += sepLen; } } LocalFree(info); } if (psz && csz) { *(psz + ret) = '\0'; csz--; ret++; } else ret++; TRACE("Returning %s\n", debugstr_w(psz)); 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, %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_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); } 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"); } } } if (nameAttr) ret = CertRDNValueToStrW(nameAttr->dwValueType, &nameAttr->Value, pszNameString, cchNameString); else ret = 0; 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 %d\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; }