I check PKCS7 signature with CryptVerifyDetachedMessageSignature and CryptVerifyMessageSignature functions.
Both of them can verify pkcs7 file with certificate which I provided in PCCERT_CONTEXT structure. I got PCCERT_CONTEXT with CertCreateCertificateContext function.
But now I have other task. I have to extract certiticateS from pkcs7 file and verify signatures with all of them.
Can you help me to know how could I do this things:
Extract certificates from pkcs7 (more than one);
Verify pkcs7 signature with them.
I have to use C++ with CryptoApi for this tasks.
If I take a look at the API it seems you can use the dwSignerIndex to verify all the signatures. The the certificate that was used to create the signature is returned in ppSignerCert.
The API says the following about dwSignerIndex:
The index of the desired signature. There can be more than one signature. CryptVerifyMessageSignature can be called repeatedly, incrementing dwSignerIndex each time. Set this parameter to zero for the first signer, or if there is only one signer. If the function returns FALSE, and GetLastError returns CRYPT_E_NO_SIGNER, the previous call processed the last signer of the message.
Related
I have a client/server architecture in which I use the openssl library to implement an encrypted communication (TLSv1.2).
Since I'm using "self signed" certificates, in order to verify server's identity, my idea is to put in the client side a physical copy of the server's public key (server_public_key.pem) and then verify if it is equals to which received in the handshake phase of TLS.
On the client, I can retrieve the latter with:
X509 *cert = SSL_get_peer_certificate(ssl);
Now, I would extract the human readable string of the public key contained in this object.
I know that I can print it in this way:
EVP_PKEY *pkey = X509_get_pubkey(cert);
PEM_write_PUBKEY(stdout, pkey);
But I need to keep it as a string (instead of send it to stdout). How can I do this ?
Use BIO_new() to create a new BIO backed by an internal memory buffer (initially empty).
Then use PEM_write_bio_PUBKEY() to write the public key to the BIO, at which point use the functions documented in the BIO's manual page to retrieve the public key.
See the cited documentation for a simple example of creating a BIO, writing to it, then reading from it. Replacing the sample write operation with PEM_write_bio_PUBKEY() should be sufficient.
I need to read a X509 certificate in C++. I couldn't find a way to do that with the GnuTLS library. The certificate has to be read in PEM or DER format, so that I can process it twith functions of the GnuTLS library. Is there a pendant to the bio files provided in openssl, which allow me to read the certificate and concert it into processable format?
Actually it is important to generate a variable which contains a tuple of the certificate and the length of the certificate. The certificate can be read using fopen() and fread(). The tuple can be processed with gnutls_x509_crt_import(). That solves the problem for me.
I want to validate certificates of signed executable images (by validation, I mean to tell if the signature comes from MS/Adobe/Oracle etc.). Does windows provides api for this task? How should I do that, no idea. Any help would be appreciated.
I'm using Windows and C++. I want to validate native executable images, not .NET assemblies or Java jar files.
UPDATE
Ok, I'll try to describe what I want shortly.
1) Validate PE certificate. Is the signature valid or not. It should work when signature is embedded in PE and when the signature is in security catalog. (I found this on sysinternals forum and works fine, so I don't need this one anymore).
2) Tell who's the signer/publisher of the file. I know it can be achieved through CryptQueryObject (I found a working example, though it doesn't work with security catalogs), but don't know how to use it with security catalog files.
There are many API and approaches how you can get and verify the signature of the executable and how you can get other additional information which you need. The problem is which level you choose (high level like WinVerifyTrust)
The easiest first API which can be used to get cryptography context from the CAT or EXE file is CryptQueryObject function. The code example from the KB323809 could get you the main idea how to decode information what you need. the main difference if you work with CAT files is that you should modify the some parameters of CryptQueryObject. I recommend you just to use CERT_QUERY_CONTENT_FLAG_ALL and CERT_QUERY_FORMAT_FLAG_ALL and CryptQueryObject will do all what you needs internally:
BOOL bIsSuccess;
DWORD dwEncoding, dwContentType, dwFormatType;
HCERTSTORE hStore = NULL;
HCRYPTMSG hMsg = NULL;
PVOID pvContext = NULL;
// fill szFileName
...
// Get message handle and store handle from the signed file.
bIsSuccess = CryptQueryObject (CERT_QUERY_OBJECT_FILE,
szFileName,
CERT_QUERY_CONTENT_FLAG_ALL,
CERT_QUERY_FORMAT_FLAG_ALL,
0,
&dwEncoding,
&dwContentType,
&dwFormatType,
&hStore,
&hMsg,
&pvContext);
The value dwContentType set by the CryptQueryObject will get you the base information about the type of the file szFileName. The pvContext will be PCCERT_CONTEXT for the most cases which you need, but it can be also PCCRL_CONTEXT or PCCTL_CONTEXT if you use .ctl or .crl file as the input. You will receive the hStore filled with all certificates from the file szFileName. So with respect of pvContext and hStore you can examine the file contain with CryptoAPI. If you do prefer
low-level massages API you can use hMsg which will be additionally set in case of some dwContentType (at least for for CERT_QUERY_CONTENT_PKCS7_SIGNED, CERT_QUERY_CONTENT_PKCS7_UNSIGNED, CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED).
To verify the signature of the file I would recommend you to use CertGetCertificateChain and CertVerifyCertificateChainPolicy to verify not only that the certificate is valid in general, but that it (or all its parents) is valid for authenticode (szOID_PKIX_KP_CODE_SIGNING). CertGetCertificateChain can be used for different revocation scenarios. You should do two separate calls with CERT_CHAIN_POLICY_AUTHENTICODE and CERT_CHAIN_POLICY_AUTHENTICODE_TS to verify that both Authenticode chain policy and Authenticode Time Stamp chain policy are valid.
UPDATED: I reread your current question (the Updated part). Your current problem is how to get the signer/publisher of the file. So I answer only on the question.
If you use the code from sysinternal for the signature verification you should just search for the line
if ( !CryptCATCatalogInfoFromContext(CatalogContext, &InfoStruct, 0) )
The statement sill set the fields of the InfoStruct in case that that file is system windows file which signature is verified with respect of some .cat file. The field InfoStruct.wszCatalogFile will get you the name of the .cat file.
For example on my Windows 7 if I try to verify the digital signature of the C:\Windows\explorer.exe file, the .cat where its hash could be found is C:\Windows\system32\CatRoot\{F750E6C3-38EE-11D1-85E5-00C04FC295EE}\Package_1_for_KB2515325~31bf3856ad364e35~amd64~~6.1.1.0.cat.
If you would use code from KB323809 with described above parameters of CryptQueryObject you will decode the SPC_SP_OPUS_INFO_OBJID ("1.3.6.1.4.1.311.2.1.12") attribute of the C:\Windows\system32\CatRoot\{F750E6C3-38EE-11D1-85E5-00C04FC295EE}\Package_1_for_KB2515325~31bf3856ad364e35~amd64~~6.1.1.0.cat (see the function GetProgAndPublisherInfo) and you will know
pwszProgramName: "Windows Express Security Catalogs"
pPublisherInfo: NULL
pMoreInfo->dwLinkChoice: SPC_URL_LINK_CHOICE
pMoreInfo->pwszUrl "http://www.microsoft.com"
So no special publisher information are included for the file. If you examine the signer of the the catalog you will find out that:
The signer of the .cat file: "Microsoft Windows"
The signer signed it with the certificate:
Serial Number: 0x6115230F00000000000A
Issuer Name: Microsoft Windows Verification PCA
Full Issuer Name:
CN = Microsoft Windows Verification PCA
O = Microsoft Corporation
L = Redmond
S = Washington
C = US
Subject Name: Microsoft Windows
Full Subject Name:
CN = Microsoft Windows
OU = MOPR
O = Microsoft Corporation
L = Redmond
S = Washington
C = US
The Date of TimeStamp : 28.02.2011 21:16:36
TimeStamp Certificate:
Serial Number: 0x6103DCF600000000000C
Issuer Name: Microsoft Time-Stamp PCA
Subject Name: Microsoft Time-Stamp Service
So you should use just the signer of the .cat file, because there are no other signer of explorer.exe.
The WinVerifyTrust function performs a trust verification action on a specified object. The function passes the inquiry to a trust provider that supports the action identifier, if one exists.
For certificate verification, use the CertGetCertificateChain and CertVerifyCertificateChainPolicy functions.
#Davita
I read the above problem thoroughly and tried to solve it.
My suggestion is to try CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED instead of CERT_QUERY_CONTENT_FLAG_ALL in the third parameter of CryptQueryObject()
I have a CERT_CONTEXT structure which I've extracted from a smart card on Windows via the CryptoAPI. I need to convert this structure into a DER encoded byte array which is consistent with OpenSSL. The closest match I've got so far is via CryptEncodeObject using X509_ASN_ENCODING and the X509_CERT_TO_BE_SIGNED modifier which takes the CERT_INFO structure as input.
The problem is that it doesn't match with the output produced by the OpenSSL i2d_X509 function. Using a 2048 bit x509 certificate as input, OpenSSL produces 1789 bytes of encoded output whilst the Windows CryptoAPI produces 1638 bytes of encoded output.
The only option left that I can see is to create an X509 cert on the fly using the values from the CERT_CONTEXT structure and the encode the resulting object directly with the i2d_X509 function. The only problem with this is that I can't extract the private key from the smart card, so this may cause problems with the x509 cert creation routines.
If anyone can provide any insight/advice/tips into these matters, I'd be much obliged.
DER encoded certificate can be obtained from (ctx->pbCertEncoded, ctx->cbCertEncoded) buffer where ctx is a PCCERT_CONTEXT object. Still you won't be able to recover the private key.
I'm loading a .p7b certificate file into memory and then calling CertCreateCertificateContext on it, but it fails with the error "ASN1 bad tag value met.".
The call look like this:
m_hContext = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, pbCertEncoded, dwCertEncodedLen);
This returns NULL and GetLastError() returns the error mentioned above.
I created the certificate file by dragging a certificate out of the settings in IE, which then does an automatic export to a file.
What am I doing wrong?
Thanks!
Try to open your certificate by some asn.1 editor.
Probably your certificate has been exported incorrectly or size of the certificate you pass to the api is wrong... Rather the second one option (incorrect cert construction or passing).
I found here the info that the encoding you try to use is not fully supported (see possible error values).
You have to use CertOpenStore() instead:
HCERTSTORE hCertStore = CertOpenStore(
CERT_STORE_PROV_FILENAME,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
NULL,
CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG,
pszFilePath));
CertCreateCertificateContext() supports one certificate only, whereas PKCS #7 file can contain many.
Quote from MSDN:
CERT_STORE_PROV_FILENAME
Initializes the store with certificates, CRLs, and CTLs from a file. The provider opens the file and first attempts to read the file as a serialized store, then as a PKCS #7 signed message, and finally as a single encoded certificate.
After the certificate store is open, you can use CertEnumCertificatesInStore() to retrieve certificate context of individual certificates from store.
Make sure the certificate is in binary format.
I had similar issue when the certificate was in "Base-64 encoded X.509".
It was fixed when i used the same certificate in "DER encoded binary X.509"
You can do this easily on windows by manually importing into cert store and then exporting using the desired format.
Certificate can then be used to be installed on other machines using winapi functions.