Get the issuing CA for a given certificate - winapi

I have a variable of type PCCERT_CONTEXT which contains a certificate (this is actually the certificate of the digital signer of a given executable file.) I need to get the certificate or at least the name of the issuing CA. I've tried using CertOpenStore and WTHelperCertFindIssuerCertificate, but have had no success. I would appreciate any help.
Regards,
Alireza

Maybe CertGetIssuerCertificateFromStore()?

You probably want CertGetCertificateChain http://msdn.microsoft.com/en-us/library/aa376078(VS.85).aspx

The CERT_CONTEXT contains the CERT_INFO structure.
The CERT_INFO structure contains a pointer to the Issuer as a CERT_NAME_BLOB.

Related

Signed PDF verification in Origami with an Adobe PKCS#7 certificate

Summarized and clarified:
Using origami, extracting a certificate from a signed pdf (signed within e.g. Adobe Reader) I cannot verify the signature:
origami = Origami::PDF.read(File.open('/path/to/file.pdf', 'r'))
pdf_signature = origami.signature[:Contents]
cert = OpenSSL::PKCS7.new(pdf_signature).certificates.first
origami.verify(trusted_certs: [cert]) #=> false
As far as I can tell, this should always be true. So maybe Adobe uses a different byte range that it takes a SHA of when signing the PDF? How do I get that verify to work?
If it's any help, after tiptoing through the changes on origami master, I was able to get the exact OpenSSL error from the storecontext: V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY - I presume it means from the X509::Store it sets up.
Full background
I'm trying to verify the digital signature of a PDF. Here's what I've got:
A PDF that I've signed using Adobe Acrobat (tried both Pro 10 and Reader DC)
The key was generated in Acrobat Pro, I have access to the .p12, or exporting as FDF, PKCS#7 or just "Certificate File". Have also tried loading this "Certificate File" via Apple's "Keychain Access" and exporting that as a .pem This gives the same result as OpenSSL::PKCS7.new(File.read('/path/to/exported.p7c')).certificates.first.to_pem which gives the same result as:
openssl pkcs7 -print_certs -inform der -in pkcs7file.p7c -out certificate.cer
So, I'm pretty sure I've extracted the certificate correctly.
Also, I can verify that exact same certificate is embedded in the PDF -
pdf_signature = origami.signature[:Contents]
OpenSSL::PKCS7.new(pdf_signature).certificates.first.to_pem #=> Same as above
With the Origami gem, I've tried loading the certificate and attempting verification:
cert = OpenSSL::X509::Certificate.new(File.read('/path/to/pem.cer'))
Origami::PDF.read(File.open('/path/to/file.pdf', 'r')).verify(trusted_certs: [cert])
Origami's output confirms the document has been signed, but the verify(..) method returns false.
Note that working through the code from this excellent answer works fine, but it only seems to work if you generate the X.509 keypair using openssl (e.g. the ruby-land bindings as per that code). Unfortunately I'm required to use the pre-existing Adobe-blessed signatures from the user's machines.
That said, aside from this I have very few restraints; I can ask the users to export their certificate in any other way that is useful to us (I can even run some simple code on their machines if necessary), though I mustn't transmit the private key in the procedure. I don't have to use Origami for the verification, but it does have to be a command accessible from ruby on an ubuntu server. The users are all running on Macs with reasonably up-to-date software.
I've gotten a little further from my original issue, but not by much:
Certificates require the correct extensions
In the original code from Harry Fairbanks' very useful answer, the extensions are paramount:
extension_factory = OpenSSL::X509::ExtensionFactory.new
extension_factory.issuer_certificate = cert
extension_factory.subject_certificate = cert
cert.add_extension extension_factory.create_extension('basicConstraints', 'CA:TRUE', true)
cert.add_extension extension_factory.create_extension('keyUsage', 'digitalSignature,keyCertSign')
cert.add_extension extension_factory.create_extension('subjectKeyIdentifier', 'hash')
So... following the rest of that answer, if you save the certificate to a pemfile, the extensions do not also get saved.
I was able to create a PDF, sign it with Origami using the key I exported from Acrobat reader, and then do the following:
cert = OpenSSL::PKCS7.new(pdf_signature).certificates.first
origami.verify(trusted_certs: [cert]) #=> false
## ... then run the extension factory snippet above
origami.verify(trusted_certs: [cert]) #=> true
Success! In fact, even Adobe Acrobat Reader was happy - which I couldn't get it to do with the self-signed certificate that Origami generated.
... however, when I sign the document using Adobe Acrobat Reader, with the same key, perform the same magical incantation on the cert, I still get false from the verify call.
Note: I have been told that this actually works for some people. Not sure why it failed for me - when I have a chance to play, will give it another go. Will mark this as answered for now!
It's possible the ciphers are different. It could be that the Adobe cipher is not the same one that the openssl is using and would then fail the verification check. Take a look at this. Details on ciphers
This might be useful too openssl commands

How to import key from CERT_CONTEXT into HCRYPTPROV

We have Windows code which is heavily based on Crypt* API and keys stored in HCRYPTPROV (asymmetric, both public and private parts). The keys are normally imported from external source using CryptImportKey().
Note: The safety of the source providing this key is out of topic here. Let's say it is safe enough for our purposes.
Now with development going on we need to adopt keys coming from X.509 certificates. Currently code loads certificate into HCERTSTORE through PFXImportCertStore() or obtains it from online CA and then certificate itself can be accesses as CERT_CONTEXT through CertEnumCertificatesInStore.
But I completely failed to find a way to move keys from certificate into HCRYPTPROV. Any ideas are extremely welcome.
Regards,
HCRYPTPROV is just a pointer. You cannot move keys there.
Have you tried to use the IntPtr property X509Certificate2.Handle yet?

How To Extract Public Key

I used the following answer (https://stackoverflow.com/a/201277/99344) to generate a certificate and sign my exe.
I need to give the public key to a third party.
I have .pvk and .cer files. How do I extract the public key?
Thanks.
OK so I found some documentation that says that the .cer file only contains the public key so it is what I wanted.

How to get Container name for PFX key?

Some time ago I installed my PFX key into Container using command like this:
sn -i mykey.pfx VS_XXX
but two months later I forgot the Container name (VS_XXX), so my question is:
How to get than name back? I know key name, I have this key, I know the key pass phrase.
Download the Keypal utility and double click it, you will find all the names of the key containers. You can choose between user profile and machine profile.
Alternatively, enumerate the certificate store to find the certificate of interest via its subject and then you can use CertGetCertificateContextProperty to get the value for PCERT_KEY_PROV_INFO_PROP_ID. This approach requires the use of Microsoft's cryptoAPI
you could just re-install the key with a new container name:
sn -i mykey.pfx VS_ABAB1234ABAB1234
Update for 2021: Found answer here https://stackoverflow.com/a/59999581/9862613
You can get the container name using SnInstallPfx tool:
SnInstallPfx.exe yourKey.pfx

How to validate a signed DLL has been signed by me?

I have created a self generated certificate to sign a DLL. When I load this DLL into my C++ application I am able to validate if the code signing certificate is valid or not by using the WinVerifyTrust api.
But I am not able to find a way to detect that the DLL has been signed by one of my certificates. Even by using the CryptQueryObject api I do not find any useful information.
Does anyone have a idea on how to do this? Or is it event possible?
Thank you
CryptVerifyCertificateSignature isn't what you want?
If you sign a certificate using your private key, it can only be verified with your public key. That's how public-key cryptography works. If you can use a public key to verify the signature, then you know that the corresponding private key must have been used to sign it.
In case you need a version that also works on earlier versions of Windows than the one Bill Zeller showed you, you can use the following:
Use CryptQueryObject with CERT_QUERY_OBJECT_FILE
Use CryptMsgGetParam with CMSG_SIGNER_CERT_INFO_PARAM on the HCRYPTMSG you received from the previous call
Now use CertCompareIntegerBlob to compare your known (certificate) serial number (or numbers, in a loop) against the one in the file
If any of the known serial numbers matches, you're done. If all comparisons fail, it's not your cert.
Note: when looking at the serial number of the certificate in the file properties dialog, the bytes shown there appear in the reverse order when compared with the contents of the PCERT_INFO (CERT_INFO::SerialNumber) you get from the CryptMsgGetParam. So make sure that you store your own serial numbers reversed or reverse them before comparison.
Also note: you'll still need to have the certificate installed as trusted, in order for WinVerifyTrust (not mentioned above) to consider the code signature trusted at all. I just described the part about how to find out it's your own certificate that was used.

Resources