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.
 
 
 
 
 
 

751 lines
22 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1995 - 1996
//
// File: makerootctl.cpp
//
// Contents: Makes a CTL used for the Auto Update of the "AuthRoot" store.
//
// See Usage() for list of options.
//
//
// Functions: main
//
// History: 08-Sep-00 philh created
//
//--------------------------------------------------------------------------
#include <windows.h>
#include "wincrypt.h"
#include "unicode.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <time.h>
#define SHA1_HASH_LEN 20
#define SHA1_HASH_NAME_LEN (2 * SHA1_HASH_LEN)
void PrintLastError(LPCSTR pszMsg)
{
DWORD dwErr = GetLastError();
printf("%s failed => 0x%x (%d) \n", pszMsg, dwErr, dwErr);
}
void Usage(void)
{
printf("Usage: makerootctl [options] [<CtlFilename>]\n");
printf("Options are:\n");
printf(" -h - This message\n");
printf(" -c - Include certs in the CTL\n");
printf(" -C <Directory> - Write certs into directory\n");
printf(" -a <AddStoreFilename> - Add\n");
printf(" -d <DeleteStoreFilename> - Delete\n");
printf(" -t <Number> - Timeout hint in SequenceNumber (secs)\n");
printf("\n");
printf("Supports multiple -a and/or -d options\n");
printf("\n");
printf("The -c and -C options are ignored for deleted roots\n");
printf("\n");
printf("For -C option, defaults to authroot.stl. Also writes authrootseq.txt\n");
printf("\n");
}
//+-------------------------------------------------------------------------
// Allocate and convert a multi-byte string to a wide string
//--------------------------------------------------------------------------
LPWSTR AllocAndSzToWsz(LPCSTR psz)
{
size_t cb;
LPWSTR pwsz = NULL;
if (-1 == (cb = mbstowcs( NULL, psz, strlen(psz))))
goto bad_param;
cb += 1; // terminating NULL
if (NULL == (pwsz = (LPWSTR) malloc( cb * sizeof(WCHAR)))) {
PrintLastError("AllocAndSzToWsz");
goto failed;
}
if (-1 == mbstowcs( pwsz, psz, cb))
goto bad_param;
goto common_return;
bad_param:
printf("Failed, bad AllocAndSzToWsz\n");
failed:
if (pwsz) {
free(pwsz);
pwsz = NULL;
}
common_return:
return pwsz;
}
BOOL OpenAndAddStoreToCollection(
IN LPCSTR pszStoreFilename,
IN OUT HCERTSTORE hCollectionStore
)
{
BOOL fResult;
HCERTSTORE hStore;
hStore = CertOpenStore(
CERT_STORE_PROV_FILENAME_A,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
0, // hCryptProv
0,
(const void *) pszStoreFilename
);
if (NULL == hStore) {
PrintLastError("Open StoreFilename");
return FALSE;
}
fResult = CertAddStoreToCollection(
hCollectionStore,
hStore,
CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG,
0 // dwPriority
);
if (!fResult)
PrintLastError("CertAddStoreToCollection");
CertCloseStore(hStore, 0);
return fResult;
}
//+-------------------------------------------------------------------------
// Converts the bytes into UNICODE ASCII HEX
//
// Needs (cb * 2 + 1) * sizeof(WCHAR) bytes of space in wsz
//--------------------------------------------------------------------------
void BytesToWStr(DWORD cb, void* pv, LPWSTR wsz)
{
BYTE* pb = (BYTE*) pv;
for (DWORD 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;
}
//+-------------------------------------------------------------------------
// Converts the bytes into ASCII HEX
//
// Needs (cb * 2 + 1) * sizeof(char) bytes of space in sz
//--------------------------------------------------------------------------
void BytesToStr(DWORD cb, void* pv, LPSTR sz)
{
BYTE* pb = (BYTE*) pv;
for (DWORD i = 0; i<cb; i++) {
int b;
b = (*pb & 0xF0) >> 4;
*sz++ = (b <= 9) ? b + '0' : (b - 10) + 'A';
b = *pb & 0x0F;
*sz++ = (b <= 9) ? b + '0' : (b - 10) + 'A';
pb++;
}
*sz++ = 0;
}
BOOL
WriteCertToDirectory(
IN LPCWSTR pwszCertDirectory,
IN PCCERT_CONTEXT pCert
)
{
BOOL fResult;
DWORD cchDir;
LPWSTR pwszFilename = NULL;
DWORD cchFilename;
DWORD cbData;
BYTE rgbSha1Hash[SHA1_HASH_LEN];
HANDLE hFile = NULL;
DWORD cbBytesWritten;
// Get cert's SHA1 hash
cbData = SHA1_HASH_LEN;
if (!CertGetCertificateContextProperty(
pCert,
CERT_SHA1_HASH_PROP_ID,
rgbSha1Hash,
&cbData
) || SHA1_HASH_LEN != cbData) {
PrintLastError("GetCertificate SHA1 Hash Property");
goto ErrorReturn;
}
// Format filename:
// L"CertDirectory" L"\\" L"AsciiHexHash" L".cer"
// For example:
// L"c:\\authroot\\216B2A29E62A00CE820146D8244141B92511B279.cer"
cchDir = wcslen(pwszCertDirectory);
cchFilename =
cchDir + 1 + SHA1_HASH_NAME_LEN + wcslen(CERT_AUTH_ROOT_CERT_EXT) + 1;
if (NULL == (pwszFilename = (LPWSTR) malloc(sizeof(WCHAR) * cchFilename)))
goto OutOfMemory;
wcscpy(pwszFilename, pwszCertDirectory);
pwszFilename[cchDir] = L'\\';
BytesToWStr(SHA1_HASH_LEN, rgbSha1Hash, pwszFilename + cchDir + 1);
wcscpy(pwszFilename + cchDir + 1 + SHA1_HASH_NAME_LEN,
CERT_AUTH_ROOT_CERT_EXT);
hFile = CreateFileU(
pwszFilename,
GENERIC_WRITE,
0, // fdwShareMode
NULL, // lpsa
CREATE_ALWAYS,
0, // fdwAttrsAndFlags
0); // TemplateFile
if (INVALID_HANDLE_VALUE == hFile) {
PrintLastError("Create File");
printf("failed for: %S\n", pwszFilename);
goto ErrorReturn;
}
if (!WriteFile(
hFile,
pCert->pbCertEncoded,
pCert->cbCertEncoded,
&cbBytesWritten,
NULL // lpOverlapped
)) {
PrintLastError("Write File");
printf("failed for: %S\n", pwszFilename);
goto ErrorReturn;
}
fResult = TRUE;
CommonReturn:
if (NULL != hFile && INVALID_HANDLE_VALUE != hFile)
CloseHandle(hFile);
if (pwszFilename)
free(pwszFilename);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
OutOfMemory:
printf("Failed:: out of memory\n");
goto ErrorReturn;
}
// Sequence Number consists of FileTime, Timeout hint byte
#define SEQ_LEN (sizeof(FILETIME) + 1)
int _cdecl main(int argc, char * argv[])
{
int ReturnStatus = 0;
LPWSTR pwszCtlFilename = NULL; // malloc'ed
LPWSTR pwszSeqFilename = NULL; // malloc'ed
HCERTSTORE hAddStore = NULL;
HCERTSTORE hDeleteStore = NULL;
BOOL fIncludeCerts = FALSE;
LPWSTR pwszCertDirectory = NULL; // malloc'ed
BYTE bTimeout = 20; // default to 20 seconds
DWORD cCert = 0;
LPSTR pszSubjectUsage = szOID_ROOT_LIST_SIGNER;
BYTE rgbDelete[] = {0x02, 0x01, 0x1}; // 0x02 - INTEGER tag
CRYPT_ATTR_BLOB DeleteValue = {sizeof(rgbDelete), rgbDelete};
CRYPT_ATTRIBUTE rgDeleteAttr[1] = {
szOID_REMOVE_CERTIFICATE, 1, &DeleteValue
};
BYTE rgbSequenceNumber[SEQ_LEN];
CTL_INFO CtlInfo;
PCTL_ENTRY pCtlEntry = NULL;
PCTL_ENTRY *ppCtlEntry = NULL;
CMSG_SIGNED_ENCODE_INFO SignInfo;
PCERT_BLOB pCertEncoded = NULL;
BYTE *pbEncoded = NULL;
DWORD cbEncoded;
PCCERT_CONTEXT pCert;
HANDLE hCtlFile = NULL;
DWORD cbBytesWritten = 0;
PCCTL_CONTEXT pCtl = NULL;
HANDLE hSeqFile = NULL;
// Create the add and delete collection stores
hAddStore = CertOpenStore(
CERT_STORE_PROV_COLLECTION,
0, // dwEncodingType
0, // hCryptProv
0, // dwFlags
NULL // pvPara
);
if (NULL == hAddStore) {
PrintLastError("CertOpenStore(Add Collection)");
goto ErrorReturn;
}
hDeleteStore = CertOpenStore(
CERT_STORE_PROV_COLLECTION,
0, // dwEncodingType
0, // hCryptProv
0, // dwFlags
NULL // pvPara
);
if (NULL == hDeleteStore) {
PrintLastError("CertOpenStore(Delete Collection)");
goto ErrorReturn;
}
while (--argc>0)
{
if (**++argv == '-')
{
switch(argv[0][1])
{
case 'c':
fIncludeCerts = TRUE;
break;
case 'C':
if (argc < 2 || argv[1][0] == '-') {
printf("-C : missing Directory argument\n");
goto BadUsage;
}
argc--;
argv++;
pwszCertDirectory = AllocAndSzToWsz(argv[0]);
break;
case 'a':
if (argc < 2 || argv[1][0] == '-') {
printf("-a : missing AddStoreFilename argument\n");
goto BadUsage;
}
argc--;
argv++;
if (!OpenAndAddStoreToCollection(argv[0], hAddStore))
goto ErrorReturn;
break;
case 'd':
if (argc < 2 || argv[1][0] == '-') {
printf("-a : missing DeleteStoreFilename argument\n");
goto BadUsage;
}
argc--;
argv++;
if (!OpenAndAddStoreToCollection(argv[0], hDeleteStore))
goto ErrorReturn;
break;
case 't':
if (argc < 2 || argv[1][0] == '-') {
printf("-t : missing timeout number argument\n");
goto BadUsage;
}
argc--;
argv++;
{
DWORD dwTimeout;
dwTimeout = (DWORD) strtoul(argv[0], NULL, 0);
if (dwTimeout > 0xFF)
dwTimeout = 0xFF;
bTimeout = (BYTE) dwTimeout;
}
break;
case 'h':
default:
goto BadUsage;
}
} else {
if (pwszCtlFilename == NULL)
pwszCtlFilename = AllocAndSzToWsz(argv[0]);
else {
printf("too many CTL filenames\n");
goto BadUsage;
}
}
}
if (NULL == pwszCtlFilename && NULL == pwszCertDirectory) {
printf("missing CTL filename\n");
goto BadUsage;
}
// Get count of the add and delete certs
pCert = NULL;
cCert = 0;
while (pCert = CertEnumCertificatesInStore(hAddStore, pCert))
cCert++;
pCert = NULL;
while (pCert = CertEnumCertificatesInStore(hDeleteStore, pCert))
cCert++;
if (cCert) {
DWORD i;
if (NULL == (pCtlEntry = (PCTL_ENTRY) malloc(
cCert * sizeof(CTL_ENTRY))))
goto OutOfMemory;
memset(pCtlEntry, 0, cCert * sizeof(CTL_ENTRY));
if (NULL == (ppCtlEntry = (PCTL_ENTRY *) malloc(
cCert * sizeof(PCTL_ENTRY))))
goto OutOfMemory;
memset(ppCtlEntry, 0, cCert * sizeof(PCTL_ENTRY));
if (fIncludeCerts) {
if (NULL == (pCertEncoded = (PCERT_BLOB) malloc(
cCert * sizeof(CERT_BLOB))))
goto OutOfMemory;
memset(pCertEncoded, 0, cCert * sizeof(CERT_BLOB));
}
// Create CTL and add CTL entry for each certificate. If enabled,
// add to list of encoded certificates
//
i = 0;
pCert = NULL;
while (pCert = CertEnumCertificatesInStore(hAddStore, pCert)) {
DWORD cbCtlEntry;
if (i >= cCert) {
printf("Unexpected error, too many add certs\n");
goto ErrorReturn;
}
cbCtlEntry = 0;
if (!CertCreateCTLEntryFromCertificateContextProperties(
pCert,
0, // cOptAttr
NULL, // pOptAttr
CTL_ENTRY_FROM_PROP_CHAIN_FLAG,
NULL, // pvReserved
NULL, // pCtlEntry
&cbCtlEntry
)) {
PrintLastError("CreateCTLEntry");
goto ErrorReturn;
}
if (NULL == (ppCtlEntry[i] = (PCTL_ENTRY) malloc(cbCtlEntry)))
goto OutOfMemory;
if (!CertCreateCTLEntryFromCertificateContextProperties(
pCert,
0, // cOptAttr
NULL, // pOptAttr
CTL_ENTRY_FROM_PROP_CHAIN_FLAG,
NULL, // pvReserved
ppCtlEntry[i],
&cbCtlEntry
)) {
PrintLastError("CreateCTLEntry");
goto ErrorReturn;
}
pCtlEntry[i] = *ppCtlEntry[i];
if (fIncludeCerts) {
pCertEncoded[i].cbData = pCert->cbCertEncoded;
pCertEncoded[i].pbData = pCert->pbCertEncoded;
}
if (pwszCertDirectory) {
if (!WriteCertToDirectory(pwszCertDirectory, pCert))
goto ErrorReturn;
}
i++;
}
pCert = NULL;
while (pCert = CertEnumCertificatesInStore(hDeleteStore, pCert)) {
DWORD cbCtlEntry;
if (i >= cCert) {
printf("Unexpected error, too many delete certs\n");
goto ErrorReturn;
}
cbCtlEntry = 0;
if (!CertCreateCTLEntryFromCertificateContextProperties(
pCert,
1, // cOptAttr
rgDeleteAttr,
0, // dwFlags
NULL, // pvReserved
NULL, // pCtlEntry
&cbCtlEntry
)) {
PrintLastError("CreateCTLEntry");
goto ErrorReturn;
}
if (NULL == (ppCtlEntry[i] = (PCTL_ENTRY) malloc(cbCtlEntry)))
goto OutOfMemory;
if (!CertCreateCTLEntryFromCertificateContextProperties(
pCert,
1, // cOptAttr
rgDeleteAttr,
0, // dwFlags
NULL, // pvReserved
ppCtlEntry[i],
&cbCtlEntry
)) {
PrintLastError("CreateCTLEntry");
goto ErrorReturn;
}
pCtlEntry[i] = *ppCtlEntry[i];
i++;
}
if (i != cCert) {
printf("Unexpected error, didn't process all the certs\n");
goto ErrorReturn;
}
}
memset(&CtlInfo, 0, sizeof(CtlInfo));
CtlInfo.dwVersion = CTL_V1;
CtlInfo.SubjectUsage.cUsageIdentifier = 1;
CtlInfo.SubjectUsage.rgpszUsageIdentifier = &pszSubjectUsage;
// CtlInfo.ListIdentifier =
GetSystemTimeAsFileTime(&CtlInfo.ThisUpdate);
// Use the 8 byte filetime, 1 byte timeout for the sequence number.
memcpy(rgbSequenceNumber, (BYTE *) &CtlInfo.ThisUpdate, sizeof(FILETIME));
rgbSequenceNumber[sizeof(FILETIME)] = bTimeout;
CtlInfo.SequenceNumber.pbData = rgbSequenceNumber;
CtlInfo.SequenceNumber.cbData = sizeof(rgbSequenceNumber);
// CtlInfo.NextUpdate =
CtlInfo.SubjectAlgorithm.pszObjId = szOID_OIWSEC_sha1;
CtlInfo.cCTLEntry = cCert;
CtlInfo.rgCTLEntry = pCtlEntry;
// CtlInfo.cExtension =
// CtlInfo.rgExtension =
memset(&SignInfo, 0, sizeof(SignInfo));
SignInfo.cbSize = sizeof(SignInfo);
// SignInfo.cSigners =
// SignInfo.rgSigners =
if (fIncludeCerts) {
SignInfo.cCertEncoded = cCert;
SignInfo.rgCertEncoded = pCertEncoded;
}
// SignInfo.cCrlEncoded =
// SignInfo.rgCrlEncoded =
cbEncoded = 0;
if (!CryptMsgEncodeAndSignCTL(
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
&CtlInfo,
&SignInfo,
0, // dwFlags
NULL, // pbEncoded
&cbEncoded
)) {
PrintLastError("EncodeAndSignCTL");
goto ErrorReturn;
}
if (NULL == (pbEncoded = (BYTE *) malloc(cbEncoded)))
goto OutOfMemory;
if (!CryptMsgEncodeAndSignCTL(
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
&CtlInfo,
&SignInfo,
0, // dwFlags
pbEncoded,
&cbEncoded
)) {
PrintLastError("EncodeAndSignCTL");
goto ErrorReturn;
}
if (NULL == pwszCtlFilename) {
DWORD cchDir;
DWORD cchFilename;
cchDir = wcslen(pwszCertDirectory);
cchFilename = cchDir + 1 + wcslen(CERT_AUTH_ROOT_CTL_FILENAME) + 1;
if (NULL == (pwszCtlFilename = (LPWSTR) malloc(
sizeof(WCHAR) * cchFilename)))
goto OutOfMemory;
wcscpy(pwszCtlFilename, pwszCertDirectory);
pwszCtlFilename[cchDir] = L'\\';
wcscpy(pwszCtlFilename + cchDir + 1, CERT_AUTH_ROOT_CTL_FILENAME);
}
hCtlFile = CreateFileU(
pwszCtlFilename,
GENERIC_WRITE,
0, // fdwShareMode
NULL, // lpsa
CREATE_ALWAYS,
0, // fdwAttrsAndFlags
0); // TemplateFile
if (INVALID_HANDLE_VALUE == hCtlFile) {
PrintLastError("Create Ctl File");
goto ErrorReturn;
}
if (!WriteFile(
hCtlFile,
pbEncoded,
cbEncoded,
&cbBytesWritten,
NULL // lpOverlapped
)) {
PrintLastError("Write Ctl File");
goto ErrorReturn;
}
if (pwszCertDirectory) {
// Create the authroot.seq file containing the CTL's SequenceNumber.
// Write to the file as big endian. The decoded value is little
// endian.
BYTE rgbSeq[SEQ_LEN];
char szSeq[SEQ_LEN * 2 + 1]; // Ascii Hex
DWORD cbSeq;
DWORD i;
DWORD cchDir;
DWORD cchFilename;
// Decode the encoded CTL to get the "real" sequence number.
pCtl = CertCreateCTLContext(
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
pbEncoded,
cbEncoded
);
if (NULL == pCtl) {
PrintLastError("CreateCTLContext");
goto ErrorReturn;
}
cbSeq = pCtl->pCtlInfo->SequenceNumber.cbData;
if (0 == cbSeq || sizeof(rgbSeq) < cbSeq) {
printf("failed, invalid SequenceNumber\n");
goto ErrorReturn;
}
// Convert the SequenceNumber to big endian ascii hex before writing to
// the file.
for (i = 0; i < cbSeq; i++)
rgbSeq[i] = pCtl->pCtlInfo->SequenceNumber.pbData[cbSeq - 1 - i];
BytesToStr(cbSeq, rgbSeq, szSeq);
cchDir = wcslen(pwszCertDirectory);
cchFilename = cchDir + 1 + wcslen(CERT_AUTH_ROOT_SEQ_FILENAME) + 1;
if (NULL == (pwszSeqFilename = (LPWSTR) malloc(
sizeof(WCHAR) * cchFilename)))
goto OutOfMemory;
wcscpy(pwszSeqFilename, pwszCertDirectory);
pwszSeqFilename[cchDir] = L'\\';
wcscpy(pwszSeqFilename + cchDir + 1, CERT_AUTH_ROOT_SEQ_FILENAME);
hSeqFile = CreateFileU(
pwszSeqFilename,
GENERIC_WRITE,
0, // fdwShareMode
NULL, // lpsa
CREATE_ALWAYS,
0, // fdwAttrsAndFlags
0); // TemplateFile
if (INVALID_HANDLE_VALUE == hSeqFile) {
PrintLastError("Create Seq File");
goto ErrorReturn;
}
if (!WriteFile(
hSeqFile,
szSeq,
cbSeq * 2,
&cbBytesWritten,
NULL // lpOverlapped
)) {
PrintLastError("Write Seq File");
goto ErrorReturn;
}
}
ReturnStatus = 0;
printf("Succeeded\n");
CommonReturn:
if (pwszCtlFilename)
free(pwszCtlFilename);
if (pwszSeqFilename)
free(pwszSeqFilename);
if (pwszCertDirectory)
free(pwszCertDirectory);
if (pCtl)
CertFreeCTLContext(pCtl);
if (hAddStore)
CertCloseStore(hAddStore, 0);
if (hDeleteStore)
CertCloseStore(hDeleteStore, 0);
if (pCtlEntry)
free(pCtlEntry);
if (ppCtlEntry) {
DWORD i;
for (i = 0; i < cCert; i++)
free(ppCtlEntry[i]);
free(ppCtlEntry);
}
if (pCertEncoded)
free(pCertEncoded);
if (pbEncoded)
free(pbEncoded);
if (NULL != hCtlFile && INVALID_HANDLE_VALUE != hCtlFile)
CloseHandle(hCtlFile);
if (NULL != hSeqFile && INVALID_HANDLE_VALUE != hSeqFile)
CloseHandle(hSeqFile);
return ReturnStatus;
BadUsage:
Usage();
ErrorReturn:
ReturnStatus = -1;
goto CommonReturn;
OutOfMemory:
printf("Failed:: out of memory\n");
goto ErrorReturn;
}