.\" -*- mode: troff; coding: utf-8 -*- .\" Automatically generated by Pod::Man v6.0.2 (Pod::Simple 3.45) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" \*(C` and \*(C' are quotes in nroff, nothing in troff, for use with C<>. .ie n \{\ . ds C` "" . ds C' "" 'br\} .el\{\ . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" Required to disable full justification in groff 1.23.0. .if n .ds AD l .\" ======================================================================== .\" .IX Title "Crypt::ASN1 3" .TH Crypt::ASN1 3 2026-05-12 "perl v5.42.2" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH NAME Crypt::ASN1 \- DER ASN.1 parser and encoder based on libtomcrypt .SH SYNOPSIS .IX Header "SYNOPSIS" .Vb 1 \& use Crypt::ASN1 qw(asn1_decode_der asn1_encode_der asn1_to_string); \& \& # \-\-\- decode \-\-\- \& my $tree = asn1_decode_der($der_bytes); \& my $tree = asn1_decode_der($der_bytes, { int => \*(Aqhex\*(Aq, bin => \*(Aqhex\*(Aq }); \& \& # \-\-\- inspect \-\-\- \& print asn1_to_string($tree); \& \& # \-\-\- encode a decoded tree \-\-\- \& my $der2 = asn1_encode_der($tree); \& \& # \-\-\- build from scratch \-\-\- \& my $der = asn1_encode_der([{ \& type => \*(AqSEQUENCE\*(Aq, \& value => [ \& { type => \*(AqINTEGER\*(Aq, value => \*(Aq42\*(Aq }, \& { type => \*(AqBOOLEAN\*(Aq, value => 1 }, \& { type => \*(AqOID\*(Aq, value => \*(Aq1.2.840.113549.1.1.11\*(Aq }, \& { type => \*(AqUTF8_STRING\*(Aq, value => \*(Aqhello\*(Aq }, \& { type => \*(AqOCTET_STRING\*(Aq, value => "\ex00\ex01\ex02" }, \& { type => \*(AqBIT_STRING\*(Aq, value => "\ex03\ex02\ex01", bits => 20 }, \& { type => \*(AqNULL\*(Aq }, \& { type => \*(AqUTCTIME\*(Aq, value => \*(Aq2025\-06\-15T12:00:00Z\*(Aq }, \& { type => \*(AqCUSTOM\*(Aq, class => \*(AqCONTEXT_SPECIFIC\*(Aq, \& constructed => 1, tag => 0, \& value => [{ type => \*(AqINTEGER\*(Aq, value => \*(Aq2\*(Aq }] }, \& ], \& }]); .Ve .SH DESCRIPTION .IX Header "DESCRIPTION" \&\fISince: CryptX\-0.089\fR .PP Parses DER\-encoded ASN.1 data into a Perl data structure without requiring any schema, and encodes Perl data structures back to DER. Uses libtomcrypt\*(Aqs \f(CW\*(C`der_decode_sequence_flexi\*(C'\fR for decoding. .PP Both the decoder output and the encoder input use the same \fBnode hash\fR structure described below. When given a tree produced by the decoder, the encoder does its best to produce the same ASN.1 that was originally parsed, regardless of what decode options were used. .SH EXPORT .IX Header "EXPORT" Nothing is exported by default. .PP You can export selected functions: .PP .Vb 1 \& use Crypt::ASN1 qw(asn1_decode_der asn1_encode_der); .Ve .PP Or all of them at once: .PP .Vb 1 \& use Crypt::ASN1 \*(Aq:all\*(Aq; .Ve .SH "NODE HASH STRUCTURE" .IX Header "NODE HASH STRUCTURE" Both the decoder and encoder operate on the same data structure: an \fBarrayref of node hashrefs\fR. Each hashref represents one ASN.1 TLV (Tag\-Length\-Value) element. .SS "Common keys" .IX Subsection "Common keys" Every node has three keys: .ie n .IP """type"" (string, required)" 4 .el .IP "\f(CWtype\fR (string, required)" 4 .IX Item "type (string, required)" The ASN.1 type name. Built\-in values include: .Sp .Vb 5 \& BOOLEAN INTEGER NULL OID \& OCTET_STRING BIT_STRING UTF8_STRING \& PRINTABLE_STRING IA5_STRING TELETEX_STRING \& UTCTIME GENERALIZEDTIME \& SEQUENCE SET CUSTOM .Ve .Sp The list above is not exhaustive for decoded input. If the decoder encounters an ASN.1 tag that does not map to one of the built\-in type names above, it is returned as \f(CW\*(C`CUSTOM\*(C'\fR with the appropriate \f(CW\*(C`class\*(C'\fR, \f(CW\*(C`constructed\*(C'\fR, and \&\f(CW\*(C`tag\*(C'\fR fields. This includes unsupported universal tags such as \&\f(CW\*(C`ENUMERATED\*(C'\fR, which decode as \f(CW\*(C`CUSTOM\*(C'\fR with \f(CW\*(C`class => "UNIVERSAL"\*(C'\fR. .ie n .IP """value"" (varies, required for most types)" 4 .el .IP "\f(CWvalue\fR (varies, required for most types)" 4 .IX Item "value (varies, required for most types)" The decoded value. Its Perl type depends on \f(CW\*(C`type\*(C'\fR and sometimes on the \&\f(CW\*(C`format\*(C'\fR key \-\- see "Per\-type details" below. .ie n .IP """format"" (string, decoder sets it, encoder reads it)" 4 .el .IP "\f(CWformat\fR (string, decoder sets it, encoder reads it)" 4 .IX Item "format (string, decoder sets it, encoder reads it)" Tells the encoder how the \f(CW\*(C`value\*(C'\fR is represented so it can convert it back to DER. Set automatically by the decoder; when building nodes from scratch you may omit it \-\- the encoder then assumes the default representation for each type. .SS "Per\-type details" .IX Subsection "Per-type details" Each subsection below documents one \f(CW\*(C`type\*(C'\fR. For types where the \f(CW\*(C`value\*(C'\fR representation depends on the decode option used, a \fBformat table\fR lists every \f(CW\*(C`format\*(C'\fR/\f(CW\*(C`value\*(C'\fR combination. \fBThe encoder accepts every combination shown\fR \-\- it reads \f(CW\*(C`format\*(C'\fR and converts \f(CW\*(C`value\*(C'\fR back to DER automatically. .PP \fIBOOLEAN\fR .IX Subsection "BOOLEAN" .PP \&\fBKeys\fR: \f(CW\*(C`type\*(C'\fR, \f(CW\*(C`format\*(C'\fR, \f(CW\*(C`value\*(C'\fR. .PP \&\f(CW\*(C`value\*(C'\fR is \f(CW1\fR (true) or \f(CW0\fR (false). \f(CW\*(C`format\*(C'\fR is always \f(CW"bool"\fR. .PP .Vb 1 \& { type => "BOOLEAN", format => "bool", value => 1 } .Ve .PP \fIINTEGER\fR .IX Subsection "INTEGER" .PP \&\fBKeys\fR: \f(CW\*(C`type\*(C'\fR, \f(CW\*(C`format\*(C'\fR, \f(CW\*(C`value\*(C'\fR. .PP \&\f(CW\*(C`value\*(C'\fR is an arbitrary\-precision signed integer. \f(CW\*(C`format\*(C'\fR describes the representation: .PP .Vb 5 \& format value decode option example \& \-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\-\-\-\-\- \& decimal decimal string (default) "255" \& hex lowercase hex string int => \*(Aqhex\*(Aq "ff" \& bytes big\-endian binary string int => \*(Aqbytes\*(Aq "\exff" .Ve .PP All three forms are accepted by the encoder. When \f(CW\*(C`format\*(C'\fR is absent the encoder treats \f(CW\*(C`value\*(C'\fR as a decimal string (a Perl integer is fine too). .PP Negative integers: \f(CW\*(C`decimal\*(C'\fR and \f(CW\*(C`hex\*(C'\fR carry a leading \f(CW\*(C`\-\*(C'\fR (e.g. \f(CW"\-5"\fR). \&\f(CW\*(C`bytes\*(C'\fR stores the unsigned magnitude only and is intended for naturally unsigned values such as RSA moduli. When decoding with \f(CW\*(C`int => \*(Aqbytes\*(Aq\*(C'\fR, negative ASN.1 INTEGER values are rejected. .PP \fINULL\fR .IX Subsection "NULL" .PP \&\fBKeys\fR: \f(CW\*(C`type\*(C'\fR, \f(CW\*(C`format\*(C'\fR, \f(CW\*(C`value\*(C'\fR. .PP \&\f(CW\*(C`value\*(C'\fR is always \f(CW\*(C`undef\*(C'\fR. \f(CW\*(C`format\*(C'\fR is always \f(CW"null"\fR. The encoder ignores \f(CW\*(C`value\*(C'\fR. .PP .Vb 1 \& { type => "NULL", format => "null", value => undef } .Ve .PP \fIOID\fR .IX Subsection "OID" .PP \&\fBKeys\fR: \f(CW\*(C`type\*(C'\fR, \f(CW\*(C`format\*(C'\fR, \f(CW\*(C`value\*(C'\fR, and optionally \f(CW\*(C`name\*(C'\fR. .PP \&\f(CW\*(C`value\*(C'\fR is a dotted\-decimal OID string (at least two arcs). \f(CW\*(C`format\*(C'\fR is always \f(CW"oid"\fR. .PP .Vb 1 \& { type => "OID", format => "oid", value => "1.2.840.113549.1.1.11" } .Ve .PP As a convenience, the encoder accepts textual arcs with leading zeros and lets DER encoding canonicalize them. For example, \f(CW"2.000.1"\fR encodes and decodes back as \f(CW"2.0.1"\fR. .PP \&\fBOptional key\fR: \f(CW\*(C`name\*(C'\fR \-\- present only when the \f(CW\*(C`oidmap\*(C'\fR decode option is supplied and the OID is found in the map. Ignored by the encoder. .PP .Vb 1 \& { ..., name => "sha256WithRSAEncryption" } # when oidmap matches .Ve .PP \fIOCTET_STRING\fR .IX Subsection "OCTET_STRING" .PP \&\fBKeys\fR: \f(CW\*(C`type\*(C'\fR, \f(CW\*(C`format\*(C'\fR, \f(CW\*(C`value\*(C'\fR. .PP \&\f(CW\*(C`value\*(C'\fR is binary data. \f(CW\*(C`format\*(C'\fR describes the representation: .PP .Vb 5 \& format value decode option example \& \-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\- \& bytes raw binary string (default) "\ex04\ex01" \& hex lowercase hex string bin => \*(Aqhex\*(Aq "0401" \& base64 Base64\-encoded string bin => \*(Aqbase64\*(Aq "BAE=" .Ve .PP All three forms are accepted by the encoder. When \f(CW\*(C`format\*(C'\fR is absent the encoder treats \f(CW\*(C`value\*(C'\fR as raw bytes. .PP \fIBIT_STRING\fR .IX Subsection "BIT_STRING" .PP \&\fBKeys\fR: \f(CW\*(C`type\*(C'\fR, \f(CW\*(C`format\*(C'\fR, \f(CW\*(C`value\*(C'\fR, \f(CW\*(C`bits\*(C'\fR. .PP \&\f(CW\*(C`value\*(C'\fR is the packed bit data (MSB\-first). \f(CW\*(C`format\*(C'\fR follows the same rules as \f(CW\*(C`OCTET_STRING\*(C'\fR (\f(CW"bytes"\fR, \f(CW"hex"\fR, or \f(CW"base64"\fR). All three forms are accepted by the encoder. .PP \&\f(CW\*(C`bits\*(C'\fR is the exact number of significant bits. The quantity \&\f(CW\*(C`8 * byte_length(value) \- bits\*(C'\fR gives the number of unused trailing bits in the last byte. .PP When \f(CW\*(C`format\*(C'\fR is absent the encoder treats \f(CW\*(C`value\*(C'\fR as raw bytes. When \&\f(CW\*(C`bits\*(C'\fR is absent it defaults to \f(CW\*(C`8 * length(value)\*(C'\fR (no unused bits). .PP .Vb 3 \& # default format (raw bytes, 25 significant bits) \& { type => "BIT_STRING", format => "bytes", \& value => "\ex03\ex02\ex01\ex00", bits => 25 } \& \& # hex format \& { type => "BIT_STRING", format => "hex", \& value => "03020100", bits => 25 } .Ve .PP \fIUTF8_STRING\fR .IX Subsection "UTF8_STRING" .PP \&\fBKeys\fR: \f(CW\*(C`type\*(C'\fR, \f(CW\*(C`format\*(C'\fR, \f(CW\*(C`value\*(C'\fR. .PP \&\f(CW\*(C`value\*(C'\fR is a Perl Unicode string (\f(CW\*(C`utf8\*(C'\fR flag on). \f(CW\*(C`format\*(C'\fR is always \&\f(CW"utf8"\fR. .PP .Vb 1 \& { type => "UTF8_STRING", format => "utf8", value => "caf\ex{e9}" } .Ve .PP \fIPRINTABLE_STRING, IA5_STRING, TELETEX_STRING\fR .IX Subsection "PRINTABLE_STRING, IA5_STRING, TELETEX_STRING" .PP \&\fBKeys\fR: \f(CW\*(C`type\*(C'\fR, \f(CW\*(C`format\*(C'\fR, \f(CW\*(C`value\*(C'\fR. .PP \&\f(CW\*(C`value\*(C'\fR is a byte string. \f(CW\*(C`format\*(C'\fR is always \f(CW"string"\fR for all three. .PP .Vb 3 \& { type => "PRINTABLE_STRING", format => "string", value => "abc" } \& { type => "IA5_STRING", format => "string", value => "ia5" } \& { type => "TELETEX_STRING", format => "string", value => "tele" } .Ve .PP \fIUTCTIME\fR .IX Subsection "UTCTIME" .PP \&\fBKeys\fR: \f(CW\*(C`type\*(C'\fR, \f(CW\*(C`format\*(C'\fR, \f(CW\*(C`value\*(C'\fR. .PP \&\f(CW\*(C`value\*(C'\fR is a timestamp. \f(CW\*(C`format\*(C'\fR describes the representation: .PP .Vb 4 \& format value decode option example \& \-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- \& rfc3339 RFC 3339 string (default) "2024\-01\-15T10:30:00Z" \& epoch Unix timestamp (integer) dt => \*(Aqepoch\*(Aq 1705314600 .Ve .PP Both forms are accepted by the encoder. When \f(CW\*(C`format\*(C'\fR is absent, the encoder auto\-detects: an all\-digit value is treated as epoch, a value matching \f(CW\*(C`YYYY\-\*(C'\fR is treated as RFC 3339. .PP For \f(CW\*(C`UTCTIME\*(C'\fR, encoder input must fall within the UTCTime year window \&\f(CW1950..2049\fR; values outside that range are rejected. Fractional seconds are also rejected for \f(CW\*(C`UTCTIME\*(C'\fR. .PP Time validation in the encoder is currently \fBsyntactic\fR, not full calendar validation. The encoder checks the accepted input shape and ASN.1\-specific constraints above, but it does not verify that every RFC 3339\-looking date and time is semantically valid. .PP The decoder expands the 2\-digit UTCTime year using the RFC 5280 window (YY >= 50 → 19YY, else 20YY). Timezone offsets are preserved (e.g. \f(CW"2024\-01\-15T10:30:00+05:30"\fR). .PP \fIGENERALIZEDTIME\fR .IX Subsection "GENERALIZEDTIME" .PP \&\fBKeys\fR: \f(CW\*(C`type\*(C'\fR, \f(CW\*(C`format\*(C'\fR, \f(CW\*(C`value\*(C'\fR. .PP Same \f(CW\*(C`format\*(C'\fR rules as \f(CW\*(C`UTCTIME\*(C'\fR; both forms are accepted by the encoder. Fractional seconds are preserved (e.g. \f(CW"2024\-01\-15T10:30:00.125Z"\fR). Validation is likewise syntactic only; semantically invalid calendar values that match the accepted timestamp syntax are not currently rejected. .PP \fISEQUENCE\fR .IX Subsection "SEQUENCE" .PP \&\fBKeys\fR: \f(CW\*(C`type\*(C'\fR, \f(CW\*(C`format\*(C'\fR, \f(CW\*(C`value\*(C'\fR. .PP \&\f(CW\*(C`value\*(C'\fR is an arrayref of child node hashrefs (in order). \f(CW\*(C`format\*(C'\fR is always \f(CW"array"\fR. .PP .Vb 1 \& { type => "SEQUENCE", format => "array", value => [ ...children... ] } .Ve .PP \fISET\fR .IX Subsection "SET" .PP \&\fBKeys\fR: \f(CW\*(C`type\*(C'\fR, \f(CW\*(C`format\*(C'\fR, \f(CW\*(C`value\*(C'\fR. .PP Same structure as \f(CW\*(C`SEQUENCE\*(C'\fR. \f(CW\*(C`format\*(C'\fR is always \f(CW"array"\fR. Both ASN.1 SET and SET OF are represented as \f(CW\*(C`type => "SET"\*(C'\fR (they share the same DER tag \f(CW0x31\fR). .PP \fICUSTOM\fR .IX Subsection "CUSTOM" .PP Represents any tag that does not map to one of the built\-in type names above. This is commonly used for context\-specific implicit/explicit tags (\f(CW\*(C`[0]\*(C'\fR, \&\f(CW\*(C`[1]\*(C'\fR, ...) found in X.509 certificates and other ASN.1 schemas, but it can also be emitted by the decoder for unsupported universal tags. .PP \&\fBKeys\fR: \f(CW\*(C`type\*(C'\fR, \f(CW\*(C`format\*(C'\fR, \f(CW\*(C`value\*(C'\fR, \f(CW\*(C`class\*(C'\fR, \f(CW\*(C`constructed\*(C'\fR, \f(CW\*(C`tag\*(C'\fR. .ie n .IP """class"" (string) \-\- ""CONTEXT_SPECIFIC"", ""APPLICATION"", ""UNIVERSAL"", or ""PRIVATE""" 4 .el .IP "\f(CWclass\fR (string) \-\- \f(CW""CONTEXT_SPECIFIC""\fR, \f(CW""APPLICATION""\fR, \f(CW""UNIVERSAL""\fR, or \f(CW""PRIVATE""\fR" 4 .IX Item "class (string) -- ""CONTEXT_SPECIFIC"", ""APPLICATION"", ""UNIVERSAL"", or ""PRIVATE""" .PD 0 .ie n .IP """constructed"" (integer) \-\- 1 if constructed, 0 if primitive" 4 .el .IP "\f(CWconstructed\fR (integer) \-\- \f(CW1\fR if constructed, \f(CW0\fR if primitive" 4 .IX Item "constructed (integer) -- 1 if constructed, 0 if primitive" .ie n .IP """tag"" (integer) \-\- the tag number (e.g. 0 for ""[0]"")" 4 .el .IP "\f(CWtag\fR (integer) \-\- the tag number (e.g. \f(CW0\fR for \f(CW[0]\fR)" 4 .IX Item "tag (integer) -- the tag number (e.g. 0 for [0])" .PD Must be a non\-negative integer within the range supported by the current encoder build. .PP \&\fBConstructed\fR (\f(CW\*(C`constructed => 1\*(C'\fR): \f(CW\*(C`value\*(C'\fR is an arrayref of child nodes. \f(CW\*(C`format\*(C'\fR is \f(CW"array"\fR. .PP .Vb 3 \& { type => "CUSTOM", format => "array", \& class => "CONTEXT_SPECIFIC", constructed => 1, tag => 0, \& value => [ { type => "INTEGER", ... } ] } .Ve .PP \&\fBPrimitive\fR (\f(CW\*(C`constructed => 0\*(C'\fR): \f(CW\*(C`value\*(C'\fR is raw data. \f(CW\*(C`format\*(C'\fR follows the same rules as \f(CW\*(C`OCTET_STRING\*(C'\fR (\f(CW"bytes"\fR, \f(CW"hex"\fR, or \&\f(CW"base64"\fR depending on the \f(CW\*(C`bin\*(C'\fR decode option). All three forms are accepted by the encoder. Primitive \f(CW\*(C`CUSTOM\*(C'\fR values must not be references. .PP .Vb 4 \& # default format \& { type => "CUSTOM", format => "bytes", \& class => "CONTEXT_SPECIFIC", constructed => 0, tag => 1, \& value => "\exAA\exBB" } \& \& # hex format (bin => \*(Aqhex\*(Aq) \& { type => "CUSTOM", format => "hex", \& class => "CONTEXT_SPECIFIC", constructed => 0, tag => 1, \& value => "aabb" } .Ve .SS "Re\-encoding Decoded Trees" .IX Subsection "Re-encoding Decoded Trees" The encoder reads \f(CW\*(C`format\*(C'\fR and converts \f(CW\*(C`value\*(C'\fR back to DER before encoding. When given a tree returned by \f(CW\*(C`asn1_decode_der\*(C'\fR, it does its best to produce the same ASN.1 that was originally parsed, regardless of the decode options used: .PP .Vb 2 \& my $tree = asn1_decode_der($der, { int=>\*(Aqhex\*(Aq, bin=>\*(Aqbase64\*(Aq, dt=>\*(Aqepoch\*(Aq }); \& my $der2 = asn1_encode_der($tree); .Ve .SS "Building nodes from scratch" .IX Subsection "Building nodes from scratch" When constructing nodes by hand you need \f(CW\*(C`type\*(C'\fR and \f(CW\*(C`value\*(C'\fR (plus the extra keys noted above for \f(CW\*(C`CUSTOM\*(C'\fR and \f(CW\*(C`BIT_STRING\*(C'\fR). You may omit \&\f(CW\*(C`format\*(C'\fR; the encoder assumes: .PP .Vb 8 \& Type default value interpretation \& \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- \& INTEGER decimal string or Perl integer \& OCTET_STRING raw bytes \& BIT_STRING raw packed bytes, bits = length(value) * 8 \& UTCTIME RFC 3339 string (or all\-digit epoch) \& GENERALIZEDTIME RFC 3339 string (or all\-digit epoch) \& CUSTOM primitive raw bytes .Ve .PP You may also supply \f(CW\*(C`format\*(C'\fR explicitly if you prefer to work with hex or base64 representations: .PP .Vb 3 \& # these two produce identical DER \& { type => "OCTET_STRING", value => "\ex04\ex01" } \& { type => "OCTET_STRING", format => "hex", value => "0401" } .Ve .SH FUNCTIONS .IX Header "FUNCTIONS" .SS asn1_decode_der .IX Subsection "asn1_decode_der" .Vb 2 \& my $tree = asn1_decode_der($der_bytes); \& my $tree = asn1_decode_der($der_bytes, \e%opts); .Ve .PP Parses \f(CW$der_bytes\fR and returns an arrayref of top\-level node hashrefs. Croaks on parse error. .PP The optional \f(CW%opts\fR hashref controls value formatting: .ie n .IP """int => \*(Aqhex\*(Aq | \*(Aqbytes\*(Aq""" 4 .el .IP "\f(CWint => \*(Aqhex\*(Aq | \*(Aqbytes\*(Aq\fR" 4 .IX Item "int => 'hex' | 'bytes'" How to represent \f(CW\*(C`INTEGER\*(C'\fR values. Default is a decimal string (\f(CW\*(C`format=>"decimal"\*(C'\fR). \&\f(CW\*(Aqhex\*(Aq\fR gives a lowercase hex string (\f(CW\*(C`format=>"hex"\*(C'\fR). \&\f(CW\*(Aqbytes\*(Aq\fR gives a raw big\-endian binary string (\f(CW\*(C`format=>"bytes"\*(C'\fR) for non\-negative INTEGER values only; decoding croaks if the DER INTEGER is negative. .ie n .IP """bin => \*(Aqhex\*(Aq | \*(Aqbase64\*(Aq""" 4 .el .IP "\f(CWbin => \*(Aqhex\*(Aq | \*(Aqbase64\*(Aq\fR" 4 .IX Item "bin => 'hex' | 'base64'" How to represent \f(CW\*(C`OCTET_STRING\*(C'\fR, \f(CW\*(C`BIT_STRING\*(C'\fR, and primitive \f(CW\*(C`CUSTOM\*(C'\fR values. Default is raw binary bytes (\f(CW\*(C`format=>"bytes"\*(C'\fR). \&\f(CW\*(Aqhex\*(Aq\fR gives a lowercase hex string (\f(CW\*(C`format=>"hex"\*(C'\fR). \&\f(CW\*(Aqbase64\*(Aq\fR gives a Base64\-encoded string (\f(CW\*(C`format=>"base64"\*(C'\fR). .ie n .IP """dt => \*(Aqepoch\*(Aq""" 4 .el .IP "\f(CWdt => \*(Aqepoch\*(Aq\fR" 4 .IX Item "dt => 'epoch'" How to represent \f(CW\*(C`UTCTIME\*(C'\fR and \f(CW\*(C`GENERALIZEDTIME\*(C'\fR values. Default is an RFC 3339 string (\f(CW\*(C`format=>"rfc3339"\*(C'\fR). \&\f(CW\*(Aqepoch\*(Aq\fR gives a Unix timestamp integer (\f(CW\*(C`format=>"epoch"\*(C'\fR). This works reliably only on Perls with 64\-bit integers; on 32\-bit integer Perls, large timestamps may overflow or lose precision. .ie n .IP """oidmap => \e%map""" 4 .el .IP "\f(CWoidmap => \e%map\fR" 4 .IX Item "oidmap => %map" A hashref mapping dotted OID strings to friendly names. When a decoded \&\f(CW\*(C`OID\*(C'\fR node\*(Aqs value exists as a key in \f(CW%map\fR, the node gets an additional \&\f(CW\*(C`name\*(C'\fR key with the mapped value. Does not affect encoding. .SS asn1_decode_pem .IX Subsection "asn1_decode_pem" .Vb 2 \& my $tree = asn1_decode_pem($pem_string); \& my $tree = asn1_decode_pem($pem_string, \e%opts); .Ve .PP Decodes the PEM envelope first (via "pem_to_der" in Crypt::Misc), then parses the resulting DER bytes. Accepts the same \f(CW%opts\fR as \f(CW\*(C`asn1_decode_der\*(C'\fR. .SS asn1_decode_der_file .IX Subsection "asn1_decode_der_file" .Vb 2 \& my $tree = asn1_decode_der_file($filename); \& my $tree = asn1_decode_der_file($filename, \e%opts); .Ve .PP Reads \f(CW$filename\fR as raw binary and parses it as DER. .SS asn1_decode_pem_file .IX Subsection "asn1_decode_pem_file" .Vb 2 \& my $tree = asn1_decode_pem_file($filename); \& my $tree = asn1_decode_pem_file($filename, \e%opts); .Ve .PP Reads \f(CW$filename\fR, decodes the PEM envelope, then parses the DER bytes. .SS asn1_encode_der .IX Subsection "asn1_encode_der" .Vb 1 \& my $der_bytes = asn1_encode_der($tree); .Ve .PP Encodes \f(CW$tree\fR (an arrayref of node hashrefs) to DER bytes. The input may be a tree previously returned by \f(CW\*(C`asn1_decode_der\*(C'\fR or one built from scratch. Croaks on invalid input. .PP The encoder normalizes every node before encoding: it reads \f(CW\*(C`format\*(C'\fR (if present) to determine how to interpret \f(CW\*(C`value\*(C'\fR, converts it to the canonical DER form, and encodes it. .PP The current low\-level encoder supports element content lengths up to \&\f(CW0xffffffff\fR bytes; larger values are rejected. .SS asn1_encode_pem .IX Subsection "asn1_encode_pem" .Vb 1 \& my $pem_string = asn1_encode_pem($tree, $header); .Ve .PP Encodes \f(CW$tree\fR to DER, then wraps in a PEM envelope with the given \&\f(CW$header\fR (e.g. \f(CW"CERTIFICATE"\fR, \f(CW"RSA PRIVATE KEY"\fR). Defaults to \&\f(CW"DATA"\fR if \f(CW$header\fR is omitted. .SS asn1_encode_der_file .IX Subsection "asn1_encode_der_file" .Vb 1 \& asn1_encode_der_file($tree, $filename); .Ve .PP Encodes \f(CW$tree\fR to DER and writes it to \f(CW$filename\fR. .SS asn1_encode_pem_file .IX Subsection "asn1_encode_pem_file" .Vb 1 \& asn1_encode_pem_file($tree, $header, $filename); .Ve .PP Encodes \f(CW$tree\fR to PEM and writes it to \f(CW$filename\fR. .SS asn1_to_string .IX Subsection "asn1_to_string" .Vb 1 \& my $text = asn1_to_string($tree); .Ve .PP Returns a human\-readable text representation of \f(CW$tree\fR (an arrayref of node hashrefs as returned by any \f(CW\*(C`asn1_decode_*\*(C'\fR function). Useful for debugging and inspection, similar to \f(CW\*(C`openssl asn1parse\*(C'\fR output. .PP .Vb 1 \& print asn1_to_string(asn1_decode_pem_file("cert.pem")); .Ve .PP produces output like: .PP .Vb 10 \& SEQUENCE (3 elem) \& SEQUENCE (8 elem) \& context_specific [0] cons (1 elem) \& INTEGER:2 \& INTEGER:17923815188543234454 \& SEQUENCE (2 elem) \& OBJECT:1.2.840.113549.1.1.11 \& NULL: \& ... \& BIT STRING:3082010a0282010100c242299a49420c21dcf9b957afcdc49... (2160 bit) .Ve .PP Binary values (\f(CW\*(C`OCTET_STRING\*(C'\fR, \f(CW\*(C`BIT_STRING\*(C'\fR, primitive \f(CW\*(C`CUSTOM\*(C'\fR) are shown as lowercase hex, truncated to 64 characters with \f(CW\*(C`...\*(C'\fR for longer values. \f(CW\*(C`BIT_STRING\*(C'\fR additionally shows the bit count in parentheses. \&\f(CW\*(C`OID\*(C'\fR nodes that have a \f(CW\*(C`name\*(C'\fR key (via \f(CW\*(C`oidmap\*(C'\fR) show the name in parentheses after the dotted value. .PP The function handles trees decoded with any combination of decode options (\f(CW\*(C`int\*(C'\fR, \f(CW\*(C`bin\*(C'\fR, \f(CW\*(C`dt\*(C'\fR). .SH "SEE ALSO" .IX Header "SEE ALSO" CryptX, Crypt::Misc