125f16eeaSchristos 225f16eeaSchristos#------------------------------------------------------------------------------ 3*a77ebd86Schristos# $File: pgp-binary-keys,v 1.2 2021/04/26 15:56:00 christos Exp $ 425f16eeaSchristos# pgp-binary-keys: This file handles pgp binary keys. 525f16eeaSchristos# 625f16eeaSchristos# An PGP certificate or message doesn't have a fixed header. Instead, 725f16eeaSchristos# they are sequences of packets: 825f16eeaSchristos# 925f16eeaSchristos# https://tools.ietf.org/html/rfc4880#section-4.3 1025f16eeaSchristos# 1125f16eeaSchristos# whose order conforms to a grammar: 1225f16eeaSchristos# 1325f16eeaSchristos# https://tools.ietf.org/html/rfc4880#section-11 1425f16eeaSchristos# 1525f16eeaSchristos# Happily most packets have a few fields that are constrained, which 1625f16eeaSchristos# allow us to fingerprint them with relatively high certainty. 1725f16eeaSchristos# 1825f16eeaSchristos# A PGP packet is described by a single byte: the so-called CTB. The 1925f16eeaSchristos# high-bit is always set. If bit 6 is set, then it is a so-called 2025f16eeaSchristos# new-style CTB; if bit 6 is clear, then it is a so-called old-style 2125f16eeaSchristos# CTB. Old-style CTBs have only four bits of type information; bits 2225f16eeaSchristos# 1-0 are used to describe the length. New-style CTBs have 6 bits of 2325f16eeaSchristos# type information. 2425f16eeaSchristos# 2525f16eeaSchristos# Following the CTB is the packet's length in bytes. If we blindly 2625f16eeaSchristos# advance the file cursor by this amount past the end of the length 2725f16eeaSchristos# information we come to the next packet. 2825f16eeaSchristos# 2925f16eeaSchristos# Data Structures 3025f16eeaSchristos# =============== 3125f16eeaSchristos# 3225f16eeaSchristos# New Style CTB 3325f16eeaSchristos# ------------- 3425f16eeaSchristos# 3525f16eeaSchristos# https://tools.ietf.org/html/rfc4880#section-4.2.2 3625f16eeaSchristos# 3725f16eeaSchristos# 76543210 3825f16eeaSchristos# ||\----/ 3925f16eeaSchristos# || tag 4025f16eeaSchristos# |always 1 4125f16eeaSchristos# always 1 4225f16eeaSchristos# 4325f16eeaSchristos# Tag bits 7 and 6 set 4425f16eeaSchristos# 0 0xC0 -- Reserved - a packet tag MUST NOT have this value 4525f16eeaSchristos# 1 0xC1 -- Public-Key Encrypted Session Key Packet 4625f16eeaSchristos# 2 0xC2 -- Signature Packet 4725f16eeaSchristos# 3 0xC3 -- Symmetric-Key Encrypted Session Key Packet 4825f16eeaSchristos# 4 0xC4 -- One-Pass Signature Packet 4925f16eeaSchristos# 5 0xC5 -- Secret-Key Packet 5025f16eeaSchristos# 6 0xC6 -- Public-Key Packet 5125f16eeaSchristos# 7 0xC7 -- Secret-Subkey Packet 5225f16eeaSchristos# 8 0xC8 -- Compressed Data Packet 5325f16eeaSchristos# 9 0xC9 -- Symmetrically Encrypted Data Packet 5425f16eeaSchristos# 10 0xCA -- Marker Packet 5525f16eeaSchristos# 11 0xCB -- Literal Data Packet 5625f16eeaSchristos# 12 0xCC -- Trust Packet 5725f16eeaSchristos# 13 0xCD -- User ID Packet 5825f16eeaSchristos# 14 0xCE -- Public-Subkey Packet 5925f16eeaSchristos# 17 0xD1 -- User Attribute Packet 6025f16eeaSchristos# 18 0xD2 -- Sym. Encrypted and Integrity Protected Data Packet 6125f16eeaSchristos# 19 0xD3 -- Modification Detection Code Packet 6225f16eeaSchristos# 60 to 63 -- Private or Experimental Values 6325f16eeaSchristos# 6425f16eeaSchristos# The CTB is followed by the length header, which is densely encoded: 6525f16eeaSchristos# 6625f16eeaSchristos# if length[0] is: 6725f16eeaSchristos# 0..191: one byte length (length[0]) 6825f16eeaSchristos# 192..223: two byte length ((length[0] - 192) * 256 + length[2] + 192 6925f16eeaSchristos# 224..254: four byte length (big endian interpretation of length[1..5]) 7025f16eeaSchristos# 255: partial body encoding 7125f16eeaSchristos# 7225f16eeaSchristos# The partial body encoding is similar to HTTP's chunk encoding. It 7325f16eeaSchristos# is only allowed for container packets (SEIP, Compressed Data and 7425f16eeaSchristos# Literal). 7525f16eeaSchristos# 7625f16eeaSchristos# Old Style CTB 7725f16eeaSchristos# ------------- 7825f16eeaSchristos# 7925f16eeaSchristos# https://tools.ietf.org/html/rfc4880#section-4.2.1 8025f16eeaSchristos# 8125f16eeaSchristos# CTB: 8225f16eeaSchristos# 8325f16eeaSchristos# 76543210 8425f16eeaSchristos# ||\--/\/ 8525f16eeaSchristos# || | length encoding 8625f16eeaSchristos# || tag 8725f16eeaSchristos# |always 0 8825f16eeaSchristos# always 1 8925f16eeaSchristos# 9025f16eeaSchristos# Tag: 9125f16eeaSchristos# 9225f16eeaSchristos# Tag bit 7 set, bits 6, 1, 0 clear 9325f16eeaSchristos# 0 0x80 -- Reserved - a packet tag MUST NOT have this value 9425f16eeaSchristos# 1 0x84 -- Public-Key Encrypted Session Key Packet 9525f16eeaSchristos# 2 0x88 -- Signature Packet 9625f16eeaSchristos# 3 0x8C -- Symmetric-Key Encrypted Session Key Packet 9725f16eeaSchristos# 4 0x90 -- One-Pass Signature Packet 9825f16eeaSchristos# 5 0x94 -- Secret-Key Packet 9925f16eeaSchristos# 6 0x98 -- Public-Key Packet 10025f16eeaSchristos# 7 0x9C -- Secret-Subkey Packet 10125f16eeaSchristos# 8 0xA0 -- Compressed Data Packet 10225f16eeaSchristos# 9 0xA4 -- Symmetrically Encrypted Data Packet 10325f16eeaSchristos# 10 0xA8 -- Marker Packet 10425f16eeaSchristos# 11 0xAC -- Literal Data Packet 10525f16eeaSchristos# 12 0xB0 -- Trust Packet 10625f16eeaSchristos# 13 0xB4 -- User ID Packet 10725f16eeaSchristos# 14 0xB8 -- Public-Subkey Packet 10825f16eeaSchristos# 10925f16eeaSchristos# Length encoding: 11025f16eeaSchristos# 11125f16eeaSchristos# Value 11225f16eeaSchristos# 0 1 byte length (following byte is the length) 11325f16eeaSchristos# 1 2 byte length (following two bytes are the length) 11425f16eeaSchristos# 2 4 byte length (following four bytes are the length) 11525f16eeaSchristos# 3 indeterminate length: natural end of packet, e.g., EOF 11625f16eeaSchristos# 11725f16eeaSchristos# An indeterminate length is only allowed for container packets 11825f16eeaSchristos# (SEIP, Compressed Data and Literal). 11925f16eeaSchristos# 12025f16eeaSchristos# Certificates 12125f16eeaSchristos# ------------ 12225f16eeaSchristos# 12325f16eeaSchristos# We check the first three packets to determine if a sequence of 12425f16eeaSchristos# OpenPGP packets is likely to be a certificate. The grammar allows 12525f16eeaSchristos# the following prefixes: 12625f16eeaSchristos# 12725f16eeaSchristos# [Primary Key] [SIG] (EOF or another certificate) 12825f16eeaSchristos# [Primary Key] [SIG] [User ID] [SIG]... 12925f16eeaSchristos# [Primary Key] [SIG] [User Attribute] [SIG]... 13025f16eeaSchristos# [Primary Key] [SIG] [Subkey] [SIG]... 13125f16eeaSchristos# [Primary Key] [User ID] [SIG]... 13225f16eeaSchristos# [Primary Key] [User Attribute] [SIG]... 13325f16eeaSchristos# [Primary Key] [Subkey] [SIG]... 13425f16eeaSchristos# 13525f16eeaSchristos# Any number of marker packets are also allowed between each packet, 13625f16eeaSchristos# but they are not normally used and we don't currently check for 13725f16eeaSchristos# them. 13825f16eeaSchristos# 13925f16eeaSchristos# The keys and subkeys may be public or private. 14025f16eeaSchristos# 14125f16eeaSchristos 14225f16eeaSchristos# Key packets and signature packets are versioned. There are two 14325f16eeaSchristos# packet versions that we need to worry about in practice: v3 and v4. 14425f16eeaSchristos# v4 packets were introduced in RFC 2440, which was published in 1998. 14525f16eeaSchristos# It also deprecated v3 packets. There are no actively used v3 14625f16eeaSchristos# certificates (GnuPG removed the code to support them in November 14725f16eeaSchristos# 2014). But there are v3 keys lying around and it is useful to 14825f16eeaSchristos# identify them. The next version of OpenPGP will introduce v5 keys. 14925f16eeaSchristos# The document has not yet been standardized so changes are still 15025f16eeaSchristos# possible. But, for our purposes, it appears that v5 data structures 15125f16eeaSchristos# will be identical to v4 data structures modulo the version number. 15225f16eeaSchristos# 15325f16eeaSchristos# https://tools.ietf.org/html/rfc2440 15425f16eeaSchristos# https://lists.gnupg.org/pipermail/gnupg-announce/2014q4/000358.html 15525f16eeaSchristos# https://www.ietf.org/id/draft-ietf-openpgp-rfc4880bis-09.html#name-key-material-packet 15625f16eeaSchristos 15725f16eeaSchristos 15825f16eeaSchristos 15925f16eeaSchristos 16025f16eeaSchristos# The first packet has to be a public key or a secret key. 16125f16eeaSchristos# 16225f16eeaSchristos# New-Style Public Key 16325f16eeaSchristos0 ubyte =0xC6 OpenPGP Public Key 16425f16eeaSchristos>&0 use primary_key_length_new 16525f16eeaSchristos# New-Style Secret Key 16625f16eeaSchristos0 ubyte =0xC5 OpenPGP Secret Key 16725f16eeaSchristos>&0 use primary_key_length_new 16825f16eeaSchristos# Old-Style Public Key 16925f16eeaSchristos0 ubyte&0xFC =0x98 OpenPGP Public Key 17025f16eeaSchristos>&-1 use primary_key_length_old 17125f16eeaSchristos# Old-Style Secret Key 17225f16eeaSchristos0 ubyte&0xFC =0x94 OpenPGP Secret Key 17325f16eeaSchristos>&-1 use primary_key_length_old 17425f16eeaSchristos 17525f16eeaSchristos# Parse the length, check the packet's body and finally advance to the 17625f16eeaSchristos# next packet. 17725f16eeaSchristos 17825f16eeaSchristos# There are 4 different new-style length encodings, but the partial 17925f16eeaSchristos# body encoding is only acceptable for the SEIP, Compressed Data, and 18025f16eeaSchristos# Literal packets, which isn't valid for any packets in a certificate 18125f16eeaSchristos# so we ignore it. 18225f16eeaSchristos0 name primary_key_length_new 18325f16eeaSchristos>&0 ubyte <192 18425f16eeaSchristos#>>&0 ubyte x (1 byte length encoding, %d bytes) 18525f16eeaSchristos>>&0 use pgp_binary_key_pk_check 18625f16eeaSchristos>>>&(&-1.B) use sig_or_component_1 18725f16eeaSchristos>&0 ubyte >191 18825f16eeaSchristos>>&-1 ubyte <225 18925f16eeaSchristos# offset = ((offset[0] - 192) << 8) + offset[1] + 192 (for the length header) 19025f16eeaSchristos# raw - (192 * 256 - 192) 19125f16eeaSchristos# = 48960 19225f16eeaSchristos#>>>&0 ubeshort x (2 byte length encoding, %d bytes) 19325f16eeaSchristos>>>&1 use pgp_binary_key_pk_check 19425f16eeaSchristos>>>>&(&-2.S-48960) use sig_or_component_1 19525f16eeaSchristos>&0 ubyte =255 19625f16eeaSchristos#>>&0 belong x (5 byte length encoding, %d bytes) 19725f16eeaSchristos>>&4 use pgp_binary_key_pk_check 19825f16eeaSchristos>>>&(&-4.L) use sig_or_component_1 19925f16eeaSchristos# Partial body encoding (only valid for container packets). 20025f16eeaSchristos# >&0 ubyte >224 20125f16eeaSchristos# >>&0 ubyte <255 partial body encoding 20225f16eeaSchristos 20325f16eeaSchristos# There are 4 different old-style length encodings, but the 20425f16eeaSchristos# indeterminate length encoding is only acceptable for the SEIP, 20525f16eeaSchristos# Compressed Data, and Literal packets, which isn't valid for any 20625f16eeaSchristos# packets in a certificate. 20725f16eeaSchristos0 name primary_key_length_old 20825f16eeaSchristos#>&0 ubyte x (ctb: %x) 20925f16eeaSchristos>&0 ubyte&0x3 =0 21025f16eeaSchristos#>>&0 ubyte x (1 byte length encoding, %d bytes) 21125f16eeaSchristos>>&1 use pgp_binary_key_pk_check 21225f16eeaSchristos>>>&(&-1.B) use sig_or_component_1 21325f16eeaSchristos>&0 ubyte&0x3 =1 21425f16eeaSchristos#>>&0 ubeshort x (2 byte length encoding, %d bytes) 21525f16eeaSchristos>>&2 use pgp_binary_key_pk_check 21625f16eeaSchristos>>>&(&-2.S) use sig_or_component_1 21725f16eeaSchristos>&0 ubyte&0x3 =2 21825f16eeaSchristos#>>&0 ubelong x (4 byte length encoding, %d bytes) 21925f16eeaSchristos>>&4 use pgp_binary_key_pk_check 22025f16eeaSchristos>>>&(&-4.L) use sig_or_component_1 22125f16eeaSchristos 22225f16eeaSchristos# Check the Key. 22325f16eeaSchristos# 22425f16eeaSchristos# https://tools.ietf.org/html/rfc4880#section-5.5.2 22525f16eeaSchristos0 name pgp_binary_key_pk_check 22625f16eeaSchristos# Valid versions are: 2, 3, 4. 5 is proposed in RFC 4880bis. 22725f16eeaSchristos# Anticipate a v6 / v7 format that like v5 is compatible with v4. 22825f16eeaSchristos# key format in a decade or so :D. 22925f16eeaSchristos>&0 ubyte >1 23025f16eeaSchristos>>&-1 ubyte <8 23125f16eeaSchristos>>>&-1 byte x Version %d 23225f16eeaSchristos# Check that keys were created after 1990. 23325f16eeaSchristos# (1990 - 1970) * 365.2524 * 24 * 60 * 60 = 631156147 23425f16eeaSchristos>>>&0 bedate >631156147 \b, Created %s 23525f16eeaSchristos>>>>&-5 ubyte >3 23625f16eeaSchristos>>>>>&4 use pgp_binary_key_algo 23725f16eeaSchristos>>>>&-5 ubyte <4 23825f16eeaSchristos>>>>>&6 use pgp_binary_key_algo 23925f16eeaSchristos 24025f16eeaSchristos# Print out the key's algorithm and the number of bits, if this is 24125f16eeaSchristos# relevant (ECC keys are a fixed size). 24225f16eeaSchristos0 name pgp_binary_key_algo 24325f16eeaSchristos>0 clear x 24425f16eeaSchristos>&0 ubyte =1 \b, RSA (Encrypt or Sign, 24525f16eeaSchristos>>&0 ubeshort x \b %d bits) 24625f16eeaSchristos>&0 ubyte =2 \b, RSA (Encrypt, 24725f16eeaSchristos>>&0 ubeshort x \b %d bits) 24825f16eeaSchristos>&0 ubyte =3 \b, RSA (Sign, 24925f16eeaSchristos>>&0 ubeshort x \b %d bits) 25025f16eeaSchristos>&0 ubyte =16 \b, El Gamal (Encrypt, 25125f16eeaSchristos>>&0 ubeshort x \b %d bits) 25225f16eeaSchristos>&0 ubyte =17 \b, DSA 25325f16eeaSchristos>>&0 ubeshort x \b (%d bits) 25425f16eeaSchristos>&0 ubyte =18 \b, ECDH 25525f16eeaSchristos>&0 ubyte =19 \b, ECDSA 25625f16eeaSchristos>&0 ubyte =20 \b, El Gamal (Encrypt or Sign, 25725f16eeaSchristos>>&0 ubeshort x \b %d bits) 25825f16eeaSchristos>&0 ubyte =22 \b, EdDSA 25925f16eeaSchristos>&0 default x 260*a77ebd86Schristos>>&0 ubyte x \b, Unknown Algorithm (%#x) 26125f16eeaSchristos 26225f16eeaSchristos# Match all possible second packets. 26325f16eeaSchristos0 name sig_or_component_1 26425f16eeaSchristos#>0 ubyte x (ctb: %x) 26525f16eeaSchristos>&0 ubyte =0xC2 26625f16eeaSchristos>>0 ubyte x \b; Signature 26725f16eeaSchristos>>&0 use sig_or_component_1_length_new 26825f16eeaSchristos>&0 ubyte =0xCD 26925f16eeaSchristos>>0 ubyte x \b; User ID 27025f16eeaSchristos>>&0 use sig_or_component_1_length_new 27125f16eeaSchristos>&0 ubyte =0xCE 27225f16eeaSchristos>>0 ubyte x \b; Public Subkey 27325f16eeaSchristos>>&0 use sig_or_component_1_length_new 27425f16eeaSchristos>&0 ubyte =0xC7 27525f16eeaSchristos>>0 ubyte x \b; Secret Subkey 27625f16eeaSchristos>>&0 use sig_or_component_1_length_new 27725f16eeaSchristos>&0 ubyte =0xD1 27825f16eeaSchristos>>0 ubyte x \b; User Attribute 27925f16eeaSchristos>>&0 use sig_or_component_1_length_new 28025f16eeaSchristos>&0 ubyte&0xFC =0x88 28125f16eeaSchristos>>0 ubyte x \b; Signature 28225f16eeaSchristos>>&-1 use sig_or_component_1_length_old 28325f16eeaSchristos>&0 ubyte&0xFC =0xB4 28425f16eeaSchristos>>0 ubyte x \b; User ID 28525f16eeaSchristos>>&-1 use sig_or_component_1_length_old 28625f16eeaSchristos>&0 ubyte&0xFC =0xB8 28725f16eeaSchristos>>0 ubyte x \b; Public Subkey 28825f16eeaSchristos>>&-1 use sig_or_component_1_length_old 28925f16eeaSchristos>&0 ubyte&0xFC =0x9C 29025f16eeaSchristos>>0 ubyte x \b; Secret Subkey 29125f16eeaSchristos>>&-1 use sig_or_component_1_length_old 29225f16eeaSchristos 29325f16eeaSchristos# Copy of 'primary_key_length_new', but calls cert_packet_3. 29425f16eeaSchristos0 name sig_or_component_1_length_new 29525f16eeaSchristos>&0 ubyte <192 29625f16eeaSchristos#>>&0 ubyte x (1 byte new length encoding, %d bytes) 29725f16eeaSchristos>>&(&-1.B) use cert_packet_3 29825f16eeaSchristos>&0 ubyte >191 29925f16eeaSchristos>>&-1 ubyte <225 30025f16eeaSchristos# offset = ((offset[0] - 192) << 8) + offset[1] + 192 + 1 (for the length header) 30125f16eeaSchristos# raw - (192 * 256 - 192 - 1) 30225f16eeaSchristos# = 48959 30325f16eeaSchristos#>>>&-1 ubeshort x (2 byte new length encoding, %d bytes) 30425f16eeaSchristos>>>&(&-1.S-48959) use cert_packet_3 30525f16eeaSchristos>&0 ubyte =255 30625f16eeaSchristos#>>&0 belong x (5 byte new length encoding, %d bytes) 30725f16eeaSchristos>>&(&-4.L) use cert_packet_3 30825f16eeaSchristos# Partial body encoding (only valid for container packets). 30925f16eeaSchristos# >&0 ubyte >224 31025f16eeaSchristos# >>&0 ubyte <255 partial body encoding 31125f16eeaSchristos 31225f16eeaSchristos0 name sig_or_component_1_length_old 31325f16eeaSchristos#>&0 ubyte x (ctb: %x) 31425f16eeaSchristos>&0 ubyte&0x3 =0 31525f16eeaSchristos#>>&0 ubyte x (1 byte old length encoding, %d bytes) 31625f16eeaSchristos>>&(&0.B+1) use cert_packet_3 31725f16eeaSchristos>&0 ubyte&0x3 =1 31825f16eeaSchristos#>>&0 ubeshort x (2 byte old length encoding, %d bytes) 31925f16eeaSchristos>>&(&0.S+2) use cert_packet_3 32025f16eeaSchristos>&0 ubyte&0x3 =2 32125f16eeaSchristos#>>&0 ubelong x (4 byte old length encoding, %d bytes) 32225f16eeaSchristos>>&(&0.L+4) use cert_packet_3 32325f16eeaSchristos 32425f16eeaSchristos# Copy of above. 32525f16eeaSchristos0 name cert_packet_3 32625f16eeaSchristos#>0 ubyte x (ctb: %x) 32725f16eeaSchristos>&0 ubyte =0xC2 32825f16eeaSchristos>>0 ubyte x \b; Signature 32925f16eeaSchristos>>&0 use cert_packet_3_length_new 33025f16eeaSchristos>&0 ubyte =0xCD 33125f16eeaSchristos>>0 ubyte x \b; User ID 33225f16eeaSchristos>>&0 use cert_packet_3_length_new 33325f16eeaSchristos>&0 ubyte =0xCE 33425f16eeaSchristos>>0 ubyte x \b; Public Subkey 33525f16eeaSchristos>>&0 use cert_packet_3_length_new 33625f16eeaSchristos>&0 ubyte =0xC7 33725f16eeaSchristos>>0 ubyte x \b; Secret Subkey 33825f16eeaSchristos>>&0 use cert_packet_3_length_new 33925f16eeaSchristos>&0 ubyte =0xD1 34025f16eeaSchristos>>0 ubyte x \b; User Attribute 34125f16eeaSchristos>>&0 use cert_packet_3_length_new 34225f16eeaSchristos>&0 ubyte&0xFC =0x88 34325f16eeaSchristos>>0 ubyte x \b; Signature 34425f16eeaSchristos>>&-1 use cert_packet_3_length_old 34525f16eeaSchristos>&0 ubyte&0xFC =0xB4 34625f16eeaSchristos>>0 ubyte x \b; User ID 34725f16eeaSchristos>>&-1 use cert_packet_3_length_old 34825f16eeaSchristos>&0 ubyte&0xFC =0xB8 34925f16eeaSchristos>>0 ubyte x \b; Public Subkey 35025f16eeaSchristos>>&-1 use cert_packet_3_length_old 35125f16eeaSchristos>&0 ubyte&0xFC =0x9C 35225f16eeaSchristos>>0 ubyte x \b; Secret Subkey 35325f16eeaSchristos>>&-1 use cert_packet_3_length_old 35425f16eeaSchristos 35525f16eeaSchristos# Copy of above. 35625f16eeaSchristos0 name cert_packet_3_length_new 35725f16eeaSchristos>&0 ubyte <192 35825f16eeaSchristos#>>&0 ubyte x (1 byte new length encoding, %d bytes) 35925f16eeaSchristos>>&(&-1.B) use pgp_binary_keys_end 36025f16eeaSchristos>&0 ubyte >191 36125f16eeaSchristos>>&-1 ubyte <225 36225f16eeaSchristos# offset = ((offset[0] - 192) << 8) + offset[1] + 192 + 1 (for the length header) 36325f16eeaSchristos# raw - (192 * 256 - 192 - 1) 36425f16eeaSchristos# = 48959 36525f16eeaSchristos#>>>&-1 ubeshort x (2 byte new length encoding, %d bytes) 36625f16eeaSchristos>>>&(&-1.S-48959) use pgp_binary_keys_end 36725f16eeaSchristos>&0 ubyte =255 36825f16eeaSchristos#>>&0 belong x (5 byte new length encoding, %d bytes) 36925f16eeaSchristos>>&(&-4.L) use pgp_binary_keys_end 37025f16eeaSchristos 37125f16eeaSchristos0 name cert_packet_3_length_old 37225f16eeaSchristos#>&0 ubyte x (ctb: %x) 37325f16eeaSchristos>&0 ubyte&0x3 =0 37425f16eeaSchristos#>>&0 ubyte x (1 byte old length encoding, %d bytes) 37525f16eeaSchristos>>&(&0.B+1) use pgp_binary_keys_end 37625f16eeaSchristos>&0 ubyte&0x3 =1 37725f16eeaSchristos#>>&0 ubeshort x (2 byte old length encoding, %d bytes) 37825f16eeaSchristos>>&(&0.S+2) use pgp_binary_keys_end 37925f16eeaSchristos>&0 ubyte&0x3 =2 38025f16eeaSchristos#>>&0 ubelong x (4 byte old length encoding, %d bytes) 38125f16eeaSchristos>>&(&0.L+4) use pgp_binary_keys_end 38225f16eeaSchristos 38325f16eeaSchristos# We managed to parse the first three packets of the certificate. Declare 38425f16eeaSchristos# victory. 38525f16eeaSchristos0 name pgp_binary_keys_end 38625f16eeaSchristos>0 byte x \b; OpenPGP Certificate 38725f16eeaSchristos!:mime application/pgp-keys 38825f16eeaSchristos!:ext pgp/gpg/pkr/asd 389