diff options
Diffstat (limited to '')
-rw-r--r-- | magic/Magdir/pgp | 581 | ||||
-rw-r--r-- | magic/Magdir/pgp-binary-keys | 388 |
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 |