diff --git a/dlls/crypt32/crypt32_En.rc b/dlls/crypt32/crypt32_En.rc index 67ecd88077d..ceb070313d3 100644 --- a/dlls/crypt32/crypt32_En.rc +++ b/dlls/crypt32/crypt32_En.rc @@ -199,4 +199,16 @@ STRINGTABLE DISCARDABLE IDS_ACCESS_METHOD_CA_ISSUERS "CA Issuers" IDS_ACCESS_METHOD_UNKNOWN "Unknown Access Method" IDS_ACCESS_LOCATION "Alternative Name" + IDS_CRL_DIST_POINT "CRL Distribution Point" + IDS_CRL_DIST_POINT_NAME "Distribution Point Name" + IDS_CRL_DIST_POINT_FULL_NAME "Full Name" + IDS_CRL_DIST_POINT_RDN_NAME "RDN Name" + IDS_CRL_DIST_POINT_REASON "CRL Reason=" + IDS_CRL_DIST_POINT_ISSUER "CRL Issuer" + IDS_REASON_KEY_COMPROMISE "Key Compromise" + IDS_REASON_CA_COMPROMISE "CA Compromise" + IDS_REASON_AFFILIATION_CHANGED "Affiliation Changed" + IDS_REASON_SUPERCEDED "Superceded" + IDS_REASON_CESSATION_OF_OPERATION "Operation Ceased" + IDS_REASON_CERTIFICATE_HOLD "Certificate Hold" } diff --git a/dlls/crypt32/cryptres.h b/dlls/crypt32/cryptres.h index b2476ce861f..0ac839f15d7 100644 --- a/dlls/crypt32/cryptres.h +++ b/dlls/crypt32/cryptres.h @@ -189,5 +189,17 @@ #define IDS_ACCESS_METHOD_CA_ISSUERS 1222 #define IDS_ACCESS_METHOD_UNKNOWN 1223 #define IDS_ACCESS_LOCATION 1224 +#define IDS_CRL_DIST_POINT 1225 +#define IDS_CRL_DIST_POINT_NAME 1226 +#define IDS_CRL_DIST_POINT_FULL_NAME 1227 +#define IDS_CRL_DIST_POINT_RDN_NAME 1228 +#define IDS_CRL_DIST_POINT_REASON 1229 +#define IDS_CRL_DIST_POINT_ISSUER 1230 +#define IDS_REASON_KEY_COMPROMISE 1231 +#define IDS_REASON_CA_COMPROMISE 1232 +#define IDS_REASON_AFFILIATION_CHANGED 1233 +#define IDS_REASON_SUPERCEDED 1234 +#define IDS_REASON_CESSATION_OF_OPERATION 1235 +#define IDS_REASON_CERTIFICATE_HOLD 1236 #endif /* ndef __WINE_CRYPTRES_H__ */ diff --git a/dlls/crypt32/object.c b/dlls/crypt32/object.c index 2bd62cd54d3..87b5a207407 100644 --- a/dlls/crypt32/object.c +++ b/dlls/crypt32/object.c @@ -904,7 +904,7 @@ static BOOL CRYPT_FormatAltNameEntry(DWORD dwFormatStrType, DWORD indentLevel, return ret; } -static BOOL CRYPT_FormatAltNameInfo(DWORD dwFormatStrType, +static BOOL CRYPT_FormatAltNameInfo(DWORD dwFormatStrType, DWORD indentLevel, CERT_ALT_NAME_INFO *name, LPWSTR str, DWORD *pcbStr) { DWORD i, size, bytesNeeded = 0; @@ -925,8 +925,8 @@ static BOOL CRYPT_FormatAltNameInfo(DWORD dwFormatStrType, for (i = 0; ret && i < name->cAltEntry; i++) { - ret = CRYPT_FormatAltNameEntry(dwFormatStrType, 0, &name->rgAltEntry[i], - NULL, &size); + ret = CRYPT_FormatAltNameEntry(dwFormatStrType, indentLevel, + &name->rgAltEntry[i], NULL, &size); if (ret) { bytesNeeded += size - sizeof(WCHAR); @@ -950,7 +950,7 @@ static BOOL CRYPT_FormatAltNameInfo(DWORD dwFormatStrType, *pcbStr = bytesNeeded; for (i = 0; ret && i < name->cAltEntry; i++) { - ret = CRYPT_FormatAltNameEntry(dwFormatStrType, 0, + ret = CRYPT_FormatAltNameEntry(dwFormatStrType, indentLevel, &name->rgAltEntry[i], str, &size); if (ret) { @@ -975,7 +975,8 @@ static BOOL CRYPT_FormatCertIssuer(DWORD dwFormatStrType, BOOL ret; LoadStringW(hInstance, IDS_CERT_ISSUER, buf, sizeof(buf) / sizeof(buf[0])); - ret = CRYPT_FormatAltNameInfo(dwFormatStrType, issuer, NULL, &bytesNeeded); + ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 0, issuer, NULL, + &bytesNeeded); bytesNeeded += strlenW(buf) * sizeof(WCHAR); if (ret) { @@ -993,7 +994,7 @@ static BOOL CRYPT_FormatCertIssuer(DWORD dwFormatStrType, strcpyW(str, buf); str += strlenW(str); bytesNeeded -= strlenW(str) * sizeof(WCHAR); - ret = CRYPT_FormatAltNameInfo(dwFormatStrType, issuer, str, + ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 0, issuer, str, &bytesNeeded); } } @@ -1121,6 +1122,8 @@ static BOOL WINAPI CRYPT_FormatAuthorityKeyId2(DWORD dwCertEncodingType, return ret; } +static const WCHAR colonCrlf[] = { ':','\r','\n',0 }; + static WCHAR aia[MAX_STRING_RESOURCE_LEN]; static WCHAR accessMethod[MAX_STRING_RESOURCE_LEN]; static WCHAR ocsp[MAX_STRING_RESOURCE_LEN]; @@ -1174,7 +1177,6 @@ static BOOL WINAPI CRYPT_FormatAuthorityInfoAccess(DWORD dwCertEncodingType, static const WCHAR colonSep[] = { ':',' ',0 }; static const WCHAR numFmt[] = { '%','d',0 }; static const WCHAR equal[] = { '=',0 }; - static const WCHAR colonCrlfSep[] = { ':','\r','\n',0 }; static BOOL stringsLoaded = FALSE; DWORD i; LPCWSTR headingSep, accessMethodSep, locationSep; @@ -1200,7 +1202,7 @@ static BOOL WINAPI CRYPT_FormatAuthorityInfoAccess(DWORD dwCertEncodingType, { headingSep = crlf; accessMethodSep = crlf; - locationSep = colonCrlfSep; + locationSep = colonCrlf; } else { @@ -1343,6 +1345,328 @@ static BOOL WINAPI CRYPT_FormatAuthorityInfoAccess(DWORD dwCertEncodingType, return ret; } +static WCHAR keyCompromise[MAX_STRING_RESOURCE_LEN]; +static WCHAR caCompromise[MAX_STRING_RESOURCE_LEN]; +static WCHAR affiliationChanged[MAX_STRING_RESOURCE_LEN]; +static WCHAR superceded[MAX_STRING_RESOURCE_LEN]; +static WCHAR operationCeased[MAX_STRING_RESOURCE_LEN]; +static WCHAR certificateHold[MAX_STRING_RESOURCE_LEN]; + +struct reason_map_entry +{ + BYTE reasonBit; + LPWSTR reason; + int id; +}; +static struct reason_map_entry reason_map[] = { + { CRL_REASON_KEY_COMPROMISE_FLAG, keyCompromise, IDS_REASON_KEY_COMPROMISE }, + { CRL_REASON_CA_COMPROMISE_FLAG, caCompromise, IDS_REASON_CA_COMPROMISE }, + { CRL_REASON_AFFILIATION_CHANGED_FLAG, affiliationChanged, + IDS_REASON_AFFILIATION_CHANGED }, + { CRL_REASON_SUPERSEDED_FLAG, superceded, IDS_REASON_SUPERCEDED }, + { CRL_REASON_CESSATION_OF_OPERATION_FLAG, operationCeased, + IDS_REASON_CESSATION_OF_OPERATION }, + { CRL_REASON_CERTIFICATE_HOLD_FLAG, certificateHold, + IDS_REASON_CERTIFICATE_HOLD }, +}; + +static BOOL CRYPT_FormatReason(DWORD dwFormatStrType, + const CRYPT_BIT_BLOB *reasonFlags, LPWSTR str, DWORD *pcbStr) +{ + static const WCHAR sep[] = { ',',' ',0 }; + static const WCHAR bitsFmt[] = { ' ','(','%','0','2','x',')',0 }; + static BOOL stringsLoaded = FALSE; + int i, numReasons = 0; + BOOL ret = TRUE; + DWORD bytesNeeded = sizeof(WCHAR); + WCHAR bits[6]; + + if (!stringsLoaded) + { + for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++) + LoadStringW(hInstance, reason_map[i].id, reason_map[i].reason, + MAX_STRING_RESOURCE_LEN); + stringsLoaded = TRUE; + } + /* No need to check reasonFlags->cbData, we already know it's positive. + * Ignore any other bytes, as they're for undefined bits. + */ + for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++) + { + if (reasonFlags->pbData[0] & reason_map[i].reasonBit) + { + bytesNeeded += strlenW(reason_map[i].reason) * sizeof(WCHAR); + if (numReasons++) + bytesNeeded += strlenW(sep) * sizeof(WCHAR); + } + } + sprintfW(bits, bitsFmt, reasonFlags->pbData[0]); + bytesNeeded += strlenW(bits); + if (!str) + *pcbStr = bytesNeeded; + else if (*pcbStr < bytesNeeded) + { + *pcbStr = bytesNeeded; + SetLastError(ERROR_MORE_DATA); + ret = FALSE; + } + else + { + *pcbStr = bytesNeeded; + for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++) + { + if (reasonFlags->pbData[0] & reason_map[i].reasonBit) + { + strcpyW(str, reason_map[i].reason); + str += strlenW(reason_map[i].reason); + if (i < sizeof(reason_map) / sizeof(reason_map[0]) - 1 && + numReasons) + { + strcpyW(str, sep); + str += strlenW(sep); + } + } + } + strcpyW(str, bits); + } + return ret; +} + +static WCHAR crlDistPoint[MAX_STRING_RESOURCE_LEN]; +static WCHAR distPointName[MAX_STRING_RESOURCE_LEN]; +static WCHAR fullName[MAX_STRING_RESOURCE_LEN]; +static WCHAR rdnName[MAX_STRING_RESOURCE_LEN]; +static WCHAR reason[MAX_STRING_RESOURCE_LEN]; +static WCHAR issuer[MAX_STRING_RESOURCE_LEN]; + +static BOOL WINAPI CRYPT_FormatCRLDistPoints(DWORD dwCertEncodingType, + DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, + DWORD *pcbFormat) +{ + CRL_DIST_POINTS_INFO *info; + DWORD size; + BOOL ret = FALSE; + + if (!cbEncoded) + { + SetLastError(E_INVALIDARG); + return FALSE; + } + if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CRL_DIST_POINTS, + pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size))) + { + static const WCHAR numFmt[] = { '%','d',0 }; + static const WCHAR colonSep[] = { ':',' ',0 }; + static const WCHAR commaSep[] = { ',',' ',0 }; + static const WCHAR colon[] = { ':',0 }; + static BOOL stringsLoaded = FALSE; + DWORD bytesNeeded = sizeof(WCHAR); /* space for NULL terminator */ + BOOL haveAnEntry = FALSE; + LPCWSTR headingSep, distPointSep, nameSep; + WCHAR distPointNum[11]; + DWORD i; + + if (!stringsLoaded) + { + LoadStringW(hInstance, IDS_CRL_DIST_POINT, crlDistPoint, + sizeof(crlDistPoint) / sizeof(crlDistPoint[0])); + LoadStringW(hInstance, IDS_CRL_DIST_POINT_NAME, distPointName, + sizeof(distPointName) / sizeof(distPointName[0])); + LoadStringW(hInstance, IDS_CRL_DIST_POINT_FULL_NAME, fullName, + sizeof(fullName) / sizeof(fullName[0])); + LoadStringW(hInstance, IDS_CRL_DIST_POINT_RDN_NAME, rdnName, + sizeof(rdnName) / sizeof(rdnName[0])); + LoadStringW(hInstance, IDS_CRL_DIST_POINT_REASON, reason, + sizeof(reason) / sizeof(reason[0])); + LoadStringW(hInstance, IDS_CRL_DIST_POINT_ISSUER, issuer, + sizeof(issuer) / sizeof(issuer[0])); + stringsLoaded = TRUE; + } + if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) + { + headingSep = crlf; + distPointSep = crlf; + nameSep = colonCrlf; + } + else + { + headingSep = colonSep; + distPointSep = commaSep; + nameSep = colon; + } + + for (i = 0; ret && i < info->cDistPoint; i++) + { + CRL_DIST_POINT *distPoint = &info->rgDistPoint[i]; + + if (distPoint->DistPointName.dwDistPointNameChoice != + CRL_DIST_POINT_NO_NAME) + { + bytesNeeded += strlenW(distPointName) * sizeof(WCHAR); + bytesNeeded += strlenW(colon) * sizeof(WCHAR); + if (distPoint->DistPointName.dwDistPointNameChoice == + CRL_DIST_POINT_FULL_NAME) + bytesNeeded += strlenW(fullName) * sizeof(WCHAR); + else + bytesNeeded += strlenW(rdnName) * sizeof(WCHAR); + bytesNeeded += strlenW(nameSep) * sizeof(WCHAR); + /* The indent level (3) is higher than when used as the issuer, + * because the name is suppordinate to the name type (full vs. + * RDN.) + */ + ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 3, + &distPoint->DistPointName.u.FullName, NULL, &size); + if (ret) + bytesNeeded += size - sizeof(WCHAR); + haveAnEntry = TRUE; + } + else if (distPoint->ReasonFlags.cbData) + { + bytesNeeded += strlenW(reason) * sizeof(WCHAR); + ret = CRYPT_FormatReason(dwFormatStrType, + &distPoint->ReasonFlags, NULL, &size); + if (ret) + bytesNeeded += size - sizeof(WCHAR); + haveAnEntry = TRUE; + } + else if (distPoint->CRLIssuer.cAltEntry) + { + bytesNeeded += strlenW(issuer) * sizeof(WCHAR); + bytesNeeded += strlenW(nameSep) * sizeof(WCHAR); + ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 2, + &distPoint->CRLIssuer, NULL, &size); + if (ret) + bytesNeeded += size - sizeof(WCHAR); + haveAnEntry = TRUE; + } + if (haveAnEntry) + { + bytesNeeded += sizeof(WCHAR); /* left bracket */ + sprintfW(distPointNum, numFmt, i + 1); + bytesNeeded += strlenW(distPointNum) * sizeof(WCHAR); + bytesNeeded += sizeof(WCHAR); /* right bracket */ + bytesNeeded += strlenW(crlDistPoint) * sizeof(WCHAR); + bytesNeeded += strlenW(headingSep) * sizeof(WCHAR); + if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) + bytesNeeded += strlenW(indent) * sizeof(WCHAR); + } + } + if (!haveAnEntry) + { + WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN]; + + LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable, + sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0])); + bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR); + if (!pbFormat) + *pcbFormat = bytesNeeded; + else if (*pcbFormat < bytesNeeded) + { + *pcbFormat = bytesNeeded; + SetLastError(ERROR_MORE_DATA); + ret = FALSE; + } + else + { + *pcbFormat = bytesNeeded; + strcpyW((LPWSTR)pbFormat, infoNotAvailable); + } + } + else + { + if (!pbFormat) + *pcbFormat = bytesNeeded; + else if (*pcbFormat < bytesNeeded) + { + *pcbFormat = bytesNeeded; + SetLastError(ERROR_MORE_DATA); + ret = FALSE; + } + else + { + LPWSTR str = pbFormat; + + *pcbFormat = bytesNeeded; + for (i = 0; ret && i < info->cDistPoint; i++) + { + CRL_DIST_POINT *distPoint = &info->rgDistPoint[i]; + + *str++ = '['; + sprintfW(distPointNum, numFmt, i + 1); + strcpyW(str, distPointNum); + str += strlenW(distPointNum); + *str++ = ']'; + strcpyW(str, crlDistPoint); + str += strlenW(crlDistPoint); + strcpyW(str, headingSep); + str += strlenW(headingSep); + if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) + { + strcpyW(str, indent); + str += strlenW(indent); + } + if (distPoint->DistPointName.dwDistPointNameChoice != + CRL_DIST_POINT_NO_NAME) + { + DWORD altNameSize = bytesNeeded; + + strcpyW(str, distPointName); + str += strlenW(distPointName); + strcpyW(str, colon); + str += strlenW(colon); + if (distPoint->DistPointName.dwDistPointNameChoice == + CRL_DIST_POINT_FULL_NAME) + { + strcpyW(str, fullName); + str += strlenW(fullName); + } + else + { + strcpyW(str, rdnName); + str += strlenW(rdnName); + } + strcpyW(str, nameSep); + str += strlenW(nameSep); + ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 3, + &distPoint->DistPointName.u.FullName, str, + &altNameSize); + if (ret) + str += altNameSize / sizeof(WCHAR) - 1; + } + else if (distPoint->ReasonFlags.cbData) + { + DWORD reasonSize = bytesNeeded; + + strcpyW(str, reason); + str += strlenW(reason); + ret = CRYPT_FormatReason(dwFormatStrType, + &distPoint->ReasonFlags, str, &reasonSize); + if (ret) + str += reasonSize / sizeof(WCHAR) - 1; + } + else if (distPoint->CRLIssuer.cAltEntry) + { + DWORD crlIssuerSize = bytesNeeded; + + strcpyW(str, issuer); + str += strlenW(issuer); + strcpyW(str, nameSep); + str += strlenW(nameSep); + ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 2, + &distPoint->CRLIssuer, str, + &crlIssuerSize); + if (ret) + str += crlIssuerSize / sizeof(WCHAR) - 1; + } + } + } + } + LocalFree(info); + } + return ret; +} + static BOOL WINAPI CRYPT_FormatEnhancedKeyUsage(DWORD dwCertEncodingType, DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, @@ -1470,6 +1794,9 @@ static CryptFormatObjectFunc CRYPT_GetBuiltinFormatFunction(DWORD encodingType, case LOWORD(X509_AUTHORITY_INFO_ACCESS): format = CRYPT_FormatAuthorityInfoAccess; break; + case LOWORD(X509_CRL_DIST_POINTS): + format = CRYPT_FormatCRLDistPoints; + break; case LOWORD(X509_ENHANCED_KEY_USAGE): format = CRYPT_FormatEnhancedKeyUsage; break; @@ -1481,6 +1808,8 @@ static CryptFormatObjectFunc CRYPT_GetBuiltinFormatFunction(DWORD encodingType, format = CRYPT_FormatAuthorityInfoAccess; else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER2)) format = CRYPT_FormatAuthorityKeyId2; + else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS)) + format = CRYPT_FormatCRLDistPoints; else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE)) format = CRYPT_FormatEnhancedKeyUsage; if (!format && !(formatStrType & CRYPT_FORMAT_STR_NO_HEX))