Debug output using print instead of printf?
Closed this issue · 7 comments
There are some handy certs etc from RFC 3280 and RFC 5280 over at https://csrc.nist.gov/Projects/pki-testing/Sample-Certificates-and-CRLs
I'm using perl 5.34 and Convert::ASN1 0.330.
When I pass the example CRL into asn_dump()
I see a few "%d" markers in the output. It looks like the asn_dump
output format is changing a bit but there's maybe a print still being used instead of a printf. So it currently looks a bit busted:
005E 13: [UNIVERSAL %d]: 23
0060 : 30 35 30 32 30 35 31 32 30 30 30 30 5A __ __ __ 050205120000Z
006D 13: [UNIVERSAL %d]: 23
006F : 30 35 30 32 30 36 31 32 30 30 30 30 5A __ __ __ 050206120000Z
007C 34: SEQUENCE: 16 {
007E 32: SEQUENCE: 16 {
0080 1: INTEGER: 2 = 18
0083 13: [UNIVERSAL %d]: 23
0085 : 30 34 31 31 31 39 31 35 35 37 30 33 5A __ __ __ 041119155703Z
0092 12: SEQUENCE: 16 {
0094 10: SEQUENCE: 16 {
0096 3: OBJECT ID: 6 = 2.5.29.21
009B 3: STRING: 4
009D : 0A 01 01 __ __ __ __ __ __ __ __ __ __ __ __ __ ...
00A0 : }
00A0 : }
00A0 : }
00A0 : }
00A0 47: [CONTEXT %d]: 0 {
This should resolve your issue. can you confirm?
diff --git a/lib/Convert/ASN1/Debug.pm b/lib/Convert/ASN1/Debug.pm
index d877b09..c706bbe 100644
--- a/lib/Convert/ASN1/Debug.pm
+++ b/lib/Convert/ASN1/Debug.pm
@@ -95,7 +95,7 @@ sub asn_dump {
my $label = $type{sprintf("%02X",$tag & ~0x20)}
|| $type{sprintf("%02X",$tag & 0xC0)}
|| "[UNIVERSAL %d]";
- print "$label: $tnum";
+ printf "$label: $tnum";
if ($tag & ASN_CONSTRUCTOR) {
print " {\n";
Hi, no that results in printf being called with too few arguments in many cases. e.g.
0000 352: SEQUENCE: 16 {
0004 202: SEQUENCE: 16 {
0007 1: INTEGER: 2 = 1
000A 13: SEQUENCE: 16 {
000C 9: OBJECT ID: 6 = 1.2.840.113549.1.1.5
0017 0: NULL: 5
0019 : }
0019 67: SEQUENCE: 16 {
001B 19: SET: 17 {
001D 17: SEQUENCE: 16 {
001F 10: OBJECT ID: 6 = 0.9.2342.19200300.100.1.25
Missing argument in printf at /Users/cjr/lib/perl5/Convert/ASN1/Debug.pm line 98, <> line 1.
at /Users/cjr/lib/perl5/Convert/ASN1/Debug.pm line 98, <ARGV> line 1.
Convert::ASN1::asn_dump("*main::STDOUT", "0\x{82}\x{1}`0\x{81}\x{ca}\x{2}\x{1}\x{1}0\x{d}\x{6}\x{9}*\x{86}H\x{86}\x{f7}\x{d}\x{1}\x{1}\x{5}\x{5}\x{0}0C1\x{13}0\x{11}\x{6}\x{a}\x{9}\x{92}&\x{89}\x{93}\x{f2},d\x{1}\x{19}\x{16}\x{3}com1\x{17}0\x{15}\x{6}\x{a}\x{9}\x{92}&\x{89}\x{93}\x{f2},"...) called at /Users/cjr/bin/dumpber line 63
002B 3: [UNIVERSAL 0]: 22
002D : 63 6F 6D __ __ __ __ __ __ __ __ __ __ __ __ __ com
0030 : }
0030 : }
Having things in %type with optional format strings seems the cause of the issue. Changing to something like
$ diff -bu ~/Downloads/Debug.pm ~/lib/perl5/Convert/ASN1/Debug.pm
--- /Users/cjr/Downloads/Debug.pm 2023-08-02 09:17:17
+++ /Users/cjr/lib/perl5/Convert/ASN1/Debug.pm 2023-08-02 10:04:18
@@ -55,6 +55,7 @@
05 NULL
06 OBJECT ID
80 [CONTEXT %d]
+ 00 [UNIVERSAL %d]
)
)
);
@@ -93,9 +94,9 @@
printf $fmt. " %4d: %s",$start,$len,$indent;
my $label = $type{sprintf("%02X",$tag & ~0x20)}
- || $type{sprintf("%02X",$tag & 0xC0)}
- || "[UNIVERSAL %d]";
- printf "$label: $tnum";
+ || $type{sprintf("%02X",$tag & 0xC0)};
+ $label = sprintf($label, $tag & ~0xE0) if $label =~ /%d/;
+ print "$label: $tnum";
if ($tag & ASN_CONSTRUCTOR) {
print " {\n";
works for me. It gets rid of the special case || "[UNIVERSAL %d]"
and handles all the other tag classes. (Note the "[CONTEXT %d]" at the end of my original error report.) Checking for a %d
in the label does feel a bit tacky.
Here's an alternative, which moves all the tag classes into %classes so we can reliably use sprintf:
$ diff -bu ~/Downloads/Debug.pm ~/lib/perl5/Convert/ASN1/Debug.pm
--- /Users/cjr/Downloads/Debug.pm 2023-08-02 09:17:17
+++ /Users/cjr/lib/perl5/Convert/ASN1/Debug.pm 2023-08-02 10:16:36
@@ -49,12 +49,19 @@
11 SET
02 INTEGER
03 BIT STRING
- C0 [PRIVATE %d]
04 STRING
- 40 [APPLICATION %d]
05 NULL
06 OBJECT ID
+ )
+ )
+);
+
+my %classes = (
+ split(/[\t\n]\s*/,
+ q(C0 [PRIVATE %d]
+ 40 [APPLICATION %d]
80 [CONTEXT %d]
+ 00 [UNIVERSAL %d]
)
)
);
@@ -93,9 +100,8 @@
printf $fmt. " %4d: %s",$start,$len,$indent;
my $label = $type{sprintf("%02X",$tag & ~0x20)}
- || $type{sprintf("%02X",$tag & 0xC0)}
- || "[UNIVERSAL %d]";
- printf "$label: $tnum";
+ || sprintf($classes{sprintf("%02X",$tag & 0xC0)}, $tag & ~0xE0);
+ print "$label: $tnum";
if ($tag & ASN_CONSTRUCTOR) {
print " {\n";
Cleaner? Dunno! Both work.
Sure, I'm attaching the script I've been using. I just used it with https://csrc.nist.gov/CSRC/media/Projects/PKI-Testing/documents/pkixtools/rfc5280_CRL.crl
$ dumpber rfc5280_CRL.crl
Take a look at this addition. It attempts to make the code for the tag to be show the leading zero when necessary. The tag for integer for instance is 06
diff --git a/lib/Convert/ASN1/Debug.pm b/lib/Convert/ASN1/Debug.pm
index ec68b80..f77b092 100644
--- a/lib/Convert/ASN1/Debug.pm
+++ b/lib/Convert/ASN1/Debug.pm
@@ -101,7 +101,7 @@ sub asn_dump {
my $label = $type{sprintf("%02X",$tag & ~0x20)}
|| sprintf($classes{sprintf("%02X",$tag & 0xC0)}, $tag & ~0xE0);
- print "$label: $tnum";
+ printf ("$label: %02d", $tnum);
if ($tag & ASN_CONSTRUCTOR) {
print " {\n";
BER can have tags bigger than one byte (the asn_decode_tag
and asn_decode_tag2
functions will decode these). I was worried that "%02d" would truncate these but although it doesn't, including the leading zero for short tag numbers looks odd to me and might mislead readers into assuming hex.
I think keeping it as print "$label: $tnum";
is fine.
# Just checking...
printf("%02d", 3) -> "03"
printf("%02d", 30) -> "30"
printf("%02d", 999) -> "999"
Here's an example of a real life certificate extension using large tag numbers: https://developer.android.com/training/articles/security-key-attestation#certificate_schema