You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
733 lines
20 KiB
733 lines
20 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 2001 - 2001
|
|
//
|
|
// File: testutil.cpp
|
|
|
|
// Contents: Test Utility API Prototypes and Definitions
|
|
//
|
|
// History: 29-Jan-01 philh created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
#include <windows.h>
|
|
#include <assert.h>
|
|
#include "testutil.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <memory.h>
|
|
#include <time.h>
|
|
#include <stddef.h>
|
|
|
|
#define TESTUTIL_MAX_EXT_CNT 30
|
|
#define TESTUTIL_MAX_ATTR_CNT 30
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Error output routines
|
|
//--------------------------------------------------------------------------
|
|
VOID
|
|
PrintErr(
|
|
IN LPCSTR pszMsg,
|
|
IN LONG lErr
|
|
)
|
|
{
|
|
printf("%s failed => 0x%x (%d) \n", pszMsg, lErr, lErr);
|
|
}
|
|
|
|
VOID
|
|
PrintLastError(
|
|
IN LPCSTR pszMsg
|
|
)
|
|
{
|
|
DWORD dwErr = GetLastError();
|
|
printf("%s failed => 0x%x (%d) \n", pszMsg, dwErr, dwErr);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Test allocation and free routines
|
|
//--------------------------------------------------------------------------
|
|
LPVOID
|
|
TestAlloc(
|
|
IN size_t cbBytes
|
|
)
|
|
{
|
|
LPVOID pv;
|
|
pv = malloc(cbBytes);
|
|
if (pv == NULL)
|
|
PrintErr("TestAlloc", (LONG) GetLastError());
|
|
return pv;
|
|
}
|
|
|
|
VOID
|
|
TestFree(
|
|
IN LPVOID pv
|
|
)
|
|
{
|
|
if (pv)
|
|
free(pv);
|
|
}
|
|
|
|
|
|
CRYPT_DECODE_PARA TestDecodePara = {
|
|
offsetof(CRYPT_DECODE_PARA, pfnFree) + sizeof(TestDecodePara.pfnFree),
|
|
TestAlloc,
|
|
TestFree
|
|
};
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Allocate and convert a multi-byte string to a wide string. TestFree()
|
|
// must be called to free the returned wide string.
|
|
//--------------------------------------------------------------------------
|
|
LPWSTR
|
|
AllocAndSzToWsz(
|
|
IN LPCSTR psz
|
|
)
|
|
{
|
|
size_t cb;
|
|
LPWSTR pwsz = NULL;
|
|
|
|
if (-1 == (cb = mbstowcs( NULL, psz, strlen(psz))))
|
|
goto bad_param;
|
|
cb += 1; // terminating NULL
|
|
if (NULL == (pwsz = (LPWSTR)TestAlloc( cb * sizeof(WCHAR)))) {
|
|
PrintLastError("AllocAndSzToWsz");
|
|
goto failed;
|
|
}
|
|
if (-1 == mbstowcs( pwsz, psz, cb))
|
|
goto bad_param;
|
|
goto common_return;
|
|
|
|
bad_param:
|
|
printf("failed => Bad AllocAndSzToWsz");
|
|
failed:
|
|
if (pwsz) {
|
|
TestFree(pwsz);
|
|
pwsz = NULL;
|
|
}
|
|
common_return:
|
|
return pwsz;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Conversions functions between encoded OID and the dot string
|
|
// representation
|
|
//--------------------------------------------------------------------------
|
|
#define MAX_OID_STRING_LEN 0x80
|
|
#define MAX_ENCODED_OID_LEN 0x80
|
|
|
|
// Encoded Attribute
|
|
//
|
|
// Attribute ::= SEQUENCE {
|
|
// type EncodedObjectID,
|
|
// values AttributeSetValue
|
|
// } --#public--
|
|
//
|
|
// AttributeSetValue ::= SET OF NOCOPYANY
|
|
|
|
|
|
BOOL
|
|
EncodedOIDToDot(
|
|
IN PCRYPT_DER_BLOB pEncodedOIDBlob,
|
|
OUT CHAR rgszOID[MAX_OID_STRING_LEN]
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
DWORD cbOID = pEncodedOIDBlob->cbData;
|
|
const BYTE *pbOID = pEncodedOIDBlob->pbData;
|
|
BYTE rgbEncodedAttr[MAX_ENCODED_OID_LEN];
|
|
PCRYPT_ATTRIBUTE pAttr = NULL;
|
|
DWORD cbAttr;
|
|
|
|
// Convert the OID into an encoded Attribute that we can
|
|
// decode to get the OID string.
|
|
if (0 == cbOID || MAX_OID_STRING_LEN - 6 < cbOID) {
|
|
strcpy(rgszOID, "Invalid OID length");
|
|
return FALSE;
|
|
}
|
|
|
|
rgbEncodedAttr[0] = MINASN1_TAG_SEQ;
|
|
rgbEncodedAttr[1] = (BYTE) (2 + cbOID + 2);
|
|
rgbEncodedAttr[2] = MINASN1_TAG_OID;
|
|
rgbEncodedAttr[3] = (BYTE) cbOID;
|
|
memcpy(&rgbEncodedAttr[4], pbOID, cbOID);
|
|
rgbEncodedAttr[4 + cbOID + 0] = MINASN1_TAG_SET;
|
|
rgbEncodedAttr[4 + cbOID + 1] = 0;
|
|
|
|
if (!CryptDecodeObjectEx(
|
|
X509_ASN_ENCODING,
|
|
PKCS_ATTRIBUTE,
|
|
rgbEncodedAttr,
|
|
2 + 2 + cbOID + 2,
|
|
CRYPT_DECODE_NOCOPY_FLAG | CRYPT_DECODE_ALLOC_FLAG,
|
|
&TestDecodePara,
|
|
(void *) &pAttr,
|
|
&cbAttr
|
|
)) {
|
|
strcpy(rgszOID, "Decode OID failed");
|
|
return FALSE;
|
|
}
|
|
|
|
if (strlen(pAttr->pszObjId) >= MAX_OID_STRING_LEN) {
|
|
strcpy(rgszOID, "Invalid OID length");
|
|
fResult = FALSE;
|
|
} else {
|
|
strcpy(rgszOID, pAttr->pszObjId);
|
|
fResult = TRUE;
|
|
}
|
|
|
|
TestFree(pAttr);
|
|
return fResult;
|
|
}
|
|
|
|
const BYTE rgbSeqTag[] = {MINASN1_TAG_SEQ, 0};
|
|
const BYTE rgbOIDTag[] = {MINASN1_TAG_OID, 0};
|
|
|
|
const MINASN1_EXTRACT_VALUE_PARA rgExtractAttrPara[] = {
|
|
// 0 - Attribute ::= SEQUENCE {
|
|
MINASN1_STEP_INTO_VALUE_OP, 0, rgbSeqTag,
|
|
// 1 - type EncodedObjectID,
|
|
MINASN1_RETURN_CONTENT_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
|
|
0, rgbOIDTag,
|
|
};
|
|
|
|
#define ATTR_VALUE_COUNT \
|
|
(sizeof(rgExtractAttrPara) / sizeof(rgExtractAttrPara[0]))
|
|
|
|
BOOL
|
|
DotToEncodedOID(
|
|
IN LPCSTR pszOID,
|
|
OUT BYTE rgbEncodedOID[MAX_ENCODED_OID_LEN],
|
|
OUT DWORD *pcbEncodedOID
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
CRYPT_ATTRIBUTE Attr;
|
|
BYTE rgbEncoded[512];
|
|
DWORD cbEncoded;
|
|
CRYPT_DER_BLOB rgValueBlob[1];
|
|
DWORD cValue;
|
|
DWORD i;
|
|
BYTE *pb;
|
|
DWORD cb;
|
|
|
|
// Encode an Attribute that only has the OID.
|
|
Attr.pszObjId = (LPSTR) pszOID;
|
|
Attr.cValue = 0;
|
|
Attr.rgValue = NULL;
|
|
|
|
cbEncoded = sizeof(rgbEncoded);
|
|
if (!CryptEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
PKCS_ATTRIBUTE,
|
|
&Attr,
|
|
rgbEncoded,
|
|
&cbEncoded
|
|
)) {
|
|
printf("\n");
|
|
printf("Asn1Encode(%s)", pszOID);
|
|
PrintLastError("");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
cValue = ATTR_VALUE_COUNT;
|
|
if (0 >= MinAsn1ExtractValues(
|
|
rgbEncoded,
|
|
cbEncoded,
|
|
&cValue,
|
|
rgExtractAttrPara,
|
|
1,
|
|
rgValueBlob
|
|
)) {
|
|
printf("Unable to encode OID: %s\n", pszOID);
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
pb = rgValueBlob[0].pbData;
|
|
cb = rgValueBlob[0].cbData;
|
|
|
|
if (0 == cb || MAX_ENCODED_OID_LEN < cb) {
|
|
printf("Invalid length for OID: %s\n", pszOID);
|
|
goto ErrorReturn;
|
|
}
|
|
memcpy(rgbEncodedOID, pb, cb);
|
|
*pcbEncodedOID = cb;
|
|
|
|
fResult = TRUE;
|
|
CommonReturn:
|
|
return fResult;
|
|
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
*pcbEncodedOID = 0;
|
|
goto CommonReturn;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Functions to print bytes
|
|
//--------------------------------------------------------------------------
|
|
VOID
|
|
PrintBytes(
|
|
IN PCRYPT_DER_BLOB pBlob
|
|
)
|
|
{
|
|
DWORD cb = pBlob->cbData;
|
|
BYTE *pb = pBlob->pbData;
|
|
|
|
if (0 == cb) {
|
|
printf(" No Bytes\n");
|
|
return;
|
|
}
|
|
|
|
for (; 0 < cb; cb--, pb++)
|
|
printf(" %02X", *pb);
|
|
|
|
printf("\n");
|
|
}
|
|
|
|
|
|
#define CROW 16
|
|
VOID
|
|
PrintMultiLineBytes(
|
|
IN LPCSTR pszHdr,
|
|
IN PCRYPT_DER_BLOB pBlob
|
|
)
|
|
{
|
|
DWORD cbSize = pBlob->cbData;
|
|
BYTE *pb = pBlob->pbData;
|
|
DWORD cb, i;
|
|
|
|
if (cbSize == 0) {
|
|
printf("%s No Bytes\n", pszHdr);
|
|
return;
|
|
}
|
|
|
|
while (cbSize > 0)
|
|
{
|
|
printf("%s", pszHdr);
|
|
cb = min(CROW, cbSize);
|
|
cbSize -= cb;
|
|
for (i = 0; i<cb; i++)
|
|
printf(" %02X", pb[i]);
|
|
for (i = cb; i<CROW; i++)
|
|
printf(" ");
|
|
printf(" '");
|
|
for (i = 0; i<cb; i++)
|
|
if (pb[i] >= 0x20 && pb[i] <= 0x7f)
|
|
printf("%c", pb[i]);
|
|
else
|
|
printf(".");
|
|
pb += cb;
|
|
printf("'\n");
|
|
}
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Allocate and read an encoded DER blob from a file
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
ReadDERFromFile(
|
|
IN LPCSTR pszFileName,
|
|
OUT PBYTE *ppbDER,
|
|
OUT PDWORD pcbDER
|
|
)
|
|
{
|
|
BOOL fRet;
|
|
HANDLE hFile = 0;
|
|
PBYTE pbDER = NULL;
|
|
DWORD cbDER;
|
|
DWORD cbRead;
|
|
|
|
if( INVALID_HANDLE_VALUE == (hFile = CreateFile( pszFileName, GENERIC_READ,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL, OPEN_EXISTING, 0, NULL))) {
|
|
printf( "can't open %s\n", pszFileName);
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
cbDER = GetFileSize( hFile, NULL);
|
|
if (cbDER == 0) {
|
|
printf( "empty file %s\n", pszFileName);
|
|
goto ErrorReturn;
|
|
}
|
|
if (NULL == (pbDER = (PBYTE)TestAlloc(cbDER))) {
|
|
printf( "can't alloc %d bytes\n", cbDER);
|
|
goto ErrorReturn;
|
|
}
|
|
if (!ReadFile( hFile, pbDER, cbDER, &cbRead, NULL) ||
|
|
(cbRead != cbDER)) {
|
|
printf( "can't read %s\n", pszFileName);
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
*ppbDER = pbDER;
|
|
*pcbDER = cbDER;
|
|
fRet = TRUE;
|
|
CommonReturn:
|
|
if (hFile)
|
|
CloseHandle(hFile);
|
|
return fRet;
|
|
ErrorReturn:
|
|
if (pbDER)
|
|
TestFree(pbDER);
|
|
*ppbDER = NULL;
|
|
*pcbDER = 0;
|
|
fRet = FALSE;
|
|
goto CommonReturn;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Write an encoded DER blob to a file
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
WriteDERToFile(
|
|
IN LPCSTR pszFileName,
|
|
IN PBYTE pbDER,
|
|
IN DWORD cbDER
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
|
|
// Write the Encoded Blob to the file
|
|
HANDLE hFile;
|
|
hFile = CreateFile(pszFileName,
|
|
GENERIC_WRITE,
|
|
0, // fdwShareMode
|
|
NULL, // lpsa
|
|
CREATE_ALWAYS,
|
|
0, // fdwAttrsAndFlags
|
|
0); // TemplateFile
|
|
if (INVALID_HANDLE_VALUE == hFile) {
|
|
fResult = FALSE;
|
|
PrintLastError("WriteDERToFile::CreateFile");
|
|
} else {
|
|
DWORD dwBytesWritten;
|
|
if (!(fResult = WriteFile(
|
|
hFile,
|
|
pbDER,
|
|
cbDER,
|
|
&dwBytesWritten,
|
|
NULL // lpOverlapped
|
|
)))
|
|
PrintLastError("WriteDERToFile::WriteFile");
|
|
CloseHandle(hFile);
|
|
}
|
|
return fResult;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Display functions
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
VOID
|
|
DisplayCert(
|
|
IN CRYPT_DER_BLOB rgCertBlob[MINASN1_CERT_BLOB_CNT],
|
|
IN BOOL fVerbose
|
|
)
|
|
{
|
|
if (0 != rgCertBlob[MINASN1_CERT_VERSION_IDX].cbData) {
|
|
printf("Version:");
|
|
PrintBytes(&rgCertBlob[MINASN1_CERT_VERSION_IDX]);
|
|
}
|
|
|
|
printf("Subject:");
|
|
DisplayName(&rgCertBlob[MINASN1_CERT_SUBJECT_IDX]);
|
|
|
|
printf("Issuer:");
|
|
DisplayName(&rgCertBlob[MINASN1_CERT_ISSUER_IDX]);
|
|
printf("SerialNumber:");
|
|
PrintBytes(&rgCertBlob[MINASN1_CERT_SERIAL_NUMBER_IDX]);
|
|
|
|
|
|
printf("NotBefore:\n");
|
|
PrintMultiLineBytes(" ", &rgCertBlob[MINASN1_CERT_NOT_BEFORE_IDX]);
|
|
printf("NotAfter:\n");
|
|
PrintMultiLineBytes(" ", &rgCertBlob[MINASN1_CERT_NOT_AFTER_IDX]);
|
|
|
|
|
|
if (0 != rgCertBlob[MINASN1_CERT_ISSUER_UNIQUE_ID_IDX].cbData) {
|
|
printf("IssuerUniqueId:\n");
|
|
PrintMultiLineBytes(" ",
|
|
&rgCertBlob[MINASN1_CERT_ISSUER_UNIQUE_ID_IDX]);
|
|
}
|
|
|
|
if (0 != rgCertBlob[MINASN1_CERT_SUBJECT_UNIQUE_ID_IDX].cbData) {
|
|
printf("SubjectUniqueId:\n");
|
|
PrintMultiLineBytes(" ",
|
|
&rgCertBlob[MINASN1_CERT_SUBJECT_UNIQUE_ID_IDX]);
|
|
}
|
|
|
|
if (fVerbose) {
|
|
CRYPT_DER_BLOB rgPubKeyInfoBlob[MINASN1_PUBKEY_INFO_BLOB_CNT];
|
|
CRYPT_DER_BLOB rgPubKeyAlgIdBlob[MINASN1_ALGID_BLOB_CNT];
|
|
CRYPT_DER_BLOB rgSignAlgIdBlob[MINASN1_ALGID_BLOB_CNT];
|
|
|
|
|
|
if (0 >= MinAsn1ParsePublicKeyInfo(
|
|
&rgCertBlob[MINASN1_CERT_PUBKEY_INFO_IDX],
|
|
rgPubKeyInfoBlob
|
|
) ||
|
|
0 >= MinAsn1ParseAlgorithmIdentifier(
|
|
&rgPubKeyInfoBlob[MINASN1_PUBKEY_INFO_ALGID_IDX],
|
|
rgPubKeyAlgIdBlob
|
|
))
|
|
printf("PublicKeyInfo: parse failed\n");
|
|
else {
|
|
CHAR rgszOID[MAX_OID_STRING_LEN];
|
|
CRYPT_DER_BLOB rgRSAPubKeyBlob[MINASN1_RSA_PUBKEY_BLOB_CNT];
|
|
|
|
EncodedOIDToDot(&rgPubKeyAlgIdBlob[MINASN1_ALGID_OID_IDX],
|
|
rgszOID);
|
|
|
|
printf("PublicKeyInfo.Algorithm: %s\n", rgszOID);
|
|
|
|
if (0 != rgPubKeyAlgIdBlob[MINASN1_ALGID_PARA_IDX].cbData) {
|
|
printf("PublicKeyInfo.Algorithm.Parameters:\n");
|
|
PrintMultiLineBytes(" ",
|
|
&rgPubKeyAlgIdBlob[MINASN1_ALGID_PARA_IDX]);
|
|
}
|
|
|
|
if (0 >= MinAsn1ParseRSAPublicKey(
|
|
&rgPubKeyInfoBlob[MINASN1_PUBKEY_INFO_PUBKEY_IDX],
|
|
rgRSAPubKeyBlob
|
|
)) {
|
|
printf("PublicKeyInfo.PublicKey:\n");
|
|
PrintMultiLineBytes(" ",
|
|
&rgPubKeyInfoBlob[MINASN1_PUBKEY_INFO_PUBKEY_IDX]);
|
|
} else {
|
|
DWORD dwByteLen;
|
|
|
|
dwByteLen =
|
|
rgRSAPubKeyBlob[MINASN1_RSA_PUBKEY_MODULUS_IDX].cbData;
|
|
if (0 < dwByteLen && 0 == rgRSAPubKeyBlob[
|
|
MINASN1_RSA_PUBKEY_MODULUS_IDX].pbData[0])
|
|
dwByteLen--;
|
|
printf("PublicKeyInfo.RSAPublicKey.BitLength: %d\n",
|
|
dwByteLen * 8);
|
|
|
|
printf("PublicKeyInfo.RSAPublicKey.Modulus:\n");
|
|
PrintMultiLineBytes(" ",
|
|
&rgRSAPubKeyBlob[MINASN1_RSA_PUBKEY_MODULUS_IDX]);
|
|
printf("PublicKeyInfo.RSAPublicKey.Exponent:");
|
|
PrintBytes(&rgRSAPubKeyBlob[MINASN1_RSA_PUBKEY_EXPONENT_IDX]);
|
|
}
|
|
}
|
|
|
|
if ( 0 >= MinAsn1ParseAlgorithmIdentifier(
|
|
&rgCertBlob[MINASN1_CERT_SIGN_ALGID_IDX],
|
|
rgSignAlgIdBlob
|
|
))
|
|
printf("SignatureAlgorithm: parse failed\n");
|
|
else {
|
|
CHAR rgszOID[MAX_OID_STRING_LEN];
|
|
EncodedOIDToDot(&rgSignAlgIdBlob[MINASN1_ALGID_OID_IDX],
|
|
rgszOID);
|
|
|
|
printf("Signature.Algorithm: %s\n", rgszOID);
|
|
if (0 != rgSignAlgIdBlob[MINASN1_ALGID_PARA_IDX].cbData) {
|
|
printf("Signature.Algorithm.Parameters:\n");
|
|
PrintMultiLineBytes(" ",
|
|
&rgSignAlgIdBlob[MINASN1_ALGID_PARA_IDX]);
|
|
}
|
|
}
|
|
|
|
printf("Signature.Content\n");
|
|
PrintMultiLineBytes(" ", &rgCertBlob[MINASN1_CERT_SIGNATURE_IDX]);
|
|
|
|
DisplayExts(&rgCertBlob[MINASN1_CERT_EXTS_IDX]);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
DisplayName(
|
|
IN PCRYPT_DER_BLOB pNameValueBlob
|
|
)
|
|
{
|
|
WCHAR wszName[512];
|
|
|
|
CertNameToStrW(
|
|
X509_ASN_ENCODING,
|
|
pNameValueBlob,
|
|
CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
|
|
wszName,
|
|
512
|
|
);
|
|
|
|
printf(" <%S>\n", wszName);
|
|
}
|
|
|
|
VOID
|
|
DisplayExts(
|
|
IN PCRYPT_DER_BLOB pExtsValueBlob
|
|
)
|
|
{
|
|
DWORD cExt;
|
|
DWORD i;
|
|
CRYPT_DER_BLOB rgrgExtBlob[TESTUTIL_MAX_EXT_CNT][MINASN1_EXT_BLOB_CNT];
|
|
|
|
if (0 == pExtsValueBlob->cbData)
|
|
return;
|
|
|
|
cExt = TESTUTIL_MAX_EXT_CNT;
|
|
if (0 >= MinAsn1ParseExtensions(
|
|
pExtsValueBlob,
|
|
&cExt,
|
|
rgrgExtBlob
|
|
)) {
|
|
printf("Extensions: parse failed\n");
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < cExt; i++) {
|
|
CHAR rgszOID[MAX_OID_STRING_LEN];
|
|
|
|
EncodedOIDToDot(&rgrgExtBlob[i][MINASN1_EXT_OID_IDX], rgszOID);
|
|
printf("Extension[%d] %s Critical: ", i, rgszOID);
|
|
if (0 != rgrgExtBlob[i][MINASN1_EXT_CRITICAL_IDX].cbData &&
|
|
0 != rgrgExtBlob[i][MINASN1_EXT_CRITICAL_IDX].pbData[0])
|
|
printf("TRUE\n");
|
|
else
|
|
printf("FALSE\n");
|
|
|
|
PrintMultiLineBytes(" ", &rgrgExtBlob[i][MINASN1_EXT_VALUE_IDX]);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
DisplayCTL(
|
|
IN PCRYPT_DER_BLOB pEncodedContentBlob,
|
|
IN BOOL fVerbose
|
|
)
|
|
{
|
|
CRYPT_DER_BLOB rgCTLBlob[MINASN1_CTL_BLOB_CNT];
|
|
|
|
if (0 >= MinAsn1ParseCTL(
|
|
pEncodedContentBlob,
|
|
rgCTLBlob
|
|
)) {
|
|
printf("CTL: parse failed\n");
|
|
return;
|
|
}
|
|
|
|
if (0 != rgCTLBlob[MINASN1_CTL_VERSION_IDX].cbData) {
|
|
printf("Version:");
|
|
PrintBytes(&rgCTLBlob[MINASN1_CTL_VERSION_IDX]);
|
|
}
|
|
|
|
printf("SubjectUsage:\n");
|
|
PrintMultiLineBytes(" ", &rgCTLBlob[MINASN1_CTL_SUBJECT_USAGE_IDX]);
|
|
|
|
if (0 != rgCTLBlob[MINASN1_CTL_LIST_ID_IDX].cbData) {
|
|
printf("ListIdentifier:\n");
|
|
PrintMultiLineBytes(" ", &rgCTLBlob[MINASN1_CTL_LIST_ID_IDX]);
|
|
}
|
|
|
|
if (0 != rgCTLBlob[MINASN1_CTL_SEQUENCE_NUMBER_IDX].cbData) {
|
|
printf("SequenceNumber:");
|
|
PrintBytes(&rgCTLBlob[MINASN1_CTL_SEQUENCE_NUMBER_IDX]);
|
|
}
|
|
|
|
printf("ThisUpdate:\n");
|
|
PrintMultiLineBytes(" ", &rgCTLBlob[MINASN1_CTL_THIS_UPDATE_IDX]);
|
|
if (0 != rgCTLBlob[MINASN1_CTL_NEXT_UPDATE_IDX].cbData) {
|
|
printf("NextUpdate:\n");
|
|
PrintMultiLineBytes(" ", &rgCTLBlob[MINASN1_CTL_NEXT_UPDATE_IDX]);
|
|
}
|
|
|
|
printf("SubjectAlgorithmIdentifier:\n");
|
|
PrintMultiLineBytes(" ", &rgCTLBlob[MINASN1_CTL_SUBJECT_ALGID_IDX]);
|
|
|
|
if (fVerbose)
|
|
DisplayExts(&rgCTLBlob[MINASN1_CTL_EXTS_IDX]);
|
|
|
|
if (0 != rgCTLBlob[MINASN1_CTL_SUBJECTS_IDX].cbData) {
|
|
DWORD cbEncoded;
|
|
const BYTE *pbEncoded;
|
|
DWORD i;
|
|
|
|
printf("\n");
|
|
|
|
// Advance past the Subjects' outer tag and length
|
|
if (0 >= MinAsn1ExtractContent(
|
|
rgCTLBlob[MINASN1_CTL_SUBJECTS_IDX].pbData,
|
|
rgCTLBlob[MINASN1_CTL_SUBJECTS_IDX].cbData,
|
|
&cbEncoded,
|
|
&pbEncoded
|
|
)) {
|
|
printf("Subjects: parse failed\n");
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
// Loop through the encoded subjects
|
|
for (i = 0; 0 != cbEncoded; i++) {
|
|
LONG cbSubject;
|
|
CRYPT_DER_BLOB rgCTLSubjectBlob[MINASN1_CTL_SUBJECT_BLOB_CNT];
|
|
|
|
printf("---- Subject[%d] ----\n", i);
|
|
|
|
cbSubject = MinAsn1ParseCTLSubject(
|
|
pbEncoded,
|
|
cbEncoded,
|
|
rgCTLSubjectBlob
|
|
);
|
|
if (0 >= cbSubject) {
|
|
printf("Subject: parse failed\n");
|
|
return;
|
|
}
|
|
|
|
printf("Identifier:\n");
|
|
PrintMultiLineBytes(" ",
|
|
&rgCTLSubjectBlob[MINASN1_CTL_SUBJECT_ID_IDX]);
|
|
|
|
if (fVerbose) {
|
|
DisplayAttrs("",
|
|
&rgCTLSubjectBlob[MINASN1_CTL_SUBJECT_ATTRS_IDX]);
|
|
printf("\n");
|
|
}
|
|
|
|
pbEncoded += cbSubject;
|
|
cbEncoded -= cbSubject;
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
DisplayAttrs(
|
|
IN LPCSTR pszHdr,
|
|
IN PCRYPT_DER_BLOB pAttrsValueBlob
|
|
)
|
|
{
|
|
DWORD cAttr;
|
|
DWORD i;
|
|
CRYPT_DER_BLOB rgrgAttrBlob[TESTUTIL_MAX_ATTR_CNT][MINASN1_ATTR_BLOB_CNT];
|
|
|
|
if (0 == pAttrsValueBlob->cbData)
|
|
return;
|
|
|
|
cAttr = TESTUTIL_MAX_ATTR_CNT;
|
|
if (0 >= MinAsn1ParseAttributes(
|
|
pAttrsValueBlob,
|
|
&cAttr,
|
|
rgrgAttrBlob
|
|
)) {
|
|
printf("%sAttributes: parse failed\n", pszHdr);
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < cAttr; i++) {
|
|
CHAR rgszOID[MAX_OID_STRING_LEN];
|
|
|
|
EncodedOIDToDot(&rgrgAttrBlob[i][MINASN1_ATTR_OID_IDX], rgszOID);
|
|
printf("%sAttribute[%d] %s:\n", pszHdr, i, rgszOID);
|
|
PrintMultiLineBytes(" ", &rgrgAttrBlob[i][MINASN1_ATTR_VALUE_IDX]);
|
|
}
|
|
}
|