mirror of https://github.com/lianthony/NT4.0
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.
1006 lines
21 KiB
1006 lines
21 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1995.
|
|
//
|
|
// File: keys.c
|
|
//
|
|
// Contents: Well known keys for certificate validation
|
|
//
|
|
// Classes:
|
|
//
|
|
// Functions:
|
|
//
|
|
// History: 9-21-95 RichardW Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
#include "sslsspi.h"
|
|
#include "encode.h"
|
|
#include "bulk.h"
|
|
#include "cakeys.h"
|
|
|
|
#define PRIVATE_KEY_TEXT "private-key"
|
|
|
|
|
|
typedef struct _KnownKey {
|
|
PSTR pszIssuer;
|
|
BSAFE_PUB_KEY * pKey;
|
|
DWORD cbKey;
|
|
DWORD Reserved; // make it align nicely
|
|
} KnownKey, * PKnownKey;
|
|
|
|
UCHAR bMD2SigPrefixReverse[] = { 0x10, 0x04, 0x00, 0x05, 0x02, 0x02, 0x0d,
|
|
0xf7, 0x86, 0x48, 0x86, 0x2a, 0x08, 0x06,
|
|
0x0c, 0x30, 0x20, 0x30 };
|
|
|
|
UCHAR bMD5SigPrefixReverse[] = { 0x10, 0x04, 0x00, 0x05, 0x05, 0x02, 0x0d,
|
|
0xf7, 0x86, 0x48, 0x86, 0x2a, 0x08, 0x06,
|
|
0x0c, 0x30, 0x20, 0x30 };
|
|
|
|
UCHAR bMD5SigPrefix[] = { 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86,
|
|
0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00,
|
|
0x04, 0x10 };
|
|
|
|
|
|
CHAR szSslRegKey[] = TEXT("System\\CurrentControlSet\\Control\\SecurityProviders\\SslSspi");
|
|
|
|
|
|
#define SSL_DEFAULT_CA_COUNT 16
|
|
|
|
KnownKey SslpTrustedCAs[ SSL_DEFAULT_CA_COUNT ];
|
|
KnownKey * SslTrustedCAs;
|
|
DWORD SslTrustedCACount;
|
|
|
|
|
|
BOOL
|
|
SslpAddKey(
|
|
KnownKey * pKey)
|
|
{
|
|
KnownKey * pCopy;
|
|
KnownKey * pFree;
|
|
PVOID pCheck;
|
|
|
|
LockSsl( SSL_ADD_KEY_TO_CA_LIST );
|
|
|
|
if ( SslTrustedCACount < SSL_DEFAULT_CA_COUNT )
|
|
{
|
|
SslpTrustedCAs[ SslTrustedCACount++ ] = *pKey ;
|
|
}
|
|
else
|
|
{
|
|
pCopy = SslAlloc( ' AC', LMEM_FIXED | LMEM_ZEROINIT,
|
|
(SslTrustedCACount + 1) * sizeof( KnownKey) );
|
|
|
|
if ( !pCopy )
|
|
{
|
|
UnlockSsl();
|
|
return( FALSE );
|
|
}
|
|
|
|
CopyMemory( pCopy, SslTrustedCAs, sizeof(KnownKey) * SslTrustedCACount );
|
|
|
|
pFree = SslTrustedCAs;
|
|
SslTrustedCAs = pCopy;
|
|
if (pFree != SslpTrustedCAs)
|
|
{
|
|
SslFree( pFree );
|
|
}
|
|
|
|
SslTrustedCAs[ SslTrustedCACount++ ] = *pKey;
|
|
}
|
|
|
|
UnlockSsl();
|
|
|
|
return( TRUE );
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
PopulateRegistry(
|
|
KnownKey * pKeys,
|
|
DWORD cKeys)
|
|
{
|
|
HKEY hKey;
|
|
DWORD err;
|
|
DWORD disp;
|
|
KnownKey * pKey;
|
|
|
|
|
|
err = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
|
|
szSslRegKey,
|
|
0,
|
|
TEXT(""),
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_WRITE,
|
|
NULL,
|
|
&hKey,
|
|
&disp);
|
|
|
|
if (err)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
pKey = pKeys;
|
|
while (cKeys--)
|
|
{
|
|
if (pKey->cbKey)
|
|
{
|
|
err = RegSetValueEx(hKey,
|
|
pKey->pszIssuer,
|
|
0,
|
|
REG_BINARY,
|
|
(PBYTE) pKey->pKey,
|
|
pKey->cbKey );
|
|
|
|
|
|
}
|
|
|
|
pKey += 1;
|
|
|
|
}
|
|
|
|
RegCloseKey( hKey );
|
|
|
|
return( TRUE );
|
|
|
|
}
|
|
|
|
BOOL
|
|
ReadFromRegistry(
|
|
KnownKey * * ppKeys,
|
|
LPDWORD pcKeys)
|
|
{
|
|
HKEY hKey;
|
|
DWORD err;
|
|
DWORD disp;
|
|
KnownKey * pKey;
|
|
DWORD cValues;
|
|
DWORD cbMaxValueNameLen;
|
|
DWORD cbMaxValueLen;
|
|
PSTR pName;
|
|
PBYTE pbValue;
|
|
DWORD cbName;
|
|
DWORD cbValue;
|
|
DWORD dwType;
|
|
|
|
err = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
|
|
szSslRegKey,
|
|
0,
|
|
TEXT(""),
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_READ,
|
|
NULL,
|
|
&hKey,
|
|
&disp);
|
|
|
|
if (err)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
err = RegQueryInfoKey( hKey,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&cValues,
|
|
&cbMaxValueNameLen,
|
|
&cbMaxValueLen,
|
|
NULL,
|
|
NULL );
|
|
|
|
if ( err )
|
|
{
|
|
RegCloseKey( hKey );
|
|
return( FALSE );
|
|
}
|
|
|
|
pName = SslAlloc( ' yeK', LMEM_FIXED | LMEM_ZEROINIT, cbMaxValueNameLen + 1 );
|
|
pbValue = SslAlloc( ' yeK', LMEM_FIXED | LMEM_ZEROINIT, cbMaxValueLen );
|
|
|
|
if ( (!pName) || (!pbValue) )
|
|
{
|
|
RegCloseKey( hKey );
|
|
return( FALSE );
|
|
}
|
|
|
|
*ppKeys = SslAlloc( ' yeK', LMEM_FIXED | LMEM_ZEROINIT, cValues * sizeof(KnownKey) );
|
|
if (! *ppKeys)
|
|
{
|
|
SslFree( pName );
|
|
SslFree( pbValue );
|
|
RegCloseKey( hKey );
|
|
return( FALSE );
|
|
}
|
|
|
|
*pcKeys = 0;
|
|
pKey = *ppKeys;
|
|
|
|
while ( cValues-- )
|
|
{
|
|
cbName = cbMaxValueNameLen + 1;
|
|
cbValue = cbMaxValueLen;
|
|
|
|
err = RegEnumValue( hKey,
|
|
cValues,
|
|
pName,
|
|
&cbName,
|
|
NULL,
|
|
&dwType,
|
|
pbValue,
|
|
&cbValue );
|
|
|
|
if ( (err != 0) ||
|
|
(dwType != REG_BINARY) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
pKey->pszIssuer = SslAlloc( 'IyeK',
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
cbName + 1 );
|
|
if (pKey->pszIssuer)
|
|
{
|
|
CopyMemory( pKey->pszIssuer, pName, cbName + 1 );
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
|
|
pKey->pKey = SslAlloc( 'PyeK',
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
cbValue );
|
|
|
|
if (pKey->pKey)
|
|
{
|
|
CopyMemory( pKey->pKey, pbValue, cbValue );
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
|
|
pKey->Reserved = 0;
|
|
pKey->cbKey = cbValue;
|
|
|
|
DebugLog(( DEB_TRACE, "Loaded CA key for %s\n", pKey->pszIssuer));
|
|
|
|
pKey++;
|
|
|
|
(*pcKeys)++;
|
|
|
|
}
|
|
|
|
RegCloseKey( hKey );
|
|
SslFree( pName );
|
|
SslFree( pbValue );
|
|
|
|
if (*pcKeys == 0)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOL
|
|
InitializeWellKnownKeys( VOID )
|
|
{
|
|
KnownKey k;
|
|
KnownKey * pk;
|
|
DWORD cKeys;
|
|
|
|
SslTrustedCAs = SslpTrustedCAs;
|
|
SslTrustedCACount = 0;
|
|
|
|
if ( ReadFromRegistry( &pk, &cKeys ) )
|
|
{
|
|
if ( cKeys < SSL_DEFAULT_CA_COUNT )
|
|
{
|
|
CopyMemory( SslpTrustedCAs, pk, cKeys * sizeof( KnownKey ) );
|
|
LocalFree( pk );
|
|
}
|
|
else
|
|
{
|
|
SslTrustedCAs = pk;
|
|
}
|
|
|
|
SslTrustedCACount = cKeys;
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
//
|
|
// Okay, build our list, and populate the registry
|
|
//
|
|
|
|
k. pKey = (LPBSAFE_PUB_KEY) CAKey0;
|
|
k.cbKey = sizeof( CAKey0 );
|
|
k.pszIssuer = CAKeyName0;
|
|
k.Reserved = 0;
|
|
|
|
SslpAddKey( &k );
|
|
|
|
k. pKey = (LPBSAFE_PUB_KEY) CAKey1;
|
|
k.cbKey = sizeof( CAKey1 );
|
|
k.pszIssuer = CAKeyName1;
|
|
k.Reserved = 0;
|
|
|
|
SslpAddKey( &k );
|
|
|
|
k. pKey = (LPBSAFE_PUB_KEY) CAKey2;
|
|
k.cbKey = sizeof( CAKey2 );
|
|
k.pszIssuer = CAKeyName2;
|
|
k.Reserved = 0;
|
|
|
|
SslpAddKey( &k );
|
|
|
|
//
|
|
// Note, this may fail,
|
|
PopulateRegistry( SslTrustedCAs, SslTrustedCACount );
|
|
|
|
return( TRUE );
|
|
|
|
}
|
|
|
|
|
|
BSAFE_PUB_KEY *
|
|
FindIssuerKey(
|
|
PSTR pszIssuer)
|
|
{
|
|
DWORD i;
|
|
BSAFE_PUB_KEY * pKey;
|
|
|
|
LockSsl( SSL_FIND_ISSUER );
|
|
|
|
for (i = 0; i < SslTrustedCACount ; i++ )
|
|
{
|
|
if (_stricmp(pszIssuer, SslTrustedCAs[i].pszIssuer) == 0)
|
|
{
|
|
pKey = SslTrustedCAs[i].pKey;
|
|
UnlockSsl();
|
|
return( pKey );
|
|
|
|
}
|
|
}
|
|
|
|
UnlockSsl();
|
|
|
|
return( NULL );
|
|
}
|
|
|
|
BOOL
|
|
SslLoadCertificate(
|
|
PUCHAR pbCertificate,
|
|
DWORD cbCertificate,
|
|
BOOL AddToWellKnownKeys)
|
|
{
|
|
PX509Certificate pCert;
|
|
PX509Certificate pCert2;
|
|
KnownKey Key;
|
|
PVOID pCheck;
|
|
|
|
if (!CrackCertificate( pbCertificate,
|
|
cbCertificate,
|
|
FALSE,
|
|
&pCert) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if (_stricmp( pCert->pszIssuer, pCert->pszSubject ) )
|
|
{
|
|
FreeCertificate( pCert );
|
|
return( FALSE );
|
|
}
|
|
|
|
pCheck = FindIssuerKey( pCert->pszIssuer );
|
|
|
|
if ( pCheck )
|
|
{
|
|
//
|
|
// Duplicate, we're out of here...
|
|
//
|
|
|
|
FreeCertificate( pCert );
|
|
return( FALSE );
|
|
}
|
|
|
|
//
|
|
// Ok, it is at least syntactically correct. Now, grab the key out of
|
|
// it, and build a known key for it:
|
|
//
|
|
|
|
Key.pszIssuer = pCert->pszIssuer;
|
|
Key.pKey = pCert->pPublicKey;
|
|
Key.cbKey = pCert->cbPublicKey;
|
|
|
|
if ( !SslpAddKey( &Key ) )
|
|
{
|
|
FreeCertificate( pCert );
|
|
return( FALSE );
|
|
}
|
|
|
|
//
|
|
// Crack it again, verifying it this time:
|
|
//
|
|
|
|
if (!CrackCertificate( pbCertificate,
|
|
cbCertificate,
|
|
TRUE,
|
|
&pCert2) )
|
|
{
|
|
FreeCertificate( pCert );
|
|
return( FALSE );
|
|
}
|
|
|
|
//
|
|
// NULL this out so it doesn't get deleted
|
|
//
|
|
|
|
pCert->pPublicKey = NULL;
|
|
pCert->pszIssuer = NULL;
|
|
FreeCertificate( pCert );
|
|
|
|
if ( AddToWellKnownKeys )
|
|
{
|
|
PopulateRegistry( &Key, 1 );
|
|
}
|
|
|
|
return( TRUE );
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
SslpEncodePrivateKey(
|
|
BSAFE_PRV_KEY * pKey,
|
|
DWORD InitialSize,
|
|
PSTR pszPassword,
|
|
PUCHAR * ppBuffer,
|
|
DWORD * pcbBuffer )
|
|
{
|
|
BSAFE_KEY_PARTS parts;
|
|
PUCHAR pBuffer;
|
|
PUCHAR pbEncoded;
|
|
PUCHAR pSave;
|
|
int Result;
|
|
DWORD Zero;
|
|
DWORD BigLen;
|
|
DWORD ShortLen;
|
|
PUCHAR pSequence;
|
|
DWORD Length;
|
|
PUCHAR pSave2;
|
|
long Delta2;
|
|
PStateBuffer pState;
|
|
PCheckSumBuffer pCheck;
|
|
UCHAR Key[16];
|
|
|
|
|
|
|
|
|
|
BSafeGetPrvKeyParts( pKey, &parts );
|
|
|
|
pBuffer = SslAlloc( 'KvrP', LMEM_FIXED | LMEM_ZEROINIT, InitialSize );
|
|
|
|
if (!pBuffer)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
pbEncoded = pBuffer;
|
|
|
|
BigLen = pKey->bitlen / 8;
|
|
ShortLen = BigLen / 2;
|
|
|
|
//
|
|
// We just do the key now, and then we'll add the other stuff later
|
|
//
|
|
|
|
//
|
|
// Encode the maximum length for now. We'll patch this up later
|
|
//
|
|
|
|
Result = EncodeHeader(pbEncoded, InitialSize, TRUE );
|
|
|
|
pbEncoded += Result;
|
|
|
|
pSave = pbEncoded;
|
|
|
|
Zero = 0;
|
|
|
|
Result = EncodeInteger(pbEncoded, (PBYTE) &Zero, 1, TRUE );
|
|
|
|
pbEncoded += Result;
|
|
|
|
Result = EncodeInteger( pbEncoded, parts.modulus, BigLen, TRUE );
|
|
|
|
pbEncoded += Result;
|
|
|
|
Result = EncodeInteger( pbEncoded, (PBYTE) &pKey->pubexp, sizeof(DWORD), TRUE );
|
|
|
|
pbEncoded += Result;
|
|
|
|
Result = EncodeInteger( pbEncoded, parts.prvexp, BigLen, TRUE );
|
|
|
|
pbEncoded += Result;
|
|
|
|
Result = EncodeInteger( pbEncoded, parts.prime1, ShortLen, TRUE );
|
|
|
|
pbEncoded += Result;
|
|
|
|
Result = EncodeInteger( pbEncoded, parts.prime2, ShortLen, TRUE );
|
|
|
|
pbEncoded += Result;
|
|
|
|
Result = EncodeInteger( pbEncoded, parts.exp1, ShortLen, TRUE );
|
|
|
|
pbEncoded += Result;
|
|
|
|
Result = EncodeInteger( pbEncoded, parts.exp2, ShortLen, TRUE );
|
|
|
|
pbEncoded += Result;
|
|
|
|
Result = EncodeInteger( pbEncoded, parts.coef, ShortLen, TRUE );
|
|
|
|
pbEncoded += Result;
|
|
|
|
Length = pbEncoded - pSave;
|
|
|
|
Result = EncodeHeader( pBuffer, Length, TRUE );
|
|
|
|
Length += Result;
|
|
|
|
pSequence = SslAlloc( 'KvrP', LMEM_FIXED | LMEM_ZEROINIT, Length + 64 );
|
|
|
|
if (!pSequence)
|
|
{
|
|
SslFree( pBuffer );
|
|
return( FALSE );
|
|
|
|
}
|
|
|
|
pbEncoded = pSequence;
|
|
|
|
Result = EncodeHeader( pbEncoded, Length + 64, TRUE );
|
|
|
|
pbEncoded += Result;
|
|
|
|
pSave = pbEncoded;
|
|
|
|
Result = EncodeInteger( pbEncoded, (PBYTE) &Zero, 1, TRUE );
|
|
|
|
pbEncoded += Result;
|
|
|
|
Result = EncodeAlgorithm( pbEncoded, BASIC_RSA, TRUE );
|
|
|
|
pbEncoded += Result;
|
|
|
|
Result = EncodeOctetString( pbEncoded, pBuffer, Length, TRUE );
|
|
|
|
pbEncoded += Result;
|
|
|
|
ZeroMemory( pBuffer, Length );
|
|
|
|
Length = pbEncoded - pSave;
|
|
|
|
Result = EncodeHeader( pSequence, Length, TRUE );
|
|
|
|
Length += Result;
|
|
|
|
SslFree( pBuffer );
|
|
|
|
pBuffer = SslAlloc('KvrP', LMEM_FIXED | LMEM_ZEROINIT, Length + 128);
|
|
|
|
if (!pBuffer)
|
|
{
|
|
SslFree( pSequence );
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
|
|
pbEncoded = pBuffer;
|
|
|
|
Result = EncodeHeader( pBuffer, Length + 128, TRUE );
|
|
|
|
pbEncoded += Result;
|
|
|
|
pSave = pbEncoded;
|
|
|
|
Result = EncodeOctetString( pbEncoded, PRIVATE_KEY_TEXT,
|
|
strlen(PRIVATE_KEY_TEXT), TRUE );
|
|
|
|
pbEncoded += Result;
|
|
|
|
Result = EncodeHeader( pbEncoded, Length + 64, TRUE );
|
|
|
|
pbEncoded += Result;
|
|
|
|
pSave2 = pbEncoded;
|
|
Delta2 = Result;
|
|
|
|
Result = EncodeAlgorithm( pbEncoded, RC4_STREAM, TRUE );
|
|
|
|
pbEncoded += Result;
|
|
|
|
//
|
|
// Encrypt the data with the password
|
|
//
|
|
|
|
ckMD5.Initialize(0, &pCheck);
|
|
ckMD5.Sum(pCheck, strlen(pszPassword), pszPassword);
|
|
ckMD5.Finalize(pCheck, Key);
|
|
ckMD5.Finish(&pCheck);
|
|
|
|
csRC4.Initialize(Key, 16, &pState);
|
|
csRC4.Encrypt(pState, pSequence, pSequence, Length);
|
|
csRC4.Discard( &pState );
|
|
|
|
Result = EncodeOctetString( pbEncoded, pSequence, Length, TRUE );
|
|
|
|
SslFree( pSequence );
|
|
|
|
pbEncoded += Result;
|
|
|
|
//
|
|
// Now, back up and fill in the correct lengths:
|
|
//
|
|
|
|
Result = EncodeHeader( pSave2-Delta2, pbEncoded - pSave2, TRUE );
|
|
|
|
Result = EncodeHeader( pBuffer, pbEncoded - pSave2, TRUE );
|
|
|
|
*pcbBuffer = pbEncoded - pBuffer;
|
|
*ppBuffer = pBuffer;
|
|
|
|
DebugLog((DEB_TRACE, "Encoded private key\n"));
|
|
|
|
return( TRUE );
|
|
|
|
}
|
|
|
|
long
|
|
SslpEncodeSubjectPubKeyInfo(
|
|
BSAFE_PRV_KEY * pKey,
|
|
PUCHAR pBuffer)
|
|
{
|
|
PUCHAR pbEncoded;
|
|
LONG Result;
|
|
PUCHAR pSave;
|
|
PUCHAR pBitString;
|
|
PUCHAR pSave2;
|
|
PUCHAR pTop;
|
|
LONG PkResult;
|
|
DWORD EstimatedLength;
|
|
|
|
|
|
//
|
|
// Encode public key now...
|
|
//
|
|
|
|
EstimatedLength = pKey->datalen + 32;
|
|
|
|
pbEncoded = pBuffer;
|
|
|
|
Result = EncodeHeader( pbEncoded, EstimatedLength, TRUE );
|
|
|
|
pbEncoded += Result;
|
|
|
|
pTop = pbEncoded;
|
|
|
|
Result = EncodeAlgorithm( pbEncoded, BASIC_RSA, TRUE );
|
|
|
|
pbEncoded += Result;
|
|
|
|
//
|
|
// now, serialize the rsa key data:
|
|
//
|
|
|
|
pBitString = SslAlloc('KbuP', LMEM_FIXED | LMEM_ZEROINIT, EstimatedLength );
|
|
|
|
if ( !pBitString )
|
|
{
|
|
return( -1 );
|
|
}
|
|
|
|
PkResult = EncodeHeader( pBitString, EstimatedLength, TRUE );
|
|
|
|
pSave = pBitString;
|
|
|
|
pBitString += PkResult;
|
|
|
|
pSave2 = pBitString;
|
|
|
|
PkResult = EncodeInteger( pBitString, (PBYTE) (pKey + 1),
|
|
pKey->keylen, TRUE );
|
|
|
|
pBitString += PkResult;
|
|
|
|
PkResult = EncodeInteger( pBitString, (PBYTE) &pKey->pubexp,
|
|
sizeof( DWORD ), TRUE );
|
|
|
|
pBitString += PkResult;
|
|
|
|
PkResult = EncodeHeader( pSave, pBitString - pSave2, TRUE );
|
|
|
|
Result = EncodeBitString( pbEncoded, pSave, pBitString - pSave, TRUE );
|
|
|
|
pbEncoded += Result;
|
|
|
|
SslFree( pSave );
|
|
|
|
Result = EncodeHeader( pBuffer, pbEncoded - pTop, TRUE );
|
|
|
|
return( Result + (pbEncoded - pTop) );
|
|
}
|
|
|
|
|
|
BOOL
|
|
SslpEncodePublicKey(
|
|
BSAFE_PRV_KEY * pKey,
|
|
PSTR pszDN,
|
|
PUCHAR * ppBuffer,
|
|
DWORD * pcbBuffer )
|
|
{
|
|
BSAFE_KEY_PARTS parts;
|
|
PUCHAR pBuffer;
|
|
PUCHAR pbEncoded;
|
|
PUCHAR pSave;
|
|
int Result;
|
|
DWORD Zero;
|
|
DWORD BigLen;
|
|
DWORD ShortLen;
|
|
DWORD Length;
|
|
PUCHAR pSave2;
|
|
PCheckSumBuffer pCheck;
|
|
UCHAR Key[16];
|
|
UCHAR Signature[34]; // Room for the Prefix
|
|
PUCHAR pPub;
|
|
LONG PubRes;
|
|
LONG PubLen;
|
|
PUCHAR pPubEncoded;
|
|
PBYTE pBufferSave;
|
|
PBYTE pPubEncodedSave;
|
|
int ResultSave;
|
|
int LengthOfReqInfo;
|
|
|
|
ShortLen = EncodeDN( NULL, pszDN, FALSE );
|
|
|
|
|
|
Length = pKey->datalen + 32 + ShortLen + 16;
|
|
|
|
pBuffer = SslAlloc( 'KbuP', LMEM_FIXED | LMEM_ZEROINIT, Length );
|
|
pBufferSave = pBuffer;
|
|
|
|
if (! pBuffer)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
pbEncoded = pBuffer;
|
|
|
|
Result = EncodeHeader( pBuffer, Length, TRUE );
|
|
ResultSave = Result;
|
|
|
|
pbEncoded += Result;
|
|
|
|
pSave = pbEncoded;
|
|
|
|
Zero = 0;
|
|
|
|
Result = EncodeInteger(pbEncoded, (PBYTE) &Zero, 1, TRUE );
|
|
|
|
pbEncoded += Result;
|
|
|
|
Result = EncodeDN(pbEncoded, pszDN, TRUE );
|
|
|
|
pbEncoded += Result;
|
|
|
|
Result = SslpEncodeSubjectPubKeyInfo( pKey, pbEncoded);
|
|
|
|
if ( Result < 0)
|
|
{
|
|
SslFree( pBufferSave );
|
|
return( FALSE );
|
|
}
|
|
|
|
pbEncoded += Result;
|
|
|
|
Result = EncodeHeader( pBuffer, pbEncoded - pSave, TRUE );
|
|
|
|
if (Result != ResultSave)
|
|
{
|
|
pBuffer += ResultSave - Result;
|
|
Result = EncodeHeader( pBuffer, pbEncoded - pSave, TRUE );
|
|
}
|
|
|
|
//
|
|
LengthOfReqInfo = Result + (pbEncoded - pSave);
|
|
|
|
|
|
//
|
|
// Generate signature
|
|
//
|
|
|
|
ckMD5.Initialize(0, &pCheck);
|
|
ckMD5.Sum(pCheck, LengthOfReqInfo, pBuffer);
|
|
ckMD5.Finalize(pCheck, Key);
|
|
ckMD5.Finish(&pCheck);
|
|
|
|
CopyMemory( Signature, bMD5SigPrefix, sizeof(bMD5SigPrefix) );
|
|
CopyMemory( Signature + sizeof(bMD5SigPrefix), Key, 16);
|
|
|
|
//
|
|
// How much space do we need?
|
|
//
|
|
|
|
PubLen = LengthOfReqInfo + pKey->datalen + 32;
|
|
pPubEncoded = SslAlloc( 'KbuP', LMEM_FIXED | LMEM_ZEROINIT, PubLen );
|
|
|
|
if ( !pPubEncoded )
|
|
{
|
|
SslFree( pBufferSave );
|
|
return( FALSE );
|
|
}
|
|
|
|
Result = EncodeHeader( pPubEncoded, PubLen, TRUE );
|
|
|
|
pPubEncodedSave = pPubEncoded;
|
|
|
|
pSave2 = pPubEncoded;
|
|
|
|
ResultSave = Result;
|
|
|
|
pPubEncoded += Result;
|
|
|
|
pSave = pPubEncoded;
|
|
|
|
CopyMemory( pPubEncoded, pBuffer, LengthOfReqInfo );
|
|
|
|
pPubEncoded += LengthOfReqInfo;
|
|
|
|
Result = EncodeAlgorithm( pPubEncoded, MD5_WITH_RSA, TRUE );
|
|
|
|
pPubEncoded += Result;
|
|
|
|
//
|
|
// pBufferSave has the real pointer
|
|
//
|
|
|
|
pBuffer = SslAlloc( 'KbuP', LMEM_FIXED | LMEM_ZEROINIT, pKey->datalen + 16 );
|
|
|
|
Result = pKey->datalen + 16;
|
|
|
|
PkcsPrivateEncrypt( Signature, sizeof(Signature),
|
|
pKey,
|
|
NETWORK_ORDER,
|
|
pBuffer, &Result);
|
|
|
|
|
|
PubRes = EncodeBitString( pPubEncoded, pBuffer, Result, TRUE );
|
|
|
|
pPubEncoded += PubRes;
|
|
|
|
Result = EncodeHeader( pSave2, (pPubEncoded - pSave), TRUE );
|
|
|
|
if (Result != ResultSave)
|
|
{
|
|
if (Result > ResultSave)
|
|
{
|
|
//
|
|
// Yuck. The chunk has actually grown from the estimate.
|
|
//
|
|
|
|
*ppBuffer = SslAlloc('KbuP', LMEM_FIXED, (pPubEncoded - pSave) + Result);
|
|
if (*ppBuffer)
|
|
{
|
|
EncodeHeader(*ppBuffer, (pPubEncoded - pSave), TRUE );
|
|
CopyMemory( *ppBuffer + Result,
|
|
pSave,
|
|
(pPubEncoded - pSave) );
|
|
|
|
SslFree( pSave2 );
|
|
pSave2 = *ppBuffer;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
pSave2++;
|
|
Result = EncodeHeader( pSave2, (pPubEncoded - pSave), TRUE );
|
|
|
|
}
|
|
}
|
|
|
|
*ppBuffer = pSave2;
|
|
|
|
*pcbBuffer = Result + (pPubEncoded - pSave);
|
|
|
|
SslFree( pBuffer );
|
|
SslFree( pBufferSave );
|
|
|
|
return( TRUE );
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
SslGenerateKeyPair(
|
|
PSSL_CREDENTIAL_CERTIFICATE pCerts,
|
|
PSTR pszDN,
|
|
PSTR pszPassword,
|
|
DWORD Bits )
|
|
{
|
|
DWORD BitsCopy;
|
|
DWORD dwPrivateSize;
|
|
DWORD dwPublicSize;
|
|
BSAFE_PRV_KEY * pPrivate;
|
|
BSAFE_PUB_KEY * pPublic;
|
|
|
|
|
|
BitsCopy = Bits;
|
|
BSafeComputeKeySizes( &dwPublicSize, &dwPrivateSize, &BitsCopy );
|
|
|
|
pPrivate = SslAlloc( 'riaP', LMEM_FIXED | LMEM_ZEROINIT, dwPrivateSize );
|
|
pPublic = SslAlloc( 'riaP', LMEM_FIXED | LMEM_ZEROINIT, dwPublicSize );
|
|
|
|
if (!pPrivate || !pPublic)
|
|
{
|
|
if (pPrivate)
|
|
{
|
|
SslFree( pPrivate );
|
|
}
|
|
|
|
if (pPublic)
|
|
{
|
|
SslFree( pPublic );
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
if (!BSafeMakeKeyPair(pPublic, pPrivate, Bits ) )
|
|
{
|
|
SslFree( pPrivate );
|
|
SslFree( pPublic );
|
|
return( FALSE );
|
|
}
|
|
|
|
//
|
|
// Ah yes, now to encode them...
|
|
//
|
|
|
|
//
|
|
// First, the private key. Why? Well, it's at least straight-forward
|
|
//
|
|
|
|
if (!SslpEncodePrivateKey(pPrivate, dwPrivateSize, pszPassword,
|
|
&pCerts->pPrivateKey, &pCerts->cbPrivateKey ) )
|
|
{
|
|
SslFree( pPrivate );
|
|
SslFree( pPublic );
|
|
return( FALSE );
|
|
|
|
}
|
|
|
|
if (!SslpEncodePublicKey(pPrivate, pszDN, &pCerts->pCertificate,
|
|
&pCerts->cbCertificate) )
|
|
{
|
|
SslFree( pPrivate );
|
|
SslFree( pPublic );
|
|
SslFree( pCerts->pPrivateKey );
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|