|
|
//+-------------------------------------------------------------------------
// 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; }
|