Extracts the message digest from a signed-data CMS object file and verifies the signature.
Public Declare Function CMS_GetSigDataDigest Lib "diCrPKI.dll"
(ByVal strHexDigest As String, ByVal nHexDigestLen As Long,
ByVal strFileIn As String, ByVal strCertFile As String,
ByVal nOptions As Long) As Long
nRet = CMS_GetSigDataDigest(strHexDigest, nHexDigestLen, strFileIn,
strCertFile, nOptions) As Long
long __stdcall CMS_GetSigDataDigest(char *szOutput, long nOutChars, const char *szFileIn, const char *szCertFile, long nOptions);
If successful, the return value is a non-negative value indicating the message digest algorithm (CAUTION: this is not the number of characters in the output); otherwise it returns a negative error code.
Public Function cmsGetSigDataDigest
(szFileIn As String, Optional szCertFile As String = "", Optional nOptions As Long = 0) As String
static std::string dipki::Cms::GetSigDataDigest (const std::string &inputFile, const std::string &certFile="")
This function extracts the message digest of the signed encapsulated content.
In doing so, it also verifies that the signature is valid.
The object may be a "detached signature" object.
If signed attributes are present, the function will extract the messageDigest
attribute for RSA and DSA signature algorithms.
If signed attributes are not present, the message digest is extracted
directly from the signature value, but only for RSASSA-PKCS1-v1_5 signatures,
as the message digest cannot be directly extracted from a DSA or RSA-PSS signature.
If given, the function will use the public key from the specified X.509 certificate to validate the signature;
otherwise it will use the first valid SignerInfo and certificate pair it finds in the SignedData.
The message digest, if found, is copied into szHexDigest.
The maximum expected length of szHexDigest is PKI_MAX_HASH_CHARS
characters.
ANSI C users must add one to this value when allocating memory.
The message digest is encoded in hexadecimal format using lower-case letters [a-f].
The message digest algorithm is indicated by the return code:
Code | Algorithm |
---|---|
PKI_HASH_SHA1 (0) | SHA-1 |
PKI_HASH_MD5 (1) | MD5 |
PKI_HASH_MD2 (2) | MD2 |
PKI_HASH_SHA256 (3) | SHA-256 |
PKI_HASH_SHA384 (4) | SHA-384 |
PKI_HASH_SHA512 (5) | SHA-512 |
PKI_HASH_SHA224 (6) | SHA-224 |
CAUTION: unlike other hash-related functions, this function does not return the length of the digest string; it returns the code for the digest algorithm.
Note that this does not verify that the message digest is that of the content.
It does, however, verify that the message digest was indeed signed by the purported signer, but it does not check the
content itself.
To verify that the SignedData object is validly signed, the user must extract the content separately
and verify that its message digest matches the digest extracted by this function.
To do this, use the functions
CMS_ReadSigDataToString()
and HASH_HexFromBytes()
.
VB6 users can use HASH_HexFromString
. See the examples below.
Alternatively, use the
CMS_VerifySigData()
to verify the signature and message digest directly and use
CMS_QuerySigData()
to extract the messageDigest attribute, if present,
without validation.
This example extracts the message digest from the "detached signature" signed CMS object
created by CMS_MakeDetachedSig
above.
Dim nDigAlg As Long
Dim strCMSFile As String
Dim strHexDigest As String
strCMSFile = "DetSignByAlice.bin"
strHexDigest = String(PKI_MAX_HASH_CHARS, " ")
nDigAlg = CMS_GetSigDataDigest(strHexDigest, Len(strHexDigest), strCMSFile, "", 0)
Debug.Print "CMS_GetSigDataDigest returns " & nDigAlg
If nDigAlg < 0 Then
Exit Function
End If
Debug.Print "Extracted digest is"
Debug.Print "[" & strHexDigest & "]"
This should produce the output
CMS_GetSigDataDigest returns 0 Extracted digest is [406aec085279ba6e16022d9e0629c0229687dd48]
This second example shows how to retrieve the message digest and independently verify this against a hash of the content.
Dim strCMSFile As String Dim strHexDigest As String Dim nDigAlg As Long Dim strData As String Dim nDataLen As Long Dim strContentDigest As String Dim nHashLen As Long strCMSFile = "4.2.bin" ' 1. Get the digest value strHexDigest = String(PKI_MAX_HASH_CHARS, " ") nDigAlg = CMS_GetSigDataDigest(strHexDigest, _ Len(strHexDigest), strCMSFile, "", 0) Debug.Print "CMS_GetSigDataDigest returns " & nDigAlg If nDigAlg < 0 Then Exit Function End If Debug.Print "Extracted digest is" Debug.Print "[" & strHexDigest & "]" ' 2. Go get the content - in this case it's in the signed-data object nDataLen = CMS_ReadSigDataToString("", 0, strCMSFile, 0) If nDataLen <= 0 Then Exit Function End If strData = String(nDataLen, " ") nDataLen = CMS_ReadSigDataToString(strData, nDataLen, strCMSFile, 0) Debug.Print "CMS_ReadSigDataToString returns " & nDataLen Debug.Print "Data is [" & strData & "]" ' 3. Compute independently the hash of what we found ' (Note how we use the digest algorithm code returned above) strContentDigest = String(PKI_MAX_HASH_CHARS, " ") nHashLen = HASH_HexFromString(strContentDigest, _ Len(strContentDigest), strData, nDataLen, nDigAlg) Debug.Print "Computed hash of content is" Debug.Print "[" & strContentDigest & "]" ' 4. Can we match this hash digest with ' what we extracted from the signed-data? strContentDigest = Left(strContentDigest, nHashLen) strHexDigest = Left(strHexDigest, nHashLen) If strContentDigest = strHexDigest Then Debug.Print "SUCCESS - digests match!" Else Debug.Print "FAILS! - no match" End If
This should produce the output
CMS_GetSigDataDigest returns 0 Extracted digest is [406aec085279ba6e16022d9e0629c0229687dd48] CMS_ReadSigDataToString returns 28 Data is [This is some sample content.] Computed hash of content is [406aec085279ba6e16022d9e0629c0229687dd48] SUCCESS - digests match!
And again, this time using C:
char *infile = "C:\\Test\\4.2.bin"; long ndigalg, mlen, hlen; char hexdigest[41]; char conthash[41]; char *message; /* 1. Get the digest string */ ndigalg = CMS_GetSigDataDigest(hexdigest, sizeof(hexdigest)-1, infile, NULL, 0); printf("CMS_GetSigDataDigest returns %ld\n", ndigalg); if (ndigalg < 0) disp_error(ndigalg); printf("SigDataDigest = %s\n", hexdigest); //assert(lRet >= 0); /* 2. Get the content from the signed-data object */ mlen = CMS_ReadSigDataToString(NULL, 0, infile, 0); printf("Message data is %ld bytes long\n", mlen); if (mlen < 0) disp_error(mlen); assert(mlen >= 0); /* Allocate some memory - NB add an extra byte */ message = malloc(mlen + 1); assert(message); /* Now read in */ mlen = CMS_ReadSigDataToString(message, mlen, infile, 0); printf("CMS_ReadSigDataToString returns %ld\n", mlen); if (mlen < 0) disp_error(mlen); assert(mlen >= 0); printf("Message is '%s'\n", message); /* 3. Create a digest of this content -- use the algorithm we got above */ hlen = HASH_HexFromBytes(conthash, sizeof(conthash)-1, (unsigned char*)message, mlen, ndigalg); printf("ContentDigest = %s\n", conthash); /* 4. Finally we can compare */ if (strncmp(conthash, hexdigest, hlen) == 0) printf("SUCCESS - digests match!\n"); else printf("FAILS! - no match\n"); /* Clean up */ free(message);
Dim strHexDigest As String Dim strData As String Const strCMSFile As String = "4.2.bin" ' Extract the digest value strHexDigest = cmsGetSigDataDigest(strCMSFile, "") Debug.Print "extracted digest=[" & strHexDigest & "]" ' Extract content from signed-data file strData = cmsReadSigDataToString(strCMSFile) Debug.Print "content='" & strData & "'" ' Compute digest value over the content Debug.Print "computed digest =[" & hashHexFromBytes(StrConv(strData, vbFromUnicode), PKI_HASH_SHA1) & "]"
CMS_ReadSigData CMS_ReadSigDataToString CMS_QuerySigData CMS_VerifySigData