/*++ Copyright (C) 1995-96 Microsoft Corporation Module Name: certify.cxx Abstract: This is the command line tool to manipulate certificates on an executable image. Author: Robert Reichel (robertre) Feb 12, 1996 Revision History: --*/ //#define UNICODE 1 //#define _UNICODE 1 #include #include #include #include // // Private prototypes // LPWIN_CERTIFICATE GetCertFromImage( LPCTSTR ImageName, DWORD Index ); SaveCertificate( LPCTSTR OutputFileName, LPCTSTR ImageName, DWORD CertIndex ); BOOL RemoveCertificateFromImage( LPCTSTR ImageName, DWORD Index ); BOOL AddCertificateToImage( LPCTSTR ImageName, LPCTSTR CertificateName, WORD CertificateType, PDWORD Index ); VOID PrintCertificate( LPWIN_CERTIFICATE Certificate, DWORD Index ); BOOL GetCertHeaderFromImage( IN LPCTSTR ImageName, IN DWORD Index, OUT LPWIN_CERTIFICATE CertificateHeader ); #define TYPE_X509 TEXT("X509") #define TYPE_PKCS7 TEXT("PKCS7") #define TYPE_UNKNOWN TEXT("Unknown") // // Globals // BOOL fVerbose = FALSE; void PrintUsage( VOID ) { fputs("Usage: PESIGMGR [switches] image-name \n" " [-?] display this message\n" " [-l] list the certificates in an image\n" " [-a:] add a certificate file to an image\n" " [-r:] remove certificate from an image\n" " [-s:] used with -r to save the removed certificate\n" " [-t:] used with -a to specify the type of the certificate\n" " where CertType may be X509 or PKCS7 [default is X509]\n", stderr ); exit(-1); } #if 0 PWSTR GetArgAsUnicode( LPSTR s ) { ULONG n; PWSTR ps; n = strlen( s ); ps = (PWSTR)HeapAlloc( GetProcessHeap(), 0, (n + 1) * sizeof( WCHAR ) ); if (ps == NULL) { printf( "Out of memory\n" ); } if (MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, s, n, ps, n ) != (LONG)n ) { printf( "Unable to convert parameter '%s' to Unicode (%u)", (ULONG)s, GetLastError() ); } ps[ n ] = UNICODE_NULL; return ps; } #endif int __cdecl main( int argc, char *argv[], char *envp[] ) { BOOL AFlagSeen = FALSE; BOOL LFlagSeen = FALSE; BOOL RFlagSeen = FALSE; BOOL SFlagSeen = FALSE; BOOL TFlagSeen = FALSE; BOOL Result; DWORD Index; DWORD RFlag_CertIndex; WORD CertificateType = WIN_CERT_TYPE_PKCS_SIGNED_DATA; // default char * CertificateName; char * ImageName = NULL; char * SFlag_CertificateFile; char c, *p; if (argc < 2) { PrintUsage(); } while (--argc) { p = *++argv; if (*p == '/' || *p == '-') { c = *++p; switch (toupper( c )) { case '?': PrintUsage(); break; case 'A': // Add Certificate to image c = *++p; if (c != ':') { PrintUsage(); } else { if (AFlagSeen == TRUE) { PrintUsage(); return( 0 ); } AFlagSeen = TRUE; CertificateName = ++p; } break; case 'V': { fVerbose = TRUE; break; } case 'T': { // // Specify the Type of the certificate // c = *++p; if (c != ':') { PrintUsage(); } else { if (TFlagSeen == TRUE) { PrintUsage(); return( 0 ); } TFlagSeen = TRUE; ++p; if (_stricmp(p, TYPE_X509) == 0) { CertificateType = WIN_CERT_TYPE_X509; if (fVerbose) { printf("Certificate type = X509\n"); } } else { if (_stricmp(p, TYPE_PKCS7) == 0) { CertificateType = WIN_CERT_TYPE_PKCS_SIGNED_DATA; if (fVerbose) { printf("Certificate type = PKCS7\n"); } } else { if (fVerbose) { printf("Unrecognized Certificate type %s\n",p); } PrintUsage(); return (0); } } } break; } case 'L': // List the certificates in an image. { if (LFlagSeen == TRUE) { PrintUsage(); return( 0 ); } LFlagSeen = TRUE; break; } case 'R': // Remove certificate from an image { c = *++p; if (c != ':') { PrintUsage(); } else { if (RFlagSeen == TRUE) { PrintUsage(); return( 0 ); } RFlagSeen = TRUE; // // Save the index // RFlag_CertIndex = atoi(++p); } break; } case 'G': c = *++p; if (c != ':') { PrintUsage(); } else { // Generate a certificate from an image. } break; case 'S': // Save the certificate c = *++p; if (c != ':') { PrintUsage(); } else { if (SFlagSeen == TRUE) { PrintUsage(); return( 0 ); } SFlagSeen = TRUE; // // Save the name of the file to put the cert into. // SFlag_CertificateFile = ++p; } break; default: fprintf( stderr, "CERTIFY: Invalid switch - /%c\n", c ); PrintUsage(); break; } } else { // // Should only be a single image name here // if (ImageName != NULL) { PrintUsage(); return( 0 ); } ImageName = *argv; } } // // Finished processing parameters, let's do the work. // if (ImageName == NULL) { if (fVerbose) { printf("Image name not specified\n"); } PrintUsage(); return(0); } if (LFlagSeen) { int Index = 0; WIN_CERTIFICATE Certificate; if (SFlagSeen || RFlagSeen || AFlagSeen) { PrintUsage(); return(0); } do { Result = GetCertHeaderFromImage( ImageName, Index, &Certificate ); if (Result) { PrintCertificate( &Certificate, Index ); } Index++; } while ( Result ); return( 1 ); } if (AFlagSeen) { // // 'A' is not used in conjunction with R or S // if (SFlagSeen || RFlagSeen) { PrintUsage(); return( 0 ); } Result = AddCertificateToImage( ImageName, CertificateName, CertificateType, &Index ); if (Result) { if (fVerbose){ printf("Certificate %d added\n",Index); } return( 1 ); } else { if (fVerbose) { printf("Unable to add Certificate to %s, error = %d\n",ImageName,GetLastError()); } return( 0 ); } } if (RFlagSeen) { if (!SFlagSeen) { if (fVerbose) { fputs("-R requires -S\n",stderr); } PrintUsage(); return(0); } // // Make sure we can save the certificate data before // we remove it from the image // Result = SaveCertificate( SFlag_CertificateFile, ImageName, RFlag_CertIndex ); if (!Result) { if (fVerbose) { printf("Unable to save certificate to file %s, error = %d\n",SFlag_CertificateFile,GetLastError()); } return(0); } // // Now that the certificate is safe, remove it from the image // Result = RemoveCertificateFromImage( ImageName, RFlag_CertIndex ); if (!Result) { if (fVerbose) { printf("Unable to remove certificate, error = %d\n",GetLastError()); } return(0); } } if (SFlagSeen && !RFlagSeen) { PrintUsage(); return( 0 ); } return 0; } VOID PrintCertificate( LPWIN_CERTIFICATE Certificate, DWORD Index ) { char * CertType; switch (Certificate->wCertificateType) { case WIN_CERT_TYPE_X509: { CertType = TYPE_X509; break; } case WIN_CERT_TYPE_PKCS_SIGNED_DATA: { CertType = TYPE_PKCS7; break; } default: { CertType = TYPE_UNKNOWN; break; } } printf("\nCertificate %3d Revision %1d Type %8s",Index,Certificate->wRevision, CertType); return; } BOOL AddCertificateToImage( IN LPCTSTR ImageName, IN LPCTSTR CertificateName, IN WORD CertificateType, OUT PDWORD Index ) /*++ Routine Description: Adds a certificate to an image, and returns its index. Arguments: ImageName - Provides the full name and path to the image to be modified. CertificateName - Provides the full name and path to a file containing the certificate to be added to the image. CertificateType - Provides the type of the certificate being added. This type will be placed in the dwType field of the resulting WIN_CERTIFICATE structure. Index - Returns the index of the certificate after it is placed in the image. Return Value: TRUE on success, FALSE on failure. More information is available via GetLastError(). --*/ { HANDLE CertificateHandle; DWORD CertificateFileSize; DWORD CertificateSize; LPWIN_CERTIFICATE Certificate = NULL; BOOL Result = FALSE; HANDLE ImageHandle; DWORD BytesRead; // // Attempt to open the certificate file // if ((CertificateHandle = CreateFile(CertificateName, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) { if (fVerbose) { printf("Unable to open %s, error = %d\n",CertificateName,GetLastError()); } goto ErrorReturn; } // // Read the certificate data into memory // CertificateFileSize = GetFileSize( CertificateHandle, NULL ); CertificateSize = CertificateFileSize + (sizeof( WIN_CERTIFICATE ) - sizeof( BYTE )); // // Hack to make certs 8 byte aligned // // CertificateSize += (8 - (CertificateSize % 8)); Certificate = (LPWIN_CERTIFICATE)malloc( CertificateSize ); if (NULL == Certificate) { if (fVerbose) { printf("malloc failed\n"); } goto ErrorReturn; } Certificate->dwLength = CertificateSize; Certificate->wRevision = WIN_CERT_REVISION_1_0; Certificate->wCertificateType = CertificateType; Result = ReadFile( CertificateHandle, &Certificate->bCertificate, CertificateFileSize, &BytesRead, NULL // Overlapped ); if (!Result) { if (fVerbose) { printf("Unable to read Certificate file, error = %d\n",GetLastError()); } goto ErrorReturn; } ImageHandle = CreateFile( ImageName, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (ImageHandle == INVALID_HANDLE_VALUE) { if (fVerbose) { printf("Unable to open image file %s, error = %d\n",ImageName,GetLastError()); } goto ErrorReturn; } Result = ImageAddCertificate( ImageHandle, Certificate, Index ); if (!Result) { if (fVerbose) { printf("ImageAddCertificate failed, error = %d\n",GetLastError()); } goto ErrorReturn; } CommonReturn: if (Certificate) free(Certificate); return( Result ); ErrorReturn: Result = FALSE; goto CommonReturn; } BOOL GetCertHeaderFromImage( IN LPCTSTR ImageName, IN DWORD Index, OUT LPWIN_CERTIFICATE CertificateHeader ) { HANDLE ImageHandle; BOOL Result; ImageHandle = CreateFile( ImageName, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (ImageHandle == INVALID_HANDLE_VALUE) { if (fVerbose) { printf("Unable to open image file %s\n",ImageName); } return( FALSE ); } Result = ImageGetCertificateHeader( ImageHandle, Index, CertificateHeader ); CloseHandle( ImageHandle ); if (!Result) { if (fVerbose) { printf("\nUnable to retrieve certificate header from %s, index=%d, error = %d\n",ImageName,Index,GetLastError()); } return( FALSE ); } return( TRUE ); } LPWIN_CERTIFICATE GetCertFromImage( IN LPCTSTR ImageName, IN DWORD Index ) /*++ Routine Description: Returns a copy of the specified certificate. Arguments: ImageName - Provides the full path to the image file containing the certificate. Index - Provides the index of the desired certificate in the image. Return Value: NULL on failure. On Success, returns a pointer to a filled in WIN_CERTIFICATE structure, which may be freed by called free(). --*/ { HANDLE ImageHandle; LPWIN_CERTIFICATE Certificate; DWORD RequiredLength = 0; BOOL Result; ImageHandle = CreateFile( ImageName, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (ImageHandle == INVALID_HANDLE_VALUE) { if (fVerbose) { printf("Unable to open image file %s\n",ImageName); } return( NULL ); } Result = ImageGetCertificateData( ImageHandle, Index, NULL, &RequiredLength ); if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { if (fVerbose) { printf("Unable to retrieve certificate data from %s, error = %d\n",ImageName,GetLastError()); } return(NULL); } Certificate = (LPWIN_CERTIFICATE) malloc( RequiredLength ); if (Certificate == NULL) { if (fVerbose) { printf("Out of memory in GetCertFromImage\n"); } return( NULL ); } Result = ImageGetCertificateData( ImageHandle, Index, Certificate, &RequiredLength ); CloseHandle( ImageHandle ); if (!Result) { if (fVerbose) { printf("Unable to retrieve certificate from %s, error = %d\n",ImageName,GetLastError()); } return( NULL ); } return( Certificate ); } BOOL RemoveCertificateFromImage( LPCTSTR ImageName, DWORD Index ) { HANDLE ImageHandle; BOOL Result; if (fVerbose) { printf("Removing certificate index %d from %s\n",Index,ImageName); } ImageHandle = CreateFile( ImageName, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (ImageHandle == INVALID_HANDLE_VALUE) { printf("Unable to open image file %s\n",ImageName); return( FALSE ); } Result = ImageRemoveCertificate( ImageHandle, Index ); if (!Result) { printf("Unable to remove certificate from %s, error = %d\n",ImageName,GetLastError()); return( FALSE ); } CloseHandle( ImageHandle ); return( TRUE ); } BOOL SaveCertificate( LPCTSTR OutputFileName, LPCTSTR ImageName, DWORD CertIndex ) { DWORD Length; BOOL Result; DWORD BytesWritten = 0; LPWIN_CERTIFICATE Certificate; HANDLE CertificateHandle; Certificate = GetCertFromImage( ImageName, CertIndex ); if (Certificate == NULL) { if (fVerbose) { printf("Unable to retrieve certificate from %s, error = %d\n",ImageName,GetLastError()); } return( FALSE ); } Length = Certificate->dwLength - sizeof( WIN_CERTIFICATE ) + sizeof( BYTE ); // // Attempt to open the certificate file // if ((CertificateHandle = CreateFile(OutputFileName, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) { printf("Unable to create %s, error = %d\n",OutputFileName,GetLastError()); return( FALSE ); } Result = WriteFile( CertificateHandle, &Certificate->bCertificate, Length, &BytesWritten, NULL // Overlapped ); if (!Result) { printf("Unable to save certificate to file %s, error = %d\n",OutputFileName,GetLastError()); return( FALSE ); } CloseHandle( CertificateHandle ); free( Certificate ); return( TRUE ); }