Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Determining the digest algorithm used by a PKCS#7 object #474

Open
gettalong opened this issue Nov 10, 2021 · 5 comments
Open

Determining the digest algorithm used by a PKCS#7 object #474

gettalong opened this issue Nov 10, 2021 · 5 comments
Labels

Comments

@gettalong
Copy link

I'm working on adding digital signature support to HexaPDF, using OpenSSL for the cryptographic needs.

One type of signature is a DER encoded PKCS#7 object. I can successfully extract the signing time, validity periods and other stuff. However, I didn't find any method that returns the message digest algorithm used during signing.

For example, when extracting the PKCS#7 object and looking at it with OpenSSL command line tools, I find that the algorithm is SHA1:

$ openssl pkcs7 -in /tmp/sig.pkcs7 -inform DER -print | head -n 7
PKCS7:
  type: pkcs7-signedData (1.2.840.113549.1.7.2)
  d.sign:
    version: 1
    md_algs:
        algorithm: sha1 (1.3.14.3.2.26)
        parameter: NULL

How can I retrieve this information using Ruby?

@rhenium
Copy link
Member

rhenium commented Nov 15, 2021

Getting digestAlgorithms (of SignedData = d.sign structure; the one appearing in the excerpt of openssl's output) is currently only possible by manually parsing DER encoded data:

der = File.binread("/tmp/sig.pkcs7")

#    ContentInfo ::= SEQUENCE {
#      contentType ContentType,
#      content
#        [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
p7 = OpenSSL::ASN1.decode(der)
raise "not a signed-data" if p7.value[0].value != "pkcs7-signedData"
signed_data = p7.value.find { |x| x.tag_class == :CONTEXT_SPECIFIC && x.tag == 0 }.value[0]

#    SignedData ::= SEQUENCE {
#      version Version,
#      digestAlgorithms DigestAlgorithmIdentifiers,
#      contentInfo ContentInfo,
#      certificates
#         [0] IMPLICIT ExtendedCertificatesAndCertificates
#           OPTIONAL,
#      crls
#        [1] IMPLICIT CertificateRevocationLists OPTIONAL,
#      signerInfos SignerInfos }
digest_algorithms = signed_data.value[1]

#    DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
#    DigestAlgorithmIdentifier ::= AlgorithmIdentifier
#    AlgorithmIdentifier  ::=  SEQUENCE  {
#         algorithm               OBJECT IDENTIFIER,
#         parameters              ANY DEFINED BY algorithm OPTIONAL  }
digest_algorithms.value.each do |algo_id|
  p algo_id.value[0].value
end

There is also another field indicating the digest algorithm inside SignerInfo. Currently neither has a corresponding method. This would be a nice addition to these classess.

@gettalong
Copy link
Author

Thanks @rhenium! If I implement this, would this be needed to be implemented in C or in Ruby?

@gettalong
Copy link
Author

@rhenium I was just revisiting this and wondering if you mean by "Currently neither has a corresponding method." that OpenSSL itself has no method for that or that the Ruby interface has no method for that?

I'm asking because I was looking through the available OpenSSL functions at https://www.openssl.org/docs/man3.0/man3/ (to see how a PKCS7/CMS structure could be created manually to include additional signed attributes) and seeing no method for getting the digest algorithm.

@alexdean
Copy link

alexdean commented Apr 13, 2023

I asked a similar question on stackoverflow. I suspected that getting this info would require digging into the raw ASN1, but wasn't sure. Reading this thread seems to confirm my guess.

There is also another field indicating the digest algorithm inside SignerInfo. Currently neither has a corresponding method. This would be a nice addition to these classess.

@rhenium would you be able to suggest an outline of how you'd like to see this implemented? i'd be available to work on this contribution, but would appreciate some guidance on how to get started.

@gettalong
Copy link
Author

@alexdean I did not add this to the Ruby OpenSSL library but in Ruby it would not be that hard, see https://github.com/gettalong/hexapdf/blob/master/lib/hexapdf/digital_signature/cms_handler.rb#L110-L116 where I manually decode the ASN.1 structure.

The drawback is that the structure gets parsed twice, once by Ruby OpenSSL and then manually. So having this integrated in Ruby OpenSSL would certainly be better.

As for your StackOverflow question, maybe this helps: https://github.com/gettalong/hexapdf/blob/master/lib/hexapdf/digital_signature/signing/signed_data_creator.rb (I had a similar problem because I needed to add some custom things to a PKCS#7/CMS signed data structure).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

4 participants