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.
2706 lines
82 KiB
2706 lines
82 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1995 - 1996
|
|
//
|
|
// File: tcert.cpp
|
|
//
|
|
// Contents: Certificate and CRL Encode/Decode API Tests
|
|
//
|
|
// See Usage() for list of test options.
|
|
//
|
|
//
|
|
// Functions: main
|
|
//
|
|
// History: 04-Mar-96 philh created
|
|
// 07-Jun-96 HelleS Added printing the command line
|
|
// and Failed or Passed at the end.
|
|
// 20-Aug-96 jeffspel name changes
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include <windows.h>
|
|
#include <regstr.h>
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <memory.h>
|
|
#include <time.h>
|
|
#include <stddef.h>
|
|
|
|
#include <wincrypt.h>
|
|
#include <signcde.h>
|
|
//#include <crypt32l.h>
|
|
|
|
|
|
// Note: the SubjectPublicKey is really the PKCS #1 ASN encoding of the
|
|
// following information. However, since the SubjectPublicKeyInfo.PublicKey
|
|
// is a CRYPT_BIT_BLOB that following is OK for testing purposes.
|
|
#ifndef RSA1
|
|
#define RSA1 ((DWORD)'R'+((DWORD)'S'<<8)+((DWORD)'A'<<16)+((DWORD)'1'<<24))
|
|
#endif
|
|
// Build my own CAPI public key
|
|
typedef struct _CAPI_PUB_KEY {
|
|
PUBLICKEYSTRUC PubKeyStruc;
|
|
RSAPUBKEY RsaPubKey;
|
|
BYTE rgbModulus[10];
|
|
} CAPI_PUB_KEY;
|
|
|
|
static const CAPI_PUB_KEY SubjectPublicKey = {
|
|
{PUBLICKEYBLOB, CUR_BLOB_VERSION, 0, CALG_RSA_SIGN}, // PUBLICKEYSTRUC
|
|
{RSA1, 10*8, 4}, // RSAPUBKEY
|
|
{0,1,2,3,4,5,6,7,8,9} // rgbModulus
|
|
};
|
|
|
|
static LPSTR pszReadFilename = NULL;
|
|
static LPSTR pszPublicKeyFilename = NULL;
|
|
static BOOL fWritePublicKeyInfo = FALSE;
|
|
|
|
static LPSTR pszForwardCertFilename = NULL;
|
|
static LPSTR pszReverseCertFilename = NULL;
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Parameters, data used to encode the messages.
|
|
//--------------------------------------------------------------------------
|
|
static DWORD dwCertEncodingType = X509_ASN_ENCODING;
|
|
|
|
static DWORD dwDecodeObjectFlags = 0;
|
|
static BOOL fFormatNameStrings = FALSE;
|
|
static BOOL fFormatAllNameStrings = FALSE;
|
|
static DWORD dwExtLen = 0;
|
|
|
|
static LPCSTR pszOIDNoSignHash = szOID_OIWSEC_sha1;
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Error output routines
|
|
//--------------------------------------------------------------------------
|
|
static void PrintError(LPCSTR pszMsg)
|
|
{
|
|
printf("%s\n", pszMsg);
|
|
}
|
|
static void PrintLastError(LPCSTR pszMsg)
|
|
{
|
|
DWORD dwErr = GetLastError();
|
|
printf("%s failed => 0x%x (%d) \n", pszMsg, dwErr, dwErr);
|
|
}
|
|
|
|
void PrintNoError(LPCSTR pszMsg)
|
|
{
|
|
printf("%s failed => expected error\n", pszMsg);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Test allocation and free routines
|
|
//--------------------------------------------------------------------------
|
|
static void *TestAlloc(
|
|
IN size_t cbBytes
|
|
)
|
|
{
|
|
void *pv;
|
|
pv = malloc(cbBytes);
|
|
if (pv == NULL) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
PrintLastError("TestAlloc");
|
|
}
|
|
return pv;
|
|
}
|
|
static void TestFree(
|
|
IN void *pv
|
|
)
|
|
{
|
|
if (pv)
|
|
free(pv);
|
|
}
|
|
|
|
static CRYPT_DECODE_PARA TestDecodePara = {
|
|
offsetof(CRYPT_DECODE_PARA, pfnFree) + sizeof(TestDecodePara.pfnFree),
|
|
TestAlloc,
|
|
TestFree
|
|
};
|
|
|
|
static void *TestDecodeObject(
|
|
IN LPCSTR lpszStructType,
|
|
IN const BYTE *pbEncoded,
|
|
IN DWORD cbEncoded,
|
|
OUT OPTIONAL DWORD *pcbStructInfo = NULL
|
|
)
|
|
{
|
|
DWORD cbStructInfo;
|
|
void *pvStructInfo;
|
|
|
|
if (!CryptDecodeObjectEx(
|
|
dwCertEncodingType,
|
|
lpszStructType,
|
|
pbEncoded,
|
|
cbEncoded,
|
|
dwDecodeObjectFlags | CRYPT_DECODE_ALLOC_FLAG,
|
|
&TestDecodePara,
|
|
(void *) &pvStructInfo,
|
|
&cbStructInfo
|
|
))
|
|
goto ErrorReturn;
|
|
|
|
CommonReturn:
|
|
if (pcbStructInfo)
|
|
*pcbStructInfo = cbStructInfo;
|
|
return pvStructInfo;
|
|
|
|
ErrorReturn:
|
|
if ((DWORD_PTR) lpszStructType <= 0xFFFF)
|
|
printf("CryptDecodeObject(StructType: %d)",
|
|
(DWORD)(DWORD_PTR) lpszStructType);
|
|
else
|
|
printf("CryptDecodeObject(StructType: %s)",
|
|
lpszStructType);
|
|
PrintLastError("");
|
|
|
|
pvStructInfo = NULL;
|
|
goto CommonReturn;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Allocate and read an encoded DER blob from a file
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
ReadDERFromFile(
|
|
LPCSTR pszFileName,
|
|
PBYTE *ppbDER,
|
|
PDWORD pcbDER
|
|
)
|
|
{
|
|
BOOL fRet;
|
|
HANDLE hFile = 0;
|
|
PBYTE pbDER = NULL;
|
|
DWORD cbDER;
|
|
DWORD cbRead;
|
|
|
|
if( INVALID_HANDLE_VALUE == (hFile = CreateFile( pszFileName, GENERIC_READ,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL, OPEN_EXISTING, 0, NULL))) {
|
|
printf( "can't open %s\n", pszFileName);
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
cbDER = GetFileSize( hFile, NULL);
|
|
if (cbDER == 0) {
|
|
printf( "empty file %s\n", pszFileName);
|
|
goto ErrorReturn;
|
|
}
|
|
if (NULL == (pbDER = (PBYTE)TestAlloc(cbDER))) {
|
|
printf( "can't alloc %d bytes\n", cbDER);
|
|
goto ErrorReturn;
|
|
}
|
|
if (!ReadFile( hFile, pbDER, cbDER, &cbRead, NULL) ||
|
|
(cbRead != cbDER)) {
|
|
printf( "can't read %s\n", pszFileName);
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
*ppbDER = pbDER;
|
|
*pcbDER = cbDER;
|
|
fRet = TRUE;
|
|
CommonReturn:
|
|
if (hFile)
|
|
CloseHandle(hFile);
|
|
return fRet;
|
|
ErrorReturn:
|
|
if (pbDER)
|
|
TestFree(pbDER);
|
|
*ppbDER = NULL;
|
|
*pcbDER = 0;
|
|
fRet = FALSE;
|
|
goto CommonReturn;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Write an encoded DER blob to a file
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
WriteDERToFile(
|
|
LPCSTR pszFileName,
|
|
PBYTE pbDER,
|
|
DWORD cbDER
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
|
|
// Write the Encoded Blob to the file
|
|
HANDLE hFile;
|
|
hFile = CreateFile(pszFileName,
|
|
GENERIC_WRITE,
|
|
0, // fdwShareMode
|
|
NULL, // lpsa
|
|
CREATE_ALWAYS,
|
|
0, // fdwAttrsAndFlags
|
|
0); // TemplateFile
|
|
if (INVALID_HANDLE_VALUE == hFile) {
|
|
fResult = FALSE;
|
|
PrintLastError("WriteDERToFile::CreateFile");
|
|
} else {
|
|
DWORD dwBytesWritten;
|
|
if (!(fResult = WriteFile(
|
|
hFile,
|
|
pbDER,
|
|
cbDER,
|
|
&dwBytesWritten,
|
|
NULL // lpOverlapped
|
|
)))
|
|
PrintLastError("WriteDERToFile::WriteFile");
|
|
CloseHandle(hFile);
|
|
}
|
|
return fResult;
|
|
}
|
|
|
|
|
|
typedef BOOL (*PFN_ENCODE)(BYTE **ppbEncoded, DWORD *pcbEncoded);
|
|
typedef BOOL (*PFN_DECODE)(BYTE *pbEncoded, DWORD cbEncoded);
|
|
typedef struct _TEST {
|
|
LPCSTR pszName;
|
|
PFN_ENCODE pfnEncode;
|
|
PFN_DECODE pfnDecode;
|
|
} TEST, *PTEST;
|
|
|
|
static BOOL EncodeCert(BYTE **ppbEncoded, DWORD *pcbEncoded);
|
|
static BOOL DecodeCert(BYTE *pbEncoded, DWORD cbEncoded);
|
|
static BOOL EncodeCrl(BYTE **ppbEncoded, DWORD *pcbEncoded);
|
|
static BOOL DecodeCrl(BYTE *pbEncoded, DWORD cbEncoded);
|
|
static BOOL EncodeCertReq(BYTE **ppbEncoded, DWORD *pcbEncoded);
|
|
static BOOL DecodeCertReq(BYTE *pbEncoded, DWORD cbEncoded);
|
|
static BOOL EncodeKeygenReq(BYTE **ppbEncoded, DWORD *pcbEncoded);
|
|
static BOOL DecodeKeygenReq(BYTE *pbEncoded, DWORD cbEncoded);
|
|
static BOOL EncodeContentInfo(BYTE **ppbEncoded, DWORD *pcbEncoded);
|
|
static BOOL DecodeContentInfo(BYTE *pbEncoded, DWORD cbEncoded);
|
|
static BOOL EncodeCertPair(BYTE **ppbEncoded, DWORD *pcbEncoded);
|
|
static BOOL DecodeCertPair(BYTE *pbEncoded, DWORD cbEncoded);
|
|
|
|
TEST Tests[] = {
|
|
"cert", EncodeCert, DecodeCert,
|
|
"crl", EncodeCrl, DecodeCrl,
|
|
"certReq", EncodeCertReq, DecodeCertReq,
|
|
"keygenReq", EncodeKeygenReq, DecodeKeygenReq,
|
|
"ContentInfo", EncodeContentInfo, DecodeContentInfo,
|
|
"CertPair", EncodeCertPair, DecodeCertPair
|
|
};
|
|
#define NTESTS (sizeof(Tests)/sizeof(Tests[0]))
|
|
|
|
static void Usage(void)
|
|
{
|
|
int i;
|
|
|
|
printf("Usage: tcert [options] [<ContentType>]\n");
|
|
printf("Options are:\n");
|
|
printf(" -h - This message\n");
|
|
printf(" -r<filename> - Read encoded content from file\n");
|
|
printf(" -w<filename> - Write encoded content to file\n");
|
|
printf(" -p<filename> - Write public key to file\n");
|
|
printf(" -P<filename> - Write Name, PublicKeyInfo to file\n");
|
|
printf(" -f - Enable name string formatting\n");
|
|
printf(" -fAll - Name string formatting (All types)\n");
|
|
printf(" -N - Enable NOCOPY decode\n");
|
|
printf(" -o<OID> - NoSignHash OID (SHA1 is default)\n");
|
|
printf(" -X<number> - eXtension byte length\n");
|
|
printf(" -F<CertFilename> - CertPair Forward certificate\n");
|
|
printf(" -R<CertFilename> - CertPair Reverse certificate\n");
|
|
printf("\n");
|
|
printf("ContentTypes (case insensitive):\n");
|
|
for (i = 0; i < NTESTS; i++)
|
|
printf(" %s\n", Tests[i].pszName);
|
|
printf("\n");
|
|
printf("Default: %s\n", Tests[0].pszName);
|
|
}
|
|
|
|
int _cdecl main(int argc, char * argv[])
|
|
{
|
|
int ReturnStatus;
|
|
BOOL fResult;
|
|
|
|
LPCSTR pszName = Tests[0].pszName;
|
|
LPSTR pszWriteFilename = NULL;
|
|
int c;
|
|
PTEST pTest;
|
|
|
|
BYTE *pbEncoded = NULL;
|
|
DWORD cbEncoded;
|
|
|
|
/*
|
|
if (!Crypt32DllMain( NULL, DLL_PROCESS_ATTACH, NULL)) {
|
|
printf("Crypt32DllMain attach failed, aborting\n");
|
|
ReturnStatus = -1;
|
|
goto CommonReturn;
|
|
}
|
|
*/
|
|
|
|
while (--argc>0)
|
|
{
|
|
if (**++argv == '-')
|
|
{
|
|
switch(argv[0][1])
|
|
{
|
|
case 'r':
|
|
pszReadFilename = argv[0]+2;
|
|
if (*pszReadFilename == '\0') {
|
|
printf("Need to specify filename\n");
|
|
goto BadUsage;
|
|
}
|
|
break;
|
|
case 'w':
|
|
pszWriteFilename = argv[0]+2;
|
|
if (*pszWriteFilename == '\0') {
|
|
printf("Need to specify filename\n");
|
|
goto BadUsage;
|
|
}
|
|
break;
|
|
case 'P':
|
|
fWritePublicKeyInfo = TRUE;
|
|
case 'p':
|
|
pszPublicKeyFilename = argv[0]+2;
|
|
if (*pszPublicKeyFilename == '\0') {
|
|
printf("Need to specify filename\n");
|
|
goto BadUsage;
|
|
}
|
|
break;
|
|
case 'F':
|
|
pszForwardCertFilename = argv[0]+2;
|
|
if (*pszForwardCertFilename == '\0') {
|
|
printf("Need to specify Forward filename\n");
|
|
goto BadUsage;
|
|
}
|
|
break;
|
|
case 'R':
|
|
pszReverseCertFilename = argv[0]+2;
|
|
if (*pszReverseCertFilename == '\0') {
|
|
printf("Need to specify Reverse filename\n");
|
|
goto BadUsage;
|
|
}
|
|
break;
|
|
case 'N':
|
|
dwDecodeObjectFlags |= CRYPT_DECODE_NOCOPY_FLAG;
|
|
break;
|
|
case 'X':
|
|
dwExtLen = (DWORD) strtoul(argv[0]+2, NULL, 0);
|
|
break;
|
|
case 'f':
|
|
if (argv[0][2]) {
|
|
if (0 != _stricmp(argv[0]+2, "ALL")) {
|
|
printf("Need to specify -fALL\n");
|
|
goto BadUsage;
|
|
}
|
|
fFormatAllNameStrings = TRUE;
|
|
} else
|
|
fFormatNameStrings = TRUE;
|
|
break;
|
|
case 'o':
|
|
pszOIDNoSignHash = (LPCSTR) argv[0]+2;
|
|
break;
|
|
case 'h':
|
|
default:
|
|
goto BadUsage;
|
|
}
|
|
} else
|
|
pszName = argv[0];
|
|
}
|
|
|
|
for (c = NTESTS, pTest = Tests; c > 0; c--, pTest++) {
|
|
if (_stricmp(pszName, pTest->pszName) == 0)
|
|
break;
|
|
}
|
|
if (c == 0) {
|
|
printf("Bad ContentType: %s\n", pszName);
|
|
goto BadUsage;
|
|
}
|
|
|
|
printf("command line: %s\n", GetCommandLine());
|
|
|
|
if (pszReadFilename) printf("Reading from: %s ", pszReadFilename);
|
|
if (pszWriteFilename) printf("Writing to: %s ", pszWriteFilename);
|
|
if (pszPublicKeyFilename) {
|
|
if (fWritePublicKeyInfo)
|
|
printf("PublicKeyInfo to: %s ", pszPublicKeyFilename);
|
|
else
|
|
printf("Public Key to: %s ", pszPublicKeyFilename);
|
|
}
|
|
if (pszForwardCertFilename)
|
|
printf("ForwardCert: %s ", pszForwardCertFilename);
|
|
if (pszReverseCertFilename)
|
|
printf("ReverseCert: %s ", pszReverseCertFilename);
|
|
printf("\n");
|
|
|
|
if (pszReadFilename)
|
|
fResult = ReadDERFromFile(pszReadFilename, &pbEncoded, &cbEncoded);
|
|
else
|
|
fResult = pTest->pfnEncode(&pbEncoded, &cbEncoded);
|
|
|
|
if (fResult) {
|
|
if (pszWriteFilename)
|
|
WriteDERToFile(pszWriteFilename, pbEncoded, cbEncoded);
|
|
pTest->pfnDecode(pbEncoded, cbEncoded);
|
|
TestFree(pbEncoded);
|
|
}
|
|
|
|
ReturnStatus = 0;
|
|
goto CommonReturn;
|
|
|
|
BadUsage:
|
|
Usage();
|
|
ReturnStatus = -1;
|
|
CommonReturn:
|
|
if (!ReturnStatus)
|
|
printf("Passed\n");
|
|
else
|
|
printf("Failed\n");
|
|
|
|
/*
|
|
if (!Crypt32DllMain( NULL, DLL_PROCESS_DETACH, NULL)) {
|
|
printf("Crypt32DllMain detach failed, aborting\n");
|
|
ReturnStatus = -1;
|
|
}
|
|
*/
|
|
|
|
return ReturnStatus;
|
|
|
|
}
|
|
|
|
static BOOL EncodeSignedContent(
|
|
BYTE *pbToBeSigned,
|
|
DWORD cbToBeSigned,
|
|
BYTE **ppbEncoded,
|
|
DWORD *pcbEncoded)
|
|
{
|
|
BOOL fResult;
|
|
BYTE *pbEncoded = NULL;
|
|
DWORD cbEncoded;
|
|
BYTE *pbSignature = NULL;
|
|
DWORD cbSignature;
|
|
CERT_SIGNED_CONTENT_INFO CertEncoding;
|
|
|
|
CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm = {
|
|
(LPSTR) pszOIDNoSignHash, 0, 0
|
|
};
|
|
|
|
CRYPT_DATA_BLOB EncodedBlob;
|
|
|
|
cbSignature = 0;
|
|
if (!CryptSignCertificate(
|
|
NULL, // hCryptProv
|
|
0, // dwKeySpec
|
|
dwCertEncodingType,
|
|
pbToBeSigned,
|
|
cbToBeSigned,
|
|
&SignatureAlgorithm,
|
|
NULL, // pvHashAuxInfo
|
|
NULL, // pbSignature
|
|
&cbSignature
|
|
)) {
|
|
PrintLastError("EncodeSignedContent::CryptSignCertificate(cbEncoded == 0)");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
pbSignature = (BYTE *) TestAlloc(cbSignature);
|
|
if (pbSignature == NULL) goto ErrorReturn;
|
|
if (!CryptSignCertificate(
|
|
NULL, // hCryptProv
|
|
0, // dwKeySpec
|
|
dwCertEncodingType,
|
|
pbToBeSigned,
|
|
cbToBeSigned,
|
|
&SignatureAlgorithm,
|
|
NULL, // pvHashAuxInfo
|
|
pbSignature,
|
|
&cbSignature
|
|
)) {
|
|
PrintLastError("EncodeSignedContent::CryptSignCertificate");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
ZeroMemory(&CertEncoding, sizeof(CertEncoding));
|
|
CertEncoding.ToBeSigned.pbData = pbToBeSigned;
|
|
CertEncoding.ToBeSigned.cbData = cbToBeSigned;
|
|
CertEncoding.SignatureAlgorithm = SignatureAlgorithm;
|
|
CertEncoding.Signature.pbData = pbSignature;
|
|
CertEncoding.Signature.cbData = cbSignature;
|
|
cbEncoded = 0;
|
|
CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
X509_CERT,
|
|
&CertEncoding,
|
|
NULL, // pbEncoded
|
|
&cbEncoded
|
|
);
|
|
if (cbEncoded == 0) {
|
|
PrintLastError("EncodeSignedContent::CryptEncodeObject(cbEncoded == 0)");
|
|
goto ErrorReturn;
|
|
}
|
|
pbEncoded = (BYTE *) TestAlloc(cbEncoded);
|
|
if (pbEncoded == NULL) goto ErrorReturn;
|
|
if (!CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
X509_CERT,
|
|
&CertEncoding,
|
|
pbEncoded,
|
|
&cbEncoded
|
|
)) {
|
|
PrintLastError("EncodeSignedContent::CryptEncodeObject");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
EncodedBlob.cbData = cbEncoded;
|
|
EncodedBlob.pbData = pbEncoded;
|
|
|
|
if (!CryptVerifyCertificateSignatureEx(
|
|
NULL, // hCryptProv
|
|
dwCertEncodingType,
|
|
CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB,
|
|
(void *) &EncodedBlob,
|
|
CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL,
|
|
NULL, // pvIssuer
|
|
0, // dwFlags
|
|
NULL // pvReserved
|
|
)) {
|
|
PrintLastError("EncodeSignedContent::CryptVerifyCertificateSignatureEx");
|
|
}
|
|
|
|
|
|
fResult = TRUE;
|
|
goto CommonReturn;
|
|
|
|
ErrorReturn:
|
|
if (pbEncoded) {
|
|
TestFree(pbEncoded);
|
|
pbEncoded = NULL;
|
|
}
|
|
cbEncoded = 0;
|
|
fResult = FALSE;
|
|
CommonReturn:
|
|
if (pbSignature)
|
|
TestFree(pbSignature);
|
|
*ppbEncoded = pbEncoded;
|
|
*pcbEncoded = cbEncoded;
|
|
return fResult;
|
|
}
|
|
|
|
static void PrintBadUnicodeEncode(LPCSTR pszMsg, DWORD dwExpectedErr,
|
|
DWORD cbEncoded)
|
|
{
|
|
DWORD dwErr = GetLastError();
|
|
|
|
if (dwErr != dwExpectedErr)
|
|
printf("%s failed => expected : 0x%x (%d), LastError: 0x%x (%d)\n",
|
|
pszMsg, dwExpectedErr, dwExpectedErr, dwErr, dwErr);
|
|
printf("%s bad unicode encode => LastError: 0x%x (%d) ",
|
|
pszMsg, dwErr, dwErr);
|
|
printf("cbEncoded: 0x%x RDN: %d Attr: %d Value: %d\n",
|
|
cbEncoded,
|
|
GET_CERT_UNICODE_RDN_ERR_INDEX(cbEncoded),
|
|
GET_CERT_UNICODE_ATTR_ERR_INDEX(cbEncoded),
|
|
GET_CERT_UNICODE_VALUE_ERR_INDEX(cbEncoded));
|
|
}
|
|
|
|
static void DoBadEncodeIssuer()
|
|
{
|
|
DWORD cbIssuerEncoded;
|
|
|
|
CERT_RDN_ATTR rgBadPrintableAttr[] = {
|
|
// 0 - rgdwPrintableOrT61ValueType,
|
|
szOID_COMMON_NAME, 0, 0,
|
|
(BYTE *) L"CN: printable or t61",
|
|
|
|
// 1 - rgdwPrintableOrT61ValueType,
|
|
szOID_LOCALITY_NAME, 0, 0,
|
|
(BYTE *) L"L: printable or t61 \"###\"",
|
|
|
|
// 2 - BAD rgdwPrintableValueType,
|
|
szOID_COUNTRY_NAME, 0, 0,
|
|
(BYTE *) L"C: printable ### az AZ 09 \'()+,-./:=? "
|
|
};
|
|
CERT_RDN rgBadPrintableRDN[] = {
|
|
1, &rgBadPrintableAttr[0],
|
|
3, &rgBadPrintableAttr[0]
|
|
};
|
|
CERT_NAME_INFO BadPrintableName = {2, rgBadPrintableRDN};
|
|
|
|
CERT_RDN_ATTR rgBadNumericAttr[] = {
|
|
// 0 - rgdwPrintableOrT61ValueType,
|
|
szOID_COMMON_NAME, 0, 0,
|
|
(BYTE *) L"CN: printable or t61",
|
|
|
|
// 1 - rgdwPrintableValueType,
|
|
szOID_COUNTRY_NAME, 0, 0,
|
|
(BYTE *) L"C: printable az AZ 09 \'()+,-./:=? ",
|
|
|
|
// 2 - rgdwPrintableOrT61ValueType,
|
|
szOID_LOCALITY_NAME, 0, 0,
|
|
(BYTE *) L"L: printable or t61 \"###\"",
|
|
|
|
// 3 - BAD rgdwNumericValueType,
|
|
szOID_X21_ADDRESS, 0, 0,
|
|
(BYTE *) L"0123456789a ",
|
|
|
|
// 4 - none, use default
|
|
szOID_REGISTERED_ADDRESS, 0, 0,
|
|
(BYTE *) L"Default"
|
|
};
|
|
CERT_RDN rgBadNumericRDN[] = {
|
|
1, &rgBadNumericAttr[0],
|
|
1, &rgBadNumericAttr[1],
|
|
1, &rgBadNumericAttr[2],
|
|
1, &rgBadNumericAttr[3],
|
|
1, &rgBadNumericAttr[4]
|
|
};
|
|
CERT_NAME_INFO BadNumericName = {5, rgBadNumericRDN};
|
|
|
|
// This one has non-zero dwValueTypes
|
|
CERT_RDN_ATTR rgBadNumericAttr2[] = {
|
|
// 0 - rgdwPrintableOrT61ValueType,
|
|
szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING, 0,
|
|
(BYTE *) L"CN: printable or t61",
|
|
|
|
// 1 - rgdwPrintableValueType,
|
|
szOID_COUNTRY_NAME, CERT_RDN_PRINTABLE_STRING, 0,
|
|
(BYTE *) L"C: printable az AZ 09 \'()+,-./:=? ",
|
|
|
|
// 2 - rgdwPrintableOrT61ValueType,
|
|
szOID_LOCALITY_NAME, CERT_RDN_T61_STRING, 0,
|
|
(BYTE *) L"L: printable or t61 \"###\"",
|
|
|
|
// 3 - BAD rgdwNumericValueType,
|
|
szOID_X21_ADDRESS, CERT_RDN_NUMERIC_STRING, 0,
|
|
(BYTE *) L"0123456789a ",
|
|
|
|
// 4 - none, use default
|
|
szOID_REGISTERED_ADDRESS, CERT_RDN_IA5_STRING, 0,
|
|
(BYTE *) L"Default"
|
|
};
|
|
CERT_RDN rgBadNumericRDN2[] = {
|
|
1, &rgBadNumericAttr2[0],
|
|
1, &rgBadNumericAttr2[1],
|
|
1, &rgBadNumericAttr2[2],
|
|
4, &rgBadNumericAttr2[1],
|
|
1, &rgBadNumericAttr2[4]
|
|
};
|
|
CERT_NAME_INFO BadNumericName2 = {5, rgBadNumericRDN2};
|
|
|
|
BYTE rgbBadIA5[] = {0x80, 0x00, 0x00, 0x00};
|
|
CERT_RDN_ATTR rgBadIA5Attr[] = {
|
|
// 0 - BAD rgdwIA5ValueType
|
|
szOID_RSA_emailAddr, 0, 0,
|
|
rgbBadIA5,
|
|
};
|
|
CERT_RDN rgBadIA5RDN[] = {
|
|
1, &rgBadIA5Attr[0]
|
|
};
|
|
CERT_NAME_INFO BadIA5Name = {1, rgBadIA5RDN};
|
|
|
|
cbIssuerEncoded = 0;
|
|
if (CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
X509_UNICODE_NAME,
|
|
&BadPrintableName,
|
|
NULL, // pbEncoded
|
|
&cbIssuerEncoded
|
|
))
|
|
PrintNoError("X509_UNICODE_NAME:: BadPrintableName");
|
|
else
|
|
PrintBadUnicodeEncode("PrintableString",
|
|
(DWORD) CRYPT_E_INVALID_PRINTABLE_STRING, cbIssuerEncoded);
|
|
|
|
cbIssuerEncoded = 0;
|
|
rgBadPrintableAttr[2].dwValueType = CERT_RDN_PRINTABLE_STRING;
|
|
if (CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
X509_UNICODE_NAME,
|
|
&BadPrintableName,
|
|
NULL, // pbEncoded
|
|
&cbIssuerEncoded
|
|
))
|
|
PrintNoError("X509_UNICODE_NAME:: BadPrintableName(set dwValueType)");
|
|
else
|
|
PrintBadUnicodeEncode("PrintableString(set dwValueType)",
|
|
(DWORD) CRYPT_E_INVALID_PRINTABLE_STRING, cbIssuerEncoded);
|
|
|
|
cbIssuerEncoded = 0;
|
|
if (!CryptEncodeObjectEx(
|
|
dwCertEncodingType,
|
|
X509_UNICODE_NAME,
|
|
&BadPrintableName,
|
|
CRYPT_UNICODE_NAME_ENCODE_DISABLE_CHECK_TYPE_FLAG,
|
|
NULL, // pEncodePara
|
|
NULL, // pbEncoded
|
|
&cbIssuerEncoded
|
|
) || 0 == cbIssuerEncoded)
|
|
PrintLastError("X509_UNICODE_NAME:: DISABLE_CHECK dwFlags");
|
|
|
|
rgBadPrintableAttr[2].dwValueType =
|
|
CERT_RDN_DISABLE_CHECK_TYPE_FLAG | CERT_RDN_PRINTABLE_STRING;
|
|
cbIssuerEncoded = 0;
|
|
if (!CryptEncodeObjectEx(
|
|
dwCertEncodingType,
|
|
X509_UNICODE_NAME,
|
|
&BadPrintableName,
|
|
0,
|
|
NULL, // pEncodePara
|
|
NULL, // pbEncoded
|
|
&cbIssuerEncoded
|
|
) || 0 == cbIssuerEncoded)
|
|
PrintLastError("X509_UNICODE_NAME:: DISABLE_CHECK dwValueType");
|
|
|
|
cbIssuerEncoded = 0;
|
|
if (!CryptEncodeObjectEx(
|
|
dwCertEncodingType,
|
|
X509_UNICODE_NAME,
|
|
&BadPrintableName,
|
|
CRYPT_UNICODE_NAME_ENCODE_ENABLE_T61_UNICODE_FLAG,
|
|
NULL, // pEncodePara
|
|
NULL, // pbEncoded
|
|
&cbIssuerEncoded
|
|
) || 0 == cbIssuerEncoded)
|
|
PrintLastError("X509_UNICODE_NAME:: ENABLE_T61 dwFlags");
|
|
|
|
rgBadPrintableAttr[1].dwValueType =
|
|
CERT_RDN_ENABLE_T61_UNICODE_FLAG;
|
|
cbIssuerEncoded = 0;
|
|
if (!CryptEncodeObjectEx(
|
|
dwCertEncodingType,
|
|
X509_UNICODE_NAME,
|
|
&BadPrintableName,
|
|
0,
|
|
NULL, // pEncodePara
|
|
NULL, // pbEncoded
|
|
&cbIssuerEncoded
|
|
) || 0 == cbIssuerEncoded)
|
|
PrintLastError("X509_UNICODE_NAME:: ENABLE_T61 dwValueType");
|
|
|
|
cbIssuerEncoded = 0;
|
|
if (!CryptEncodeObjectEx(
|
|
dwCertEncodingType,
|
|
X509_UNICODE_NAME,
|
|
&BadPrintableName,
|
|
CRYPT_UNICODE_NAME_ENCODE_ENABLE_UTF8_UNICODE_FLAG,
|
|
NULL, // pEncodePara
|
|
NULL, // pbEncoded
|
|
&cbIssuerEncoded
|
|
) || 0 == cbIssuerEncoded)
|
|
PrintLastError("X509_UNICODE_NAME:: ENABLE_UTF8 dwFlags");
|
|
|
|
cbIssuerEncoded = 0;
|
|
if (CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
X509_UNICODE_NAME,
|
|
&BadNumericName,
|
|
NULL, // pbEncoded
|
|
&cbIssuerEncoded
|
|
))
|
|
PrintNoError("X509_UNICODE_NAME:: BadNumericName");
|
|
else
|
|
PrintBadUnicodeEncode("NumericString",
|
|
(DWORD) CRYPT_E_INVALID_NUMERIC_STRING, cbIssuerEncoded);
|
|
|
|
cbIssuerEncoded = 0;
|
|
if (CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
X509_UNICODE_NAME,
|
|
&BadNumericName2,
|
|
NULL, // pbEncoded
|
|
&cbIssuerEncoded
|
|
))
|
|
PrintNoError("X509_UNICODE_NAME:: BadNumericName2");
|
|
else
|
|
PrintBadUnicodeEncode("NumericString2",
|
|
(DWORD) CRYPT_E_INVALID_NUMERIC_STRING, cbIssuerEncoded);
|
|
|
|
cbIssuerEncoded = 0;
|
|
if (CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
X509_UNICODE_NAME,
|
|
&BadIA5Name,
|
|
NULL, // pbEncoded
|
|
&cbIssuerEncoded
|
|
))
|
|
PrintNoError("X509_UNICODE_NAME:: BadIA5Name");
|
|
else
|
|
PrintBadUnicodeEncode("IA5String",
|
|
(DWORD) CRYPT_E_INVALID_IA5_STRING, cbIssuerEncoded);
|
|
}
|
|
|
|
static BYTE *EncodeIssuer(DWORD *pcbIssuerEncoded)
|
|
{
|
|
BYTE *pbIssuerEncoded = NULL;
|
|
DWORD cbIssuerEncoded;
|
|
|
|
BYTE rgbOctet[] = {1, 0xFF, 0x7F};
|
|
BYTE rgbEncodedBlob[] = {0x05, 00};
|
|
|
|
CERT_RDN_ATTR rgAttr[] = {
|
|
// 0 - rgdwPrintableOrT61ValueType
|
|
szOID_COMMON_NAME, 0, 0,
|
|
(BYTE *) L"CN: printable or t61",
|
|
|
|
// 1 - rgdwPrintableValueType
|
|
szOID_COUNTRY_NAME, 0, 0,
|
|
(BYTE *) L"C: printable az AZ 09 \'()+,-./:=? ",
|
|
|
|
// 2 - rgdwPrintableOrT61ValueType
|
|
szOID_LOCALITY_NAME, 0, 0,
|
|
(BYTE *) L"L: printable or t61 \"###\"",
|
|
|
|
// 3 - rgdwNumericValueType
|
|
szOID_X21_ADDRESS, 0, 0,
|
|
(BYTE *) L" 0123456789 ",
|
|
|
|
// 4 - none, use default
|
|
szOID_REGISTERED_ADDRESS, 0, 0,
|
|
(BYTE *) L"Default",
|
|
|
|
// 5 - rgdwIA5ValueType
|
|
szOID_RSA_emailAddr, 0, 0,
|
|
(BYTE *) L"Email, IA5 !@#$%^&*()_+{|}",
|
|
|
|
// 6 - Unicode
|
|
"1.2.2.5", CERT_RDN_BMP_STRING, 0,
|
|
(BYTE *) L"Null terminated UNICODE",
|
|
|
|
// 7 - Unicode
|
|
"1.2.2.5.1", CERT_RDN_BMP_STRING, 10 *2,
|
|
(BYTE *) L"Length UNICODE",
|
|
|
|
// 8 - Universal
|
|
"1.2.2.5.2", CERT_RDN_UNIVERSAL_STRING, 0,
|
|
(BYTE *) L"Universal ~!@#$%^&*()_+{}:\"<>?",
|
|
|
|
// 9 - Octet
|
|
"1.2.2.5.3", CERT_RDN_OCTET_STRING, sizeof(rgbOctet),
|
|
rgbOctet,
|
|
|
|
// 10 - EncodedBlob
|
|
"1.2.2.5.4", CERT_RDN_ENCODED_BLOB, sizeof(rgbEncodedBlob),
|
|
rgbEncodedBlob,
|
|
|
|
// 11 - Empty rgdwPrintableOrT61ValueType
|
|
szOID_LOCALITY_NAME, 0, 0, NULL,
|
|
|
|
// 12 - Empty rgdwNumericValueType
|
|
szOID_X21_ADDRESS, 0, 0, NULL,
|
|
|
|
// 13 - DC (IA5)
|
|
szOID_DOMAIN_COMPONENT, 0, 0,
|
|
(BYTE *) L"microsoft",
|
|
|
|
// 14 - DC (IA5)
|
|
szOID_DOMAIN_COMPONENT, 0, 0,
|
|
(BYTE *) L"com",
|
|
|
|
// 15 - UTF8
|
|
"1.2.8.5", CERT_RDN_UTF8_STRING, 0,
|
|
(BYTE *) L"Null terminated UTF8",
|
|
|
|
// 16 - UTF8
|
|
"1.2.8.5.1", CERT_RDN_UTF8_STRING, 11 *2,
|
|
(BYTE *) L"Length UTF8",
|
|
|
|
// Note, FFFE and FFFF are excluded from the UTF8 standard
|
|
// 17 - UTF8
|
|
"1.2.8.5.2", CERT_RDN_UTF8_STRING, 0,
|
|
(BYTE *) L"SPECIAL UTF8: "
|
|
L"\x0001 \x0002 \x007e \x007f "
|
|
L"\x0080 \x0081 \x07fe \x07ff "
|
|
L"\x0800 \x0801 \xfffc \xfffd",
|
|
|
|
// 18 - UNICODE
|
|
"1.2.8.5.3", CERT_RDN_UNICODE_STRING, 0,
|
|
(BYTE *) L"SPECIAL UNICODE: "
|
|
L"\x0001 \x0002 \x007e \x007f "
|
|
L"\x0080 \x0081 \x07fe \x07ff "
|
|
L"\x0800 \x0801 \xfffe \xffff",
|
|
|
|
// 19 - DC (UTF8)
|
|
szOID_DOMAIN_COMPONENT, 0, 0,
|
|
(BYTE *) L"Unicode DC: "
|
|
L"\x0001 \x0002 \x007e \x007f "
|
|
L"\x0080 \x0081 \x07fe \x07ff "
|
|
L"\x0800 \x0801 \xfffe \xffff",
|
|
|
|
// 20 - Universal
|
|
"1.2.2.5.2.1.1.1", CERT_RDN_UNIVERSAL_STRING, 0,
|
|
(BYTE *) L"SPECIAL UNIVERSAL with Surrogate Pairs: "
|
|
L"\xd800\xdc00\xdbff\xdfff"
|
|
L"\xdbfe\xdc03\xd801\xdfcf"
|
|
L"\xd801\x0081\xdc01\xdc02"
|
|
L"\xd805\xd806\xd807\xdc04"
|
|
L"\xd802\xd803\xfffe\xd804",
|
|
|
|
};
|
|
|
|
CERT_RDN rgRDN[] = {
|
|
1, &rgAttr[0],
|
|
1, &rgAttr[1],
|
|
1, &rgAttr[2],
|
|
1, &rgAttr[3],
|
|
1, &rgAttr[4],
|
|
1, &rgAttr[5],
|
|
3, &rgAttr[5],
|
|
13, &rgAttr[8]
|
|
};
|
|
CERT_NAME_INFO Name = {8, rgRDN};
|
|
|
|
DoBadEncodeIssuer();
|
|
|
|
cbIssuerEncoded = 0;
|
|
CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
X509_UNICODE_NAME,
|
|
&Name,
|
|
NULL, // pbEncoded
|
|
&cbIssuerEncoded
|
|
);
|
|
if (cbIssuerEncoded == 0) {
|
|
PrintLastError("EncodeIssuer::CryptEncodeObject(cbEncoded == 0)");
|
|
goto ErrorReturn;
|
|
}
|
|
pbIssuerEncoded = (BYTE *) TestAlloc(cbIssuerEncoded);
|
|
if (pbIssuerEncoded == NULL) goto ErrorReturn;
|
|
if (!CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
X509_UNICODE_NAME,
|
|
&Name,
|
|
pbIssuerEncoded,
|
|
&cbIssuerEncoded
|
|
)) {
|
|
PrintLastError("EncodeIssuer::CryptEncodeObject");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
goto CommonReturn;
|
|
|
|
ErrorReturn:
|
|
if (pbIssuerEncoded)
|
|
TestFree(pbIssuerEncoded);
|
|
pbIssuerEncoded = NULL;
|
|
cbIssuerEncoded = 0;
|
|
CommonReturn:
|
|
*pcbIssuerEncoded = cbIssuerEncoded;
|
|
return pbIssuerEncoded;
|
|
}
|
|
|
|
static BOOL EncodeCert(BYTE **ppbEncoded, DWORD *pcbEncoded)
|
|
{
|
|
BOOL fResult;
|
|
BYTE *pbIssuerEncoded = NULL;
|
|
DWORD cbIssuerEncoded;
|
|
|
|
BYTE *pbNameEncoded = NULL;
|
|
DWORD cbNameEncoded;
|
|
BYTE *pbCertEncoded = NULL;
|
|
DWORD cbCertEncoded;
|
|
|
|
DWORD SerialNumber[2] = {0x12345678, 0x33445566};
|
|
SYSTEMTIME SystemTime;
|
|
|
|
#define ISSUER_UNIQUE_ID "IssuerUniqueId"
|
|
|
|
#define ATTR_0_0 "attr 0_0 printable"
|
|
#define ATTR_0_1 "attr 0_1 IA5"
|
|
#define ATTR_1_0 "attr 1_0 numeric"
|
|
#define ATTR_1_1 "attr 1_1 octet"
|
|
#define ATTR_2_0 "attr 2_0 teletex"
|
|
#define ATTR_2_1 "attr 2_1 videotex"
|
|
#define ATTR_2_2 "attr 2_2 graphic"
|
|
#define ATTR_2_3 "attr 2_3 visible"
|
|
#define ATTR_2_4 "attr 2_4 general"
|
|
#define ATTR_2_5 L"attr 2_5 BMP:: Unicode"
|
|
#define ATTR_2_6 L"attr 2_6 UTF8:: Unicode"
|
|
|
|
ULONG Universal[] = {0x12345678, 0, 0xFFFF1111, 0x87654321,
|
|
0x00FFFF,
|
|
0x010000,
|
|
0x010001,
|
|
0x10FFFE,
|
|
0x10FFFF,
|
|
0x110000,
|
|
0x10F803,
|
|
0x0107CF,
|
|
0x011C04,
|
|
};
|
|
|
|
BYTE NullDer[] = {0x05, 0x00};
|
|
BYTE IntegerDer[] = {0x02, 0x01, 0x35};
|
|
CERT_RDN_ATTR rgAttr0[] = {
|
|
"1.2.0.0", CERT_RDN_PRINTABLE_STRING,
|
|
strlen(ATTR_0_0), (BYTE *) ATTR_0_0,
|
|
"1.2.0.1", CERT_RDN_IA5_STRING,
|
|
strlen(ATTR_0_1), (BYTE *) ATTR_0_1
|
|
};
|
|
CERT_RDN_ATTR rgAttr1[] = {
|
|
"1.2.1.0", CERT_RDN_NUMERIC_STRING,
|
|
strlen(ATTR_1_0), (BYTE *) ATTR_1_0,
|
|
"1.2.1.1", CERT_RDN_OCTET_STRING,
|
|
strlen(ATTR_1_1), (BYTE *) ATTR_1_1,
|
|
"1.2.1.2", CERT_RDN_PRINTABLE_STRING,
|
|
0, NULL,
|
|
"1.2.1.3", CERT_RDN_ENCODED_BLOB,
|
|
sizeof(NullDer), NullDer,
|
|
"1.2.1.4", CERT_RDN_ENCODED_BLOB,
|
|
sizeof(IntegerDer), IntegerDer
|
|
};
|
|
CERT_RDN_ATTR rgAttr2[] = {
|
|
"1.2.2.0", CERT_RDN_TELETEX_STRING,
|
|
strlen(ATTR_2_0), (BYTE *) ATTR_2_0,
|
|
"1.2.2.1", CERT_RDN_VIDEOTEX_STRING,
|
|
strlen(ATTR_2_1), (BYTE *) ATTR_2_1,
|
|
"1.2.2.2", CERT_RDN_GRAPHIC_STRING,
|
|
strlen(ATTR_2_2), (BYTE *) ATTR_2_2,
|
|
"1.2.2.3", CERT_RDN_VISIBLE_STRING,
|
|
strlen(ATTR_2_3), (BYTE *) ATTR_2_3,
|
|
"1.2.2.4", CERT_RDN_GENERAL_STRING,
|
|
strlen(ATTR_2_4), (BYTE *) ATTR_2_4,
|
|
"1.2.2.5", CERT_RDN_BMP_STRING,
|
|
wcslen(ATTR_2_5) * 2, (BYTE *) ATTR_2_5,
|
|
"1.2.2.6", CERT_RDN_UTF8_STRING,
|
|
wcslen(ATTR_2_6) * 2, (BYTE *) ATTR_2_6,
|
|
"1.2.2.7", CERT_RDN_UNIVERSAL_STRING,
|
|
sizeof(Universal), (BYTE *) Universal
|
|
};
|
|
|
|
CERT_RDN_ATTR rgAttr3[] = {
|
|
"1.2.2.2", CERT_RDN_OCTET_STRING,
|
|
0, NULL,
|
|
"1.2.2.3", CERT_RDN_NUMERIC_STRING,
|
|
0, NULL,
|
|
"1.2.2.4", CERT_RDN_PRINTABLE_STRING,
|
|
0, NULL,
|
|
"1.2.2.5", CERT_RDN_TELETEX_STRING,
|
|
0, NULL,
|
|
"1.2.2.6", CERT_RDN_VIDEOTEX_STRING,
|
|
0, NULL,
|
|
"1.2.2.7", CERT_RDN_IA5_STRING,
|
|
0, NULL,
|
|
"1.2.2.8", CERT_RDN_GRAPHIC_STRING,
|
|
0, NULL,
|
|
"1.2.2.9", CERT_RDN_VISIBLE_STRING,
|
|
0, NULL,
|
|
"1.2.2.10", CERT_RDN_GENERAL_STRING,
|
|
0, NULL,
|
|
"1.2.2.11", CERT_RDN_UNIVERSAL_STRING,
|
|
0, NULL,
|
|
"1.2.2.12", CERT_RDN_BMP_STRING,
|
|
0, NULL,
|
|
"1.2.2.13", CERT_RDN_UTF8_STRING,
|
|
0, NULL
|
|
};
|
|
CERT_RDN rgRDN[] = {
|
|
2, rgAttr0,
|
|
5, rgAttr1,
|
|
8, rgAttr2,
|
|
12, rgAttr3
|
|
};
|
|
CERT_NAME_INFO Name = {4, rgRDN};
|
|
|
|
#define EXT_0 "extension 0 ."
|
|
#define EXT_1 "extension 1 .."
|
|
#define EXT_2 "extension 2 ..."
|
|
#define EXT_3 "extension 3 ...."
|
|
CERT_EXTENSION rgExt[] = {
|
|
"1.14.0", TRUE, strlen(EXT_0), (BYTE *) EXT_0,
|
|
"1.14.1.35.45", FALSE, strlen(EXT_1), (BYTE *) EXT_1,
|
|
"1.14.2", TRUE, strlen(EXT_2), (BYTE *) EXT_2,
|
|
"1.14.4", FALSE, strlen(EXT_3), (BYTE *) EXT_3
|
|
};
|
|
CERT_INFO Cert;
|
|
BYTE *pbExt = NULL;
|
|
|
|
if (dwExtLen) {
|
|
DWORD i;
|
|
if (NULL == (pbExt = (BYTE *) TestAlloc(dwExtLen)))
|
|
goto ErrorReturn;
|
|
|
|
for (i = 0; i < dwExtLen; i++)
|
|
pbExt[i] = (BYTE) i;
|
|
|
|
rgExt[3].Value.cbData = dwExtLen;
|
|
rgExt[3].Value.pbData = pbExt;
|
|
}
|
|
|
|
cbNameEncoded = 0;
|
|
CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
X509_NAME,
|
|
&Name,
|
|
NULL, // pbEncoded
|
|
&cbNameEncoded
|
|
);
|
|
if (cbNameEncoded == 0) {
|
|
PrintLastError("EncodeCert::CryptEncodeObject(cbEncoded == 0)");
|
|
goto ErrorReturn;
|
|
}
|
|
pbNameEncoded = (BYTE *) TestAlloc(cbNameEncoded);
|
|
if (pbNameEncoded == NULL) goto ErrorReturn;
|
|
if (!CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
X509_NAME,
|
|
&Name,
|
|
pbNameEncoded,
|
|
&cbNameEncoded
|
|
)) {
|
|
PrintLastError("EncodeCert::CryptEncodeObject");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
pbIssuerEncoded = EncodeIssuer(&cbIssuerEncoded);
|
|
if (NULL == pbIssuerEncoded)
|
|
goto ErrorReturn;
|
|
|
|
memset(&Cert, 0, sizeof(Cert));
|
|
Cert.dwVersion = CERT_V3;
|
|
Cert.SerialNumber.pbData = (BYTE *) &SerialNumber;
|
|
Cert.SerialNumber.cbData = sizeof(SerialNumber);
|
|
Cert.SignatureAlgorithm.pszObjId = "1.2.4.5.898";
|
|
Cert.Issuer.pbData = pbIssuerEncoded;
|
|
Cert.Issuer.cbData = cbIssuerEncoded;
|
|
|
|
GetSystemTime(&SystemTime);
|
|
SystemTimeToFileTime(&SystemTime, &Cert.NotBefore);
|
|
SystemTime.wYear++;
|
|
SystemTimeToFileTime(&SystemTime, &Cert.NotAfter);
|
|
|
|
Cert.Subject.pbData = pbNameEncoded;
|
|
Cert.Subject.cbData = cbNameEncoded;
|
|
Cert.SubjectPublicKeyInfo.Algorithm.pszObjId = "1.3.4.5.911";
|
|
Cert.SubjectPublicKeyInfo.PublicKey.pbData = (BYTE *) &SubjectPublicKey;
|
|
Cert.SubjectPublicKeyInfo.PublicKey.cbData = sizeof(SubjectPublicKey);
|
|
Cert.IssuerUniqueId.pbData = (BYTE *) ISSUER_UNIQUE_ID;
|
|
Cert.IssuerUniqueId.cbData = strlen(ISSUER_UNIQUE_ID);
|
|
Cert.IssuerUniqueId.cUnusedBits = 5;
|
|
// Cert.SubjectUniqueId = 0
|
|
Cert.cExtension = sizeof(rgExt) / sizeof(rgExt[0]);
|
|
Cert.rgExtension = rgExt;
|
|
|
|
cbCertEncoded = 0;
|
|
CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
X509_CERT_TO_BE_SIGNED,
|
|
&Cert,
|
|
NULL, // pbEncoded
|
|
&cbCertEncoded
|
|
);
|
|
if (cbCertEncoded == 0) {
|
|
PrintLastError("EncodeCert::CryptEncodeObject(cbEncoded == 0)");
|
|
goto ErrorReturn;
|
|
}
|
|
pbCertEncoded = (BYTE *) TestAlloc(cbCertEncoded);
|
|
if (pbCertEncoded == NULL) goto ErrorReturn;
|
|
if (!CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
X509_CERT_TO_BE_SIGNED,
|
|
&Cert,
|
|
pbCertEncoded,
|
|
&cbCertEncoded
|
|
)) {
|
|
PrintLastError("EncodeCert::CryptEncodeObject");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
if (!EncodeSignedContent(
|
|
pbCertEncoded,
|
|
cbCertEncoded,
|
|
ppbEncoded,
|
|
pcbEncoded))
|
|
goto ErrorReturn;
|
|
|
|
fResult = TRUE;
|
|
goto CommonReturn;
|
|
|
|
ErrorReturn:
|
|
*ppbEncoded = NULL;
|
|
*pcbEncoded = 0;
|
|
fResult = FALSE;
|
|
CommonReturn:
|
|
if (pbNameEncoded)
|
|
TestFree(pbNameEncoded);
|
|
if (pbIssuerEncoded)
|
|
TestFree(pbIssuerEncoded);
|
|
if (pbCertEncoded)
|
|
TestFree(pbCertEncoded);
|
|
if (pbExt)
|
|
TestFree(pbExt);
|
|
|
|
return fResult;
|
|
}
|
|
|
|
static BOOL EncodeCertReq(BYTE **ppbEncoded, DWORD *pcbEncoded)
|
|
{
|
|
BOOL fResult;
|
|
BYTE *pbNameEncoded = NULL;
|
|
DWORD cbNameEncoded;
|
|
BYTE *pbCertReqEncoded = NULL;
|
|
DWORD cbCertReqEncoded;
|
|
|
|
BYTE *pbExtEncoded = NULL;
|
|
DWORD cbExtEncoded;
|
|
|
|
|
|
#define CERT_REQ_0 "Cert Request subject 0"
|
|
#define CERT_REQ_1 "Cert Request subject 1 ...."
|
|
#define CERT_REQ_2 "Cert Request subject 2 ......."
|
|
|
|
|
|
CERT_RDN_ATTR rgNameAttr[] = {
|
|
"1.2.1.0", CERT_RDN_PRINTABLE_STRING,
|
|
strlen(CERT_REQ_0), (BYTE *) CERT_REQ_0,
|
|
"1.2.1.1", CERT_RDN_PRINTABLE_STRING,
|
|
strlen(CERT_REQ_1), (BYTE *) CERT_REQ_1,
|
|
"1.2.1.2", CERT_RDN_PRINTABLE_STRING,
|
|
strlen(CERT_REQ_2), (BYTE *) CERT_REQ_2
|
|
};
|
|
CERT_RDN rgRDN[] = {
|
|
1, &rgNameAttr[0],
|
|
1, &rgNameAttr[1],
|
|
1, &rgNameAttr[2]
|
|
};
|
|
CERT_NAME_INFO Name = {3, rgRDN};
|
|
|
|
BYTE NullDer[] = {0x05, 0x00};
|
|
BYTE IntegerDer[] = {0x02, 0x01, 0x35};
|
|
CRYPT_ATTR_BLOB rgAttrBlob[2] = {
|
|
2, (BYTE *) NullDer,
|
|
3, (BYTE *) IntegerDer
|
|
};
|
|
|
|
CRYPT_ATTR_BLOB ExtAttrBlob;
|
|
|
|
CRYPT_ATTRIBUTE rgAttr[] = {
|
|
szOID_RSA_certExtensions,
|
|
1, &ExtAttrBlob,
|
|
"1.2.3.4.5.0",
|
|
1, rgAttrBlob,
|
|
"1.2.1.1.1.1.1.1",
|
|
2, rgAttrBlob
|
|
};
|
|
|
|
#define REQ_EXT_0 "request extension 0 -"
|
|
#define REQ_EXT_1 "request extension 1 --"
|
|
#define REQ_EXT_2 "request extension 2 ---"
|
|
#define REQ_EXT_3 "request extension 3 ----"
|
|
CERT_EXTENSION rgExt[4] = {
|
|
"2.50.0", FALSE, strlen(REQ_EXT_0), (BYTE *) REQ_EXT_0,
|
|
"2.51.1", TRUE, strlen(REQ_EXT_1), (BYTE *) REQ_EXT_1,
|
|
"2.52.2", FALSE, strlen(REQ_EXT_2), (BYTE *) REQ_EXT_2,
|
|
"2.53.3", FALSE, strlen(REQ_EXT_3), (BYTE *) REQ_EXT_3
|
|
};
|
|
CERT_EXTENSIONS Extensions = {4, &rgExt[0]};
|
|
|
|
CERT_REQUEST_INFO CertReq;
|
|
|
|
cbNameEncoded = 0;
|
|
CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
X509_NAME,
|
|
&Name,
|
|
NULL, // pbEncoded
|
|
&cbNameEncoded
|
|
);
|
|
if (cbNameEncoded == 0) {
|
|
PrintLastError("EncodeCertReq::CryptEncodeObject(cbEncoded == 0)");
|
|
goto ErrorReturn;
|
|
}
|
|
pbNameEncoded = (BYTE *) TestAlloc(cbNameEncoded);
|
|
if (pbNameEncoded == NULL) goto ErrorReturn;
|
|
if (!CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
X509_NAME,
|
|
&Name,
|
|
pbNameEncoded,
|
|
&cbNameEncoded
|
|
)) {
|
|
PrintLastError("EncodeCertReq::CryptEncodeObject");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
cbExtEncoded = 0;
|
|
CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
X509_EXTENSIONS,
|
|
&Extensions,
|
|
NULL, // pbEncoded
|
|
&cbExtEncoded
|
|
);
|
|
if (cbExtEncoded == 0) {
|
|
PrintLastError("EncodeCertReq::CryptEncodeObject(cbEncoded == 0)");
|
|
goto ErrorReturn;
|
|
}
|
|
pbExtEncoded = (BYTE *) TestAlloc(cbExtEncoded);
|
|
if (pbExtEncoded == NULL) goto ErrorReturn;
|
|
if (!CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
X509_EXTENSIONS,
|
|
&Extensions,
|
|
pbExtEncoded,
|
|
&cbExtEncoded
|
|
)) {
|
|
PrintLastError("EncodeCertReq::CryptEncodeObject");
|
|
goto ErrorReturn;
|
|
}
|
|
ExtAttrBlob.pbData = pbExtEncoded;
|
|
ExtAttrBlob.cbData = cbExtEncoded;
|
|
|
|
memset(&CertReq, 0, sizeof(CertReq));
|
|
CertReq.dwVersion = 2;
|
|
CertReq.Subject.pbData = pbNameEncoded;
|
|
CertReq.Subject.cbData = cbNameEncoded;
|
|
CertReq.SubjectPublicKeyInfo.Algorithm.pszObjId = "1.3.4.5.911";
|
|
CertReq.SubjectPublicKeyInfo.PublicKey.pbData = (BYTE *) &SubjectPublicKey;
|
|
CertReq.SubjectPublicKeyInfo.PublicKey.cbData = sizeof(SubjectPublicKey);
|
|
CertReq.cAttribute = sizeof(rgAttr) / sizeof(rgAttr[0]);
|
|
CertReq.rgAttribute = rgAttr;
|
|
|
|
cbCertReqEncoded = 0;
|
|
CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
X509_CERT_REQUEST_TO_BE_SIGNED,
|
|
&CertReq,
|
|
NULL, // pbEncoded
|
|
&cbCertReqEncoded
|
|
);
|
|
if (cbCertReqEncoded == 0) {
|
|
PrintLastError("EncodeCertReq::CryptEncodeObject(cbEncoded == 0)");
|
|
goto ErrorReturn;
|
|
}
|
|
pbCertReqEncoded = (BYTE *) TestAlloc(cbCertReqEncoded);
|
|
if (pbCertReqEncoded == NULL) goto ErrorReturn;
|
|
if (!CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
X509_CERT_REQUEST_TO_BE_SIGNED,
|
|
&CertReq,
|
|
pbCertReqEncoded,
|
|
&cbCertReqEncoded
|
|
)) {
|
|
PrintLastError("EncodeCertReq::CryptEncodeObject");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
if (!EncodeSignedContent(
|
|
pbCertReqEncoded,
|
|
cbCertReqEncoded,
|
|
ppbEncoded,
|
|
pcbEncoded))
|
|
goto ErrorReturn;
|
|
|
|
fResult = TRUE;
|
|
goto CommonReturn;
|
|
|
|
ErrorReturn:
|
|
*ppbEncoded = NULL;
|
|
*pcbEncoded = 0;
|
|
fResult = FALSE;
|
|
CommonReturn:
|
|
if (pbExtEncoded)
|
|
TestFree(pbExtEncoded);
|
|
if (pbNameEncoded)
|
|
TestFree(pbNameEncoded);
|
|
if (pbCertReqEncoded)
|
|
TestFree(pbCertReqEncoded);
|
|
|
|
return fResult;
|
|
}
|
|
|
|
static BOOL EncodeKeygenReq(BYTE **ppbEncoded, DWORD *pcbEncoded)
|
|
{
|
|
BOOL fResult;
|
|
BYTE *pbKeygenReqEncoded = NULL;
|
|
DWORD cbKeygenReqEncoded;
|
|
|
|
CERT_KEYGEN_REQUEST_INFO KeygenReq;
|
|
|
|
memset(&KeygenReq, 0, sizeof(KeygenReq));
|
|
KeygenReq.dwVersion = CERT_KEYGEN_REQUEST_V1;
|
|
KeygenReq.SubjectPublicKeyInfo.Algorithm.pszObjId = "1.3.4.5.911";
|
|
KeygenReq.SubjectPublicKeyInfo.PublicKey.pbData = (BYTE *) &SubjectPublicKey;
|
|
KeygenReq.SubjectPublicKeyInfo.PublicKey.cbData = sizeof(SubjectPublicKey);
|
|
KeygenReq.pwszChallengeString = L"Keygen Challenge String";
|
|
|
|
cbKeygenReqEncoded = 0;
|
|
CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
X509_KEYGEN_REQUEST_TO_BE_SIGNED,
|
|
&KeygenReq,
|
|
NULL, // pbEncoded
|
|
&cbKeygenReqEncoded
|
|
);
|
|
if (cbKeygenReqEncoded == 0) {
|
|
PrintLastError("EncodeKeygenReq::CryptEncodeObject(cbEncoded == 0)");
|
|
goto ErrorReturn;
|
|
}
|
|
pbKeygenReqEncoded = (BYTE *) TestAlloc(cbKeygenReqEncoded);
|
|
if (pbKeygenReqEncoded == NULL) goto ErrorReturn;
|
|
if (!CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
X509_KEYGEN_REQUEST_TO_BE_SIGNED,
|
|
&KeygenReq,
|
|
pbKeygenReqEncoded,
|
|
&cbKeygenReqEncoded
|
|
)) {
|
|
PrintLastError("EncodeKeygenReq::CryptEncodeObject");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
if (!EncodeSignedContent(
|
|
pbKeygenReqEncoded,
|
|
cbKeygenReqEncoded,
|
|
ppbEncoded,
|
|
pcbEncoded))
|
|
goto ErrorReturn;
|
|
|
|
fResult = TRUE;
|
|
goto CommonReturn;
|
|
|
|
ErrorReturn:
|
|
*ppbEncoded = NULL;
|
|
*pcbEncoded = 0;
|
|
fResult = FALSE;
|
|
CommonReturn:
|
|
if (pbKeygenReqEncoded)
|
|
TestFree(pbKeygenReqEncoded);
|
|
|
|
return fResult;
|
|
}
|
|
|
|
static BOOL EncodeContentInfo(BYTE **ppbEncoded, DWORD *pcbEncoded)
|
|
{
|
|
BOOL fResult;
|
|
BYTE *pbEncoded = NULL;
|
|
DWORD cbEncoded;
|
|
|
|
CRYPT_CONTENT_INFO ContentInfo;
|
|
BYTE rgb0[] = {0x4, 0x5, 0x11, 0x22, 0x33, 0x44, 0x55}; // OCTET STRING
|
|
CRYPT_DER_BLOB Content = {
|
|
sizeof(rgb0), rgb0
|
|
};
|
|
|
|
|
|
memset(&ContentInfo, 0, sizeof(ContentInfo));
|
|
ContentInfo.pszObjId = "1.2.3.4.5.6.7.8.9.10";
|
|
ContentInfo.Content = Content;
|
|
|
|
cbEncoded = 0;
|
|
CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
PKCS_CONTENT_INFO,
|
|
&ContentInfo,
|
|
NULL, // pbEncoded
|
|
&cbEncoded
|
|
);
|
|
if (cbEncoded == 0) {
|
|
PrintLastError("EncodeContentInfo::CryptEncodeObject(cbEncoded == 0)");
|
|
goto ErrorReturn;
|
|
}
|
|
pbEncoded = (BYTE *) TestAlloc(cbEncoded);
|
|
if (pbEncoded == NULL) goto ErrorReturn;
|
|
if (!CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
PKCS_CONTENT_INFO,
|
|
&ContentInfo,
|
|
pbEncoded,
|
|
&cbEncoded
|
|
)) {
|
|
PrintLastError("EncodeContent::CryptEncodeObject");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
fResult = TRUE;
|
|
goto CommonReturn;
|
|
|
|
ErrorReturn:
|
|
if (pbEncoded) {
|
|
TestFree(pbEncoded);
|
|
pbEncoded = NULL;
|
|
}
|
|
cbEncoded = 0;
|
|
fResult = FALSE;
|
|
|
|
CommonReturn:
|
|
*ppbEncoded = pbEncoded;
|
|
*pcbEncoded = cbEncoded;
|
|
|
|
return fResult;
|
|
}
|
|
|
|
static LPCSTR FileTimeText(FILETIME *pft)
|
|
{
|
|
static char buf[80];
|
|
FILETIME ftLocal;
|
|
struct tm ctm;
|
|
SYSTEMTIME st;
|
|
|
|
FileTimeToLocalFileTime(pft, &ftLocal);
|
|
if (FileTimeToSystemTime(&ftLocal, &st))
|
|
{
|
|
ctm.tm_sec = st.wSecond;
|
|
ctm.tm_min = st.wMinute;
|
|
ctm.tm_hour = st.wHour;
|
|
ctm.tm_mday = st.wDay;
|
|
ctm.tm_mon = st.wMonth-1;
|
|
ctm.tm_year = st.wYear-1900;
|
|
ctm.tm_wday = st.wDayOfWeek;
|
|
ctm.tm_yday = 0;
|
|
ctm.tm_isdst = 0;
|
|
strcpy(buf, asctime(&ctm));
|
|
buf[strlen(buf)-1] = 0;
|
|
}
|
|
else
|
|
sprintf(buf, "<FILETIME %08lX:%08lX>", pft->dwHighDateTime,
|
|
pft->dwLowDateTime);
|
|
return buf;
|
|
}
|
|
|
|
#define CROW 16
|
|
static void PrintBytes(LPCSTR pszHdr, BYTE *pb, DWORD cbSize)
|
|
{
|
|
ULONG cb, i;
|
|
|
|
while (cbSize > 0)
|
|
{
|
|
printf("%s", pszHdr);
|
|
cb = min(CROW, cbSize);
|
|
cbSize -= cb;
|
|
for (i = 0; i<cb; i++)
|
|
printf(" %02X", pb[i]);
|
|
for (i = cb; i<CROW; i++)
|
|
printf(" ");
|
|
printf(" '");
|
|
for (i = 0; i<cb; i++)
|
|
if (pb[i] >= 0x20 && pb[i] <= 0x7f)
|
|
printf("%c", pb[i]);
|
|
else
|
|
printf(".");
|
|
pb += cb;
|
|
printf("'\n");
|
|
}
|
|
}
|
|
|
|
static BOOL DecodeName(BYTE *pbEncoded, DWORD cbEncoded)
|
|
{
|
|
BOOL fResult;
|
|
PCERT_NAME_INFO pInfo = NULL;
|
|
DWORD i,j;
|
|
PCERT_RDN pRDN;
|
|
PCERT_RDN_ATTR pAttr;
|
|
|
|
if (NULL == (pInfo = (PCERT_NAME_INFO) TestDecodeObject(
|
|
X509_NAME,
|
|
pbEncoded,
|
|
cbEncoded
|
|
))) goto ErrorReturn;
|
|
|
|
for (i = 0, pRDN = pInfo->rgRDN; i < pInfo->cRDN; i++, pRDN++) {
|
|
for (j = 0, pAttr = pRDN->rgRDNAttr; j < pRDN->cRDNAttr; j++, pAttr++) {
|
|
LPSTR pszObjId = pAttr->pszObjId;
|
|
if (pszObjId == NULL)
|
|
pszObjId = "<NULL OBJID>";
|
|
printf(" [%d,%d] %s ValueType: %d\n",
|
|
i, j, pszObjId, pAttr->dwValueType);
|
|
if (pAttr->Value.cbData)
|
|
PrintBytes(" ", pAttr->Value.pbData, pAttr->Value.cbData);
|
|
else
|
|
printf(" NO Value Bytes\n");
|
|
}
|
|
}
|
|
|
|
if (fFormatAllNameStrings) {
|
|
CERT_NAME_BLOB Name;
|
|
DWORD cwsz;
|
|
LPWSTR pwsz;
|
|
DWORD csz;
|
|
LPSTR psz;
|
|
Name.pbData = pbEncoded;
|
|
Name.cbData = cbEncoded;
|
|
#define DELTA_DECRMENT 7
|
|
DWORD dwDelta;
|
|
|
|
DWORD rgdwStrType[] = {
|
|
CERT_SIMPLE_NAME_STR,
|
|
CERT_OID_NAME_STR,
|
|
CERT_X500_NAME_STR,
|
|
CERT_SIMPLE_NAME_STR | CERT_NAME_STR_SEMICOLON_FLAG |
|
|
CERT_NAME_STR_NO_PLUS_FLAG | CERT_NAME_STR_NO_QUOTING_FLAG,
|
|
CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG |
|
|
CERT_NAME_STR_NO_QUOTING_FLAG,
|
|
CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG,
|
|
0
|
|
};
|
|
DWORD *pdwStrType;
|
|
|
|
for (pdwStrType = rgdwStrType, dwDelta = DELTA_DECRMENT; *pdwStrType;
|
|
pdwStrType++, dwDelta += DELTA_DECRMENT) {
|
|
printf("\nCertNameToStrW(dwStrType == 0x%x)\n", *pdwStrType);
|
|
cwsz = CertNameToStrW(
|
|
dwCertEncodingType,
|
|
&Name,
|
|
*pdwStrType,
|
|
NULL, // pwsz
|
|
0); // cwsz
|
|
if (pwsz = (LPWSTR) TestAlloc(cwsz * sizeof(WCHAR))) {
|
|
CertNameToStrW(
|
|
dwCertEncodingType,
|
|
&Name,
|
|
*pdwStrType,
|
|
pwsz,
|
|
cwsz);
|
|
printf(" %S\n", pwsz);
|
|
if (cwsz > dwDelta) {
|
|
CertNameToStrW(
|
|
dwCertEncodingType,
|
|
&Name,
|
|
*pdwStrType,
|
|
pwsz,
|
|
cwsz - dwDelta);
|
|
printf("Delta[-%d]\n", dwDelta);
|
|
printf(" %S\n", pwsz);
|
|
}
|
|
TestFree(pwsz);
|
|
}
|
|
}
|
|
|
|
for (pdwStrType = rgdwStrType, dwDelta = DELTA_DECRMENT; *pdwStrType;
|
|
pdwStrType++, dwDelta += DELTA_DECRMENT) {
|
|
printf("\nCertNameToStrA(dwStrType == 0x%x)\n", *pdwStrType);
|
|
csz = CertNameToStrA(
|
|
dwCertEncodingType,
|
|
&Name,
|
|
*pdwStrType,
|
|
NULL, // psz
|
|
0); // csz
|
|
if (psz = (LPSTR) TestAlloc(csz)) {
|
|
CertNameToStrA(
|
|
dwCertEncodingType,
|
|
&Name,
|
|
*pdwStrType,
|
|
psz,
|
|
csz);
|
|
printf(" %s\n", psz);
|
|
if (csz > dwDelta) {
|
|
csz = CertNameToStrA(
|
|
dwCertEncodingType,
|
|
&Name,
|
|
*pdwStrType,
|
|
psz,
|
|
csz - dwDelta);
|
|
printf("Delta[-%d]\n", dwDelta);
|
|
if (1 >= csz) {
|
|
DWORD dwErr = GetLastError();
|
|
printf(" No CertNameToStrA string, LastError: 0x%x (%d) \n",
|
|
dwErr, dwErr);
|
|
} else
|
|
printf(" %s\n", psz);
|
|
}
|
|
TestFree(psz);
|
|
}
|
|
}
|
|
} else if (fFormatNameStrings) {
|
|
CERT_NAME_BLOB Name;
|
|
DWORD cwsz;
|
|
LPWSTR pwsz;
|
|
Name.pbData = pbEncoded;
|
|
Name.cbData = cbEncoded;
|
|
|
|
cwsz = CertNameToStrW(
|
|
dwCertEncodingType,
|
|
&Name,
|
|
CERT_X500_NAME_STR,
|
|
NULL, // pwsz
|
|
0); // cwsz
|
|
if (pwsz = (LPWSTR) TestAlloc(cwsz * sizeof(WCHAR))) {
|
|
CertNameToStrW(
|
|
dwCertEncodingType,
|
|
&Name,
|
|
CERT_X500_NAME_STR,
|
|
pwsz,
|
|
cwsz);
|
|
printf(" %S\n", pwsz);
|
|
TestFree(pwsz);
|
|
}
|
|
}
|
|
|
|
fResult = TRUE;
|
|
goto CommonReturn;
|
|
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
CommonReturn:
|
|
if (pInfo)
|
|
TestFree(pInfo);
|
|
return fResult;
|
|
}
|
|
|
|
static void DecodeSignedContent(
|
|
BYTE *pbEncoded,
|
|
DWORD cbEncoded,
|
|
LPCSTR lpszToBeSignedStructType,
|
|
DWORD cbToBeSignedStruct
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
PCERT_INFO pInfo = NULL;
|
|
LPSTR pszObjId;
|
|
DWORD cbInfo;
|
|
|
|
PCERT_SIGNED_CONTENT_INFO pCertEncoding;
|
|
|
|
if (NULL == (pCertEncoding = (PCERT_SIGNED_CONTENT_INFO) TestDecodeObject(
|
|
X509_CERT,
|
|
pbEncoded,
|
|
cbEncoded
|
|
))) goto ErrorReturn;
|
|
|
|
// Decode the ToBeSigned
|
|
cbInfo = 0x12345678;
|
|
if (!CryptDecodeObject(
|
|
dwCertEncodingType,
|
|
lpszToBeSignedStructType,
|
|
pCertEncoding->ToBeSigned.pbData,
|
|
pCertEncoding->ToBeSigned.cbData,
|
|
dwDecodeObjectFlags | CRYPT_DECODE_TO_BE_SIGNED_FLAG,
|
|
NULL, // pvInfo
|
|
&cbInfo))
|
|
PrintLastError("CryptDecodeObject(TO_BE_SIGNED_FLAG)");
|
|
else if (cbInfo != cbToBeSignedStruct)
|
|
printf("failed => CryptDecodeObject(TO_BE_SIGNED_FLAG) returned cbInfo = %d, not %d\n",
|
|
cbInfo, cbToBeSignedStruct);
|
|
cbInfo = 0x12345678;
|
|
if (!CryptDecodeObject(
|
|
dwCertEncodingType,
|
|
lpszToBeSignedStructType,
|
|
pCertEncoding->ToBeSigned.pbData,
|
|
pCertEncoding->ToBeSigned.cbData,
|
|
dwDecodeObjectFlags,
|
|
NULL, // pvInfo
|
|
&cbInfo))
|
|
PrintLastError("CryptDecodeObject(ToBeSigned, without flag)");
|
|
else if (cbInfo != cbToBeSignedStruct)
|
|
printf("failed => CryptDecodeObject(ToBeSigned without flag) returned cbInfo = %d, not %d\n",
|
|
cbInfo, cbToBeSignedStruct);
|
|
|
|
pszObjId = pCertEncoding->SignatureAlgorithm.pszObjId;
|
|
if (pszObjId == NULL)
|
|
pszObjId = "<NULL OBJID>";
|
|
printf("Content SignatureAlgorithm:: %s\n", pszObjId);
|
|
if (pCertEncoding->SignatureAlgorithm.Parameters.cbData) {
|
|
printf("Content SignatureAlgorithm.Parameters::\n");
|
|
PrintBytes(" ", pCertEncoding->SignatureAlgorithm.Parameters.pbData,
|
|
pCertEncoding->SignatureAlgorithm.Parameters.cbData);
|
|
}
|
|
|
|
if (pCertEncoding->Signature.cbData) {
|
|
printf("Content Signature::\n");
|
|
PrintBytes(" ", pCertEncoding->Signature.pbData,
|
|
pCertEncoding->Signature.cbData);
|
|
} else
|
|
printf("Content Signature:: NONE\n");
|
|
|
|
printf("Content Length:: %d\n", pCertEncoding->ToBeSigned.cbData);
|
|
|
|
fResult = TRUE;
|
|
goto CommonReturn;
|
|
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
CommonReturn:
|
|
if (pCertEncoding)
|
|
TestFree(pCertEncoding);
|
|
}
|
|
|
|
static void PrintExtensions(DWORD cExt, PCERT_EXTENSION pExt)
|
|
{
|
|
DWORD i;
|
|
|
|
for (i = 0; i < cExt; i++, pExt++) {
|
|
LPSTR pszObjId = pExt->pszObjId;
|
|
if (pszObjId == NULL)
|
|
pszObjId = "<NULL OBJID>";
|
|
LPSTR pszCritical = pExt->fCritical ? "TRUE" : "FALSE";
|
|
printf(" [%d] %s Critical: %s\n", i, pszObjId, pszCritical);
|
|
if (pExt->Value.cbData)
|
|
PrintBytes(" ", pExt->Value.pbData, pExt->Value.cbData);
|
|
else
|
|
printf(" NO Value Bytes\n");
|
|
}
|
|
}
|
|
|
|
static void DecodeExtensions(BYTE *pbEncoded, DWORD cbEncoded)
|
|
{
|
|
PCERT_EXTENSIONS pInfo;
|
|
if (NULL == (pInfo = (PCERT_EXTENSIONS) TestDecodeObject(
|
|
X509_EXTENSIONS,
|
|
pbEncoded,
|
|
cbEncoded
|
|
))) goto ErrorReturn;
|
|
|
|
PrintExtensions(pInfo->cExtension, pInfo->rgExtension);
|
|
goto CommonReturn;
|
|
|
|
ErrorReturn:
|
|
CommonReturn:
|
|
if (pInfo)
|
|
TestFree(pInfo);
|
|
}
|
|
|
|
static void PrintAttributes(DWORD cAttr, PCRYPT_ATTRIBUTE pAttr)
|
|
{
|
|
DWORD i;
|
|
DWORD j;
|
|
|
|
for (i = 0; i < cAttr; i++, pAttr++) {
|
|
DWORD cValue = pAttr->cValue;
|
|
PCRYPT_ATTR_BLOB pValue = pAttr->rgValue;
|
|
LPSTR pszObjId = pAttr->pszObjId;
|
|
if (pszObjId == NULL)
|
|
pszObjId = "<NULL OBJID>";
|
|
if (cValue) {
|
|
for (j = 0; j < cValue; j++, pValue++) {
|
|
printf(" [%d,%d] %s\n", i, j, pszObjId);
|
|
if (pValue->cbData) {
|
|
PrintBytes(" ", pValue->pbData, pValue->cbData);
|
|
if (strcmp(pszObjId, szOID_RSA_certExtensions) == 0 ||
|
|
strcmp(pszObjId, SPC_CERT_EXTENSIONS_OBJID) == 0) {
|
|
printf(" Extensions::\n");
|
|
DecodeExtensions(pValue->pbData, pValue->cbData);
|
|
}
|
|
} else
|
|
printf(" NO Value Bytes\n");
|
|
}
|
|
} else
|
|
printf(" [%d] %s :: No Values\n", i, pszObjId);
|
|
}
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Write the public key to the file
|
|
//--------------------------------------------------------------------------
|
|
BOOL WritePublicKeyToFile(
|
|
LPCSTR pszFileName,
|
|
PBYTE pbPub,
|
|
DWORD cbPub
|
|
)
|
|
{
|
|
FILE *stream;
|
|
DWORD i;
|
|
|
|
if (NULL == (stream = fopen(pszFileName, "w"))) {
|
|
printf("Failed to open %s for writing public key\n", pszFileName);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
for (i = 0; i < cbPub; i++) {
|
|
fprintf(stream, "0x%02X", pbPub[i]);
|
|
if (i != (cbPub - 1))
|
|
fprintf(stream, ",");
|
|
if ((i + 1) % 16 == 0)
|
|
fprintf(stream, "\n");
|
|
}
|
|
fprintf(stream, "\n");
|
|
|
|
fclose(stream);
|
|
return TRUE;
|
|
}
|
|
|
|
void WriteBytesToFile(
|
|
IN FILE *stream,
|
|
IN const BYTE *pb,
|
|
IN DWORD cb
|
|
)
|
|
{
|
|
DWORD i;
|
|
|
|
fprintf(stream, "= {\n");
|
|
for (i = 0; i < cb; i++) {
|
|
if ((i % 8) == 0)
|
|
fprintf(stream, " ");
|
|
fprintf(stream, "0x%02X", pb[i]);
|
|
if (i == (cb - 1))
|
|
fprintf(stream, "\n");
|
|
else {
|
|
fprintf(stream, ",");
|
|
if ((i + 1) % 8 == 0)
|
|
fprintf(stream, "\n");
|
|
else
|
|
fprintf(stream, " ");
|
|
}
|
|
}
|
|
|
|
fprintf(stream, "};\n\n");
|
|
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Write the Name and PublicKeyInfo to the file
|
|
//--------------------------------------------------------------------------
|
|
BOOL WritePublicKeyInfoToFile(
|
|
LPCSTR pszFileName,
|
|
PCERT_INFO pCertInfo
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
FILE *stream;
|
|
LPWSTR pwszName = NULL;
|
|
DWORD cchName;
|
|
BYTE *pbEncoded = NULL;
|
|
DWORD cbEncoded;
|
|
|
|
if (NULL == (stream = fopen(pszFileName, "w"))) {
|
|
printf("Failed to open %s for writing PublicKeyInfo\n", pszFileName);
|
|
return FALSE;
|
|
}
|
|
|
|
// Output the Subject X500 name string as a comment
|
|
cchName = CertNameToStrW(
|
|
X509_ASN_ENCODING,
|
|
&pCertInfo->Subject,
|
|
CERT_X500_NAME_STR,
|
|
NULL, // pwsz
|
|
0 // cch
|
|
);
|
|
if (NULL == (pwszName = (LPWSTR) TestAlloc(cchName * sizeof(WCHAR))))
|
|
goto ErrorReturn;
|
|
cchName = CertNameToStrW(
|
|
X509_ASN_ENCODING,
|
|
&pCertInfo->Subject,
|
|
CERT_NAME_STR_REVERSE_FLAG |
|
|
CERT_X500_NAME_STR,
|
|
pwszName,
|
|
cchName
|
|
);
|
|
|
|
fprintf(stream, "// Name:: <%S>\n", pwszName);
|
|
// Write the encoded Subject Name bytes
|
|
WriteBytesToFile(stream, pCertInfo->Subject.pbData,
|
|
pCertInfo->Subject.cbData);
|
|
|
|
fprintf(stream, "// PublicKeyInfo\n");
|
|
|
|
// Encode and write the PublicKeyInfo bytes
|
|
|
|
if (!CryptEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_PUBLIC_KEY_INFO,
|
|
&pCertInfo->SubjectPublicKeyInfo,
|
|
NULL, // pbEncoded
|
|
&cbEncoded
|
|
)) {
|
|
PrintLastError("CryptEncodeObject(X509_PUBLIC_KEY_INFO)");
|
|
goto ErrorReturn;
|
|
}
|
|
pbEncoded = (BYTE *) TestAlloc(cbEncoded);
|
|
if (pbEncoded == NULL) goto ErrorReturn;
|
|
if (!CryptEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_PUBLIC_KEY_INFO,
|
|
&pCertInfo->SubjectPublicKeyInfo,
|
|
pbEncoded,
|
|
&cbEncoded
|
|
)) {
|
|
PrintLastError("CryptEncodeObject(X509_PUBLIC_KEY_INFO)");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
WriteBytesToFile(stream, pbEncoded, cbEncoded);
|
|
|
|
fprintf(stream, "\n");
|
|
|
|
fResult = TRUE;
|
|
CommonReturn:
|
|
fclose(stream);
|
|
|
|
TestFree(pwszName);
|
|
TestFree(pbEncoded);
|
|
return fResult;
|
|
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
goto CommonReturn;
|
|
}
|
|
|
|
static BOOL DecodeCert(BYTE *pbEncoded, DWORD cbEncoded)
|
|
{
|
|
BOOL fResult;
|
|
PCERT_INFO pInfo = NULL;
|
|
DWORD cbInfo;
|
|
LPSTR pszObjId;
|
|
|
|
if (NULL == (pInfo = (PCERT_INFO) TestDecodeObject(
|
|
X509_CERT_TO_BE_SIGNED,
|
|
pbEncoded,
|
|
cbEncoded,
|
|
&cbInfo
|
|
))) goto ErrorReturn;
|
|
|
|
printf("Version:: %d\n", pInfo->dwVersion);
|
|
{
|
|
DWORD cb;
|
|
BYTE *pb;
|
|
printf("SerialNumber::");
|
|
for (cb = pInfo->SerialNumber.cbData,
|
|
pb = pInfo->SerialNumber.pbData + (cb - 1);
|
|
cb > 0; cb--, pb--) {
|
|
printf(" %02X", *pb);
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
pszObjId = pInfo->SignatureAlgorithm.pszObjId;
|
|
if (pszObjId == NULL)
|
|
pszObjId = "<NULL OBJID>";
|
|
printf("SignatureAlgorithm:: %s\n", pszObjId);
|
|
if (pInfo->SignatureAlgorithm.Parameters.cbData) {
|
|
printf("SignatureAlgorithm.Parameters::\n");
|
|
PrintBytes(" ", pInfo->SignatureAlgorithm.Parameters.pbData,
|
|
pInfo->SignatureAlgorithm.Parameters.cbData);
|
|
}
|
|
|
|
printf("Issuer::\n");
|
|
DecodeName(pInfo->Issuer.pbData, pInfo->Issuer.cbData);
|
|
|
|
printf("NotBefore:: %s\n", FileTimeText(&pInfo->NotBefore));
|
|
printf("NotAfter:: %s\n", FileTimeText(&pInfo->NotAfter));
|
|
|
|
printf("Subject::\n");
|
|
DecodeName(pInfo->Subject.pbData, pInfo->Subject.cbData);
|
|
|
|
pszObjId = pInfo->SubjectPublicKeyInfo.Algorithm.pszObjId;
|
|
if (pszObjId == NULL)
|
|
pszObjId = "<NULL OBJID>";
|
|
printf("SubjectPublicKeyInfo.Algorithm:: %s\n", pszObjId);
|
|
if (pInfo->SubjectPublicKeyInfo.Algorithm.Parameters.cbData) {
|
|
printf("SubjectPublicKeyInfo.Algorithm.Parameters::\n");
|
|
PrintBytes(" ",
|
|
pInfo->SubjectPublicKeyInfo.Algorithm.Parameters.pbData,
|
|
pInfo->SubjectPublicKeyInfo.Algorithm.Parameters.cbData);
|
|
}
|
|
printf("SubjectPublicKeyInfo.PublicKey");
|
|
if (pInfo->SubjectPublicKeyInfo.PublicKey.cUnusedBits)
|
|
printf(" (UnusedBits: %d)",
|
|
pInfo->SubjectPublicKeyInfo.PublicKey.cUnusedBits);
|
|
printf("::\n");
|
|
if (pInfo->SubjectPublicKeyInfo.PublicKey.cbData) {
|
|
PrintBytes(" ", pInfo->SubjectPublicKeyInfo.PublicKey.pbData,
|
|
pInfo->SubjectPublicKeyInfo.PublicKey.cbData);
|
|
} else
|
|
printf(" No public key\n");
|
|
|
|
if (pszPublicKeyFilename) {
|
|
if (fWritePublicKeyInfo)
|
|
WritePublicKeyInfoToFile(pszPublicKeyFilename, pInfo);
|
|
else
|
|
WritePublicKeyToFile(pszPublicKeyFilename,
|
|
pInfo->SubjectPublicKeyInfo.PublicKey.pbData,
|
|
pInfo->SubjectPublicKeyInfo.PublicKey.cbData
|
|
);
|
|
}
|
|
|
|
|
|
if (pszReadFilename == NULL) {
|
|
// Verify that the public key was properly encoded/decoded
|
|
CERT_PUBLIC_KEY_INFO PublicKeyInfo;
|
|
|
|
memset(&PublicKeyInfo, 0, sizeof(PublicKeyInfo));
|
|
PublicKeyInfo.Algorithm.pszObjId = "1.3.4.5.911";
|
|
PublicKeyInfo.PublicKey.pbData = (BYTE *) &SubjectPublicKey;
|
|
PublicKeyInfo.PublicKey.cbData = sizeof(SubjectPublicKey);
|
|
if (!CertComparePublicKeyInfo(
|
|
dwCertEncodingType,
|
|
&PublicKeyInfo,
|
|
&pInfo->SubjectPublicKeyInfo))
|
|
PrintLastError("CertComparePublicKeyInfo");
|
|
}
|
|
|
|
if (pInfo->IssuerUniqueId.cbData) {
|
|
printf("IssuerUniqueId");
|
|
if (pInfo->IssuerUniqueId.cUnusedBits)
|
|
printf(" (UnusedBits: %d)", pInfo->IssuerUniqueId.cUnusedBits);
|
|
printf("::\n");
|
|
PrintBytes(" ", pInfo->IssuerUniqueId.pbData,
|
|
pInfo->IssuerUniqueId.cbData);
|
|
}
|
|
|
|
if (pInfo->SubjectUniqueId.cbData) {
|
|
printf("SubjectUniqueId");
|
|
if (pInfo->SubjectUniqueId.cUnusedBits)
|
|
printf(" (UnusedBits: %d)", pInfo->SubjectUniqueId.cUnusedBits);
|
|
printf("::\n");
|
|
PrintBytes(" ", pInfo->SubjectUniqueId.pbData,
|
|
pInfo->SubjectUniqueId.cbData);
|
|
}
|
|
|
|
if (pInfo->cExtension == 0)
|
|
printf("Extensions:: NONE\n");
|
|
else {
|
|
printf("Extensions::\n");
|
|
PrintExtensions(pInfo->cExtension, pInfo->rgExtension);
|
|
}
|
|
|
|
DecodeSignedContent(pbEncoded, cbEncoded, X509_CERT_TO_BE_SIGNED,
|
|
cbInfo);
|
|
|
|
fResult = TRUE;
|
|
goto CommonReturn;
|
|
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
CommonReturn:
|
|
if (pInfo)
|
|
TestFree(pInfo);
|
|
return fResult;
|
|
}
|
|
|
|
|
|
static BOOL DecodeCertReq(BYTE *pbEncoded, DWORD cbEncoded)
|
|
{
|
|
BOOL fResult;
|
|
PCERT_REQUEST_INFO pInfo = NULL;
|
|
DWORD cbInfo;
|
|
LPSTR pszObjId;
|
|
|
|
if (NULL == (pInfo = (PCERT_REQUEST_INFO) TestDecodeObject(
|
|
X509_CERT_REQUEST_TO_BE_SIGNED,
|
|
pbEncoded,
|
|
cbEncoded,
|
|
&cbInfo
|
|
))) goto ErrorReturn;
|
|
|
|
printf("Version:: %d\n", pInfo->dwVersion);
|
|
printf("Subject::\n");
|
|
DecodeName(pInfo->Subject.pbData, pInfo->Subject.cbData);
|
|
|
|
pszObjId = pInfo->SubjectPublicKeyInfo.Algorithm.pszObjId;
|
|
if (pszObjId == NULL)
|
|
pszObjId = "<NULL OBJID>";
|
|
printf("SubjectPublicKeyInfo.Algorithm:: %s\n", pszObjId);
|
|
if (pInfo->SubjectPublicKeyInfo.Algorithm.Parameters.cbData) {
|
|
printf("SubjectPublicKeyInfo.Algorithm.Parameters::\n");
|
|
PrintBytes(" ",
|
|
pInfo->SubjectPublicKeyInfo.Algorithm.Parameters.pbData,
|
|
pInfo->SubjectPublicKeyInfo.Algorithm.Parameters.cbData);
|
|
}
|
|
printf("SubjectPublicKeyInfo.PublicKey");
|
|
if (pInfo->SubjectPublicKeyInfo.PublicKey.cUnusedBits)
|
|
printf(" (UnusedBits: %d)",
|
|
pInfo->SubjectPublicKeyInfo.PublicKey.cUnusedBits);
|
|
printf("::\n");
|
|
if (pInfo->SubjectPublicKeyInfo.PublicKey.cbData) {
|
|
PrintBytes(" ", pInfo->SubjectPublicKeyInfo.PublicKey.pbData,
|
|
pInfo->SubjectPublicKeyInfo.PublicKey.cbData);
|
|
} else
|
|
printf(" No public key\n");
|
|
|
|
|
|
if (pInfo->cAttribute == 0)
|
|
printf("Attributes:: NONE\n");
|
|
else {
|
|
printf("Attributes::\n");
|
|
PrintAttributes(pInfo->cAttribute, pInfo->rgAttribute);
|
|
}
|
|
|
|
DecodeSignedContent(pbEncoded, cbEncoded, X509_CERT_REQUEST_TO_BE_SIGNED,
|
|
cbInfo);
|
|
|
|
fResult = TRUE;
|
|
goto CommonReturn;
|
|
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
CommonReturn:
|
|
if (pInfo)
|
|
TestFree(pInfo);
|
|
return fResult;
|
|
}
|
|
|
|
static BOOL DecodeKeygenReq(BYTE *pbEncoded, DWORD cbEncoded)
|
|
{
|
|
BOOL fResult;
|
|
PCERT_KEYGEN_REQUEST_INFO pInfo = NULL;
|
|
DWORD cbInfo;
|
|
LPSTR pszObjId;
|
|
|
|
if (NULL == (pInfo = (PCERT_KEYGEN_REQUEST_INFO) TestDecodeObject(
|
|
X509_KEYGEN_REQUEST_TO_BE_SIGNED,
|
|
pbEncoded,
|
|
cbEncoded,
|
|
&cbInfo
|
|
))) goto ErrorReturn;
|
|
|
|
printf("Version:: %d\n", pInfo->dwVersion);
|
|
|
|
pszObjId = pInfo->SubjectPublicKeyInfo.Algorithm.pszObjId;
|
|
if (pszObjId == NULL)
|
|
pszObjId = "<NULL OBJID>";
|
|
printf("SubjectPublicKeyInfo.Algorithm:: %s\n", pszObjId);
|
|
if (pInfo->SubjectPublicKeyInfo.Algorithm.Parameters.cbData) {
|
|
printf("SubjectPublicKeyInfo.Algorithm.Parameters::\n");
|
|
PrintBytes(" ",
|
|
pInfo->SubjectPublicKeyInfo.Algorithm.Parameters.pbData,
|
|
pInfo->SubjectPublicKeyInfo.Algorithm.Parameters.cbData);
|
|
}
|
|
printf("SubjectPublicKeyInfo.PublicKey");
|
|
if (pInfo->SubjectPublicKeyInfo.PublicKey.cUnusedBits)
|
|
printf(" (UnusedBits: %d)",
|
|
pInfo->SubjectPublicKeyInfo.PublicKey.cUnusedBits);
|
|
printf("::\n");
|
|
if (pInfo->SubjectPublicKeyInfo.PublicKey.cbData) {
|
|
PrintBytes(" ", pInfo->SubjectPublicKeyInfo.PublicKey.pbData,
|
|
pInfo->SubjectPublicKeyInfo.PublicKey.cbData);
|
|
} else
|
|
printf(" No public key\n");
|
|
|
|
printf("ChallengeString:: %S\n", pInfo->pwszChallengeString);
|
|
|
|
DecodeSignedContent(pbEncoded, cbEncoded, X509_KEYGEN_REQUEST_TO_BE_SIGNED,
|
|
cbInfo);
|
|
|
|
fResult = TRUE;
|
|
goto CommonReturn;
|
|
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
CommonReturn:
|
|
if (pInfo)
|
|
TestFree(pInfo);
|
|
return fResult;
|
|
}
|
|
|
|
static BOOL DecodeContentInfo(BYTE *pbEncoded, DWORD cbEncoded)
|
|
{
|
|
BOOL fResult;
|
|
PCRYPT_CONTENT_INFO pInfo = NULL;
|
|
LPSTR pszObjId;
|
|
|
|
if (NULL == (pInfo = (PCRYPT_CONTENT_INFO) TestDecodeObject(
|
|
PKCS_CONTENT_INFO,
|
|
pbEncoded,
|
|
cbEncoded
|
|
))) goto ErrorReturn;
|
|
|
|
pszObjId = pInfo->pszObjId;
|
|
if (pszObjId == NULL)
|
|
pszObjId = "<NULL OBJID>";
|
|
printf("ContentType:: %s\n", pszObjId);
|
|
if (pInfo->Content.cbData) {
|
|
printf("Content::\n");
|
|
PrintBytes(" ", pInfo->Content.pbData, pInfo->Content.cbData);
|
|
} else
|
|
printf("NO Content\n");
|
|
|
|
fResult = TRUE;
|
|
goto CommonReturn;
|
|
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
CommonReturn:
|
|
if (pInfo)
|
|
TestFree(pInfo);
|
|
return fResult;
|
|
}
|
|
|
|
static void TestCompareIntegerBlob()
|
|
{
|
|
BYTE bZero = 0;
|
|
BYTE bFF = 0xFF;
|
|
|
|
BYTE rgbLeadZero1[] = {0x12, 0x34, 0x56, 0x87, 0, 0};
|
|
BYTE rgbLeadZero2[] = {0x12, 0x34, 0x56, 0x87, 0, 0, 0, 0};
|
|
|
|
BYTE rgbLeadFF1[] = {0x12, 0x34, 0x56, 0x87, 0xFF, 0xFF};
|
|
BYTE rgbLeadFF2[] = {0x12, 0x34, 0x56, 0x87};
|
|
|
|
CRYPT_INTEGER_BLOB Int1;
|
|
CRYPT_INTEGER_BLOB Int2;
|
|
|
|
Int1.pbData = &bZero;
|
|
Int1.cbData = sizeof(bZero);
|
|
Int2 = Int1;
|
|
if (!CertCompareIntegerBlob(&Int1, &Int2))
|
|
printf("Failed => Compare of Zero == Zero\n");
|
|
|
|
Int1.pbData = &bFF;
|
|
Int1.cbData = sizeof(bFF);
|
|
Int2 = Int1;
|
|
if (!CertCompareIntegerBlob(&Int1, &Int2))
|
|
printf("Failed => Compare of FF == FF\n");
|
|
|
|
Int1.pbData = &bZero;
|
|
Int1.cbData = sizeof(bZero);
|
|
if (CertCompareIntegerBlob(&Int1, &Int2))
|
|
printf("Failed => Compare of Zero != FF\n");
|
|
|
|
Int1.pbData = rgbLeadZero1;
|
|
Int1.cbData = sizeof(rgbLeadZero1);
|
|
Int2.pbData = rgbLeadZero2;
|
|
Int2.cbData = sizeof(rgbLeadZero2);
|
|
if (!CertCompareIntegerBlob(&Int1, &Int2))
|
|
printf("Failed => Compare of Leading Zeroes\n");
|
|
|
|
Int1.pbData = rgbLeadFF1;
|
|
Int1.cbData = sizeof(rgbLeadFF1);
|
|
Int2.pbData = rgbLeadFF2;
|
|
Int2.cbData = sizeof(rgbLeadFF2);
|
|
if (!CertCompareIntegerBlob(&Int1, &Int2))
|
|
printf("Failed => Compare of Leading FFs\n");
|
|
|
|
Int1.pbData = rgbLeadZero1;
|
|
Int1.cbData = sizeof(rgbLeadZero1);
|
|
if (CertCompareIntegerBlob(&Int1, &Int2))
|
|
printf("Failed => Compare of Leading Zeroes != Leading FFs\n");
|
|
}
|
|
|
|
static BOOL EncodeCrl(BYTE **ppbEncoded, DWORD *pcbEncoded)
|
|
{
|
|
BOOL fResult;
|
|
BYTE *pbNameEncoded = NULL;
|
|
DWORD cbNameEncoded;
|
|
BYTE *pbCrlEncoded = NULL;
|
|
DWORD cbCrlEncoded;
|
|
|
|
DWORD SerialNumber0[2] = {0x12345678, 0x33445566};
|
|
DWORD SerialNumber1[1] = {0x12345678};
|
|
SYSTEMTIME SystemTime;
|
|
|
|
|
|
#define CRL_ATTR_0_0 "attr 0_0 printable"
|
|
#define CRL_ATTR_0_1 "attr 0_1 IA5"
|
|
#define CRL_ATTR_1_0 "attr 1_0 numeric"
|
|
#define CRL_ATTR_1_1 "attr 1_1 octet"
|
|
|
|
CERT_RDN_ATTR rgAttr0[] = {
|
|
"1.2.3.4.5.0.0.0", CERT_RDN_PRINTABLE_STRING,
|
|
strlen(CRL_ATTR_0_0), (BYTE *) CRL_ATTR_0_0,
|
|
"1.2.3.4.5.0.1.1.1", CERT_RDN_IA5_STRING,
|
|
strlen(CRL_ATTR_0_1), (BYTE *) CRL_ATTR_0_1
|
|
};
|
|
CERT_RDN_ATTR rgAttr1[] = {
|
|
"1.2.3.4.5.1.0", CERT_RDN_NUMERIC_STRING,
|
|
strlen(CRL_ATTR_1_0), (BYTE *) CRL_ATTR_1_0,
|
|
"1.2.3.4.5.1.1", CERT_RDN_OCTET_STRING,
|
|
strlen(CRL_ATTR_1_1), (BYTE *) CRL_ATTR_1_1,
|
|
"1.2.3.4.5.2", CERT_RDN_PRINTABLE_STRING,
|
|
0, NULL
|
|
};
|
|
CERT_RDN rgRDN[] = {
|
|
2, rgAttr0,
|
|
3, rgAttr1,
|
|
};
|
|
CERT_NAME_INFO Name = {2, rgRDN};
|
|
|
|
#define CRL_EXT_0 "extension 0 ."
|
|
#define CRL_EXT_1 "extension 1 .."
|
|
#define CRL_EXT_2 "extension 2 ..."
|
|
#define CRL_EXT_3 "extension 3 ...."
|
|
CERT_EXTENSION rgExt[] = {
|
|
"1.14.89990", FALSE, strlen(CRL_EXT_0), (BYTE *) CRL_EXT_0,
|
|
"1.14.89991", TRUE, strlen(CRL_EXT_1), (BYTE *) CRL_EXT_1,
|
|
"1.14.89992", FALSE, strlen(CRL_EXT_2), (BYTE *) CRL_EXT_2,
|
|
"1.14.89993", FALSE, strlen(CRL_EXT_3), (BYTE *) CRL_EXT_3
|
|
};
|
|
CRL_INFO Crl;
|
|
BYTE *pbExt = NULL;
|
|
|
|
if (dwExtLen) {
|
|
DWORD i;
|
|
if (NULL == (pbExt = (BYTE *) TestAlloc(dwExtLen)))
|
|
goto ErrorReturn;
|
|
|
|
for (i = 0; i < dwExtLen; i++)
|
|
pbExt[i] = (BYTE) i;
|
|
|
|
rgExt[3].Value.cbData = dwExtLen;
|
|
rgExt[3].Value.pbData = pbExt;
|
|
}
|
|
|
|
CRL_ENTRY rgCrlEntry[2];
|
|
|
|
TestCompareIntegerBlob();
|
|
|
|
cbNameEncoded = 0;
|
|
CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
X509_NAME,
|
|
&Name,
|
|
NULL, // pbEncoded
|
|
&cbNameEncoded
|
|
);
|
|
if (cbNameEncoded == 0) {
|
|
PrintLastError("EncodeCrl::CryptEncodeObject(cbEncoded == 0)");
|
|
goto ErrorReturn;
|
|
}
|
|
pbNameEncoded = (BYTE *) TestAlloc(cbNameEncoded);
|
|
if (pbNameEncoded == NULL) goto ErrorReturn;
|
|
if (!CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
X509_NAME,
|
|
&Name,
|
|
pbNameEncoded,
|
|
&cbNameEncoded
|
|
)) {
|
|
PrintLastError("EncodeCrl::CryptEncodeObject");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
GetSystemTime(&SystemTime);
|
|
|
|
memset(rgCrlEntry, 0, sizeof(rgCrlEntry));
|
|
rgCrlEntry[0].SerialNumber.pbData = (BYTE *) &SerialNumber0[0];
|
|
rgCrlEntry[0].SerialNumber.cbData = sizeof(SerialNumber0);
|
|
SystemTime.wYear--;
|
|
SystemTimeToFileTime(&SystemTime, &rgCrlEntry[0].RevocationDate);
|
|
rgCrlEntry[0].cExtension = 0;
|
|
rgCrlEntry[0].rgExtension = NULL;
|
|
|
|
rgCrlEntry[1].SerialNumber.pbData = (BYTE *) &SerialNumber1[0];
|
|
rgCrlEntry[1].SerialNumber.cbData = sizeof(SerialNumber1);
|
|
SystemTime.wYear--;
|
|
SystemTimeToFileTime(&SystemTime, &rgCrlEntry[1].RevocationDate);
|
|
rgCrlEntry[1].cExtension = 2;
|
|
rgCrlEntry[1].rgExtension = &rgExt[1];
|
|
|
|
memset(&Crl, 0, sizeof(Crl));
|
|
Crl.dwVersion = CRL_V2;
|
|
Crl.SignatureAlgorithm.pszObjId = "1.2.4.5.898";
|
|
Crl.Issuer.pbData = pbNameEncoded;
|
|
Crl.Issuer.cbData = cbNameEncoded;
|
|
GetSystemTime(&SystemTime);
|
|
SystemTimeToFileTime(&SystemTime, &Crl.ThisUpdate);
|
|
SystemTime.wYear++;
|
|
SystemTimeToFileTime(&SystemTime, &Crl.NextUpdate);
|
|
Crl.cCRLEntry = sizeof(rgCrlEntry) / sizeof(rgCrlEntry[0]);
|
|
Crl.rgCRLEntry = rgCrlEntry;
|
|
Crl.cExtension = sizeof(rgExt) / sizeof(rgExt[0]);
|
|
Crl.rgExtension = rgExt;
|
|
|
|
cbCrlEncoded = 0;
|
|
CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
X509_CERT_CRL_TO_BE_SIGNED,
|
|
&Crl,
|
|
NULL, // pbEncoded
|
|
&cbCrlEncoded
|
|
);
|
|
if (cbCrlEncoded == 0) {
|
|
PrintLastError("EncodeCrl::CryptEncodeObject(cbEncoded == 0)");
|
|
goto ErrorReturn;
|
|
}
|
|
pbCrlEncoded = (BYTE *) TestAlloc(cbCrlEncoded);
|
|
if (pbCrlEncoded == NULL) goto ErrorReturn;
|
|
if (!CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
X509_CERT_CRL_TO_BE_SIGNED,
|
|
&Crl,
|
|
pbCrlEncoded,
|
|
&cbCrlEncoded
|
|
)) {
|
|
PrintLastError("EncodeCrl::CryptEncodeObject");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
if (!EncodeSignedContent(
|
|
pbCrlEncoded,
|
|
cbCrlEncoded,
|
|
ppbEncoded,
|
|
pcbEncoded))
|
|
goto ErrorReturn;
|
|
|
|
fResult = TRUE;
|
|
goto CommonReturn;
|
|
|
|
ErrorReturn:
|
|
*ppbEncoded = NULL;
|
|
*pcbEncoded = 0;
|
|
fResult = FALSE;
|
|
CommonReturn:
|
|
if (pbNameEncoded)
|
|
TestFree(pbNameEncoded);
|
|
if (pbExt)
|
|
TestFree(pbExt);
|
|
if (pbCrlEncoded)
|
|
TestFree(pbCrlEncoded);
|
|
|
|
return fResult;
|
|
}
|
|
|
|
static void PrintCrlEntries(DWORD cEntry, PCRL_ENTRY pEntry)
|
|
{
|
|
DWORD i;
|
|
|
|
for (i = 0; i < cEntry; i++, pEntry++) {
|
|
{
|
|
DWORD cb;
|
|
BYTE *pb;
|
|
printf(" [%d] SerialNumber::", i);
|
|
for (cb = pEntry->SerialNumber.cbData,
|
|
pb = pEntry->SerialNumber.pbData + (cb - 1);
|
|
cb > 0; cb--, pb--) {
|
|
printf(" %02X", *pb);
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
printf(" [%d] RevocationDate:: %s\n", i,
|
|
FileTimeText(&pEntry->RevocationDate));
|
|
|
|
if (pEntry->cExtension == 0)
|
|
printf(" [%d] Extensions:: NONE\n", i);
|
|
else {
|
|
printf(" [%d] Extensions::\n", i);
|
|
PrintExtensions(pEntry->cExtension, pEntry->rgExtension);
|
|
}
|
|
}
|
|
}
|
|
|
|
static BOOL DecodeCrl(BYTE *pbEncoded, DWORD cbEncoded)
|
|
{
|
|
BOOL fResult;
|
|
PCRL_INFO pInfo = NULL;
|
|
DWORD cbInfo;
|
|
LPSTR pszObjId;
|
|
|
|
if (NULL == (pInfo = (PCRL_INFO) TestDecodeObject(
|
|
X509_CERT_CRL_TO_BE_SIGNED,
|
|
pbEncoded,
|
|
cbEncoded,
|
|
&cbInfo
|
|
))) goto ErrorReturn;
|
|
|
|
printf("Version:: %d\n", pInfo->dwVersion);
|
|
|
|
pszObjId = pInfo->SignatureAlgorithm.pszObjId;
|
|
if (pszObjId == NULL)
|
|
pszObjId = "<NULL OBJID>";
|
|
printf("SignatureAlgorithm:: %s\n", pszObjId);
|
|
if (pInfo->SignatureAlgorithm.Parameters.cbData) {
|
|
printf("SignatureAlgorithm.Parameters::\n");
|
|
PrintBytes(" ", pInfo->SignatureAlgorithm.Parameters.pbData,
|
|
pInfo->SignatureAlgorithm.Parameters.cbData);
|
|
}
|
|
|
|
printf("Issuer::\n");
|
|
DecodeName(pInfo->Issuer.pbData, pInfo->Issuer.cbData);
|
|
|
|
printf("ThisUpdate:: %s\n", FileTimeText(&pInfo->ThisUpdate));
|
|
printf("NextUpdate:: %s\n", FileTimeText(&pInfo->NextUpdate));
|
|
|
|
if (pInfo->cExtension == 0)
|
|
printf("Extensions:: NONE\n");
|
|
else {
|
|
printf("Extensions::\n");
|
|
PrintExtensions(pInfo->cExtension, pInfo->rgExtension);
|
|
}
|
|
|
|
if (pInfo->cCRLEntry == 0)
|
|
printf("Entries:: NONE\n");
|
|
else {
|
|
printf("Entries::\n");
|
|
PrintCrlEntries(pInfo->cCRLEntry, pInfo->rgCRLEntry);
|
|
}
|
|
|
|
DecodeSignedContent(pbEncoded, cbEncoded, X509_CERT_CRL_TO_BE_SIGNED,
|
|
cbInfo);
|
|
|
|
fResult = TRUE;
|
|
goto CommonReturn;
|
|
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
CommonReturn:
|
|
if (pInfo)
|
|
TestFree(pInfo);
|
|
return fResult;
|
|
}
|
|
|
|
static BOOL EncodeCertPair(BYTE **ppbEncoded, DWORD *pcbEncoded)
|
|
{
|
|
BOOL fResult;
|
|
BYTE *pbEncoded = NULL;
|
|
DWORD cbEncoded;
|
|
|
|
CERT_PAIR CertPair;
|
|
|
|
memset(&CertPair, 0, sizeof(CertPair));
|
|
if (pszForwardCertFilename)
|
|
ReadDERFromFile(pszForwardCertFilename,
|
|
&CertPair.Forward.pbData, &CertPair.Forward.cbData);
|
|
if (pszReverseCertFilename)
|
|
ReadDERFromFile(pszReverseCertFilename,
|
|
&CertPair.Reverse.pbData, &CertPair.Reverse.cbData);
|
|
|
|
cbEncoded = 0;
|
|
CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
X509_CERT_PAIR,
|
|
&CertPair,
|
|
NULL, // pbEncoded
|
|
&cbEncoded
|
|
);
|
|
if (cbEncoded == 0) {
|
|
PrintLastError("EncodeCertPair::CryptEncodeObject(cbEncoded == 0)");
|
|
goto ErrorReturn;
|
|
}
|
|
pbEncoded = (BYTE *) TestAlloc(cbEncoded);
|
|
if (pbEncoded == NULL) goto ErrorReturn;
|
|
if (!CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
X509_CERT_PAIR,
|
|
&CertPair,
|
|
pbEncoded,
|
|
&cbEncoded
|
|
)) {
|
|
PrintLastError("EncodeCertPair::CryptEncodeObject");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
fResult = TRUE;
|
|
goto CommonReturn;
|
|
|
|
ErrorReturn:
|
|
if (pbEncoded) {
|
|
TestFree(pbEncoded);
|
|
pbEncoded = NULL;
|
|
}
|
|
cbEncoded = 0;
|
|
fResult = FALSE;
|
|
|
|
CommonReturn:
|
|
TestFree(CertPair.Forward.pbData);
|
|
TestFree(CertPair.Reverse.pbData);
|
|
*ppbEncoded = pbEncoded;
|
|
*pcbEncoded = cbEncoded;
|
|
|
|
return fResult;
|
|
}
|
|
|
|
static BOOL DecodeCertPair(BYTE *pbEncoded, DWORD cbEncoded)
|
|
{
|
|
BOOL fResult;
|
|
PCERT_PAIR pInfo = NULL;
|
|
|
|
if (NULL == (pInfo = (PCERT_PAIR) TestDecodeObject(
|
|
X509_CERT_PAIR,
|
|
pbEncoded,
|
|
cbEncoded
|
|
))) goto ErrorReturn;
|
|
|
|
if (pInfo->Forward.cbData) {
|
|
printf("Forward Certificate::\n");
|
|
PrintBytes(" ", pInfo->Forward.pbData, pInfo->Forward.cbData);
|
|
} else
|
|
printf("NO Forward Certificate\n");
|
|
|
|
if (pInfo->Reverse.cbData) {
|
|
printf("Reverse Certificate::\n");
|
|
PrintBytes(" ", pInfo->Reverse.pbData, pInfo->Reverse.cbData);
|
|
} else
|
|
printf("NO Reverse Certificate\n");
|
|
|
|
fResult = TRUE;
|
|
goto CommonReturn;
|
|
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
CommonReturn:
|
|
TestFree(pInfo);
|
|
return fResult;
|
|
}
|