Windows NT 4.0 source code leak
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

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