417 lines
12 KiB
C++
417 lines
12 KiB
C++
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
//
|
||
|
// Copyright (C) Microsoft Corporation, 1999 - 1999
|
||
|
//
|
||
|
// File: dumpcert.cxx
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
#include "precomp.hxx"
|
||
|
#include <wincrypt.h>
|
||
|
#include <rpcssl.h>
|
||
|
|
||
|
#if 0
|
||
|
|
||
|
stuff clobbered by Unicode -> ANSI port:
|
||
|
|
||
|
wchar_t -> char
|
||
|
WCHAR -> char
|
||
|
L"" -> ""
|
||
|
%S -> %s
|
||
|
W suffix-> A suffix
|
||
|
wcscmp -> strcmp
|
||
|
wmain -> main
|
||
|
LPWSTR -> LPSTR
|
||
|
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#define ByteSwapShort(Value) \
|
||
|
Value = ( (((Value) & 0x00FF) << 8) \
|
||
|
| (((Value) & 0xFF00) >> 8))
|
||
|
|
||
|
#define INITIAL_NAME_LENGTH 100
|
||
|
|
||
|
#define MSSTD_PREFIX_LENGTH 6
|
||
|
const char MSSTD_PREFIX[] = "msstd:";
|
||
|
|
||
|
#define FULLPATH_PREFIX_LENGTH 8
|
||
|
const char FULLPATH_PREFIX[] = "fullsic:";
|
||
|
|
||
|
//------------------------------------------------------------------------
|
||
|
|
||
|
void DumpCertInfo( PCERT_INFO Info );
|
||
|
void RecordErrorAndExit( char * Action, unsigned long Error );
|
||
|
|
||
|
extern "C"
|
||
|
{
|
||
|
int __cdecl
|
||
|
main( int argc,
|
||
|
char * argv[],
|
||
|
char * envp[]
|
||
|
);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
int __cdecl
|
||
|
main( int argc,
|
||
|
char * argv[],
|
||
|
char * envp[]
|
||
|
)
|
||
|
{
|
||
|
HCERTSTORE Store;
|
||
|
PCCERT_CONTEXT Context = 0;
|
||
|
unsigned Criterion = CERT_FIND_ANY;
|
||
|
void * SearchData = 0;
|
||
|
char * StoreName = "My";
|
||
|
int i;
|
||
|
char * MatchString = 0;
|
||
|
BOOL fMatch = FALSE;
|
||
|
BOOL fOutput = FALSE;
|
||
|
unsigned long OutputFlags = 0;
|
||
|
DWORD StoreFlags = CERT_SYSTEM_STORE_CURRENT_USER;
|
||
|
|
||
|
for (i=1; i < argc; ++i)
|
||
|
{
|
||
|
if (0 == strcmp(argv[i], "-subject"))
|
||
|
{
|
||
|
Criterion = CERT_FIND_SUBJECT_STR_W;
|
||
|
++i;
|
||
|
if (i >= argc)
|
||
|
{
|
||
|
printf("-subject must be followed by a subject name or substring\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
SearchData = argv[i];
|
||
|
}
|
||
|
else if (0 == strcmp(argv[i], "-issuer"))
|
||
|
{
|
||
|
Criterion = CERT_FIND_ISSUER_STR_W;
|
||
|
++i;
|
||
|
if (i >= argc)
|
||
|
{
|
||
|
printf("-issuer must be followed by an issuer name or substring\n");
|
||
|
return 1;
|
||
|
}
|
||
|
SearchData = argv[i];
|
||
|
}
|
||
|
else if (0 == strcmp(argv[i], "-store"))
|
||
|
{
|
||
|
++i;
|
||
|
if (i >= argc)
|
||
|
{
|
||
|
printf("-store must be followed by a store name, such as 'Root' or 'My'\n");
|
||
|
return 1;
|
||
|
}
|
||
|
StoreName = argv[i];
|
||
|
}
|
||
|
else if (0 == strcmp(argv[i], "-location"))
|
||
|
{
|
||
|
++i;
|
||
|
|
||
|
if (i >= argc)
|
||
|
{
|
||
|
printf("-location must be followed by 'USER:' or by 'HKLM'\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
if (0 == strcmp(argv[i], "USER:"))
|
||
|
{
|
||
|
StoreFlags = CERT_SYSTEM_STORE_CURRENT_USER;
|
||
|
}
|
||
|
else if (0 == strcmp(argv[i], "HKLM"))
|
||
|
{
|
||
|
StoreFlags = CERT_SYSTEM_STORE_LOCAL_MACHINE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printf("-location must be followed by 'USER:' or by 'HKLM'\n");
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
else if (0 == strcmp(argv[i], "-output"))
|
||
|
{
|
||
|
fOutput = TRUE;
|
||
|
++i;
|
||
|
|
||
|
if(i >= argc)
|
||
|
{
|
||
|
printf("-output must be followed by 'msstd' or by 'fullsic'\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
if (0 == strcmp(argv[i], "fullsic"))
|
||
|
{
|
||
|
OutputFlags = RPC_C_FULL_CERT_CHAIN;
|
||
|
}
|
||
|
else if (0 == strcmp(argv[i], "msstd"))
|
||
|
{
|
||
|
OutputFlags = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printf("-output must be followed by 'msstd' or by 'fullsic'\n");
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
else if (0 == strcmp(argv[i], "-match"))
|
||
|
{
|
||
|
fMatch = TRUE;
|
||
|
|
||
|
++i;
|
||
|
if(i >= argc)
|
||
|
{
|
||
|
printf("-match must be followed by '@filename', listing the name of the file containing the match string\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
if (argv[i][0] == '@')
|
||
|
{
|
||
|
DWORD BytesRead;
|
||
|
HANDLE hMatchFile;
|
||
|
|
||
|
hMatchFile = CreateFileA( argv[i]+1,
|
||
|
GENERIC_READ,
|
||
|
FILE_SHARE_READ,
|
||
|
0, // no security
|
||
|
OPEN_EXISTING, // must already exist
|
||
|
FILE_ATTRIBUTE_NORMAL,
|
||
|
NULL // no template file
|
||
|
);
|
||
|
|
||
|
if (hMatchFile == ULongToHandle(0xffffffff))
|
||
|
{
|
||
|
printf("can't open file %s\n", argv[i]+1);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
DWORD Size = GetFileSize( hMatchFile, 0);
|
||
|
if (Size == 0xffffffff)
|
||
|
{
|
||
|
printf("GetFileSize failed with 0x%x\n", GetLastError());
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
if (Size % 2)
|
||
|
{
|
||
|
printf("the match-string file must be in Unicode.\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
MatchString = new char[ Size/sizeof(char) + sizeof(char) ];
|
||
|
if (!MatchString)
|
||
|
{
|
||
|
printf("can't allocate memory\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
if (!ReadFile( hMatchFile,
|
||
|
MatchString,
|
||
|
Size,
|
||
|
&BytesRead,
|
||
|
0 // not overlapped
|
||
|
)
|
||
|
|| BytesRead != Size)
|
||
|
{
|
||
|
printf("can't read file data: 0x%x\n", GetLastError());
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
MatchString[ Size/sizeof(char) ] = 0;
|
||
|
|
||
|
if (MatchString[0] == 0xfeff)
|
||
|
{
|
||
|
++MatchString;
|
||
|
}
|
||
|
else if (MatchString[0] == 0xfffe)
|
||
|
{
|
||
|
char * pc;
|
||
|
|
||
|
for (pc = MatchString; *pc; ++pc)
|
||
|
{
|
||
|
ByteSwapShort(*pc);
|
||
|
}
|
||
|
|
||
|
++MatchString;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
MatchString = argv[i];
|
||
|
}
|
||
|
|
||
|
printf("string to match is '%s'\n", MatchString);
|
||
|
}
|
||
|
else if (0 == strcmp(argv[i], "-?") ||
|
||
|
0 == strcmp(argv[i], "-help"))
|
||
|
{
|
||
|
printf("usage:\n"
|
||
|
" dumpcert \n"
|
||
|
" [-subject subject-substring]\n"
|
||
|
" [-issuer issuer-substring]\n"
|
||
|
" [-store store-name]\n"
|
||
|
" [-output ('fullsic' | 'msstd')\n"
|
||
|
" [-location ('HKLM' | 'USER:')\n"
|
||
|
" [-match @filename]\n"
|
||
|
);
|
||
|
return 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printf("unknown option '%s'\n", argv[i]);
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Store = CertOpenStore( CERT_STORE_PROV_SYSTEM_A,
|
||
|
0,
|
||
|
0,
|
||
|
StoreFlags,
|
||
|
StoreName
|
||
|
);
|
||
|
|
||
|
if (!Store)
|
||
|
{
|
||
|
RecordErrorAndExit("opening the store", GetLastError());
|
||
|
}
|
||
|
|
||
|
for(;;)
|
||
|
{
|
||
|
Context = CertFindCertificateInStore( Store,
|
||
|
X509_ASN_ENCODING,
|
||
|
0,
|
||
|
Criterion,
|
||
|
SearchData,
|
||
|
Context
|
||
|
);
|
||
|
if (!Context)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
DumpCertInfo( Context->pCertInfo );
|
||
|
if (fOutput)
|
||
|
{
|
||
|
unsigned char * OutputBuffer = 0;
|
||
|
DWORD Status = RpcCertGeneratePrincipalNameA( Context, OutputFlags, &OutputBuffer );
|
||
|
if (Status)
|
||
|
{
|
||
|
printf("GeneratePrincName returned %d = 0x%x\n", Status, Status);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printf(" generated name = '%s'\n", OutputBuffer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (fMatch)
|
||
|
{
|
||
|
printf("matching is not implemented because RpcCertMatchPrincipalName is not exported\n");
|
||
|
#if 0
|
||
|
DWORD Status = RpcCertMatchPrincipalName( Context, MatchString );
|
||
|
if (Status)
|
||
|
{
|
||
|
printf("MatchPrincipalName returned %d = 0x%x\n", Status, Status);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printf("The names matched.\n");
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (GetLastError() != CRYPT_E_NOT_FOUND)
|
||
|
{
|
||
|
RecordErrorAndExit("getting certificates", GetLastError());
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void DumpCertInfo( PCERT_INFO Info )
|
||
|
{
|
||
|
SYSTEMTIME NotBeforeTime;
|
||
|
SYSTEMTIME NotAfterTime;
|
||
|
char SubjectName[1000];
|
||
|
char IssuerName[1000];
|
||
|
|
||
|
if (!FileTimeToSystemTime( &Info->NotBefore, &NotBeforeTime ))
|
||
|
{
|
||
|
RecordErrorAndExit("translating not-before time", GetLastError());
|
||
|
}
|
||
|
|
||
|
if (!FileTimeToSystemTime( &Info->NotAfter, &NotAfterTime ))
|
||
|
{
|
||
|
RecordErrorAndExit("translating not-after time", GetLastError());
|
||
|
}
|
||
|
|
||
|
if (!CertNameToStrA( X509_ASN_ENCODING,
|
||
|
&Info->Subject,
|
||
|
CERT_X500_NAME_STR | CERT_NAME_STR_SEMICOLON_FLAG,
|
||
|
SubjectName,
|
||
|
sizeof(SubjectName)
|
||
|
))
|
||
|
{
|
||
|
RecordErrorAndExit("unpacking subject name", GetLastError());
|
||
|
}
|
||
|
|
||
|
if (!CertNameToStrA( X509_ASN_ENCODING,
|
||
|
&Info->Issuer,
|
||
|
CERT_X500_NAME_STR | CERT_NAME_STR_SEMICOLON_FLAG,
|
||
|
IssuerName,
|
||
|
sizeof(IssuerName)
|
||
|
))
|
||
|
{
|
||
|
RecordErrorAndExit("unpacking issuer name", GetLastError());
|
||
|
}
|
||
|
|
||
|
printf("----------------------------------------------------\n\n");
|
||
|
|
||
|
printf(" subject: %s\n", SubjectName);
|
||
|
printf(" issuer: %s\n", IssuerName);
|
||
|
printf(" version %d\n", Info->dwVersion );
|
||
|
printf(" valid from %02d:%02d:%02d on %d-%02d-%d\n",
|
||
|
NotBeforeTime.wHour,
|
||
|
NotBeforeTime.wMinute,
|
||
|
NotBeforeTime.wSecond,
|
||
|
NotBeforeTime.wMonth,
|
||
|
NotBeforeTime.wDay,
|
||
|
NotBeforeTime.wYear
|
||
|
);
|
||
|
|
||
|
printf(" to %02d:%02d:%02d on %d-%02d-%d\n",
|
||
|
NotAfterTime.wHour,
|
||
|
NotAfterTime.wMinute,
|
||
|
NotAfterTime.wSecond,
|
||
|
NotAfterTime.wMonth,
|
||
|
NotAfterTime.wDay,
|
||
|
NotAfterTime.wYear
|
||
|
);
|
||
|
}
|
||
|
|
||
|
|
||
|
void RecordErrorAndExit( char * Action, unsigned long Error )
|
||
|
{
|
||
|
char * lpMsgBuf = "";
|
||
|
|
||
|
FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
||
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||
|
NULL,
|
||
|
Error,
|
||
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
||
|
(LPSTR) &lpMsgBuf,
|
||
|
0,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
printf("error while %s: %x (%d) \"%s\"", Action, Error, Error, lpMsgBuf);
|
||
|
}
|
||
|
|
||
|
|