Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4714 lines
136 KiB

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