Open alexdean opened 1 year ago
also tried an approach based on code cited in https://stackoverflow.com/questions/53044007/how-to-use-sha1-digest-during-signing-with-opensslpkcs7-sign-when-creating-smi
micalg = 'sha-256'
# construct the signature
pkcs7 = OpenSSL::PKCS7.new
pkcs7.type = :signed
signer = OpenSSL::PKCS7::Signer.new(
@server_info.certificate,
@server_info.pkey,
As2::DigestSelector.for_code(micalg).new
)
pkcs7.add_data(mdn_text)
pkcs7.add_certificate(@server_info.certificate)
pkcs7.add_signer(signer)
pkcs7.detached = true
File.open('test_sig.p7m', 'wb') { |fp| fp.write(pkcs7.to_pem) }
File.open('test_sig_message.txt', 'wb') { |fp| fp.write(mdn_text) }
This signature is missing some important data which prevents it from being verified. Note unable to find message digest
in the verification error at the bottom.
-> % openssl smime -verify -binary -inform PEM \
-in test_sig.p7m \
-content test_sig_message.txt \
-certfile test/certificates/server.crt \
-nointern \
-noverify
Content-Type: multipart/report; report-type=disposition-notification;
boundary="----=_Part_7_20230405102219370"
------=_Part_7_20230405102219370
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
The AS2 message has been received successfully
------=_Part_7_20230405102219370
Content-Type: message/disposition-notification
Content-Transfer-Encoding: 7bit
Reporting-UA: BOB
Original-Recipient: rfc822; BOB
Final-Recipient: rfc822; BOB
Original-Message-ID: <message@server>
Disposition: automatic-action/MDN-sent-automatically; processed
Received-Content-MIC: micmicmic, sha256
------=_Part_7_20230405102219370--
Verification failure
140704403170880:error:21FFF06C:PKCS7 routines:CRYPTO_internal:unable to find message digest:/AppleInternal/Library/BuildRoots/9e200cfa-7d96-11ed-886f-a23c4f261b56/Library/Caches/com.apple.xbs/Sources/libressl/libressl-3.3/crypto/pkcs7/pk7_doit.c:1036:
140704403170880:error:21FFF069:PKCS7 routines:CRYPTO_internal:signature failure:/AppleInternal/Library/BuildRoots/9e200cfa-7d96-11ed-886f-a23c4f261b56/Library/Caches/com.apple.xbs/Sources/libressl/libressl-3.3/crypto/pkcs7/pk7_smime.c:407:
comparing this signature with one generated by OpenSSL::PKCS7.sign
, it's easy to spot differences.
-> % openssl pkcs7 -in test_sig.p7m -print
signer_info:
version: 1
issuer_and_serial:
issuer: O=Ruby AS2 Test Server, CN=server.test-ruby-as2.com
serial: 10029315826167849756
digest_alg:
algorithm: sha256 (2.16.840.1.101.3.4.2.1)
parameter: NULL
auth_attr:
object: contentType (1.2.840.113549.1.9.3)
value.set:
OBJECT:pkcs7-data (1.2.840.113549.1.7.1)
digest_enc_alg:
algorithm: rsaEncryption (1.2.840.113549.1.1.1)
parameter: NULL
enc_digest:
unauth_attr:
<EMPTY>
-----BEGIN PKCS7-----
compare this to a signature created by OpenSSL::PKCS7.sign
and then dumped to a PEM file...
signer_info:
version: 1
issuer_and_serial:
issuer: C=US, CN=ruby-as2.test.com
serial: 10470737887412000493
digest_alg:
algorithm: sha256 (2.16.840.1.101.3.4.2.1)
parameter: NULL
auth_attr:
object: contentType (1.2.840.113549.1.9.3)
value.set:
OBJECT:pkcs7-data (1.2.840.113549.1.7.1)
object: signingTime (1.2.840.113549.1.9.5)
value.set:
UTCTIME:Apr 4 20:25:53 2023 GMT
object: messageDigest (1.2.840.113549.1.9.4)
value.set:
OCTET STRING:
0000 - e3 c5 d4 00 e9 47 6d 40-cc 32 26 40 d3 .....Gm@.2&@.
000d - b9 03 7e e4 7d d9 70 ab-ab 99 be 56 c7 ..~.}.p....V.
001a - 61 d7 0a a9 5b ba a...[.
object: S/MIME Capabilities (1.2.840.113549.1.9.15)
value.set:
SEQUENCE:
0:d=0 hl=2 l= 106 cons: SEQUENCE
2:d=1 hl=2 l= 11 cons: SEQUENCE
4:d=2 hl=2 l= 9 prim: OBJECT :aes-256-cbc
15:d=1 hl=2 l= 11 cons: SEQUENCE
17:d=2 hl=2 l= 9 prim: OBJECT :aes-192-cbc
28:d=1 hl=2 l= 11 cons: SEQUENCE
30:d=2 hl=2 l= 9 prim: OBJECT :aes-128-cbc
41:d=1 hl=2 l= 10 cons: SEQUENCE
43:d=2 hl=2 l= 8 prim: OBJECT :des-ede3-cbc
53:d=1 hl=2 l= 14 cons: SEQUENCE
55:d=2 hl=2 l= 8 prim: OBJECT :rc2-cbc
65:d=2 hl=2 l= 2 prim: INTEGER :80
69:d=1 hl=2 l= 13 cons: SEQUENCE
71:d=2 hl=2 l= 8 prim: OBJECT :rc2-cbc
81:d=2 hl=2 l= 1 prim: INTEGER :40
84:d=1 hl=2 l= 7 cons: SEQUENCE
86:d=2 hl=2 l= 5 prim: OBJECT :des-cbc
93:d=1 hl=2 l= 13 cons: SEQUENCE
95:d=2 hl=2 l= 8 prim: OBJECT :rc2-cbc
105:d=2 hl=2 l= 1 prim: INTEGER :28
digest_enc_alg:
algorithm: rsaEncryption (1.2.840.113549.1.1.1)
parameter: NULL
enc_digest:
0000 - 6b 19 21 cd b4 60 90 68-43 89 2b 0a 09 28 4c k.!..`.hC.+..(L
000f - c7 1a 70 b5 39 4a 44 ca-2a 11 37 4d 91 78 94 ..p.9JD.*.7M.x.
001e - be 66 3c e4 1d 9f c4 b2-58 9d b6 42 4a d3 1a .f<.....X..BJ..
002d - aa 5e 87 77 8c f7 ab a6-90 31 e2 03 63 69 0a .^.w.....1..ci.
003c - f0 54 ba 36 38 88 56 4c-36 77 4a 90 ab e6 04 .T.68.VL6wJ....
004b - 3d 12 79 63 14 8b 20 26-42 0f bf fa 3f 87 62 =.yc.. &B...?.b
005a - a3 35 bc 23 7c c3 3f b5-28 96 36 28 9b 5c d9 .5.#|.?.(.6(.\.
0069 - e3 3c 52 70 f4 aa 1d 9f-6c 21 ff 26 21 1a 94 .<Rp....l!.&!..
0078 - 9b a0 d7 93 04 51 9c 28-f8 5f 2f a0 e7 7d 67 .....Q.(._/..}g
0087 - 65 df 15 49 2a d3 d1 02-a5 69 a4 b2 d8 27 68 e..I*....i...'h
0096 - e1 38 81 21 c2 91 fa 15-8f ba 66 7f c2 56 82 .8.!......f..V.
00a5 - 4c d0 02 1d 7f 09 e4 97-6a 2b 7a 43 b3 84 0a L.......j+zC...
00b4 - 55 fe a7 fa e7 9c 9a 34-5a cb 98 16 a3 53 15 U......4Z....S.
00c3 - 04 ec 3c 43 37 c4 0e f0-c2 26 65 84 1f c6 a2 ..<C7....&e....
00d2 - a0 08 dd 9d 70 0d 7e ee-53 44 b6 b0 07 00 1d ....p.~.SD.....
00e1 - 1b 67 cd 0b 4b f0 90 3a-d1 27 3a 47 47 a2 b2 .g..K..:.':GG..
00f0 - cd 97 78 2c c7 70 97 8a-83 b6 5e 82 47 f5 e8 ..x,.p....^.G..
00ff - 42 B
unauth_attr:
<EMPTY>
-----BEGIN PKCS7-----
sample code to read digest algorithm...
asn1 decoding method also used in #29.
def build_concise_asn1(item)
if item.respond_to?(:value)
item_value = item.value
else
item_value = item
end
if item.respond_to?(:each)
out_value = []
# OpenSSL::ASN1::Sequence responds to .each
item.each { |i| out_value << build_concise_asn1(i) }
elsif item_value.respond_to?(:each)
out_value = []
# OpenSSL::ASN1::ASN1Data does not respond to .each
# but it's .value may be an array so we should recurse
item_value.each { |i| out_value << build_concise_asn1(i) }
else
# when we hit a leaf node
if item.is_a?(OpenSSL::ASN1::Integer)
out_value = item_value.to_i
elsif item.is_a?(OpenSSL::ASN1::ObjectId)
out_value = {oid:item.oid, value:item_value}
else
out_value = item_value
end
end
out_value
end
pkcs7 = OpenSSL::PKCS7.sign(@server_info.certificate, @server_info.pkey, mdn_text)
pkcs7.detached = true
asn1 = OpenSSL::ASN1.decode(pkcs7)
simpler = build_concise_asn1(asn1)
simpler[1][0][1].map { |alg| alg[0][:value] }.join(',')
=> "SHA256"
things to check/verify:
join
because iirc multiple algorithms can be specified. need to review ASN1 schema to confirm if this is accurate.https://letsencrypt.org/docs/a-warm-welcome-to-asn1-and-der/
http://luca.ntop.org/Teaching/Appunti/asn1.html
in #25 i added a new MDN format which does not use
OpenSSL::PKCS7.write_smime
.One item i wasn't able to solve in that PR was how to specify the
micalg
parameter used in theContent-Type
header. The workaround in that PR is to still callwrite_smime
and use a regex to extract themicalg
parameter. Would like to remove that hack when possible.what we need to replicate
write_smime
produces a header like this:but i have not been able to figure out where/how it chooses the
sha-256
value. it is unconnected to the certificate we use or the MIC alg we use in the MDN report we're signing.looking for input
asked for help in https://stackoverflow.com/questions/75934159/how-does-openssl-smime-determine-micalg-parameter should check back there periodically to look for an answer.