Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

1157 lines
34 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1995 - 1999
//
// File: certhlpr.cpp
//
// Contents: import and export of private keys
//
// Functions: ImportExoprtDllMain
// CryptImportPKCS8
// CryptExportPKCS8
//
// History:
//--------------------------------------------------------------------------
#include "global.hxx"
#ifdef __cplusplus
extern "C" {
#endif
#include "prvtkey.h"
#ifdef __cplusplus
} // Balance extern "C" above
#endif
#define INFO_LEN_ALIGN(Len) ((Len + 7) & ~7)
static const BYTE NullDer[2] = {0x05, 0x00};
static const CRYPT_OBJID_BLOB NullDerBlob = {2, (BYTE *)&NullDer[0]};
static HCRYPTASN1MODULE hPrivateKeyAsn1Module;
static HCRYPTOIDFUNCSET hEncodePrivKeyFuncSet;
static HCRYPTOIDFUNCSET hDecodePrivKeyFuncSet;
//+-------------------------------------------------------------------------
// OSS ASN.1 PKCS#8 PrivateKey Encode / Decode functions
//--------------------------------------------------------------------------
static BOOL WINAPI OssRSAPrivateKeyStrucEncode(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN BLOBHEADER *pBlobHeader,
OUT BYTE *pbEncoded,
IN OUT DWORD *pcbEncoded
);
static BOOL WINAPI OssRSAPrivateKeyStrucDecode(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN const BYTE *pbEncoded,
IN DWORD cbEncoded,
IN DWORD dwFlags,
OUT BLOBHEADER *pBlobHeader,
IN OUT DWORD *pcbBlobHeader
);
static BOOL WINAPI OssPrivateKeyInfoEncode(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN PCRYPT_PRIVATE_KEY_INFO pInfo,
OUT BYTE *pbEncoded,
IN OUT DWORD *pcbEncoded
);
static BOOL WINAPI OssPrivateKeyInfoDecode(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN const BYTE *pbEncoded,
IN DWORD cbEncoded,
IN DWORD dwFlags,
OUT PCRYPT_PRIVATE_KEY_INFO pInfo,
IN OUT DWORD *pcbInfo
);
static BOOL WINAPI OssEncryptedPrivateKeyInfoEncode(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN PCRYPT_ENCRYPTED_PRIVATE_KEY_INFO pInfo,
OUT BYTE *pbEncoded,
IN OUT DWORD *pcbEncoded
);
static BOOL WINAPI OssEncryptedPrivateKeyInfoDecode(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN const BYTE *pbEncoded,
IN DWORD cbEncoded,
IN DWORD dwFlags,
OUT PCRYPT_ENCRYPTED_PRIVATE_KEY_INFO pInfo,
IN OUT DWORD *pcbInfo
);
static const CRYPT_OID_FUNC_ENTRY PrivateKeyEncodeFuncTable[] = {
PKCS_RSA_PRIVATE_KEY, OssRSAPrivateKeyStrucEncode,
PKCS_PRIVATE_KEY_INFO, OssPrivateKeyInfoEncode,
PKCS_ENCRYPTED_PRIVATE_KEY_INFO, OssEncryptedPrivateKeyInfoEncode
};
#define PRIVATEKEY_ENCODE_FUNC_COUNT (sizeof(PrivateKeyEncodeFuncTable) / \
sizeof(PrivateKeyEncodeFuncTable[0]))
static const CRYPT_OID_FUNC_ENTRY PrivateKeyDecodeFuncTable[] = {
PKCS_RSA_PRIVATE_KEY, OssRSAPrivateKeyStrucDecode,
PKCS_PRIVATE_KEY_INFO, OssPrivateKeyInfoDecode,
PKCS_ENCRYPTED_PRIVATE_KEY_INFO, OssEncryptedPrivateKeyInfoDecode,
};
#define PRIVATEKEY_DECODE_FUNC_COUNT (sizeof(PrivateKeyDecodeFuncTable) / \
sizeof(PrivateKeyDecodeFuncTable[0]))
BOOL
WINAPI
EncodeDecodeDllMain(
HMODULE hInst,
ULONG ul_reason_for_call,
LPVOID lpReserved)
{
switch( ul_reason_for_call )
{
case DLL_PROCESS_ATTACH:
if (NULL == (hEncodePrivKeyFuncSet = CryptInitOIDFunctionSet(
CRYPT_OID_ENCODE_OBJECT_FUNC,
0)))
goto ErrorReturn;
if (NULL == (hDecodePrivKeyFuncSet = CryptInitOIDFunctionSet(
CRYPT_OID_DECODE_OBJECT_FUNC,
0)))
goto ErrorReturn;
if (!CryptInstallOIDFunctionAddress(
NULL, // hModule
X509_ASN_ENCODING,
CRYPT_OID_ENCODE_OBJECT_FUNC,
PRIVATEKEY_ENCODE_FUNC_COUNT,
PrivateKeyEncodeFuncTable,
0)) // dwFlags
goto ErrorReturn;
if (!CryptInstallOIDFunctionAddress(
NULL, // hModule
X509_ASN_ENCODING,
CRYPT_OID_DECODE_OBJECT_FUNC,
PRIVATEKEY_DECODE_FUNC_COUNT,
PrivateKeyDecodeFuncTable,
0)) // dwFlags
goto ErrorReturn;
#ifdef OSS_CRYPT_ASN1
if (0 == (hPrivateKeyAsn1Module =
I_CryptInstallAsn1Module(prvtkey, 0, NULL)) )
goto ErrorReturn;
#else
PRVTKEY_Module_Startup();
if (0 == (hPrivateKeyAsn1Module = I_CryptInstallAsn1Module(
PRVTKEY_Module, 0, NULL))) {
PRVTKEY_Module_Cleanup();
goto ErrorReturn;
}
#endif // OSS_CRYPT_ASN1
break;
case DLL_PROCESS_DETACH:
I_CryptUninstallAsn1Module(hPrivateKeyAsn1Module);
#ifndef OSS_CRYPT_ASN1
PRVTKEY_Module_Cleanup();
#endif // OSS_CRYPT_ASN1
break;
default:
break;
}
return TRUE;
ErrorReturn:
return FALSE;
}
static inline ASN1encoding_t GetEncoder(void)
{
return I_CryptGetAsn1Encoder(hPrivateKeyAsn1Module);
}
static inline ASN1decoding_t GetDecoder(void)
{
return I_CryptGetAsn1Decoder(hPrivateKeyAsn1Module);
}
//+-------------------------------------------------------------------------
// Encode an OSS formatted info structure
//
// Called by the OssX509*Encode() functions.
//--------------------------------------------------------------------------
static BOOL OssInfoEncode(
IN int pdunum,
IN void *pOssInfo,
OUT BYTE *pbEncoded,
IN OUT DWORD *pcbEncoded
)
{
return PkiAsn1EncodeInfo(
GetEncoder(),
pdunum,
pOssInfo,
pbEncoded,
pcbEncoded);
}
//+-------------------------------------------------------------------------
// Decode into an allocated, OSS formatted info structure
//
// Called by the OssX509*Decode() functions.
//--------------------------------------------------------------------------
static BOOL OssInfoDecodeAndAlloc(
IN int pdunum,
IN const BYTE *pbEncoded,
IN DWORD cbEncoded,
OUT void **ppOssInfo
)
{
return PkiAsn1DecodeAndAllocInfo(
GetDecoder(),
pdunum,
pbEncoded,
cbEncoded,
ppOssInfo);
}
//+-------------------------------------------------------------------------
// Free an allocated, OSS formatted info structure
//
// Called by the OssX509*Decode() functions.
//--------------------------------------------------------------------------
static void OssInfoFree(
IN int pdunum,
IN void *pOssInfo
)
{
if (pOssInfo) {
DWORD dwErr = GetLastError();
// TlsGetValue globbers LastError
PkiAsn1FreeInfo(GetDecoder(), pdunum, pOssInfo);
SetLastError(dwErr);
}
}
//+-------------------------------------------------------------------------
// Set/Get CRYPT_DATA_BLOB (Octet String)
//--------------------------------------------------------------------------
static inline void OssX509SetOctetString(
IN PCRYPT_DATA_BLOB pInfo,
OUT OCTETSTRING *pOss
)
{
pOss->value = pInfo->pbData;
pOss->length = pInfo->cbData;
}
static inline void OssX509GetOctetString(
IN OCTETSTRING *pOss,
IN DWORD dwFlags,
OUT PCRYPT_DATA_BLOB pInfo,
IN OUT BYTE **ppbExtra,
IN OUT LONG *plRemainExtra
)
{
PkiAsn1GetOctetString(pOss->length, pOss->value, dwFlags,
pInfo, ppbExtra, plRemainExtra);
}
//+-------------------------------------------------------------------------
// Set/Get Object Identifier string
//--------------------------------------------------------------------------
static BOOL OssX509SetObjId(
IN LPSTR pszObjId,
OUT ObjectID *pOss
)
{
pOss->count = sizeof(pOss->value) / sizeof(pOss->value[0]);
if (PkiAsn1ToObjectIdentifier(pszObjId, &pOss->count, pOss->value))
return TRUE;
else {
SetLastError((DWORD) CRYPT_E_BAD_ENCODE);
return FALSE;
}
}
static void OssX509GetObjId(
IN ObjectID *pOss,
IN DWORD dwFlags,
OUT LPSTR *ppszObjId,
IN OUT BYTE **ppbExtra,
IN OUT LONG *plRemainExtra
)
{
LONG lRemainExtra = *plRemainExtra;
BYTE *pbExtra = *ppbExtra;
LONG lAlignExtra;
DWORD cbObjId;
cbObjId = lRemainExtra > 0 ? lRemainExtra : 0;
PkiAsn1FromObjectIdentifier(
pOss->count,
pOss->value,
(LPSTR) pbExtra,
&cbObjId
);
lAlignExtra = INFO_LEN_ALIGN(cbObjId);
lRemainExtra -= lAlignExtra;
if (lRemainExtra >= 0) {
if(cbObjId) {
*ppszObjId = (LPSTR) pbExtra;
} else
*ppszObjId = NULL;
pbExtra += lAlignExtra;
}
*plRemainExtra = lRemainExtra;
*ppbExtra = pbExtra;
}
//+-------------------------------------------------------------------------
// Set/Get "Any" DER BLOB
//--------------------------------------------------------------------------
static inline void OssX509SetAny(
IN PCRYPT_OBJID_BLOB pInfo,
OUT NOCOPYANY *pOss
)
{
#ifdef OSS_CRYPT_ASN1
PkiAsn1SetAny(pInfo, (OpenType *) pOss);
#else
PkiAsn1SetAny(pInfo, pOss);
#endif // OSS_CRYPT_ASN1
}
static inline void OssX509GetAny(
IN NOCOPYANY *pOss,
IN DWORD dwFlags,
OUT PCRYPT_OBJID_BLOB pInfo,
IN OUT BYTE **ppbExtra,
IN OUT LONG *plRemainExtra
)
{
#ifdef OSS_CRYPT_ASN1
PkiAsn1GetAny((OpenType *) pOss, dwFlags, pInfo, ppbExtra, plRemainExtra);
#else
PkiAsn1GetAny(pOss, dwFlags, pInfo, ppbExtra, plRemainExtra);
#endif // OSS_CRYPT_ASN1
}
//+-------------------------------------------------------------------------
// Set/Free/Get SeqOfAny
//--------------------------------------------------------------------------
static BOOL WINAPI OssX509SetSeqOfAny(
IN DWORD cValue,
IN PCRYPT_DER_BLOB pValue,
#ifdef OSS_CRYPT_ASN1
OUT unsigned int *pOssCount,
#else
OUT ASN1uint32_t *pOssCount,
#endif // OSS_CRYPT_ASN1
OUT NOCOPYANY **ppOssValue
)
{
*pOssCount = 0;
*ppOssValue = NULL;
if (cValue > 0) {
NOCOPYANY *pOssValue;
pOssValue = (NOCOPYANY *) SSAlloc(cValue * sizeof(NOCOPYANY));
if (pOssValue == NULL)
return FALSE;
memset(pOssValue, 0, cValue * sizeof(NOCOPYANY));
*pOssCount = cValue;
*ppOssValue = pOssValue;
for ( ; cValue > 0; cValue--, pValue++, pOssValue++)
OssX509SetAny(pValue, pOssValue);
}
return TRUE;
}
static void OssX509FreeSeqOfAny(
IN NOCOPYANY *pOssValue
)
{
if (pOssValue)
SSFree(pOssValue);
}
static void OssX509GetSeqOfAny(
IN unsigned int OssCount,
IN NOCOPYANY *pOssValue,
IN DWORD dwFlags,
OUT DWORD *pcValue,
OUT PCRYPT_DER_BLOB *ppValue,
IN OUT BYTE **ppbExtra,
IN OUT LONG *plRemainExtra
)
{
LONG lAlignExtra;
PCRYPT_ATTR_BLOB pValue;
lAlignExtra = INFO_LEN_ALIGN(OssCount * sizeof(CRYPT_DER_BLOB));
*plRemainExtra -= lAlignExtra;
if (*plRemainExtra >= 0) {
*pcValue = OssCount;
pValue = (PCRYPT_DER_BLOB) *ppbExtra;
*ppValue = pValue;
*ppbExtra += lAlignExtra;
} else
pValue = NULL;
for (; OssCount > 0; OssCount--, pOssValue++, pValue++)
OssX509GetAny(pOssValue, dwFlags, pValue, ppbExtra, plRemainExtra);
}
//+-------------------------------------------------------------------------
// Set/Free/Get CRYPT_ATTRIBUTE
//--------------------------------------------------------------------------
static BOOL WINAPI OssX509SetAttribute(
IN PCRYPT_ATTRIBUTE pInfo,
OUT Attribute *pOss
)
{
memset(pOss, 0, sizeof(*pOss));
if (!OssX509SetObjId(pInfo->pszObjId, &pOss->type))
return FALSE;
return OssX509SetSeqOfAny(
pInfo->cValue,
pInfo->rgValue,
&pOss->values.count,
&pOss->values.value);
}
static void OssX509FreeAttribute(
IN OUT Attribute *pOss
)
{
OssX509FreeSeqOfAny(pOss->values.value);
}
static void OssX509GetAttribute(
IN Attribute *pOss,
IN DWORD dwFlags,
OUT PCRYPT_ATTRIBUTE pInfo,
IN OUT BYTE **ppbExtra,
IN OUT LONG *plRemainExtra
)
{
OssX509GetObjId(&pOss->type, dwFlags,
&pInfo->pszObjId, ppbExtra, plRemainExtra);
OssX509GetSeqOfAny(pOss->values.count, pOss->values.value, dwFlags,
&pInfo->cValue, &pInfo->rgValue, ppbExtra, plRemainExtra);
}
//+-------------------------------------------------------------------------
// Set/Get CRYPT_ALGORITHM_IDENTIFIER
//--------------------------------------------------------------------------
static BOOL OssX509SetAlgorithm(
IN PCRYPT_ALGORITHM_IDENTIFIER pInfo,
OUT AlgorithmIdentifier *pOss
)
{
memset(pOss, 0, sizeof(*pOss));
if (pInfo->pszObjId) {
if (!OssX509SetObjId(pInfo->pszObjId, &pOss->algorithm))
return FALSE;
if (pInfo->Parameters.cbData)
OssX509SetAny(&pInfo->Parameters, &pOss->parameters);
else
// Per PKCS #1: default to the ASN.1 type NULL.
OssX509SetAny((PCRYPT_OBJID_BLOB) &NullDerBlob, &pOss->parameters);
pOss->bit_mask |= parameters_present;
}
return TRUE;
}
static void OssX509GetAlgorithm(
IN AlgorithmIdentifier *pOss,
IN DWORD dwFlags,
OUT PCRYPT_ALGORITHM_IDENTIFIER pInfo,
IN OUT BYTE **ppbExtra,
IN OUT LONG *plRemainExtra
)
{
if (*plRemainExtra >= 0)
memset(pInfo, 0, sizeof(*pInfo));
OssX509GetObjId(&pOss->algorithm, dwFlags, &pInfo->pszObjId,
ppbExtra, plRemainExtra);
if (pOss->bit_mask & parameters_present)
OssX509GetAny(&pOss->parameters, dwFlags, &pInfo->Parameters,
ppbExtra, plRemainExtra);
}
//+-------------------------------------------------------------------------
// Helper function for Encode RSA Private Key
//--------------------------------------------------------------------------
static BOOL WINAPI AllocAndCopyHugeInteger(
IN BYTE *pbHugeInteger,
IN DWORD cbHugeInteger,
OUT HUGEINTEGER *pHugeInteger
)
{
BYTE *pbAllocBuffer = NULL;
if (NULL == (pbAllocBuffer = (BYTE *) SSAlloc(cbHugeInteger + 1)))
return FALSE;
*pbAllocBuffer = 0;
memcpy(pbAllocBuffer + 1, pbHugeInteger, cbHugeInteger);
PkiAsn1ReverseBytes(pbAllocBuffer + 1, cbHugeInteger);
pHugeInteger->length = cbHugeInteger + 1;
pHugeInteger->value = pbAllocBuffer;
return TRUE;
}
#ifndef RSA2
#define RSA2 ((DWORD)'R'+((DWORD)'S'<<8)+((DWORD)'A'<<16)+((DWORD)'2'<<24))
#endif
//+-------------------------------------------------------------------------
// Encode RSA Private Key
//--------------------------------------------------------------------------
static BOOL WINAPI OssRSAPrivateKeyStrucEncode(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN BLOBHEADER *pBlobHeader,
OUT BYTE *pbEncoded,
IN OUT DWORD *pcbEncoded
)
{
BOOL fResult;
BYTE *pbKeyBlob;
RSAPUBKEY *pRsaPubKey;
BYTE *pbCurrentHugeInteger;
DWORD cbHugeInteger;
BYTE *pbAllocBuffer = NULL;
RSAPrivateKey OssRSAPrivateKey;
memset(&OssRSAPrivateKey, 0, (size_t) sizeof(RSAPrivateKey));
// The CAPI RSA private key representation consists of the following sequence:
// - BLOBHEADER blobheader;
// - RSAPUBKEY rsapubkey;
// - BYTE modulus[rsapubkey.bitlen/8];
// - BYTE prime1[rsapubkey.bitlen/16];
// - BYTE prime2[rsapubkey.bitlen/16];
// - BYTE exponent1[rsapubkey.bitlen/16];
// - BYTE exponent2[rsapubkey.bitlen/16];
// - BYTE coefficient[rsapubkey.bitlen/16];
// - BYTE privateExponent[rsapubkey.bitlen/8];
pbKeyBlob = (BYTE *) pBlobHeader;
pRsaPubKey = (RSAPUBKEY *) (pbKeyBlob + sizeof(BLOBHEADER));
assert(pRsaPubKey->bitlen / 8 > 0);
assert(pBlobHeader->bType == PRIVATEKEYBLOB);
assert(pBlobHeader->bVersion == CUR_BLOB_VERSION);
assert(pBlobHeader->aiKeyAlg == CALG_RSA_SIGN ||
pBlobHeader->aiKeyAlg == CALG_RSA_KEYX);
assert(pRsaPubKey->magic == RSA2);
assert(pRsaPubKey->bitlen % 8 == 0);
if (pBlobHeader->bType != PRIVATEKEYBLOB)
goto InvalidArg;
// PKCS #1 ASN.1 encode
//
// ASN.1 isn't reversing HUGE_INTEGERs. Also, after doing the
// reversal insert a leading 0 byte to force it to always be treated
// as an unsigned integer
OssRSAPrivateKey.version = 0; // currently on version 0
// MODULUS
pbCurrentHugeInteger = pbKeyBlob + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY);
cbHugeInteger = pRsaPubKey->bitlen / 8;
if (!AllocAndCopyHugeInteger(pbCurrentHugeInteger,
cbHugeInteger,
&(OssRSAPrivateKey.modulus)))
goto ErrorReturn;
// PUBLIC EXPONENT
OssRSAPrivateKey.publicExponent = pRsaPubKey->pubexp;
// PRIME1
pbCurrentHugeInteger += cbHugeInteger;
cbHugeInteger = pRsaPubKey->bitlen / 16;
if (!AllocAndCopyHugeInteger(pbCurrentHugeInteger,
cbHugeInteger,
&(OssRSAPrivateKey.prime1)))
goto ErrorReturn;
// PRIME2
pbCurrentHugeInteger += cbHugeInteger;
if (!AllocAndCopyHugeInteger(pbCurrentHugeInteger,
cbHugeInteger,
&(OssRSAPrivateKey.prime2)))
goto ErrorReturn;
// EXPONENT1
pbCurrentHugeInteger += cbHugeInteger;
if (!AllocAndCopyHugeInteger(pbCurrentHugeInteger,
cbHugeInteger,
&(OssRSAPrivateKey.exponent1)))
goto ErrorReturn;
// EXPONENT2
pbCurrentHugeInteger += cbHugeInteger;
if (!AllocAndCopyHugeInteger(pbCurrentHugeInteger,
cbHugeInteger,
&(OssRSAPrivateKey.exponent2)))
goto ErrorReturn;
// COEFFICIENT
pbCurrentHugeInteger += cbHugeInteger;
if (!AllocAndCopyHugeInteger(pbCurrentHugeInteger,
cbHugeInteger,
&(OssRSAPrivateKey.coefficient)))
goto ErrorReturn;
// PRIVATE EXPONENT
pbCurrentHugeInteger += cbHugeInteger;
cbHugeInteger = pRsaPubKey->bitlen / 8;
if (!AllocAndCopyHugeInteger(pbCurrentHugeInteger,
cbHugeInteger,
&(OssRSAPrivateKey.privateExponent)))
goto ErrorReturn;
fResult = OssInfoEncode(
RSAPrivateKey_PDU,
&OssRSAPrivateKey,
pbEncoded,
pcbEncoded
);
goto CommonReturn;
InvalidArg:
SetLastError((DWORD) E_INVALIDARG);
ErrorReturn:
*pcbEncoded = 0;
fResult = FALSE;
CommonReturn:
if (OssRSAPrivateKey.modulus.value)
SSFree(OssRSAPrivateKey.modulus.value);
if (OssRSAPrivateKey.prime1.value)
SSFree(OssRSAPrivateKey.prime1.value);
if (OssRSAPrivateKey.prime2.value)
SSFree(OssRSAPrivateKey.prime2.value);
if (OssRSAPrivateKey.exponent1.value)
SSFree(OssRSAPrivateKey.exponent1.value);
if (OssRSAPrivateKey.exponent2.value)
SSFree(OssRSAPrivateKey.exponent2.value);
if (OssRSAPrivateKey.coefficient.value)
SSFree(OssRSAPrivateKey.coefficient.value);
if (OssRSAPrivateKey.privateExponent.value)
SSFree(OssRSAPrivateKey.privateExponent.value);
return fResult;
}
//+-------------------------------------------------------------------------
// Helper function for Decode RSA Private Key
//--------------------------------------------------------------------------
static BOOL WINAPI CopyHugeIntegerToByteArray(
HUGEINTEGER *pHugeInteger,
BYTE *pbBuffer,
DWORD cbBuffer,
BOOL fGetRidOfLeading0)
{
memset(pbBuffer, 0, (size_t) cbBuffer);
DWORD cbHugeInteger = pHugeInteger->length;
BYTE *pbHugeInteger = pHugeInteger->value;
// get rid of leading zero on the huge integer
if ((cbHugeInteger > 1) &&
(*pbHugeInteger == 0) &&
(fGetRidOfLeading0))
{
pbHugeInteger++;
cbHugeInteger--;
}
else if ((cbHugeInteger > cbBuffer) &&
(*pbHugeInteger != 0) &&
(fGetRidOfLeading0))
{
//
// THIS IS A UNSUPPORTED KEY FORMAT PROBLEM!!
//
SetLastError((DWORD) ERROR_UNSUPPORTED_TYPE);
assert(0);
return FALSE;
}
// verify there is enough space in pbBuffer to receive
// the huge integer
if (cbHugeInteger > cbBuffer)
{
SetLastError((DWORD) CRYPT_E_BAD_ENCODE);
assert(0);
return FALSE;
}
// advance pbBuffer to the correct place within itself,
// this will leave leading zeros at the beginning of the buffer
/*else
pbBuffer += (cbBuffer - cbHugeInteger);*/
if (cbHugeInteger > 0) {
memcpy(pbBuffer, pbHugeInteger, cbHugeInteger);
// ASN.1 isn't reversing HUGEINTEGERs
PkiAsn1ReverseBytes(pbBuffer, cbHugeInteger);
}
return TRUE;
}
//+-------------------------------------------------------------------------
// Decode RSA Private Key
//--------------------------------------------------------------------------
static BOOL WINAPI OssRSAPrivateKeyStrucDecode(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN const BYTE *pbEncoded,
IN DWORD cbEncoded,
IN DWORD dwFlags,
OUT BLOBHEADER *pBlobHeader,
IN OUT DWORD *pcbBlobHeader
)
{
BOOL fResult;
RSAPrivateKey *pOssPrivateKey = NULL;
if (pBlobHeader == NULL)
*pcbBlobHeader = 0;
if ((fResult = OssInfoDecodeAndAlloc(
RSAPrivateKey_PDU,
pbEncoded,
cbEncoded,
(void **) &pOssPrivateKey))) {
DWORD cbPrivateKeyStruc;
BYTE *pbOssModulus;
DWORD cbModulus;
DWORD cbNonModulus;
// Now convert the OSS RSA private key into CAPI's representation which
// consists of the following sequence:
// - BLOBHEADER blobheader;
// - RSAPUBKEY rsapubkey;
// - BYTE modulus[rsapubkey.bitlen/8];
// - BYTE prime1[rsapubkey.bitlen/16];
// - BYTE prime2[rsapubkey.bitlen/16];
// - BYTE exponent1[rsapubkey.bitlen/16];
// - BYTE exponent2[rsapubkey.bitlen/16];
// - BYTE coefficient[rsapubkey.bitlen/16];
// - BYTE privateExponent[rsapubkey.bitlen/8];
cbModulus = pOssPrivateKey->modulus.length;
pbOssModulus = pOssPrivateKey->modulus.value;
// 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 && *pbOssModulus == 0) {
pbOssModulus++;
cbModulus--;
}
cbNonModulus = (cbModulus / 2) + (cbModulus % 2);
cbPrivateKeyStruc = sizeof(BLOBHEADER) + // length of BLOBHEADER
sizeof(RSAPUBKEY) + // length of RSAPUBKEY
(cbModulus * 2) + // length of modulus and privateExponent
(cbNonModulus * 5); // length of prime1&2, exponent1&2, and coefficient
if (*pcbBlobHeader < cbPrivateKeyStruc) {
if (pBlobHeader) {
fResult = FALSE;
SetLastError((DWORD) ERROR_MORE_DATA);
}
} else {
BYTE *pbKeyBlob = (BYTE *) pBlobHeader;
RSAPUBKEY *pRsaPubKey =
(RSAPUBKEY *) (pbKeyBlob + sizeof(PUBLICKEYSTRUC));
BYTE *pbModulus = pbKeyBlob + sizeof(PUBLICKEYSTRUC) +
sizeof(RSAPUBKEY);
BYTE *pbCurrentPosition = NULL;
pBlobHeader->bType = PRIVATEKEYBLOB;
pBlobHeader->bVersion = CUR_BLOB_VERSION;
pBlobHeader->reserved = 0;
// Note: KEYX can also be used for doing a signature
pBlobHeader->aiKeyAlg = CALG_RSA_KEYX;
pRsaPubKey->magic = RSA2;
pRsaPubKey->bitlen = cbModulus * 8;
pRsaPubKey->pubexp = pOssPrivateKey->publicExponent;
// MODULUS
if (cbModulus > 0) {
memcpy(pbModulus, pbOssModulus, cbModulus);
// ASN.1 isn't reversing HUGEINTEGERs
PkiAsn1ReverseBytes(pbModulus, cbModulus);
}
// PRIME1
pbCurrentPosition = pbModulus + cbModulus;
if (!CopyHugeIntegerToByteArray(&pOssPrivateKey->prime1,
pbCurrentPosition,
cbNonModulus,
(pOssPrivateKey->prime1.length - 1) == cbNonModulus))
goto ErrorReturn;
// PRIME2
pbCurrentPosition += cbNonModulus;
if (!CopyHugeIntegerToByteArray(&pOssPrivateKey->prime2,
pbCurrentPosition,
cbNonModulus,
(pOssPrivateKey->prime2.length - 1) == cbNonModulus))
goto ErrorReturn;
// EXPONENT1
pbCurrentPosition += cbNonModulus;
if (!CopyHugeIntegerToByteArray(&pOssPrivateKey->exponent1,
pbCurrentPosition,
cbNonModulus,
(pOssPrivateKey->exponent1.length - 1) == cbNonModulus))
goto ErrorReturn;
// EXPONENT2
pbCurrentPosition += cbNonModulus;
if (!CopyHugeIntegerToByteArray(&pOssPrivateKey->exponent2,
pbCurrentPosition,
cbNonModulus,
(pOssPrivateKey->exponent2.length - 1) == cbNonModulus))
goto ErrorReturn;
// COEFFICIENT
pbCurrentPosition += cbNonModulus;
if (!CopyHugeIntegerToByteArray(&pOssPrivateKey->coefficient,
pbCurrentPosition,
cbNonModulus,
(pOssPrivateKey->coefficient.length - 1) == cbNonModulus))
goto ErrorReturn;
// PRIVATE EXPONENT
pbCurrentPosition += cbNonModulus;
if (!CopyHugeIntegerToByteArray(&pOssPrivateKey->privateExponent,
pbCurrentPosition,
cbModulus,
(pOssPrivateKey->privateExponent.length - 1) == cbModulus))
goto ErrorReturn;
}
*pcbBlobHeader = cbPrivateKeyStruc;
} else
*pcbBlobHeader = 0;
OssInfoFree(RSAPrivateKey_PDU, pOssPrivateKey);
goto CommonReturn;
ErrorReturn:
*pcbBlobHeader = 0;
fResult = FALSE;
CommonReturn:
return fResult;
}
//+-------------------------------------------------------------------------
// Encode Private Key Info
//--------------------------------------------------------------------------
static BOOL WINAPI OssPrivateKeyInfoEncode(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN PCRYPT_PRIVATE_KEY_INFO pInfo,
OUT BYTE *pbEncoded,
IN OUT DWORD *pcbEncoded
)
{
BOOL fResult;
PrivateKeyInfo OssPrivateKeyInfo;
Attribute *pOssAttr = NULL;
DWORD cAttr;
PCRYPT_ATTRIBUTE pAttr;
memset(&OssPrivateKeyInfo, 0, sizeof(PrivateKeyInfo));
OssPrivateKeyInfo.version = pInfo->Version;
if (!OssX509SetAlgorithm(&pInfo->Algorithm, &OssPrivateKeyInfo.privateKeyAlgorithm))
goto ErrorReturn;
OssX509SetOctetString(&pInfo->PrivateKey, &OssPrivateKeyInfo.privateKey);
if (pInfo->pAttributes) {
cAttr = pInfo->pAttributes->cAttr;
pAttr = pInfo->pAttributes->rgAttr;
OssPrivateKeyInfo.privateKeyAttributes.count = cAttr;
OssPrivateKeyInfo.privateKeyAttributes.value = NULL;
if (cAttr > 0) {
pOssAttr = (Attribute *) SSAlloc(cAttr * sizeof(Attribute));
if (pOssAttr == NULL)
goto ErrorReturn;
memset(pOssAttr, 0, cAttr * sizeof(Attribute));
OssPrivateKeyInfo.privateKeyAttributes.value= pOssAttr;
}
for ( ; cAttr > 0; cAttr--, pAttr++, pOssAttr++) {
if (!OssX509SetAttribute(pAttr, pOssAttr))
goto ErrorReturn;
}
OssPrivateKeyInfo.bit_mask |= privateKeyAttributes_present;
}
fResult = OssInfoEncode(
PrivateKeyInfo_PDU,
&OssPrivateKeyInfo,
pbEncoded,
pcbEncoded
);
goto CommonReturn;
ErrorReturn:
*pcbEncoded = 0;
fResult = FALSE;
CommonReturn:
if (OssPrivateKeyInfo.privateKeyAttributes.value) {
pOssAttr = OssPrivateKeyInfo.privateKeyAttributes.value;
cAttr = OssPrivateKeyInfo.privateKeyAttributes.count;
for ( ; cAttr > 0; cAttr--, pOssAttr++)
OssX509FreeAttribute(pOssAttr);
SSFree(OssPrivateKeyInfo.privateKeyAttributes.value);
}
return fResult;
}
//+-------------------------------------------------------------------------
// Decode Private Key Info
//--------------------------------------------------------------------------
static BOOL WINAPI OssPrivateKeyInfoDecode(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN const BYTE *pbEncoded,
IN DWORD cbEncoded,
IN DWORD dwFlags,
OUT PCRYPT_PRIVATE_KEY_INFO pInfo,
IN OUT DWORD *pcbInfo
)
{
BOOL fResult;
PrivateKeyInfo *pPrivateKeyInfo = NULL;
BYTE *pbExtra;
LONG lRemainExtra;
if (pInfo == NULL)
*pcbInfo = 0;
if (!OssInfoDecodeAndAlloc(
PrivateKeyInfo_PDU,
pbEncoded,
cbEncoded,
(void **) &pPrivateKeyInfo))
goto EncodeError;
// for lRemainExtra < 0, LENGTH_ONLY calculation
lRemainExtra = (LONG) *pcbInfo - sizeof(CRYPT_PRIVATE_KEY_INFO);
if (lRemainExtra < 0) {
pbExtra = NULL;
} else {
// Default all optional fields to zero
memset(pInfo, 0, sizeof(CRYPT_PRIVATE_KEY_INFO));
// Update fields not needing extra memory after the CRYPT_PRIVATE_KEY_INFO
pInfo->Version = pPrivateKeyInfo->version;
pbExtra = (BYTE *) pInfo + sizeof(CRYPT_PRIVATE_KEY_INFO);
}
OssX509GetAlgorithm(&pPrivateKeyInfo->privateKeyAlgorithm, dwFlags,
&pInfo->Algorithm, &pbExtra, &lRemainExtra);
OssX509GetOctetString(&pPrivateKeyInfo->privateKey, dwFlags,
&pInfo->PrivateKey, &pbExtra, &lRemainExtra);
if (pPrivateKeyInfo->bit_mask & privateKeyAttributes_present) {
DWORD cAttr;
PCRYPT_ATTRIBUTE pAttr;
Attribute *pOssAttr;
LONG lAlignExtra;
// put the CRYPT_ATTRIBUTES structure in the extra buffer space
// and point pInfo->pAttributes to it
if ((pbExtra) && (lRemainExtra >= sizeof(CRYPT_ATTRIBUTES))) {
memset(pbExtra, 0, sizeof(CRYPT_ATTRIBUTES));
pInfo->pAttributes = (PCRYPT_ATTRIBUTES) pbExtra;
pbExtra += sizeof(CRYPT_ATTRIBUTES);
}
lRemainExtra -= sizeof(CRYPT_ATTRIBUTES);
cAttr = pPrivateKeyInfo->privateKeyAttributes.count;
lAlignExtra = INFO_LEN_ALIGN(cAttr * sizeof(CRYPT_ATTRIBUTE));
lRemainExtra -= lAlignExtra;
if (lRemainExtra >= 0) {
pInfo->pAttributes->cAttr = cAttr;
pAttr = (PCRYPT_ATTRIBUTE) pbExtra;
pInfo->pAttributes->rgAttr = pAttr;
pbExtra += lAlignExtra;
} else
pAttr = NULL;
pOssAttr = pPrivateKeyInfo->privateKeyAttributes.value;
for (; cAttr > 0; cAttr--, pAttr++, pOssAttr++)
OssX509GetAttribute(pOssAttr, dwFlags,
pAttr, &pbExtra, &lRemainExtra);
}
if (lRemainExtra >= 0)
*pcbInfo = *pcbInfo - (DWORD) lRemainExtra;
else {
*pcbInfo = *pcbInfo + (DWORD) -lRemainExtra;
if (pInfo) goto LengthError;
}
fResult = TRUE;
goto CommonReturn;
LengthError:
SetLastError((DWORD) ERROR_MORE_DATA);
fResult = FALSE;
goto CommonReturn;
EncodeError:
SetLastError((DWORD) CRYPT_E_BAD_ENCODE);
// ErrorReturn:
*pcbInfo = 0;
fResult = FALSE;
CommonReturn:
OssInfoFree(PrivateKeyInfo_PDU, pPrivateKeyInfo);
return fResult;
}
//+-------------------------------------------------------------------------
// Encode Encrypted Private Key Info
//--------------------------------------------------------------------------
static BOOL WINAPI OssEncryptedPrivateKeyInfoEncode(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN PCRYPT_ENCRYPTED_PRIVATE_KEY_INFO pInfo,
OUT BYTE *pbEncoded,
IN OUT DWORD *pcbEncoded
)
{
BOOL fResult;
EncryptedPrivateKeyInfo OssEncryptedPrivateKeyInfo;
memset(&OssEncryptedPrivateKeyInfo, 0, sizeof(EncryptedPrivateKeyInfo));
if (!OssX509SetAlgorithm(&pInfo->EncryptionAlgorithm, &OssEncryptedPrivateKeyInfo.encryptionAlgorithm))
goto ErrorReturn;
OssX509SetOctetString(&pInfo->EncryptedPrivateKey, &OssEncryptedPrivateKeyInfo.encryptedData);
fResult = OssInfoEncode(
EncryptedPrivateKeyInfo_PDU,
&OssEncryptedPrivateKeyInfo,
pbEncoded,
pcbEncoded
);
goto CommonReturn;
ErrorReturn:
*pcbEncoded = 0;
fResult = FALSE;
CommonReturn:
return fResult;
}
//+-------------------------------------------------------------------------
// Decode Encrypted Private Key Info
//--------------------------------------------------------------------------
static BOOL WINAPI OssEncryptedPrivateKeyInfoDecode(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN const BYTE *pbEncoded,
IN DWORD cbEncoded,
IN DWORD dwFlags,
OUT PCRYPT_ENCRYPTED_PRIVATE_KEY_INFO pInfo,
IN OUT DWORD *pcbInfo
)
{
BOOL fResult;
EncryptedPrivateKeyInfo *pEncryptedPrivateKeyInfo = NULL;
BYTE *pbExtra;
LONG lRemainExtra;
if (pInfo == NULL)
*pcbInfo = 0;
if (!OssInfoDecodeAndAlloc(
EncryptedPrivateKeyInfo_PDU,
pbEncoded,
cbEncoded,
(void **) &pEncryptedPrivateKeyInfo))
goto EncodeError;
// for lRemainExtra < 0, LENGTH_ONLY calculation
lRemainExtra = (LONG) *pcbInfo - sizeof(CRYPT_ENCRYPTED_PRIVATE_KEY_INFO);
if (lRemainExtra < 0) {
pbExtra = NULL;
} else {
memset(pInfo, 0, sizeof(CRYPT_ENCRYPTED_PRIVATE_KEY_INFO));
pbExtra = (BYTE *) pInfo + sizeof(CRYPT_ENCRYPTED_PRIVATE_KEY_INFO);
}
OssX509GetAlgorithm(&pEncryptedPrivateKeyInfo->encryptionAlgorithm, dwFlags,
&pInfo->EncryptionAlgorithm, &pbExtra, &lRemainExtra);
OssX509GetOctetString(&pEncryptedPrivateKeyInfo->encryptedData, dwFlags,
&pInfo->EncryptedPrivateKey, &pbExtra, &lRemainExtra);
if (lRemainExtra >= 0)
*pcbInfo = *pcbInfo - (DWORD) lRemainExtra;
else {
*pcbInfo = *pcbInfo + (DWORD) -lRemainExtra;
if (pInfo) goto LengthError;
}
fResult = TRUE;
goto CommonReturn;
LengthError:
SetLastError((DWORD) ERROR_MORE_DATA);
fResult = FALSE;
goto CommonReturn;
EncodeError:
SetLastError((DWORD) CRYPT_E_BAD_ENCODE);
//ErrorReturn:
*pcbInfo = 0;
fResult = FALSE;
CommonReturn:
OssInfoFree(EncryptedPrivateKeyInfo_PDU, pEncryptedPrivateKeyInfo);
return fResult;
}