0

CryptVerifyMessageSignature and CryptDecryptMessage functions allow me to check if an S/MIME signature is valid (or decrypt encrypted data in CryptDecryptMessage case) and also return the certificate which was used for signing (or encryption). However, there is no information about which algorithms were actually used for signing and encryption. How can I get this info?

I'm using C# but any C/C++ sample or hint is also welcome.

Edit: signature verification code snippet (the entire code is very big to include it here) added upon request

IntPtr pbDetachedSignBlob = IntPtr.Zero;
uint cbDetachedSignBlob = (uint)signatureBytes.Length;
IntPtr pbContent = IntPtr.Zero;
uint cbContent = (uint)data.Length;

pbDetachedSignBlob = Marshal.AllocHGlobal((int)cbDetachedSignBlob);
Marshal.Copy(signatureBytes, 0, pbDetachedSignBlob, (int)cbDetachedSignBlob);
pbContent = Marshal.AllocHGlobal((int)cbContent);
Marshal.Copy(data, 0, pbContent, (int)cbContent);
IntPtr[] messageArray = { pbContent };
uint[] messageSizeArray = { cbContent };

GCHandle messageArrayHandle = GCHandle.Alloc(messageArray, GCHandleType.Pinned);
IntPtr messageArrayPtr = (IntPtr)messageArrayHandle.AddrOfPinnedObject();

int ret = CryptoApiFuncs.MessageFuncs.CryptVerifyDetachedMessageSignature(pVerifyPara, 0, pbDetachedSignBlob, cbDetachedSignBlob, 1, messageArrayPtr, ref messageSizeArray[0], ref pSignerCert);
Alex
  • 2,469
  • 3
  • 28
  • 61

2 Answers2

1

Couldn't find the way to do this directly via CryptoAPI but managed to accomplish this with System.Security.Cryptography.Pkcs.SignedCms class:

SignedCms cms = new SignedCms(new ContentInfo(data));
cms.Decode(signature);
string algName = cms.SignerInfos[0].DigestAlgorithm.FriendlyName;

where data is the message bytes being verified and signature is the detached signature bytes.

Production code must also be ready to expect non-single values in SignerInfos collection but the sample code shows the idea.

The same way, EnvelopedCms class provides the details on encryption algorithm of the message:

EnvelopedCms cms = new EnvelopedCms();
cms.Decode(data);
string s = cms.ContentEncryptionAlgorithm.Oid.FriendlyName;
Alex
  • 2,469
  • 3
  • 28
  • 61
0

The api you are using, carry out checks validity of digital signature which goes with documents and so on.. this check is done against a certificate, the info of whom are contained in the CERT_CONTEXT structure (pSignerCert) into which in turn it is contained a CERT_INFO structure (pCertInfo CERT_CONTEXT structure field).

Into CERT_CONTEXT you can find infos about standard certicate type of encoding used (X509_ASN_ENCODING or PKCS_7_ASN_ENCODING).

Into CERT_INFO you can find CRYPT_ALGORITHM_IDENTIFIER and other more detailed infos.

For a documentation about CryptVerifyDetachedMessageSignature apis and related structures:

EDIT:

Digital signature system generally works creating an hash of the data to sign (SHA1 minimum level older certificates standard, now newer certicates start from a level of SHA256..), then this hash get encrypted with a private key using an algorithm of asymmetric cryptography (RSA).

When the message is received, it get decrypted with the public key contained in the certificate released publicly, and then the date get hashed with the right algorithm, declared in the certificate (from programmatically point of view, see the struct fields upon) and if the two hashes (one in the same certificate that goes with the data, and the other calculated on the client who verify the digital signature) correspond, then it is verified that the data are not corrupted or changed by someone other than the author, and if the certificate it is released by a valid certification authority, then the author is also identified in a sure manner.

Ciro Corvino
  • 2,038
  • 5
  • 20
  • 33
  • This is the info I already have. As I wrote in the post, I have no problems with getting the certificates used for signing and encryption. I can't find the algorithm used for that. CRYPT_ALGORITHM_IDENTIFIER you mentioned corresponds to the algorithm used to sign the certificate itself, not the data signed with this certificate's key. For instance, I have a message which is signed with SHA1 alg while the certificate itself is signed with SHA256 alg. – Alex Dec 28 '16 at 17:06
  • the infos (public key and algorithm) about data signing with the private key you can find in CERT_INFO field: CERT_PUBLIC_KEY_INFO SubjectPublicKeyInfo, which in turn reports the algorithm infos always in a CRYPT_ALGORITHM_IDENTIFIER structure. I have referred that about the other more detailed infos... – Ciro Corvino Dec 28 '16 at 18:03
  • 1
    Again, everything you mentioned is about the certificate. I don't need this info, I've already extracted everything from CERT_CONTEXT, CERT_INFO and CERT_PUBLIC_KEY_INFO. I'm aware of these structures and I already have all the info from them. Now I need the info of algorithm which was used to sign the message. It's not contained in the certificate (for instance, I can use the same certificate to sign with different algorithms). – Alex Dec 29 '16 at 09:26
  • Sorry but in the fields of the CERT_INFO that I indicated are contained both the algorithms to sign the data (SubjectPublicKeyInfo) and to sign the resulting hash (pCertInfo). These are the infos about signing with certificates. Maybe you are searching for encryption of data independent by the certificate signing mechanism. If the data are already encrypted before any digital sign is applied, then you have not any info about that, you have to know which algorithm it is used. – Ciro Corvino Dec 29 '16 at 09:38
  • SubjectPublicKeyInfo and pCertInfo indeed contain diff. algs but they both are not related to what I need. One of them Signature Algorithm (sha256RSA) and another - Signature Hash Algorithm (sha256). Both are associated with the cert. I need THIRD algorihtm (SHA1 - 1.3.14.3.2.26 or 1.3.14.3.2.26.29) which is not returned by any of the above. And my message is not encrypted, just signed. When I open message in Outlook, I can see all 3 algs. But with my code only two are returned (the same ones you mentioned). – Alex Dec 29 '16 at 10:33
  • it is a bit strange.. as far as I know digital signature works creating an hash of the data to sign (SHA1 minimum level older certificates standard, now newer certicates start from a level of SHA256..), then this hash get encrypted with a private key using an algorithm of asymettric cryptography (RSA). When the message is received, it get decrypted with the public key contained in the certificate released publicly, and then the date get hashed with the right algorithm, declared in the certificate (from programmatically point of view, see the struct fields discussed up to now..), (continue...) – Ciro Corvino Dec 29 '16 at 13:14
  • (...continue) and if the two hashes (one in the same certificate that goes with the data, and the other calculated on the client who verify the digital signature) correspond, then it is verified that the data are not corrupted or changed by someone other than the author, and if the certificate it is released by a valid certification authority, then the author is also identified in a sure manner. So I cannot figure out how a second hashing or encryption algorithm could work in this process and why.. – Ciro Corvino Dec 29 '16 at 13:15
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/131801/discussion-between-alex-and-ciro-corvino). – Alex Dec 29 '16 at 13:18