|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1998 - 1999
//
// File: selfsign.cpp
//
//--------------------------------------------------------------------------
#include "global.hxx"
#include <dbgdef.h>
PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate( IN HCRYPTPROV hProv, IN PCERT_NAME_BLOB pSubjectIssuerBlob, IN DWORD dwFlags, OPTIONAL PCRYPT_KEY_PROV_INFO pKeyProvInfo, OPTIONAL PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, OPTIONAL PSYSTEMTIME pStartTime, OPTIONAL PSYSTEMTIME pEndTime, OPTIONAL PCERT_EXTENSIONS pExtensions ) {
PCCERT_CONTEXT pCertContext = NULL; DWORD errBefore = GetLastError(); DWORD err = ERROR_SUCCESS; DWORD cbPubKeyInfo = 0; PCERT_PUBLIC_KEY_INFO pPubKeyInfo = NULL; BYTE * pbCert = NULL; DWORD cbCert = 0; LPSTR sz = NULL; DWORD cb = 0; BYTE * pbToBeSigned = NULL; BYTE * pbSignature = NULL;
CERT_INFO certInfo; GUID serialNbr; CRYPT_KEY_PROV_INFO keyProvInfo; CERT_SIGNED_CONTENT_INFO sigInfo; CRYPT_ALGORITHM_IDENTIFIER algID;
LPWSTR wsz = NULL; BOOL fFreehProv = FALSE; HCRYPTKEY hKey = NULL; UUID guidContainerName; RPC_STATUS RpcStatus;
memset(&certInfo, 0, sizeof(CERT_INFO)); memset(&serialNbr, 0, sizeof(serialNbr)); memset(&keyProvInfo, 0, sizeof(CRYPT_KEY_PROV_INFO)); memset(&sigInfo, 0, sizeof(CERT_SIGNED_CONTENT_INFO));
// do key spec now because we need it
if(pKeyProvInfo == NULL) keyProvInfo.dwKeySpec = AT_SIGNATURE; else keyProvInfo.dwKeySpec = pKeyProvInfo->dwKeySpec;
// see if we have an hProv, if not, create one
if(hProv == NULL) {
fFreehProv = TRUE;
// if not prov info, make one up, signing RSA cert, default provider
if(pKeyProvInfo == NULL) {
RpcStatus = UuidCreate(&guidContainerName); if (!(RPC_S_OK == RpcStatus || RPC_S_UUID_LOCAL_ONLY == RpcStatus)) { // Use stack randomness
; }
// note: unlike UUidToString, always must LocalFree() returned memory
UuidToStringU(&guidContainerName, &wsz); if( !CryptAcquireContextU( &hProv, wsz, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET) ) { hProv = NULL; goto ErrorCryptAcquireContext; } } else {
// first use the existing keyset
if( !CryptAcquireContextU( &hProv, pKeyProvInfo->pwszContainerName, pKeyProvInfo->pwszProvName, pKeyProvInfo->dwProvType, pKeyProvInfo->dwFlags) ) {
// otherwise generate a keyset
if( !CryptAcquireContextU( &hProv, pKeyProvInfo->pwszContainerName, pKeyProvInfo->pwszProvName, pKeyProvInfo->dwProvType, pKeyProvInfo->dwFlags | CRYPT_NEWKEYSET) ) { hProv = NULL; goto ErrorCryptAcquireContext; } } }
// we have the keyset, now make sure we have the key gen'ed
if( !CryptGetUserKey( hProv, keyProvInfo.dwKeySpec, &hKey) ) {
// doesn't exist so gen it
assert(hKey == NULL); if(!CryptGenKey( hProv, keyProvInfo.dwKeySpec, 0, &hKey) ) { goto ErrorCryptGenKey; } } }
// get the exportable public key bits
if( !CryptExportPublicKeyInfo( hProv, keyProvInfo.dwKeySpec, X509_ASN_ENCODING, NULL, &cbPubKeyInfo) || (pPubKeyInfo = (PCERT_PUBLIC_KEY_INFO) PkiNonzeroAlloc(cbPubKeyInfo)) == NULL || !CryptExportPublicKeyInfo( hProv, keyProvInfo.dwKeySpec, X509_ASN_ENCODING, pPubKeyInfo, &cbPubKeyInfo) ) goto ErrorCryptExportPublicKeyInfo;
// default if we don't have an algid
if(pSignatureAlgorithm == NULL) { memset(&algID, 0, sizeof(algID)); algID.pszObjId = szOID_OIWSEC_sha1RSASign; pSignatureAlgorithm = &algID; }
// make a temp cert, only care about key info
// and serial number for uniqueness
RpcStatus = UuidCreate(&serialNbr); if (!(RPC_S_OK == RpcStatus || RPC_S_UUID_LOCAL_ONLY == RpcStatus)) { // Use stack randomness.
; } certInfo.dwVersion = CERT_V3; certInfo.SubjectPublicKeyInfo = *pPubKeyInfo; certInfo.SerialNumber.cbData = sizeof(serialNbr); certInfo.SerialNumber.pbData = (BYTE *) &serialNbr; certInfo.SignatureAlgorithm = *pSignatureAlgorithm; certInfo.Issuer = *pSubjectIssuerBlob; certInfo.Subject = *pSubjectIssuerBlob;
// only put in extensions if we have them
if( pExtensions != NULL) { certInfo.cExtension = pExtensions->cExtension; certInfo.rgExtension = pExtensions->rgExtension; }
//default if we don't have times
if(pStartTime == NULL) GetSystemTimeAsFileTime(&certInfo.NotBefore); else if(!SystemTimeToFileTime(pStartTime, &certInfo.NotBefore)) goto ErrorSystemTimeToFileTime;
if(pEndTime == NULL) *(((DWORDLONG UNALIGNED *) &certInfo.NotAfter)) = *(((DWORDLONG UNALIGNED *) &certInfo.NotBefore)) + 0x11F03C3613000i64; else if(!SystemTimeToFileTime(pEndTime, &certInfo.NotAfter)) goto ErrorSystemTimeToFileTime; // encode the cert
if( !CryptEncodeObject( CRYPT_ASN_ENCODING, X509_CERT_TO_BE_SIGNED, &certInfo, NULL, // pbEncoded
&sigInfo.ToBeSigned.cbData ) || (pbToBeSigned = (BYTE *) PkiNonzeroAlloc(sigInfo.ToBeSigned.cbData)) == NULL || !CryptEncodeObject( CRYPT_ASN_ENCODING, X509_CERT_TO_BE_SIGNED, &certInfo, pbToBeSigned, &sigInfo.ToBeSigned.cbData ) ) goto ErrorEncodeTempCertToBeSigned; sigInfo.ToBeSigned.pbData = pbToBeSigned;
// sign the certificate
sigInfo.SignatureAlgorithm = certInfo.SignatureAlgorithm;
// this is to work around an OSS bug of not accepting zero length bit strings
// this is only needed if we don't actually sign the code.
sigInfo.Signature.pbData = (BYTE *) &sigInfo; sigInfo.Signature.cbData = 1; if( (CERT_CREATE_SELFSIGN_NO_SIGN & dwFlags) == 0 ) { if( !CryptSignCertificate( hProv, keyProvInfo.dwKeySpec, CRYPT_ASN_ENCODING, sigInfo.ToBeSigned.pbData, sigInfo.ToBeSigned.cbData, &sigInfo.SignatureAlgorithm, NULL, NULL, &sigInfo.Signature.cbData) || (pbSignature = (BYTE *) PkiNonzeroAlloc(sigInfo.Signature.cbData)) == NULL || !CryptSignCertificate( hProv, keyProvInfo.dwKeySpec, CRYPT_ASN_ENCODING, sigInfo.ToBeSigned.pbData, sigInfo.ToBeSigned.cbData, &sigInfo.SignatureAlgorithm, NULL, pbSignature, &sigInfo.Signature.cbData) ) goto ErrorCryptSignCertificate; sigInfo.Signature.pbData = pbSignature; } // encode the final cert.
if( !CryptEncodeObject( CRYPT_ASN_ENCODING, X509_CERT, &sigInfo, NULL, &cbCert ) || (pbCert = (BYTE *) PkiNonzeroAlloc(cbCert)) == NULL || !CryptEncodeObject( CRYPT_ASN_ENCODING, X509_CERT, &sigInfo, pbCert, &cbCert ) ) goto ErrorEncodeTempCert;
// get a cert context from the encoding
if( (pCertContext = CertCreateCertificateContext( CRYPT_ASN_ENCODING, pbCert, cbCert)) == NULL ) goto ErrorCreateTempCertContext;
if( (CERT_CREATE_SELFSIGN_NO_KEY_INFO & dwFlags) == 0 ) { // get the key prov info
if(pKeyProvInfo == NULL) { // get a key prov info from the hProv
if( !CryptGetProvParam( hProv, PP_NAME, NULL, &cb, 0) || (sz = (char *) PkiNonzeroAlloc(cb)) == NULL || !CryptGetProvParam( hProv, PP_NAME, (BYTE *) sz, &cb, 0) ) goto ErrorGetProvName; keyProvInfo.pwszProvName = MkWStr(sz); PkiFree(sz); sz = NULL;
cb = 0; if( !CryptGetProvParam( hProv, PP_CONTAINER, NULL, &cb, 0) || (sz = (char *) PkiNonzeroAlloc(cb)) == NULL || !CryptGetProvParam( hProv, PP_CONTAINER, (BYTE *) sz, &cb, 0) ) goto ErrorGetContainerName; keyProvInfo.pwszContainerName = MkWStr(sz);
cb = sizeof(keyProvInfo.dwProvType); if( !CryptGetProvParam( hProv, PP_PROVTYPE, (BYTE *) &keyProvInfo.dwProvType, &cb, 0) ) goto ErrorGetProvType; pKeyProvInfo = &keyProvInfo; }
// put the key property on the certificate
if( !CertSetCertificateContextProperty( pCertContext, CERT_KEY_PROV_INFO_PROP_ID, 0, pKeyProvInfo) ) goto ErrorSetTempCertPropError; } CommonReturn:
if(hKey != NULL) CryptDestroyKey(hKey); if(fFreehProv && hProv != NULL) CryptReleaseContext(hProv, 0); if(keyProvInfo.pwszProvName != NULL) FreeWStr(keyProvInfo.pwszProvName);
if(keyProvInfo.pwszContainerName != NULL) FreeWStr(keyProvInfo.pwszContainerName);
if(wsz != NULL) LocalFree(wsz);
PkiFree(pPubKeyInfo); PkiFree(pbToBeSigned); PkiFree(pbSignature); PkiFree(pbCert); PkiFree(sz);
// don't know if we have an error or not
// but I do know the errBefore is set properly
SetLastError(errBefore);
return(pCertContext);
ErrorReturn:
if(GetLastError() == ERROR_SUCCESS) SetLastError((DWORD) E_UNEXPECTED); err = GetLastError();
// We have an error, make sure we set it.
errBefore = GetLastError();
if(pCertContext != NULL) CertFreeCertificateContext(pCertContext); pCertContext = NULL;
goto CommonReturn;
TRACE_ERROR(ErrorCryptGenKey); TRACE_ERROR(ErrorCryptAcquireContext); TRACE_ERROR(ErrorCryptExportPublicKeyInfo); TRACE_ERROR(ErrorEncodeTempCertToBeSigned); TRACE_ERROR(ErrorEncodeTempCert); TRACE_ERROR(ErrorCreateTempCertContext); TRACE_ERROR(ErrorGetProvName); TRACE_ERROR(ErrorGetContainerName); TRACE_ERROR(ErrorGetProvType); TRACE_ERROR(ErrorSetTempCertPropError); TRACE_ERROR(ErrorCryptSignCertificate); TRACE_ERROR(ErrorSystemTimeToFileTime); }
|