windows-nt/Source/XPSP1/NT/ds/security/cryptoapi/mincrypt/lib/asn1parse.cpp
2020-09-26 16:20:57 +08:00

938 lines
32 KiB
C++

//+-------------------------------------------------------------------------
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 2001 - 2001
//
// File: asn1parse.cpp
//
// Contents: Minimal ASN.1 parse functions.
//
// Functions: MinAsn1ParseCertificate
// MinAsn1ParseAlgorithmIdentifier
// MinAsn1ParsePublicKeyInfo
// MinAsn1ParseRSAPublicKey
// MinAsn1ParseExtensions
// MinAsn1ParseSignedData
// MinAsn1ParseSignedDataCertificates
// MinAsn1ParseAttributes
// MinAsn1ParseCTL
// MinAsn1ParseCTLSubject
// MinAsn1ParseIndirectData
//
// History: 15-Jan-01 philh created
//--------------------------------------------------------------------------
#include "global.hxx"
const BYTE rgbSeqTag[] = {MINASN1_TAG_SEQ, 0};
const BYTE rgbSetTag[] = {MINASN1_TAG_SET, 0};
const BYTE rgbOIDTag[] = {MINASN1_TAG_OID, 0};
const BYTE rgbIntegerTag[] = {MINASN1_TAG_INTEGER, 0};
const BYTE rgbBooleanTag[] = {MINASN1_TAG_BOOLEAN, 0};
const BYTE rgbBitStringTag[] = {MINASN1_TAG_BITSTRING, 0};
const BYTE rgbOctetStringTag[] = {MINASN1_TAG_OCTETSTRING, 0};
const BYTE rgbConstructedContext0Tag[] =
{MINASN1_TAG_CONSTRUCTED_CONTEXT_0, 0};
const BYTE rgbConstructedContext1Tag[] =
{MINASN1_TAG_CONSTRUCTED_CONTEXT_1, 0};
const BYTE rgbConstructedContext3Tag[] =
{MINASN1_TAG_CONSTRUCTED_CONTEXT_3, 0};
const BYTE rgbContext1Tag[] = {MINASN1_TAG_CONTEXT_1, 0};
const BYTE rgbContext2Tag[] = {MINASN1_TAG_CONTEXT_2, 0};
const BYTE rgbChoiceOfTimeTag[] =
{MINASN1_TAG_UTC_TIME, MINASN1_TAG_GENERALIZED_TIME, 0};
const MINASN1_EXTRACT_VALUE_PARA rgParseCertPara[] = {
// 0 - SignedContent ::= SEQUENCE {
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_STEP_INTO_VALUE_OP,
MINASN1_CERT_ENCODED_IDX, rgbSeqTag,
// 0.1 - toBeSigned ::== SEQUENCE {
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_STEP_INTO_VALUE_OP,
MINASN1_CERT_TO_BE_SIGNED_IDX, rgbSeqTag,
// 0.1.0 - version [0] EXPLICIT CertificateVersion DEFAULT v1,
MINASN1_OPTIONAL_STEP_INTO_VALUE_OP, 0, rgbConstructedContext0Tag,
// 0.1.0.0 - version number (INTEGER)
MINASN1_RETURN_CONTENT_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_CERT_VERSION_IDX, rgbIntegerTag,
// 0.1.0.1
MINASN1_STEP_OUT_VALUE_OP, 0, NULL,
// 0.1.1 - serialNumber CertificateSerialNumber,
MINASN1_RETURN_CONTENT_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_CERT_SERIAL_NUMBER_IDX, rgbIntegerTag,
// 0.1.2 - signature AlgorithmIdentifier,
MINASN1_STEP_OVER_VALUE_OP, 0, rgbSeqTag,
// 0.1.3 - issuer NOCOPYANY, -- really Name
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_CERT_ISSUER_IDX, rgbSeqTag,
// 0.1.4 - validity Validity,
MINASN1_STEP_INTO_VALUE_OP, 0, rgbSeqTag,
// 0.1.4.0 - notBefore ChoiceOfTime,
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_CERT_NOT_BEFORE_IDX, rgbChoiceOfTimeTag,
// 0.1.4.1 - notAfter ChoiceOfTime,
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_CERT_NOT_AFTER_IDX, rgbChoiceOfTimeTag,
// 0.1.4.2
MINASN1_STEP_OUT_VALUE_OP, 0, NULL,
// 0.1.5 - subject NOCOPYANY, -- really Name
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_CERT_SUBJECT_IDX, rgbSeqTag,
// 0.1.6 - subjectPublicKeyInfo SubjectPublicKeyInfo,
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_CERT_PUBKEY_INFO_IDX, rgbSeqTag,
// 0.1.7 - issuerUniqueIdentifier [1] IMPLICIT BITSTRING OPTIONAL,
// Note, advanced past the unused bits octet
MINASN1_RETURN_CONTENT_BLOB_FLAG | MINASN1_OPTIONAL_STEP_OVER_VALUE_OP,
MINASN1_CERT_ISSUER_UNIQUE_ID_IDX, rgbContext1Tag,
// 0.1.8 - subjectUniqueIdentifier [2] IMPLICIT BITSTRING OPTIONAL,
// Note, advanced past the unused bits octet
MINASN1_RETURN_CONTENT_BLOB_FLAG | MINASN1_OPTIONAL_STEP_OVER_VALUE_OP,
MINASN1_CERT_SUBJECT_UNIQUE_ID_IDX, rgbContext2Tag,
// 0.1.9 - extensions [3] EXPLICIT Extensions OPTIONAL
MINASN1_RETURN_CONTENT_BLOB_FLAG | MINASN1_OPTIONAL_STEP_OVER_VALUE_OP,
MINASN1_CERT_EXTS_IDX, rgbConstructedContext3Tag,
// 0.1.10
MINASN1_STEP_OUT_VALUE_OP, 0, NULL,
// 0.2 - signatureAlgorithm AlgorithmIdentifier,
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_CERT_SIGN_ALGID_IDX, rgbSeqTag,
// 0.3 - signature BITSTRING
// Note, advanced past the unused bits octet
MINASN1_RETURN_CONTENT_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_CERT_SIGNATURE_IDX, rgbBitStringTag,
};
#define PARSE_CERT_PARA_CNT \
(sizeof(rgParseCertPara) / sizeof(rgParseCertPara[0]))
//+-------------------------------------------------------------------------
// Function: MinAsn1ParseCertificate
//
// Parses an ASN.1 encoded X.509 certificate.
//
// Returns:
// success - > 0 => bytes skipped, length of the encoded certificate
// failure - < 0 => negative (offset + 1) of first bad tagged value
//
// All BITSTRING fields have been advanced past the unused count octet.
//--------------------------------------------------------------------------
LONG
WINAPI
MinAsn1ParseCertificate(
IN const BYTE *pbEncoded,
IN DWORD cbEncoded,
OUT CRYPT_DER_BLOB rgCertBlob[MINASN1_CERT_BLOB_CNT]
)
{
LONG lSkipped;
DWORD cValuePara = PARSE_CERT_PARA_CNT;
lSkipped = MinAsn1ExtractValues(
pbEncoded,
cbEncoded,
&cValuePara,
rgParseCertPara,
MINASN1_CERT_BLOB_CNT,
rgCertBlob
);
if (0 < lSkipped) {
lSkipped = rgCertBlob[MINASN1_CERT_ENCODED_IDX].cbData;
// If present, fixup the ISSUER_UNIQUE_ID and SUBJECT_UNIQUE_ID bit
// fields to advance past the first contents octet containing the
// number of unused bits
if (0 != rgCertBlob[MINASN1_CERT_ISSUER_UNIQUE_ID_IDX].cbData) {
rgCertBlob[MINASN1_CERT_ISSUER_UNIQUE_ID_IDX].pbData += 1;
rgCertBlob[MINASN1_CERT_ISSUER_UNIQUE_ID_IDX].cbData -= 1;
}
if (0 != rgCertBlob[MINASN1_CERT_SUBJECT_UNIQUE_ID_IDX].cbData) {
rgCertBlob[MINASN1_CERT_SUBJECT_UNIQUE_ID_IDX].pbData += 1;
rgCertBlob[MINASN1_CERT_SUBJECT_UNIQUE_ID_IDX].cbData -= 1;
}
}
return lSkipped;
}
const MINASN1_EXTRACT_VALUE_PARA rgParseAlgIdPara[] = {
// 0 - AlgorithmIdentifier ::= SEQUENCE {
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_STEP_INTO_VALUE_OP,
MINASN1_ALGID_ENCODED_IDX, rgbSeqTag,
// 0.0 - algorithm ObjectID,
MINASN1_RETURN_CONTENT_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_ALGID_OID_IDX, rgbOIDTag,
// 0.1 parameters ANY OPTIONAL
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_OPTIONAL_STEP_OVER_VALUE_OP,
MINASN1_ALGID_PARA_IDX, NULL,
};
#define PARSE_ALGID_PARA_CNT \
(sizeof(rgParseAlgIdPara) / sizeof(rgParseAlgIdPara[0]))
//+-------------------------------------------------------------------------
// Function: MinAsn1ParseAlgorithmIdentifier
//
// Parses an ASN.1 encoded Algorithm Identifier contained in numerous
// other ASN.1 structures, such as, X.509 certificate and PKCS #7 Signed Data
// message.
//
// Returns:
// success - > 0 => bytes skipped, length of the encoded algorithm
// identifier
// failure - < 0 => negative (offset + 1) of first bad tagged value
//--------------------------------------------------------------------------
LONG
WINAPI
MinAsn1ParseAlgorithmIdentifier(
IN PCRYPT_DER_BLOB pAlgIdValueBlob,
OUT CRYPT_DER_BLOB rgAlgIdBlob[MINASN1_ALGID_BLOB_CNT]
)
{
LONG lSkipped;
DWORD cValuePara = PARSE_ALGID_PARA_CNT;
lSkipped = MinAsn1ExtractValues(
pAlgIdValueBlob->pbData,
pAlgIdValueBlob->cbData,
&cValuePara,
rgParseAlgIdPara,
MINASN1_ALGID_BLOB_CNT,
rgAlgIdBlob
);
if (0 < lSkipped)
lSkipped = rgAlgIdBlob[MINASN1_ALGID_ENCODED_IDX].cbData;
return lSkipped;
}
const MINASN1_EXTRACT_VALUE_PARA rgParsePubKeyInfoPara[] = {
// 0 - PublicKeyInfo ::= SEQUENCE {
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_STEP_INTO_VALUE_OP,
MINASN1_PUBKEY_INFO_ENCODED_IDX, rgbSeqTag,
// 0.0 - algorithm AlgorithmIdentifier,
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_PUBKEY_INFO_ALGID_IDX, rgbSeqTag,
// 0.1 - PublicKey BITSTRING
MINASN1_RETURN_CONTENT_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_PUBKEY_INFO_PUBKEY_IDX, rgbBitStringTag,
};
#define PARSE_PUBKEY_INFO_PARA_CNT \
(sizeof(rgParsePubKeyInfoPara) / sizeof(rgParsePubKeyInfoPara[0]))
//+-------------------------------------------------------------------------
// Function: MinAsn1ParsePublicKeyInfo
//
// Parses an ASN.1 encoded Public Key Info structure contained in an
// X.509 certificate
//
// Returns:
// success - > 0 => bytes skipped, length of the encoded public key
// info
// failure - < 0 => negative (offset + 1) of first bad tagged value
//
// All BITSTRING fields have been advanced past the unused count octet.
//--------------------------------------------------------------------------
LONG
WINAPI
MinAsn1ParsePublicKeyInfo(
IN PCRYPT_DER_BLOB pPubKeyInfoValueBlob,
CRYPT_DER_BLOB rgPubKeyInfoBlob[MINASN1_PUBKEY_INFO_BLOB_CNT]
)
{
LONG lSkipped;
DWORD cValuePara = PARSE_PUBKEY_INFO_PARA_CNT;
lSkipped = MinAsn1ExtractValues(
pPubKeyInfoValueBlob->pbData,
pPubKeyInfoValueBlob->cbData,
&cValuePara,
rgParsePubKeyInfoPara,
MINASN1_PUBKEY_INFO_BLOB_CNT,
rgPubKeyInfoBlob
);
if (0 < lSkipped)
lSkipped = rgPubKeyInfoBlob[MINASN1_PUBKEY_INFO_ENCODED_IDX].cbData;
return lSkipped;
}
const MINASN1_EXTRACT_VALUE_PARA rgParseRSAPubKeyPara[] = {
// 0 - RSAPublicKey ::= SEQUENCE {
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_STEP_INTO_VALUE_OP,
MINASN1_RSA_PUBKEY_ENCODED_IDX, rgbSeqTag,
// 0.0 - modulus HUGEINTEGER, -- n
MINASN1_RETURN_CONTENT_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_RSA_PUBKEY_MODULUS_IDX, rgbIntegerTag,
// 0.1 - publicExponent INTEGER (0..4294967295) -- e
MINASN1_RETURN_CONTENT_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_RSA_PUBKEY_EXPONENT_IDX, rgbIntegerTag,
};
#define PARSE_RSA_PUBKEY_PARA_CNT \
(sizeof(rgParseRSAPubKeyPara) / sizeof(rgParseRSAPubKeyPara[0]))
//+-------------------------------------------------------------------------
// Function: MinAsn1ParseRSAPublicKey
//
// Parses an ASN.1 encoded RSA PKCS #1 Public Key contained in the contents of
// Public Key BITSTRING in a X.509 certificate.
//
// Returns:
// success - > 0 => bytes skipped, length of the encoded RSA public key
// failure - < 0 => negative (offset + 1) of first bad tagged value
//--------------------------------------------------------------------------
LONG
WINAPI
MinAsn1ParseRSAPublicKey(
IN PCRYPT_DER_BLOB pPubKeyContentBlob,
CRYPT_DER_BLOB rgRSAPubKeyBlob[MINASN1_RSA_PUBKEY_BLOB_CNT]
)
{
LONG lSkipped;
DWORD cValuePara = PARSE_RSA_PUBKEY_PARA_CNT;
lSkipped = MinAsn1ExtractValues(
pPubKeyContentBlob->pbData,
pPubKeyContentBlob->cbData,
&cValuePara,
rgParseRSAPubKeyPara,
MINASN1_RSA_PUBKEY_BLOB_CNT,
rgRSAPubKeyBlob
);
if (0 < lSkipped)
lSkipped = rgRSAPubKeyBlob[MINASN1_RSA_PUBKEY_ENCODED_IDX].cbData;
return lSkipped;
}
const MINASN1_EXTRACT_VALUE_PARA rgParseExtPara[] = {
// 0 - Extension ::= SEQUENCE {
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_STEP_INTO_VALUE_OP,
MINASN1_EXT_ENCODED_IDX, rgbSeqTag,
// 0.0 - extnId EncodedObjectID,
MINASN1_RETURN_CONTENT_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_EXT_OID_IDX, rgbOIDTag,
// 0.1 - critical BOOLEAN DEFAULT FALSE,
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_OPTIONAL_STEP_OVER_VALUE_OP,
MINASN1_EXT_CRITICAL_IDX, rgbBooleanTag,
// 0.2 - extnValue OCTETSTRING
MINASN1_RETURN_CONTENT_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_EXT_VALUE_IDX, rgbOctetStringTag,
};
#define PARSE_EXT_PARA_CNT \
(sizeof(rgParseExtPara) / sizeof(rgParseExtPara[0]))
//+-------------------------------------------------------------------------
// Function: MinAsn1ParseExtensions
//
// Parses an ASN.1 encoded sequence of extensions contained in
// other ASN.1 structures, such as, X.509 certificate and CTL.
//
// Upon input, *pcExt contains the maximum number of parsed extensions
// that can be returned. Updated with the number of extensions processed.
//
// Returns:
// success - >= 0 => bytes skipped, length of the encoded extensions
// processed. If all extensions were processed,
// bytes skipped = pExtsValueBlob->cbData.
// failure - < 0 => negative (offset + 1) of first bad tagged value
//--------------------------------------------------------------------------
LONG
WINAPI
MinAsn1ParseExtensions(
IN PCRYPT_DER_BLOB pExtsValueBlob, // Extensions ::= SEQUENCE OF Extension
IN OUT DWORD *pcExt,
OUT CRYPT_DER_BLOB rgrgExtBlob[][MINASN1_EXT_BLOB_CNT]
)
{
const BYTE *pbEncoded = (const BYTE *) pExtsValueBlob->pbData;
DWORD cbEncoded = pExtsValueBlob->cbData;
DWORD cExt = *pcExt;
DWORD iExt = 0;
LONG lAllExts = 0;
const BYTE *pb;
DWORD cb;
if (0 == cbEncoded)
// No extensions
goto CommonReturn;
// Step into the SEQUENCE
if (0 >= MinAsn1ExtractContent(
pbEncoded,
cbEncoded,
&cb,
&pb
)) {
lAllExts = -1;
goto CommonReturn;
}
for (iExt = 0; 0 < cb && iExt < cExt; iExt++) {
LONG lExt;
DWORD cbExt;
DWORD cValuePara = PARSE_EXT_PARA_CNT;
lExt = MinAsn1ExtractValues(
pb,
cb,
&cValuePara,
rgParseExtPara,
MINASN1_EXT_BLOB_CNT,
rgrgExtBlob[iExt]
);
if (0 >= lExt) {
if (0 == lExt)
lExt = -1;
lAllExts = -((LONG)(pb - pbEncoded)) + lExt;
goto CommonReturn;
}
cbExt = rgrgExtBlob[iExt][MINASN1_EXT_ENCODED_IDX].cbData;
pb += cbExt;
cb -= cbExt;
}
lAllExts = (LONG)(pb - pbEncoded);
assert((DWORD) lAllExts <= cbEncoded);
CommonReturn:
*pcExt = iExt;
return lAllExts;
}
const MINASN1_EXTRACT_VALUE_PARA rgParseSignedDataPara[] = {
// 0 - ContentInfo ::= SEQUENCE {
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_STEP_INTO_VALUE_OP,
MINASN1_SIGNED_DATA_ENCODED_IDX, rgbSeqTag,
// 0.0 - contentType ContentType,
MINASN1_RETURN_CONTENT_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_SIGNED_DATA_OUTER_OID_IDX, rgbOIDTag,
// 0.1 - content [0] EXPLICIT ANY -- OPTIONAL
MINASN1_STEP_INTO_VALUE_OP, 0, rgbConstructedContext0Tag,
// 0.1.0 - SignedData ::= SEQUENCE {
MINASN1_STEP_INTO_VALUE_OP, 0, rgbSeqTag,
// 0.1.0.0 - version INTEGER,
MINASN1_RETURN_CONTENT_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_SIGNED_DATA_VERSION_IDX, rgbIntegerTag,
// 0.1.0.1 - digestAlgorithms DigestAlgorithmIdentifiers,
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_SIGNED_DATA_DIGEST_ALGIDS_IDX, rgbSetTag,
// 0.1.0.2 - ContentInfo ::= SEQUENCE {
MINASN1_STEP_INTO_VALUE_OP, 0, rgbSeqTag,
// 0.1.0.2.0 - contentType ContentType,
MINASN1_RETURN_CONTENT_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_SIGNED_DATA_CONTENT_OID_IDX, rgbOIDTag,
// 0.1.0.2.1 - content [0] EXPLICIT ANY -- OPTIONAL
MINASN1_RETURN_CONTENT_BLOB_FLAG | MINASN1_OPTIONAL_STEP_OVER_VALUE_OP,
MINASN1_SIGNED_DATA_CONTENT_DATA_IDX, rgbConstructedContext0Tag,
// 0.1.0.2.2
MINASN1_STEP_OUT_VALUE_OP, 0, NULL,
// 0.1.0.3 - certificates [0] IMPLICIT Certificates OPTIONAL,
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_OPTIONAL_STEP_OVER_VALUE_OP,
MINASN1_SIGNED_DATA_CERTS_IDX, rgbConstructedContext0Tag,
// 0.1.0.4 - crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_OPTIONAL_STEP_OVER_VALUE_OP,
MINASN1_SIGNED_DATA_CRLS_IDX, rgbConstructedContext1Tag,
// 0.1.0.5 - signerInfos :: = SET OF
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_STEP_INTO_VALUE_OP,
MINASN1_SIGNED_DATA_SIGNER_INFOS_IDX, rgbSetTag,
// 0.1.0.5.0 - SignerInfo ::= SEQUENCE {
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_OPTIONAL_STEP_INTO_VALUE_OP,
MINASN1_SIGNED_DATA_SIGNER_INFO_ENCODED_IDX, rgbSeqTag,
// 0.1.0.5.0.0 - version INTEGER,
MINASN1_RETURN_CONTENT_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_SIGNED_DATA_SIGNER_INFO_VERSION_IDX, rgbIntegerTag,
// 0.1.0.5.0.1 - issuerAndSerialNumber IssuerAndSerialNumber
MINASN1_STEP_INTO_VALUE_OP, 0, rgbSeqTag,
// 0.1.0.5.0.1.0 - issuer ANY,
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_SIGNED_DATA_SIGNER_INFO_ISSUER_IDX, rgbSeqTag,
// 0.1.0.5.0.1.1 - serialNumber INTEGER
MINASN1_RETURN_CONTENT_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_SIGNED_DATA_SIGNER_INFO_SERIAL_NUMBER_IDX, rgbIntegerTag,
// 0.1.0.5.0.1.2
MINASN1_STEP_OUT_VALUE_OP, 0, NULL,
// 0.1.0.5.0.2 - digestAlgorithm DigestAlgorithmIdentifier,
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_SIGNED_DATA_SIGNER_INFO_DIGEST_ALGID_IDX, rgbSeqTag,
// 0.1.0.5.0.3 - authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL,
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_OPTIONAL_STEP_OVER_VALUE_OP,
MINASN1_SIGNED_DATA_SIGNER_INFO_AUTH_ATTRS_IDX, rgbConstructedContext0Tag,
// 0.1.0.5.0.4 - digestEncryptionAlgorithm DigestEncryptionAlgId,
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_SIGNED_DATA_SIGNER_INFO_ENCRYPT_DIGEST_ALGID_IDX, rgbSeqTag,
// 0.1.0.5.0.5 - encryptedDigest EncryptedDigest,
MINASN1_RETURN_CONTENT_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_SIGNED_DATA_SIGNER_INFO_ENCYRPT_DIGEST_IDX, rgbOctetStringTag,
// 0.1.0.5.0.6 - unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_OPTIONAL_STEP_OVER_VALUE_OP,
MINASN1_SIGNED_DATA_SIGNER_INFO_UNAUTH_ATTRS_IDX, rgbConstructedContext1Tag,
};
#define PARSE_SIGNED_DATA_PARA_CNT \
(sizeof(rgParseSignedDataPara) / sizeof(rgParseSignedDataPara[0]))
//+-------------------------------------------------------------------------
// Function: MinAsn1ParseSignedData
//
// Parses an ASN.1 encoded PKCS #7 Signed Data Message. Assumes the
// PKCS #7 message is definite length encoded. Assumes PKCS #7 version
// 1.5, ie, not the newer CMS version.
//
// Returns:
// success - > 0 => bytes skipped, length of the encoded message
// failure - < 0 => negative (offset + 1) of first bad tagged value
//--------------------------------------------------------------------------
LONG
WINAPI
MinAsn1ParseSignedData(
IN const BYTE *pbEncoded,
IN DWORD cbEncoded,
OUT CRYPT_DER_BLOB rgSignedDataBlob[MINASN1_SIGNED_DATA_BLOB_CNT]
)
{
LONG lSkipped;
DWORD cValuePara = PARSE_SIGNED_DATA_PARA_CNT;
lSkipped = MinAsn1ExtractValues(
pbEncoded,
cbEncoded,
&cValuePara,
rgParseSignedDataPara,
MINASN1_SIGNED_DATA_BLOB_CNT,
rgSignedDataBlob
);
if (0 < lSkipped)
lSkipped = rgSignedDataBlob[MINASN1_SIGNED_DATA_ENCODED_IDX].cbData;
return lSkipped;
}
//+-------------------------------------------------------------------------
// Function: MinAsn1ParseSignedDataCertificates
//
// Parses an ASN.1 encoded set of certificates contained in
// a Signed Data message.
//
// Upon input, *pcCert contains the maximum number of parsed certificates
// that can be returned. Updated with the number of certificates processed.
//
// Returns:
// success - >= 0 => bytes skipped, length of the encoded certificates
// processed. If all certificates were processed,
// bytes skipped = pCertsValueBlob->cbData.
// failure - < 0 => negative (offset + 1) of first bad tagged value
//
// The rgrgCertBlob[][] is updated with pointer to and length of the
// fields in the encoded certificate. See MinAsn1ParseCertificate for the
// field definitions.
//--------------------------------------------------------------------------
LONG
WINAPI
MinAsn1ParseSignedDataCertificates(
IN PCRYPT_DER_BLOB pCertsValueBlob,
IN OUT DWORD *pcCert,
OUT CRYPT_DER_BLOB rgrgCertBlob[][MINASN1_CERT_BLOB_CNT]
)
{
const BYTE *pbEncoded = (const BYTE *) pCertsValueBlob->pbData;
DWORD cbEncoded = pCertsValueBlob->cbData;
DWORD cCert = *pcCert;
DWORD iCert = 0;
LONG lAllCerts = 0;
const BYTE *pb;
DWORD cb;
if (0 == cbEncoded)
// No certificates
goto CommonReturn;
// Skip outer tag and length
if (0 >= MinAsn1ExtractContent(
pbEncoded,
cbEncoded,
&cb,
&pb
)) {
lAllCerts = -1;
goto CommonReturn;
}
for (iCert = 0; 0 < cb && iCert < cCert; iCert++) {
LONG lCert;
lCert = MinAsn1ParseCertificate(
pb,
cb,
rgrgCertBlob[iCert]
);
if (0 >= lCert) {
if (0 == lCert)
lCert = -1;
lAllCerts = -((LONG)(pb - pbEncoded)) + lCert;
goto CommonReturn;
}
pb += lCert;
cb -= lCert;
}
lAllCerts = (LONG)(pb - pbEncoded);
assert((DWORD) lAllCerts <= cbEncoded);
CommonReturn:
*pcCert = iCert;
return lAllCerts;
}
const MINASN1_EXTRACT_VALUE_PARA rgParseAttrPara[] = {
// 0 - Attribute ::= SEQUENCE {
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_STEP_INTO_VALUE_OP,
MINASN1_ATTR_ENCODED_IDX, rgbSeqTag,
// 0.0 - attributeType ObjectID,
MINASN1_RETURN_CONTENT_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_ATTR_OID_IDX, rgbOIDTag,
// 0.1 - attributeValue SET OF
MINASN1_RETURN_CONTENT_BLOB_FLAG | MINASN1_STEP_INTO_VALUE_OP,
MINASN1_ATTR_VALUES_IDX, rgbSetTag,
// 0.1.0 - Value ANY -- OPTIONAL
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_OPTIONAL_STEP_OVER_VALUE_OP,
MINASN1_ATTR_VALUE_IDX, NULL,
};
#define PARSE_ATTR_PARA_CNT \
(sizeof(rgParseAttrPara) / sizeof(rgParseAttrPara[0]))
//+-------------------------------------------------------------------------
// Function: MinAsn1ParseAttributes
//
// Parses an ASN.1 encoded sequence of attributes contained in
// other ASN.1 structures, such as, Signer Info authenticated or
// unauthenticated attributes.
//
// The outer tag is ignored. It can be a SET, [0] IMPLICIT, or [1] IMPLICIT.
//
// Upon input, *pcAttr contains the maximum number of parsed attributes
// that can be returned. Updated with the number of attributes processed.
//
// Returns:
// success - >= 0 => bytes skipped, length of the encoded attributes
// processed. If all attributes were processed,
// bytes skipped = pAttrsValueBlob->cbData.
// failure - < 0 => negative (offset + 1) of first bad tagged value
//--------------------------------------------------------------------------
LONG
WINAPI
MinAsn1ParseAttributes(
IN PCRYPT_DER_BLOB pAttrsValueBlob,
IN OUT DWORD *pcAttr,
OUT CRYPT_DER_BLOB rgrgAttrBlob[][MINASN1_ATTR_BLOB_CNT]
)
{
const BYTE *pbEncoded = (const BYTE *) pAttrsValueBlob->pbData;
DWORD cbEncoded = pAttrsValueBlob->cbData;
DWORD cAttr = *pcAttr;
DWORD iAttr = 0;
LONG lAllAttrs = 0;
const BYTE *pb;
DWORD cb;
if (0 == cbEncoded)
// No attributes
goto CommonReturn;
// Skip the outer tag and length
if (0 >= MinAsn1ExtractContent(
pbEncoded,
cbEncoded,
&cb,
&pb
)) {
lAllAttrs = -1;
goto CommonReturn;
}
for (iAttr = 0; 0 < cb && iAttr < cAttr; iAttr++) {
LONG lAttr;
DWORD cbAttr;
DWORD cValuePara = PARSE_ATTR_PARA_CNT;
lAttr = MinAsn1ExtractValues(
pb,
cb,
&cValuePara,
rgParseAttrPara,
MINASN1_ATTR_BLOB_CNT,
rgrgAttrBlob[iAttr]
);
if (0 >= lAttr) {
if (0 == lAttr)
lAttr = -1;
lAllAttrs = -((LONG)(pb - pbEncoded)) + lAttr;
goto CommonReturn;
}
cbAttr = rgrgAttrBlob[iAttr][MINASN1_ATTR_ENCODED_IDX].cbData;
pb += cbAttr;
cb -= cbAttr;
}
lAllAttrs = (LONG)(pb - pbEncoded);
assert((DWORD) lAllAttrs <= cbEncoded);
CommonReturn:
*pcAttr = iAttr;
return lAllAttrs;
}
const MINASN1_EXTRACT_VALUE_PARA rgParseCTLPara[] = {
// 0 - CertificateTrustList ::= SEQUENCE {
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_STEP_INTO_VALUE_OP,
MINASN1_CTL_ENCODED_IDX, rgbSeqTag,
// 0.0 - version CTLVersion DEFAULT v1,
MINASN1_RETURN_CONTENT_BLOB_FLAG | MINASN1_OPTIONAL_STEP_OVER_VALUE_OP,
MINASN1_CTL_VERSION_IDX, rgbIntegerTag,
// 0.1 - subjectUsage SubjectUsage,
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_CTL_SUBJECT_USAGE_IDX, rgbSeqTag,
// 0.2 - listIdentifier ListIdentifier OPTIONAL,
MINASN1_RETURN_CONTENT_BLOB_FLAG | MINASN1_OPTIONAL_STEP_OVER_VALUE_OP,
MINASN1_CTL_LIST_ID_IDX, rgbOctetStringTag,
// 0.3 - sequenceNumber HUGEINTEGER OPTIONAL,
MINASN1_RETURN_CONTENT_BLOB_FLAG | MINASN1_OPTIONAL_STEP_OVER_VALUE_OP,
MINASN1_CTL_SEQUENCE_NUMBER_IDX, rgbIntegerTag,
// 0.4 - ctlThisUpdate ChoiceOfTime,
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_CTL_THIS_UPDATE_IDX, rgbChoiceOfTimeTag,
// 0.5 - ctlNextUpdate ChoiceOfTime OPTIONAL,
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_OPTIONAL_STEP_OVER_VALUE_OP,
MINASN1_CTL_NEXT_UPDATE_IDX, rgbChoiceOfTimeTag,
// 0.6 - subjectAlgorithm AlgorithmIdentifier,
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_CTL_SUBJECT_ALGID_IDX, rgbSeqTag,
// 0.7 - trustedSubjects TrustedSubjects OPTIONAL,
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_OPTIONAL_STEP_OVER_VALUE_OP,
MINASN1_CTL_SUBJECTS_IDX, rgbSeqTag,
// 0.8 - ctlExtensions [0] EXPLICIT Extensions OPTIONAL
MINASN1_RETURN_CONTENT_BLOB_FLAG | MINASN1_OPTIONAL_STEP_OVER_VALUE_OP,
MINASN1_CTL_EXTS_IDX, rgbConstructedContext0Tag,
};
#define PARSE_CTL_PARA_CNT \
(sizeof(rgParseCTLPara) / sizeof(rgParseCTLPara[0]))
//+-------------------------------------------------------------------------
// Function: MinAsn1ParseCTL
//
// Parses an ASN.1 encoded Certificate Trust List (CTL). A CTL is always
// contained as the inner content data in a PKCS #7 Signed Data. A CTL has
// the following OID: "1.3.6.1.4.1.311.10.1".
//
// A catalog file is formatted as a PKCS #7 Signed CTL.
//
// Returns:
// success - > 0 => bytes skipped, length of the encoded CTL
// failure - < 0 => negative (offset + 1) of first bad tagged value
//--------------------------------------------------------------------------
LONG
WINAPI
MinAsn1ParseCTL(
IN PCRYPT_DER_BLOB pEncodedContentBlob,
OUT CRYPT_DER_BLOB rgCTLBlob[MINASN1_CTL_BLOB_CNT]
)
{
LONG lSkipped;
DWORD cValuePara = PARSE_CTL_PARA_CNT;
lSkipped = MinAsn1ExtractValues(
pEncodedContentBlob->pbData,
pEncodedContentBlob->cbData,
&cValuePara,
rgParseCTLPara,
MINASN1_CTL_BLOB_CNT,
rgCTLBlob
);
if (0 < lSkipped)
lSkipped = rgCTLBlob[MINASN1_CTL_ENCODED_IDX].cbData;
return lSkipped;
}
const MINASN1_EXTRACT_VALUE_PARA rgParseCTLSubjectPara[] = {
// 0 - TrustedSubject ::= SEQUENCE {
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_STEP_INTO_VALUE_OP,
MINASN1_CTL_SUBJECT_ENCODED_IDX, rgbSeqTag,
// 0.0 - subjectIdentifier SubjectIdentifier,
MINASN1_RETURN_CONTENT_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_CTL_SUBJECT_ID_IDX, rgbOctetStringTag,
// 0.1 - subjectAttributes Attributes OPTIONAL
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_OPTIONAL_STEP_OVER_VALUE_OP,
MINASN1_CTL_SUBJECT_ATTRS_IDX, rgbSetTag,
};
#define PARSE_CTL_SUBJECT_PARA_CNT \
(sizeof(rgParseCTLSubjectPara) / sizeof(rgParseCTLSubjectPara[0]))
//+-------------------------------------------------------------------------
// Function: MinAsn1ParseCTLSubject
//
// Parses an ASN.1 encoded CTL Subject contained within a CTL's SEQUENCE OF
// Subjects.
//
// Returns:
// success - > 0 => bytes skipped, length of the encoded subject.
// failure - < 0 => negative (offset + 1) of first bad tagged value
//--------------------------------------------------------------------------
LONG
WINAPI
MinAsn1ParseCTLSubject(
IN const BYTE *pbEncoded,
IN DWORD cbEncoded,
OUT CRYPT_DER_BLOB rgCTLSubjectBlob[MINASN1_CTL_SUBJECT_BLOB_CNT]
)
{
LONG lSkipped;
DWORD cValuePara = PARSE_CTL_SUBJECT_PARA_CNT;
lSkipped = MinAsn1ExtractValues(
pbEncoded,
cbEncoded,
&cValuePara,
rgParseCTLSubjectPara,
MINASN1_CTL_SUBJECT_BLOB_CNT,
rgCTLSubjectBlob
);
if (0 < lSkipped)
lSkipped = rgCTLSubjectBlob[MINASN1_CTL_SUBJECT_ENCODED_IDX].cbData;
return lSkipped;
}
const MINASN1_EXTRACT_VALUE_PARA rgParseIndirectDataPara[] = {
// 0 - SpcIndirectDataContent ::= SEQUENCE {
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_STEP_INTO_VALUE_OP,
MINASN1_INDIRECT_DATA_ENCODED_IDX, rgbSeqTag,
// 0.0 - data SpcAttributeTypeAndOptionalValue,
MINASN1_STEP_INTO_VALUE_OP, 0, rgbSeqTag,
// 0.0.0 - type ObjectID,
MINASN1_RETURN_CONTENT_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_INDIRECT_DATA_ATTR_OID_IDX, rgbOIDTag,
// 0.0.1 - value NOCOPYANY OPTIONAL
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_OPTIONAL_STEP_OVER_VALUE_OP,
MINASN1_INDIRECT_DATA_ATTR_VALUE_IDX, NULL,
// 0.0.2
MINASN1_STEP_OUT_VALUE_OP, 0, NULL,
// 0.1 - messageDigest DigestInfo
MINASN1_STEP_INTO_VALUE_OP, 0, rgbSeqTag,
// 0.1.0 - digestAlgorithm AlgorithmIdentifier,
MINASN1_RETURN_VALUE_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_INDIRECT_DATA_DIGEST_ALGID_IDX, rgbSeqTag,
// 0.1.1 - digest OCTETSTRING
MINASN1_RETURN_CONTENT_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
MINASN1_INDIRECT_DATA_DIGEST_IDX, rgbOctetStringTag,
};
#define PARSE_INDIRECT_DATA_PARA_CNT \
(sizeof(rgParseIndirectDataPara) / sizeof(rgParseIndirectDataPara[0]))
//+-------------------------------------------------------------------------
// Function: MinAsn1ParseIndirectData
//
// Parses an ASN.1 encoded Indirect Data. Indirect Data is always
// contained as the inner content data in a PKCS #7 Signed Data. It has
// the following OID: "1.3.6.1.4.1.311.2.1.4"
//
// An Authenticode signed file contains a PKCS #7 Signed Indirect Data.
//
// Returns:
// success - > 0 => bytes skipped, length of the encoded Indirect Data
// failure - < 0 => negative (offset + 1) of first bad tagged value
//--------------------------------------------------------------------------
LONG
WINAPI
MinAsn1ParseIndirectData(
IN PCRYPT_DER_BLOB pEncodedContentBlob,
OUT CRYPT_DER_BLOB rgIndirectDataBlob[MINASN1_INDIRECT_DATA_BLOB_CNT]
)
{
LONG lSkipped;
DWORD cValuePara = PARSE_INDIRECT_DATA_PARA_CNT;
lSkipped = MinAsn1ExtractValues(
pEncodedContentBlob->pbData,
pEncodedContentBlob->cbData,
&cValuePara,
rgParseIndirectDataPara,
MINASN1_INDIRECT_DATA_BLOB_CNT,
rgIndirectDataBlob
);
if (0 < lSkipped)
lSkipped = rgIndirectDataBlob[MINASN1_INDIRECT_DATA_ENCODED_IDX].cbData;
return lSkipped;
}