summaryrefslogtreecommitdiffstats
path: root/magic/Magdir/pgp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--magic/Magdir/pgp581
-rw-r--r--magic/Magdir/pgp-binary-keys388
2 files changed, 969 insertions, 0 deletions
diff --git a/magic/Magdir/pgp b/magic/Magdir/pgp
new file mode 100644
index 0000000..d818838
--- /dev/null
+++ b/magic/Magdir/pgp
@@ -0,0 +1,581 @@
+
+#------------------------------------------------------------------------------
+# $File: pgp,v 1.25 2021/04/26 15:56:00 christos Exp $
+# pgp: file(1) magic for Pretty Good Privacy
+
+# Handling of binary PGP keys is in pgp-binary-keys.
+# see https://lists.gnupg.org/pipermail/gnupg-devel/1999-September/016052.html
+#
+0 beshort 0xa600 PGP encrypted data
+#!:mime application/pgp-encrypted
+#0 string -----BEGIN\040PGP text/PGP armored data
+!:mime text/PGP # encoding: armored data
+#>15 string PUBLIC\040KEY\040BLOCK- public key block
+#>15 string MESSAGE- message
+#>15 string SIGNED\040MESSAGE- signed message
+#>15 string PGP\040SIGNATURE- signature
+
+# Update: Joerg Jenderek
+# URL: http://en.wikipedia.org/wiki/Pretty_Good_Privacy
+# Reference: https://reposcope.com/mimetype/application/pgp-keys
+2 string ---BEGIN\040PGP\040PRIVATE\040KEY\040BLOCK- PGP private key block
+#!:mime text/PGP
+!:mime application/pgp-keys
+!:ext asc
+2 string ---BEGIN\040PGP\040PUBLIC\040KEY\040BLOCK- PGP public key block
+!:mime application/pgp-keys
+!:ext asc
+>10 search/100 \n\n
+>>&0 use pgp
+0 string -----BEGIN\040PGP\040MESSAGE- PGP message
+# https://reposcope.com/mimetype/application/pgp-encrypted
+#!:mime application/pgp
+!:mime application/pgp-encrypted
+!:ext asc
+#!:ext asc/pgp/gpg
+>10 search/100 \n\n
+>>&0 use pgp
+# Reference: https://www.gnupg.org/gph/en/manual/x135.html
+0 string -----BEGIN\040PGP\040SIGNED\040MESSAGE- PGP signed message
+#!:mime text/plain
+!:mime text/PGP
+#!:mime application/pgp
+!:ext asc
+0 string -----BEGIN\040PGP\040SIGNATURE- PGP signature
+# https://reposcope.com/mimetype/application/pgp-signature
+!:mime application/pgp-signature
+!:ext asc
+>10 search/100 \n\n
+>>&0 use pgp
+
+# Decode the type of the packet based on it's base64 encoding.
+# Idea from Mark Martinec
+# The specification is in RFC 4880, section 4.2 and 4.3:
+# https://tools.ietf.org/html/rfc4880#section-4.2
+
+0 name pgp
+>0 byte 0x67 Reserved (old)
+>0 byte 0x68 Public-Key Encrypted Session Key (old)
+>0 byte 0x69 Signature (old)
+>0 byte 0x6a Symmetric-Key Encrypted Session Key (old)
+>0 byte 0x6b One-Pass Signature (old)
+>0 byte 0x6c Secret-Key (old)
+>0 byte 0x6d Public-Key (old)
+>0 byte 0x6e Secret-Subkey (old)
+>0 byte 0x6f Compressed Data (old)
+>0 byte 0x70 Symmetrically Encrypted Data (old)
+>0 byte 0x71 Marker (old)
+>0 byte 0x72 Literal Data (old)
+>0 byte 0x73 Trust (old)
+>0 byte 0x74 User ID (old)
+>0 byte 0x75 Public-Subkey (old)
+>0 byte 0x76 Unused (old)
+>0 byte 0x77
+>>1 byte&0xc0 0x00 Reserved
+>>1 byte&0xc0 0x40 Public-Key Encrypted Session Key
+>>1 byte&0xc0 0x80 Signature
+>>1 byte&0xc0 0xc0 Symmetric-Key Encrypted Session Key
+>0 byte 0x78
+>>1 byte&0xc0 0x00 One-Pass Signature
+>>1 byte&0xc0 0x40 Secret-Key
+>>1 byte&0xc0 0x80 Public-Key
+>>1 byte&0xc0 0xc0 Secret-Subkey
+>0 byte 0x79
+>>1 byte&0xc0 0x00 Compressed Data
+>>1 byte&0xc0 0x40 Symmetrically Encrypted Data
+>>1 byte&0xc0 0x80 Marker
+>>1 byte&0xc0 0xc0 Literal Data
+>0 byte 0x7a
+>>1 byte&0xc0 0x00 Trust
+>>1 byte&0xc0 0x40 User ID
+>>1 byte&0xc0 0x80 Public-Subkey
+>>1 byte&0xc0 0xc0 Unused [z%x]
+>0 byte 0x30
+>>1 byte&0xc0 0x00 Unused [0%x]
+>>1 byte&0xc0 0x40 User Attribute
+>>1 byte&0xc0 0x80 Sym. Encrypted and Integrity Protected Data
+>>1 byte&0xc0 0xc0 Modification Detection Code
+
+# magic signatures to detect PGP crypto material (from stef)
+# detects and extracts metadata from:
+# - symmetric encrypted packet header
+# - RSA (e=65537) secret (sub-)keys
+
+# 1024b RSA encrypted data
+
+0 string \x84\x8c\x03 PGP RSA encrypted session key -
+>3 belong x keyid: %08X
+>7 belong x %08X
+>11 byte 0x01 RSA (Encrypt or Sign) 1024b
+>11 byte 0x02 RSA Encrypt-Only 1024b
+>12 string \x04\x00
+>12 string \x03\xff
+>12 string \x03\xfe
+>12 string \x03\xfd
+>12 string \x03\xfc
+>12 string \x03\xfb
+>12 string \x03\xfa
+>12 string \x03\xf9
+>142 byte 0xd2 .
+
+# 2048b RSA encrypted data
+
+0 string \x85\x01\x0c\x03 PGP RSA encrypted session key -
+>4 belong x keyid: %08X
+>8 belong x %08X
+>12 byte 0x01 RSA (Encrypt or Sign) 2048b
+>12 byte 0x02 RSA Encrypt-Only 2048b
+>13 string \x08\x00
+>13 string \x07\xff
+>13 string \x07\xfe
+>13 string \x07\xfd
+>13 string \x07\xfc
+>13 string \x07\xfb
+>13 string \x07\xfa
+>13 string \x07\xf9
+>271 byte 0xd2 .
+
+# 3072b RSA encrypted data
+
+0 string \x85\x01\x8c\x03 PGP RSA encrypted session key -
+>4 belong x keyid: %08X
+>8 belong x %08X
+>12 byte 0x01 RSA (Encrypt or Sign) 3072b
+>12 byte 0x02 RSA Encrypt-Only 3072b
+>13 string \x0c\x00
+>13 string \x0b\xff
+>13 string \x0b\xfe
+>13 string \x0b\xfd
+>13 string \x0b\xfc
+>13 string \x0b\xfb
+>13 string \x0b\xfa
+>13 string \x0b\xf9
+>399 byte 0xd2 .
+
+# 4096b RSA encrypted data
+
+0 string \x85\x02\x0c\x03 PGP RSA encrypted session key -
+>4 belong x keyid: %08X
+>8 belong x %08X
+>12 byte 0x01 RSA (Encrypt or Sign) 4096b
+>12 byte 0x02 RSA Encrypt-Only 4096b
+>13 string \x10\x00
+>13 string \x0f\xff
+>13 string \x0f\xfe
+>13 string \x0f\xfd
+>13 string \x0f\xfc
+>13 string \x0f\xfb
+>13 string \x0f\xfa
+>13 string \x0f\xf9
+>527 byte 0xd2 .
+
+# 8192b RSA encrypted data
+
+0 string \x85\x04\x0c\x03 PGP RSA encrypted session key -
+>4 belong x keyid: %08X
+>8 belong x %08X
+>12 byte 0x01 RSA (Encrypt or Sign) 8192b
+>12 byte 0x02 RSA Encrypt-Only 8192b
+>13 string \x20\x00
+>13 string \x1f\xff
+>13 string \x1f\xfe
+>13 string \x1f\xfd
+>13 string \x1f\xfc
+>13 string \x1f\xfb
+>13 string \x1f\xfa
+>13 string \x1f\xf9
+>1039 byte 0xd2 .
+
+# 1024b Elgamal encrypted data
+
+0 string \x85\x01\x0e\x03 PGP Elgamal encrypted session key -
+>4 belong x keyid: %08X
+>8 belong x %08X
+>12 byte 0x10 Elgamal Encrypt-Only 1024b.
+>13 string \x04\x00
+>13 string \x03\xff
+>13 string \x03\xfe
+>13 string \x03\xfd
+>13 string \x03\xfc
+>13 string \x03\xfb
+>13 string \x03\xfa
+>13 string \x03\xf9
+
+# 2048b Elgamal encrypted data
+
+0 string \x85\x02\x0e\x03 PGP Elgamal encrypted session key -
+>4 belong x keyid: %08X
+>8 belong x %08X
+>12 byte 0x10 Elgamal Encrypt-Only 2048b.
+>13 string \x08\x00
+>13 string \x07\xff
+>13 string \x07\xfe
+>13 string \x07\xfd
+>13 string \x07\xfc
+>13 string \x07\xfb
+>13 string \x07\xfa
+>13 string \x07\xf9
+
+# 3072b Elgamal encrypted data
+
+0 string \x85\x03\x0e\x03 PGP Elgamal encrypted session key -
+>4 belong x keyid: %08X
+>8 belong x %08X
+>12 byte 0x10 Elgamal Encrypt-Only 3072b.
+>13 string \x0c\x00
+>13 string \x0b\xff
+>13 string \x0b\xfe
+>13 string \x0b\xfd
+>13 string \x0b\xfc
+>13 string \x0b\xfb
+>13 string \x0b\xfa
+>13 string \x0b\xf9
+
+# crypto algo mapper
+
+0 name crypto
+>0 byte 0x00 Plaintext or unencrypted data
+>0 byte 0x01 IDEA
+>0 byte 0x02 TripleDES
+>0 byte 0x03 CAST5 (128 bit key)
+>0 byte 0x04 Blowfish (128 bit key, 16 rounds)
+>0 byte 0x07 AES with 128-bit key
+>0 byte 0x08 AES with 192-bit key
+>0 byte 0x09 AES with 256-bit key
+>0 byte 0x0a Twofish with 256-bit key
+
+# hash algo mapper
+
+0 name hash
+>0 byte 0x01 MD5
+>0 byte 0x02 SHA-1
+>0 byte 0x03 RIPE-MD/160
+>0 byte 0x08 SHA256
+>0 byte 0x09 SHA384
+>0 byte 0x0a SHA512
+>0 byte 0x0b SHA224
+
+# display public key algorithms as human readable text
+0 name key_algo
+>0 byte 0x01 RSA (Encrypt or Sign)
+# keep old look of version 5.28 without parentheses
+>0 byte 0x02 RSA Encrypt-Only
+>0 byte 0x03 RSA (Sign-Only)
+>0 byte 16 ElGamal (Encrypt-Only)
+>0 byte 17 DSA
+>0 byte 18 Elliptic Curve
+>0 byte 19 ECDSA
+>0 byte 20 ElGamal (Encrypt or Sign)
+>0 byte 21 Diffie-Hellman
+>0 default x
+>>0 ubyte <22 unknown (pub %d)
+# this should never happen
+>>0 ubyte >21 invalid (%d)
+
+# pgp symmetric encrypted data
+
+0 byte 0x8c PGP symmetric key encrypted data -
+>1 byte 0x0d
+>1 byte 0x0c
+>2 byte 0x04
+>3 use crypto
+>4 byte 0x01 salted -
+>>5 use hash
+>>14 byte 0xd2 .
+>>14 byte 0xc9 .
+>4 byte 0x03 salted & iterated -
+>>5 use hash
+>>15 byte 0xd2 .
+>>15 byte 0xc9 .
+
+# encrypted keymaterial needs s2k & can be checksummed/hashed
+
+0 name chkcrypto
+>0 use crypto
+>1 byte 0x00 Simple S2K
+>1 byte 0x01 Salted S2K
+>1 byte 0x03 Salted&Iterated S2K
+>2 use hash
+
+# all PGP keys start with this prolog
+# containing version, creation date, and purpose
+
+0 name keyprolog
+>0 byte 0x04
+>1 beldate x created on %s -
+>5 byte 0x01 RSA (Encrypt or Sign)
+>5 byte 0x02 RSA Encrypt-Only
+
+# end of secret keys known signature
+# contains e=65537 and the prolog to
+# the encrypted parameters
+
+0 name keyend
+>0 string \x00\x11\x01\x00\x01 e=65537
+>5 use crypto
+>5 byte 0xff checksummed
+>>6 use chkcrypto
+>5 byte 0xfe hashed
+>>6 use chkcrypto
+
+# PGP secret keys contain also the public parts
+# these vary by bitsize of the key
+
+0 name x1024
+>0 use keyprolog
+>6 string \x03\xfe
+>6 string \x03\xff
+>6 string \x04\x00
+>136 use keyend
+
+0 name x2048
+>0 use keyprolog
+>6 string \x80\x00
+>6 string \x07\xfe
+>6 string \x07\xff
+>264 use keyend
+
+0 name x3072
+>0 use keyprolog
+>6 string \x0b\xfe
+>6 string \x0b\xff
+>6 string \x0c\x00
+>392 use keyend
+
+0 name x4096
+>0 use keyprolog
+>6 string \x10\x00
+>6 string \x0f\xfe
+>6 string \x0f\xff
+>520 use keyend
+
+# \x00|\x1f[\xfe\xff]).{1024})'
+0 name x8192
+>0 use keyprolog
+>6 string \x20\x00
+>6 string \x1f\xfe
+>6 string \x1f\xff
+>1032 use keyend
+
+# depending on the size of the pkt
+# we branch into the proper key size
+# signatures defined as x{keysize}
+
+0 name pgpkey
+>0 string \x01\xd8 1024b
+>>2 use x1024
+>0 string \x01\xeb 1024b
+>>2 use x1024
+>0 string \x01\xfb 1024b
+>>2 use x1024
+>0 string \x01\xfd 1024b
+>>2 use x1024
+>0 string \x01\xf3 1024b
+>>2 use x1024
+>0 string \x01\xee 1024b
+>>2 use x1024
+>0 string \x01\xfe 1024b
+>>2 use x1024
+>0 string \x01\xf4 1024b
+>>2 use x1024
+>0 string \x02\x0d 1024b
+>>2 use x1024
+>0 string \x02\x03 1024b
+>>2 use x1024
+>0 string \x02\x05 1024b
+>>2 use x1024
+>0 string \x02\x15 1024b
+>>2 use x1024
+>0 string \x02\x00 1024b
+>>2 use x1024
+>0 string \x02\x10 1024b
+>>2 use x1024
+>0 string \x02\x04 1024b
+>>2 use x1024
+>0 string \x02\x06 1024b
+>>2 use x1024
+>0 string \x02\x16 1024b
+>>2 use x1024
+>0 string \x03\x98 2048b
+>>2 use x2048
+>0 string \x03\xab 2048b
+>>2 use x2048
+>0 string \x03\xbb 2048b
+>>2 use x2048
+>0 string \x03\xbd 2048b
+>>2 use x2048
+>0 string \x03\xcd 2048b
+>>2 use x2048
+>0 string \x03\xb3 2048b
+>>2 use x2048
+>0 string \x03\xc3 2048b
+>>2 use x2048
+>0 string \x03\xc5 2048b
+>>2 use x2048
+>0 string \x03\xd5 2048b
+>>2 use x2048
+>0 string \x03\xae 2048b
+>>2 use x2048
+>0 string \x03\xbe 2048b
+>>2 use x2048
+>0 string \x03\xc0 2048b
+>>2 use x2048
+>0 string \x03\xd0 2048b
+>>2 use x2048
+>0 string \x03\xb4 2048b
+>>2 use x2048
+>0 string \x03\xc4 2048b
+>>2 use x2048
+>0 string \x03\xc6 2048b
+>>2 use x2048
+>0 string \x03\xd6 2048b
+>>2 use x2048
+>0 string \x05X 3072b
+>>2 use x3072
+>0 string \x05k 3072b
+>>2 use x3072
+>0 string \x05{ 3072b
+>>2 use x3072
+>0 string \x05} 3072b
+>>2 use x3072
+>0 string \x05\x8d 3072b
+>>2 use x3072
+>0 string \x05s 3072b
+>>2 use x3072
+>0 string \x05\x83 3072b
+>>2 use x3072
+>0 string \x05\x85 3072b
+>>2 use x3072
+>0 string \x05\x95 3072b
+>>2 use x3072
+>0 string \x05n 3072b
+>>2 use x3072
+>0 string \x05\x7e 3072b
+>>2 use x3072
+>0 string \x05\x80 3072b
+>>2 use x3072
+>0 string \x05\x90 3072b
+>>2 use x3072
+>0 string \x05t 3072b
+>>2 use x3072
+>0 string \x05\x84 3072b
+>>2 use x3072
+>0 string \x05\x86 3072b
+>>2 use x3072
+>0 string \x05\x96 3072b
+>>2 use x3072
+>0 string \x07[ 4096b
+>>2 use x4096
+>0 string \x07\x18 4096b
+>>2 use x4096
+>0 string \x07+ 4096b
+>>2 use x4096
+>0 string \x07; 4096b
+>>2 use x4096
+>0 string \x07= 4096b
+>>2 use x4096
+>0 string \x07M 4096b
+>>2 use x4096
+>0 string \x073 4096b
+>>2 use x4096
+>0 string \x07C 4096b
+>>2 use x4096
+>0 string \x07E 4096b
+>>2 use x4096
+>0 string \x07U 4096b
+>>2 use x4096
+>0 string \x07. 4096b
+>>2 use x4096
+>0 string \x07> 4096b
+>>2 use x4096
+>0 string \x07@ 4096b
+>>2 use x4096
+>0 string \x07P 4096b
+>>2 use x4096
+>0 string \x074 4096b
+>>2 use x4096
+>0 string \x07D 4096b
+>>2 use x4096
+>0 string \x07F 4096b
+>>2 use x4096
+>0 string \x07V 4096b
+>>2 use x4096
+>0 string \x0e[ 8192b
+>>2 use x8192
+>0 string \x0e\x18 8192b
+>>2 use x8192
+>0 string \x0e+ 8192b
+>>2 use x8192
+>0 string \x0e; 8192b
+>>2 use x8192
+>0 string \x0e= 8192b
+>>2 use x8192
+>0 string \x0eM 8192b
+>>2 use x8192
+>0 string \x0e3 8192b
+>>2 use x8192
+>0 string \x0eC 8192b
+>>2 use x8192
+>0 string \x0eE 8192b
+>>2 use x8192
+>0 string \x0eU 8192b
+>>2 use x8192
+>0 string \x0e. 8192b
+>>2 use x8192
+>0 string \x0e> 8192b
+>>2 use x8192
+>0 string \x0e@ 8192b
+>>2 use x8192
+>0 string \x0eP 8192b
+>>2 use x8192
+>0 string \x0e4 8192b
+>>2 use x8192
+>0 string \x0eD 8192b
+>>2 use x8192
+>0 string \x0eF 8192b
+>>2 use x8192
+>0 string \x0eV 8192b
+>>2 use x8192
+
+# PGP RSA (e=65537) secret (sub-)key header
+
+0 byte 0x97 PGP Secret Sub-key -
+>1 use pgpkey
+0 byte 0x9d
+# Update: Joerg Jenderek
+# secret subkey packet (tag 7) with same structure as secret key packet (tag 5)
+# skip Fetus.Sys16 CALIBUS.MAIN OrbFix.Sys16.Ex by looking for positive len
+>1 ubeshort >0
+#>1 ubeshort x \b, body length %#x
+# next packet type often 88h,89h~(tag 2)~Signature Packet
+#>>(1.S+3) ubyte x \b, next packet type %#x
+# skip Dragon.SHR DEMO.INIT by looking for positive version
+>>3 ubyte >0
+# skip BUISSON.13 GUITAR1 by looking for low version number
+>>>3 ubyte <5 PGP Secret Sub-key
+# sub-key are normally part of secret key. So it does not occur as standalone file
+#!:ext bin
+# version 2,3~old 4~new . Comment following line for version 5.28 look
+>>>>3 ubyte x (v%d)
+>>>>3 ubyte x -
+# old versions 2 or 3 but no real example found
+>>>>3 ubyte <4
+# 2 byte for key bits in version 5.28 look
+>>>>>11 ubeshort x %db
+>>>>>4 beldate x created on %s -
+# old versions use 2 additional bytes after time stamp
+#>>>>>8 ubeshort x %#x
+# display key algorithm 1~RSA Encrypt|Sign - 21~Diffie-Hellman
+>>>>>10 use key_algo
+>>>>>(11.S/8) ubequad x
+# look after first key
+>>>>>>&5 use keyend
+# new version
+>>>>3 ubyte >3
+>>>>>9 ubeshort x %db
+>>>>>4 beldate x created on %s -
+# display key algorithm
+>>>>>8 use key_algo
+>>>>>(9.S/8) ubequad x
+# look after first key for something like s2k
+>>>>>>&3 use keyend
diff --git a/magic/Magdir/pgp-binary-keys b/magic/Magdir/pgp-binary-keys
new file mode 100644
index 0000000..1ce76d9
--- /dev/null
+++ b/magic/Magdir/pgp-binary-keys
@@ -0,0 +1,388 @@
+
+#------------------------------------------------------------------------------
+# $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