|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1997 - 1999
//
// File: makecert.cpp
//
//--------------------------------------------------------------------------
//+-------------------------------------------------------------------------
//
// MakeCert - x509 certificate generator
//
// Generates test certificates for Software Publishers. The default
// root key and certificate is stored as a program resource.
//
// HansHu 2/20/96 created
// Philh 5/17/96 changed to use wincert
// Xiaohs 5/12/97 localization and change the command line options
//
//--------------------------------------------------------------------------
#define _CRYPT32_
#include "global.hxx"
//+-------------------------------------------------------------------------
// contants
//--------------------------------------------------------------------------
//allow max 10 extensions per certificate
#define MAX_EXT_CNT 10
//+-------------------------------------------------------------------------
// Parameters configurable via command line arguments
//--------------------------------------------------------------------------
BOOL fUseSubjectPvkFile = FALSE; BOOL fUseSubjectKeyContainer = FALSE; BOOL fUseIssuerPvkFile = FALSE; BOOL fSetSubjectName = FALSE; //use has specify the -n option
#if (1) //DSIE: Bug 205195
BOOL fPrivateKeyExportable = FALSE; #endif
WCHAR* wszSubjectKey = NULL; WCHAR* wszSubjectCertFile = NULL; WCHAR* wszSubjectStore = NULL; WCHAR* wszSubjectStoreLocation = NULL; DWORD dwSubjectStoreFlag = CERT_SYSTEM_STORE_CURRENT_USER;
WCHAR* wszIssuerKey = NULL; WCHAR* wszIssuerCertFile = NULL; WCHAR* wszIssuerStore = NULL; WCHAR* wszIssuerStoreLocation = NULL; DWORD dwIssuerStoreFlag = CERT_SYSTEM_STORE_CURRENT_USER; WCHAR* wszIssuerCertName = NULL; DWORD dwIssuerKeySpec = 0;
WCHAR* wszSubjectX500Name = NULL; WCHAR* wszSubjectRequestFile = NULL; WCHAR* wszPolicyLink = NULL; WCHAR* wszOutputFile = NULL; WCHAR* wszAuthority = NULL; WCHAR* wszAlgorithm = NULL; WCHAR* wszCertType = NULL; WCHAR* wszIssuerKeyType = NULL; WCHAR* wszSubjectKeyType = NULL; WCHAR* wszEKUOids = NULL;
DWORD dwKeySpec = 0; BOOL fCertIndividual = FALSE; BOOL fCertCommercial = FALSE; BOOL fSelfSigned = FALSE; BOOL fGlueCert = FALSE; BOOL fNetscapeClientAuth = FALSE; BOOL fNoPubKeyPara = FALSE; BOOL fNoVerifyPublic = FALSE; LPWSTR wszIssuerProviderName = NULL; DWORD dwIssuerProviderType = PROV_RSA_FULL; LPWSTR wszSubjectProviderName = NULL; DWORD dwSubjectProviderType = PROV_RSA_FULL; ALG_ID algidHash = CALG_MD5; ULONG ulSerialNumber = 0; // In future, allow serial nubmers of larger size
BOOL fSetSerialNumber = FALSE; DWORD dwCertStoreEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING; BOOL fIssuerInformation = FALSE; BOOL fSubjectInformation = FALSE;
LPWSTR wszDhParaCertFile = NULL; DWORD dwKeyBitLen = 0;
WCHAR wszGlue[10]; WCHAR wszKey[10]; WCHAR wszName[40]; WCHAR wszRoot[40]; WCHAR wszMakeCertRoot[40]; //used for indicating to use the root.cer. Root is also a registry name
WCHAR wszPlus[10]; WCHAR wszNULL[10];
FILETIME g_ftNotBefore = { 0, 0 }; FILETIME g_ftNotAfter = { 0, 0 }; FILETIME g_ftZero = { 0, 0 }; long nMonths = -1;
long pathLenConstraint = -1; BYTE certTypes = 0; // must be of type BYTE
CHAR* szSignatureAlgObjId = NULL;
static CERT_RDN_ATTR GlueRDNAttr= { SPC_GLUE_RDN_OBJID, CERT_RDN_PRINTABLE_STRING, {0, (BYTE *) wszGlue } };
//Global Data for loading the string
#define OPTION_SWITCH_SIZE 5
HMODULE hModule=NULL;
//---------------------------------------------------------------------------
// Get the hModule hanlder and init two DLLMain.
//
//---------------------------------------------------------------------------
BOOL InitModule() { if(!(hModule=GetModuleHandle(NULL))) return FALSE; return TRUE; }
//-------------------------------------------------------------------------
//
// BasicUsage()
//
//
//-------------------------------------------------------------------------
static void BasicUsage() { IDSwprintf(hModule,IDS_SYNTAX); IDSwprintf(hModule,IDS_BASIC_OPTIONS); IDSwprintf(hModule,IDS_OPTION_SK_DESC); #if (1) //DSIE: Bug 205195.
IDSwprintf(hModule,IDS_OPTION_PE_DESC); #endif
IDSwprintf(hModule,IDS_OPTION_SS_DESC); IDSwprintf(hModule,IDS_OPTION_SS_DESC1); IDSwprintf(hModule,IDS_OPTION_SR_DESC); IDS_IDS_IDS_IDSwprintf(hModule,IDS_OPTION_VALUES_DEFAULT, IDS_OPTION_CU, IDS_OPTION_LM,IDS_OPTION_CU ); IDSwprintf(hModule,IDS_OPTION_SERIAL_DESC); IDSwprintf(hModule,IDS_OPTION_AUTH_DESC); IDS_IDS_IDSwprintf(hModule,IDS_OPTION_VALUES_2, IDS_OPTION_AUTH_IND, IDS_OPTION_AUTH_COM); IDSwprintf(hModule,IDS_OPTION_N_DESC); IDSwprintf(hModule,IDS_OPTION_BASIC_DESC); IDSwprintf(hModule,IDS_OPTION_EXTENDED_DESC);
}
//-------------------------------------------------------------------------
//
// ExtendedUsage()
//
//
//-------------------------------------------------------------------------
static void ExtendedUsage() { IDSwprintf(hModule,IDS_SYNTAX); IDSwprintf(hModule,IDS_EXTENDED_OPTIONS); IDSwprintf(hModule,IDS_OPTION_SC_DESC); IDSwprintf(hModule,IDS_OPTION_SV_DESC); IDSwprintf(hModule,IDS_OPTION_IC_DESC); IDSwprintf(hModule,IDS_OPTION_IK_DESC); IDSwprintf(hModule,IDS_OPTION_IV_DESC); IDSwprintf(hModule,IDS_OPTION_IS_DESC); IDSwprintf(hModule,IDS_OPTION_IR_DESC); IDS_IDS_IDS_IDSwprintf(hModule,IDS_OPTION_VALUES_DEFAULT, IDS_OPTION_CU, IDS_OPTION_LM,IDS_OPTION_CU ); IDSwprintf(hModule,IDS_OPTION_IN_DESC); IDSwprintf(hModule,IDS_OPTION_ALGO_DESC, IDS_OPTION_ALGO); IDS_IDS_IDS_IDSwprintf(hModule,IDS_OPTION_VALUES_DEFAULT,IDS_OPTION_ALGO_MD5, IDS_OPTION_ALGO_SHA, IDS_OPTION_ALGO_MD5); IDSwprintf(hModule,IDS_OPTION_IP_DESC); IDSwprintf(hModule,IDS_OPTION_IY_DESC); IDSwprintf(hModule,IDS_OPTION_SP_DESC); IDSwprintf(hModule,IDS_OPTION_SY_DESC); IDSwprintf(hModule,IDS_OPTION_IKY_DESC); IDS_IDS_IDS_IDSwprintf(hModule,IDS_OPTION_VALUES_KY, IDS_OPTION_KY_SIG, IDS_OPTION_KY_EXC,IDS_OPTION_KY_SIG); IDSwprintf(hModule,IDS_OPTION_SKY_DESC); IDS_IDS_IDS_IDSwprintf(hModule,IDS_OPTION_VALUES_KY, IDS_OPTION_KY_SIG, IDS_OPTION_KY_EXC,IDS_OPTION_KY_SIG); IDSwprintf(hModule,IDS_OPTION_L_DESC); IDSwprintf(hModule,IDS_OPTION_CY_DESC); IDS_IDS_IDSwprintf(hModule,IDS_OPTION_VALUES_2, IDS_OPTION_CY_END, IDS_OPTION_CY_AUTH); IDSwprintf(hModule,IDS_OPTION_B_DESC); IDSwprintf(hModule,IDS_OPTION_M_DESC); IDSwprintf(hModule,IDS_OPTION_E_DESC); IDSwprintf(hModule,IDS_OPTION_H_DESC); // IDSwprintf(hModule,IDS_OPTION_G_DESC);
IDSwprintf(hModule,IDS_OPTION_KEY_LEN_DESC); IDSwprintf(hModule,IDS_OPTION_R_DESC); IDSwprintf(hModule,IDS_OPTION_NSCP_DESC); IDSwprintf(hModule,IDS_OPTION_ENHKEY_USAGE_DESC);
IDSwprintf(hModule,IDS_OPTION_BASIC_DESC); IDSwprintf(hModule,IDS_OPTION_EXTENDED_DESC); }
static void UndocumentedUsage() { IDSwprintf(hModule,IDS_SYNTAX);
IDSwprintf(hModule,IDS_OPTION_SQ_DESC); IDSwprintf(hModule,IDS_OPTION_NOPUBKEYPARA_DESC); IDSwprintf(hModule,IDS_OPTION_DH_PARA_DESC); IDSwprintf(hModule,IDS_OPTION_NOPUBVERIFY_DESC); }
//+=========================================================================
// Local Support Functions
//==========================================================================
//+-------------------------------------------------------------------------
// Error output routines
//--------------------------------------------------------------------------
void PrintLastError(int ids) { DWORD dwErr = GetLastError(); IDS_IDS_DW_DWwprintf(hModule,IDS_ERR_LAST, ids, dwErr, dwErr); } //+-------------------------------------------------------------------------
// Allocation and free macros
//--------------------------------------------------------------------------
#define MakeCertAlloc(p1) ToolUtlAlloc(p1, hModule, IDS_ERR_DESC_ALLOC)
#define MakeCertFree(p1) ToolUtlFree(p1)
//-----------------------------------------------------------------------------
//
// Calculate the number of days
//-----------------------------------------------------------------------------
WORD DaysInMonth(WORD wMonth, WORD wYear) { static int mpMonthDays[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; // J F M A M J J A S O N D
WORD w = (WORD)mpMonthDays[wMonth]; if ((wMonth == 2) && (wYear % 4 == 0) && (wYear%400 == 0 || wYear%100 != 0)) { w += 1; } return w; }
//-----------------------------------------------------------------------------
//
// Convert the string into a FILETIME. Let OLE do a bunch of work for us.
//----------------------------------------------------------------------------
BOOL FtFromWStr(LPCWSTR wsz, FILETIME* pft) { memset(pft, 0, sizeof(*pft));
WCHAR wszMonth[3]; DWORD lcid=0; WORD langid=0;
//make sure wsz follows the mm/dd/yyyy
if(wcslen(wsz)!=wcslen(L"mm/dd/yyyy")) return FALSE;
//make sure wsz starts with "mm"
wszMonth[0]=wsz[0]; wszMonth[1]=wsz[1]; wszMonth[2]=L'\0';
if(!((_wtol(wszMonth)>0)&&(_wtol(wszMonth)<=12))) return FALSE;
if (wsz) { //
// The DATE Type
//
// The DATE type is implemented using an 8-byte floating-point number.
// Days are represented by whole number increments starting with 30
// December 1899, midnight as time zero. Hour values are expressed
// as the absolute value of the fractional part of the number.
//
// We are using the English locale since the input format
// should always be mm/dd/yyyy
//
langid=MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
lcid = MAKELCID (langid, SORT_DEFAULT);
DATE date; if (VarDateFromStr((LPWSTR)wsz, lcid, 0, &date) != S_OK) { return FALSE; } if (date < 0) { return FALSE; } // not implemented
double days = date; double hours = ((days - (LONG) days) * 24); double minutes= ((hours - (LONG) hours) * 60); double seconds= ((minutes - (LONG) minutes) * 60); double ms = ((seconds - (LONG) seconds) * 1000);
SYSTEMTIME st; st.wYear = 1899; st.wMonth = 12; ULONG wDay = 30 + (ULONG)days; st.wHour = (WORD)hours; st.wMinute = (WORD)minutes; st.wSecond = (WORD)seconds; st.wMilliseconds = (WORD)ms;
//
// Correct for rounding errors in the arithmetic
//
if (st.wMilliseconds >= 0.5) st.wSecond += 1; st.wMilliseconds = 0; if (st.wSecond >= 60) { st.wMinute += 1; st.wSecond -= 60; } if (st.wMinute >= 60) { st.wHour += 1; st.wMinute -= 60; } if (st.wHour >= 24) { st.wHour -= 24; }
while (wDay > DaysInMonth(st.wMonth, st.wYear)) { wDay -= DaysInMonth(st.wMonth, st.wYear); st.wMonth += 1; if (st.wMonth > 12) { st.wMonth = 1; st.wYear += 1; } }
st.wDay = (WORD)wDay; st.wDayOfWeek = 0;
FILETIME ft; SystemTimeToFileTime(&st, &ft); LocalFileTimeToFileTime(&ft, pft);
return TRUE; } else return FALSE; }
//-------------------------------------------------------------------------
//
// Set the parameters. Each parameter can only be set once
//
//--------------------------------------------------------------------------
BOOL SetParam(WCHAR **pwszParam, WCHAR *wszValue) { if(*pwszParam!=NULL) { IDSwprintf(hModule,IDS_ERR_TOO_MANY_PARAM); return FALSE; }
*pwszParam=wszValue;
if(NULL==wszValue) return FALSE; return TRUE;
}
//--------------------------------------------------------------------------
//
// Command Line Parsing
//
//--------------------------------------------------------------------------
static BOOL ParseCommandLine(int argc, WCHAR* wargv[]) { for ( int i = 1; i < argc; ++i ) { WCHAR* p = wargv[i]; if(IDSwcsnicmp(hModule,p, IDS_SWITCH1, 1)!=0 && IDSwcsnicmp(hModule,p,IDS_SWITCH2, 1)!=0) { if(!SetParam(&wszOutputFile,p)) goto BasicErr; else continue; }
//move over to the real option
++p;
if(IDSwcsicmp(hModule,p, IDS_OPTION_SERIAL)==0) { i++; p=wargv[i];
if(NULL==p) goto BasicErr;
ulSerialNumber=_wtol(p); fSetSerialNumber=TRUE;
continue; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_H)==0) { i++; p=wargv[i];
if(NULL==p) goto ExtendedErr;
pathLenConstraint=_wtol(p);
if(pathLenConstraint < 0) goto ExtendedErr;
continue; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_CY)==0) { i++; p=wargv[i];
if(!SetParam(&wszCertType, p)) goto ExtendedErr;
continue; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_M)==0) { i++; p=wargv[i];
if(NULL==p) goto ExtendedErr;
nMonths=_wtol(p);
if(nMonths < 0) goto ExtendedErr;
continue; } if(IDSwcsicmp(hModule,p, IDS_OPTION_B)==0) { i++; p=wargv[i]; if(NULL==p) goto ExtendedErr;
if(!FtFromWStr(p, &g_ftNotBefore)) { IDSwprintf(hModule, IDS_ERR_INVALID_B); goto ExtendedErr; }
continue; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_E)==0) { i++; p=wargv[i]; if(NULL==p) goto ExtendedErr;
if(!FtFromWStr(p, &g_ftNotAfter)) { IDSwprintf(hModule, IDS_ERR_INVALID_E); goto ExtendedErr; }
continue; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_AUTH)==0) { i++; p=wargv[i];
if(!SetParam(&wszAuthority, p)) goto BasicErr;
continue; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_R)==0) { fSelfSigned=TRUE; continue; } if(IDSwcsicmp(hModule,p, IDS_OPTION_SK)==0) { i++; p=wargv[i];
if(!SetParam(&wszSubjectKey, p)) { if(TRUE==fUseSubjectPvkFile) IDSwprintf(hModule, IDS_ERR_SK_SV);
goto BasicErr; }
fUseSubjectKeyContainer=TRUE; fSubjectInformation=TRUE; continue; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_SQ)==0) { i++; p=wargv[i];
if(!SetParam(&wszSubjectRequestFile, p)) goto UndocumentedErr; continue; } if(IDSwcsicmp(hModule,p, IDS_OPTION_SV)==0) { i++; p=wargv[i];
if(!SetParam(&wszSubjectKey, p)) { if(TRUE==fUseSubjectKeyContainer) IDSwprintf(hModule, IDS_ERR_SK_SV); goto ExtendedErr; }
fSubjectInformation=TRUE; fUseSubjectPvkFile=TRUE; continue; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_SC)==0) { i++; p=wargv[i];
if(!SetParam(&wszSubjectCertFile, p)) goto ExtendedErr;
fSubjectInformation=TRUE; continue; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_SS)==0) { i++; p=wargv[i];
if(!SetParam(&wszSubjectStore, p)) goto BasicErr;
continue; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_SR)==0) { i++; p=wargv[i];
if(!SetParam(&wszSubjectStoreLocation, p)) goto BasicErr;
continue; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_N)==0) { i++; p=wargv[i];
if(!SetParam(&wszSubjectX500Name, p)) goto BasicErr;
fSetSubjectName = TRUE; continue; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_IP)==0) { i++; p=wargv[i];
if(!SetParam(&wszIssuerProviderName, p)) goto ExtendedErr;
fIssuerInformation = TRUE;
continue; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_IY)==0) { i++; p=wargv[i]; if(NULL==p) goto ExtendedErr;
dwIssuerProviderType=_wtol(p);
fIssuerInformation = TRUE;
continue; } if(IDSwcsicmp(hModule,p, IDS_OPTION_SP)==0) { i++; p=wargv[i];
if(!SetParam(&wszSubjectProviderName, p)) goto ExtendedErr;
fSubjectInformation=TRUE;
continue; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_SY)==0) { i++; p=wargv[i]; if(NULL==p) goto ExtendedErr;
dwSubjectProviderType=_wtol(p);
fSubjectInformation=TRUE; continue; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_IK)==0) { i++; p=wargv[i];
if(!SetParam(&wszIssuerKey, p)) goto ExtendedErr;
fIssuerInformation = TRUE;
continue; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_IV)==0) { i++; p=wargv[i];
if(!SetParam(&wszIssuerKey, p)) goto ExtendedErr;
fUseIssuerPvkFile=TRUE; fIssuerInformation = TRUE;
continue; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_IS)==0) { i++; p=wargv[i];
if(!SetParam(&wszIssuerStore, p)) goto ExtendedErr;
fIssuerInformation = TRUE;
continue; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_IR)==0) { i++; p=wargv[i];
if(!SetParam(&wszIssuerStoreLocation,p)) goto ExtendedErr;
fIssuerInformation = TRUE;
continue; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_IN)==0) { i++; p=wargv[i];
if(!SetParam(&wszIssuerCertName,p)) goto ExtendedErr;
fIssuerInformation = TRUE;
continue; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_IC)==0) { i++; p=wargv[i];
if(!SetParam(&wszIssuerCertFile, p)) goto ExtendedErr;
fIssuerInformation = TRUE;
continue; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_L)==0) { i++; p=wargv[i];
if(!SetParam(&wszPolicyLink, p)) goto ExtendedErr;
continue; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_SKY)==0) { i++; p=wargv[i];
if(!SetParam(&wszSubjectKeyType, p)) goto ExtendedErr;
fSubjectInformation=TRUE;
continue; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_IKY)==0) { i++; p=wargv[i];
if(!SetParam(&wszIssuerKeyType, p)) goto ExtendedErr;
fIssuerInformation = TRUE;
continue; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_ALGO)==0) { i++; p=wargv[i];
if(!SetParam(&wszAlgorithm, p)) goto ExtendedErr;
continue; }
if (IDSwcsicmp(hModule,p, IDS_OPTION_ENHKEY_USAGE)==0) { i++; p=wargv[i];
if (!SetParam(&wszEKUOids, p)) goto ExtendedErr;
continue; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_NSCP)==0) { fNetscapeClientAuth = TRUE; continue; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_NOPUBVERIFY)==0) { fNoVerifyPublic = TRUE; continue; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_EXTENDED)==0) { //display extended options
goto ExtendedErr; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_TEST)==0) { //display extended options
goto UndocumentedErr; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_NOPUBKEYPARA)==0) { fNoPubKeyPara = TRUE; continue; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_DH_PARA)==0) { i++; p=wargv[i];
if(!SetParam(&wszDhParaCertFile, p)) goto UndocumentedErr;
continue; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_KEY_LEN)==0) { i++; p=wargv[i]; if(NULL==p) goto UndocumentedErr;
dwKeyBitLen=_wtol(p);
continue; }
if(IDSwcsicmp(hModule,p, IDS_OPTION_PE)==0) { fPrivateKeyExportable=TRUE; continue; }
//display basic options
goto BasicErr; }
//Only change container name if request private key
//to be exportable. This way we maintain backward
//compatibility, and allow user to request private
//key to be marked as exportable.
//Note: If the private key is not marked as exportable,
// the hardcoded container name, "JoeSoft", is
// always used, which means more than one cert
// can share the same key pair.
//Note2: If the user specifies the container name, use that one instead
if (fPrivateKeyExportable && (wszSubjectKey == NULL)) { UUID uuidContainerName; RPC_STATUS rpcs;
rpcs = UuidCreate(&uuidContainerName); if ((rpcs != RPC_S_OK) && (rpcs != RPC_S_UUID_LOCAL_ONLY) && (rpcs != RPC_S_UUID_NO_ADDRESS)) { IDSwprintf(hModule, IDS_ERR_PE_CONTAINER); goto BasicErr; }
if (RPC_S_OK != UuidToStringU(&uuidContainerName, &wszSubjectKey)) { IDSwprintf(hModule, IDS_ERR_PE_CONTAINER); goto BasicErr; } }
//make sure the either output file or the subject' cert store is set
if((wszOutputFile==NULL) && (wszSubjectStore==NULL)) { IDSwprintf(hModule, IDS_ERR_NO_OUTPUT); goto BasicErr; }
//set the authority
if(wszAuthority) { if(IDSwcsicmp(hModule,wszAuthority, IDS_OPTION_AUTH_IND) == 0) fCertIndividual = TRUE; else { if(IDSwcsicmp(hModule,wszAuthority, IDS_OPTION_AUTH_COM) == 0) fCertCommercial = TRUE; else { IDSwprintf(hModule,IDS_ERR_NO_AUTH); goto BasicErr; } } }
//set the algorithm
if(wszAlgorithm) { if(IDSwcsicmp(hModule,wszAlgorithm, IDS_OPTION_ALGO_SHA) == 0) algidHash = CALG_SHA; else { if(IDSwcsicmp(hModule,wszAlgorithm, IDS_OPTION_ALGO_MD5) == 0) algidHash = CALG_MD5; else { IDSwprintf(hModule,IDS_ERR_NO_ALGO); goto ExtendedErr; } } }
//set the cert type
if(wszCertType) { if(IDSwcsicmp(hModule,wszCertType, IDS_OPTION_CY_END) == 0) certTypes |= CERT_END_ENTITY_SUBJECT_FLAG; else { if(IDSwcsicmp(hModule,wszCertType, IDS_OPTION_CY_AUTH) == 0) certTypes |= CERT_CA_SUBJECT_FLAG; else { IDSwprintf(hModule,IDS_ERR_NO_CY); goto ExtendedErr; } } }
//set the issuer key type
if(wszIssuerKeyType) { if(IDSwcsicmp(hModule,wszIssuerKeyType, IDS_OPTION_KY_SIG) == 0) dwIssuerKeySpec = AT_SIGNATURE; else { if(IDSwcsicmp(hModule,wszIssuerKeyType, IDS_OPTION_KY_EXC) == 0) dwIssuerKeySpec = AT_KEYEXCHANGE; else dwIssuerKeySpec=_wtol(wszIssuerKeyType); }
}
//set the subject key type
if(wszSubjectKeyType) { if(IDSwcsicmp(hModule,wszSubjectKeyType, IDS_OPTION_KY_SIG) == 0) dwKeySpec = AT_SIGNATURE; else { if(IDSwcsicmp(hModule,wszSubjectKeyType, IDS_OPTION_KY_EXC) == 0) dwKeySpec = AT_KEYEXCHANGE; else dwKeySpec=_wtol(wszSubjectKeyType); }
}
//determing the issuer store location
if(wszIssuerStoreLocation) { if(IDSwcsicmp(hModule,wszIssuerStoreLocation, IDS_OPTION_CU) == 0) dwIssuerStoreFlag = CERT_SYSTEM_STORE_CURRENT_USER; else { if(IDSwcsicmp(hModule,wszIssuerStoreLocation, IDS_OPTION_LM) == 0) dwIssuerStoreFlag = CERT_SYSTEM_STORE_LOCAL_MACHINE; else { IDSwprintf(hModule,IDS_ERR_NO_IR); goto ExtendedErr; } } }
//determind the subject store location
if(wszSubjectStoreLocation) { if(IDSwcsicmp(hModule,wszSubjectStoreLocation, IDS_OPTION_CU) == 0) dwSubjectStoreFlag = CERT_SYSTEM_STORE_CURRENT_USER; else { if(IDSwcsicmp(hModule,wszSubjectStoreLocation, IDS_OPTION_LM) == 0) dwSubjectStoreFlag = CERT_SYSTEM_STORE_LOCAL_MACHINE; else { IDSwprintf(hModule,IDS_ERR_NO_IR); goto BasicErr; } } }
//wszIssuerStore and wszIssuerKey can not be set at the same time
if(wszIssuerKey || wszIssuerProviderName || wszIssuerKeyType) { if(wszIssuerStore || wszIssuerCertName) { //remind user that -ik, -iv, -ip can not be
//set with -is, -in options
IDSwprintf(hModule,IDS_ERR_TOO_MANY_STORE_KEY); goto ExtendedErr; } }
//wszCertFile and wszCertName can not be set at the same time
if(wszIssuerCertFile && wszIssuerCertName) { IDSwprintf(hModule, IDS_ERR_CERT_FILE_NAME); goto ExtendedErr; }
//is wszIsserCertFile is NULL
if(wszIssuerCertFile==NULL) { //we init wszIssuerKey to "MakeCertRoot" if there is no store
//information
if(wszIssuerStore==NULL) { if(wszIssuerKey) { //if wszIssuerKey is set, we have to set the IssuerCertFile
IDSwprintf(hModule, IDS_ERR_NO_ISSUER_CER_FILE); goto ExtendedErr; } else { wszIssuerKey=wszMakeCertRoot; } } } else { //either wszIssuerStore or wszIssuerKey should be set
if((!wszIssuerStore) && (!wszIssuerKey)) { IDSwprintf(hModule, IDS_ERR_EITHER_STORE_OR_KEY); goto ExtendedErr; } }
//for self signed certificate, user should not supply
//issuer information
if(fIssuerInformation && fSelfSigned) { IDSwprintf(hModule, IDS_NO_ISSUER_FOR_SELF_SIGNED); goto ExtendedErr; }
//user can not request a self signed certificate with
//a PKCS10 file. We neither generate or have access
//to the private key
if(fSelfSigned && wszSubjectRequestFile) { IDSwprintf(hModule, IDS_NO_PKCS10_AND_SELF_SIGNED); goto ExtendedErr; }
if(fSubjectInformation && wszSubjectRequestFile) { IDSwprintf(hModule, IDS_NO_PKCS10_AND_SUBJECT_PVK); goto ExtendedErr; }
//for self signed certificate, copy the provider type
//to the issuer so that the signatureAlgObjID will
//be corrrect
if(fSelfSigned) dwIssuerProviderType = dwSubjectProviderType;
// Set the signature and public key algorithm parameters
if (PROV_DSS == dwIssuerProviderType || PROV_DSS_DH == dwIssuerProviderType) szSignatureAlgObjId = szOID_X957_SHA1DSA; else if (algidHash == CALG_SHA) szSignatureAlgObjId = szOID_OIWSEC_sha1RSASign; else szSignatureAlgObjId = szOID_RSA_MD5RSA;
return TRUE;
BasicErr: BasicUsage(); return FALSE;
ExtendedErr: ExtendedUsage(); return FALSE;
UndocumentedErr: UndocumentedUsage(); return FALSE; }
static BOOL MakeCert();
//+-------------------------------------------------------------------------
// Check if creating a self signed certificate
//--------------------------------------------------------------------------
static BOOL IsSelfSignedCert() { return fSelfSigned; }
//--------------------------------------------------------------------------
//
// wmain
//
//--------------------------------------------------------------------------
extern "C" int __cdecl wmain(int argc, WCHAR ** wargv) { int status = 0;
//get the module handle
if(!InitModule()) return -1;
//load the string for Glue cert attribute
if(!LoadStringU(hModule, IDS_GLUE,wszGlue, sizeof(wszGlue)/sizeof(wszGlue[0]))) return -1; //load the string for wszSubjectKey and wszSubjectX500Name
if(!LoadStringU(hModule, IDS_JOE_SOFT, wszKey, sizeof(wszKey)/sizeof(wszKey[0])) || !LoadStringU(hModule, IDS_JOE_NAME, wszName, sizeof(wszName)/sizeof(wszName[0])) || !LoadStringU(hModule, IDS_MAKECERT_ROOT, wszMakeCertRoot, sizeof(wszMakeCertRoot)/sizeof(wszMakeCertRoot[0])) || !LoadStringU(hModule, IDS_PLUS, wszPlus, sizeof(wszPlus)/sizeof(wszPlus[0])) || !LoadStringU(hModule, IDS_ROOT, wszRoot, sizeof(wszRoot)/sizeof(wszRoot[0])) ) return -1;
LoadStringU(hModule, IDS_NULL, wszNULL, sizeof(wszNULL)/sizeof(wszNULL[0]));
// Parse the command line
if (!ParseCommandLine(argc, wargv)) { return -1; }
//init wszSubjectKey and wszSubjectX500Name
if(wszSubjectKey==NULL) wszSubjectKey=wszKey;
if(wszSubjectX500Name==NULL) wszSubjectX500Name=wszName;
if (FAILED(CoInitialize(NULL))) { IDSwprintf(hModule,IDS_ERR_COINIT); return -1; }
// Get to work and make the certificate
if (!MakeCert()) { CoUninitialize(); goto ErrorReturn; }
//print out the success information
IDSwprintf(hModule,IDS_SUCCEEDED);
CommonReturn: CoUninitialize(); return status;
ErrorReturn: status = -1; IDSwprintf(hModule,IDS_ERR_FAILED); goto CommonReturn; }
//+=========================================================================
// MakeCert support functions
//==========================================================================
static BOOL IsRootKey(); static PCCERT_CONTEXT GetRootCertContext(); static HCRYPTPROV GetRootProv(OUT LPWSTR *ppwszTmpContainer); static PCCERT_CONTEXT GetIssuerCertContext(); static BOOL VerifyIssuerKey( IN HCRYPTPROV hProv, IN PCERT_PUBLIC_KEY_INFO pIssuerKeyInfo ); static HCRYPTPROV GetIssuerProv(OUT LPWSTR *ppwszTmpContainer); static HCRYPTPROV GetSubjectProv(OUT LPWSTR *ppwszTmpContainer); static HCRYPTPROV GetProvFromStore(IN LPWSTR pwszStoreName);
static BOOL GetPublicKey( HCRYPTPROV hProv, PCERT_PUBLIC_KEY_INFO *ppPubKeyInfo ); static BOOL GetSubject( OUT PCCERT_CONTEXT *ppCertContext, OUT BYTE **ppbEncodedName, OUT DWORD *pcbEncodedName ); static BOOL GetRequestInfo( OUT PCERT_REQUEST_INFO *ppStuff); static BOOL EncodeSubject( OUT BYTE **ppbEncoded, IN OUT DWORD *pcbEncoded ); static BOOL SignAndEncodeCert( HCRYPTPROV hProv, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, BYTE *pbToBeSigned, DWORD cbToBeSigned, BYTE **ppbEncoded, DWORD *pcbEncoded );
static BOOL CreateAuthorityKeyId( IN HCRYPTPROV hProv, PCERT_INFO pIssuerCert, OUT BYTE **ppbEncoded, IN OUT DWORD *pcbEncoded ); static BOOL CreateSpcSpAgency( OUT BYTE **ppbEncoded, IN OUT DWORD *pcbEncoded ); static BOOL CreateEnhancedKeyUsage( OUT BYTE **ppbEncoded, IN OUT DWORD *pcbEncoded ); static BOOL CreateKeyUsage( OUT BYTE **ppbEncoded, IN OUT DWORD *pcbEncoded ); static BOOL CreateBasicConstraints( OUT BYTE **ppbEncoded, IN OUT DWORD *pcbEncoded );
static void BytesToWStr(ULONG cb, void* pv, LPWSTR wsz);
BOOL SaveCertToStore(HCRYPTPROV hProv, DWORD dwEncodingType, LPWSTR wszStore, DWORD dwFlag, BYTE *pbEncodedCert, DWORD cbEncodedCert, LPWSTR wszPvk, BOOL fPvkFile, DWORD dwKeySpecification, LPWSTR wszCapiProv, DWORD dwCapiProvType);
PCCERT_CONTEXT GetIssuerCertAndStore(HCERTSTORE *phCertStore, BOOL *pfMore);
HRESULT GetCertHashFromFile(LPWSTR pwszCertFile, BYTE **ppHash, DWORD *pcbHash, BOOL *pfMore);
BOOL EmptySubject(CERT_NAME_BLOB *pSubject);
BOOL GetExtensionsFromRequest(PCERT_REQUEST_INFO pReqInfo, DWORD *pdwCount, PCERT_EXTENSIONS **pprgExtensions);
//+=========================================================================
// Support functions to generate DH keys having the 'Q'parameter
//==========================================================================
static BOOL GenDhKey( IN HCRYPTPROV hProv, IN DWORD dwFlags ); static BOOL UpdateDhPublicKey( IN OUT PCERT_PUBLIC_KEY_INFO *ppPubKeyInfo ); static BOOL IsDh3Csp();
//+-------------------------------------------------------------------------
// Make the subject certificate. If the subject doesn't have a private
// key, then, create.
//--------------------------------------------------------------------------
static BOOL MakeCert() { BOOL fResult;
HCRYPTPROV hIssuerProv = 0; LPWSTR pwszTmpIssuerContainer = NULL; BOOL fDidIssuerAcquire=FALSE; LPWSTR pwszTmpIssuerProvName=NULL; DWORD dwTmpIssuerProvType; PCCERT_CONTEXT pIssuerCertContext = NULL; HCERTSTORE hIssuerCertStore=NULL; PCERT_INFO pIssuerCert =NULL; // not allocated
PCERT_REQUEST_INFO pReqInfo =NULL; HCRYPTPROV hSubjectProv = 0; LPWSTR pwszTmpSubjectContainer = NULL; PCCERT_CONTEXT pSubjectCertContext = NULL; DWORD dwRequestExtensions=0; PCERT_EXTENSIONS *rgpRequestExtensions=NULL; DWORD dwExtIndex=0; DWORD dwPerExt=0; DWORD dwExistExt=0;
PCERT_PUBLIC_KEY_INFO pSubjectPubKeyInfo = NULL; // not allocated
PCERT_PUBLIC_KEY_INFO pAllocSubjectPubKeyInfo = NULL; BYTE *pbSubjectEncoded = NULL; DWORD cbSubjectEncoded =0; BYTE *pbKeyIdEncoded = NULL; DWORD cbKeyIdEncoded =0; BYTE *pbSerialNumber = NULL; DWORD cbSerialNumber = 0; BYTE *pbSpcSpAgencyEncoded = NULL; DWORD cbSpcSpAgencyEncoded =0; BYTE *pbSpcCommonNameEncoded = NULL; DWORD cbSpcCommonNameEncoded =0; BYTE *pbKeyUsageEncoded = NULL; DWORD cbKeyUsageEncoded =0; BYTE *pbFinancialCriteria = NULL; DWORD cbFinancialCriteria =0; BYTE *pbBasicConstraintsEncoded = NULL; DWORD cbBasicConstraintsEncoded =0; BYTE *pbCertEncoded = NULL; DWORD cbCertEncoded =0; BYTE *pbEKUEncoded = NULL; DWORD cbEKUEncoded = 0;
CERT_INFO Cert; GUID SerialNumber;
CERT_EXTENSION *rgExt=NULL; DWORD dwExtAlloc=0; DWORD cExt = 0;
CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm = { szSignatureAlgObjId, 0, 0 };
BYTE *pbIssuerEncoded; // not allocated
DWORD cbIssuerEncoded;
if (wszSubjectRequestFile) { if (!GetRequestInfo(&pReqInfo)) { IDSwprintf(hModule,IDS_INVALID_REQUEST_FILE, wszSubjectRequestFile); goto ErrorReturn; }
pSubjectPubKeyInfo = &(pReqInfo->SubjectPublicKeyInfo);
if(!GetExtensionsFromRequest(pReqInfo, &dwRequestExtensions, &rgpRequestExtensions)) { IDSwprintf(hModule,IDS_INVALID_ATTR_REQUEST_FILE, wszSubjectRequestFile); goto ErrorReturn; } //if the subject informatin is empt or user has supplied the subject
//name through the command line, we use the command line options
if(fSetSubjectName || wszSubjectCertFile || EmptySubject(&(pReqInfo->Subject))) { if (wszSubjectCertFile) { // Get encoded subject name and public key from the subject cert
if (!GetSubject(&pSubjectCertContext, &pbSubjectEncoded, &cbSubjectEncoded)) goto ErrorReturn; } else { // Encode the subject name
if (!EncodeSubject(&pbSubjectEncoded, &cbSubjectEncoded)) goto ErrorReturn; } } else { cbSubjectEncoded = pReqInfo->Subject.cbData;
pbSubjectEncoded = (BYTE *) MakeCertAlloc(cbSubjectEncoded);
if(NULL == pbSubjectEncoded) goto ErrorReturn;
memcpy(pbSubjectEncoded, pReqInfo->Subject.pbData, cbSubjectEncoded);
} } else { if (wszSubjectCertFile) { // Get encoded subject name and public key from the subject cert
if (!GetSubject(&pSubjectCertContext, &pbSubjectEncoded, &cbSubjectEncoded)) goto ErrorReturn; pSubjectPubKeyInfo = &pSubjectCertContext->pCertInfo->SubjectPublicKeyInfo; pbSerialNumber = pSubjectCertContext->pCertInfo->SerialNumber.pbData; cbSerialNumber = pSubjectCertContext->pCertInfo->SerialNumber.cbData; } else { //
// Get access to the subject's (public) key, creating it if necessary
//
if (0 == (hSubjectProv = GetSubjectProv(&pwszTmpSubjectContainer))) goto ErrorReturn;
if (!GetPublicKey(hSubjectProv, &pAllocSubjectPubKeyInfo)) goto ErrorReturn; pSubjectPubKeyInfo = pAllocSubjectPubKeyInfo;
//
// Encode the subject name
//
if (!EncodeSubject(&pbSubjectEncoded, &cbSubjectEncoded)) goto ErrorReturn; } }
//
// Get access to the issuer's (private) key
//
if( IsSelfSignedCert()) { hIssuerProv=hSubjectProv; dwIssuerKeySpec=dwKeySpec;
pbIssuerEncoded = pbSubjectEncoded; cbIssuerEncoded = cbSubjectEncoded; pIssuerCert = &Cert;
if (!VerifyIssuerKey(hIssuerProv, pSubjectPubKeyInfo)) goto ErrorReturn;
} else { //get the hProv from the certificate store
if(wszIssuerStore) { BOOL fMore=FALSE;
pwszTmpIssuerContainer=NULL;
//get the non-root private key set based on the store name
//first, get the certificate context from the cert store
if(NULL==(pIssuerCertContext=GetIssuerCertAndStore( &hIssuerCertStore, &fMore))) { if(fMore==FALSE) IDSwprintf(hModule, IDS_ERR_NO_ISSUER_CERT, wszIssuerStore); else IDSwprintf(hModule, IDS_ERR_MORE_ISSUER_CERT, wszIssuerStore);
goto ErrorReturn; }
//second, get the hProv from the certifcate context
if(!GetCryptProvFromCert( NULL, pIssuerCertContext, &hIssuerProv, &dwIssuerKeySpec, &fDidIssuerAcquire, &pwszTmpIssuerContainer, &pwszTmpIssuerProvName, &dwTmpIssuerProvType)) { IDSwprintf(hModule, IDS_ERR_NO_PROV_FROM_CERT); goto ErrorReturn; } } else {
if (0 == (hIssuerProv = GetIssuerProv(&pwszTmpIssuerContainer))) goto ErrorReturn;
// Get the Issuer's Certificate
if (NULL == (pIssuerCertContext = GetIssuerCertContext())) goto ErrorReturn; }
// Verify the issuer's key. Its public key must match the one
// in the issuer's provider
//
pIssuerCert = pIssuerCertContext->pCertInfo;
if ((!fNoVerifyPublic) && (!VerifyIssuerKey(hIssuerProv, &pIssuerCert->SubjectPublicKeyInfo))) goto ErrorReturn;
pbIssuerEncoded = pIssuerCert->Subject.pbData; cbIssuerEncoded = pIssuerCert->Subject.cbData; }
//
// Update the CERT_INFO
//
memset(&Cert, 0, sizeof(Cert)); Cert.dwVersion = CERT_V3;
if (0 != cbSerialNumber) { Cert.SerialNumber.pbData = pbSerialNumber; Cert.SerialNumber.cbData = cbSerialNumber; } else if (fSetSerialNumber) { Cert.SerialNumber.pbData = (BYTE *) &ulSerialNumber; Cert.SerialNumber.cbData = sizeof(ulSerialNumber); } else if (0 == Cert.SerialNumber.cbData) { CoCreateGuid(&SerialNumber); Cert.SerialNumber.pbData = (BYTE *) &SerialNumber; Cert.SerialNumber.cbData = sizeof(SerialNumber); }
Cert.SignatureAlgorithm = SignatureAlgorithm; Cert.Issuer.pbData = pbIssuerEncoded; Cert.Issuer.cbData = cbIssuerEncoded;
{ SYSTEMTIME st; //decide NotBefore
// Let the user override the default validity endpoints
//
if (CompareFileTime(&g_ftNotBefore, &g_ftZero) != 0) { Cert.NotBefore = g_ftNotBefore; } else { // Default validity: now through end of 2039
GetSystemTimeAsFileTime(&Cert.NotBefore); }
//decide NotAfter
if (CompareFileTime(&g_ftNotAfter, &g_ftZero) != 0) { Cert.NotAfter = g_ftNotAfter; } else { memset(&st, 0, sizeof(st)); st.wYear = 2039; st.wMonth = 12; st.wDay = 31; st.wHour = 23; st.wMinute= 59; st.wSecond= 59; SystemTimeToFileTime(&st, &Cert.NotAfter); }
//add the number of months
if (nMonths >= 0) { //if the user has specified NotAfter with -E switch, error
if(CompareFileTime(&g_ftNotAfter, &g_ftZero) != 0) goto ErrorReturn;
if (nMonths > 0) { FILETIME tempFT; DWORD dwMonth; SYSTEMTIME tempST; BOOL fFirstDayOfMonth;
//
// Cert.NotBefore is stored as UTC, but the user has entered
// nMonths based on local time, so convert to local time, then:
// NotAfter = (NotBefore - 1 second) + nMonths
//
if (!FileTimeToLocalFileTime(&Cert.NotBefore, &tempFT)) goto ErrorReturn;
//
// if the day is the first day of the month, then subtract
// one second after the months are added to the NotBefore
// time instead of before the months are added, otherwise
// we could end up with the wrong ending date.
//
if (FileTimeToSystemTime(&tempFT, &tempST)) { fFirstDayOfMonth = (tempST.wDay == 1); } else { goto ErrorReturn; }
// Subtract one second from the starting date, and then
// add the number of months to that time
//
// FILETIME is in units of 100 nanoseconds (10**-7)
if (!fFirstDayOfMonth) { unsigned __int64* pli = (unsigned __int64*) &tempFT; *pli -= 10000000; // ten million
} if (!FileTimeToSystemTime(&tempFT, &st)) goto ErrorReturn; dwMonth = (DWORD) nMonths + st.wMonth; while (dwMonth > 12) { dwMonth -= 12; st.wYear += 1; } st.wMonth = (WORD) dwMonth;
//
// This loop is because the ending month may not have as
// many days as the starting month... so the initial
// ending day may not even exist, thus, loop until we
// find one that does or we go below 28 (no month ever has
// less than 28 days)
//
while(!SystemTimeToFileTime(&st, &tempFT)) { if(st.wDay >= 29 ) st.wDay--; else goto ErrorReturn; }
//
// if first day of month then subtract our one second
// after month calculations
//
if (fFirstDayOfMonth) { unsigned __int64* pli = (unsigned __int64*) &tempFT; *pli -= 10000000; // ten million
}
if (!LocalFileTimeToFileTime(&tempFT, &Cert.NotAfter)) goto ErrorReturn; } else { if (!FileTimeToSystemTime(&Cert.NotBefore, &st)) goto ErrorReturn;
if (!SystemTimeToFileTime(&st, &Cert.NotAfter)) goto ErrorReturn; } } }
Cert.Subject.pbData = pbSubjectEncoded; Cert.Subject.cbData = cbSubjectEncoded; Cert.SubjectPublicKeyInfo = *pSubjectPubKeyInfo;
//allocate memory to hold all the extensions
dwExtAlloc = MAX_EXT_CNT; for(dwExtIndex=0; dwExtIndex < dwRequestExtensions; dwExtIndex++) dwExtAlloc += (rgpRequestExtensions[dwExtIndex])->cExtension;
rgExt = (CERT_EXTENSION *)MakeCertAlloc(dwExtAlloc * sizeof(CERT_EXTENSION)); if(NULL == rgExt) goto ErrorReturn;
memset(rgExt, 0, dwExtAlloc * sizeof(CERT_EXTENSION)); cExt=0; // Cert Extensions
if (fNetscapeClientAuth) { // Set Netscape specific extensions
static BYTE rgXxxxData[] = { 0x30, 0x03, 0x02, 0x01, 0x00 }; rgExt[cExt].pszObjId = "2.5.29.19"; rgExt[cExt].fCritical = FALSE; rgExt[cExt].Value.pbData = rgXxxxData; rgExt[cExt].Value.cbData = sizeof(rgXxxxData); cExt++;
static BYTE rgNscpData[] = { 0x03, 0x02, 0x07, 0x80 }; rgExt[cExt].pszObjId = "2.16.840.1.113730.1.1"; rgExt[cExt].fCritical = FALSE; rgExt[cExt].Value.pbData = rgNscpData; rgExt[cExt].Value.cbData = sizeof(rgNscpData); cExt++; }
if (pathLenConstraint >= 0 || certTypes) { if (!CreateBasicConstraints( &pbBasicConstraintsEncoded, &cbBasicConstraintsEncoded)) goto ErrorReturn; rgExt[cExt].pszObjId = szOID_BASIC_CONSTRAINTS2; rgExt[cExt].fCritical = TRUE; rgExt[cExt].Value.pbData = pbBasicConstraintsEncoded; rgExt[cExt].Value.cbData = cbBasicConstraintsEncoded; cExt++; }
if (fCertCommercial || fCertIndividual) { if (!CreateKeyUsage( &pbKeyUsageEncoded, &cbKeyUsageEncoded)) goto ErrorReturn; rgExt[cExt].pszObjId = szOID_KEY_USAGE_RESTRICTION; rgExt[cExt].fCritical = TRUE; rgExt[cExt].Value.pbData = pbKeyUsageEncoded; rgExt[cExt].Value.cbData = cbKeyUsageEncoded; cExt++; }
if (wszPolicyLink) { if (!CreateSpcSpAgency( &pbSpcSpAgencyEncoded, &cbSpcSpAgencyEncoded)) goto ErrorReturn; rgExt[cExt].pszObjId = SPC_SP_AGENCY_INFO_OBJID; rgExt[cExt].fCritical = FALSE; rgExt[cExt].Value.pbData = pbSpcSpAgencyEncoded; rgExt[cExt].Value.cbData = cbSpcSpAgencyEncoded; cExt++; }
//if user has specified fCertCommercial or fCertIndividual,
//we add the code signing oid to the EKU extensions
if (wszEKUOids || fCertCommercial || fCertIndividual) { if (!CreateEnhancedKeyUsage( &pbEKUEncoded, &cbEKUEncoded)) goto ErrorReturn;
rgExt[cExt].pszObjId = szOID_ENHANCED_KEY_USAGE; rgExt[cExt].fCritical = FALSE; rgExt[cExt].Value.pbData = pbEKUEncoded; rgExt[cExt].Value.cbData = cbEKUEncoded; cExt++; }
if (!CreateAuthorityKeyId( hIssuerProv, pIssuerCert, &pbKeyIdEncoded, &cbKeyIdEncoded)) goto ErrorReturn; rgExt[cExt].pszObjId = szOID_AUTHORITY_KEY_IDENTIFIER; rgExt[cExt].fCritical = FALSE; rgExt[cExt].Value.pbData = pbKeyIdEncoded; rgExt[cExt].Value.cbData = cbKeyIdEncoded; cExt++;
//we now combine the extension from the certificate request file.
//In case of duplication of extensions, the command line options
//have higher priority
for(dwExtIndex=0; dwExtIndex < dwRequestExtensions; dwExtIndex++) { for(dwPerExt=0; dwPerExt < rgpRequestExtensions[dwExtIndex]->cExtension; dwPerExt++) { for(dwExistExt=0; dwExistExt<cExt; dwExistExt++) { if(0 == strcmp(rgExt[dwExistExt].pszObjId, (rgpRequestExtensions[dwExtIndex]->rgExtension[dwPerExt]).pszObjId)) break; }
//we merge if this is a new extension
if(dwExistExt == cExt) { memcpy(&(rgExt[cExt]), &(rgpRequestExtensions[dwExtIndex]->rgExtension[dwPerExt]), sizeof(CERT_EXTENSION)); cExt++; } } }
Cert.rgExtension = rgExt; Cert.cExtension = cExt;
//
// Sign and encode the certificate
//
cbCertEncoded = 0; CryptSignAndEncodeCertificate( hIssuerProv, dwIssuerKeySpec, X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED, &Cert, &Cert.SignatureAlgorithm, NULL, // pvHashAuxInfo
NULL, // pbEncoded
&cbCertEncoded ); if (cbCertEncoded == 0) { PrintLastError(IDS_ERR_SIGN_ENCODE_CB); goto ErrorReturn; } pbCertEncoded = (BYTE *) MakeCertAlloc(cbCertEncoded); if (pbCertEncoded == NULL) goto ErrorReturn; if (!CryptSignAndEncodeCertificate( hIssuerProv, dwIssuerKeySpec, X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED, &Cert, &Cert.SignatureAlgorithm, NULL, // pvHashAuxInfo
pbCertEncoded, &cbCertEncoded )) { PrintLastError(IDS_ERR_SIGN_ENCODE); goto ErrorReturn; }
//output the encoded certificate to an output file
if(wszOutputFile) {
if (S_OK!=OpenAndWriteToFile(wszOutputFile, pbCertEncoded, cbCertEncoded)) { PrintLastError(IDS_ERR_DESC_WRITE); goto ErrorReturn; } }
//output the encoded certificate to an cerificate store
if(wszSubjectStore) { if((!SaveCertToStore(hSubjectProv, dwCertStoreEncodingType, wszSubjectStore, dwSubjectStoreFlag, pbCertEncoded, cbCertEncoded, wszSubjectKey, fUseSubjectPvkFile, dwKeySpec, wszSubjectProviderName, dwSubjectProviderType))) { PrintLastError(IDS_ERR_DESC_SAVE_STORE); goto ErrorReturn;
} }
fResult = TRUE; goto CommonReturn;
ErrorReturn: fResult = FALSE; CommonReturn:
if((!IsSelfSignedCert()) && hIssuerProv) { if(wszIssuerStore) { FreeCryptProvFromCert(fDidIssuerAcquire, hIssuerProv, pwszTmpIssuerProvName, dwTmpIssuerProvType, pwszTmpIssuerContainer); } else { PvkFreeCryptProv(hIssuerProv, wszIssuerProviderName, dwIssuerProviderType, pwszTmpIssuerContainer); } }
PvkFreeCryptProv(hSubjectProv, wszSubjectProviderName, dwSubjectProviderType,pwszTmpSubjectContainer);
if (pIssuerCertContext) CertFreeCertificateContext(pIssuerCertContext); if(hIssuerCertStore) CertCloseStore(hIssuerCertStore, 0);
if (pSubjectCertContext) CertFreeCertificateContext(pSubjectCertContext);
//pReqInfo is allocated via CryptQueryObject
if (pReqInfo) LocalFree((HLOCAL)pReqInfo);
if (pAllocSubjectPubKeyInfo) MakeCertFree(pAllocSubjectPubKeyInfo); if (pbSubjectEncoded) MakeCertFree(pbSubjectEncoded); if (pbKeyIdEncoded) MakeCertFree(pbKeyIdEncoded); if (pbSpcSpAgencyEncoded) MakeCertFree(pbSpcSpAgencyEncoded); if (pbEKUEncoded) MakeCertFree(pbEKUEncoded); if (pbSpcCommonNameEncoded) MakeCertFree(pbSpcCommonNameEncoded); if (pbKeyUsageEncoded) MakeCertFree(pbKeyUsageEncoded); if (pbFinancialCriteria) MakeCertFree(pbFinancialCriteria); if (pbBasicConstraintsEncoded) MakeCertFree(pbBasicConstraintsEncoded); if (pbCertEncoded) MakeCertFree(pbCertEncoded); if (rgpRequestExtensions) { for(dwExtIndex=0; dwExtIndex<dwRequestExtensions; dwExtIndex++) { if(rgpRequestExtensions[dwExtIndex]) MakeCertFree(rgpRequestExtensions[dwExtIndex]); }
MakeCertFree(rgpRequestExtensions); } if (rgExt) MakeCertFree(rgExt);
return fResult; }
//+-------------------------------------------------------------------------
// save the certificate to a certificate store. Attach private key information
// to the certificate
//--------------------------------------------------------------------------
BOOL SaveCertToStore( HCRYPTPROV hProv, DWORD dwEncodingType, LPWSTR wszStore, DWORD dwFlag, BYTE *pbEncodedCert, DWORD cbEncodedCert, LPWSTR wszPvk, BOOL fPvkFile, DWORD dwKeySpecification, LPWSTR wszCapiProv, DWORD dwCapiProvType) { BOOL fResult=FALSE; HCERTSTORE hStore=NULL; PCCERT_CONTEXT pCertContext=NULL; CRYPT_KEY_PROV_INFO KeyProvInfo; CRYPT_DATA_BLOB dataBlob; DWORD cwchar; LPWSTR pwszPvkProperty=NULL; HRESULT hr=S_OK;
HCRYPTPROV hDefaultProvName=NULL; DWORD cbData=0; LPSTR pszName=NULL; LPWSTR pwszName=NULL;
//init
memset(&KeyProvInfo, 0, sizeof(CRYPT_KEY_PROV_INFO));
//open a cert store
hStore=CertOpenStore(CERT_STORE_PROV_SYSTEM_W, dwEncodingType, hProv, CERT_STORE_NO_CRYPT_RELEASE_FLAG|dwFlag, wszStore);
if(hStore==NULL) goto CLEANUP;
//add the encoded certificate to store
if(!CertAddEncodedCertificateToStore( hStore, X509_ASN_ENCODING, pbEncodedCert, cbEncodedCert, CERT_STORE_ADD_REPLACE_EXISTING, &pCertContext)) goto CLEANUP;
//if user has specified a request file, there is no need to
//add the private key property
if(wszSubjectRequestFile) { fResult = TRUE; goto CLEANUP; }
//add properties to the certificate
KeyProvInfo.pwszContainerName=wszPvk; KeyProvInfo.pwszProvName=wszCapiProv, KeyProvInfo.dwProvType=dwCapiProvType, KeyProvInfo.dwKeySpec=dwKeySpecification;
//if wszCapiProv is NULL, we get the default provider name
if(NULL==wszCapiProv) { //get the default provider
if(CryptAcquireContext(&hDefaultProvName, NULL, NULL, KeyProvInfo.dwProvType, CRYPT_VERIFYCONTEXT)) {
//get the provider name
if(CryptGetProvParam(hDefaultProvName, PP_NAME, NULL, &cbData, 0) && (0!=cbData)) {
if(pszName=(LPSTR)MakeCertAlloc(cbData)) { if(CryptGetProvParam(hDefaultProvName, PP_NAME, (BYTE *)pszName, &cbData, 0)) { pwszName=MkWStr(pszName);
KeyProvInfo.pwszProvName=pwszName; } } } } }
//free the provider as we want
if(hDefaultProvName) CryptReleaseContext(hDefaultProvName, 0);
hDefaultProvName=NULL;
if(fPvkFile) { //add the property related to private key file
if(S_OK != (hr=ComposePvkString(&KeyProvInfo, &pwszPvkProperty, &cwchar))) { SetLastError(hr); goto CLEANUP; }
//set up
dataBlob.cbData=cwchar*sizeof(WCHAR); dataBlob.pbData=(BYTE *)pwszPvkProperty;
if(!CertSetCertificateContextProperty( pCertContext, CERT_PVK_FILE_PROP_ID, 0, &dataBlob)) goto CLEANUP;
} else { if (dwSubjectStoreFlag == CERT_SYSTEM_STORE_LOCAL_MACHINE) KeyProvInfo.dwFlags = CRYPT_MACHINE_KEYSET;
//add property related to the key container
if(!CertSetCertificateContextProperty( pCertContext, CERT_KEY_PROV_INFO_PROP_ID, 0, &KeyProvInfo)) goto CLEANUP; }
fResult=TRUE;
CLEANUP:
//free the cert context
if(pCertContext) CertFreeCertificateContext(pCertContext);
//free the cert store
if(hStore) CertCloseStore(hStore, 0);
if(pwszPvkProperty) MakeCertFree(pwszPvkProperty);
if(pszName) MakeCertFree(pszName);
if(pwszName) FreeWStr(pwszName);
if(hDefaultProvName) CryptReleaseContext(hDefaultProvName, 0);
return fResult;
}
//+-------------------------------------------------------------------------
// Check if the root issuer.
//--------------------------------------------------------------------------
static BOOL IsRootKey() { if(IDSwcsicmp(hModule,(WCHAR *)wszIssuerKey, IDS_MAKECERT_ROOT) != 0) return FALSE;
//in orde to be sure that we are using the default root, wszIssuerCertFile
//has to NULL
if(wszIssuerCertFile!=NULL) return FALSE;
return TRUE; }
//+-------------------------------------------------------------------------
// Get the root's certificate from the program's resources
//--------------------------------------------------------------------------
static PCCERT_CONTEXT GetRootCertContext() { PCCERT_CONTEXT pCert = NULL; HRSRC hRes; CHAR szCer[10];
//load the string CER
if(!LoadStringA(hModule, IDS_CER, szCer, sizeof(szCer)/sizeof(szCer[0]))) { IDSwprintf(hModule,IDS_ERR_LOAD_ROOT); return pCert; }
//
// The root certificate is stored as a resource of ours.
// Load it...
//
if (0 != (hRes = FindResource(NULL, MAKEINTRESOURCE(IDR_ROOTCERTIFICATE), szCer))) { HGLOBAL hglobRes; if (NULL != (hglobRes = LoadResource(NULL, hRes))) { BYTE *pbRes; DWORD cbRes;
cbRes = SizeofResource(NULL, hRes); pbRes = (BYTE *) LockResource(hglobRes); if (cbRes && pbRes) pCert = CertCreateCertificateContext(X509_ASN_ENCODING, pbRes, cbRes); UnlockResource(hglobRes); FreeResource(hglobRes); } }
if (pCert == NULL) IDSwprintf(hModule,IDS_ERR_LOAD_ROOT); return pCert; }
//+-------------------------------------------------------------------------
// Get the root's private key from the program's resources and create
// a temporary key provider container
//--------------------------------------------------------------------------
static HCRYPTPROV GetRootProv(OUT LPWSTR *ppwszTmpContainer) { HCRYPTPROV hProv = 0; HRSRC hRes; CHAR szPvk[10]; WCHAR wszRootSig[40];
//load the string CER
if(!LoadStringA(hModule, IDS_PVK, szPvk, sizeof(szPvk)/sizeof(szPvk[0]))) { IDSwprintf(hModule,IDS_ERR_ROOT_KEY); return hProv; }
//load the string "Root Signature"
if(!LoadStringU(hModule, IDS_ROOT_SIGNATURE, wszRootSig, sizeof(wszRootSig)/sizeof(wszRootSig[0]))) { IDSwprintf(hModule,IDS_ERR_ROOT_KEY); return hProv; }
*ppwszTmpContainer = NULL;
if (0 != (hRes = FindResource(NULL, MAKEINTRESOURCE(IDR_PVKROOT), szPvk))) { HGLOBAL hglobRes; if (NULL != (hglobRes = LoadResource(NULL, hRes))) { BYTE *pbRes; DWORD cbRes;
cbRes = SizeofResource(NULL, hRes); pbRes = (BYTE *) LockResource(hglobRes); if (cbRes && pbRes) { PvkPrivateKeyAcquireContextFromMemory( wszIssuerProviderName, dwIssuerProviderType, pbRes, cbRes, NULL, // hwndOwner
wszRootSig, &dwIssuerKeySpec, &hProv, ppwszTmpContainer ); } UnlockResource(hglobRes); FreeResource(hglobRes); } }
if (hProv == 0) IDSwprintf(hModule,IDS_ERR_ROOT_KEY); return hProv; }
//+-------------------------------------------------------------------------
// Get the issuer's certificate
//--------------------------------------------------------------------------
static PCCERT_CONTEXT GetIssuerCertContext() { if (IsRootKey()) { PCCERT_CONTEXT pCert = NULL; wszIssuerKey=wszRoot;
// Get root certificate from the program's resources
pCert=GetRootCertContext();
wszIssuerKey=wszMakeCertRoot;
return pCert; } else { PCCERT_CONTEXT pCert = NULL; BYTE *pb; DWORD cb;
//make sure we have issuer's certificate
if(wszIssuerCertFile) {
if (S_OK==RetrieveBLOBFromFile(wszIssuerCertFile,&cb, &pb)) { pCert = CertCreateCertificateContext(X509_ASN_ENCODING, pb, cb); UnmapViewOfFile(pb); } }
if (pCert == NULL) IDSwprintf(hModule,IDS_ERR_LOAD_ISSUER, wszIssuerCertFile); return pCert; } }
//+-------------------------------------------------------------------------
// Verify the issuer's certificate. The public key in the certificate
// must match the public key associated with the private key in the
// issuer's provider
//--------------------------------------------------------------------------
static BOOL VerifyIssuerKey( IN HCRYPTPROV hProv, IN PCERT_PUBLIC_KEY_INFO pIssuerKeyInfo ) { BOOL fResult; PCERT_PUBLIC_KEY_INFO pPubKeyInfo = NULL; DWORD cbPubKeyInfo;
// Get issuer's public key
cbPubKeyInfo = 0; CryptExportPublicKeyInfo( hProv, dwIssuerKeySpec, X509_ASN_ENCODING, NULL, // pPubKeyInfo
&cbPubKeyInfo ); if (cbPubKeyInfo == 0) { PrintLastError(IDS_ERR_EXPORT_PUB); goto ErrorReturn; } if (NULL == (pPubKeyInfo = (PCERT_PUBLIC_KEY_INFO) MakeCertAlloc(cbPubKeyInfo))) goto ErrorReturn; if (!CryptExportPublicKeyInfo( hProv, dwIssuerKeySpec, X509_ASN_ENCODING, pPubKeyInfo, &cbPubKeyInfo )) { PrintLastError(IDS_ERR_EXPORT_PUB); goto ErrorReturn; }
if (!CertComparePublicKeyInfo( X509_ASN_ENCODING, pIssuerKeyInfo, pPubKeyInfo)) { // This might be the test root with an incorrectly
// encoded public key. Convert to the capi representation and
// compare.
BYTE rgProvKey[256]; BYTE rgCertKey[256]; DWORD cbProvKey = sizeof(rgProvKey); DWORD cbCertKey = sizeof(rgCertKey);
if (!CryptDecodeObject(X509_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB, pIssuerKeyInfo->PublicKey.pbData, pIssuerKeyInfo->PublicKey.cbData, 0, // dwFlags
rgProvKey, &cbProvKey) || !CryptDecodeObject(X509_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB, pPubKeyInfo->PublicKey.pbData, pPubKeyInfo->PublicKey.cbData, 0, // dwFlags
rgCertKey, &cbCertKey) || cbProvKey == 0 || cbProvKey != cbCertKey || memcmp(rgProvKey, rgCertKey, cbProvKey) != 0) { IDSwprintf(hModule,IDS_ERR_MISMATCH); goto ErrorReturn; } }
fResult = TRUE; goto CommonReturn;
ErrorReturn: fResult = FALSE; CommonReturn: if (pPubKeyInfo) MakeCertFree(pPubKeyInfo); return fResult; }
//+-------------------------------------------------------------------------
// Get the issuer's private signature key provider
//--------------------------------------------------------------------------
static HCRYPTPROV GetIssuerProv(OUT LPWSTR *ppwszTmpContainer) { HCRYPTPROV hProv=0; WCHAR wszIssuerSig[40];
//load the string "Issuer Signature"
if(!LoadStringU(hModule, IDS_ISSUER_SIGNATURE, wszIssuerSig, sizeof(wszIssuerSig)/sizeof(wszIssuerSig[0]))) { IDSwprintf(hModule,IDS_ERR_ROOT_KEY); return NULL; }
if (IsRootKey()) { wszIssuerKey=wszRoot;
// Get root key from the program's resoures and create a temporary
// key container
hProv = GetRootProv(ppwszTmpContainer);
wszIssuerKey=wszMakeCertRoot; } else { // get the non-root private key set from either pvk file
// of the key container
if(fUseIssuerPvkFile) { if(S_OK!=PvkGetCryptProv( NULL, wszIssuerSig, wszIssuerProviderName, dwIssuerProviderType, wszIssuerKey, NULL, &dwIssuerKeySpec, ppwszTmpContainer, &hProv)) hProv=0; } else { if(S_OK!=PvkGetCryptProv( NULL, wszIssuerSig, wszIssuerProviderName, dwIssuerProviderType, NULL, wszIssuerKey, &dwIssuerKeySpec, ppwszTmpContainer, &hProv)) hProv=0; }
if (hProv == 0) IDSwprintf(hModule,IDS_ERR_ISSUER_KEY, wszIssuerKey); } return hProv; }
//+-------------------------------------------------------------------------
// Get the subject's private key provider
//--------------------------------------------------------------------------
static HCRYPTPROV GetSubjectProv(OUT LPWSTR *ppwszTmpContainer) { HCRYPTPROV hProv=0; WCHAR wszKeyName[40]; int ids; WCHAR *wszRegKeyName=NULL; BOOL fResult; HCRYPTKEY hKey=NULL; DWORD dwFlags = 0; DWORD dwRequiredKeySpec; HCRYPTKEY hPubKey; UUID TmpContainerUuid;
if(dwKeySpec==AT_SIGNATURE) ids=IDS_SUB_SIG; else ids=IDS_SUB_EXCHANGE;
//load the string
if(!LoadStringU(hModule, ids, wszKeyName, sizeof(wszKeyName)/sizeof(wszKeyName[0]))) goto CreateKeyError; //try to get the hProv from either a private key file or
//key container
if(fUseSubjectPvkFile) { // Try to open the PVK file if it already exists:
if(S_OK != PvkGetCryptProv(NULL, wszKeyName, wszSubjectProviderName, dwSubjectProviderType, wszSubjectKey, NULL, &dwKeySpec, ppwszTmpContainer, &hProv)) hProv=0; } else // try to open the key container to see if it exists:
{ if (dwSubjectStoreFlag == CERT_SYSTEM_STORE_LOCAL_MACHINE) { // For machine keysets, we have to do all this ourselves:
if(!CryptAcquireContextU(&hProv, wszSubjectKey, wszSubjectProviderName, dwSubjectProviderType, CRYPT_MACHINE_KEYSET)) hProv=0; else { //try to figure out the key specification
if(dwKeySpec==0) dwRequiredKeySpec=AT_SIGNATURE; else dwRequiredKeySpec=dwKeySpec; //make sure dwKeySpec is the correct key spec
if (CryptGetUserKey(hProv, dwRequiredKeySpec, &hPubKey)) { CryptDestroyKey(hPubKey); dwKeySpec = dwRequiredKeySpec; } else { //we fail if user required another key spec
if(dwKeySpec != 0) { // Doesn't have the specified public key
CryptReleaseContext(hProv, 0); hProv = 0; } else { //now we try AT_EXCHANGE key
dwRequiredKeySpec=AT_KEYEXCHANGE; if (CryptGetUserKey(hProv, dwRequiredKeySpec, &hPubKey)) { CryptDestroyKey(hPubKey); dwKeySpec = dwRequiredKeySpec; } else { // Doesn't have the specified public key
CryptReleaseContext(hProv, 0); hProv = 0; } } } } } else { // For user keysets we can use this function to try to acquire the key:
if(S_OK != PvkGetCryptProv(NULL, wszKeyName, wszSubjectProviderName, dwSubjectProviderType, NULL, wszSubjectKey, &dwKeySpec, ppwszTmpContainer, &hProv)) hProv=0; } }
// If the keyset didn't already exist, generate a new private keyset:
if (0 == hProv) { //now that we have to generate private keys, generate
//AT_SIGNATURE key by default:
if(dwKeySpec==0) dwKeySpec=AT_SIGNATURE;
//when the subject PVK file is used
if(fUseSubjectPvkFile) { // Create a temporary keyset to load the private key into
if (CoCreateGuid((GUID *)&TmpContainerUuid) != S_OK) { goto CreateKeyError; }
if (NULL == (wszRegKeyName = (LPWSTR) MakeCertAlloc (((sizeof(UUID) * 2 + 1) * sizeof(WCHAR))))) goto CreateKeyError;
BytesToWStr(sizeof(UUID), &TmpContainerUuid, wszRegKeyName);
// Open a new key container
if (!CryptAcquireContextU( &hProv, wszRegKeyName, wszSubjectProviderName, dwSubjectProviderType, CRYPT_NEWKEYSET // dwFlags
)) goto CreateKeyError;
// generate new keys in the key container
if (AT_KEYEXCHANGE == dwKeySpec && PROV_DSS_DH == dwSubjectProviderType) { if (!GenDhKey( hProv, CRYPT_EXPORTABLE // dwFlags
)) goto ErrorReturn; } else if (!CryptGenKey( hProv, dwKeySpec, (dwKeyBitLen << 16) | CRYPT_EXPORTABLE, &hKey )) goto CreateKeyError; else CryptDestroyKey(hKey);
// Save the key into the file and delete from the provider
//
HANDLE hFile = CreateFileU( wszSubjectKey, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, // lpsa
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL // hTemplateFile
);
if (hFile == INVALID_HANDLE_VALUE) { if (GetLastError() == ERROR_FILE_EXISTS) IDSwprintf(hModule,IDS_ERR_SUB_FILE_EXIST, wszSubjectKey); else IDSwprintf(hModule,IDS_ERR_SUB_FILE_CREATE, wszSubjectKey);
fResult = FALSE; } else { dwFlags = 0;
if (AT_KEYEXCHANGE == dwKeySpec && PROV_DSS_DH == dwSubjectProviderType && IsDh3Csp()) dwFlags |= CRYPT_BLOB_VER3;
fResult = PvkPrivateKeySave( hProv, hFile, dwKeySpec, NULL, // hwndOwner
wszKeyName, dwFlags ); }
//release hProv
CryptReleaseContext(hProv, 0);
fResult &= CryptAcquireContextU( &hProv, wszRegKeyName, wszSubjectProviderName, dwSubjectProviderType, CRYPT_DELETEKEYSET); hProv = 0;
if (hFile != INVALID_HANDLE_VALUE) { CloseHandle(hFile);
if (!fResult) DeleteFileU(wszSubjectKey); }
if (!fResult) goto CreateKeyError;
//get hProv
if(S_OK != PvkGetCryptProv(NULL, wszKeyName, wszSubjectProviderName, dwSubjectProviderType, wszSubjectKey, NULL, &dwKeySpec, ppwszTmpContainer, &hProv)) hProv=0; } else { // If we're not using a PVK file:
// generate a machine keyset if the cert is going to the machine store
dwFlags = CRYPT_NEWKEYSET; if (dwSubjectStoreFlag == CERT_SYSTEM_STORE_LOCAL_MACHINE) dwFlags |= CRYPT_MACHINE_KEYSET;
// Open a new key container
if (!CryptAcquireContextU( &hProv, wszSubjectKey, wszSubjectProviderName, dwSubjectProviderType, dwFlags // dwFlags
)) goto CreateKeyError;
// Before, dwFlags contained flags for CryptAcquireContext.
// Now these are flags to CSPGenKey
dwFlags = 0;
if (fPrivateKeyExportable) dwFlags |= CRYPT_EXPORTABLE;
if (AT_KEYEXCHANGE == dwKeySpec && PROV_DSS_DH == dwSubjectProviderType) { if (!GenDhKey( hProv, dwFlags // dwFlags
)) goto ErrorReturn; } else if (!CryptGenKey( hProv, dwKeySpec, (dwKeyBitLen << 16) | dwFlags, &hKey )) goto CreateKeyError; else CryptDestroyKey(hKey);
//try to get the user key
if (CryptGetUserKey( hProv, dwKeySpec, &hKey )) { CryptDestroyKey(hKey); } else { // Doesn't have the specified public key
CryptReleaseContext(hProv, 0); hProv=0; } }
if (0 == hProv ) { IDSwprintf(hModule,IDS_ERR_SUB_KEY, wszSubjectKey); goto ErrorReturn; } }//hProv==0
goto CommonReturn;
CreateKeyError: IDSwprintf(hModule,IDS_ERR_SUB_KEY_CREATE, wszSubjectKey); ErrorReturn: if (hProv) { CryptReleaseContext(hProv, 0); hProv = 0; } CommonReturn: if(wszRegKeyName) MakeCertFree(wszRegKeyName);
return hProv; }
//+-------------------------------------------------------------------------
// Allocate and get the public key info for the provider
//--------------------------------------------------------------------------
static BOOL GetPublicKey( HCRYPTPROV hProv, PCERT_PUBLIC_KEY_INFO *ppPubKeyInfo ) { BOOL fResult;
PCERT_PUBLIC_KEY_INFO pPubKeyInfo = NULL; DWORD cbPubKeyInfo;
cbPubKeyInfo = 0; CryptExportPublicKeyInfo( hProv, dwKeySpec, X509_ASN_ENCODING, NULL, // pPubKeyInfo
&cbPubKeyInfo ); if (cbPubKeyInfo == 0) { PrintLastError(IDS_ERR_EXPORT_PUB); goto ErrorReturn; } if (NULL == (pPubKeyInfo = (PCERT_PUBLIC_KEY_INFO) MakeCertAlloc(cbPubKeyInfo))) goto ErrorReturn; if (!CryptExportPublicKeyInfo( hProv, dwKeySpec, X509_ASN_ENCODING, pPubKeyInfo, &cbPubKeyInfo )) { PrintLastError(IDS_ERR_EXPORT_PUB); goto ErrorReturn; }
if (fNoPubKeyPara) { pPubKeyInfo->Algorithm.Parameters.cbData = 0; pPubKeyInfo->Algorithm.Parameters.pbData = NULL; }
if (AT_KEYEXCHANGE == dwKeySpec && PROV_DSS_DH == dwSubjectProviderType) { if (!UpdateDhPublicKey(&pPubKeyInfo)) goto ErrorReturn; }
fResult = TRUE; goto CommonReturn;
ErrorReturn: fResult = FALSE; if (pPubKeyInfo) { MakeCertFree(pPubKeyInfo); pPubKeyInfo = NULL; } CommonReturn: *ppPubKeyInfo = pPubKeyInfo; return fResult; }
//+-------------------------------------------------------------------------
// Encode the Glue Name from the input name by prepending the following
// CERT_RDN_ATTR:
// pszObjID = SPC_GLUE_RDN_OBJID
// dwValueType = CERT_RDN_PRINTABLE_STRING
// Value = "Glue"
//--------------------------------------------------------------------------
static BOOL EncodeGlueName( IN PCERT_NAME_BLOB pName, OUT BYTE **ppbEncodedGlueName, OUT DWORD *pcbEncodedGlueName ) { BOOL fResult; PCERT_NAME_INFO pNameInfo = NULL; DWORD cbNameInfo;
CERT_NAME_INFO GlueNameInfo; DWORD cGlueRDN; PCERT_RDN pGlueRDN = NULL;
BYTE *pbEncodedGlueName = NULL; DWORD cbEncodedGlueName;
DWORD i;
cbNameInfo = 0; CryptDecodeObject(X509_ASN_ENCODING, X509_UNICODE_NAME, pName->pbData, pName->cbData, 0, // dwFlags
NULL, // pNameInfo
&cbNameInfo ); if (cbNameInfo == 0) goto ErrorReturn; if (NULL == (pNameInfo = (PCERT_NAME_INFO) MakeCertAlloc(cbNameInfo))) goto ErrorReturn; if (!CryptDecodeObject(X509_ASN_ENCODING, X509_UNICODE_NAME, pName->pbData, pName->cbData, 0, // dwFlags
pNameInfo, &cbNameInfo)) goto ErrorReturn;
cGlueRDN = pNameInfo->cRDN + 1; if (NULL == (pGlueRDN = (PCERT_RDN) MakeCertAlloc(cGlueRDN * sizeof(CERT_RDN)))) goto ErrorReturn;
pGlueRDN[0].cRDNAttr = 1; pGlueRDN[0].rgRDNAttr = &GlueRDNAttr; for (i = 1; i < cGlueRDN; i++) pGlueRDN[i] = pNameInfo->rgRDN[i - 1]; GlueNameInfo.cRDN = cGlueRDN; GlueNameInfo.rgRDN = pGlueRDN;
cbEncodedGlueName = 0; CryptEncodeObject(X509_ASN_ENCODING, X509_UNICODE_NAME, &GlueNameInfo, NULL, // pbEncodedGlueName
&cbEncodedGlueName ); if (cbEncodedGlueName == 0) goto ErrorReturn; if (NULL == (pbEncodedGlueName = (BYTE *) MakeCertAlloc(cbEncodedGlueName))) goto ErrorReturn; if (!CryptEncodeObject(X509_ASN_ENCODING, X509_UNICODE_NAME, &GlueNameInfo, pbEncodedGlueName, &cbEncodedGlueName)) goto ErrorReturn;
fResult = TRUE; goto CommonReturn;
ErrorReturn: if (pbEncodedGlueName) { MakeCertFree(pbEncodedGlueName); pbEncodedGlueName = NULL; } cbEncodedGlueName = 0; fResult = FALSE; CommonReturn: if (pNameInfo) MakeCertFree(pNameInfo); if (pGlueRDN) MakeCertFree(pGlueRDN);
*ppbEncodedGlueName = pbEncodedGlueName; *pcbEncodedGlueName = cbEncodedGlueName; return fResult; }
//+-------------------------------------------------------------------------
// Get the subject's cert context and encoded name
//--------------------------------------------------------------------------
static BOOL GetRequestInfo(OUT CERT_REQUEST_INFO **ppCertInfo) { BOOL fResult = FALSE;
fResult = CryptQueryObject( CERT_QUERY_OBJECT_FILE, wszSubjectRequestFile, CERT_QUERY_CONTENT_FLAG_PKCS10, CERT_QUERY_FORMAT_FLAG_ALL, CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, NULL, NULL, NULL, (const void **)ppCertInfo);
return fResult;
}
//+-------------------------------------------------------------------------
// GetExtensionsFromRequest
//
// We get all the requested extensions from the PKCS10 request
//--------------------------------------------------------------------------
BOOL GetExtensionsFromRequest(PCERT_REQUEST_INFO pReqInfo, DWORD *pdwCount, PCERT_EXTENSIONS **pprgExtensions) { DWORD dwIndex = 0; BOOL fResult = FALSE; PCRYPT_ATTRIBUTE pAttr=NULL; DWORD cbData=0;
*pdwCount =0; *pprgExtensions=NULL;
if(!pReqInfo) goto CLEANUP;
// Look for the RSA extension OID first:
for(dwIndex=0; dwIndex < pReqInfo->cAttribute; dwIndex++) { if(0 == strcmp((pReqInfo->rgAttribute[dwIndex]).pszObjId, szOID_RSA_certExtensions)) break; }
if( dwIndex == pReqInfo->cAttribute) { // We could not find the RSA OID. Try the old Microsoft OID next:
for(dwIndex=0; dwIndex < pReqInfo->cAttribute; dwIndex++) { if(0 == strcmp((pReqInfo->rgAttribute[dwIndex]).pszObjId, SPC_CERT_EXTENSIONS_OBJID)) break; } if( dwIndex == pReqInfo->cAttribute) { // We could not find the requested extensions.
fResult = TRUE; goto CLEANUP; } }
pAttr=&(pReqInfo->rgAttribute[dwIndex]);
if(0 == pAttr->cValue) { fResult=TRUE; goto CLEANUP; }
*pprgExtensions = (PCERT_EXTENSIONS *)MakeCertAlloc((pAttr->cValue) * sizeof(PCERT_EXTENSIONS));
if(NULL == (*pprgExtensions)) goto CLEANUP;
memset(*pprgExtensions, 0, (pAttr->cValue) * sizeof(PCERT_EXTENSIONS));
for(dwIndex=0; dwIndex<pAttr->cValue; dwIndex++) { cbData = 0; if(!CryptDecodeObject(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, X509_EXTENSIONS, pAttr->rgValue[dwIndex].pbData, pAttr->rgValue[dwIndex].cbData, 0, NULL, &cbData)) goto CLEANUP;
(*pprgExtensions)[dwIndex]=(PCERT_EXTENSIONS)MakeCertAlloc(cbData);
if(NULL == (*pprgExtensions)[dwIndex]) goto CLEANUP;
if(!CryptDecodeObject(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, X509_EXTENSIONS, pAttr->rgValue[dwIndex].pbData, pAttr->rgValue[dwIndex].cbData, 0, (*pprgExtensions)[dwIndex], &cbData)) goto CLEANUP; }
*pdwCount=pAttr->cValue;
fResult = TRUE;
CLEANUP:
if(FALSE == fResult) { //we need to free the memory
if(*pprgExtensions) { for(dwIndex=0; dwIndex<pAttr->cValue; dwIndex++) { if((*pprgExtensions)[dwIndex]) MakeCertFree((*pprgExtensions)[dwIndex]); }
MakeCertFree(*pprgExtensions); *pprgExtensions = NULL; }
*pdwCount=0; }
return fResult;
}
//+-------------------------------------------------------------------------
// Get the subject's cert context and encoded name
//--------------------------------------------------------------------------
static BOOL GetSubject( OUT PCCERT_CONTEXT *ppCertContext, OUT BYTE **ppbEncodedName, OUT DWORD *pcbEncodedName ) { BOOL fResult; PCCERT_CONTEXT pCert = NULL; BYTE *pb; DWORD cb; BYTE *pbEncodedName = NULL; DWORD cbEncodedName;
if (S_OK==RetrieveBLOBFromFile(wszSubjectCertFile,&cb, &pb)) { pCert = CertCreateCertificateContext(X509_ASN_ENCODING, pb, cb); UnmapViewOfFile(pb); } if (pCert == NULL) goto BadFile;
if (0 == (cbEncodedName = pCert->pCertInfo->Subject.cbData)) goto BadFile; if (fGlueCert ) { if (!EncodeGlueName( &pCert->pCertInfo->Subject, &pbEncodedName, &cbEncodedName)) goto ErrorReturn; } else { if (NULL == (pbEncodedName = (BYTE *) MakeCertAlloc(cbEncodedName))) goto ErrorReturn; memcpy(pbEncodedName, pCert->pCertInfo->Subject.pbData, cbEncodedName); }
fResult = TRUE; goto CommonReturn;
BadFile: IDSwprintf(hModule, IDS_ERR_CANNOT_LOAD_SUB_CERT, wszSubjectCertFile); ErrorReturn: if (pbEncodedName) { MakeCertFree(pbEncodedName); pbEncodedName = NULL; } cbEncodedName = 0; if (pCert) { CertFreeCertificateContext(pCert); pCert = NULL; } fResult = FALSE; CommonReturn: *ppCertContext = pCert; *ppbEncodedName = pbEncodedName; *pcbEncodedName = cbEncodedName; return fResult; }
//+-------------------------------------------------------------------------
// Convert and encode the subject's X500 formatted name
//--------------------------------------------------------------------------
static BOOL EncodeSubject( OUT BYTE **ppbEncoded, IN OUT DWORD *pcbEncoded ) { BOOL fResult; DWORD cbEncodedSubject=0; BYTE *pbEncodedSubject=NULL; BYTE *pbEncoded = NULL; DWORD cbEncoded;
CERT_NAME_BLOB SubjectInfo;
//encode the wszSubjectX500Name into an encoded X509_NAME
if(!CertStrToNameW( X509_ASN_ENCODING, wszSubjectX500Name, CERT_NAME_STR_REVERSE_FLAG, NULL, NULL, &cbEncodedSubject, NULL)) { PrintLastError(IDS_CERT_STR_TO_NAME); goto ErrorReturn; }
pbEncodedSubject = (BYTE *) MakeCertAlloc(cbEncodedSubject); if (pbEncodedSubject == NULL) goto ErrorReturn;
if(!CertStrToNameW( X509_ASN_ENCODING, wszSubjectX500Name, CERT_NAME_STR_REVERSE_FLAG, NULL, pbEncodedSubject, &cbEncodedSubject, NULL)) { PrintLastError(IDS_CERT_STR_TO_NAME); goto ErrorReturn; }
SubjectInfo.cbData=cbEncodedSubject; SubjectInfo.pbData=pbEncodedSubject;
//add the GLUE CDRT_RDN_ATTR
if (fGlueCert) { if(!EncodeGlueName(&SubjectInfo, &pbEncoded, &cbEncoded)) goto ErrorReturn; } else { cbEncoded=cbEncodedSubject; pbEncoded=pbEncodedSubject; }
fResult = TRUE; goto CommonReturn;
ErrorReturn: if (pbEncoded) { MakeCertFree(pbEncoded); pbEncoded = NULL; } cbEncoded = 0; fResult = FALSE; CommonReturn: //we need to free the memory for pbEncodedSubject for GlueCert
if(fGlueCert) { if(pbEncodedSubject) { MakeCertFree(pbEncodedSubject); pbEncodedSubject=NULL; } } *ppbEncoded = pbEncoded; *pcbEncoded = cbEncoded; return fResult; }
// The test root's public key isn't encoded properly in the certificate.
// It's missing a leading zero to make it a unsigned integer.
static BYTE rgbTestRoot[] = { #include "root.h"
}; static CERT_PUBLIC_KEY_INFO TestRootPublicKeyInfo = { szOID_RSA_RSA, 0, NULL, sizeof(rgbTestRoot), rgbTestRoot, 0 };
static BYTE rgbTestRootInfoAsn[] = { #include "rootasn.h"
};
//+-------------------------------------------------------------------------
// X509 Extensions: Allocate and Encode functions
//--------------------------------------------------------------------------
static BOOL CreateAuthorityKeyId( IN HCRYPTPROV hProv, IN PCERT_INFO pIssuerCert, OUT BYTE **ppbEncoded, IN OUT DWORD *pcbEncoded ) { BOOL fResult; BYTE *pbEncoded = NULL; DWORD cbEncoded; CERT_AUTHORITY_KEY_ID_INFO KeyIdInfo; #define MAX_HASH_LEN 20
BYTE rgbHash[MAX_HASH_LEN]; DWORD cbHash = MAX_HASH_LEN;
// Issuer's KeyId: MD5 hash of the encoded issuer's public key info
// First check if the issuer is the test root with an incorrectly
// encoded public key.
if (CertComparePublicKeyInfo( X509_ASN_ENCODING, &pIssuerCert->SubjectPublicKeyInfo, &TestRootPublicKeyInfo )) { if (!CryptHashCertificate( hProv, CALG_MD5, 0, // dwFlags
rgbTestRootInfoAsn, sizeof(rgbTestRootInfoAsn), rgbHash, &cbHash)) { PrintLastError(IDS_CRYPT_HASH_CERT); goto ErrorReturn; } } else { if (!CryptHashPublicKeyInfo( hProv, CALG_MD5, 0, // dwFlags
X509_ASN_ENCODING, &pIssuerCert->SubjectPublicKeyInfo, rgbHash, &cbHash)) { PrintLastError(IDS_CRYPT_HASP_PUB); goto ErrorReturn; } } KeyIdInfo.KeyId.pbData = rgbHash; KeyIdInfo.KeyId.cbData = cbHash;
// Issuer's Issuer
KeyIdInfo.CertIssuer = pIssuerCert->Issuer;
// Issuer's SerialNumber
KeyIdInfo.CertSerialNumber = pIssuerCert->SerialNumber;
cbEncoded = 0; CryptEncodeObject(X509_ASN_ENCODING, X509_AUTHORITY_KEY_ID, &KeyIdInfo, NULL, // pbEncoded
&cbEncoded ); if (cbEncoded == 0) { PrintLastError(IDS_ENCODE_AUTH_KEY); goto ErrorReturn; } pbEncoded = (BYTE *) MakeCertAlloc(cbEncoded); if (pbEncoded == NULL) goto ErrorReturn; if (!CryptEncodeObject(X509_ASN_ENCODING, X509_AUTHORITY_KEY_ID, &KeyIdInfo, pbEncoded, &cbEncoded )) { PrintLastError(IDS_ENCODE_AUTH_KEY); goto ErrorReturn; }
fResult = TRUE; goto CommonReturn;
ErrorReturn: if (pbEncoded) { MakeCertFree(pbEncoded); pbEncoded = NULL; } cbEncoded = 0; fResult = FALSE; CommonReturn: *ppbEncoded = pbEncoded; *pcbEncoded = cbEncoded; return fResult; }
static BOOL CreateSpcSpAgency( OUT BYTE **ppbEncoded, IN OUT DWORD *pcbEncoded ) { BOOL fResult; BYTE *pbEncoded = NULL; DWORD cbEncoded;
SPC_LINK PolicyLink; SPC_SP_AGENCY_INFO AgencyInfo;
memset(&AgencyInfo, 0, sizeof(AgencyInfo));
if (wszPolicyLink) { PolicyLink.dwLinkChoice = SPC_URL_LINK_CHOICE; PolicyLink.pwszUrl = wszPolicyLink; AgencyInfo.pPolicyInformation = &PolicyLink; }
cbEncoded = 0; CryptEncodeObject(X509_ASN_ENCODING, SPC_SP_AGENCY_INFO_OBJID, &AgencyInfo, NULL, // pbEncoded
&cbEncoded); if (cbEncoded == 0) { PrintLastError(IDS_ENCODE_SPC_AGENCY); goto ErrorReturn; } pbEncoded = (BYTE *) MakeCertAlloc(cbEncoded); if (pbEncoded == NULL) goto ErrorReturn; if (!CryptEncodeObject(X509_ASN_ENCODING, SPC_SP_AGENCY_INFO_STRUCT, &AgencyInfo, pbEncoded, &cbEncoded )) { PrintLastError(IDS_ENCODE_SPC_AGENCY); goto ErrorReturn; }
fResult = TRUE; goto CommonReturn;
ErrorReturn: if (pbEncoded) { MakeCertFree(pbEncoded); pbEncoded = NULL; } cbEncoded = 0; fResult = FALSE; CommonReturn: *ppbEncoded = pbEncoded; *pcbEncoded = cbEncoded; return fResult; }
static BOOL CreateEnhancedKeyUsage( OUT BYTE **ppbEncoded, IN OUT DWORD *pcbEncoded ) { BOOL fResult = FALSE; LPBYTE pbEncoded =NULL; DWORD cbEncoded =0; DWORD cCount =0; LPSTR psz=NULL; LPSTR pszTok=NULL; DWORD cTok = 0; PCERT_ENHKEY_USAGE pUsage =NULL; LPSTR pszCodeSigning = szOID_PKIX_KP_CODE_SIGNING; BOOL fFound=FALSE;
if(wszEKUOids) { if ( WSZtoSZ(wszEKUOids, &psz) != S_OK ) goto CLEANUP;
//
// Count the number of OIDs as well as converting from comma delimited
// to NULL character delimited
//
pszTok = strtok(psz, ","); while ( pszTok != NULL ) { cTok++; pszTok = strtok(NULL, ","); }
//
// Allocate a cert enhanced key usage structure and fill it in with
// the string tokens
//
// we allocate one more string for the code signing OIDs
//
pUsage = (PCERT_ENHKEY_USAGE)new BYTE [sizeof(CERT_ENHKEY_USAGE) + ( (cTok + 1) * sizeof(LPSTR) )];
if(NULL == pUsage) goto CLEANUP;
pszTok = psz; pUsage->cUsageIdentifier = cTok; pUsage->rgpszUsageIdentifier = (LPSTR *)((LPBYTE)pUsage+sizeof(CERT_ENHKEY_USAGE));
for ( cCount = 0; cCount < cTok; cCount++ ) { pUsage->rgpszUsageIdentifier[cCount] = pszTok; pszTok = pszTok+strlen(pszTok)+1; }
//we add the code signing OID if use has specified commerical or individual signing
if(fCertCommercial || fCertIndividual) { //check to see if the code signing OID is alreayd present
for(cCount = 0; cCount < pUsage->cUsageIdentifier; cCount++) { if(0 == strcmp(pszCodeSigning,pUsage->rgpszUsageIdentifier[cCount])) { fFound=TRUE; break; } }
if(FALSE == fFound) { (pUsage->rgpszUsageIdentifier)[pUsage->cUsageIdentifier] = pszCodeSigning; (pUsage->cUsageIdentifier)++ ; } } } else { if(fCertCommercial || fCertIndividual) {
pUsage = (PCERT_ENHKEY_USAGE)new BYTE [sizeof(CERT_ENHKEY_USAGE)];
if(NULL == pUsage) goto CLEANUP;
pUsage->cUsageIdentifier = 1; pUsage->rgpszUsageIdentifier = &pszCodeSigning; } else { goto CLEANUP; } }
//
// Encode the usage
//
if(!CryptEncodeObject( X509_ASN_ENCODING, szOID_ENHANCED_KEY_USAGE, pUsage, NULL, &cbEncoded )) goto CLEANUP;
pbEncoded = new BYTE [cbEncoded];
if(NULL == pbEncoded) goto CLEANUP;
fResult = CryptEncodeObject( X509_ASN_ENCODING, szOID_ENHANCED_KEY_USAGE, pUsage, pbEncoded, &cbEncoded );
//
// Cleanup
//
CLEANUP:
if(pUsage) delete[] pUsage;
if(psz) MakeCertFree(psz);
if ( TRUE == fResult) { *ppbEncoded = pbEncoded; *pcbEncoded = cbEncoded; } else { if(pbEncoded) delete[] pbEncoded; }
return fResult; }
static BOOL CreateKeyUsage( OUT BYTE **ppbEncoded, IN OUT DWORD *pcbEncoded ) { BOOL fResult; BYTE *pbEncoded = NULL; DWORD cbEncoded; CERT_KEY_USAGE_RESTRICTION_INFO KeyUsageInfo; BYTE bRestrictedKeyUsage; DWORD cCertPolicyId;
LPSTR rgpszIndividualCertPolicyElementId[1] = { SPC_INDIVIDUAL_SP_KEY_PURPOSE_OBJID }; LPSTR rgpszCommercialCertPolicyElementId[1] = { SPC_COMMERCIAL_SP_KEY_PURPOSE_OBJID }; CERT_POLICY_ID rgCertPolicyId[2];
memset(&KeyUsageInfo, 0, sizeof(KeyUsageInfo));
bRestrictedKeyUsage = CERT_DIGITAL_SIGNATURE_KEY_USAGE; KeyUsageInfo.RestrictedKeyUsage.pbData = &bRestrictedKeyUsage; KeyUsageInfo.RestrictedKeyUsage.cbData = 1; KeyUsageInfo.RestrictedKeyUsage.cUnusedBits = 7;
cCertPolicyId = 0; if (fCertIndividual) { rgCertPolicyId[cCertPolicyId].cCertPolicyElementId = 1; rgCertPolicyId[cCertPolicyId].rgpszCertPolicyElementId = rgpszIndividualCertPolicyElementId; cCertPolicyId++; } if (fCertCommercial) { rgCertPolicyId[cCertPolicyId].cCertPolicyElementId = 1; rgCertPolicyId[cCertPolicyId].rgpszCertPolicyElementId = rgpszCommercialCertPolicyElementId; cCertPolicyId++; }
if (cCertPolicyId > 0) { KeyUsageInfo.cCertPolicyId = cCertPolicyId; KeyUsageInfo.rgCertPolicyId = rgCertPolicyId; }
cbEncoded = 0; CryptEncodeObject(X509_ASN_ENCODING, X509_KEY_USAGE_RESTRICTION, &KeyUsageInfo, NULL, // pbEncoded
&cbEncoded ); if (cbEncoded == 0) { PrintLastError(IDS_ENCODE_KEY_USAGE); goto ErrorReturn; } pbEncoded = (BYTE *) MakeCertAlloc(cbEncoded); if (pbEncoded == NULL) goto ErrorReturn; if (!CryptEncodeObject(X509_ASN_ENCODING, X509_KEY_USAGE_RESTRICTION, &KeyUsageInfo, pbEncoded, &cbEncoded )) { PrintLastError(IDS_ENCODE_KEY_USAGE); goto ErrorReturn; }
fResult = TRUE; goto CommonReturn;
ErrorReturn: if (pbEncoded) { MakeCertFree(pbEncoded); pbEncoded = NULL; } cbEncoded = 0; fResult = FALSE; CommonReturn: *ppbEncoded = pbEncoded; *pcbEncoded = cbEncoded; return fResult; }
static BOOL CreateBasicConstraints( OUT BYTE **ppbEncoded, IN OUT DWORD *pcbEncoded ) { BOOL fResult; BYTE *pbEncoded = NULL; DWORD cbEncoded; CERT_BASIC_CONSTRAINTS2_INFO Info2;
memset(&Info2, 0, sizeof(Info2)); if (certTypes == 0) certTypes = CERT_END_ENTITY_SUBJECT_FLAG;
if (CERT_CA_SUBJECT_FLAG & certTypes) { Info2.fCA = TRUE; }
if (pathLenConstraint < 0) { Info2.fPathLenConstraint = FALSE; } else { Info2.fPathLenConstraint = TRUE; Info2.dwPathLenConstraint = pathLenConstraint; }
cbEncoded = 0; CryptEncodeObject(X509_ASN_ENCODING, X509_BASIC_CONSTRAINTS2, &Info2, NULL, // pbEncoded
&cbEncoded ); if (cbEncoded == 0) { PrintLastError(IDS_ENCODE_BASIC_CONSTRAINTS2); goto ErrorReturn; } pbEncoded = (BYTE *) MakeCertAlloc(cbEncoded); if (pbEncoded == NULL) goto ErrorReturn; if (!CryptEncodeObject(X509_ASN_ENCODING, X509_BASIC_CONSTRAINTS2, &Info2, pbEncoded, &cbEncoded )) { PrintLastError(IDS_ENCODE_BASIC_CONSTRAINTS2); goto ErrorReturn; }
fResult = TRUE; goto CommonReturn;
ErrorReturn: if (pbEncoded) { MakeCertFree(pbEncoded); pbEncoded = NULL; } cbEncoded = 0; fResult = FALSE; CommonReturn: *ppbEncoded = pbEncoded; *pcbEncoded = cbEncoded; return fResult; }
//+-------------------------------------------------------------------------
// Converts the bytes into WCHAR hex
//
// Needs (cb * 2 + 1) * sizeof(WCHAR) bytes of space in wsz
//--------------------------------------------------------------------------
static void BytesToWStr(ULONG cb, void* pv, LPWSTR wsz) { BYTE* pb = (BYTE*) pv; for (ULONG i = 0; i<cb; i++) { int b; b = (*pb & 0xF0) >> 4; *wsz++ = (b <= 9) ? b + L'0' : (b - 10) + L'A'; b = *pb & 0x0F; *wsz++ = (b <= 9) ? b + L'0' : (b - 10) + L'A'; pb++; } *wsz++ = 0; }
//-----------------------------------------------------------------------
//
// Get the hash from a cert file
//
//--------------------------------------------------------------------------
HRESULT GetCertHashFromFile(LPWSTR pwszCertFile, BYTE **ppHash, DWORD *pcbHash, BOOL *pfMore) { HRESULT hr; HCERTSTORE hCertStore=NULL; PCCERT_CONTEXT pSigningCert=NULL; PCCERT_CONTEXT pPreCert=NULL; PCCERT_CONTEXT pDupCert=NULL; DWORD dwCount=0;
if(!ppHash || !pcbHash || !pfMore) return E_INVALIDARG;
//init
*pcbHash=0; *ppHash=NULL; *pfMore=FALSE; //open a cert store
hCertStore=CertOpenStore(CERT_STORE_PROV_FILENAME_W, dwCertStoreEncodingType, NULL, 0, pwszCertFile);
if(hCertStore==NULL) { hr=SignError(); goto CLEANUP; }
while(pDupCert=CertEnumCertificatesInStore(hCertStore, pPreCert)) { dwCount++;
// Fail if there is more than one cert in the store
if(dwCount > 1) { CertFreeCertificateContext(pDupCert); pDupCert=NULL; CertFreeCertificateContext(pSigningCert); pSigningCert=NULL;
*pfMore=TRUE; hr=E_FAIL; goto CLEANUP; }
pPreCert=pDupCert;
pSigningCert=CertDuplicateCertificateContext(pDupCert);
}
if(pSigningCert==NULL) { hr=CRYPT_E_NO_DECRYPT_CERT; goto CLEANUP; }
//get the hash
if(!CertGetCertificateContextProperty(pSigningCert, CERT_SHA1_HASH_PROP_ID, NULL, pcbHash)) { hr=SignError(); goto CLEANUP; }
*ppHash=(BYTE *)ToolUtlAlloc(*pcbHash); if(!(*ppHash)) { hr=E_OUTOFMEMORY; goto CLEANUP; }
if(!CertGetCertificateContextProperty(pSigningCert, CERT_SHA1_HASH_PROP_ID, *ppHash, pcbHash)) { hr=SignError(); goto CLEANUP; }
hr=S_OK;
CLEANUP:
if(pSigningCert) CertFreeCertificateContext(pSigningCert);
if(hCertStore) CertCloseStore(hCertStore, 0);
if(hr!=S_OK) { if(*ppHash) { ToolUtlFree(*ppHash); *ppHash=NULL; }
}
return hr; }
//-----------------------------------------------------------------------
//
// Get the signing certificate
//
//--------------------------------------------------------------------------
PCCERT_CONTEXT GetIssuerCertAndStore(HCERTSTORE *phCertStore, BOOL *pfMore) { PCCERT_CONTEXT pSigningCert=NULL; PCCERT_CONTEXT pPreCert=NULL; PCCERT_CONTEXT pDupCert=NULL; BYTE *pHash=NULL; DWORD cbHash; HCERTSTORE hCertStore=NULL; CRYPT_HASH_BLOB HashBlob; DWORD dwCount=0;
//init the output
if(!phCertStore || !pfMore) return NULL;
*phCertStore=NULL; *pfMore=FALSE;
//open a cert store
hCertStore=CertOpenStore(CERT_STORE_PROV_SYSTEM_W, dwCertStoreEncodingType, NULL, dwIssuerStoreFlag|CERT_STORE_READONLY_FLAG, wszIssuerStore);
if(!hCertStore) return NULL;
//get the hash of the certificate. Find the cert based on
//pwszCertFile
if(wszIssuerCertFile) { if(S_OK != GetCertHashFromFile(wszIssuerCertFile, &pHash, &cbHash, pfMore)) goto CLEANUP; HashBlob.cbData=cbHash; HashBlob.pbData=pHash;
pSigningCert=CertFindCertificateInStore(hCertStore, X509_ASN_ENCODING, 0, CERT_FIND_SHA1_HASH, &HashBlob, NULL); } else { //find the certificate with the common name
if(wszIssuerCertName) { while(pDupCert=CertFindCertificateInStore(hCertStore, X509_ASN_ENCODING, 0, CERT_FIND_SUBJECT_STR_W, wszIssuerCertName, pPreCert)) { dwCount++;
if(dwCount > 1) { CertFreeCertificateContext(pDupCert); pDupCert=NULL; CertFreeCertificateContext(pSigningCert); pSigningCert=NULL;
*pfMore=TRUE; goto CLEANUP; }
pPreCert=pDupCert;
pSigningCert=CertDuplicateCertificateContext(pDupCert);
} } else { //no searching criteria, find the only cert in the store
while(pDupCert=CertEnumCertificatesInStore(hCertStore, pPreCert)) { dwCount++;
if(dwCount > 1) { CertFreeCertificateContext(pDupCert); pDupCert=NULL; CertFreeCertificateContext(pSigningCert); pSigningCert=NULL;
*pfMore=TRUE; goto CLEANUP; }
pPreCert=pDupCert;
pSigningCert=CertDuplicateCertificateContext(pDupCert);
} } } CLEANUP:
if(pHash) ToolUtlFree(pHash);
if(pSigningCert) { *phCertStore=hCertStore; } else { //free the hCertStore
CertCloseStore(hCertStore, 0); }
return pSigningCert;
}
//-----------------------------------------------------------------------
//
// EmptySubject
//
//--------------------------------------------------------------------------
BOOL EmptySubject(CERT_NAME_BLOB *pSubject) { BOOL fEmpty = TRUE; CERT_NAME_INFO *pCertNameInfo=NULL; DWORD cbData =0; if(!pSubject) goto CLEANUP;
if(!CryptDecodeObject(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, X509_UNICODE_NAME, pSubject->pbData, pSubject->cbData, 0, NULL, &cbData)) goto CLEANUP;
pCertNameInfo = (CERT_NAME_INFO *)MakeCertAlloc(cbData); if(NULL == pCertNameInfo) goto CLEANUP;
if(!CryptDecodeObject(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, X509_UNICODE_NAME, pSubject->pbData, pSubject->cbData, 0, pCertNameInfo, &cbData)) goto CLEANUP;
if((pCertNameInfo->cRDN) > 0) fEmpty = FALSE;
CLEANUP:
if(pCertNameInfo) MakeCertFree(pCertNameInfo);
return fEmpty;
}
//+=========================================================================
// Support functions to generate DH keys having the 'Q'parameter
//==========================================================================
static BOOL EncodeAndAllocObject( IN LPCSTR lpszStructType, IN const void *pvStructInfo, OUT BYTE **ppbEncoded, IN OUT DWORD *pcbEncoded ) { BOOL fResult; BYTE *pbEncoded = NULL; DWORD cbEncoded = 0;
if (!CryptEncodeObject( X509_ASN_ENCODING, lpszStructType, pvStructInfo, NULL, &cbEncoded )) goto ErrorReturn; if (NULL == (pbEncoded = (BYTE *) MakeCertAlloc(cbEncoded))) goto ErrorReturn; if (!CryptEncodeObject( X509_ASN_ENCODING, lpszStructType, pvStructInfo, pbEncoded, &cbEncoded )) goto ErrorReturn;
fResult = TRUE;
CommonReturn: *ppbEncoded = pbEncoded; *pcbEncoded = cbEncoded; return fResult;
ErrorReturn: fResult = FALSE; MakeCertFree(pbEncoded); pbEncoded = NULL; goto CommonReturn; }
static BOOL DecodeAndAllocObject( IN LPCSTR lpszStructType, IN const BYTE *pbEncoded, IN DWORD cbEncoded, OUT void **ppvStructInfo, IN OUT DWORD *pcbStructInfo ) { BOOL fResult; void *pvStructInfo = NULL; DWORD cbStructInfo = 0;
if (!CryptDecodeObject( X509_ASN_ENCODING, lpszStructType, pbEncoded, cbEncoded, 0, // dwFlags
NULL, &cbStructInfo )) goto ErrorReturn; if (NULL == (pvStructInfo = MakeCertAlloc(cbStructInfo))) goto ErrorReturn; if (!CryptDecodeObject( X509_ASN_ENCODING, lpszStructType, pbEncoded, cbEncoded, 0, // dwFlags
pvStructInfo, &cbStructInfo )) goto ErrorReturn;
fResult = TRUE;
CommonReturn: *ppvStructInfo = pvStructInfo; *pcbStructInfo = cbStructInfo; return fResult;
ErrorReturn: fResult = FALSE; MakeCertFree(pvStructInfo); pvStructInfo = NULL; goto CommonReturn; }
static BYTE rgbDhQ[21]; static CRYPT_UINT_BLOB DhQ = {0, NULL};
static BOOL GetDhParaFromCertFile( OUT PCERT_X942_DH_PARAMETERS *ppX942DhPara ) { BOOL fResult; PCCERT_CONTEXT pDhCert = NULL; PCERT_X942_DH_PARAMETERS pX942DhPara = NULL;
BYTE *pb; DWORD cb;
if (S_OK == RetrieveBLOBFromFile(wszDhParaCertFile, &cb, &pb)) { pDhCert = CertCreateCertificateContext(X509_ASN_ENCODING, pb, cb); UnmapViewOfFile(pb); } if (pDhCert == NULL) goto DhParaCertFileError;
if (!DecodeAndAllocObject( X942_DH_PARAMETERS, pDhCert->pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.pbData, pDhCert->pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.cbData, (void **) &pX942DhPara, &cb )) goto DhParaCertFileError;
fResult = TRUE; CommonReturn: CertFreeCertificateContext(pDhCert); *ppX942DhPara = pX942DhPara; return fResult;
DhParaCertFileError: IDSwprintf(hModule, IDS_ERR_DH_PARA_FILE, wszDhParaCertFile); MakeCertFree(pX942DhPara); pX942DhPara = NULL; fResult = FALSE; goto CommonReturn; }
static BOOL GetDhParaFromDssKey( OUT PCERT_DSS_PARAMETERS *ppDssPara ) { BOOL fResult; HCRYPTPROV hProv = 0; HCRYPTKEY hKey = 0; WCHAR *wszRegKeyName = NULL; UUID TmpContainerUuid; PCERT_DSS_PARAMETERS pDssPara = NULL; PCERT_PUBLIC_KEY_INFO pPubKeyInfo = NULL; DWORD cbPubKeyInfo; DWORD cbDssPara;
// Create a temporary keyset to load the private key into
if (CoCreateGuid((GUID *)&TmpContainerUuid) != S_OK) { goto CreateKeyError; }
if (NULL == (wszRegKeyName = (LPWSTR) MakeCertAlloc (((sizeof(UUID) * 2 + 1) * sizeof(WCHAR))))) goto CreateKeyError;
BytesToWStr(sizeof(UUID), &TmpContainerUuid, wszRegKeyName);
// Open a new key container
if (!CryptAcquireContextU( &hProv, wszRegKeyName, wszSubjectProviderName, dwSubjectProviderType, CRYPT_NEWKEYSET // dwFlags
)) { hProv = 0; goto CreateKeyError; }
if (0 == dwKeyBitLen) dwKeyBitLen = 512; // generate new DSS key in the key container
if (!CryptGenKey( hProv, AT_SIGNATURE, (dwKeyBitLen << 16) | CRYPT_EXPORTABLE, &hKey )) goto CreateKeyError; else CryptDestroyKey(hKey);
cbPubKeyInfo = 0; CryptExportPublicKeyInfo( hProv, AT_SIGNATURE, X509_ASN_ENCODING, NULL, // pPubKeyInfo
&cbPubKeyInfo ); if (cbPubKeyInfo == 0) { PrintLastError(IDS_ERR_EXPORT_PUB); goto ErrorReturn; } if (NULL == (pPubKeyInfo = (PCERT_PUBLIC_KEY_INFO) MakeCertAlloc(cbPubKeyInfo))) goto ErrorReturn; if (!CryptExportPublicKeyInfo( hProv, AT_SIGNATURE, X509_ASN_ENCODING, pPubKeyInfo, &cbPubKeyInfo )) { PrintLastError(IDS_ERR_EXPORT_PUB); goto ErrorReturn; }
if (!DecodeAndAllocObject( X509_DSS_PARAMETERS, pPubKeyInfo->Algorithm.Parameters.pbData, pPubKeyInfo->Algorithm.Parameters.cbData, (void **) &pDssPara, &cbDssPara )) goto CreateKeyError;
// Save away the DSS 'Q' parameter. It will be used in GetPublicKey()
// to update the DH parameters in the PublicKeyInfo
if (pDssPara->q.cbData <= sizeof(rgbDhQ)) { memcpy(rgbDhQ, pDssPara->q.pbData, pDssPara->q.cbData); DhQ.cbData = pDssPara->q.cbData; DhQ.pbData = rgbDhQ; }
fResult = TRUE; CommonReturn: if (hProv) { // Delete the just created DSS key
CryptReleaseContext(hProv, 0); CryptAcquireContextU( &hProv, wszRegKeyName, wszSubjectProviderName, dwSubjectProviderType, CRYPT_DELETEKEYSET ); } MakeCertFree(wszRegKeyName); MakeCertFree(pPubKeyInfo);
*ppDssPara = pDssPara; return fResult;
CreateKeyError: IDSwprintf(hModule,IDS_ERR_SUB_KEY_CREATE, wszSubjectKey); ErrorReturn: MakeCertFree(pDssPara); pDssPara = NULL; fResult = FALSE; goto CommonReturn; }
#ifndef DH3
#define DH3 (((DWORD)'D'<<8)+((DWORD)'H'<<16)+((DWORD)'3'<<24))
#endif
static BOOL CreateDh3PubKeyStruc( IN PCERT_X942_DH_PARAMETERS pX942DhPara, OUT PUBLICKEYSTRUC **ppPubKeyStruc, OUT DWORD *pcbPubKeyStruc ) { BOOL fResult; PUBLICKEYSTRUC *pPubKeyStruc = NULL; DWORD cbPubKeyStruc; BYTE *pbKeyBlob; DHPUBKEY_VER3 *pCspPubKey; BYTE *pbKey;
DWORD cbP; DWORD cbQ; DWORD cbJ; DWORD cb;
cbP = pX942DhPara->p.cbData; cbQ = pX942DhPara->q.cbData; cbJ = pX942DhPara->j.cbData;
if (0 == cbQ) { *ppPubKeyStruc = NULL; *pcbPubKeyStruc = 0; return TRUE; }
// The CAPI public key representation consists of the following sequence:
// - PUBLICKEYSTRUC
// - DHPUBKEY_VER3
// - rgbP[cbP]
// - rgbQ[cbQ]
// - rgbG[cbP]
// - rgbJ[cbJ] -- optional
// - rgbY[cbP] -- will be omitted here
cbPubKeyStruc = sizeof(PUBLICKEYSTRUC) + sizeof(DHPUBKEY_VER3) + cbP + cbQ + cbP + cbJ;
if (NULL == (pPubKeyStruc = (PUBLICKEYSTRUC *) MakeCertAlloc( cbPubKeyStruc))) goto ErrorReturn; memset(pPubKeyStruc, 0, cbPubKeyStruc);
pbKeyBlob = (BYTE *) pPubKeyStruc; pCspPubKey = (DHPUBKEY_VER3 *) (pbKeyBlob + sizeof(PUBLICKEYSTRUC)); pbKey = pbKeyBlob + sizeof(PUBLICKEYSTRUC) + sizeof(DHPUBKEY_VER3);
pPubKeyStruc->bType = PUBLICKEYBLOB; pPubKeyStruc->bVersion = 3; pPubKeyStruc->aiKeyAlg = CALG_DH_SF; pCspPubKey->magic = DH3; pCspPubKey->bitlenP = cbP * 8; pCspPubKey->bitlenQ = cbQ * 8; pCspPubKey->bitlenJ = cbJ * 8;
pCspPubKey->DSSSeed.counter = 0xFFFFFFFF; if (pX942DhPara->pValidationParams) { PCERT_X942_DH_VALIDATION_PARAMS pValidationParams;
pValidationParams = pX942DhPara->pValidationParams; if (0 != pValidationParams->pgenCounter && sizeof(pCspPubKey->DSSSeed.seed) == pValidationParams->seed.cbData) { pCspPubKey->DSSSeed.counter = pValidationParams->pgenCounter; memcpy(pCspPubKey->DSSSeed.seed, pValidationParams->seed.pbData, sizeof(pCspPubKey->DSSSeed.seed)); } }
// rgbP[cbP]
memcpy(pbKey, pX942DhPara->p.pbData, cbP); pbKey += cbP;
// rgbQ[cbQ]
memcpy(pbKey, pX942DhPara->q.pbData, cbQ); pbKey += cbQ;
// rgbG[cbP]
cb = pX942DhPara->g.cbData; if (0 == cb || cb > cbP) goto ErrorReturn; memcpy(pbKey, pX942DhPara->g.pbData, cb); if (cbP > cb) memset(pbKey + cb, 0, cbP - cb); pbKey += cbP;
// rgbJ[cbJ]
if (cbJ) { memcpy(pbKey, pX942DhPara->j.pbData, cbJ); pbKey += cbJ; }
fResult = TRUE;
CommonReturn: *ppPubKeyStruc = pPubKeyStruc; *pcbPubKeyStruc = cbPubKeyStruc; return fResult; ErrorReturn: MakeCertFree(pPubKeyStruc); pPubKeyStruc = NULL; cbPubKeyStruc = 0; fResult = FALSE; goto CommonReturn; }
static BOOL IsDh3Csp() { BOOL fResult; HCRYPTPROV hProv = 0; HCRYPTKEY hKey = 0; WCHAR *wszRegKeyName = NULL; UUID TmpContainerUuid; PCERT_X942_DH_PARAMETERS pX942DhPara = NULL; PCERT_PUBLIC_KEY_INFO pPubKeyInfo = NULL; DWORD cbPubKeyInfo; DWORD cbX942DhPara;
// Create a temporary keyset to load the private key into
if (CoCreateGuid((GUID *)&TmpContainerUuid) != S_OK) { goto CreateKeyError; }
if (NULL == (wszRegKeyName = (LPWSTR) MakeCertAlloc (((sizeof(UUID) * 2 + 1) * sizeof(WCHAR))))) goto CreateKeyError;
BytesToWStr(sizeof(UUID), &TmpContainerUuid, wszRegKeyName);
// Open a new key container
if (!CryptAcquireContextU( &hProv, wszRegKeyName, wszSubjectProviderName, dwSubjectProviderType, CRYPT_NEWKEYSET // dwFlags
)) { hProv = 0; goto CreateKeyError; }
// generate new DH key in the key container
if (!CryptGenKey( hProv, AT_KEYEXCHANGE, (512 << 16) | CRYPT_EXPORTABLE, &hKey )) goto CreateKeyError; else CryptDestroyKey(hKey);
cbPubKeyInfo = 0; CryptExportPublicKeyInfo( hProv, AT_KEYEXCHANGE, X509_ASN_ENCODING, NULL, // pPubKeyInfo
&cbPubKeyInfo ); if (cbPubKeyInfo == 0) { PrintLastError(IDS_ERR_EXPORT_PUB); goto ErrorReturn; } if (NULL == (pPubKeyInfo = (PCERT_PUBLIC_KEY_INFO) MakeCertAlloc(cbPubKeyInfo))) goto ErrorReturn; if (!CryptExportPublicKeyInfo( hProv, AT_KEYEXCHANGE, X509_ASN_ENCODING, pPubKeyInfo, &cbPubKeyInfo )) { PrintLastError(IDS_ERR_EXPORT_PUB); goto ErrorReturn; }
if (!DecodeAndAllocObject( X942_DH_PARAMETERS, pPubKeyInfo->Algorithm.Parameters.pbData, pPubKeyInfo->Algorithm.Parameters.cbData, (void **) &pX942DhPara, &cbX942DhPara )) goto CreateKeyError;
if (pX942DhPara->q.cbData) // Q para is only supported in Dh3 version of CSP
fResult = TRUE; else fResult = FALSE; CommonReturn: if (hProv) { // Delete the just created DH key
CryptReleaseContext(hProv, 0); CryptAcquireContextU( &hProv, wszRegKeyName, wszSubjectProviderName, dwSubjectProviderType, CRYPT_DELETEKEYSET ); } MakeCertFree(wszRegKeyName); MakeCertFree(pX942DhPara); MakeCertFree(pPubKeyInfo);
return fResult;
CreateKeyError: IDSwprintf(hModule,IDS_ERR_SUB_KEY_CREATE, wszSubjectKey); ErrorReturn: fResult = FALSE; goto CommonReturn; }
static BOOL GenDhKey( IN HCRYPTPROV hProv, IN DWORD dwFlags ) { BOOL fResult; HCRYPTKEY hKey = 0; PCERT_X942_DH_PARAMETERS pX942DhPara = NULL; PCERT_DSS_PARAMETERS pDssPara = NULL;
PCRYPT_UINT_BLOB pP; PCRYPT_UINT_BLOB pG; DWORD cbP;
PUBLICKEYSTRUC *pDh3PubKeyStruc = NULL; DWORD cbDh3PubKeyStruc; BOOL fSetKeyPara;
if (wszDhParaCertFile) { if (!GetDhParaFromCertFile(&pX942DhPara)) goto ErrorReturn;
CreateDh3PubKeyStruc(pX942DhPara, &pDh3PubKeyStruc, &cbDh3PubKeyStruc);
pP = &pX942DhPara->p; pG = &pX942DhPara->g; } else if (dwKeyBitLen > 1024 || IsDh3Csp()) { // generate new keys in the key container
if (!CryptGenKey( hProv, AT_KEYEXCHANGE, (dwKeyBitLen << 16) | dwFlags, &hKey )) { hKey = 0; goto CreateKeyError; } else goto SuccessReturn; } else { if (!GetDhParaFromDssKey(&pDssPara)) goto ErrorReturn;
pP = &pDssPara->p; pG = &pDssPara->g; }
cbP = pP->cbData; if (!CryptGenKey( hProv, CALG_DH_SF, ((cbP * 8) << 16) | CRYPT_PREGEN | dwFlags, &hKey)) { hKey = 0; goto CreateKeyError; }
fSetKeyPara = FALSE; if (pDh3PubKeyStruc) { CRYPT_DATA_BLOB Dh3Blob;
Dh3Blob.pbData = (PBYTE) pDh3PubKeyStruc; Dh3Blob.cbData = cbDh3PubKeyStruc;
if (CryptSetKeyParam( hKey, KP_PUB_PARAMS, (PBYTE) &Dh3Blob, 0)) // dwFlags
fSetKeyPara = TRUE; }
if (!fSetKeyPara) { if (!CryptSetKeyParam( hKey, KP_P, (PBYTE) pP, 0)) // dwFlags
goto CreateKeyError;
// Note, the length of G can be less than length P. Pad with leading
// zeroes in little endian form.
if (pG->cbData < cbP) { DWORD cbG = pG->cbData;
// We are done using P parameter. Overwrite with the G parameter and
// pad with leading zeroes in little endian form.
memcpy(pP->pbData, pG->pbData, cbG); memset(pP->pbData + cbG, 0, cbP - cbG); pG = pP; } if (!CryptSetKeyParam( hKey, KP_G, (PBYTE) pG, 0)) // dwFlags
goto CreateKeyError; }
if (!CryptSetKeyParam( hKey, KP_X, NULL, // pbData
0)) // dwFlags
goto CreateKeyError;
SuccessReturn: fResult = TRUE; CommonReturn: if (hKey) CryptDestroyKey(hKey); MakeCertFree(pDh3PubKeyStruc); MakeCertFree(pX942DhPara); MakeCertFree(pDssPara); return fResult;
CreateKeyError: IDSwprintf(hModule,IDS_ERR_SUB_KEY_CREATE, wszSubjectKey); ErrorReturn: fResult = FALSE; goto CommonReturn; }
static BOOL UpdateDhPublicKey( IN OUT PCERT_PUBLIC_KEY_INFO *ppPubKeyInfo ) { BOOL fResult; PCERT_PUBLIC_KEY_INFO pPubKeyInfo = *ppPubKeyInfo; PCERT_X942_DH_PARAMETERS pX942DhPara = NULL; DWORD cbDhPara; PCERT_X942_DH_PARAMETERS pX942DhParaCertFile = NULL;
BYTE *pbReencodedPara = NULL; DWORD cbReencodedPara; BYTE *pbReencodedPubKeyInfo = NULL; DWORD cbReencodedPubKeyInfo; PCERT_PUBLIC_KEY_INFO pUpdatedPubKeyInfo = NULL; DWORD cbUpdatedPubKeyInfo;
if (NULL == wszDhParaCertFile && 0 == DhQ.cbData) return TRUE;
if (!DecodeAndAllocObject( X942_DH_PARAMETERS, pPubKeyInfo->Algorithm.Parameters.pbData, pPubKeyInfo->Algorithm.Parameters.cbData, (void **) &pX942DhPara, &cbDhPara )) { PrintLastError(IDS_ERR_EXPORT_PUB); goto ErrorReturn; }
if (wszDhParaCertFile) { if (!GetDhParaFromCertFile(&pX942DhParaCertFile)) goto ErrorReturn;
if (!CertCompareIntegerBlob(&pX942DhPara->p, &pX942DhParaCertFile->p)) goto DhParaCertFileError; if (!CertCompareIntegerBlob(&pX942DhPara->g, &pX942DhParaCertFile->g)) goto DhParaCertFileError;
// Use Dh parameters from the CertFile
MakeCertFree(pX942DhPara); pX942DhPara = pX942DhParaCertFile; pX942DhParaCertFile = NULL; } else if (pX942DhPara->q.cbData) { MakeCertFree(pX942DhPara); return TRUE; } else // Use Q parameter saved away when the DH key was generated
pX942DhPara->q = DhQ;
// Re-encode the DH parameters
if (!EncodeAndAllocObject( X942_DH_PARAMETERS, pX942DhPara, &pbReencodedPara, &cbReencodedPara )) { PrintLastError(IDS_ERR_EXPORT_PUB); goto ErrorReturn; }
if (0 == strcmp(szOID_RSA_DH, pPubKeyInfo->Algorithm.pszObjId)) pPubKeyInfo->Algorithm.pszObjId = szOID_ANSI_X942_DH;
// Re-encode the PublicKeyInfo using the above re-encoded DH parameters
pPubKeyInfo->Algorithm.Parameters.pbData = pbReencodedPara; pPubKeyInfo->Algorithm.Parameters.cbData = cbReencodedPara; if (!EncodeAndAllocObject( X509_PUBLIC_KEY_INFO, pPubKeyInfo, &pbReencodedPubKeyInfo, &cbReencodedPubKeyInfo )) { PrintLastError(IDS_ERR_EXPORT_PUB); goto ErrorReturn; }
// Decode to get the updated public key info
if (!DecodeAndAllocObject( X509_PUBLIC_KEY_INFO, pbReencodedPubKeyInfo, cbReencodedPubKeyInfo, (void **) &pUpdatedPubKeyInfo, &cbUpdatedPubKeyInfo )) { PrintLastError(IDS_ERR_EXPORT_PUB); goto ErrorReturn; }
fResult = TRUE; CommonReturn: MakeCertFree(pbReencodedPubKeyInfo); MakeCertFree(pbReencodedPara); MakeCertFree(pX942DhPara); MakeCertFree(pX942DhParaCertFile);
MakeCertFree(pPubKeyInfo); *ppPubKeyInfo = pUpdatedPubKeyInfo; return fResult;
DhParaCertFileError: IDSwprintf(hModule, IDS_ERR_DH_PARA_FILE, wszDhParaCertFile); ErrorReturn: MakeCertFree(pUpdatedPubKeyInfo); pUpdatedPubKeyInfo = NULL; fResult = FALSE; goto CommonReturn; }
|