324 lines
7.8 KiB
C
324 lines
7.8 KiB
C
//+---------------------------------------------------------------------------
|
|
//
|
|
// 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 "spbase.h"
|
|
#include <oidenc.h>
|
|
|
|
#include <rsa.h>
|
|
|
|
#define SCHANNEL_GENKEY_NAME "SchannelGenKey"
|
|
|
|
BOOL
|
|
GenerateKeyPair(
|
|
PSSL_CREDENTIAL_CERTIFICATE pCerts,
|
|
PSTR pszDN,
|
|
PSTR pszPassword,
|
|
DWORD Bits)
|
|
{
|
|
|
|
BOOL fRet = FALSE;
|
|
DWORD BitsCopy;
|
|
DWORD dwPrivateSize;
|
|
DWORD dwPublicSize;
|
|
MD5_CTX md5Ctx;
|
|
struct RC4_KEYSTRUCT rc4Key;
|
|
|
|
BLOBHEADER *pCapiPrivate = NULL;
|
|
BLOBHEADER *pCapiPublic = NULL;
|
|
|
|
PRIVATE_KEY_FILE_ENCODE PrivateEncode;
|
|
CERT_REQUEST_INFO Req;
|
|
|
|
CRYPT_ALGORITHM_IDENTIFIER SignAlg;
|
|
|
|
HCRYPTPROV hProv = 0;
|
|
HCRYPTKEY hKey = 0;
|
|
|
|
if(!SchannelInit(TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
pCerts->pPrivateKey = NULL;
|
|
Req.SubjectPublicKeyInfo.PublicKey.pbData = NULL;
|
|
Req.Subject.pbData = NULL;
|
|
pCerts->pCertificate = NULL;
|
|
|
|
CryptAcquireContext(&hProv, SCHANNEL_GENKEY_NAME, NULL, PROV_RSA_FULL, CRYPT_DELETEKEYSET);
|
|
|
|
if(!CryptAcquireContext(&hProv, SCHANNEL_GENKEY_NAME, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
if(!CryptGenKey(hProv, CALG_RSA_SIGN, (Bits << 16) | CRYPT_EXPORTABLE, &hKey))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
if(!CryptExportKey(hKey, 0, PRIVATEKEYBLOB, 0, NULL, &dwPrivateSize))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
pCapiPrivate = (BLOBHEADER *)SPExternalAlloc(dwPrivateSize);
|
|
if(!CryptExportKey(hKey, 0, PRIVATEKEYBLOB, 0, (PBYTE)pCapiPrivate, &dwPrivateSize))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
|
|
if(!CryptExportKey(hKey, 0, PUBLICKEYBLOB, 0, NULL, &dwPublicSize))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
pCapiPublic = (BLOBHEADER *)SPExternalAlloc(dwPublicSize);
|
|
if(!CryptExportKey(hKey, 0, PUBLICKEYBLOB, 0, (PBYTE)pCapiPublic, &dwPublicSize))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
// Encode the private key into a
|
|
// priavate key blob.
|
|
if(!CryptEncodeObject(X509_ASN_ENCODING,
|
|
szPrivateKeyInfoEncode,
|
|
pCapiPrivate,
|
|
NULL,
|
|
&PrivateEncode.EncryptedBlob.cbData))
|
|
{
|
|
goto error;
|
|
}
|
|
PrivateEncode.EncryptedBlob.pbData = SPExternalAlloc(PrivateEncode.EncryptedBlob.cbData);
|
|
if(PrivateEncode.EncryptedBlob.pbData == NULL)
|
|
{
|
|
goto error;
|
|
}
|
|
if(!CryptEncodeObject(X509_ASN_ENCODING,
|
|
szPrivateKeyInfoEncode,
|
|
pCapiPrivate,
|
|
PrivateEncode.EncryptedBlob.pbData,
|
|
&PrivateEncode.EncryptedBlob.cbData))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
// Okay, now encrypt this
|
|
MD5Init(&md5Ctx);
|
|
MD5Update(&md5Ctx, pszPassword, lstrlen(pszPassword));
|
|
MD5Final(&md5Ctx);
|
|
|
|
rc4_key(&rc4Key, 16, md5Ctx.digest);
|
|
ZeroMemory(&md5Ctx, sizeof(md5Ctx));
|
|
|
|
rc4(&rc4Key,
|
|
PrivateEncode.EncryptedBlob.cbData,
|
|
PrivateEncode.EncryptedBlob.pbData);
|
|
ZeroMemory(&rc4Key, sizeof(rc4Key));
|
|
|
|
//
|
|
PrivateEncode.Alg.pszObjId = szOID_RSA_ENCRYPT_RC4_MD5;
|
|
PrivateEncode.Alg.Parameters.pbData = NULL;
|
|
PrivateEncode.Alg.Parameters.cbData = 0;
|
|
|
|
|
|
// Ah yes, now to encode them...
|
|
//
|
|
// First, the private key. Why? Well, it's at least straight-forward
|
|
// First, get the size of the private key encode...
|
|
if(!CryptEncodeObject(X509_ASN_ENCODING,
|
|
szPrivateKeyFileEncode,
|
|
&PrivateEncode,
|
|
NULL,
|
|
&pCerts->cbPrivateKey))
|
|
{
|
|
goto error;
|
|
}
|
|
pCerts->pPrivateKey = SPExternalAlloc(pCerts->cbPrivateKey);
|
|
|
|
if(!CryptEncodeObject(X509_ASN_ENCODING,
|
|
szPrivateKeyFileEncode,
|
|
&PrivateEncode,
|
|
pCerts->pPrivateKey,
|
|
&pCerts->cbPrivateKey))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
|
|
SPExternalFree(PrivateEncode.EncryptedBlob.pbData);
|
|
|
|
// Create the Req structure so we can encode it.
|
|
Req.dwVersion = CERT_REQUEST_V1;
|
|
|
|
// Initialize the PublicKeyInfo
|
|
Req.SubjectPublicKeyInfo.Algorithm.pszObjId = szOID_RSA_RSA;
|
|
Req.SubjectPublicKeyInfo.Algorithm.Parameters.cbData = 0;
|
|
Req.SubjectPublicKeyInfo.Algorithm.Parameters.pbData = NULL;
|
|
|
|
Req.SubjectPublicKeyInfo.PublicKey.cbData;
|
|
|
|
|
|
// Encode the public key info
|
|
if(!CryptEncodeObject(X509_ASN_ENCODING,
|
|
szOID_RSA_RSA_Public,
|
|
pCapiPublic,
|
|
NULL,
|
|
&Req.SubjectPublicKeyInfo.PublicKey.cbData))
|
|
{
|
|
goto error;
|
|
}
|
|
Req.SubjectPublicKeyInfo.PublicKey.pbData =
|
|
SPExternalAlloc(Req.SubjectPublicKeyInfo.PublicKey.cbData);
|
|
|
|
if(Req.SubjectPublicKeyInfo.PublicKey.pbData == NULL)
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
// Encode the public key info
|
|
if(!CryptEncodeObject(X509_ASN_ENCODING,
|
|
szOID_RSA_RSA_Public,
|
|
pCapiPublic,
|
|
Req.SubjectPublicKeyInfo.PublicKey.pbData,
|
|
&Req.SubjectPublicKeyInfo.PublicKey.cbData))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
Req.SubjectPublicKeyInfo.PublicKey.cUnusedBits = 0;
|
|
|
|
// Encode the name
|
|
Req.Subject.cbData = EncodeDN(NULL, pszDN, FALSE);
|
|
if((LONG)Req.Subject.cbData < 0)
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
Req.Subject.pbData = SPExternalAlloc(Req.Subject.cbData);
|
|
|
|
if(Req.Subject.pbData== NULL)
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
Req.Subject.cbData = EncodeDN(Req.Subject.pbData, pszDN, TRUE);
|
|
|
|
if((LONG)Req.Subject.cbData < 0)
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
|
|
// Attributes
|
|
Req.cAttribute = 0;
|
|
Req.rgAttribute = NULL;
|
|
|
|
SignAlg.pszObjId = szOID_RSA_MD5RSA;
|
|
SignAlg.Parameters.cbData = 0;
|
|
SignAlg.Parameters.pbData = NULL;
|
|
|
|
// Encode the public key info
|
|
if(!CryptSignAndEncodeCertificate(
|
|
hProv,
|
|
AT_SIGNATURE,
|
|
X509_ASN_ENCODING,
|
|
X509_CERT_REQUEST_TO_BE_SIGNED,
|
|
&Req,
|
|
&SignAlg,
|
|
NULL,
|
|
NULL,
|
|
&pCerts->cbCertificate))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
pCerts->pCertificate = SPExternalAlloc(pCerts->cbCertificate);
|
|
if(pCerts->pCertificate == NULL)
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
// Encode the public key info
|
|
if(!CryptSignAndEncodeCertificate(
|
|
hProv,
|
|
AT_SIGNATURE,
|
|
X509_ASN_ENCODING,
|
|
X509_CERT_REQUEST_TO_BE_SIGNED,
|
|
&Req,
|
|
&SignAlg,
|
|
NULL,
|
|
pCerts->pCertificate,
|
|
&pCerts->cbCertificate))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
fRet = TRUE;
|
|
|
|
goto cleanup;
|
|
|
|
error:
|
|
if(pCerts->pPrivateKey)
|
|
{
|
|
SPExternalFree(pCerts->pPrivateKey);
|
|
}
|
|
|
|
if(pCerts->pCertificate)
|
|
{
|
|
SPExternalFree(pCerts->pCertificate);
|
|
}
|
|
|
|
|
|
cleanup:
|
|
if(pCapiPrivate)
|
|
{
|
|
SPExternalFree(pCapiPrivate);
|
|
}
|
|
|
|
if(pCapiPublic)
|
|
{
|
|
SPExternalFree(pCapiPublic);
|
|
}
|
|
|
|
|
|
if(Req.SubjectPublicKeyInfo.PublicKey.pbData)
|
|
{
|
|
SPExternalFree(Req.SubjectPublicKeyInfo.PublicKey.pbData);
|
|
}
|
|
|
|
if(Req.Subject.pbData)
|
|
{
|
|
SPExternalFree(Req.Subject.pbData);
|
|
}
|
|
|
|
|
|
if(hKey != 0)
|
|
{
|
|
CryptDestroyKey(hKey);
|
|
}
|
|
|
|
if(hProv != 0)
|
|
{
|
|
|
|
CryptReleaseContext(hProv,0);
|
|
CryptAcquireContext(&hProv, SCHANNEL_GENKEY_NAME, NULL, PROV_RSA_FULL, CRYPT_DELETEKEYSET);
|
|
}
|
|
return(fRet);
|
|
}
|