1158 lines
34 KiB
C++
1158 lines
34 KiB
C++
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// 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;
|
|
}
|