When you have a problem trying to decrypt/get a protected message, the message can end up on the AMS dead letter queue. This blog post explains how to look into the message and find the list of recipient, and the signer of the data.
This started off as a short blog post, then as I added more background and more detailed instructions it just grew!
The sections are
Background on the format of the protected message.
The protected message conforms to the PKCS#7 protocol as defined here.
The specification defines six formats, of which three are:
- signed data
- envelopedData where data is wrapped in an opaque envelope – it has been encrypted
- signedAndEnveloped.
These may look like the AMS classes: Integerity, Confidential, and Privacy; close – but no cigar. AMS does the signing before encryption, and so only signed data, and envelopedData are used. To see who signed a privacy message, you have to decrypt it.
I wrote a program to browse the messages on a queue, and write the protected data out to a Linux file. You can use openssl tools to explore file.
There is a PDMQ header at the front of the data. This has a variable length
- at offset 0 is “PDMQ” in ASCII.
- like other variable length MQ structures, at offset 8 is an MQLONG StrucLength. Don’t forget you may need to convert from big-endian to little-endian on some platforms.
- The data after the header is the data is ASN.1 encoded, starting with x’30’.
30 second overview of ASN.1 encoding
ASN.1 encoding takes data like “typeOfRequest,{[id1,key1],[id2,key2]} and converts it into
- a SEQUENCE (the items have an order) of typeOfRequest, keys
- where keys are a SET (because it does not matter if the order is id1, id2, or id2, id1)
- ID is an integer…
Terms like countryName C=GB map into a String of type 2.5.4.6 with length 2 and value GB.
When this is decoded it take 2.5.4.6 and says this is CountryName. You can look up the id here. There is a document with popular ones in it.
You can use openssl to format a file of ASN.1 encoded data and interpret the values. For example
openssl asn1parse -inform DER -in colin.pkj -i -offset 104 > asn1
says
- openssl asn1parse this command
- -inform DER in format is decimal encoded (not base 64)
- -in colin.pkj this is the input file
- -i says indent the output to prettify it
- -offset 104 skip over the PDMQ header
- > asn1 write the output to the file asn1
When I changed my program to skip over the PMDQ header and write out just the data, I didn’t need the -offset parameter.
I’ve also used this to display the contents of a certificate in .der format.
What does signed data look like?
The spec says signed data looks like
ContentInfo ::= SEQUENCE {
contentType ContentType,
content
}
where contentType is SignedData...
SignedData ::= SEQUENCE {
version Version,
digestAlgorithms DigestAlgorithmIdentifiers,
contentInfo ContentInfo,
certificates
signerInfos SignerInfos
}
The start of the output of the openssl asn1parse command for an integrity message contained
0:d=0 hl=4 l=1723 cons: SEQUENCE
4:d=1 hl=2 l= 9 prim: OBJECT :pkcs7-signedData
15:d=1 hl=4 l=1708 cons: cont [ 0 ]
19:d=2 hl=4 l=1704 cons: SEQUENCE
23:d=3 hl=2 l= 1 prim: INTEGER :01
26:d=3 hl=2 l= 15 cons: SET
28:d=4 hl=2 l= 13 cons: SEQUENCE
30:d=5 hl=2 l= 9 prim: OBJECT :sha256
41:d=5 hl=2 l= 0 prim: NULL
43:d=3 hl=2 l= 20 cons: SEQUENCE
45:d=4 hl=2 l= 9 prim: OBJECT :pkcs7-data
56:d=4 hl=2 l= 7 cons: cont [ 0 ]
58:d=5 hl=2 l= 5 prim: OCTET STRING :AAAAA
The columns are
- offset from the start
- d= nesting depth, so a sequence within a set, within a sequence would be d=3
- dl= length of length field
- l= length of the field
- cons|prim. I think of these as
- cons is construction … SEQ, SET etc.
- prim is primary data
- SEQUENCE, OBJECT, INTEGER type of value
Looking at the output
- at offset 4 we have ContentType which is :pkcs7-signedData
- at offset 23 we have the SignedData version :01
- at offset 30 we have a SET of digestAlgorithms, there is one in the SEQUENCE and it has the value :sha256
- at offset 45 we have contentInfo :pkcs7-data
- at offset 58 we have the message data, the very boring AAAAA.
After the data we have signer info
SignerInfo ::= SEQUENCE {
version Version,
issuerAndSerialNumber IssuerAndSerialNumber,
digestAlgorithm DigestAlgorithmIdentifier,
authenticatedAttributes
[0] IMPLICIT Attributes OPTIONAL,
digestEncryptionAlgorithm
DigestEncryptionAlgorithmIdentifier,
encryptedDigest EncryptedDigest,
unauthenticatedAttributes
[1] IMPLICIT Attributes OPTIONAL }
Extracting the interesting fields out of the data (to make it easier to read)
- Certificate serial number: 01B0
- Issuer:
- countryName:GB,
- organizationName:SSS,
- organizationalUnitName: CA,
- commonName:SSCARSA1024
- Not before time: 210328172922Z
- Not after time: 231223172922Z
- Subject:
- countryName:GB,
- organizationName:aaaa,
- commonName: ja2
- digestAlgorithm: rsaEncryption
- X509v3 Key Usage:….
- X509v3 Subject Alternative Name…
- digestEncryptedAlgorithm: sha256WithRSAEncryption
- …
What does encrypted data look like?
The spec says
EnvelopedData ::= SEQUENCE {
version Version,
recipientInfos RecipientInfos,
encryptedContentInfo EncryptedContentInfo }
RecipientInfos ::= SET OF RecipientInfo
EncryptedContentInfo ::= SEQUENCE {
contentType ContentType,
contentEncryptionAlgorithm
ContentEncryptionAlgorithmIdentifier,
encryptedContent
[0] IMPLICIT EncryptedContent OPTIONAL }
Instead of listing the DN’s of the recipients, it listed CA certificate + serial number (which equates to the same thing). As a self signed has signed itself, there is an entry for the self signed.
4:d=1 hl=2 l= 9 prim: OBJECT :pkcs7-envelopedData
23:d=3 hl=2 l= 1 prim: INTEGER :00
42:d=8 hl=2 l= 9 cons: SEQUENCE
self signed
C=GB,O=AAA,CN=colinPaice, serial=606439D5
44:d=9 hl=2 l= 3 prim: OBJECT :countryName
49:d=9 hl=2 l= 2 prim: PRINTABLESTRING :GB
57:d=9 hl=2 l= 3 prim: OBJECT :organizationName
62:d=9 hl=2 l= 3 prim: PRINTABLESTRING :AAA
71:d=9 hl=2 l= 3 prim: OBJECT :commonName
76:d=9 hl=2 l= 11 prim: PRINTABLESTRING :colin paice
89:d=6 hl=2 l= 4 prim: INTEGER :606439D5
97:d=6 hl=2 l= 9 prim: OBJECT :rsaEncryption
the following is the encrypted key for this user
110:d=5 hl=3 l= 128 prim: OCTET STRING [HEX DUMP]:861C...F2
241:d=4 hl=4 l= 348 cons: SEQUENCE
245:d=5 hl=2 l= 1 prim: INTEGER :00
248:d=5 hl=2 l= 68 cons: SEQUENCE
This is the issuer C=GB,O=SSS,OU=CA,CN=SSCARSA1024, serial 1B0
256:d=9 hl=2 l= 3 prim: OBJECT :countryName
261:d=9 hl=2 l= 2 prim: PRINTABLESTRING :GB
269:d=9 hl=2 l= 3 prim: OBJECT :organizationName
274:d=9 hl=2 l= 3 prim: UTF8STRING :SSS
283:d=9 hl=2 l= 3 prim: OBJECT :organizationalUnitName
288:d=9 hl=2 l= 2 prim: UTF8STRING :CA
296:d=9 hl=2 l= 3 prim: OBJECT :commonName
301:d=9 hl=2 l= 11 prim: UTF8STRING :SSCARSA1024
314:d=6 hl=2 l= 2 prim: INTEGER :01B0
318:d=5 hl=2 l=13 cons: SEQUENCE
320:d=6 hl=2 l= 9 prim: OBJECT :rsaEncryption
the following is the encrypted key for this user
333:d=5 hl=4 l=256 prim:OCTET STRING [HEX DUMP]:35..7BF
This is for Issuer O=TEMP, OU=TEST,CN=TEMP4Certification Authority Serial = 5D
593:d=4 hl=4 l= 354 cons: SEQUENCE
597:d=5 hl=2 l= 1 prim: INTEGER :00
608:d=9 hl=2 l= 3 prim: OBJECT :organizationName
613:d=9 hl=2 l= 4 prim: PRINTABLESTRING :TEMP
623:d=9 hl=2 l= 3 prim: OBJECT :organizationalUnitName
628:d=9 hl=2 l= 4 prim: PRINTABLESTRING :TEST
638:d=9 hl=2 l= 3 prim: OBJECT :commonName
643:d=9 hl=2 l= 28 prim: PRINTABLESTRING :TEMP4Certification Authority
673:d=6 hl=2 l= 1 prim: INTEGER :5D
678:d=6 hl=2 l= 9 prim: OBJECT :rsaEncryption
the following is the encrypted key for this user
691:d=5 hl=4 l= 256 prim:OCTET STRING [HEX DUMP]:6A...68
951:d=3 hl=2 l= 76 cons: SEQUENCE
953:d=4 hl=2 l= 9 prim: OBJECT :pkcs7-data
964:d=4 hl=2 l= 29 cons: SEQUENCE
966:d=5 hl=2 l= 9 prim: OBJECT :aes-128-cbc
977:d=5 hl=2 l= 16 prim: OCTET STRING [HEX DUMP]:9D...543A
There were three recipients configured for the queue (setmqspl -r option)
- CN=ja2, O=aaaa, C=GB. See offset 256 to 333, giving the Issuer, the certificate serial number, encryption type, and the hex dump of the encrypted key.
- Serial Number: 01 B0
- Issued by: CN=SSCARSA1024, OU=CA, O=SSS, C=GB
- CN=colin paice, O=AAA, C=GB See offset 44 to 110, giving the Issuer (this is self signed), the certificate serial number, encryption type, and the hex dump of thea encrypted key.
- Serial Number: 60 64 39 D5
- Issued by: CN=colin paice, O=AAA, C=GB
- CN=ADCDB,O=SSS. See offset 597 to 691, giving the Issuer, the certificate serial number, encryption type, and the hex dump of the encrypted key.
- Serial Number: 5D
- Issued by: CN=TEMP4Certification Authority, OU=TEST, O=TEMP
It was not easy to take the issuer information and map this to the Subject. I had to go through the whole of my keystore to find the information.
How to map Issuer+ serial to subject
For .jks keystores you can use
keytool -list -keystore ja2.jks -storepass zpassword -v |grep ‘Serial\|Issuer:\|Owner:’ | less
and search for the serial Issuer CN, and the serial number which follows it. For example
Owner: CN=ja2, O=aaaa, C=GB
Issuer: CN=SSCARSA1024, OU=CA, O=SSS, C=GB
Serial number: 1b0
For .CMS I used a bash shell script to extract the contents, then display the details of each label.
ks="/home/colinpaice/mq/zzserver.kdb"
pw="password"
z=runmqakm -cert -list -db $ks -pw $pw | awk '{print $2}'
for x in $z;do
runmqakm -cert -details -db $ks -pw $pw -label $x |grep 'Serial\|Issuer\|Subject'
done
What encryption algorithm was used?
At offset 966 is
966:d=5 hl=2 l= 9 prim: OBJECT :aes-128-cbc
The aes128 matches the -e AES128 option on the queue.
What does privacy look like?
Just like encrypted. it has
955:d=4 hl=2 l= 9 prim: OBJECT :pkcs7-signedData
instead of
953:d=4 hl=2 l=9 prim: OBJECT:pkcs7-data
The signing data is encrypted, so cannot be viewed.
Decrypting the data
If you have a file of the data, you can use openssl cms to decrypt it. The example below uses the private key for ja2 in ja2.key.pem. ( I knew it was ja2’s key file from the information above).
openssl cms -decrypt -in colin.pkj -inform der -inkey ~/ssl/ssl2/ja2.key.pem -out colin.der
Now that it is decrypted, display the signed package
openssl asn1parse -inform DER -in colin.der -i
and I can see information about the signer: the issuer, the signer and the signing time; and the payload.
Using Java to look at the data
You can use Java to process the message, using code from bouncycastle (used by MQ).
Read the message as a byte array (data) and use
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.util.ASN1Dump;
....
ASN1InputStream ais = new ASN1InputStream(data);
ASN1Primitive obj = ais.readObject();
System.out.println(ASN1Dump.dumpAsString(obj, true));
This produces output like the ans1parse above but without the conversion of 2.5.4.6 to CountryName etc. You can either guess the meaning, or look it up here.
ObjectIdentifier(1.2.840.113549.1.7.2)
Tagged [0]
Sequence
Integer(1)
Set
Sequence
ObjectIdentifier(2.16.840.1.101.3.4.2.1)
NULL
Sequence
ObjectIdentifier(1.2.840.113549.1.7.1)
Tagged [0]
DER Octet String[3]
424242 BBB
Tagged [0]
Sequence
Sequence
Tagged [0]
Integer(2)
Integer(432)
Sequence
ObjectIdentifier(1.2.840.113549.1.1.11)
NULL
Sequence
Set
Sequence
ObjectIdentifier(2.5.4.6)
PrintableString(GB)
Set
Sequence
ObjectIdentifier(2.5.4.10)
UTF8String(SSS)
Set
Sequence
ObjectIdentifier(2.5.4.11)
UTF8String(CA)
Set
Sequence
ObjectIdentifier(2.5.4.3)
UTF8String(SSCARSA1024)
Sequence
UTCTime(210328172922GMT+00:00)
UTCTime(231223172922GMT+00:00)
Other AMS blog posts