123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388 |
- #------------------------------------------------------------------------------
- # $File: pgp-binary-keys,v 1.2 2021/04/26 15:56:00 christos Exp $
- # pgp-binary-keys: This file handles pgp binary keys.
- #
- # An PGP certificate or message doesn't have a fixed header. Instead,
- # they are sequences of packets:
- #
- # https://tools.ietf.org/html/rfc4880#section-4.3
- #
- # whose order conforms to a grammar:
- #
- # https://tools.ietf.org/html/rfc4880#section-11
- #
- # Happily most packets have a few fields that are constrained, which
- # allow us to fingerprint them with relatively high certainty.
- #
- # A PGP packet is described by a single byte: the so-called CTB. The
- # high-bit is always set. If bit 6 is set, then it is a so-called
- # new-style CTB; if bit 6 is clear, then it is a so-called old-style
- # CTB. Old-style CTBs have only four bits of type information; bits
- # 1-0 are used to describe the length. New-style CTBs have 6 bits of
- # type information.
- #
- # Following the CTB is the packet's length in bytes. If we blindly
- # advance the file cursor by this amount past the end of the length
- # information we come to the next packet.
- #
- # Data Structures
- # ===============
- #
- # New Style CTB
- # -------------
- #
- # https://tools.ietf.org/html/rfc4880#section-4.2.2
- #
- # 76543210
- # ||\----/
- # || tag
- # |always 1
- # always 1
- #
- # Tag bits 7 and 6 set
- # 0 0xC0 -- Reserved - a packet tag MUST NOT have this value
- # 1 0xC1 -- Public-Key Encrypted Session Key Packet
- # 2 0xC2 -- Signature Packet
- # 3 0xC3 -- Symmetric-Key Encrypted Session Key Packet
- # 4 0xC4 -- One-Pass Signature Packet
- # 5 0xC5 -- Secret-Key Packet
- # 6 0xC6 -- Public-Key Packet
- # 7 0xC7 -- Secret-Subkey Packet
- # 8 0xC8 -- Compressed Data Packet
- # 9 0xC9 -- Symmetrically Encrypted Data Packet
- # 10 0xCA -- Marker Packet
- # 11 0xCB -- Literal Data Packet
- # 12 0xCC -- Trust Packet
- # 13 0xCD -- User ID Packet
- # 14 0xCE -- Public-Subkey Packet
- # 17 0xD1 -- User Attribute Packet
- # 18 0xD2 -- Sym. Encrypted and Integrity Protected Data Packet
- # 19 0xD3 -- Modification Detection Code Packet
- # 60 to 63 -- Private or Experimental Values
- #
- # The CTB is followed by the length header, which is densely encoded:
- #
- # if length[0] is:
- # 0..191: one byte length (length[0])
- # 192..223: two byte length ((length[0] - 192) * 256 + length[2] + 192
- # 224..254: four byte length (big endian interpretation of length[1..5])
- # 255: partial body encoding
- #
- # The partial body encoding is similar to HTTP's chunk encoding. It
- # is only allowed for container packets (SEIP, Compressed Data and
- # Literal).
- #
- # Old Style CTB
- # -------------
- #
- # https://tools.ietf.org/html/rfc4880#section-4.2.1
- #
- # CTB:
- #
- # 76543210
- # ||\--/\/
- # || | length encoding
- # || tag
- # |always 0
- # always 1
- #
- # Tag:
- #
- # Tag bit 7 set, bits 6, 1, 0 clear
- # 0 0x80 -- Reserved - a packet tag MUST NOT have this value
- # 1 0x84 -- Public-Key Encrypted Session Key Packet
- # 2 0x88 -- Signature Packet
- # 3 0x8C -- Symmetric-Key Encrypted Session Key Packet
- # 4 0x90 -- One-Pass Signature Packet
- # 5 0x94 -- Secret-Key Packet
- # 6 0x98 -- Public-Key Packet
- # 7 0x9C -- Secret-Subkey Packet
- # 8 0xA0 -- Compressed Data Packet
- # 9 0xA4 -- Symmetrically Encrypted Data Packet
- # 10 0xA8 -- Marker Packet
- # 11 0xAC -- Literal Data Packet
- # 12 0xB0 -- Trust Packet
- # 13 0xB4 -- User ID Packet
- # 14 0xB8 -- Public-Subkey Packet
- #
- # Length encoding:
- #
- # Value
- # 0 1 byte length (following byte is the length)
- # 1 2 byte length (following two bytes are the length)
- # 2 4 byte length (following four bytes are the length)
- # 3 indeterminate length: natural end of packet, e.g., EOF
- #
- # An indeterminate length is only allowed for container packets
- # (SEIP, Compressed Data and Literal).
- #
- # Certificates
- # ------------
- #
- # We check the first three packets to determine if a sequence of
- # OpenPGP packets is likely to be a certificate. The grammar allows
- # the following prefixes:
- #
- # [Primary Key] [SIG] (EOF or another certificate)
- # [Primary Key] [SIG] [User ID] [SIG]...
- # [Primary Key] [SIG] [User Attribute] [SIG]...
- # [Primary Key] [SIG] [Subkey] [SIG]...
- # [Primary Key] [User ID] [SIG]...
- # [Primary Key] [User Attribute] [SIG]...
- # [Primary Key] [Subkey] [SIG]...
- #
- # Any number of marker packets are also allowed between each packet,
- # but they are not normally used and we don't currently check for
- # them.
- #
- # The keys and subkeys may be public or private.
- #
- # Key packets and signature packets are versioned. There are two
- # packet versions that we need to worry about in practice: v3 and v4.
- # v4 packets were introduced in RFC 2440, which was published in 1998.
- # It also deprecated v3 packets. There are no actively used v3
- # certificates (GnuPG removed the code to support them in November
- # 2014). But there are v3 keys lying around and it is useful to
- # identify them. The next version of OpenPGP will introduce v5 keys.
- # The document has not yet been standardized so changes are still
- # possible. But, for our purposes, it appears that v5 data structures
- # will be identical to v4 data structures modulo the version number.
- #
- # https://tools.ietf.org/html/rfc2440
- # https://lists.gnupg.org/pipermail/gnupg-announce/2014q4/000358.html
- # https://www.ietf.org/id/draft-ietf-openpgp-rfc4880bis-09.html#name-key-material-packet
- # The first packet has to be a public key or a secret key.
- #
- # New-Style Public Key
- 0 ubyte =0xC6 OpenPGP Public Key
- >&0 use primary_key_length_new
- # New-Style Secret Key
- 0 ubyte =0xC5 OpenPGP Secret Key
- >&0 use primary_key_length_new
- # Old-Style Public Key
- 0 ubyte&0xFC =0x98 OpenPGP Public Key
- >&-1 use primary_key_length_old
- # Old-Style Secret Key
- 0 ubyte&0xFC =0x94 OpenPGP Secret Key
- >&-1 use primary_key_length_old
- # Parse the length, check the packet's body and finally advance to the
- # next packet.
- # There are 4 different new-style length encodings, but the partial
- # body encoding is only acceptable for the SEIP, Compressed Data, and
- # Literal packets, which isn't valid for any packets in a certificate
- # so we ignore it.
- 0 name primary_key_length_new
- >&0 ubyte <192
- #>>&0 ubyte x (1 byte length encoding, %d bytes)
- >>&0 use pgp_binary_key_pk_check
- >>>&(&-1.B) use sig_or_component_1
- >&0 ubyte >191
- >>&-1 ubyte <225
- # offset = ((offset[0] - 192) << 8) + offset[1] + 192 (for the length header)
- # raw - (192 * 256 - 192)
- # = 48960
- #>>>&0 ubeshort x (2 byte length encoding, %d bytes)
- >>>&1 use pgp_binary_key_pk_check
- >>>>&(&-2.S-48960) use sig_or_component_1
- >&0 ubyte =255
- #>>&0 belong x (5 byte length encoding, %d bytes)
- >>&4 use pgp_binary_key_pk_check
- >>>&(&-4.L) use sig_or_component_1
- # Partial body encoding (only valid for container packets).
- # >&0 ubyte >224
- # >>&0 ubyte <255 partial body encoding
- # There are 4 different old-style length encodings, but the
- # indeterminate length encoding is only acceptable for the SEIP,
- # Compressed Data, and Literal packets, which isn't valid for any
- # packets in a certificate.
- 0 name primary_key_length_old
- #>&0 ubyte x (ctb: %x)
- >&0 ubyte&0x3 =0
- #>>&0 ubyte x (1 byte length encoding, %d bytes)
- >>&1 use pgp_binary_key_pk_check
- >>>&(&-1.B) use sig_or_component_1
- >&0 ubyte&0x3 =1
- #>>&0 ubeshort x (2 byte length encoding, %d bytes)
- >>&2 use pgp_binary_key_pk_check
- >>>&(&-2.S) use sig_or_component_1
- >&0 ubyte&0x3 =2
- #>>&0 ubelong x (4 byte length encoding, %d bytes)
- >>&4 use pgp_binary_key_pk_check
- >>>&(&-4.L) use sig_or_component_1
- # Check the Key.
- #
- # https://tools.ietf.org/html/rfc4880#section-5.5.2
- 0 name pgp_binary_key_pk_check
- # Valid versions are: 2, 3, 4. 5 is proposed in RFC 4880bis.
- # Anticipate a v6 / v7 format that like v5 is compatible with v4.
- # key format in a decade or so :D.
- >&0 ubyte >1
- >>&-1 ubyte <8
- >>>&-1 byte x Version %d
- # Check that keys were created after 1990.
- # (1990 - 1970) * 365.2524 * 24 * 60 * 60 = 631156147
- >>>&0 bedate >631156147 \b, Created %s
- >>>>&-5 ubyte >3
- >>>>>&4 use pgp_binary_key_algo
- >>>>&-5 ubyte <4
- >>>>>&6 use pgp_binary_key_algo
- # Print out the key's algorithm and the number of bits, if this is
- # relevant (ECC keys are a fixed size).
- 0 name pgp_binary_key_algo
- >0 clear x
- >&0 ubyte =1 \b, RSA (Encrypt or Sign,
- >>&0 ubeshort x \b %d bits)
- >&0 ubyte =2 \b, RSA (Encrypt,
- >>&0 ubeshort x \b %d bits)
- >&0 ubyte =3 \b, RSA (Sign,
- >>&0 ubeshort x \b %d bits)
- >&0 ubyte =16 \b, El Gamal (Encrypt,
- >>&0 ubeshort x \b %d bits)
- >&0 ubyte =17 \b, DSA
- >>&0 ubeshort x \b (%d bits)
- >&0 ubyte =18 \b, ECDH
- >&0 ubyte =19 \b, ECDSA
- >&0 ubyte =20 \b, El Gamal (Encrypt or Sign,
- >>&0 ubeshort x \b %d bits)
- >&0 ubyte =22 \b, EdDSA
- >&0 default x
- >>&0 ubyte x \b, Unknown Algorithm (%#x)
- # Match all possible second packets.
- 0 name sig_or_component_1
- #>0 ubyte x (ctb: %x)
- >&0 ubyte =0xC2
- >>0 ubyte x \b; Signature
- >>&0 use sig_or_component_1_length_new
- >&0 ubyte =0xCD
- >>0 ubyte x \b; User ID
- >>&0 use sig_or_component_1_length_new
- >&0 ubyte =0xCE
- >>0 ubyte x \b; Public Subkey
- >>&0 use sig_or_component_1_length_new
- >&0 ubyte =0xC7
- >>0 ubyte x \b; Secret Subkey
- >>&0 use sig_or_component_1_length_new
- >&0 ubyte =0xD1
- >>0 ubyte x \b; User Attribute
- >>&0 use sig_or_component_1_length_new
- >&0 ubyte&0xFC =0x88
- >>0 ubyte x \b; Signature
- >>&-1 use sig_or_component_1_length_old
- >&0 ubyte&0xFC =0xB4
- >>0 ubyte x \b; User ID
- >>&-1 use sig_or_component_1_length_old
- >&0 ubyte&0xFC =0xB8
- >>0 ubyte x \b; Public Subkey
- >>&-1 use sig_or_component_1_length_old
- >&0 ubyte&0xFC =0x9C
- >>0 ubyte x \b; Secret Subkey
- >>&-1 use sig_or_component_1_length_old
- # Copy of 'primary_key_length_new', but calls cert_packet_3.
- 0 name sig_or_component_1_length_new
- >&0 ubyte <192
- #>>&0 ubyte x (1 byte new length encoding, %d bytes)
- >>&(&-1.B) use cert_packet_3
- >&0 ubyte >191
- >>&-1 ubyte <225
- # offset = ((offset[0] - 192) << 8) + offset[1] + 192 + 1 (for the length header)
- # raw - (192 * 256 - 192 - 1)
- # = 48959
- #>>>&-1 ubeshort x (2 byte new length encoding, %d bytes)
- >>>&(&-1.S-48959) use cert_packet_3
- >&0 ubyte =255
- #>>&0 belong x (5 byte new length encoding, %d bytes)
- >>&(&-4.L) use cert_packet_3
- # Partial body encoding (only valid for container packets).
- # >&0 ubyte >224
- # >>&0 ubyte <255 partial body encoding
- 0 name sig_or_component_1_length_old
- #>&0 ubyte x (ctb: %x)
- >&0 ubyte&0x3 =0
- #>>&0 ubyte x (1 byte old length encoding, %d bytes)
- >>&(&0.B+1) use cert_packet_3
- >&0 ubyte&0x3 =1
- #>>&0 ubeshort x (2 byte old length encoding, %d bytes)
- >>&(&0.S+2) use cert_packet_3
- >&0 ubyte&0x3 =2
- #>>&0 ubelong x (4 byte old length encoding, %d bytes)
- >>&(&0.L+4) use cert_packet_3
- # Copy of above.
- 0 name cert_packet_3
- #>0 ubyte x (ctb: %x)
- >&0 ubyte =0xC2
- >>0 ubyte x \b; Signature
- >>&0 use cert_packet_3_length_new
- >&0 ubyte =0xCD
- >>0 ubyte x \b; User ID
- >>&0 use cert_packet_3_length_new
- >&0 ubyte =0xCE
- >>0 ubyte x \b; Public Subkey
- >>&0 use cert_packet_3_length_new
- >&0 ubyte =0xC7
- >>0 ubyte x \b; Secret Subkey
- >>&0 use cert_packet_3_length_new
- >&0 ubyte =0xD1
- >>0 ubyte x \b; User Attribute
- >>&0 use cert_packet_3_length_new
- >&0 ubyte&0xFC =0x88
- >>0 ubyte x \b; Signature
- >>&-1 use cert_packet_3_length_old
- >&0 ubyte&0xFC =0xB4
- >>0 ubyte x \b; User ID
- >>&-1 use cert_packet_3_length_old
- >&0 ubyte&0xFC =0xB8
- >>0 ubyte x \b; Public Subkey
- >>&-1 use cert_packet_3_length_old
- >&0 ubyte&0xFC =0x9C
- >>0 ubyte x \b; Secret Subkey
- >>&-1 use cert_packet_3_length_old
- # Copy of above.
- 0 name cert_packet_3_length_new
- >&0 ubyte <192
- #>>&0 ubyte x (1 byte new length encoding, %d bytes)
- >>&(&-1.B) use pgp_binary_keys_end
- >&0 ubyte >191
- >>&-1 ubyte <225
- # offset = ((offset[0] - 192) << 8) + offset[1] + 192 + 1 (for the length header)
- # raw - (192 * 256 - 192 - 1)
- # = 48959
- #>>>&-1 ubeshort x (2 byte new length encoding, %d bytes)
- >>>&(&-1.S-48959) use pgp_binary_keys_end
- >&0 ubyte =255
- #>>&0 belong x (5 byte new length encoding, %d bytes)
- >>&(&-4.L) use pgp_binary_keys_end
- 0 name cert_packet_3_length_old
- #>&0 ubyte x (ctb: %x)
- >&0 ubyte&0x3 =0
- #>>&0 ubyte x (1 byte old length encoding, %d bytes)
- >>&(&0.B+1) use pgp_binary_keys_end
- >&0 ubyte&0x3 =1
- #>>&0 ubeshort x (2 byte old length encoding, %d bytes)
- >>&(&0.S+2) use pgp_binary_keys_end
- >&0 ubyte&0x3 =2
- #>>&0 ubelong x (4 byte old length encoding, %d bytes)
- >>&(&0.L+4) use pgp_binary_keys_end
- # We managed to parse the first three packets of the certificate. Declare
- # victory.
- 0 name pgp_binary_keys_end
- >0 byte x \b; OpenPGP Certificate
- !:mime application/pgp-keys
- !:ext pgp/gpg/pkr/asd
|