diff options
author | Werner Koch <[email protected]> | 2024-04-11 06:27:53 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 2024-04-11 06:27:53 +0000 |
commit | 6737e07a9b04064947ae37abd28b845a09abee22 (patch) | |
tree | 402f06510340ea3f90ecc28ba050a178ef44ee94 /doc/keyformat.txt | |
parent | doc: Fix a few typos in agent/keyformat.txt (diff) | |
download | gnupg-6737e07a9b04064947ae37abd28b845a09abee22.tar.gz gnupg-6737e07a9b04064947ae37abd28b845a09abee22.zip |
doc: Move keyformat.txt to here.
--
Diffstat (limited to 'doc/keyformat.txt')
-rw-r--r-- | doc/keyformat.txt | 520 |
1 files changed, 520 insertions, 0 deletions
diff --git a/doc/keyformat.txt b/doc/keyformat.txt new file mode 100644 index 000000000..dadfed4eb --- /dev/null +++ b/doc/keyformat.txt @@ -0,0 +1,520 @@ +keyformat.txt emacs, please switch to -*- org -*- mode +------------- + + +Some notes on the format of the secret keys used with gpg-agent. + +* Location of keys + +The secret keys[1] are stored on a per file basis in a directory below +the ~/.gnupg home directory. This directory is named + + private-keys-v1.d + +and should have permissions 700. + +The secret keys are stored in files with a name matching the +hexadecimal representation of the keygrip[2] and suffixed with ".key". + +* Extended Private Key Format + +** Overview +GnuPG 2.3+ uses a new format to store private keys that is both +more flexible and easier to read and edit by human beings. The new +format stores name,value-pairs using the common mail and http header +convention. Example (here indented with two spaces): + + Description: Key to sign all GnuPG released tarballs. + The key is actually stored on a smart card. + Use-for-ssh: yes + OpenSSH-cert: long base64 encoded string wrapped so that this + key file can be easily edited with a standard editor. + Token: D2760001240102000005000011730000 OPENPGP.1 - + Token: FF020001008A77C1 PIV.9C - + Key: (shadowed-private-key + (rsa + (n #00AA1AD2A55FD8C8FDE9E1941772D9CC903FA43B268CB1B5A1BAFDC900 + 2961D8AEA153424DC851EF13B83AC64FBE365C59DC1BD3E83017C90D4365B4 + 83E02859FC13DB5842A00E969480DB96CE6F7D1C03600392B8E08EF0C01FC7 + 19F9F9086B25AD39B4F1C2A2DF3E2BE317110CFFF21D4A11455508FE407997 + 601260816C8422297C0637BB291C3A079B9CB38A92CE9E551F80AA0EBF4F0E + 72C3F250461E4D31F23A7087857FC8438324A013634563D34EFDDCBF2EA80D + F9662C9CCD4BEF2522D8BDFED24CEF78DC6B309317407EAC576D889F88ADA0 + 8C4FFB480981FB68C5C6CA27503381D41018E6CDC52AAAE46B166BDC10637A + E186A02BA2497FDC5D1221#) + (e #00010001#) + (shadowed t1-v1 + (#D2760001240102000005000011730000# OPENPGP.1) + ))) + +GnuPG 2.2 is also able to read and write keys using the new format +However, it only makes use of some of the values. + +Keys in the extended format can be recognized by looking at the first +byte of the file. If it starts with a '(' it is a naked S-expression, +otherwise it is a key in extended format. + +*** Names +A name must start with a letter and end with a colon. Valid +characters are all ASCII letters, numbers and the hyphen. Comparison +of names is done case insensitively. Names may be used several times +to represent an array of values. Note that the name "Key" is special +in that it is mandatory and must occur only once. + +*** Values +Values are UTF-8 encoded strings. Values can be wrapped at any point, +and continued in the next line indicated by leading whitespace. A +continuation line with one leading space does not introduce a blank so +that the lines can be effectively concatenated. A blank line as part +of a continuation line encodes a newline. + +*** Comments +Lines containing only whitespace, and lines starting with whitespace +followed by '#' are considered to be comments and are ignored. + +** Well known names +*** Description +This is a human readable string describing the key. + +*** Key +The name "Key" is special in that it is mandatory and must occur only +once. The associated value holds the actual S-expression with the +cryptographic key. The S-expression is formatted using the 'Advanced +Format' (GCRYSEXP_FMT_ADVANCED) that avoids non-printable characters +so that the file can be easily inspected and edited. See section +'Private Key Format' below for details. + +*** Created +The UTC time the key was created in ISO compressed format +(yyyymmddThhmmss). This information can be used to re-create an +OpenPGP key. + +*** Label +This is a short human readable description for the key which can be +used by the software to describe the key in a user interface. For +example as part of the description in a prompt for a PIN or +passphrase. It is often used instead of a comment element as present +in the S-expression of the "Key" item. + +*** OpenSSH-cert +This takes a base64 encoded string wrapped so that this +key file can be easily edited with a standard editor. Several of such +items can be used. + +*** Token +If such an item exists it overrides the info given by the "shadow" +parameter in the S-expression. Using this item makes it possible to +describe a key which is stored on several tokens and also makes it +easy to update this info using a standard editor. The syntax is +similar to the "shadow" parameter: + +- Serialnumber of the token. +- Key reference from the token in full format (e.g. "OpenPGP.2"). +- An optional fixed length of the PIN or "-". +- The human readable serial number of a card. This is usually what is + printed on the actual card. This value is taken directly from the + card but when asking to insert a card it is useful to have this + value available. GnuPG takes care of creating and possibly updating + this entry. This is percent-plus-escaped. + + +*** Use-for-ssh +If given and the value is "yes" or "1" the key is allowed for use by +gpg-agent's ssh-agent implementation. This is thus the same as +putting the keygrip into the 'sshcontrol' file. Only one such item +should exist. If another non-zero value between 1 and 99999 is used, +this is taken to establish the order in which the keys are returned to +ssh; lower numbers are returned first. If a negative value is used +this overrides currently active (inserted) cards and thus allows to +prefer on-disk keys over inserted cards. A value of -1 has the +highest priority; values are capped at -999 and have a lower priority +but still above the positive values, inserted cards or the order in +sshcontrol. + + +*** Use-for-p11 +If given and the value is "yes" or "1" the key is allowed for use by +GnuPG's PKCS#11 interface (Scute). Note that Scute needs to be +configured to use this optimization. + +*** Remote-list +Allow to list the key with the KEYINFO command from a remote machine +via the extra socket. A boolean value is expected; the default is +"no". Note that KEYINFO will anyway provide information if the +keygrip is specified. + +*** Confirm +If given and the value is "yes", a user will be asked confirmation by +a dialog window when the key is about to be used for +PKSIGN/PKAUTH/PKDECRYPT operation. If the value is "restricted", it +is only asked for the access through extra/browser socket. + +*** Prompt +This field is for card key. If given and the value is "yes" +(default), a user will be prompted about insertion of the card by a +dialog window when card is not available. When the value is "no", a +card operation is refused with GPG_ERR_UNUSABLE_SECKEY error. + +*** Backup-info +This gives information for a backup of the key. The following fields +are space delimited: + +- Hexified keygrip (uppercase) to make it easy to identify the + filename. When restoring software should make sure that the keygrip + matches the one derived from the "Key" field. +- Backup time in as ISO string. +- Name of the backup software. +- Arbitrary information. + +* Private Key Format +** Unprotected Private Key Format + +The content of the file is an S-Expression like the ones used with +Libgcrypt. Here is an example of an unprotected file: + +(private-key + (rsa + (n #00e0ce9..[some bytes not shown]..51#) + (e #010001#) + (d #046129F..[some bytes not shown]..81#) + (p #00e861b..[some bytes not shown]..f1#) + (q #00f7a7c..[some bytes not shown]..61#) + (u #304559a..[some bytes not shown]..9b#) + ) + (created-at timestamp) + (uri http://foo.bar x-foo:whatever_you_want) + (comment whatever) +) + +"comment", "created-at" and "uri" are optional. "comment" is +currently used to keep track of ssh key comments. "created-at" is used +to keep track of the creation time stamp used with OpenPGP keys; it is +optional but required for some operations to calculate the fingerprint +of the key. This timestamp should be a string with the number of +seconds since Epoch or an ISO time string (yyyymmddThhmmss). + +** Protected Private Key Format + +A protected key is like this: + +(protected-private-key + (rsa + (n #00e0ce9..[some bytes not shown]..51#) + (e #010001#) + (protected mode (parms) encrypted_octet_string) + (protected-at <isotimestamp>) + ) + (uri http://foo.bar x-foo:whatever_you_want) + (comment whatever) +) + + +In this scheme the encrypted_octet_string is encrypted according to +the algorithm described after the keyword protected; most protection +algorithms need some parameters, which are given in a list before the +encrypted_octet_string. The result of the decryption process is a +list of the secret key parameters. The protected-at expression is +optional; the isotimestamp is 15 bytes long (e.g. "19610711T172000"). + +The currently defined protection modes are: + +*** openpgp-s2k3-sha1-aes-cbc + + This describes an algorithm using AES in CBC mode for + encryption, SHA-1 for integrity protection and the String to Key + algorithm 3 from OpenPGP (rfc4880). + + Example: + + (protected openpgp-s2k3-sha1-aes-cbc + ((sha1 16byte_salt no_of_iterations) 16byte_iv) + encrypted_octet_string + ) + + The encrypted_octet string should yield this S-Exp (in canonical + representation) after decryption: + + ( + ( + (d #046129F..[some bytes not shown]..81#) + (p #00e861b..[some bytes not shown]..f1#) + (q #00f7a7c..[some bytes not shown]..61#) + (u #304559a..[some bytes not shown]..9b#) + ) + (hash sha1 #...[hashvalue]...#) + ) + + For padding reasons, random bytes are appended to this list - they can + easily be stripped by looking for the end of the list. + + The hash is calculated on the concatenation of the public key and + secret key parameter lists: i.e. it is required to hash the + concatenation of these 6 canonical encoded lists for RSA, including + the parenthesis, the algorithm keyword and (if used) the protected-at + list. + + (rsa + (n #00e0ce9..[some bytes not shown]..51#) + (e #010001#) + (d #046129F..[some bytes not shown]..81#) + (p #00e861b..[some bytes not shown]..f1#) + (q #00f7a7c..[some bytes not shown]..61#) + (u #304559a..[some bytes not shown]..9b#) + (protected-at "18950523T000000") + ) + + After decryption the hash must be recalculated and compared against + the stored one - If they don't match the integrity of the key is not + given. + +*** openpgp-s2k3-ocb-aes + + This describes an algorithm using AES-128 in OCB mode, a nonce + of 96 bit, a taglen of 128 bit, and the String to Key algorithm 3 + from OpenPGP (rfc4880). + + Example: + + (protected openpgp-s2k3-ocb-aes + ((sha1 16byte_salt no_of_iterations) 12byte_nonce) + encrypted_octet_string + ) + + The encrypted_octet string should yield this S-Exp (in canonical + representation) after decryption: + + ( + ( + (d #046129F..[some bytes not shown]..81#) + (p #00e861b..[some bytes not shown]..f1#) + (q #00f7a7c..[some bytes not shown]..61#) + (u #304559a..[some bytes not shown]..9b#) + ) + ) + + For padding reasons, random bytes may be appended to this list - + they can easily be stripped by looking for the end of the list. + + The associated data required for this protection mode is the list + forming the public key parameters. For the above example this is + is this canonical encoded S-expression: + + (rsa + (n #00e0ce9..[some bytes not shown]..51#) + (e #010001#) + (protected-at "18950523T000000") + ) + +*** openpgp-native + + This is a wrapper around the OpenPGP Private Key Transport format + which resembles the standard OpenPGP format and allows the use of an + existing key without re-encrypting to the default protection format. + + Example: + + (protected openpgp-native + (openpgp-private-key + (version V) + (algo PUBKEYALGO) + (skey _ P1 _ P2 _ P3 ... e PN) + (csum n) + (protection PROTTYPE PROTALGO IV S2KMODE S2KHASH S2KSALT S2KCOUNT))) + + Note that the public key parameters in SKEY are duplicated and + should be identical to their copies in the standard parameter + elements. Here is an example of an entire protected private key + using this format: + + (protected-private-key + (rsa + (n #00e0ce9..[some bytes not shown]..51#) + (e #010001#) + (protected openpgp-native + (openpgp-private-key + (version 4) + (algo rsa) + (skey _ #00e0ce9..[some bytes not shown]..51# + _ #010001# + e #.........................#) + (protection sha1 aes #aabbccddeeff00112233445566778899# + 3 sha1 #2596f93e85f41e53# 3:190)))) + (uri http://foo.bar x-foo:whatever_you_want) + (comment whatever)) + +** Shadowed Private Key Format + +To keep track of keys stored on IC cards we use a third format for +private keys which are called shadow keys as they are only a reference +to keys stored on a token: + +(shadowed-private-key + (rsa + (n #00e0ce9..[some bytes not shown]..51#) + (e #010001#) + (shadowed protocol (info)) + ) + (uri http://foo.bar x-foo:whatever_you_want) + (comment whatever) +) + +The currently used protocols are "t1-v1" (token info version 1) and +"tpm2-v1" (TPM format key information). The second list with the +information has this layout for "t1-v1": + +(card_serial_number id_string_of_key fixed_pin_length) + +FIXED_PIN_LENGTH is optional. It can be used to store the length of +the PIN; a value of 0 indicates that this information is not +available. The rationale for this field is that some pinpad equipped +readers don't allow passing a variable length PIN. + +This is the (info) layout for "tpm2-v1": + +(parent tpm_private_string tpm_public_string) + +Although this precise format is encapsulated inside the tpm2daemon +itself and nothing in gpg ever uses this. + +More items may be added to the list. + +** OpenPGP Private Key Transfer Format + +This format is used to transfer keys between gpg and gpg-agent. + +(openpgp-private-key + (version V) + (algo PUBKEYALGO) + (curve CURVENAME) + (skey _ P1 _ P2 _ P3 ... e PN) + (csum n) + (protection PROTTYPE PROTALGO IV S2KMODE S2KHASH S2KSALT S2KCOUNT)) + + + * V is the packet version number (3 or 4). + * PUBKEYALGO is a Libgcrypt algo name + * CURVENAME is the name of the curve - only used with ECC. + * P1 .. PN are the parameters; the public parameters are never encrypted + the secret key parameters are encrypted if the "protection" list is + given. To make this more explicit each parameter is preceded by a + flag "_" for cleartext or "e" for encrypted text. + * CSUM is the deprecated 16 bit checksum as defined by OpenPGP. This + is an optional element. + * If PROTTYPE is "sha1" the new style SHA1 checksum is used if it is "sum" + the old 16 bit checksum (above) is used and if it is "none" no + protection at all is used. + * PROTALGO is a Libgcrypt style cipher algorithm name + * IV is the initialization vector. + * S2KMODE is the value from RFC-4880. + * S2KHASH is a libgcrypt style hash algorithm identifier. + * S2KSALT is the 8 byte salt + * S2KCOUNT is the count value from RFC-4880. + +** Persistent Passphrase Format + +Note: That this has not yet been implemented. + +To allow persistent storage of cached passphrases we use a scheme +similar to the private-key storage format. This is a master +passphrase format where each file may protect several secrets under +one master passphrase. It is possible to have several of those files +each protected by a dedicated master passphrase. Clear text keywords +allow listing the available protected passphrases. + +The name of the files with these protected secrets have this form: +pw-<string>.dat. STRING may be an arbitrary string, as a default name +for the passphrase storage the name "pw-default.dat" is suggested. + + +(protected-shared-secret + ((desc descriptive_text) + (key [key_1] (keyword_1 keyword_2 keyword_n)) + (key [key_2] (keyword_21 keyword_22 keyword_2n)) + (key [key_n] (keyword_n1 keyword_n2 keyword_nn)) + (protected mode (parms) encrypted_octet_string) + (protected-at <isotimestamp>) + ) +) + +After decryption the encrypted_octet_string yields this S-expression: + +( + ( + (value key_1 value_1) + (value key_2 value_2) + (value key_n value_n) + ) + (hash sha1 #...[hashvalue]...#) +) + +The "descriptive_text" is displayed with the prompt to enter the +unprotection passphrase. + +KEY_1 to KEY_N are unique identifiers for the shared secret, for +example an URI. In case this information should be kept confidential +as well, they may not appear in the unprotected part; however they are +mandatory in the encrypted_octet_string. The list of keywords is +optional. The order of the "key" lists and the order of the "value" +lists must match, that is the first "key"-list is associated with the +first "value" list in the encrypted_octet_string. + +The protection mode etc. is identical to the protection mode as +described for the private key format. + +list of the secret key parameters. The protected-at expression is +optional; the isotimestamp is 15 bytes long (e.g. "19610711T172000"). + +The "hash" in the encrypted_octet_string is calculated on the +concatenation of the key list and value lists: i.e it is required to +hash the concatenation of all these lists, including the +parenthesis and (if used) the protected-at list. + +Example: + +(protected-shared-secret + ((desc "List of system passphrases") + (key "uid-1002" ("Knuth" "Donald Ervin Knuth")) + (key "uid-1001" ("Dijkstra" "Edsger Wybe Dijkstra")) + (key) + (protected mode (parms) encrypted_octet_string) + (protected-at "20100915T111722") + ) +) + +with "encrypted_octet_string" decoding to: + +( + ( + (value 4:1002 "signal flags at the lock") + (value 4:1001 "taocp") + (value 1:0 "premature optimization is the root of all evil") + ) + (hash sha1 #0102030405060708091011121314151617181920#) +) + +To compute the hash this S-expression (in canonical format) was +hashed: + + ((desc "List of system passphrases") + (key "uid-1002" ("Knuth" "Donald Ervin Knuth")) + (key "uid-1001" ("Dijkstra" "Edsger Wybe Dijkstra")) + (key) + (value 4:1002 "signal flags at the lock") + (value 4:1001 "taocp") + (value 1:0 "premature optimization is the root of all evil") + (protected-at "20100915T111722") + ) + +* Notes + +[1] I usually use the terms private and secret key exchangeable but prefer the +term secret key because it can be visually be better distinguished +from the term public key. + +[2] The keygrip is a unique identifier for a key pair, it is +independent of any protocol, so that the same key can be used with +different protocols. PKCS-15 calls this a subjectKeyHash; it can be +calculated using Libgcrypt's gcry_pk_get_keygrip (). + +[3] Even when canonical representation are required we will show the +S-expression here in a more readable representation. |