mirror of https://github.com/tongzx/nt5src
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.
580 lines
16 KiB
580 lines
16 KiB
//+-------------------------------------------------------------------------
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 2001 - 2001
|
|
//
|
|
// File: verhash.cpp
|
|
//
|
|
// Contents: Minimal Cryptographic functions to verify ASN.1 encoded
|
|
// signed hashes. Signed hashes are used in X.509 certificates
|
|
// and PKCS #7 signed data.
|
|
//
|
|
// Also contains md5 or sha1 memory hash function.
|
|
//
|
|
//
|
|
// Functions: MinCryptDecodeHashAlgorithmIdentifier
|
|
// MinCryptHashMemory
|
|
// MinCryptVerifySignedHash
|
|
//
|
|
// History: 17-Jan-01 philh created
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include "global.hxx"
|
|
#include <md5.h>
|
|
#include <md2.h>
|
|
#include <sha.h>
|
|
#include <rsa.h>
|
|
|
|
#define MAX_RSA_PUB_KEY_BIT_LEN 4096
|
|
#define MAX_RSA_PUB_KEY_BYTE_LEN (MAX_RSA_PUB_KEY_BIT_LEN / 8 )
|
|
#define MAX_BSAFE_PUB_KEY_MODULUS_BYTE_LEN \
|
|
(MAX_RSA_PUB_KEY_BYTE_LEN + sizeof(DWORD) * 4)
|
|
|
|
typedef struct _BSAFE_PUB_KEY_CONTENT {
|
|
BSAFE_PUB_KEY Header;
|
|
BYTE rgbModulus[MAX_BSAFE_PUB_KEY_MODULUS_BYTE_LEN];
|
|
} BSAFE_PUB_KEY_CONTENT, *PBSAFE_PUB_KEY_CONTENT;
|
|
|
|
|
|
#ifndef RSA1
|
|
#define RSA1 ((DWORD)'R'+((DWORD)'S'<<8)+((DWORD)'A'<<16)+((DWORD)'1'<<24))
|
|
#endif
|
|
|
|
// from \nt\ds\win32\ntcrypto\scp\nt_sign.c
|
|
|
|
//
|
|
// Reverse ASN.1 Encodings of possible hash identifiers. The leading byte is
|
|
// the length of the remaining byte string.
|
|
//
|
|
|
|
static const BYTE
|
|
*md2Encodings[]
|
|
// 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
|
= { (CONST BYTE *)"\x12\x10\x04\x00\x05\x02\x02\x0d\xf7\x86\x48\x86\x2a\x08\x06\x0c\x30\x20\x30",
|
|
(CONST BYTE *)"\x10\x10\x04\x02\x02\x0d\xf7\x86\x48\x86\x2a\x08\x06\x0a\x30\x1e\x30",
|
|
(CONST BYTE *)"\x00" },
|
|
|
|
*md5Encodings[]
|
|
= { (CONST BYTE *)"\x12\x10\x04\x00\x05\x05\x02\x0d\xf7\x86\x48\x86\x2a\x08\x06\x0c\x30\x20\x30",
|
|
(CONST BYTE *)"\x10\x10\x04\x05\x02\x0d\xf7\x86\x48\x86\x2a\x08\x06\x0a\x30\x1e\x30",
|
|
(CONST BYTE *)"\x00" },
|
|
|
|
*shaEncodings[]
|
|
= { (CONST BYTE *)"\x0f\x14\x04\x00\x05\x1a\x02\x03\x0e\x2b\x05\x06\x09\x30\x21\x30",
|
|
(CONST BYTE *)"\x0d\x14\x04\x1a\x02\x03\x0e\x2b\x05\x06\x07\x30\x1f\x30",
|
|
(CONST BYTE *)"\x00"};
|
|
|
|
|
|
|
|
typedef struct _ENCODED_OID_INFO {
|
|
DWORD cbEncodedOID;
|
|
const BYTE *pbEncodedOID;
|
|
ALG_ID AlgId;
|
|
} ENCODED_OID_INFO, *PENCODED_OID_INFO;
|
|
|
|
//
|
|
// SHA1/MD5/MD2 HASH OIDS
|
|
//
|
|
|
|
// #define szOID_OIWSEC_sha1 "1.3.14.3.2.26"
|
|
const BYTE rgbOIWSEC_sha1[] =
|
|
{0x2B, 0x0E, 0x03, 0x02, 0x1A};
|
|
|
|
// #define szOID_OIWSEC_sha "1.3.14.3.2.18"
|
|
const BYTE rgbOID_OIWSEC_sha[] =
|
|
{0x2B, 0x0E, 0x03, 0x02, 0x12};
|
|
|
|
// #define szOID_RSA_MD5 "1.2.840.113549.2.5"
|
|
const BYTE rgbOID_RSA_MD5[] =
|
|
{0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05};
|
|
|
|
// #define szOID_RSA_MD2 "1.2.840.113549.2.2"
|
|
const BYTE rgbOID_RSA_MD2[] =
|
|
{0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x02};
|
|
|
|
//
|
|
// RSA SHA1/MD5/MD2 SIGNATURE OIDS
|
|
//
|
|
|
|
// #define szOID_RSA_SHA1RSA "1.2.840.113549.1.1.5"
|
|
const BYTE rgbOID_RSA_SHA1RSA[] =
|
|
{0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05};
|
|
|
|
// #define szOID_RSA_MD5RSA "1.2.840.113549.1.1.4"
|
|
const BYTE rgbOID_RSA_MD5RSA[] =
|
|
{0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04};
|
|
|
|
// #define szOID_OIWSEC_sha1RSASign "1.3.14.3.2.29"
|
|
const BYTE rgbOID_OIWSEC_sha1RSASign[] =
|
|
{0x2B, 0x0E, 0x03, 0x02, 0x1D};
|
|
|
|
// #define szOID_OIWSEC_shaRSA "1.3.14.3.2.15"
|
|
const BYTE rgbOID_OIWSEC_shaRSA[] =
|
|
{0x2B, 0x0E, 0x03, 0x02, 0x0F};
|
|
|
|
// #define szOID_OIWSEC_md5RSA "1.3.14.3.2.3"
|
|
const BYTE rgbOID_OIWSEC_md5RSA[] =
|
|
{0x2B, 0x0E, 0x03, 0x02, 0x03};
|
|
|
|
// #define szOID_RSA_MD2RSA "1.2.840.113549.1.1.2"
|
|
const BYTE rgbOID_RSA_MD2RSA[] =
|
|
{0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x02};
|
|
|
|
// #define szOID_OIWDIR_md2RSA "1.3.14.7.2.3.1"
|
|
const BYTE rgbOID_OIWDIR_md2RSA[] =
|
|
{0x2B, 0x0E, 0x07, 0x02, 0x03, 0x01};
|
|
|
|
|
|
const ENCODED_OID_INFO HashAlgTable[] = {
|
|
// Hash OIDs
|
|
sizeof(rgbOIWSEC_sha1), rgbOIWSEC_sha1, CALG_SHA1,
|
|
sizeof(rgbOID_OIWSEC_sha), rgbOID_OIWSEC_sha, CALG_SHA1,
|
|
sizeof(rgbOID_RSA_MD5), rgbOID_RSA_MD5, CALG_MD5,
|
|
sizeof(rgbOID_RSA_MD2), rgbOID_RSA_MD2, CALG_MD2,
|
|
|
|
// Signature OIDs
|
|
sizeof(rgbOID_RSA_SHA1RSA), rgbOID_RSA_SHA1RSA, CALG_SHA1,
|
|
sizeof(rgbOID_RSA_MD5RSA), rgbOID_RSA_MD5RSA, CALG_MD5,
|
|
sizeof(rgbOID_OIWSEC_sha1RSASign), rgbOID_OIWSEC_sha1RSASign, CALG_SHA1,
|
|
sizeof(rgbOID_OIWSEC_shaRSA), rgbOID_OIWSEC_shaRSA, CALG_SHA1,
|
|
sizeof(rgbOID_OIWSEC_md5RSA), rgbOID_OIWSEC_md5RSA, CALG_MD5,
|
|
sizeof(rgbOID_RSA_MD2RSA), rgbOID_RSA_MD2RSA, CALG_MD2,
|
|
sizeof(rgbOID_OIWDIR_md2RSA), rgbOID_OIWDIR_md2RSA, CALG_MD2,
|
|
};
|
|
#define HASH_ALG_CNT (sizeof(HashAlgTable) / sizeof(HashAlgTable[0]))
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Decodes an ASN.1 encoded Algorithm Identifier and converts to
|
|
// a CAPI Hash AlgID, such as, CALG_SHA1 or CALG_MD5.
|
|
//
|
|
// Returns 0 if there isn't a CAPI AlgId corresponding to the Algorithm
|
|
// Identifier.
|
|
//
|
|
// Only CALG_SHA1, CALG_MD5 and CALG_MD2 are supported.
|
|
//--------------------------------------------------------------------------
|
|
ALG_ID
|
|
WINAPI
|
|
MinCryptDecodeHashAlgorithmIdentifier(
|
|
IN PCRYPT_DER_BLOB pAlgIdValueBlob
|
|
)
|
|
{
|
|
ALG_ID HashAlgId = 0;
|
|
LONG lSkipped;
|
|
CRYPT_DER_BLOB rgAlgIdBlob[MINASN1_ALGID_BLOB_CNT];
|
|
DWORD cbEncodedOID;
|
|
const BYTE *pbEncodedOID;
|
|
DWORD i;
|
|
|
|
lSkipped = MinAsn1ParseAlgorithmIdentifier(
|
|
pAlgIdValueBlob,
|
|
rgAlgIdBlob
|
|
);
|
|
if (0 >= lSkipped)
|
|
goto CommonReturn;
|
|
|
|
cbEncodedOID = rgAlgIdBlob[MINASN1_ALGID_OID_IDX].cbData;
|
|
pbEncodedOID = rgAlgIdBlob[MINASN1_ALGID_OID_IDX].pbData;
|
|
|
|
for (i = 0; i < HASH_ALG_CNT; i++) {
|
|
if (cbEncodedOID == HashAlgTable[i].cbEncodedOID &&
|
|
0 == memcmp(pbEncodedOID, HashAlgTable[i].pbEncodedOID,
|
|
cbEncodedOID)) {
|
|
HashAlgId = HashAlgTable[i].AlgId;
|
|
break;
|
|
}
|
|
}
|
|
|
|
CommonReturn:
|
|
return HashAlgId;
|
|
}
|
|
|
|
|
|
#pragma warning (push)
|
|
// local variable 'Md5Ctx' may be used without having been initialized
|
|
#pragma warning (disable: 4701)
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Hashes one or more memory blobs according to the Hash ALG_ID.
|
|
//
|
|
// rgbHash is updated with the resultant hash. *pcbHash is updated with
|
|
// the length associated with the hash algorithm.
|
|
//
|
|
// If the function succeeds, the return value is ERROR_SUCCESS. Otherwise,
|
|
// a nonzero error code is returned.
|
|
//
|
|
// Only CALG_SHA1, CALG_MD5 and CALG_MD2 are supported.
|
|
//--------------------------------------------------------------------------
|
|
LONG
|
|
WINAPI
|
|
MinCryptHashMemory(
|
|
IN ALG_ID HashAlgId,
|
|
IN DWORD cBlob,
|
|
IN PCRYPT_DER_BLOB rgBlob,
|
|
OUT BYTE rgbHash[MINCRYPT_MAX_HASH_LEN],
|
|
OUT DWORD *pcbHash
|
|
)
|
|
{
|
|
A_SHA_CTX ShaCtx;
|
|
MD5_CTX Md5Ctx;
|
|
MD2_CTX Md2Ctx;
|
|
DWORD iBlob;
|
|
|
|
switch (HashAlgId) {
|
|
case CALG_MD2:
|
|
memset(&Md2Ctx, 0, sizeof(Md2Ctx));
|
|
*pcbHash = MINCRYPT_MD2_HASH_LEN;
|
|
break;
|
|
|
|
case CALG_MD5:
|
|
MD5Init(&Md5Ctx);
|
|
*pcbHash = MINCRYPT_MD5_HASH_LEN;
|
|
break;
|
|
|
|
case CALG_SHA1:
|
|
A_SHAInit(&ShaCtx);
|
|
*pcbHash = MINCRYPT_SHA1_HASH_LEN;
|
|
break;
|
|
|
|
default:
|
|
*pcbHash = 0;
|
|
return NTE_BAD_ALGID;
|
|
}
|
|
|
|
for (iBlob = 0; iBlob < cBlob; iBlob++) {
|
|
BYTE *pb = rgBlob[iBlob].pbData;
|
|
DWORD cb = rgBlob[iBlob].cbData;
|
|
|
|
if (0 == cb)
|
|
continue;
|
|
|
|
switch (HashAlgId) {
|
|
case CALG_MD2:
|
|
MD2Update(&Md2Ctx, pb, cb);
|
|
break;
|
|
|
|
case CALG_MD5:
|
|
MD5Update(&Md5Ctx, pb, cb);
|
|
break;
|
|
|
|
case CALG_SHA1:
|
|
A_SHAUpdate(&ShaCtx, pb, cb);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
switch (HashAlgId) {
|
|
case CALG_MD2:
|
|
MD2Final(&Md2Ctx);
|
|
memcpy(rgbHash, Md2Ctx.state, MINCRYPT_MD2_HASH_LEN);
|
|
break;
|
|
|
|
case CALG_MD5:
|
|
MD5Final(&Md5Ctx);
|
|
assert(MD5DIGESTLEN == MINCRYPT_MD5_HASH_LEN);
|
|
memcpy(rgbHash, Md5Ctx.digest, MD5DIGESTLEN);
|
|
break;
|
|
|
|
case CALG_SHA1:
|
|
A_SHAFinal(&ShaCtx, rgbHash);
|
|
break;
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
#pragma warning (pop)
|
|
|
|
//+=========================================================================
|
|
// MinCryptVerifySignedHash Support Functions
|
|
//-=========================================================================
|
|
|
|
VOID
|
|
WINAPI
|
|
I_ReverseAndCopyBytes(
|
|
OUT BYTE *pbDst,
|
|
IN const BYTE *pbSrc,
|
|
IN DWORD cb
|
|
)
|
|
{
|
|
if (0 == cb)
|
|
return;
|
|
for (pbDst += cb - 1; cb > 0; cb--)
|
|
*pbDst-- = *pbSrc++;
|
|
}
|
|
|
|
|
|
|
|
// The basis for much of the code in this function can be found in
|
|
// \nt\ds\win32\ntcrypto\scp\nt_key.c
|
|
LONG
|
|
WINAPI
|
|
I_ConvertParsedRSAPubKeyToBSafePubKey(
|
|
IN CRYPT_DER_BLOB rgRSAPubKeyBlob[MINASN1_RSA_PUBKEY_BLOB_CNT],
|
|
OUT PBSAFE_PUB_KEY_CONTENT pBSafePubKeyContent
|
|
)
|
|
{
|
|
LONG lErr;
|
|
DWORD cbModulus;
|
|
const BYTE *pbAsn1Modulus;
|
|
DWORD cbExp;
|
|
const BYTE *pbAsn1Exp;
|
|
DWORD cbTmpLen;
|
|
LPBSAFE_PUB_KEY pBSafePubKey;
|
|
|
|
// Get the ASN.1 public key modulus (BIG ENDIAN). The modulus length
|
|
// is the public key byte length.
|
|
cbModulus = rgRSAPubKeyBlob[MINASN1_RSA_PUBKEY_MODULUS_IDX].cbData;
|
|
pbAsn1Modulus = rgRSAPubKeyBlob[MINASN1_RSA_PUBKEY_MODULUS_IDX].pbData;
|
|
// Strip off a leading 0 byte. Its there in the decoded ASN
|
|
// integer for an unsigned integer with the leading bit set.
|
|
if (cbModulus > 1 && *pbAsn1Modulus == 0) {
|
|
pbAsn1Modulus++;
|
|
cbModulus--;
|
|
}
|
|
if (MAX_RSA_PUB_KEY_BYTE_LEN < cbModulus)
|
|
goto ExceededMaxPubKeyModulusLen;
|
|
|
|
// Get the ASN.1 public exponent (BIG ENDIAN).
|
|
cbExp = rgRSAPubKeyBlob[MINASN1_RSA_PUBKEY_EXPONENT_IDX].cbData;
|
|
pbAsn1Exp = rgRSAPubKeyBlob[MINASN1_RSA_PUBKEY_EXPONENT_IDX].pbData;
|
|
// Strip off a leading 0 byte. Its there in the decoded ASN
|
|
// integer for an unsigned integer with the leading bit set.
|
|
if (cbExp > 1 && *pbAsn1Exp == 0) {
|
|
pbAsn1Exp++;
|
|
cbExp--;
|
|
}
|
|
if (sizeof(DWORD) < cbExp)
|
|
goto ExceededMaxPubKeyExpLen;
|
|
|
|
if (0 == cbModulus || 0 == cbExp)
|
|
goto InvalidPubKey;
|
|
|
|
// Update the BSAFE data structure from the parsed and length validated
|
|
// ASN.1 public key modulus and exponent components.
|
|
|
|
cbTmpLen = (sizeof(DWORD) * 2) - (cbModulus % (sizeof(DWORD) * 2));
|
|
if ((sizeof(DWORD) * 2) != cbTmpLen)
|
|
cbTmpLen += sizeof(DWORD) * 2;
|
|
|
|
memset(pBSafePubKeyContent, 0, sizeof(*pBSafePubKeyContent));
|
|
pBSafePubKey = &pBSafePubKeyContent->Header;
|
|
pBSafePubKey->magic = RSA1;
|
|
pBSafePubKey->keylen = cbModulus + cbTmpLen;
|
|
pBSafePubKey->bitlen = cbModulus * 8;
|
|
pBSafePubKey->datalen = cbModulus - 1;
|
|
|
|
I_ReverseAndCopyBytes((BYTE *) &pBSafePubKey->pubexp, pbAsn1Exp, cbExp);
|
|
I_ReverseAndCopyBytes(pBSafePubKeyContent->rgbModulus, pbAsn1Modulus,
|
|
cbModulus);
|
|
|
|
lErr = ERROR_SUCCESS;
|
|
CommonReturn:
|
|
return lErr;
|
|
|
|
ExceededMaxPubKeyModulusLen:
|
|
ExceededMaxPubKeyExpLen:
|
|
InvalidPubKey:
|
|
lErr = NTE_BAD_PUBLIC_KEY;
|
|
goto CommonReturn;
|
|
}
|
|
|
|
|
|
// The basis for much of the code in this function can be found in
|
|
// \nt\ds\win32\ntcrypto\scp\nt_sign.c
|
|
LONG
|
|
WINAPI
|
|
I_VerifyPKCS1SigningFormat(
|
|
IN BSAFE_PUB_KEY *pKey,
|
|
IN ALG_ID HashAlgId,
|
|
IN BYTE *pbHash,
|
|
IN DWORD cbHash,
|
|
IN BYTE *pbPKCS1Format
|
|
)
|
|
{
|
|
LONG lErr = ERROR_INTERNAL_ERROR;
|
|
const BYTE **rgEncOptions;
|
|
BYTE rgbTmpHash[MINCRYPT_MAX_HASH_LEN];
|
|
DWORD i;
|
|
DWORD cb;
|
|
BYTE *pbStart;
|
|
DWORD cbTmp;
|
|
|
|
switch (HashAlgId)
|
|
{
|
|
case CALG_MD2:
|
|
rgEncOptions = md2Encodings;
|
|
break;
|
|
|
|
case CALG_MD5:
|
|
rgEncOptions = md5Encodings;
|
|
break;
|
|
|
|
case CALG_SHA:
|
|
rgEncOptions = shaEncodings;
|
|
break;
|
|
|
|
default:
|
|
goto UnsupportedHash;
|
|
}
|
|
|
|
// Reverse the hash to match the signature.
|
|
for (i = 0; i < cbHash; i++)
|
|
rgbTmpHash[i] = pbHash[cbHash - (i + 1)];
|
|
|
|
// See if it matches.
|
|
if (0 != memcmp(rgbTmpHash, pbPKCS1Format, cbHash))
|
|
{
|
|
goto BadSignature;
|
|
}
|
|
|
|
cb = cbHash;
|
|
for (i = 0; 0 != *rgEncOptions[i]; i += 1)
|
|
{
|
|
pbStart = (LPBYTE)rgEncOptions[i];
|
|
cbTmp = *pbStart++;
|
|
if (0 == memcmp(&pbPKCS1Format[cb], pbStart, cbTmp))
|
|
{
|
|
cb += cbTmp; // Adjust the end of the hash data.
|
|
break;
|
|
}
|
|
}
|
|
|
|
// check to make sure the rest of the PKCS #1 padding is correct
|
|
if ((0x00 != pbPKCS1Format[cb])
|
|
|| (0x00 != pbPKCS1Format[pKey->datalen])
|
|
|| (0x1 != pbPKCS1Format[pKey->datalen - 1]))
|
|
{
|
|
goto BadSignature;
|
|
}
|
|
|
|
for (i = cb + 1; i < pKey->datalen - 1; i++)
|
|
{
|
|
if (0xff != pbPKCS1Format[i])
|
|
{
|
|
goto BadSignature;
|
|
}
|
|
}
|
|
|
|
lErr = ERROR_SUCCESS;
|
|
|
|
CommonReturn:
|
|
return lErr;
|
|
|
|
UnsupportedHash:
|
|
lErr = NTE_BAD_ALGID;
|
|
goto CommonReturn;
|
|
|
|
BadSignature:
|
|
lErr = NTE_BAD_SIGNATURE;
|
|
goto CommonReturn;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Verifies a signed hash.
|
|
//
|
|
// The ASN.1 encoded Public Key Info is parsed and used to decrypt the
|
|
// signed hash. The decrypted signed hash is compared with the input
|
|
// hash.
|
|
//
|
|
// If the signed hash was successfully verified, ERROR_SUCCESS is returned.
|
|
// Otherwise, a nonzero error code is returned.
|
|
//
|
|
// Only RSA signed hashes are supported.
|
|
//
|
|
// Only MD2, MD5 and SHA1 hashes are supported.
|
|
//--------------------------------------------------------------------------
|
|
LONG
|
|
WINAPI
|
|
MinCryptVerifySignedHash(
|
|
IN ALG_ID HashAlgId,
|
|
IN BYTE *pbHash,
|
|
IN DWORD cbHash,
|
|
IN PCRYPT_DER_BLOB pSignedHashContentBlob,
|
|
IN PCRYPT_DER_BLOB pPubKeyInfoValueBlob
|
|
)
|
|
{
|
|
LONG lErr;
|
|
LONG lSkipped;
|
|
|
|
CRYPT_DER_BLOB rgPubKeyInfoBlob[MINASN1_PUBKEY_INFO_BLOB_CNT];
|
|
CRYPT_DER_BLOB rgRSAPubKeyBlob[MINASN1_RSA_PUBKEY_BLOB_CNT];
|
|
BSAFE_PUB_KEY_CONTENT BSafePubKeyContent;
|
|
LPBSAFE_PUB_KEY pBSafePubKey;
|
|
|
|
DWORD cbSignature;
|
|
const BYTE *pbAsn1Signature;
|
|
|
|
BYTE rgbBSafeIn[MAX_BSAFE_PUB_KEY_MODULUS_BYTE_LEN];
|
|
BYTE rgbBSafeOut[MAX_BSAFE_PUB_KEY_MODULUS_BYTE_LEN];
|
|
|
|
|
|
// Attempt to parse and convert the ASN.1 encoded public key into
|
|
// an RSA BSAFE formatted key.
|
|
lSkipped = MinAsn1ParsePublicKeyInfo(
|
|
pPubKeyInfoValueBlob,
|
|
rgPubKeyInfoBlob
|
|
);
|
|
if (0 >= lSkipped)
|
|
goto ParsePubKeyInfoError;
|
|
|
|
lSkipped = MinAsn1ParseRSAPublicKey(
|
|
&rgPubKeyInfoBlob[MINASN1_PUBKEY_INFO_PUBKEY_IDX],
|
|
rgRSAPubKeyBlob
|
|
);
|
|
if (0 >= lSkipped)
|
|
goto ParseRSAPubKeyError;
|
|
|
|
lErr = I_ConvertParsedRSAPubKeyToBSafePubKey(
|
|
rgRSAPubKeyBlob,
|
|
&BSafePubKeyContent
|
|
);
|
|
if (ERROR_SUCCESS != lErr)
|
|
goto CommonReturn;
|
|
|
|
pBSafePubKey = &BSafePubKeyContent.Header;
|
|
|
|
// Get the ASN.1 signature (BIG ENDIAN).
|
|
//
|
|
// It must be the same length as the public key
|
|
cbSignature = pSignedHashContentBlob->cbData;
|
|
pbAsn1Signature = pSignedHashContentBlob->pbData;
|
|
if (cbSignature != pBSafePubKey->bitlen / 8)
|
|
goto InvalidSignatureLen;
|
|
|
|
// Decrypt the signature (LITTLE ENDIAN)
|
|
assert(sizeof(rgbBSafeIn) >= cbSignature);
|
|
I_ReverseAndCopyBytes(rgbBSafeIn, pbAsn1Signature, cbSignature);
|
|
memset(&rgbBSafeIn[cbSignature], 0, sizeof(rgbBSafeIn) - cbSignature);
|
|
memset(rgbBSafeOut, 0, sizeof(rgbBSafeOut));
|
|
|
|
if (!BSafeEncPublic(pBSafePubKey, rgbBSafeIn, rgbBSafeOut))
|
|
goto BSafeEncPublicError;
|
|
|
|
|
|
lErr = I_VerifyPKCS1SigningFormat(
|
|
pBSafePubKey,
|
|
HashAlgId,
|
|
pbHash,
|
|
cbHash,
|
|
rgbBSafeOut
|
|
);
|
|
|
|
CommonReturn:
|
|
return lErr;
|
|
|
|
ParsePubKeyInfoError:
|
|
ParseRSAPubKeyError:
|
|
lErr = NTE_BAD_PUBLIC_KEY;
|
|
goto CommonReturn;
|
|
|
|
InvalidSignatureLen:
|
|
BSafeEncPublicError:
|
|
lErr = NTE_BAD_SIGNATURE;
|
|
goto CommonReturn;
|
|
}
|
|
|