//+------------------------------------------------------------------------- // Microsoft Windows // // Copyright (C) Microsoft Corporation, 2001 - 2001 // // File: mincrypt.h // // Contents: Minimal Cryptographic API Prototypes and Definitions // // Contains cryptographic functions to verify PKCS #7 Signed Data // messages, X.509 certificate chains, Authenticode signed // files and file hashes in system catalogs. // // These APIs rely on the APIs defined in minasn1.h for doing // the low level ASN.1 parsing. // // These APIs are implemented to be self contained and to // allow for code obfuscation. These APIs will be included // in such applications as, DRM or licensing verification. // // If the file name or file handle option is selected, // the following APIs will need to call the kernel32.dll APIs // to open, map and unmap files: // MinCryptHashFile // MinCryptVerifySignedFile // The following API will need to call kernel32.dll and // wintrust.dll APIs to find, open, map and unmap files: // MinCryptVerifyHashInSystemCatalogs // Except for the calls in the above APIs, // no calls to APIs in other DLLs. // // Additionally, since these APIs have been pared down // from their wincrypt.h and crypt32.dll counterparts they are // a good candidate for applications with minimal memory and CPU // resources. // // APIs: // MinCryptDecodeHashAlgorithmIdentifier // MinCryptHashMemory // MinCryptVerifySignedHash // MinCryptVerifyCertificate // MinCryptVerifySignedData // MinCryptHashFile // MinCryptVerifySignedFile // MinCryptVerifyHashInSystemCatalogs // //---------------------------------------------------------------------------- #ifndef __MINCRYPT_H__ #define __MINCRYPT_H__ #if defined (_MSC_VER) #if ( _MSC_VER >= 800 ) #if _MSC_VER >= 1200 #pragma warning(push) #endif #pragma warning(disable:4201) /* Nameless struct/union */ #endif #if (_MSC_VER > 1020) #pragma once #endif #endif #include #include #ifdef __cplusplus extern "C" { #endif #define MINCRYPT_MAX_HASH_LEN 20 #define MINCRYPT_SHA1_HASH_LEN 20 #define MINCRYPT_MD5_HASH_LEN 16 #define MINCRYPT_MD2_HASH_LEN 16 //+------------------------------------------------------------------------- // Decodes an ASN.1 encoded Algorithm Identifier and converts to // a CAPI Hash AlgID, such as, CALG_SHA1 or CALG_MD5. // // Returns 0 if there isn't a CAPI AlgId corresponding to the Algorithm // Identifier. // // Only CALG_SHA1, CALG_MD5 and CALG_MD2 are supported. //-------------------------------------------------------------------------- ALG_ID WINAPI MinCryptDecodeHashAlgorithmIdentifier( IN PCRYPT_DER_BLOB pAlgIdValueBlob ); //+------------------------------------------------------------------------- // Hashes one or more memory blobs according to the Hash ALG_ID. // // rgbHash is updated with the resultant hash. *pcbHash is updated with // the length associated with the hash algorithm. // // If the function succeeds, the return value is ERROR_SUCCESS. Otherwise, // a nonzero error code is returned. // // Only CALG_SHA1, CALG_MD5 and CALG_MD2 are supported. //-------------------------------------------------------------------------- LONG WINAPI MinCryptHashMemory( IN ALG_ID HashAlgId, IN DWORD cBlob, IN PCRYPT_DER_BLOB rgBlob, OUT BYTE rgbHash[MINCRYPT_MAX_HASH_LEN], OUT DWORD *pcbHash ); //+------------------------------------------------------------------------- // Verifies a signed hash. // // The ASN.1 encoded Public Key Info is parsed and used to decrypt the // signed hash. The decrypted signed hash is compared with the input // hash. // // If the signed hash was successfully verified, ERROR_SUCCESS is returned. // Otherwise, a nonzero error code is returned. // // Only RSA signatures are supported. // // Only MD2, MD5 and SHA1 hashes are supported. //-------------------------------------------------------------------------- LONG WINAPI MinCryptVerifySignedHash( IN ALG_ID HashAlgId, IN BYTE *pbHash, IN DWORD cbHash, IN PCRYPT_DER_BLOB pSignedHashContentBlob, IN PCRYPT_DER_BLOB pPubKeyInfoValueBlob ); //+------------------------------------------------------------------------- // Verifies a previously parsed X.509 Certificate. // // Assumes the ASN.1 encoded X.509 certificate was parsed via // MinAsn1ParseCertificate() and the set of potential issuer certificates // were parsed via one or more of: // - MinAsn1ParseCertificate() // - MinAsn1ParseSignedDataCertificates() // - MinAsn1ExtractParsedCertificatesFromSignedData() // // Iteratively finds the issuer certificate via its encoded name. The // public key in the issuer certificate is used to verify the subject // certificate's signature. This is repeated until finding a self signed // certificate or a baked in root identified by its encoded name. // For a self signed certificate, compares against the baked in root // public keys. // // If the certificate and its issuers were successfully verified to a // baked in root, ERROR_SUCCESS is returned. Otherwise, a nonzero error // code is returned. //-------------------------------------------------------------------------- LONG WINAPI MinCryptVerifyCertificate( IN CRYPT_DER_BLOB rgSubjectCertBlob[MINASN1_CERT_BLOB_CNT], IN DWORD cIssuerCert, IN CRYPT_DER_BLOB rgrgIssuerCertBlob[][MINASN1_CERT_BLOB_CNT] ); //+------------------------------------------------------------------------- // Function: MinCryptVerifySignedData // // Verifies an ASN.1 encoded PKCS #7 Signed Data Message. // // Assumes the PKCS #7 message is definite length encoded. // Assumes PKCS #7 version 1.5, ie, not the newer CMS version. // We only look at the first signer. // // The Signed Data message is parsed. Its signature is verified. Its // signer certificate chain is verified to a baked in root public key. // // If the Signed Data was successfully verified, ERROR_SUCCESS is returned. // Otherwise, a nonzero error code is returned. // // Here are some interesting errors that can be returned: // CRYPT_E_BAD_MSG - unable to ASN1 parse as a signed data message // ERROR_NO_DATA - the content is empty // CRYPT_E_NO_SIGNER - not signed or unable to find signer cert // CRYPT_E_UNKNOWN_ALGO- unknown MD5 or SHA1 ASN.1 algorithm identifier // CERT_E_UNTRUSTEDROOT- the signer chain's root wasn't baked in // CERT_E_CHAINING - unable to build signer chain to a root // CRYPT_E_AUTH_ATTR_MISSING - missing digest authenticated attribute // CRYPT_E_HASH_VALUE - content hash != authenticated digest attribute // NTE_BAD_ALGID - unsupported hash or public key algorithm // NTE_BAD_PUBLIC_KEY - not a valid RSA public key // NTE_BAD_SIGNATURE - bad PKCS #7 or signer chain signature // // The rgVerSignedDataBlob[] is updated with pointer to and length of the // following fields in the encoded PKCS #7 message. //-------------------------------------------------------------------------- // Content Object Identifier content bytes (OID) #define MINCRYPT_VER_SIGNED_DATA_CONTENT_OID_IDX 0 // Content data content bytes excluding "[0] EXPLICIT" tag // (OPTIONAL MinAsn1ParseCTL, MinAsn1ParseIndirectData) #define MINCRYPT_VER_SIGNED_DATA_CONTENT_DATA_IDX 1 // Signer certificate's encoded bytes (MinAsn1ParseCertificate) #define MINCRYPT_VER_SIGNED_DATA_SIGNER_CERT_IDX 2 // Authenticated attributes value bytes including "[0] IMPLICIT" tag // (OPTIONAL, MinAsn1ParseAttributes) #define MINCRYPT_VER_SIGNED_DATA_AUTH_ATTRS_IDX 3 // Unauthenticated attributes value bytes including "[1] IMPLICIT" tag // (OPTIONAL, MinAsn1ParseAttributes) #define MINCRYPT_VER_SIGNED_DATA_UNAUTH_ATTRS_IDX 4 #define MINCRYPT_VER_SIGNED_DATA_BLOB_CNT 5 LONG WINAPI MinCryptVerifySignedData( IN const BYTE *pbEncoded, IN DWORD cbEncoded, OUT CRYPT_DER_BLOB rgVerSignedDataBlob[MINCRYPT_VER_SIGNED_DATA_BLOB_CNT] ); //+------------------------------------------------------------------------- // File Type Definitions // // Specifies the type of the "const VOID *pvFile" parameter //-------------------------------------------------------------------------- // pvFile - LPCWSTR pwszFilename #define MINCRYPT_FILE_NAME 1 // pvFile - HANDLE hFile #define MINCRYPT_FILE_HANDLE 2 // pvFile - PCRYPT_DATA_BLOB pFileBlob #define MINCRYPT_FILE_BLOB 3 //+------------------------------------------------------------------------- // Hashes the file according to the Hash ALG_ID. // // According to dwFileType, pvFile can be a pwszFilename, hFile or pFileBlob. // Only requires READ access. // // dwFileType: // MINCRYPT_FILE_NAME : pvFile - LPCWSTR pwszFilename // MINCRYPT_FILE_HANDLE : pvFile - HANDLE hFile // MINCRYPT_FILE_BLOB : pvFile - PCRYPT_DATA_BLOB pFileBlob // // rgbHash is updated with the resultant hash. *pcbHash is updated with // the length associated with the hash algorithm. // // If the function succeeds, the return value is ERROR_SUCCESS. Otherwise, // a nonzero error code is returned. // // Only CALG_SHA1 and CALG_MD5 are supported. // // If a NT PE 32 bit file format, hashed according to imagehlp rules, ie, skip // section containing potential signature, ... . Otherwise, the entire file // is hashed. //-------------------------------------------------------------------------- LONG WINAPI MinCryptHashFile( IN DWORD dwFileType, IN const VOID *pvFile, IN ALG_ID HashAlgId, OUT BYTE rgbHash[MINCRYPT_MAX_HASH_LEN], OUT DWORD *pcbHash ); //+------------------------------------------------------------------------- // Verifies a previously signed file. // // According to dwFileType, pvFile can be a pwszFilename, hFile or pFileBlob. // Only requires READ access. // // dwFileType: // MINCRYPT_FILE_NAME : pvFile - LPCWSTR pwszFilename // MINCRYPT_FILE_HANDLE : pvFile - HANDLE hFile // MINCRYPT_FILE_BLOB : pvFile - PCRYPT_DATA_BLOB pFileBlob // // Checks if the file has an embedded PKCS #7 Signed Data message containing // Indirect Data. The PKCS #7 is verified via MinCryptVerifySignedData(). // The Indirect Data is parsed via MinAsn1ParseIndirectData() to get the // HashAlgId and the file hash. MinCryptHashFile() is called to hash the // file. The returned hash is compared against the Indirect Data's hash. // // The caller can request one or more signer authenticated attribute values // to be returned. The still encoded values are returned in the // caller allocated memory. The beginning of this returned memory will // be set to an array of attribute value blobs pointing to these // encoded values (CRYPT_DER_BLOB rgAttrBlob[cAttrOID]). // For performance reasons, the caller should make every attempt to allow // for a single pass call. The necessary memory size is: // (cAttrOID * sizeof(CRYPT_DER_BLOB)) + // total length of encoded attribute values. // // *pcbAttr will be updated with the number of bytes required to contain // the attribute blobs and values. If the input memory is insufficient, // ERROR_INSUFFICIENT_BUFFER will be returned if no other error. // // For a multi-valued attribute, only the first value is returned. // // If the function succeeds, the return value is ERROR_SUCCESS. Otherwise, // a nonzero error code is returned. // // Only NT, PE 32 bit file formats are supported. //-------------------------------------------------------------------------- LONG WINAPI MinCryptVerifySignedFile( IN DWORD dwFileType, IN const VOID *pvFile, IN OPTIONAL DWORD cAttrOID, IN OPTIONAL CRYPT_DER_BLOB rgAttrEncodedOIDBlob[], // CRYPT_DER_BLOB rgAttrBlob[cAttrOID] header is at beginning // with the bytes pointed to immediately following OUT OPTIONAL CRYPT_DER_BLOB *rgAttrValueBlob, IN OUT OPTIONAL DWORD *pcbAttr ); //+------------------------------------------------------------------------- // Verifies the hashes in the system catalogs. // // Iterates through the hashes and attempts to find the system catalog // containing it. If found, the system catalog file is verified as a // PKCS #7 Signed Data message with its signer cert verified up to a baked // in root. // // The following mscat32.dll APIs are called to find the system catalog file: // CryptCATAdminAcquireContext // CryptCATAdminReleaseContext // CryptCATAdminEnumCatalogFromHash // CryptCATAdminReleaseCatalogContext // CryptCATCatalogInfoFromContext // // If the hash was successfully verified, rglErr[] is set to ERROR_SUCCESS. // Otherwise, rglErr[] is set to a nonzero error code. // // The caller can request one or more catalog subject attribute, // extension or signer authenticated attribute values to be returned for // each hash. The still encoded values are returned in the // caller allocated memory. The beginning of this returned memory will // be set to a 2 dimensional array of attribute value blobs pointing to these // encoded values (CRYPT_DER_BLOB rgrgAttrValueBlob[cHash][cAttrOID]). // For performance reasons, the caller should make every attempt to allow // for a single pass call. The necessary memory size is: // (cHash * cAttrOID * sizeof(CRYPT_DER_BLOB)) + // total length of encoded attribute values. // // *pcbAttr will be updated with the number of bytes required to contain // the attribute blobs and values. If the input memory is insufficient, // ERROR_INSUFFICIENT_BUFFER will be returned if no other error. // // For a multi-valued attribute, only the first value is returned. // // If the function succeeds, the return value is ERROR_SUCCESS. This may // be returned for unsuccessful rglErr[] values. Otherwise, // a nonzero error code is returned. //-------------------------------------------------------------------------- LONG WINAPI MinCryptVerifyHashInSystemCatalogs( IN ALG_ID HashAlgId, IN DWORD cHash, IN CRYPT_HASH_BLOB rgHashBlob[], OUT LONG rglErr[], IN OPTIONAL DWORD cAttrOID, IN OPTIONAL CRYPT_DER_BLOB rgAttrEncodedOIDBlob[], // CRYPT_DER_BLOB rgrgAttrValueBlob[cHash][cAttrOID] header is at beginning // with the bytes pointed to immediately following OUT OPTIONAL CRYPT_DER_BLOB *rgrgAttrValueBlob, IN OUT OPTIONAL DWORD *pcbAttr ); #ifdef __cplusplus } // Balance extern "C" above #endif #if defined (_MSC_VER) #if ( _MSC_VER >= 800 ) #if _MSC_VER >= 1200 #pragma warning(pop) #else #pragma warning(default:4201) #endif #endif #endif #endif // __MINCRYPT_H__