//+--------------------------------------------------------------------------- // // 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 "pctsspi.h" #include "encode.h" #include "bulk.h" #define PRIVATE_KEY_TEXT "private-key" UCHAR RsaSecureServer[] = { 0x00, 0x00, 0x00, 0x00, // Magic 0x00, 0x00, 0x00, 0x00, // Key len 0x00, 0x00, 0x00, 0x00, // bitlen 0x00, 0x00, 0x00, 0x00, // datalen 0x01, 0x00, 0x01, 0x00, // exponent 0x7b, 0x1e, 0xc8, 0xd6, 0x2d, 0xdd, 0xe5, 0x48, 0x67, 0x70, 0x6d, 0x9c, 0x39, 0x97, 0xb1, 0x82, 0x69, 0x3a, 0x73, 0x2c, 0x54, 0x49, 0xd5, 0x15, 0x1e, 0x9c, 0x59, 0x11, 0x4a, 0x2e, 0x13, 0x1a, 0x29, 0xa7, 0x1d, 0xb9, 0x48, 0x98, 0x56, 0x89, 0x50, 0xe3, 0x4c, 0x77, 0x9b, 0x3e, 0x76, 0x71, 0x13, 0x70, 0x65, 0x07, 0x84, 0x6d, 0x59, 0x81, 0xf7, 0x8f, 0x07, 0x88, 0x6c, 0x56, 0x22, 0x66, 0x25, 0x4b, 0xc9, 0x4b, 0xa2, 0x05, 0x9a, 0x81, 0x68, 0x76, 0xad, 0x02, 0x21, 0xb1, 0xe9, 0x55, 0x37, 0x86, 0x16, 0xd2, 0x08, 0x82, 0x8a, 0xe2, 0x08, 0x8f, 0xbf, 0xc9, 0x51, 0x40, 0x84, 0xe5, 0x03, 0x54, 0x64, 0x78, 0x35, 0xeb, 0xce, 0x37, 0x2c, 0x8e, 0xae, 0xad, 0x0c, 0x76, 0x01, 0x25, 0xac, 0x57, 0x83, 0x89, 0xaa, 0x5a, 0x3e, 0x83, 0xae, 0xc1, 0x7a, 0xce, 0x92, 0x00, 0x00, 0x00 }; UCHAR NetscapeTestKey[] = { 0x00, 0x00, 0x00, 0x00, // Magic 0x00, 0x00, 0x00, 0x00, // Key len 0x00, 0x00, 0x00, 0x00, // bitlen 0x00, 0x00, 0x00, 0x00, // datalen 0x03, 0x00, 0x00, 0x00, // exponent 0x63, 0x16, 0xcc, 0xd3, 0x9c, 0x5f, 0x3e, 0x1a, 0x40, 0xd2, 0x4e, 0x77, 0xe0, 0x00, 0x09, 0xfd, 0x68, 0x15, 0x87, 0x68, 0x0b, 0x2d, 0x29, 0x2a, 0x3f, 0x40, 0xcb, 0x1f, 0x61, 0x33, 0x8e, 0xd5, 0x96, 0xb3, 0x28, 0xcf, 0x94, 0x58, 0xde, 0xfc, 0x74, 0xbd, 0x33, 0xdb, 0xb9, 0x09, 0x3e, 0x67, 0x36, 0xa7, 0xdd, 0xdd, 0x16, 0xe0, 0xbd, 0x16, 0x0e, 0x52, 0xcb, 0xb8, 0xe1, 0xb7, 0x16, 0xa0, 0x45, 0xa7, 0xff, 0x65, 0xc9, 0xb8, 0x8a, 0x59, 0x12, 0x37, 0x6b, 0x7d, 0x21, 0x4a, 0x4a, 0x48, 0x21, 0xbf, 0x4e, 0x6a, 0xa3, 0x95, 0x34, 0xa0, 0xc1, 0x32, 0xa7, 0xf0, 0xde, 0x56, 0x15, 0xad, 0x60, 0xc3, 0x14, 0xe6, 0x07, 0x51, 0x7c, 0xfe, 0x2a, 0x02, 0x50, 0x13, 0x5b, 0x82, 0xb2, 0x9b, 0xdf, 0x2d, 0x15, 0x81, 0xe9, 0xcb, 0x3c, 0xa1, 0x72, 0x7b, 0x18, 0xba, 0xec, 0x8a, 0x6c, 0xb4, 0x00, 0x00, 0x00, 0x00 }; BSAFE_PUB_KEY * pRsaSecureServer; BSAFE_PUB_KEY * pNetscapeTestKey; typedef struct _KnownKey { PSTR pszIssuer; BSAFE_PUB_KEY * pKey; } KnownKey, * PKnownKey; KnownKey PctKnownKeys[] = { {"C=US, O=RSA Data Security, Inc., OU=Secure Server Certification Authority", NULL }, {"C=US, OU=Test CA, O=Netscape Communications Corp.", NULL} }; VOID InitializeWellKnownKeys( VOID ) { pRsaSecureServer = (BSAFE_PUB_KEY *) RsaSecureServer; pRsaSecureServer->magic = RSA1; pRsaSecureServer->bitlen = 16 * 8 * 8; pRsaSecureServer->keylen = 16 * 8 + 8; pRsaSecureServer->datalen = 16 * 8 - 1; PctKnownKeys[0].pKey = pRsaSecureServer; pNetscapeTestKey = (BSAFE_PUB_KEY *) NetscapeTestKey; pNetscapeTestKey->magic = RSA1; pNetscapeTestKey->bitlen = 16 * 8 * 8; pNetscapeTestKey->keylen = 16 * 8 + 8; pNetscapeTestKey->datalen = 16 * 8 - 1; PctKnownKeys[1].pKey = pNetscapeTestKey; } BSAFE_PUB_KEY * FindIssuerKey( PSTR pszIssuer) { DWORD i; for (i = 0; i < sizeof(PctKnownKeys) / sizeof(KnownKey) ; i++ ) { if (_stricmp(pszIssuer, PctKnownKeys[i].pszIssuer) == 0) { return(PctKnownKeys[i].pKey); } } return( NULL ); } BOOL PctpEncodePrivateKey( 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 = LocalAlloc( 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 = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, Length + 64 ); if (!pSequence) { LocalFree( 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; LocalFree( pBuffer ); pBuffer = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, Length + 128); if (!pBuffer) { LocalFree( 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 ); LocalFree( 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 ); DebugLog((DEB_TRACE, "Encoded private key\n")); return( TRUE ); } BOOL PctGenerateKeyPair( PPCT_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 = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, dwPrivateSize ); pPublic = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, dwPublicSize ); if (!pPrivate || !pPublic) { if (pPrivate) { LocalFree( pPrivate ); } if (pPublic) { LocalFree( pPublic ); } return( FALSE ); } if (!BSafeMakeKeyPair(pPublic, pPrivate, Bits ) ) { LocalFree( pPrivate ); LocalFree( pPublic ); return( FALSE ); } // // Ah yes, now to encode them... // // // First, the private key. Why? Well, it's at least straight-forward // if (!PctpEncodePrivateKey(pPrivate, dwPrivateSize, pszPassword, &pCerts->pPrivateKey, &pCerts->cbPrivateKey ) ) { LocalFree( pPrivate ); LocalFree( pPublic ); return( FALSE ); } }