summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorKali Kaneko <kali@futeisha.org>2014-07-02 11:38:15 -0500
committerKali Kaneko <kali@futeisha.org>2014-07-02 11:38:15 -0500
commitd1955bd267a132c24d9e64dde7a1cdb8bd9fe9c5 (patch)
tree241d30509e30704431ddd378883e477eaa225a07 /docs
parentbc02d9b78a274f3d2a73c63473bc6b28cfcc5f8d (diff)
Imported Upstream version 1.2.6
Diffstat (limited to 'docs')
-rw-r--r--docs/Complete-Guide-to-Publishing-OpenPGP-in-DNS.md832
-rw-r--r--docs/DETAILS1225
-rw-r--r--docs/Makefile153
-rw-r--r--docs/NOTES-python-gnupg-3.1-audit.html946
-rw-r--r--docs/NOTES-python-gnupg-3.1-audit.org232
-rw-r--r--docs/NOTES-python-openpgp-implementations.txt31
-rw-r--r--docs/OpenPGP-keys-in-DNS.md133
-rw-r--r--docs/_static/DETAILS.html2677
-rw-r--r--docs/_static/agogo.css337
-rw-r--r--docs/_static/pygments.css69
-rw-r--r--docs/change-license-emails.txt272
-rw-r--r--docs/conf.py312
-rw-r--r--docs/gnupg.rst131
-rw-r--r--docs/gpg-migrate.txt208
-rw-r--r--docs/index.rst44
-rw-r--r--docs/make.bat190
16 files changed, 7792 insertions, 0 deletions
diff --git a/docs/Complete-Guide-to-Publishing-OpenPGP-in-DNS.md b/docs/Complete-Guide-to-Publishing-OpenPGP-in-DNS.md
new file mode 100644
index 0000000..5112c97
--- /dev/null
+++ b/docs/Complete-Guide-to-Publishing-OpenPGP-in-DNS.md
@@ -0,0 +1,832 @@
+<!--
+
+Livejournal Introduction:
+
+I recently wrestled with something, learned quite a lot, and came up with a document that I'm really rather proud of, that
+shares knowledge that's not all out there in one place anywhere else. Along the way I've written some software that I'm
+releasing, that makes all of what I've learned a lot easier, and may help make the world a little more secure. I'd like to
+share it here.
+
+This is going to be a technical post. For that I apologize. The target of this post is anyone who has a GPG key that they'd
+like to expand to a greater audience, and who controls DNS for any of the email domains they publish. Anyone that I host DNS
+or mail for is also welcome to do this, if you use PGP, as part of the goal of writing this is to encourage adoption and use
+of these methods
+
+<lj-cut text="This will be long and technical">
+-->
+
+# The complete guide to publishing PGP keys in DNS
+
+## Introduction
+
+Publishing PGP keys is a pain. There are many disjoint keyservers, three or
+four _networks_ of which, which do (or don't) share information with each
+other. Some are corporate, some are private. And it's a crapshoot as to
+whose key is going to be on which, or worse, which will have the latest copy
+of a person's key.
+
+For a long time, GPG has had a way to publish keys in DNS, but it hasn't been
+well documented. This document hopes to change that.
+
+After reading this, you should:
+
+* Know the three ways to publish a key
+
+* Have at least a couple tools to do so
+
+* Have learned a bit more about DNS
+
+The target audience for this guide is a technical one. It's expected you
+understand what DNS is, and what an RFC and a resource record is.
+
+There are three ways to publish a PGP key in DNS. Most modern versions of GPG
+can retrieve from all three, although it's not enabled by default. There are
+no compile-time options you need to enable it, and it's simple to turn on. Of
+the three key-publishing methods, there are two that you probably shouldn't
+use at the same time, and there are advantages and disadvantages to each,
+which I hope to outline below, both in general and for each method.
+
+### Advantages to DNS publishing of your keys
+
+* It's universal. Your DNS is your own, and you don't have to worry about
+ which network of vastly-disconnectedkeyservers is caching your key.
+
+* Using DNS does not stop you from publishing via other means.
+
+* If you run an organization, you can easily publish all your employee-keys
+ via this method, and in the same step,define a signing-policy, such that a
+ person need only assign trust to your organization's "keysigning key" (or
+ theCEO's key, or the CTO's), without the trouble of running a keyserver.
+
+* DNSSEC can be (somewhat) used as an additional trust-path vector. More on
+ this in the notes at the bottom.
+
+* You do not have to be searching DNS for keys in order to publish. On the
+ same note, you do not have to be publishing in this manner to search
+ forothers there.
+
+### Disadvantages to DNS publishing
+
+* If you don't control your own DNS (or have a good relationship with your DNS
+ admin), this isn't going to beas easy or even possible. Ideally, you want
+ to be running BIND.
+
+* With two of the three methods listed here, you're going to need to be able
+ to put a CERT record into your DNS. Mostweb-enabled DNS tools probably will
+ not give you this ability. The third uses TXT records, which SPF has caused
+ to befairly universal in web-interfaces. However, it's also the least
+ standards-defined of the three.
+
+* Using at least some of these methods, it's not always a "set it and forget
+ it" procedure. You may need toperiodically re-export your key and
+ re-publish it, especially if you gain new signatures.
+
+* Using some of these methods, you're going to be putting some pretty large,
+ pretty unwiedly lines in your DNS zones. Not everyone will easily be able
+ to retrieve them, but again, you can still publish other ways.
+
+* Using some of these methods, DNS is just a means to an end: you still need
+ to publish your key elsewhere, like a webpage,and the DNS records just point
+ at it.
+
+* Initial verifications of most of these seem to imply that only DSA keys are
+ supported, although I welcome feedback. Itseems the community is trying to
+ get RSA keys to make a comeback. They're the only type supported by the
+ gpg2.0 card, andthey are the default keytype. There was a while where they
+ weren't, though. Since writing this document, I've discoveredthat "new" RSA
+ keys work, but ancient RSA keys with no subkeys tend to misbehave.
+
+### Turning on key-fetching via DNS
+
+Inside your GPG "options" file, find the "auto-key-locate" line, and add
+"cert" and/or "pka" to the options.
+
+ auto-key-locate cert pka (as well as other methods, like keyserver URLs)
+
+
+Don't be surprised if a lot of people don't use this method.
+
+Note that you can also turn on two options during signature verification.
+They are specified in a "verify-options" clause in your config file, or on the
+command line, and they are (right from the GPG manpage):
+
+ pka-lookups
+
+ Enable PKA lookups to verify sender addresses. Note that
+ PKA is based on DNS, and so enabling this option may dis-
+ close information on when and what signatures are veri-
+ fied or to whom data is encrypted. This is similar to the
+ "web bug" described for the auto-key-retrieve feature.
+
+And:
+
+ pka-trust-increase
+
+ Raise the trust in a signature to full if the signature
+ passes PKA validation. This option is only meaningful if
+ pka-lookups is set.
+
+
+You can also use the same options on the command line (as you'll see in this
+document).
+
+## Types of PGP Key Records
+
+### DNS PKA Records
+
+Relevant RFCs: None that I can find.
+
+Other Docs: The GPG source and mailing lists.
+
+#### Advantages
+
+* It's a TXT record. Easy to put in a zonefile with most management software.
+* No special tools required to generate, just three simple pieces of data.
+* Since it uses a special subzone, you can manage the _pka namespace in a
+ separate zonefile.
+* GPG has an option, when verifying a signature, to look up these records
+ (--verify-options pka-lookups), so it's doubly useful, both from a
+ distribution and a verification point.
+
+#### Disadvantages
+
+* As with IPGP certs, you're at the mercy of the URL. This doesn't put your
+ key in DNS, just the location of it, and the fingerprint. Some clients may
+ not be able to support https or http 1.1.
+* Not RFC standard.
+
+#### Howto
+
+1. Figure out which key you want to export:
+
+ %gpg --list-keys danm@prime.gushi.org
+ Warning: using insecure memory!
+ pub 1024D/624BB249 2000-10-02 &lt;-- I'm going to use this one.
+ uid Daniel P. Mahoney &lt;danm@prime.gushi.org&gt;
+ uid Daniel Mahoney (Secondary Email) &lt;gushi@gushi.org&gt;
+ sub 2048g/DE20C529 2000-10-02
+ pub 1024R/309C17C5 1997-05-08
+ uid Daniel P. Mahoney &lt;danm@prime.gushi.org&gt;
+
+2. Export the key to a file (I use keyid.pub.asc, but it can be anything)
+
+ %gpg --export --armor 624BB249 &gt; 624BB249.pub.asc
+ Warning: using insecure memory!
+ %
+
+3. Get the fingerprint for your key:
+
+ %gpg --list-keys --fingerprint 624BB249
+ gpg: WARNING: using insecure memory!
+ gpg: please see http://www.gnupg.org/faq.html for more information
+ pub 1024D/624BB249 2000-10-02
+ Key fingerprint = C206 3054 5492 95F3 3490 37FF FBBE 5A30 624B B249 &lt;-- That bit is your fingerprint.
+ uid Daniel P. Mahoney &lt;danm@prime.gushi.org&gt;
+ uid Daniel Mahoney (Secondary Email) &lt;gushi@gushi.org&gt;
+ sub 2048g/DE20C529 2000-10-02
+
+4. Copy the file somewhere, like your webspace. It need not live on the same
+ server. It needs to be accessable by the url you create in the next step.
+
+ %cp 624BB249.pub.asc public_html/danm.pubkey.txt
+
+5. Make up your text record. The format is:
+
+ danm._pka.prime.gushi.org. TXT "v=pka1;fpr=C2063054549295F3349037FFFBBE5A30624BB249;uri=http://prime.gushi.org/danm.pubkey.txt"
+
+
+We'll take this in several parts. The record label is simply the email
+address with "._pka." replacing the "@". danm@prime.gushi.org becomes
+danm._pka.prime.gushi.org. Don't forget the trailing dot, if you're using the
+fully qualified name. I recommend sticking with fully-qualified, for
+simplicity.
+
+The body of the record is also simple. The v portion is just a version.
+There's only one version as far as I can tell, 'pka1'. The fpr is the
+fingerprint, with all whitespace stripped, and in uppercase. The uri is the
+location a key can be retrieved from. All the "names" are lowercase,
+separated by semicolons.
+
+6. Publish the above record in your DNS. Bump your serial number and reload
+ your nameserver. If you're using DNSSEC, re-sign your zone.
+
+#### Testing
+
+Most of the tests we're going to do for these are essentially the same
+activity. See if our DNS server is handing out an answer, and then see if GPG
+can retrieve it.
+
+1. A simple dig:
+
+ %dig +short danm._pka.prime.gushi.org. TXT
+ "v=pka1\;fpr=C2063054549295F3349037FFFBBE5A30624BB249\;uri=http://prime.gushi.org/danm.pubkey.txt"
+
+(The backslashes before the semicolons are normal). Other than that, it seems
+to make sense and match what I put in.)
+
+2. Test it with GPG. Rather than messing around with, and adding-from and
+ deleting from live keyrings, you can do:
+
+ %echo "foo" | gpg --no-default-keyring --keyring /tmp/gpg-$$ --encrypt --armor --auto-key-locate pka -r you@you.com
+
+
+(where you@you.com is the address of your primary key.) The /tmp/gpg-$$
+creates a random file named after your PID. What you should see, and what I
+see, is something like this:
+
+ gpg: WARNING: using insecure memory!
+ gpg: please see http://www.gnupg.org/faq.html for more information
+ gpg: keyring `/tmp/gpg-39996' created
+ gpg: requesting key 624BB249 from http server prime.gushi.org
+ gpg: key 624BB249: public key "Daniel P. Mahoney &lt;danm@prime.gushi.org&gt;" imported
+ gpg: public key of ultimately trusted key CF45887D not found
+ gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
+ gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
+ gpg: Total number processed: 1
+ gpg: imported: 1
+ gpg: automatically retrieved `danm@prime.gushi.org' via PKA
+ gpg: DE20C529: There is no assurance this key belongs to the named user
+ pub 2048g/DE20C529 2000-10-02 Daniel P. Mahoney &lt;danm@prime.gushi.org&gt;
+ Primary key fingerprint: C206 3054 5492 95F3 3490 37FF FBBE 5A30 624B B249
+ Subkey fingerprint: CE40 B786 81E2 5CB9 F7D3 1318 9488 EB58 DE20 C529
+ It is NOT certain that the key belongs to the person named
+ in the user ID. If you *really* know what you are doing,
+ you may answer the next question with yes.
+ Use this key anyway? (y/N) y
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG v1.4.10 (FreeBSD)
+ hQIOA5SI61jeIMUpEAf/UotgWP8VQC9VTY36HaZeXO1CTFk90x0qlPrAhJk9YaoA
+ 2eHNKZSoHKqaLjzTbaWnWHnNZu0IllIS+qrAwNeIAhswfzDoc8Q9+/4sGSR3LmxA
+ 8SEwrJIvLmGVbqJEtnH8TTHIEao/lpL/d+ul4nLfbXRn0NW+MsaCAi8UsjbLlJeV
+ n4p0GQlpDoZCE55DTwMzfWMT84YVwuXTesuN+i7sSyJn2hT1rXuK1BCVcsgTcKdy
+ QhIo3EfKBlfFp74yiU7QCmlAujD6U6a93mmxezPIHVx/WGXgPExVRGgEzfT/tUcI
+ IQ2xMDUv4BF05hgm04GPGCbBY431j4UkdWWI6bvMLwgA2i01NmflH/6Z8+ss6J1M
+ e3RWnR7TPl5lDkXFBtLGAzO+HrsC5A32SbkTw+WsljCQLifJ2EalfoJ1QGY4Sp3v
+ H2YunwZLVPTc+D2JnrXfqNmi5zYZio8by3c8L0CgWdMwZ7PPxZpTOLN77/MIjBkJ
+ EBb8Z6SZCgzTIhN5z56ZgWFvmSKf1vKkeUcrgxMs+DnA+XqBMJ9w520JwoTLjJza
+ syrlYVhd+ktY21DYB9OJ5MZx2HMAtkUDRAzW1zoLcehk1kdZNzhpjU5hqSjT8/GN
+ trKFeqkmKemrq2GvMNyJyrEOB8e7KgbmXa95YKH0Wh2D4SWpXukegyCspmY4tDE+
+ uckaFSao+48g8D6vs1irGSxBRjyhD/jPDblrgpo=
+ =NbgW
+ -----END PGP MESSAGE-----
+
+The "insecure memory" warning is a silly warning that the only way to turn off is to run GPG setuid root.
+You can see in the output that the key comes from PKA.
+
+The "it is NOT certain" warning has nothing to do with the fact that it came
+from DNS. You will get that warning every time you use that key (or any gpg
+key) until you have edited it and assigned ownertrust to it, or until the key
+is signed with a trusted signature, either from your personal web of trust, or
+from a signing service like the pgp.com directory.
+
+3. Ask other people to run it for you and send you the resulting blob. You should be able to decrypt it with your private key.
+
+### PGP CERT Records
+
+Also known as: The "big" CERT record.
+
+Relevant RFCs: [RFC 2538](http://www.faqs.org/rfcs/rfc2538.html),
+[RFC 4398](http://www.faqs.org/rfcs/rfc4398.html), specifically sections 2.1
+and 3.3
+
+#### Advantages
+
+* DNS is all you need. You don't have to host the key elsewhere. As a DNS
+ nerd, this strikes me as very cool.
+
+* Suprisingly easy to verify with dig, if you have a base64 converter handy
+ (openssl includes one)
+
+#### Disadvantages
+
+* These records can get big. Really big. Especially if you have photo-ids on your keys. You can play with export-options to shrink it somewhat. Big dns packets may require EDNS, or dns-over-tcp, which not everyone supports, but support is becoming more widespread as a result of DNSSEC awareness.
+
+* Requires the make-dns-cert tool, which isn't built by default.
+
+* Requires you to have some control over your actual zonefile. Most control panels won't cut it.
+
+* Make-dns-cert currently generates a very ugly record for this.
+
+ #### How to
+
+1. As before, the first step is to figure out which key we want.
+
+ %gpg --list-keys danm@prime.gushi.org
+ Warning: using insecure memory!
+ pub 1024D/624BB249 2000-10-02 &lt;-- I'm going to use this one.
+ uid Daniel P. Mahoney &lt;danm@prime.gushi.org&gt;
+ uid Daniel Mahoney (Secondary Email) &lt;gushi@gushi.org&gt;
+ sub 2048g/DE20C529 2000-10-02
+ pub 1024R/309C17C5 1997-05-08
+ uid Daniel P. Mahoney &lt;danm@prime.gushi.org&gt;
+
+2. We export the key, but this time, it needs to be binary.
+
+ %gpg --export 624BB249 &gt; 624BB249.pub.bin
+ Warning: using insecure memory!
+
+3. We run make-dns-cert on it. make-dns-cert comes with no manual or docs,
+ but running with -h gives you all the clue you need.
+
+ make-dns-cert
+ -f fingerprint
+ -u URL
+ -k key file
+ -n DNS name
+
+So then,
+
+ make-dns-cert -n danm.prime.gushi.org. -k 624BB249.pub.bin
+ <pre>`%make-dns-cert -n danm.prime.gushi.org. -k 624BB249.pub.bin
+ danm.prime.gushi.org. TYPE37 \# 1298 0003 0000 00 9901A20439D8DAF1110400F770EC6AA006076334BEC6DB6FBB237DC194BC0AB8
+ 302C8953F04C28FC2085235D4F10EFA027234FBD63D142CCADD5213AD2B79A22C89ED9B4138370D8220D0F987F993A5364A4A7AC3D42F3765C384
+ 71DDD0FF3372E4AE6F7BEE1E18EF464A0BEB5BBE860A08238891455EBE7CB53D567E981F78ADBD263206B0493ADCB74DD00A0FF0E9A1CD245415E
+ CEF59435162AFCE4CDD14BC70400EA38FF501256E773DEA299404854D99F4EDB2757AA911A9C77C68AB8D6622E517A556C43D21F0523C568F016C
+ D0DB89EF435F0D53B4E07434213F899E6578955DC2C147931E7B6901C9FD8A02705417D69A879B3CC196D2AC2EAEF311192EE89ABAF5A60942167
+ B4625735FCBDFB5DE0E3AC1236A53FA4D7CDD7D75F5DE85AF50400867D9546B28B79AF10541053CF4AB06A6171BFD21458BFD12AF1AE2B2401CAD
+ 8851661F8AF6602F80EDAC99C79616BE1F910F4156242003779C68D7A079A8B18F89DD293E1B247E7420471300A4A0730AA61DE281CCC211FC405
+ A0A8A79877999FF9042AD892AB927DA371E8883BBB370AB7A97841408C3486BB18598CF2559BB42844616E69656C20502E204D61686F6E6579203
+ C64616E6D407072696D652E67757368692E6F72673E884E04101102000E050239D8DAF1040B030102021901000A0910FBBE5A30624BB249FA2E00
+ 9B057503ED498695AE5ED73CA1B98EBAEE13F717E500A0921E0D92724459100266FEBBC29E911C8B0F530BB43244616E69656C204D61686F6E657
+ 920285365636F6E6461727920456D61696C29203C67757368694067757368692E6F72673E8860041311020020050245D49FD7021B23060B090807
+ 030204150208030416020301021E01021780000A0910FBBE5A30624BB249158400A082C8AF43DA8B85F740D6B1A6E9FF0B4490520B8C00A08F77D
+ 21FBF86C842963E8090DC0646D1DD7F95C9B9020D0439D8DAF4100800F64257B7087F081772A2BAD6A942F305E8F95311394FB6F16EB94B3820DA
+ 01A756A314E98F4055F3D007C6CB43A994ADF74C648649F80C83BD65E917D4A1D350F8F5595FDC76524F3D3D8DDBCE99E1579259CDFDB8AE744FC
+ 5FC76BC83C5473061CE7CC966FF15F9BBFD915EC701AAD35B9E8DA0A5723AD41AF0BF4600582BE5F488FD584E49DBCD20B49DE49107366B336C38
+ 0D451D0F7C88B31C7C5B2D8EF6F3C923C043F0A55B188D8EBB558CB85D38D334FD7C175743A31D186CDE33212CB52AFF3CE1B1294018118D7C84A
+ 70A72D686C40319C807297ACA950CD9969FABD00A509B0246D3083D66A45D419F9C7CBD894B221926BAABA25EC355E9320B3B00020207FF5E1A3C
+ C5DA00E1E94EC8EF6C7FE9B49D944C71D8BBC817DD8E64A7344B9E48392E0B833B3B1DB7E6D5A38BE2826DEF0060F78C6417871EAF1CFBCBC47D2
+ 7E93718D975E0A3A36D868C021D6B771740CE2918307D69D614BBF0632DC31932EA31397A7F3B04618C9A76C2F38265C7037E303EDD8AEF03D069
+ 208E3FE9C4EA77D83E6311ED36C013D58C54E914B263A459E22D463A0288510C4752B99C163EEA0A55686979691AB0D9F9AA0C06C834446D7A723
+ EC534D819301382621ACF8930C74E9FD28C8797718AEC2C30CF601E24194B799234104A3D6239657B1D4AD545BDAA637F61541435CB51B4D138FB
+ F55E1A9FD2EED860E4459D6795B6FCCA23155A8846041811020006050239D8DAF4000A0910FBBE5A30624BB249415A009E37BCFDC64E76CBF6A86
+ 82B85EA161BD1DFB793DF00A0C471BC7B9723535CD855D8FF1EB93F01E251B698
+ %
+
+The program prints that all on **one line**.
+
+Immediately, we notice a few things.
+
+* The record type isn't "CERT", it's "TYPE37". This confused me for a while until I discovered [RFC3597](http://www.faqs.org/rfcs/rfc3597.html) Basically, it's a way that a DNS server can handle a resource record it doesn't know about, by giving it some special fields like the "#", as well as a length (which is the 1298 you see there).
+
+* The rest of the record is on one line. I wrapped it for the purposes of brevity. If I were using this in a zonefile, I would need to be careful that I wrapped it on a byte-boundary (every two characters is a byte). If I miss the boundary, named will refuse to load it, dnssec-signzone won't touch it, etc.
+
+4. So the thing is ugly and you don't want to touch it. The easiest way to work with it is to drop all that into a file:
+
+ %make-dns-cert -n danm.prime.gushi.org. -k 624BB249.pub.bin &gt; 624BB249.big.cert
+
+
+5. And then either read it into your editor, or tack it on like this:
+
+ %cat 624BB249.big.cert &gt;&gt; your.zonefile
+
+Be sure to make a backup first. Either way, you never have to copy/paste the raw hex and worry about newlines being inserted where you don't want them.
+
+6. Before you reload your zone, you might want to use named-checkzone on it first:
+
+ prime# named-checkzone gushi.org gushi.org.hosts
+ zone gushi.org/IN: loaded serial 2009102909
+ OK
+ prime#
+
+7. Voice of experience: You may want to dial the TTL (which controls how long servers will cache your data) way down on the record above. It's not hard, just put a number before the TYPE37, with a space, i.e:
+
+ danm.prime.gushi.org. 30 TYPE37
+
+This way if it all goes terribly wrong, or you need to make changes, it won't be cached for very long.
+
+8. If it looks okay, bump your serial number and reload.
+
+#### Testing
+
+1. As above, you can dig, but you won't be able to easily read the results:
+
+ prime# dig +short danm.prime.gushi.org CERT
+ ;; Truncated, retrying in TCP mode.
+
+
+PGP 0 0
+mQGiBDnY2vERBAD3cOxqoAYHYzS+xttvuyN9wZS8CrgwLIlT8Ewo/CCF
+I11PEO+gJyNPvWPRQsyt1SE60reaIsie2bQTg3DYIg0PmH+ZOlNkpKes
+PULzdlw4Rx3dD/M3Lkrm977h4Y70ZKC+tbvoYKCCOIkUVevny1PVZ+mB
+94rb0mMgawSTrct03QCg/w6aHNJFQV7O9ZQ1Fir85M3RS8cEAOo4/1AS
+Vudz3qKZQEhU2Z9O2ydXqpEanHfGirjWYi5RelVsQ9IfBSPFaPAWzQ24
+nvQ18NU7TgdDQhP4meZXiVXcLBR5Mee2kByf2KAnBUF9aah5s8wZbSrC
+6u8xEZLuiauvWmCUIWe0Ylc1/L37XeDjrBI2pT+k183X119d6Fr1BACG
+fZVGsot5rxBUEFPPSrBqYXG/0hRYv9Eq8a4rJAHK2IUWYfivZgL4DtrJ
+nHlha+H5EPQVYkIAN3nGjXoHmosY+J3Sk+GyR+dCBHEwCkoHMKph3igc
+zCEfxAWgqKeYd5mf+QQq2JKrkn2jceiIO7s3CrepeEFAjDSGuxhZjPJV
+m7QoRGFuaWVsIFAuIE1haG9uZXkgPGRhbm1AcHJpbWUuZ3VzaGkub3Jn
+PohOBBARAgAOBQI52NrxBAsDAQICGQEACgkQ+75aMGJLskn6LgCbBXUD
+7UmGla5e1zyhuY667hP3F+UAoJIeDZJyRFkQAmb+u8KekRyLD1MLtDJE
+YW5pZWwgTWFob25leSAoU2Vjb25kYXJ5IEVtYWlsKSA8Z3VzaGlAZ3Vz
+aGkub3JnPohgBBMRAgAgBQJF1J/XAhsjBgsJCAcDAgQVAggDBBYCAwEC
+HgECF4AACgkQ+75aMGJLskkVhACggsivQ9qLhfdA1rGm6f8LRJBSC4wA
+oI930h+/hshClj6AkNwGRtHdf5XJuQINBDnY2vQQCAD2Qle3CH8IF3Ki
+utapQvMF6PlTETlPtvFuuUs4INoBp1ajFOmPQFXz0AfGy0OplK33TGSG
+SfgMg71l6RfUodNQ+PVZX9x2Uk89PY3bzpnhV5JZzf24rnRPxfx2vIPF
+RzBhznzJZv8V+bv9kV7HAarTW56NoKVyOtQa8L9GAFgr5fSI/VhOSdvN
+ILSd5JEHNmszbDgNRR0PfIizHHxbLY7288kjwEPwpVsYjY67VYy4XTjT
+NP18F1dDox0YbN4zISy1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6ypUM
+2Zafq9AKUJsCRtMIPWakXUGfnHy9iUsiGSa6q6Jew1XpMgs7AAICB/9e
+GjzF2gDh6U7I72x/6bSdlExx2LvIF92OZKc0S55IOS4Lgzs7Hbfm1aOL
+4oJt7wBg94xkF4cerxz7y8R9J+k3GNl14KOjbYaMAh1rdxdAzikYMH1p
+1hS78GMtwxky6jE5en87BGGMmnbC84JlxwN+MD7diu8D0Gkgjj/pxOp3
+2D5jEe02wBPVjFTpFLJjpFniLUY6AohRDEdSuZwWPuoKVWhpeWkasNn5
+qgwGyDREbXpyPsU02BkwE4JiGs+JMMdOn9KMh5dxiuwsMM9gHiQZS3mS
+NBBKPWI5ZXsdStVFvapjf2FUFDXLUbTROPv1Xhqf0u7YYORFnWeVtvzK
+IxVaiEYEGBECAAYFAjnY2vQACgkQ+75aMGJLsklBWgCeN7z9xk52y/ao
+aCuF6hYb0d+3k98AoMRxvHuXI1Nc2FXY/x65PwHiUbaY
+
+
+It's still ugly, but it's not AS ugly because it's base64, which includes
+spaces, at least, and is easier to search for a pattern. Base64 can also be
+easily wrapped on any boundary, which is nice.
+
+You can run your existing exported key through a base64 converter, like the
+one built into the openssl binary, if you want to compare:
+
+ %cat 624BB249.pub.bin | openssl enc -base64
+ mQGiBDnY2vERBAD3cOxqoAYHYzS+xttvuyN9wZS8CrgwLIlT8Ewo/CCFI11PEO+g
+ JyNPvWPRQsyt1SE60reaIsie2bQTg3DYIg0PmH+ZOlNkpKesPULzdlw4Rx3dD/M3
+ Lkrm977h4Y70ZKC+tbvoYKCCOIkUVevny1PVZ+mB94rb0mMgawSTrct03QCg/w6a
+ (...etc...)
+ OPv1Xhqf0u7YYORFnWeVtvzKIxVaiEYEGBECAAYFAjnY2vQACgkQ+75aMGJLsklB
+ WgCeN7z9xk52y/aoaCuF6hYb0d+3k98AoMRxvHuXI1Nc2FXY/x65PwHiUbaY
+
+
+Now, while you could compare things byte-by-byte here, what I've done as a
+"casual check" is just pick random strings in the text and see if they match
+up. For example, you can see that "reaIsie2" is present in both. They both
+start with and end with similar strings on every line. The real test, of
+course, is to see if GPG recognizes it as a valid key.
+
+By the way, since I use DNSSEC, dnssec-signzone rewrites this record into the
+proper "presentation format" for me, which is base64. If you want a similar
+function, you can use named-compilezone to get some of the same effects, or
+you can use the shell script I provide later in this document, with which you
+don't even need make-dns-cert.
+
+2. Testing with gpg
+
+As above, the command to test this is remarkably simple:
+
+ %rm /tmp/gpg-*
+ %echo "foo" | gpg --no-default-keyring --keyring /tmp/gpg-$$ --encrypt --armor --auto-key-locate cert -r danm@prime.gushi.org
+ gpg: keyring `/tmp/gpg-39996' created
+ gpg: key 624BB249: public key "Daniel P. Mahoney &lt;danm@prime.gushi.org&gt;" imported
+ gpg: Total number processed: 1
+ gpg: imported: 1
+ gpg: automatically retrieved `danm@prime.gushi.org' via DNS CERT
+ gpg: DE20C529: There is no assurance this key belongs to the named user
+ pub 2048g/DE20C529 2000-10-02 Daniel P. Mahoney &lt;danm@prime.gushi.org&gt;
+ Primary key fingerprint: C206 3054 5492 95F3 3490 37FF FBBE 5A30 624B B249
+ Subkey fingerprint: CE40 B786 81E2 5CB9 F7D3 1318 9488 EB58 DE20 C529
+ It is NOT certain that the key belongs to the person named
+ in the user ID. If you *really* know what you are doing,
+ you may answer the next question with yes.
+ Use this key anyway? (y/N) y
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG v1.4.10 (FreeBSD)
+ hQIOA5SI61jeIMUpEAf/Sx7MKWm+e9EpUTSrDaBp4nJfDcBeqbYJulPRbDZz7eVW
+ 2+ol6sG0jWjuirbG1YppZccEr9mgqaQujdSXb/bleD8POS0TEWuf3aPswFQvHf90
+ NLEzHt6BnfLoeobXXxyCflNaGX8zW+XgJtwZqAc2+jietuz8MOUhrf5m17CsW/wZ
+ IuEqwaek+K1irJp+w3rhaE08Jzb/S4CCifeW9J3mK57chQoPOu7Nz3rY666YKp/3
+ 9T9StOgmFiNpvtFPNy4N7hHMHvbQwRsKlnkl+a7n0Aq2+OF4d1+/k2EE4uSGgcz0
+ oHvee8DnuOx3P92mO4Jz5/0O0lwBD7I51iOjzUurTAgAiIM5sHV8/QFCVzH9Ule+
+ gd8Wo5momcphkU/AXpce5Xgi/Vm4oGQ0x0queii8afUrzkpeN5SuwgQfAdOPiXW5
+ 2bo527jBllxOxjeBasfky82XheTnLzbAQNvQNTEM9zE7zCl1LQJUZEJ1hVzcOevI
+ s+cm/AaGII9VkrAtSt3aLSRZuRJHFmhGvYd2Hz5WzcV1YFjXXP1eLwfetDBlaeB9
+ /K5v4hZBkIZPbHX0DcLVrP96mCIT4wCBYSJw+I6n0E6Fz3IfybQG2HMfqWp966/c
+ 00ijx/aRDh42Dr/fTropuzzFzQr7weYDa1JnN3Zoftv6Zb/n+NcrmMiDCH8jJV6E
+ uMkaeeB5Mv7ssDQ9kPhO989CHFcznrE1lgOxjX8=
+ =NTLY
+ -----END PGP MESSAGE-----
+
+Okay, as above, try to decrypt that with your private key.
+
+### IPGP CERT Records
+
+Also known as: The "little" or "short" CERT record. (These terms are purely my
+own).
+
+Relevant RFCs: [RFC 2538](http://www.faqs.org/rfcs/rfc2538.html),
+[RFC 4398](http://www.faqs.org/rfcs/rfc4398.html), specifically sections 2.1
+and 3.3
+
+IPGP certs are interesting. It's basically the same pieces of infomation that
+are in the PKA record, as above, except that it's supported by an RFC.
+Despite the RFC compliance, I am not sure if any non-gpg client knows to look
+for them. However, because it's a DNS cert, make-dns-cert encodes the
+information in binary, and your DNS server will see it in base64. So
+verifying it visually is harder than verifying either of the above.
+
+#### Advantages
+
+* Small, easy-to-transmit records.
+* Can use the same uri as the PKA record.
+
+#### Disadvantages
+
+* Relies on the URI scheme. I haven't yet been able to get a definitive list
+ of what uri schemes are supported, although I've seen http and finger. I've
+ also seen reports that unless gpg is compiled against curl, http 1.1 is not
+ supported (what this actually means is that any host that supports SSL will
+ probably work, because of some of the nuances of SSL).
+* With PGP certs and IPGP certs, GPG will only parse the first key it gets, so
+ if you publish both, and one doesn't work, there's no failover. I've argued
+ that this should be fixed.
+* Requires make-dns-cert, which is not built in GPG by default. (But see "A
+ Better Way" below)
+* Requires publication in your main DNS zone.
+* Despite being RFC compliant, GPG has additional trust vectors for PKA but
+ not this, despite the fact that they share basically the same information.
+* Harder to verify with dig.
+
+#### Howto
+
+1. Note that some of these steps are redundant. If you're already doing a PKA
+ key, skip to step 5.
+
+2. Dig:
+
+ %gpg --list-keys danm@prime.gushi.org
+ Warning: using insecure memory!
+ pub 1024D/624BB249 2000-10-02 &lt;-- I'm going to use this one.
+ uid Daniel P. Mahoney &lt;danm@prime.gushi.org&gt;
+ uid Daniel Mahoney (Secondary Email) &lt;gushi@gushi.org&gt;
+ sub 2048g/DE20C529 2000-10-02
+ pub 1024R/309C17C5 1997-05-08
+ uid Daniel P. Mahoney &lt;danm@prime.gushi.org&gt;
+
+3. Export the key to a file (I use keyid.pub.asc, but it can be anything)
+
+ %gpg --export --armor 624BB249 &gt; 624BB249.pub.asc
+ Warning: using insecure memory!
+ %
+
+4. Get the fingerprint for your key:
+
+ %gpg --list-keys --fingerprint 624BB249
+ gpg: WARNING: using insecure memory!
+ gpg: please see http://www.gnupg.org/faq.html for more information
+ pub 1024D/624BB249 2000-10-02
+ Key fingerprint = C206 3054 5492 95F3 3490 37FF FBBE 5A30 624B B249 &lt;-- That bit is your fingerprint.
+ uid Daniel P. Mahoney &lt;danm@prime.gushi.org&gt;
+ uid Daniel Mahoney (Secondary Email) &lt;gushi@gushi.org&gt;
+ sub 2048g/DE20C529 2000-10-02
+
+5. As above, run make-dns-cert. This time we use the -n, -f, and -u options:
+
+ %make-dns-cert -n danm.prime.gushi.org. -f C2063054549295F3349037FFFBBE5A30624BB249 -u http://prime.gushi.org/danm.pubkey.txt
+ danm.prime.gushi.org. TYPE37 \# 64 0006 0000 00 14 C2063054549295F3349037FFFBBE5A30624BB249 687474703A2F2F7072696D652E67757368692E6F72672F64616E6D2E7075626B65792E747874
+ %
+
+
+6. Put the above in DNS. All on one line. Optionally add a TTL.
+
+7. IMPORTANT: make sure you don't have any other CERT records with the same
+ label (i.e. a "big" cert, as above). While it won't break things, you have
+ no control over which (of multiple) people will get.
+
+8. Reload your zone, and test. Testing will probably look VERY MUCH like the
+ above, but here are the steps anyway:
+
+#### Testing
+
+1. Dig:
+
+ %dig +short danm.prime.gushi.org CERT
+ 6 0 0 FMIGMFRUkpXzNJA3//u+WjBiS7JJaHR0cDovL3ByaW1lLmd1c2hpLm9y Zy9kYW5tLnB1YmtleS50eHQ=
+
+Sadly, I haven't come across an easy way to decipher it yet, but there's
+always gpg.
+
+2. GPG:
+
+Since we're fetching the same kind of record, the command is exactly the same
+as before:
+
+ %echo "foo" | gpg --no-default-keyring --keyring /tmp/gpg-$$ --encrypt --armor --auto-key-locate cert -r danm@prime.gushi.org
+ gpg: WARNING: using insecure memory!
+ gpg: please see http://www.gnupg.org/faq.html for more information
+ gpg: keyring `/tmp/gpg-39996' created
+ gpg: requesting key 624BB249 from http server prime.gushi.org
+ gpg: key 624BB249: public key "Daniel P. Mahoney &lt;danm@prime.gushi.org&gt;" imported
+ gpg: public key of ultimately trusted key CF45887D not found
+ gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
+ gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
+ gpg: Total number processed: 1
+ gpg: imported: 1
+ gpg: automatically retrieved `danm@prime.gushi.org' via DNS CERT
+ gpg: DE20C529: There is no assurance this key belongs to the named user
+ pub 2048g/DE20C529 2000-10-02 Daniel P. Mahoney &lt;danm@prime.gushi.org&gt;
+ Primary key fingerprint: C206 3054 5492 95F3 3490 37FF FBBE 5A30 624B B249
+ Subkey fingerprint: CE40 B786 81E2 5CB9 F7D3 1318 9488 EB58 DE20 C529
+ It is NOT certain that the key belongs to the person named
+ in the user ID. If you *really* know what you are doing,
+ you may answer the next question with yes.
+ Use this key anyway? (y/N) y
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG v1.4.10 (FreeBSD)
+ hQIOA5SI61jeIMUpEAgApZurJi3hZmDaUFjB2j93eX/lTl96xq6T//sz6nT6jcTx
+ IPnq1RN8IrIQPjDBByHdqOZBT5hhblr9xi7NKIIv3W4q4L0z0fJx7NERPZNvn/H0
+ DkTwfDgAvCRxcKjenpLSwKZFwLjyfS7wjlDr3HFX7Tila0hbzplHslvgTE0QMcd7
+ 7oNmEyOL3z+yZr/afQGp2wpzDv4YB9zOiNHcHcenqX0yrtiqKozZ9VAldi53rb/q
+ f38lwInbveyAcEQkE2iFwhRsbMR4VLcsBoxY6D9brsBprt23ey8Rnv+bQ9IAR0VN
+ /WYzU4zUUqb8HmpNFXQLEgH8A2BENw+bxkVYHjSfWQf/cBSGAzfBQQVJ7qp4tN0Z
+ FRVe51dokbU4NM9tGBdCzFHWARVkQX/Ulekd4F3sxBR/sum1UOT2xl2THVBz7/Pq
+ UCrTRPA0uH4dIbL5JpfGZhqsJ079+wmUWUtJIiO2wXi7ePEA/DrBC6p7jlmjyYN/
+ AeSKcPoTeLX+zryV5bECx4RO6S56EEcy0Ns0pASGMsgUnKL6Adrv3Y6ea3ZAOQMn
+ H9Uo28BKTKNUvUaBpN8cV8jIbKYPPW9i04kvEQRqs5rdamERCY1vVTqYTrcLsNqz
+ fF3KopX+V82X1oE2QuGdFfd8mK57ZXJL3VRUrfohQjhfYNKzougiP46rQQv79MYT
+ j8kazWyJUuufm6NVco1/35Zdp1UhHu8qTgXxrjo=
+ =zY9G
+ -----END PGP MESSAGE-----
+ %
+
+Strangely, the output doesn't say what PKA does (a PKA retrieval has a line
+about fetching via HTTP), however, by checking my webserver logs, I can see it
+retrieved it from there:
+
+ %tail -200 /usr/local/apache/logs/prime.gushi.org.log | grep pubkey | tail -1
+ prime.gushi.org 72.9.101.130 - - [28/Oct/2009:23:50:43 -0400] "GET /danm.pubkey.txt HTTP/1.1" 200 4337 "-" "-"
+ %
+
+As usual, test decryption, etc. You're done.
+
+## Further Steps
+
+* Figure out which of these are useful to you, and use them.* When someone
+ asks for your public key, tell them to run the above command instead of
+ mailing them your key or sending them a keyserver URL.
+
+* Consider using the pka-related verify-options.
+
+* Look into embracing DNSSEC. With a signed root, there's a good trust-path
+ vector here. Who knows, maybe some day GPG will be dnssec-aware so it will
+ give more credit to a secure DNS transaction. Without a signed root, there
+ are still ways to have those who care about security use it, through
+ services such as [ISC's DLV registry](http://dlv.isc.org).
+
+* On DNSSEC: At present, GPG cannot see the difference between an insecure
+ response (one from an unsigned zone) and a correctly validated one from a
+ signed zone. (In a signed zone, an unsigned or malformed will simply get a
+ SERVFAIL dns response). Look into sponsoring development of GPG to make it
+ as an application more aware of this.
+
+## A better way to generate records
+
+In reading over a lot of these commands, I've come across a few problems with
+the tools involved. They either require you to assemble large records by
+hand, or manipulate huge files.
+
+DNS has also come a long way since these tools were written, and RFCs have
+solidified that have determined the "presentation format" (i.e. the "master
+file format") of what CERT records should look like.
+
+On top of everything, the make-dns-cert tool is not built by default, and is
+not present in most binary distributions (RPM's, deb packages, FreeBSD's
+ports).
+
+Thus, I took it upon myself to rewrite make-dns-cert as a shell script.
+
+### Advantages
+
+* Extracts your key for you (takes a keyid as the argument).
+* Formats all three record types for you, you can pipe it right into your zone
+ file.
+* Takes email address as an argument, generates record label.
+* No compiling needed.
+* Should work with most systems. Requires openssl and sed, a few other
+ standard utilities.
+* Generates base64-ified CERT records, split into easy, manageable pieces.
+* Generates DNS-friendly comments, so repeating tasks are easy to reference.
+* (Eventually) available as a tarball, or as a paste-and-go script.
+* Arguments are in logical DNS record order `emailaddress keyid [url]`.
+* Will generate an IPGP CERT record without a URI (this is legal per RFC4398).
+
+You can see sample output
+[here](http://www.gushi.org/make-dns-cert/sample-output.txt), and you can view
+the script itself
+[here](http://www.gushi.org/make-dns-cert/make-dns-cert.sh.txt). Depending on
+your MIME settings, you can probably get a download link if you go
+[here](http://www.gushi.org/make-dns-cert/make-dns-cert.sh). If you see the
+script rather than getting a download prompt, you can just save-as.
+
+README, Changelog, TODO coming soon.
+
+## Other notes
+
+I'm not 100 percent sure (mainly because I haven't tried), but with IPGP cert,
+and PKA, I believe I could in theory point at a keyserver directly, for
+example, specify a uri of
+[http://pgp.mit.edu:11371/pks/lookup?op=get&amp;search=0xB0307039309C17C5](http://pgp.mit.edu:11371/pks/lookup?op=get&amp;search=0xB0307039309C17C5).
+I'm a bit dubious about the question marks and equals-signs, or if I might
+have to uri-encode things. It's something to be tried.
+
+I'm trying to convince the GPG people that this would be much better adopted
+if the make-dns-cert tool was built/included by default, or if its function
+were included in gpg rather than a third-party tool. This is analagous as to
+how dnssec-keygen is used to generate SSHFP DNS records.
+
+It doesn't do any actual cryptography, just some binary conversion, so in
+theory it could be rewritten in pure-perl, so there's nothing to compile.
+
+I've made the argument to the GPG developers that if multiple CERT records are
+available, all should be tried if one fails. So far, if multiple exist, only
+the first received is parsed, and of course, DNS round-robins the answers by
+default.
+
+It took me quite a lot of trial and error to realize that there's a difference
+between "modern" RSA keys, like this:
+
+ %gpg --list-keys --fingerprint gushi@prime.gushi.org
+ pub 2048R/CF45887D 2009-10-29
+ Key fingerprint = FCB0 485E 050D DDFA 83C6 76E3 E722 3C05 CF45 887D
+ uid Gushi Test &lt;gushi@prime.gushi.org&gt;
+ sub 2048R/C9761244 2009-10-29
+
+and ancient RSA keys like this pgp2.6.2 monster:
+
+ %gpg --list-keys --fingerprint danm@prime.gushi.org
+ pub 1024R/309C17C5 1997-05-08
+ Key fingerprint = 04 4B 1A 2E C4 62 95 73 73 A4 EA D0 08 A4 45 76
+ uid Daniel P. Mahoney &lt;danm@prime.gushi.org&gt;
+
+Note the lack of a subkey there. Note the weird fingerprint. I have not been
+able to get this key to properly export with gpg. If someone knows the Deep
+Magic, let me know.
+
+## References
+
+### Blog posts and list threads
+
+While researching this I came across little more than a few blog posts, and a
+few short discussions on the gpg-devel mailing list.
+
+* [A blog entry](http://www.df7cb.de/blog/2007/openpgp-dns.html) that seems to
+ have things mostly right.
+
+* [GPG Mailing List Discussion](http://lists.gnupg.org/pipermail/gnupg-users/2006-April/028314.html)
+ which seems to date towhen these features were first added.
+
+* [My own thread](http://www.mail-archive.com/gnupg-users@gnupg.org/msg12336.html)
+ on the gnupg-users mailing list that led upto this doc.
+
+* [A slideshow of a talk given on PKA](ftp://ftp.g10code.com/people/werner/talks/pka-intro.ps.gz)
+ (really the only doc I couldfind with regard to PKA). Note that this is a
+ postscript doc, for reasons I cannot fathom.
+
+### RFCs
+
+* [RFC 3597](http://www.faqs.org/rfcs/rfc3597.html) defines the odd format of
+ the records that make-dns-cert generates, if itconfuses you.
+
+* [RFC 2538](http://www.faqs.org/rfcs/rfc2538.html), which was superseded by
+ [RFC4398](http://www.faqs.org/rfcs/rfc4398.html), defines the format for a
+ CERT record.
+
+## Todo
+
+* At least one GPG enthusiast has suggested to me that any tools I write to
+ handle keys should simply be able to insert themusing nsupdate. I don't
+ disagree, but there's a complicated metric there as some of these require
+ manipulation of a site'smain zone, or at the very least, many subzones. In
+ doing this I'd also like to find out a bit about how to do nsupdate
+ withsig(0) and KEY records, which with the right policies would mean I could
+ do this without touching named.conf. That may be the subject of a whole
+ other howto.
+
+* (Done) I need to get the shell script cleaned up a bit more, and generate
+ proper docs, and start tracking it with version control.
+
+* I should probably get the gumption up to formally license all this stuff.
+ For right now, I declare it under the
+ [ISCLicense](http://en.wikipedia.org/wiki/ISC_license).
+
+* I'd like to track down the full list of supported URI types for PKA/IPGP
+ CERT records. There doesn't seem to be a defined standard for it.
+
+## Epilogue
+
+### About the author
+
+Dan Mahoney is a Systems Admin in the Bay Area, California. In his spare time
+he enjoys thinking for those brief fleeting moments what he would do if he had
+more free time. Keyid 624BB249, or email address danm@prime.gushi.org.
+
+### About this Document
+
+This document was written in [gnu nano](http://nano-editor.org), and HTML was
+generated using [Markdown](http://daringfireball.net/projects/markdown).
+
+Markdown rocks.
+
+Originally published on my livejournal at
+[http://gushi.livejournal.com/524199.html](http://gushi.livejournal.com/524199.html),
+its main home is at
+[http://www.gushi.org/make-dns-cert/HOWTO.html](http://www.gushi.org/make-dns-cert/HOWTO.html),
+which is where later versions will be published.
+
+Free to use, comments to the above email address are welcome.
diff --git a/docs/DETAILS b/docs/DETAILS
new file mode 100644
index 0000000..d5c5cea
--- /dev/null
+++ b/docs/DETAILS
@@ -0,0 +1,1225 @@
+# doc/DETAILS -*- org -*-
+#+TITLE: GnuPG Details
+# Globally disable superscripts and subscripts:
+#+OPTIONS: ^:{}
+#
+
+# Note: This file uses org-mode; it should be easy to read as plain
+# text but be aware of some markup peculiarities: Verbatim code is
+# enclosed in #+begin-example, #+end-example blocks or marked by a
+# colon as the first non-white-space character, words bracketed with
+# equal signs indicate a monospace font, and the usual /italics/,
+# *bold*, and _underline_ conventions are recognized.
+
+This is the DETAILS file for GnuPG which specifies some internals and
+parts of the external API for GPG and GPGSM.
+
+* Format of the colon listings
+ The format is a based on colon separated record, each recods starts
+ with a tag string and extends to the end of the line. Here is an
+ example:
+#+begin_example
+$ gpg --with-colons --list-keys \
+ --with-fingerprint --with-fingerprint wk@gnupg.org
+pub:f:1024:17:6C7EE1B8621CC013:899817715:1055898235::m:::scESC:
+fpr:::::::::ECAF7590EB3443B5C7CF3ACB6C7EE1B8621CC013:
+uid:f::::::::Werner Koch <wk@g10code.com>:
+uid:f::::::::Werner Koch <wk@gnupg.org>:
+sub:f:1536:16:06AD222CADF6A6E1:919537416:1036177416:::::e:
+fpr:::::::::CF8BCC4B18DE08FCD8A1615906AD222CADF6A6E1:
+sub:r:1536:20:5CE086B5B5A18FF4:899817788:1025961788:::::esc:
+fpr:::::::::AB059359A3B81F410FCFF97F5CE086B5B5A18FF4:
+#+end_example
+
+The double =--with-fingerprint= prints the fingerprint for the subkeys
+too. Old versions of gpg used a lighly different format and required
+the use of the option =--fixed-list-mode= to conform to format
+described here.
+
+** Description of the fields
+*** Field 1 - Type of record
+
+ - pub :: Public key
+ - crt :: X.509 certificate
+ - crs :: X.509 certificate and private key available
+ - sub :: Subkey (secondary key)
+ - sec :: Secret key
+ - ssb :: Secret subkey (secondary key)
+ - uid :: User id (only field 10 is used).
+ - uat :: User attribute (same as user id except for field 10).
+ - sig :: Signature
+ - rev :: Revocation signature
+ - fpr :: Fingerprint (fingerprint is in field 10)
+ - pkd :: Public key data [*]
+ - grp :: Keygrip
+ - rvk :: Revocation key
+ - tru :: Trust database information [*]
+ - spk :: Signature subpacket [*]
+ - cfg :: Configuration data [*]
+
+ Records marked with an asterisk are described at [[*Special%20field%20formats][*Special fields]].
+
+*** Field 2 - Validity
+
+ This is a letter describing the computed validity of a key.
+ Currently this is a single letter, but be prepared that additional
+ information may follow in some future versions. Note that GnuPG <
+ 2.1 does not set this field for secret key listings.
+
+ - o :: Unknown (this key is new to the system)
+ - i :: The key is invalid (e.g. due to a missing self-signature)
+ - d :: The key has been disabled
+ (deprecated - use the 'D' in field 12 instead)
+ - r :: The key has been revoked
+ - e :: The key has expired
+ - - :: Unknown validity (i.e. no value assigned)
+ - q :: Undefined validity. '-' and 'q' may safely be treated as
+ the same value for most purposes
+ - n :: The key is not valid
+ - m :: The key is marginal valid.
+ - f :: The key is fully valid
+ - u :: The key is ultimately valid. This often means that the
+ secret key is available, but any key may be marked as
+ ultimately valid.
+ - w :: The key has a well known private part.
+ - s :: The key has special validity. This means that it might be
+ self-signed and expected to be used in the STEED sytem.
+
+ If the validity information is given for a UID or UAT record, it
+ describes the validity calculated based on this user ID. If given
+ for a key record it describes the validity taken from the best
+ rated user ID.
+
+ For X.509 certificates a 'u' is used for a trusted root
+ certificate (i.e. for the trust anchor) and an 'f' for all other
+ valid certificates.
+
+*** Field 3 - Key length
+
+ The length of key in bits.
+
+*** Field 4 - Public key algorithm
+
+ The values here are those from the OpenPGP specs or if they are
+ greather than 255 the algorithm ids as used by Libgcrypt.
+
+*** Field 5 - KeyID
+
+ This is the 64 bit keyid as specified by OpenPGP and the last 64
+ bit of the SHA-1 fingerprint of an X.509 certifciate.
+
+*** Field 6 - Creation date
+
+ The creation date of the key is given in UTC. For UID and UAT
+ records, this is used for the self-signature date. Note that the
+ date is usally printed in seconds since epoch, however, we are
+ migrating to an ISO 8601 format (e.g. "19660205T091500"). This is
+ currently only relevant for X.509. A simple way to detect the new
+ format is to scan for the 'T'. Note that old versions of gpg
+ without using the =--fixed-list-mode= option used a "yyyy-mm-tt"
+ format.
+
+*** Field 7 - Expiration date
+
+ Key or UID/UAT expiration date or empty if it does not expire.
+
+*** Field 8 - Certificate S/N, UID hash, trust signature info
+
+ Used for serial number in crt records. For UID and UAT records,
+ this is a hash of the user ID contents used to represent that
+ exact user ID. For trust signatures, this is the trust depth
+ seperated by the trust value by a space.
+
+*** Field 9 - Ownertrust
+
+ This is only used on primary keys. This is a single letter, but
+ be prepared that additional information may follow in future
+ versions. For trust signatures with a regular expression, this is
+ the regular expression value, quoted as in field 10.
+
+*** Field 10 - User-ID
+ The value is quoted like a C string to avoid control characters
+ (the colon is quoted =\x3a=). For a "pub" record this field is
+ not used on --fixed-list-mode. A UAT record puts the attribute
+ subpacket count here, a space, and then the total attribute
+ subpacket size. In gpgsm the issuer name comes here. A FPR
+ record stores the fingerprint here. The fingerprint of a
+ revocation key is stored here.
+*** Field 11 - Signature class
+
+ Signature class as per RFC-4880. This is a 2 digit hexnumber
+ followed by either the letter 'x' for an exportable signature or
+ the letter 'l' for a local-only signature. The class byte of an
+ revocation key is also given here, 'x' and 'l' is used the same
+ way. This field if not used for X.509.
+
+*** Field 12 - Key capabilities
+
+ The defined capabilities are:
+
+ - e :: Encrypt
+ - s :: Sign
+ - c :: Certify
+ - a :: Authentication
+ - ? :: Unknown capability
+
+ A key may have any combination of them in any order. In addition
+ to these letters, the primary key has uppercase versions of the
+ letters to denote the _usable_ capabilities of the entire key, and
+ a potential letter 'D' to indicate a disabled key.
+
+*** Field 13 - Issuer certificate fingerprint or other info
+
+ Used in FPR records for S/MIME keys to store the fingerprint of
+ the issuer certificate. This is useful to build the certificate
+ path based on certificates stored in the local key database it is
+ only filled if the issuer certificate is available. The root has
+ been reached if this is the same string as the fingerprint. The
+ advantage of using this value is that it is guaranteed to have
+ been been build by the same lookup algorithm as gpgsm uses.
+
+ For "uid" records this field lists the preferences in the same way
+ gpg's --edit-key menu does.
+
+ For "sig" records, this is the fingerprint of the key that issued
+ the signature. Note that this is only filled in if the signature
+ verified correctly. Note also that for various technical reasons,
+ this fingerprint is only available if --no-sig-cache is used.
+
+*** Field 14 - Flag field
+
+ Flag field used in the --edit menu output
+
+*** Field 15 - S/N of a token
+
+ Used in sec/sbb to print the serial number of a token (internal
+ protect mode 1002) or a '#' if that key is a simple stub (internal
+ protect mode 1001)
+
+*** Field 16 - Hash algorithm
+
+ For sig records, this is the used hash algorithm. For example:
+ 2 = SHA-1, 8 = SHA-256.
+
+** Special fields
+
+*** PKD - Public key data
+
+ If field 1 has the tag "pkd", a listing looks like this:
+#+begin_example
+pkd:0:1024:B665B1435F4C2 .... FF26ABB:
+ ! ! !-- the value
+ ! !------ for information number of bits in the value
+ !--------- index (eg. DSA goes from 0 to 3: p,q,g,y)
+#+end_example
+
+*** TRU - Trust database information
+ Example for a "tru" trust base record:
+#+begin_example
+ tru:o:0:1166697654:1:3:1:5
+#+end_example
+
+ - Field 2 :: Reason for staleness of trust. If this field is
+ empty, then the trustdb is not stale. This field may
+ have multiple flags in it:
+
+ - o :: Trustdb is old
+ - t :: Trustdb was built with a different trust model
+ than the one we are using now.
+
+ - Field 3 :: Trust model
+
+ - 0 :: Classic trust model, as used in PGP 2.x.
+ - 1 :: PGP trust model, as used in PGP 6 and later.
+ This is the same as the classic trust model,
+ except for the addition of trust signatures.
+
+ GnuPG before version 1.4 used the classic trust model
+ by default. GnuPG 1.4 and later uses the PGP trust
+ model by default.
+
+ - Field 4 :: Date trustdb was created in seconds since Epoch.
+ - Field 5 :: Date trustdb will expire in seconds since Epoch.
+ - Field 6 :: Number of marginally trusted users to introduce a new
+ key signer (gpg's option --marginals-needed).
+ - Field 7 :: Number of completely trusted users to introduce a new
+ key signer. (gpg's option --completes-needed)
+
+ - Field 8 :: Maximum depth of a certification chain. (gpg's option
+ --max-cert-depth)
+
+*** SPK - Signature subpacket records
+
+ - Field 2 :: Subpacket number as per RFC-4880 and later.
+ - Field 3 :: Flags in hex. Currently the only two bits assigned
+ are 1, to indicate that the subpacket came from the
+ hashed part of the signature, and 2, to indicate the
+ subpacket was marked critical.
+ - Field 4 :: Length of the subpacket. Note that this is the
+ length of the subpacket, and not the length of field
+ 5 below. Due to the need for %-encoding, the length
+ of field 5 may be up to 3x this value.
+ - Field 5 :: The subpacket data. Printable ASCII is shown as
+ ASCII, but other values are rendered as %XX where XX
+ is the hex value for the byte.
+
+*** CFG - Configuration data
+
+ --list-config outputs information about the GnuPG configuration
+ for the benefit of frontends or other programs that call GnuPG.
+ There are several list-config items, all colon delimited like the
+ rest of the --with-colons output. The first field is always "cfg"
+ to indicate configuration information. The second field is one of
+ (with examples):
+
+ - version :: The third field contains the version of GnuPG.
+
+ : cfg:version:1.3.5
+
+ - pubkey :: The third field contains the public key algorithms
+ this version of GnuPG supports, separated by
+ semicolons. The algorithm numbers are as specified in
+ RFC-4880. Note that in contrast to the --status-fd
+ interface these are _not_ the Libgcrypt identifiers.
+
+ : cfg:pubkey:1;2;3;16;17
+
+ - cipher :: The third field contains the symmetric ciphers this
+ version of GnuPG supports, separated by semicolons.
+ The cipher numbers are as specified in RFC-4880.
+
+ : cfg:cipher:2;3;4;7;8;9;10
+
+ - digest :: The third field contains the digest (hash) algorithms
+ this version of GnuPG supports, separated by
+ semicolons. The digest numbers are as specified in
+ RFC-4880.
+
+ : cfg:digest:1;2;3;8;9;10
+
+ - compress :: The third field contains the compression algorithms
+ this version of GnuPG supports, separated by
+ semicolons. The algorithm numbers are as specified
+ in RFC-4880.
+
+ : cfg:compress:0;1;2;3
+
+ - group :: The third field contains the name of the group, and the
+ fourth field contains the values that the group expands
+ to, separated by semicolons.
+
+ For example, a group of:
+ : group mynames = paige 0x12345678 joe patti
+ would result in:
+ : cfg:group:mynames:patti;joe;0x12345678;paige
+
+
+* Format of the --status-fd output
+
+ Every line is prefixed with "[GNUPG:] ", followed by a keyword with
+ the type of the status line and some arguments depending on the type
+ (maybe none); an application should always be prepared to see more
+ arguments in future versions.
+
+** General status codes
+*** NEWSIG
+ May be issued right before a signature verification starts. This
+ is useful to define a context for parsing ERROR status messages.
+ No arguments are currently defined.
+
+*** GOODSIG <long_keyid_or_fpr> <username>
+ The signature with the keyid is good. For each signature only one
+ of the codes GOODSIG, BADSIG, EXPSIG, EXPKEYSIG, REVKEYSIG or
+ ERRSIG will be emitted. In the past they were used as a marker
+ for a new signature; new code should use the NEWSIG status
+ instead. The username is the primary one encoded in UTF-8 and %XX
+ escaped. The fingerprint may be used instead of the long keyid if
+ it is available. This is the case with CMS and might eventually
+ also be available for OpenPGP.
+
+*** EXPSIG <long_keyid_or_fpr> <username>
+ The signature with the keyid is good, but the signature is
+ expired. The username is the primary one encoded in UTF-8 and %XX
+ escaped. The fingerprint may be used instead of the long keyid if
+ it is available. This is the case with CMS and might eventually
+ also be available for OpenPGP.
+
+*** EXPKEYSIG <long_keyid_or_fpr> <username>
+ The signature with the keyid is good, but the signature was made
+ by an expired key. The username is the primary one encoded in
+ UTF-8 and %XX escaped. The fingerprint may be used instead of the
+ long keyid if it is available. This is the case with CMS and
+ might eventually also be available for OpenPGP.
+
+*** REVKEYSIG <long_keyid_or_fpr> <username>
+ The signature with the keyid is good, but the signature was made
+ by a revoked key. The username is the primary one encoded in UTF-8
+ and %XX escaped. The fingerprint may be used instead of the long
+ keyid if it is available. This is the case with CMS and might
+ eventually also beñ available for OpenPGP.
+
+*** BADSIG <long_keyid_or_fpr> <username>
+ The signature with the keyid has not been verified okay. The
+ username is the primary one encoded in UTF-8 and %XX escaped. The
+ fingerprint may be used instead of the long keyid if it is
+ available. This is the case with CMS and might eventually also be
+ available for OpenPGP.
+
+*** ERRSIG <keyid> <pkalgo> <hashalgo> <sig_class> <time> <rc>
+ It was not possible to check the signature. This may be caused by
+ a missing public key or an unsupported algorithm. A RC of 4
+ indicates unknown algorithm, a 9 indicates a missing public
+ key. The other fields give more information about this signature.
+ sig_class is a 2 byte hex-value. The fingerprint may be used
+ instead of the keyid if it is available. This is the case with
+ gpgsm and might eventually also be available for OpenPGP.
+
+ Note, that TIME may either be the number of seconds since Epoch or
+ the letter 'T'.
+ an ISO 8601 string. The latter can be detected by the presence of
+
+*** VALIDSIG <args>
+
+ The args are:
+
+ - <fingerprint_in_hex>
+ - <sig_creation_date>
+ - <sig-timestamp>
+ - <expire-timestamp>
+ - <sig-version>
+ - <reserved>
+ - <pubkey-algo>
+ - <hash-algo>
+ - <sig-class>
+ - [ <primary-key-fpr> ]
+
+ This status indicates that the signature is good. This is the same
+ as GOODSIG but has the fingerprint as the argument. Both status
+ lines are emitted for a good signature. All arguments here are on
+ one long line. sig-timestamp is the signature creation time in
+ seconds after the epoch. expire-timestamp is the signature
+ expiration time in seconds after the epoch (zero means "does not
+ expire"). sig-version, pubkey-algo, hash-algo, and sig-class (a
+ 2-byte hex value) are all straight from the signature packet.
+ PRIMARY-KEY-FPR is the fingerprint of the primary key or identical
+ to the first argument. This is useful to get back to the primary
+ key without running gpg again for this purpose.
+
+ The primary-key-fpr parameter is used for OpenPGP and not
+ class is not defined for CMS and currently set to 0 and 00.
+ available for CMS signatures. The sig-version as well as the sig
+
+ Note, that *-TIMESTAMP may either be a number of seconds since
+ Epoch or an ISO 8601 string which can be detected by the presence
+ of the letter 'T'.
+
+*** SIG_ID <radix64_string> <sig_creation_date> <sig-timestamp>
+ This is emitted only for signatures of class 0 or 1 which have
+ been verified okay. The string is a signature id and may be used
+ in applications to detect replay attacks of signed messages. Note
+ that only DLP algorithms give unique ids - others may yield
+ duplicated ones when they have been created in the same second.
+
+ Note, that SIG-TIMESTAMP may either be a number of seconds since
+ Epoch or an ISO 8601 string which can be detected by the presence
+ of the letter 'T'.
+
+*** ENC_TO <long_keyid> <keytype> <keylength>
+ The message is encrypted to this LONG_KEYID. KEYTYPE is the
+ numerical value of the public key algorithm or 0 if it is not
+ known, KEYLENGTH is the length of the key or 0 if it is not known
+ (which is currently always the case). Gpg prints this line
+ always; Gpgsm only if it knows the certificate.
+
+*** BEGIN_DECRYPTION
+ Mark the start of the actual decryption process. This is also
+ emitted when in --list-only mode.
+*** END_DECRYPTION
+ Mark the end of the actual decryption process. This are also
+ emitted when in --list-only mode.
+*** DECRYPTION_INFO <mdc_method> <sym_algo>
+ Print information about the symmetric encryption algorithm and the
+ MDC method. This will be emitted even if the decryption fails.
+
+*** DECRYPTION_FAILED
+ The symmetric decryption failed - one reason could be a wrong
+ passphrase for a symmetrical encrypted message.
+
+*** DECRYPTION_OKAY
+ The decryption process succeeded. This means, that either the
+ correct secret key has been used or the correct passphrase for a
+ conventional encrypted message was given. The program itself may
+ return an errorcode because it may not be possible to verify a
+ signature for some reasons.
+
+*** SESSION_KEY <algo>:<hexdigits>
+ The session key used to decrypt the message. This message will
+ only be emitted when the special option --show-session-key is
+ used. The format is suitable to be passed to the option
+ --override-session-key
+
+*** BEGIN_ENCRYPTION <mdc_method> <sym_algo>
+ Mark the start of the actual encryption process.
+
+*** END_ENCRYPTION
+ Mark the end of the actual encryption process.
+
+*** FILE_START <what> <filename>
+ Start processing a file <filename>. <what> indicates the performed
+ operation:
+ - 1 :: verify
+ - 2 :: encrypt
+ - 3 :: decrypt
+
+*** FILE_DONE
+ Marks the end of a file processing which has been started
+ by FILE_START.
+
+*** BEGIN_SIGNING
+ Mark the start of the actual signing process. This may be used as
+ an indication that all requested secret keys are ready for use.
+
+*** ALREADY_SIGNED <long-keyid>
+ Warning: This is experimental and might be removed at any time.
+
+*** SIG_CREATED <type> <pk_algo> <hash_algo> <class> <timestamp> <keyfpr>
+ A signature has been created using these parameters.
+ Values for type <type> are:
+ - D :: detached
+ - C :: cleartext
+ - S :: standard
+ (only the first character should be checked)
+
+ <class> are 2 hex digits with the OpenPGP signature class.
+
+ Note, that TIMESTAMP may either be a number of seconds since Epoch
+ or an ISO 8601 string which can be detected by the presence of the
+ letter 'T'.
+
+*** NOTATION_
+ There are actually two related status codes to convey notation
+ data:
+
+ - NOTATION_NAME <name>
+ - NOTATION_DATA <string>
+
+ <name> and <string> are %XX escaped; the data may be split among
+ several NOTATION_DATA lines.
+
+*** POLICY_URL <string>
+ Note that URL in <string> is %XX escaped.
+
+*** PLAINTEXT <format> <timestamp> <filename>
+ This indicates the format of the plaintext that is about to be
+ written. The format is a 1 byte hex code that shows the format of
+ the plaintext: 62 ('b') is binary data, 74 ('t') is text data with
+ no character set specified, and 75 ('u') is text data encoded in
+ the UTF-8 character set. The timestamp is in seconds since the
+ epoch. If a filename is available it gets printed as the third
+ argument, percent-escaped as usual.
+
+*** PLAINTEXT_LENGTH <length>
+ This indicates the length of the plaintext that is about to be
+ written. Note that if the plaintext packet has partial length
+ encoding it is not possible to know the length ahead of time. In
+ that case, this status tag does not appear.
+
+*** ATTRIBUTE <arguments>
+ The list or argemnts are:
+ - <fpr>
+ - <octets>
+ - <type>
+ - <index>
+ - <count>
+ - <timestamp>
+ - <expiredate>
+ - <flags>
+
+ This is one long line issued for each attribute subpacket when an
+ attribute packet is seen during key listing. <fpr> is the
+ fingerprint of the key. <octets> is the length of the attribute
+ subpacket. <type> is the attribute type (e.g. 1 for an image).
+ <index> and <count> indicate that this is the N-th indexed
+ subpacket of count total subpackets in this attribute packet.
+ <timestamp> and <expiredate> are from the self-signature on the
+ attribute packet. If the attribute packet does not have a valid
+ self-signature, then the timestamp is 0. <flags> are a bitwise OR
+ of:
+ - 0x01 :: this attribute packet is a primary uid
+ - 0x02 :: this attribute packet is revoked
+ - 0x04 :: this attribute packet is expired
+
+*** SIG_SUBPACKET <type> <flags> <len> <data>
+ This indicates that a signature subpacket was seen. The format is
+ the same as the "spk" record above.
+
+** Key related
+*** INV_RECP, INV_SGNR
+ The two similar status codes:
+
+ - INV_RECP <reason> <requested_recipient>
+ - INV_SGNR <reason> <requested_sender>
+
+ are issued for each unusable recipient/sender. The reasons codes
+ currently in use are:
+
+ - 0 :: No specific reason given
+ - 1 :: Not Found
+ - 2 :: Ambigious specification
+ - 3 :: Wrong key usage
+ - 4 :: Key revoked
+ - 5 :: Key expired
+ - 6 :: No CRL known
+ - 7 :: CRL too old
+ - 8 :: Policy mismatch
+ - 9 :: Not a secret key
+ - 10 :: Key not trusted
+ - 11 :: Missing certificate
+ - 12 :: Missing issuer certificate
+
+ Note that for historical reasons the INV_RECP status is also used
+ for gpgsm's SIGNER command where it relates to signer's of course.
+ Newer GnuPG versions are using INV_SGNR; applications should
+ ignore the INV_RECP during the sender's command processing once
+ they have seen an INV_SGNR. Different codes are used so that they
+ can be distinguish while doing an encrypt+sign operation.
+*** NO_RECP <reserved>
+ Issued if no recipients are usable.
+
+*** NO_SGNR <reserved>
+ Issued if no senders are usable.
+
+*** KEYEXPIRED <expire-timestamp>
+ The key has expired. expire-timestamp is the expiration time in
+ seconds since Epoch. This status line is not very useful because
+ it will also be emitted for expired subkeys even if this subkey is
+ not used. To check whether a key used to sign a message has
+ expired, the EXPKEYSIG status line is to be used.
+
+ Note, that the TIMESTAMP may either be a number of seconds since
+ Epoch or an ISO 8601 string which can be detected by the presence
+ of the letter 'T'.
+
+*** KEYREVOKED
+ The used key has been revoked by its owner. No arguments yet.
+
+*** NO_PUBKEY <long keyid>
+ The public key is not available
+
+*** NO_SECKEY <long keyid>
+ The secret key is not available
+
+*** KEY_CREATED <type> <fingerprint> [<handle>]
+ A key has been created. Values for <type> are:
+ - B :: primary and subkey
+ - P :: primary
+ - S :: subkey
+ The fingerprint is one of the primary key for type B and P and the
+ one of the subkey for S. Handle is an arbitrary non-whitespace
+ string used to match key parameters from batch key creation run.
+
+*** KEY_NOT_CREATED [<handle>]
+ The key from batch run has not been created due to errors.
+
+*** TRUST_
+ These are several similar status codes:
+
+ - TRUST_UNDEFINED <error_token>
+ - TRUST_NEVER <error_token>
+ - TRUST_MARGINAL [0 [<validation_model>]]
+ - TRUST_FULLY [0 [<validation_model>]]
+ - TRUST_ULTIMATE [0 [<validation_model>]]
+
+ For good signatures one of these status lines are emitted to
+ indicate the validity of the key used to create the signature.
+ The error token values are currently only emitted by gpgsm.
+
+ VALIDATION_MODEL describes the algorithm used to check the
+ validity of the key. The defaults are the standard Web of Trust
+ model for gpg and the the standard X.509 model for gpgsm. The
+ defined values are
+
+ - pgp :: The standard PGP WoT.
+ - shell :: The standard X.509 model.
+ - chain :: The chain model.
+ - steed :: The STEED model.
+
+ Note that the term =TRUST_= in the status names is used for
+ historic reasons; we now speak of validity.
+
+*** PKA_TRUST_
+ This is is one:
+
+ - PKA_TRUST_GOOD <mailbox>
+ - PKA_TRUST_BAD <mailbox>
+
+ Depending on the outcome of the PKA check one of the above status
+ codes is emitted in addition to a =TRUST_*= status.
+
+** Remote control
+*** GET_BOOL, GET_LINE, GET_HIDDEN, GOT_IT
+
+ These status line are used with --command-fd for interactive
+ control of the process.
+
+*** USERID_HINT <long main keyid> <string>
+ Give a hint about the user ID for a certain keyID.
+
+*** NEED_PASSPHRASE <long keyid> <long main keyid> <keytype> <keylength>
+ Issued whenever a passphrase is needed. KEYTYPE is the numerical
+ value of the public key algorithm or 0 if this is not applicable,
+ KEYLENGTH is the length of the key or 0 if it is not known (this
+ is currently always the case).
+
+*** NEED_PASSPHRASE_SYM <cipher_algo> <s2k_mode> <s2k_hash>
+ Issued whenever a passphrase for symmetric encryption is needed.
+
+*** NEED_PASSPHRASE_PIN <card_type> <chvno> [<serialno>]
+ Issued whenever a PIN is requested to unlock a card.
+
+*** MISSING_PASSPHRASE
+ No passphrase was supplied. An application which encounters this
+ message may want to stop parsing immediately because the next
+ message will probably be a BAD_PASSPHRASE. However, if the
+ application is a wrapper around the key edit menu functionality it
+ might not make sense to stop parsing but simply ignoring the
+ following BAD_PASSPHRASE.
+
+*** BAD_PASSPHRASE <long keyid>
+ The supplied passphrase was wrong or not given. In the latter
+ case you may have seen a MISSING_PASSPHRASE.
+
+*** GOOD_PASSPHRASE
+ The supplied passphrase was good and the secret key material
+ is therefore usable.
+
+** Import/Export
+*** IMPORT_CHECK <long keyid> <fingerprint> <user ID>
+ This status is emitted in interactive mode right before
+ the "import.okay" prompt.
+
+*** IMPORTED <long keyid> <username>
+ The keyid and name of the signature just imported
+
+*** IMPORT_OK <reason> [<fingerprint>]
+ The key with the primary key's FINGERPRINT has been imported.
+ REASON flags are:
+
+ - 0 :: Not actually changed
+ - 1 :: Entirely new key.
+ - 2 :: New user IDs
+ - 4 :: New signatures
+ - 8 :: New subkeys
+ - 16 :: Contains private key.
+
+ The flags may be ORed.
+
+*** IMPORT_PROBLEM <reason> [<fingerprint>]
+ Issued for each import failure. Reason codes are:
+
+ - 0 :: No specific reason given.
+ - 1 :: Invalid Certificate.
+ - 2 :: Issuer Certificate missing.
+ - 3 :: Certificate Chain too long.
+ - 4 :: Error storing certificate.
+
+*** IMPORT_RES <args>
+ Final statistics on import process (this is one long line). The
+ args are a list of unsigned numbers separated by white space:
+
+ - <count>
+ - <no_user_id>
+ - <imported>
+ - <imported_rsa>
+ - <unchanged>
+ - <n_uids>
+ - <n_subk>
+ - <n_sigs>
+ - <n_revoc>
+ - <sec_read>
+ - <sec_imported>
+ - <sec_dups>
+ - <skipped_new_keys>
+ - <not_imported>
+
+** Smartcard related
+*** CARDCTRL <what> [<serialno>]
+ This is used to control smartcard operations. Defined values for
+ WHAT are:
+
+ - 1 :: Request insertion of a card. Serialnumber may be given
+ to request a specific card. Used by gpg 1.4 w/o
+ scdaemon
+ - 2 :: Request removal of a card. Used by gpg 1.4 w/o scdaemon.
+ - 3 :: Card with serialnumber detected
+ - 4 :: No card available
+ - 5 :: No card reader available
+ - 6 :: No card support available
+
+*** SC_OP_FAILURE [<code>]
+ An operation on a smartcard definitely failed. Currently there is
+ no indication of the actual error code, but application should be
+ prepared to later accept more arguments. Defined values for
+ <code> are:
+
+ - 0 :: unspecified error (identically to a missing CODE)
+ - 1 :: canceled
+ - 2 :: bad PIN
+
+*** SC_OP_SUCCESS
+ A smart card operaion succeeded. This status is only printed for
+ certain operation and is mostly useful to check whether a PIN
+ change really worked.
+
+** Miscellaneous status codes
+*** NODATA <what>
+ No data has been found. Codes for WHAT are:
+
+ - 1 :: No armored data.
+ - 2 :: Expected a packet but did not found one.
+ - 3 :: Invalid packet found, this may indicate a non OpenPGP
+ message.
+ - 4 :: Signature expected but not found
+
+ You may see more than one of these status lines.
+
+*** UNEXPECTED <what>
+ Unexpected data has been encountered. Codes for WHAT are:
+ - 0 :: Not further specified
+
+*** TRUNCATED <maxno>
+ The output was truncated to MAXNO items. This status code is
+ issued for certain external requests.
+
+*** ERROR <error location> <error code> [<more>]
+ This is a generic error status message, it might be followed by
+ error location specific data. <error code> and <error_location>
+ should not contain spaces. The error code is a either a string
+ commencing with a letter or such a string prefixed with a
+ numerical error code and an underscore; e.g.: "151011327_EOF".
+
+*** SUCCESS [<location>]
+ Postive confirimation that an operation succeeded. <location> is
+ optional but if given should not contain spaces. Used only with a
+ few commands.
+
+*** BADARMOR
+ The ASCII armor is corrupted. No arguments yet.
+
+*** DELETE_PROBLEM <reason_code>
+ Deleting a key failed. Reason codes are:
+ - 1 :: No such key
+ - 2 :: Must delete secret key first
+ - 3 :: Ambigious specification
+
+*** PROGRESS <what> <char> <cur> <total>
+ Used by the primegen and Public key functions to indicate
+ progress. <char> is the character displayed with no --status-fd
+ enabled, with the linefeed replaced by an 'X'. <cur> is the
+ current amount done and <total> is amount to be done; a <total> of
+ 0 indicates that the total amount is not known. The condition
+ : TOTAL && CUR == TOTAL
+ may be used to detect the end of an operation.
+
+ Well known values for WHAT are:
+
+ - pk_dsa :: DSA key generation
+ - pk_elg :: Elgamal key generation
+ - primegen :: Prime generation
+ - need_entropy :: Waiting for new entropy in the RNG
+ - tick :: Generic tick without any special meaning - useful
+ for letting clients know that the server is still
+ working.
+ - starting_agent :: A gpg-agent was started because it is not
+ running as a daemon.
+ - learncard :: Send by the agent and gpgsm while learing
+ the data of a smartcard.
+ - card_busy :: A smartcard is still working
+
+*** BACKUP_KEY_CREATED <fingerprint> <fname>
+ A backup of a key identified by <fingerprint> has been writte to
+ the file <fname>; <fname> is percent-escaped.
+
+*** MOUNTPOINT <name>
+ <name> is a percent-plus escaped filename describing the
+ mountpoint for the current operation (e.g. used by "g13 --mount").
+ This may either be the specified mountpoint or one randomly
+ choosen by g13.
+
+*** PINENTRY_LAUNCHED <pid>
+ This status line is emitted by gpg to notify a client that a
+ Pinentry has been launched. <pid> is the PID of the Pinentry. It
+ may be used to display a hint to the user but can't be used to
+ synchronize with Pinentry. Note that there is also an Assuan
+ inquiry line with the same name used internally or, if enabled,
+ send to the client instead of this status line. Such an inquiry
+ may be used to sync with Pinentry
+
+** Obsolete status codes
+*** SIGEXPIRED
+ Removed on 2011-02-04. This is deprecated in favor of KEYEXPIRED.
+*** RSA_OR_IDEA
+ Obsolete. This status message used to be emitted for requests to
+ use the IDEA or RSA algorithms. It has been dropped from GnuPG
+ 2.1 after the respective patents expired.
+*** SHM_INFO, SHM_GET, SHM_GET_BOOL, SHM_GET_HIDDEN
+ These were used for the ancient shared memory based co-processing.
+*** BEGIN_STREAM, END_STREAM
+ Used to issued by the experimental pipemode.
+
+
+* Format of the --attribute-fd output
+
+ When --attribute-fd is set, during key listings (--list-keys,
+ --list-secret-keys) GnuPG dumps each attribute packet to the file
+ descriptor specified. --attribute-fd is intended for use with
+ --status-fd as part of the required information is carried on the
+ ATTRIBUTE status tag (see above).
+
+ The contents of the attribute data is specified by RFC 4880. For
+ convenience, here is the Photo ID format, as it is currently the
+ only attribute defined:
+
+ - Byte 0-1 :: The length of the image header. Due to a historical
+ accident (i.e. oops!) back in the NAI PGP days, this
+ is a little-endian number. Currently 16 (0x10 0x00).
+
+ - Byte 2 :: The image header version. Currently 0x01.
+
+ - Byte 3 :: Encoding format. 0x01 == JPEG.
+
+ - Byte 4-15 :: Reserved, and currently unused.
+
+ All other data after this header is raw image (JPEG) data.
+
+
+* Unattended key generation
+
+ Please see the GnuPG manual for a description.
+
+
+* Layout of the TrustDB
+
+ The TrustDB is built from fixed length records, where the first byte
+ describes the record type. All numeric values are stored in network
+ byte order. The length of each record is 40 bytes. The first record
+ of the DB is always of type 1 and this is the only record of this
+ type.
+
+ FIXME: The layout changed, document it here.
+#+begin_example
+ Record type 0:
+ --------------
+ Unused record, can be reused for any purpose.
+
+ Record type 1:
+ --------------
+ Version information for this TrustDB. This is always the first
+ record of the DB and the only one with type 1.
+ 1 byte value 1
+ 3 bytes 'gpg' magic value
+ 1 byte Version of the TrustDB (2)
+ 1 byte marginals needed
+ 1 byte completes needed
+ 1 byte max_cert_depth
+ The three items are used to check whether the cached
+ validity value from the dir record can be used.
+ 1 u32 locked flags [not used]
+ 1 u32 timestamp of trustdb creation
+ 1 u32 timestamp of last modification which may affect the validity
+ of keys in the trustdb. This value is checked against the
+ validity timestamp in the dir records.
+ 1 u32 timestamp of last validation [currently not used]
+ (Used to keep track of the time, when this TrustDB was checked
+ against the pubring)
+ 1 u32 record number of keyhashtable [currently not used]
+ 1 u32 first free record
+ 1 u32 record number of shadow directory hash table [currently not used]
+ It does not make sense to combine this table with the key table
+ because the keyid is not in every case a part of the fingerprint.
+ 1 u32 record number of the trusthashtbale
+
+
+ Record type 2: (directory record)
+ --------------
+ Informations about a public key certificate.
+ These are static values which are never changed without user interaction.
+
+ 1 byte value 2
+ 1 byte reserved
+ 1 u32 LID . (This is simply the record number of this record.)
+ 1 u32 List of key-records (the first one is the primary key)
+ 1 u32 List of uid-records
+ 1 u32 cache record
+ 1 byte ownertrust
+ 1 byte dirflag
+ 1 byte maximum validity of all the user ids
+ 1 u32 time of last validity check.
+ 1 u32 Must check when this time has been reached.
+ (0 = no check required)
+
+
+ Record type 3: (key record)
+ --------------
+ Informations about a primary public key.
+ (This is mainly used to lookup a trust record)
+
+ 1 byte value 3
+ 1 byte reserved
+ 1 u32 LID
+ 1 u32 next - next key record
+ 7 bytes reserved
+ 1 byte keyflags
+ 1 byte pubkey algorithm
+ 1 byte length of the fingerprint (in bytes)
+ 20 bytes fingerprint of the public key
+ (This is the value we use to identify a key)
+
+ Record type 4: (uid record)
+ --------------
+ Informations about a userid
+ We do not store the userid but the hash value of the userid because that
+ is sufficient.
+
+ 1 byte value 4
+ 1 byte reserved
+ 1 u32 LID points to the directory record.
+ 1 u32 next next userid
+ 1 u32 pointer to preference record
+ 1 u32 siglist list of valid signatures
+ 1 byte uidflags
+ 1 byte validity of the key calculated over this user id
+ 20 bytes ripemd160 hash of the username.
+
+
+ Record type 5: (pref record)
+ --------------
+ This record type is not anymore used.
+
+ 1 byte value 5
+ 1 byte reserved
+ 1 u32 LID; points to the directory record (and not to the uid record!).
+ (or 0 for standard preference record)
+ 1 u32 next
+ 30 byte preference data
+
+ Record type 6 (sigrec)
+ -------------
+ Used to keep track of key signatures. Self-signatures are not
+ stored. If a public key is not in the DB, the signature points to
+ a shadow dir record, which in turn has a list of records which
+ might be interested in this key (and the signature record here
+ is one).
+
+ 1 byte value 6
+ 1 byte reserved
+ 1 u32 LID points back to the dir record
+ 1 u32 next next sigrec of this uid or 0 to indicate the
+ last sigrec.
+ 6 times
+ 1 u32 Local_id of signatures dir or shadow dir record
+ 1 byte Flag: Bit 0 = checked: Bit 1 is valid (we have a real
+ directory record for this)
+ 1 = valid is set (but may be revoked)
+
+
+
+ Record type 8: (shadow directory record)
+ --------------
+ This record is used to reserve a LID for a public key. We
+ need this to create the sig records of other keys, even if we
+ do not yet have the public key of the signature.
+ This record (the record number to be more precise) will be reused
+ as the dir record when we import the real public key.
+
+ 1 byte value 8
+ 1 byte reserved
+ 1 u32 LID (This is simply the record number of this record.)
+ 2 u32 keyid
+ 1 byte pubkey algorithm
+ 3 byte reserved
+ 1 u32 hintlist A list of records which have references to
+ this key. This is used for fast access to
+ signature records which are not yet checked.
+ Note, that this is only a hint and the actual records
+ may not anymore hold signature records for that key
+ but that the code cares about this.
+ 18 byte reserved
+
+
+
+ Record Type 10 (hash table)
+ --------------
+ Due to the fact that we use fingerprints to lookup keys, we can
+ implement quick access by some simple hash methods, and avoid
+ the overhead of gdbm. A property of fingerprints is that they can be
+ used directly as hash values. (They can be considered as strong
+ random numbers.)
+ What we use is a dynamic multilevel architecture, which combines
+ hashtables, record lists, and linked lists.
+
+ This record is a hashtable of 256 entries; a special property
+ is that all these records are stored consecutively to make one
+ big table. The hash value is simple the 1st, 2nd, ... byte of
+ the fingerprint (depending on the indirection level).
+
+ When used to hash shadow directory records, a different table is used
+ and indexed by the keyid.
+
+ 1 byte value 10
+ 1 byte reserved
+ n u32 recnum; n depends on the record length:
+ n = (reclen-2)/4 which yields 9 for the current record length
+ of 40 bytes.
+
+ the total number of such record which makes up the table is:
+ m = (256+n-1) / n
+ which is 29 for a record length of 40.
+
+ To look up a key we use the first byte of the fingerprint to get
+ the recnum from this hashtable and look up the addressed record:
+ - If this record is another hashtable, we use 2nd byte
+ to index this hash table and so on.
+ - if this record is a hashlist, we walk all entries
+ until we found one a matching one.
+ - if this record is a key record, we compare the
+ fingerprint and to decide whether it is the requested key;
+
+
+ Record type 11 (hash list)
+ --------------
+ see hash table for an explanation.
+ This is also used for other purposes.
+
+ 1 byte value 11
+ 1 byte reserved
+ 1 u32 next next hash list record
+ n times n = (reclen-5)/5
+ 1 u32 recnum
+
+ For the current record length of 40, n is 7
+
+
+
+ Record type 254 (free record)
+ ---------------
+ All these records form a linked list of unused records.
+ 1 byte value 254
+ 1 byte reserved (0)
+ 1 u32 next_free
+#+end_example
+
+
+* GNU extensions to the S2K algorithm
+
+ S2K mode 101 is used to identify these extensions.
+ After the hash algorithm the 3 bytes "GNU" are used to make
+ clear that these are extensions for GNU, the next bytes gives the
+ GNU protection mode - 1000. Defined modes are:
+ - 1001 :: Do not store the secret part at all.
+ - 1002 :: A stub to access smartcards (not used in 1.2.x)
+
+* Keyserver helper message format
+
+ The keyserver may be contacted by a Unix Domain socket or via TCP.
+
+ The format of a request is:
+#+begin_example
+ command-tag
+ "Content-length:" digits
+ CRLF
+#+end_example
+
+ Where command-tag is
+
+#+begin_example
+ NOOP
+ GET <user-name>
+ PUT
+ DELETE <user-name>
+#+end_example
+
+The format of a response is:
+
+#+begin_example
+ "GNUPG/1.0" status-code status-text
+ "Content-length:" digits
+ CRLF
+#+end_example
+followed by <digits> bytes of data
+
+Status codes are:
+
+ - 1xx :: Informational - Request received, continuing process
+
+ - 2xx :: Success - The action was successfully received, understood,
+ and accepted
+
+ - 4xx :: Client Error - The request contains bad syntax or cannot be
+ fulfilled
+
+ - 5xx :: Server Error - The server failed to fulfill an apparently
+ valid request
+
+
+* Object identifiers
+
+ OIDs below the GnuPG arc:
+
+#+begin_example
+ 1.3.6.1.4.1.11591.2 GnuPG
+ 1.3.6.1.4.1.11591.2.1 notation
+ 1.3.6.1.4.1.11591.2.1.1 pkaAddress
+ 1.3.6.1.4.1.11591.2.2 X.509 extensions
+ 1.3.6.1.4.1.11591.2.2.1 standaloneCertificate
+ 1.3.6.1.4.1.11591.2.2.2 wellKnownPrivateKey
+ 1.3.6.1.4.1.11591.2.12242973 invalid encoded OID
+#+end_example
+
+
+
+* Miscellaneous notes
+
+** v3 fingerprints
+ For packet version 3 we calculate the keyids this way:
+ - RSA :: Low 64 bits of n
+ - ELGAMAL :: Build a v3 pubkey packet (with CTB 0x99) and
+ calculate a RMD160 hash value from it. This is used
+ as the fingerprint and the low 64 bits are the keyid.
+
+** Simplified revocation certificates
+ Revocation certificates consist only of the signature packet;
+ "--import" knows how to handle this. The rationale behind it is to
+ keep them small.
+
+** Documentation on HKP (the http keyserver protocol):
+
+ A minimalistic HTTP server on port 11371 recognizes a GET for
+ /pks/lookup. The standard http URL encoded query parameters are
+ this (always key=value):
+
+ - op=index (like pgp -kv), op=vindex (like pgp -kvv) and op=get (like
+ pgp -kxa)
+
+ - search=<stringlist>. This is a list of words that must occur in the key.
+ The words are delimited with space, points, @ and so on. The delimiters
+ are not searched for and the order of the words doesn't matter (but see
+ next option).
+
+ - exact=on. This switch tells the hkp server to only report exact matching
+ keys back. In this case the order and the "delimiters" are important.
+
+ - fingerprint=on. Also reports the fingerprints when used with 'index' or
+ 'vindex'
+
+ The keyserver also recognizes http-POSTs to /pks/add. Use this to upload
+ keys.
+
+
+ A better way to do this would be a request like:
+
+ /pks/lookup/<gnupg_formatierte_user_id>?op=<operation>
+
+ This can be implemented using Hurd's translator mechanism.
+ However, I think the whole key server stuff has to be re-thought;
+ I have some ideas and probably create a white paper.
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 0000000..2d43a93
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,153 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS = -E -n
+SPHINXBUILD = sphinx-build
+PAPER =
+BUILDDIR = _build
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
+
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " singlehtml to make a single large HTML file"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " devhelp to make HTML files and a Devhelp project"
+ @echo " epub to make an epub"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
+ @echo " text to make text files"
+ @echo " man to make manual pages"
+ @echo " texinfo to make Texinfo files"
+ @echo " info to make Texinfo files and run them through makeinfo"
+ @echo " gettext to make PO message catalogs"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+ -rm -rf $(BUILDDIR)/*
+
+html:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+ @echo
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+ @echo
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/python-gnupg.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/python-gnupg.qhc"
+
+devhelp:
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+ @echo
+ @echo "Build finished."
+ @echo "To view the help file:"
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/python-gnupg"
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/python-gnupg"
+ @echo "# devhelp"
+
+epub:
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+ @echo
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
+ "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through pdflatex..."
+ $(MAKE) -C $(BUILDDIR)/latex all-pdf
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+ @echo
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+ @echo
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+texinfo:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo
+ @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+ @echo "Run \`make' in that directory to run these through makeinfo" \
+ "(use \`make info' here to do that automatically)."
+
+info:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo "Running Texinfo files through makeinfo..."
+ make -C $(BUILDDIR)/texinfo info
+ @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+gettext:
+ $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+ @echo
+ @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/docs/NOTES-python-gnupg-3.1-audit.html b/docs/NOTES-python-gnupg-3.1-audit.html
new file mode 100644
index 0000000..fbd6e0d
--- /dev/null
+++ b/docs/NOTES-python-gnupg-3.1-audit.html
@@ -0,0 +1,946 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+<head>
+<title>python-gnupg audit</title>
+<meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1"/>
+<meta name="title" content="python-gnupg audit"/>
+<meta name="generator" content="Org-mode"/>
+<meta name="generated" content="2013-02-01 Fri"/>
+<meta name="author" content="isis"/>
+<meta name="description" content=""/>
+<meta name="keywords" content=""/>
+<style type="text/css">
+ <!--/*--><![CDATA[/*><!--*/
+ html { font-family: Times, serif; font-size: 12pt; }
+ .title { text-align: center; }
+ .todo { color: red; }
+ .done { color: green; }
+ .tag { background-color: #add8e6; font-weight:normal }
+ .target { }
+ .timestamp { color: #bebebe; }
+ .timestamp-kwd { color: #5f9ea0; }
+ .right {margin-left:auto; margin-right:0px; text-align:right;}
+ .left {margin-left:0px; margin-right:auto; text-align:left;}
+ .center {margin-left:auto; margin-right:auto; text-align:center;}
+ p.verse { margin-left: 3% }
+ pre {
+ border: 1pt solid #AEBDCC;
+ background-color: #F3F5F7;
+ padding: 5pt;
+ font-family: courier, monospace;
+ font-size: 90%;
+ overflow:auto;
+ }
+ table { border-collapse: collapse; }
+ td, th { vertical-align: top; }
+ th.right { text-align:center; }
+ th.left { text-align:center; }
+ th.center { text-align:center; }
+ td.right { text-align:right; }
+ td.left { text-align:left; }
+ td.center { text-align:center; }
+ dt { font-weight: bold; }
+ div.figure { padding: 0.5em; }
+ div.figure p { text-align: center; }
+ div.inlinetask {
+ padding:10px;
+ border:2px solid gray;
+ margin:10px;
+ background: #ffffcc;
+ }
+ textarea { overflow-x: auto; }
+ .linenr { font-size:smaller }
+ .code-highlighted {background-color:#ffff00;}
+ .org-info-js_info-navigation { border-style:none; }
+ #org-info-js_console-label { font-size:10px; font-weight:bold;
+ white-space:nowrap; }
+ .org-info-js_search-highlight {background-color:#ffff00; color:#000000;
+ font-weight:bold; }
+ /*]]>*/-->
+</style>
+<script type="text/javascript">
+/*
+@licstart The following is the entire license notice for the
+JavaScript code in this tag.
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+
+The JavaScript code in this tag is free software: you can
+redistribute it and/or modify it under the terms of the GNU
+General Public License (GNU GPL) as published by the Free Software
+Foundation, either version 3 of the License, or (at your option)
+any later version. The code is distributed WITHOUT ANY WARRANTY;
+without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU GPL for more details.
+
+As additional permission under GNU GPL version 3 section 7, you
+may distribute non-source (e.g., minimized or compacted) forms of
+that code without the copy of the GNU GPL normally required by
+section 4, provided you include this license notice and a URL
+through which recipients can access the Corresponding Source.
+
+
+@licend The above is the entire license notice
+for the JavaScript code in this tag.
+*/
+<!--/*--><![CDATA[/*><!--*/
+ function CodeHighlightOn(elem, id)
+ {
+ var target = document.getElementById(id);
+ if(null != target) {
+ elem.cacheClassElem = elem.className;
+ elem.cacheClassTarget = target.className;
+ target.className = "code-highlighted";
+ elem.className = "code-highlighted";
+ }
+ }
+ function CodeHighlightOff(elem, id)
+ {
+ var target = document.getElementById(id);
+ if(elem.cacheClassElem)
+ elem.className = elem.cacheClassElem;
+ if(elem.cacheClassTarget)
+ target.className = elem.cacheClassTarget;
+ }
+/*]]>*///-->
+</script>
+
+</head>
+<body>
+
+<div id="preamble">
+
+</div>
+
+<div id="content">
+<h1 class="title">python-gnupg audit</h1>
+
+<p> <span class="timestamp-wrapper"> <span class="timestamp">2013-02-01 Fri</span></span><br/>
+</p>
+
+<div id="table-of-contents">
+<h2>Table of Contents</h2>
+<div id="text-table-of-contents">
+<ul>
+<li><a href="#sec-1">1 gnugp._<sub>main</sub>_<sub>()</sub></a>
+<ul>
+<li><a href="#sec-1-1">1.1 comments</a></li>
+<li><a href="#sec-1-2">1.2 def <sub>copy</sub><sub>data</sub>(instream, outstream)</a>
+<ul>
+<li><a href="#sec-1-2-1">1.2.1 L79:</a></li>
+<li><a href="#sec-1-2-2">1.2.2 L78:</a></li>
+<li><a href="#sec-1-2-3">1.2.3 L88:</a></li>
+</ul>
+</li>
+<li><a href="#sec-1-3">1.3 def <sub>threaded</sub><sub>copy</sub><sub>data</sub>(instream, outstream):</a>
+<ul>
+<li><a href="#sec-1-3-1">1.3.1 L99:</a></li>
+</ul>
+</li>
+<li><a href="#sec-1-4">1.4 def <sub>write</sub><sub>passphrase</sub>(stream, passphrase, encoding):</a>
+<ul>
+<li><a href="#sec-1-4-1">1.4.1 L110:</a></li>
+</ul></li>
+</ul>
+</li>
+<li><a href="#sec-2">2 class Verify(object)</a></li>
+<li><a href="#sec-3">3 class ImportResult(object)</a></li>
+<li><a href="#sec-4">4 class ListKeys(list):</a></li>
+<li><a href="#sec-5">5 class Crypt(Verify):</a>
+<ul>
+<li><a href="#sec-5-1">5.1 def _<sub>init</sub>_<sub>(self, gpg)</sub></a>
+<ul>
+<li><a href="#sec-5-1-1">5.1.1 L338</a></li>
+</ul></li>
+</ul>
+</li>
+<li><a href="#sec-6">6 class GenKey(object)</a></li>
+<li><a href="#sec-7">7 class DeleteResult(object)</a></li>
+<li><a href="#sec-8">8 class Sign(object)</a></li>
+<li><a href="#sec-9">9 class GPG(object)</a>
+<ul>
+<li>
+<ul>
+<li><a href="#sec-9-1">9.1 L474:</a></li>
+</ul>
+</li>
+<li><a href="#sec-9-1">9.1 def _<sub>init</sub>_<sub>(self, gpgbinary='gpg', gnupghome=None, verbose=False, use<sub>agent</sub>=False, keyring=None)</sub></a>
+<ul>
+<li><a href="#sec-9-1-1">9.1.1 L494-495:</a></li>
+</ul>
+</li>
+<li><a href="#sec-9-2">9.2 def <sub>open</sub><sub>subprocess</sub>(self, args, passphrase=False)</a>
+<ul>
+<li><a href="#sec-9-2-1">9.2.1 L515:</a></li>
+</ul>
+</li>
+<li><a href="#sec-9-3">9.3 def <sub>collect</sub><sub>output</sub>(self, process, result, writer=None, stdin=None)</a></li>
+<li><a href="#sec-9-4">9.4 def <sub>handle</sub><sub>io</sub>(self, args, file, result, passphrase=None, binary=False)</a>
+<ul>
+<li><a href="#sec-9-4-1">9.4.1 L601:</a></li>
+</ul>
+</li>
+<li><a href="#sec-9-5">9.5 def sign(self, message, **kwargs)</a>
+<ul>
+<li><a href="#sec-9-5-1">9.5.1 L617-619:</a></li>
+</ul>
+</li>
+<li><a href="#sec-9-6">9.6 def sign<sub>file</sub>(self, file, keyid=None, passphrase=None, clearsign=True, detach=False, binary=False)</a>
+<ul>
+<li><a href="#sec-9-6-1">9.6.1 L632-635:</a></li>
+<li><a href="#sec-9-6-2">9.6.2 L626-641:</a></li>
+</ul>
+</li>
+<li><a href="#sec-9-7">9.7 def verify(self, data):</a>
+<ul>
+<li><a href="#sec-9-7-1">9.7.1 L668-670:</a></li>
+</ul>
+</li>
+<li><a href="#sec-9-8">9.8 def verify<sub>file</sub>(self, file, data<sub>filename</sub>=None)</a>
+<ul>
+<li><a href="#sec-9-8-1">9.8.1 L683:</a></li>
+<li><a href="#sec-9-8-2">9.8.2 L684:</a></li>
+<li><a href="#sec-9-8-3">9.8.3 L690:</a></li>
+</ul>
+</li>
+<li><a href="#sec-9-9">9.9 def import<sub>keys</sub>(self, key<sub>data</sub>)</a>
+<ul>
+<li><a href="#sec-9-9-1">9.9.1 L749:</a></li>
+</ul>
+</li>
+<li><a href="#sec-9-10">9.10 def recieve<sub>keys</sub>(self, keyserver, *keyids)</a>
+<ul>
+<li><a href="#sec-9-10-1">9.10.1 L770:</a></li>
+</ul>
+</li>
+<li><a href="#sec-9-11">9.11 def export<sub>keys</sub>(self, keyids, secret=False)</a>
+<ul>
+<li><a href="#sec-9-11-1">9.11.1 L795-796:</a></li>
+</ul>
+</li>
+<li><a href="#sec-9-12">9.12 def list<sub>keys</sub>(self, secret=False)</a>
+<ul>
+<li><a href="#sec-9-12-1">9.12.1 L827:</a></li>
+</ul>
+</li>
+<li><a href="#sec-9-13">9.13 def gen<sub>key</sub>(self, input)</a>
+<ul>
+<li><a href="#sec-9-13-1">9.13.1 L864:</a></li>
+</ul>
+</li>
+<li><a href="#sec-9-14">9.14 def gen<sub>key</sub><sub>input</sub>(self, **kwargs)</a>
+<ul>
+<li><a href="#sec-9-14-1">9.14.1 L981-983:</a></li>
+</ul>
+</li>
+<li><a href="#sec-9-15">9.15 def encrypt<sub>file</sub>(self, file, recipiencts, sign=None, &hellip;)</a>
+<ul>
+<li><a href="#sec-9-15-1">9.15.1 L939:</a></li>
+</ul>
+</li>
+<li><a href="#sec-9-16">9.16 def encrypt(self, data, recipients, **kwargs):</a>
+<ul>
+<li><a href="#sec-9-16-1">9.16.1 L997:</a></li>
+</ul>
+</li>
+<li><a href="#sec-9-17">9.17 def decrypt(self, message **kwargs):</a>
+<ul>
+<li><a href="#sec-9-17-1">9.17.1 L1003:</a></li>
+</ul>
+</li>
+<li><a href="#sec-9-18">9.18 def decrypt<sub>file</sub>(self, file, always<sub>trust</sub>=False, passphrase=None, output=None)</a>
+<ul>
+<li><a href="#sec-9-18-1">9.18.1 L1013:</a></li>
+</ul></li>
+</ul>
+</li>
+<li><a href="#sec-10">10 POC</a></li>
+</ul>
+</div>
+</div>
+
+<div id="outline-container-1" class="outline-2">
+<h2 id="sec-1"><span class="section-number-2">1</span> gnugp._<sub>main</sub>_<sub>()</sub></h2>
+<div class="outline-text-2" id="text-1">
+
+
+</div>
+
+<div id="outline-container-1-1" class="outline-3">
+<h3 id="sec-1-1"><span class="section-number-3">1.1</span> comments</h3>
+<div class="outline-text-3" id="text-1-1">
+
+<p>L58 NullHandler?? see self.<sub>write</sub><sub>passphrase</sub>
+L61 there nifty check for p3k
+</p></div>
+
+</div>
+
+<div id="outline-container-1-2" class="outline-3">
+<h3 id="sec-1-2"><span class="section-number-3">1.2</span> def <sub>copy</sub><sub>data</sub>(instream, outstream) &nbsp;&nbsp;&nbsp;<span class="tag"><span class="cleanup">cleanup</span></span></h3>
+<div class="outline-text-3" id="text-1-2">
+
+<p> copies data from one stream to another, 1024 bytes at a time.
+</p>
+</div>
+
+<div id="outline-container-1-2-1" class="outline-4">
+<h4 id="sec-1-2-1"><span class="section-number-4">1.2.1</span> L79: &nbsp;&nbsp;&nbsp;<span class="tag"><span class="bad_logic">bad_logic</span></span></h4>
+<div class="outline-text-4" id="text-1-2-1">
+
+<p> instream is apparently a file descriptor, but is not checked nor
+ encased in a try/except block.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-1-2-2" class="outline-4">
+<h4 id="sec-1-2-2"><span class="section-number-4">1.2.2</span> L78: &nbsp;&nbsp;&nbsp;<span class="tag"><span class="hanging_fd">hanging_fd</span>&nbsp;<span class="bad_logic">bad_logic</span></span></h4>
+<div class="outline-text-4" id="text-1-2-2">
+
+<p> while True: loop, should be
+</p><pre class="example">
+with open(instream) as instrm:
+</pre>
+
+</div>
+
+</div>
+
+<div id="outline-container-1-2-3" class="outline-4">
+<h4 id="sec-1-2-3"><span class="section-number-4">1.2.3</span> L88: &nbsp;&nbsp;&nbsp;<span class="tag"><span class="bad_exception_handling">bad_exception_handling</span></span></h4>
+<div class="outline-text-4" id="text-1-2-3">
+
+<pre class="example">
+except:
+</pre>
+
+<p> should catch an IOError, or whatever specific error is raised for broken
+ pipes.
+</p></div>
+</div>
+
+</div>
+
+<div id="outline-container-1-3" class="outline-3">
+<h3 id="sec-1-3"><span class="section-number-3">1.3</span> def <sub>threaded</sub><sub>copy</sub><sub>data</sub>(instream, outstream):</h3>
+<div class="outline-text-3" id="text-1-3">
+
+
+</div>
+
+<div id="outline-container-1-3-1" class="outline-4">
+<h4 id="sec-1-3-1"><span class="section-number-4">1.3.1</span> L99:</h4>
+<div class="outline-text-4" id="text-1-3-1">
+
+<p> this just wraps self.<sub>copy</sub><sub>data</sub> in a thread
+</p></div>
+</div>
+
+</div>
+
+<div id="outline-container-1-4" class="outline-3">
+<h3 id="sec-1-4"><span class="section-number-3">1.4</span> def <sub>write</sub><sub>passphrase</sub>(stream, passphrase, encoding): &nbsp;&nbsp;&nbsp;<span class="tag"><span class="vuln">vuln</span>&nbsp;<span class="cleanup">cleanup</span></span></h3>
+<div class="outline-text-3" id="text-1-4">
+
+
+</div>
+
+<div id="outline-container-1-4-1" class="outline-4">
+<h4 id="sec-1-4-1"><span class="section-number-4">1.4.1</span> L110: &nbsp;&nbsp;&nbsp;<span class="tag"><span class="writes_passphrase_to_disk">writes_passphrase_to_disk</span></span></h4>
+<div class="outline-text-4" id="text-1-4-1">
+
+<p> logger writes passphrase into debug log. this should be patched.
+</p></div>
+</div>
+</div>
+
+</div>
+
+<div id="outline-container-2" class="outline-2">
+<h2 id="sec-2"><span class="section-number-2">2</span> class Verify(object)</h2>
+<div class="outline-text-2" id="text-2">
+
+<p> basic parsing class, no errors found
+</p></div>
+
+</div>
+
+<div id="outline-container-3" class="outline-2">
+<h2 id="sec-3"><span class="section-number-2">3</span> class ImportResult(object)</h2>
+<div class="outline-text-2" id="text-3">
+
+<p> basic parsing class, no errors found
+</p></div>
+
+</div>
+
+<div id="outline-container-4" class="outline-2">
+<h2 id="sec-4"><span class="section-number-2">4</span> class ListKeys(list):</h2>
+<div class="outline-text-2" id="text-4">
+
+<p> basic parsing class, no errors found
+</p></div>
+
+</div>
+
+<div id="outline-container-5" class="outline-2">
+<h2 id="sec-5"><span class="section-number-2">5</span> class Crypt(Verify):</h2>
+<div class="outline-text-2" id="text-5">
+
+<p> basic parsing class, no errors found
+</p>
+</div>
+
+<div id="outline-container-5-1" class="outline-3">
+<h3 id="sec-5-1"><span class="section-number-3">5.1</span> def _<sub>init</sub>_<sub>(self, gpg)</sub> &nbsp;&nbsp;&nbsp;<span class="tag"><span class="cleanup">cleanup</span></span></h3>
+<div class="outline-text-3" id="text-5-1">
+
+
+</div>
+
+<div id="outline-container-5-1-1" class="outline-4">
+<h4 id="sec-5-1-1"><span class="section-number-4">5.1.1</span> L338 &nbsp;&nbsp;&nbsp;<span class="tag"><span class="mro_conflict">mro_conflict</span></span></h4>
+<div class="outline-text-4" id="text-5-1-1">
+
+
+
+
+
+<pre class="src src-python">Verify.__init__(<span style="color: #00cdcd; font-weight: bold;">self</span>,gpg)
+</pre>
+
+
+<p>
+ should be changed to:
+</p>
+
+
+
+<pre class="src src-python"><span style="color: #0000ee; font-weight: bold;">super</span>(Verify, <span style="color: #00cdcd; font-weight: bold;">self</span>).__init__(gpg)
+</pre>
+
+</div>
+</div>
+</div>
+
+</div>
+
+<div id="outline-container-6" class="outline-2">
+<h2 id="sec-6"><span class="section-number-2">6</span> class GenKey(object)</h2>
+<div class="outline-text-2" id="text-6">
+
+<p> basic parsing class, no errors found
+</p></div>
+
+</div>
+
+<div id="outline-container-7" class="outline-2">
+<h2 id="sec-7"><span class="section-number-2">7</span> class DeleteResult(object)</h2>
+<div class="outline-text-2" id="text-7">
+
+<p> basic parsing class, no errors found
+</p></div>
+
+</div>
+
+<div id="outline-container-8" class="outline-2">
+<h2 id="sec-8"><span class="section-number-2">8</span> class Sign(object)</h2>
+<div class="outline-text-2" id="text-8">
+
+<p> basic parsing class, no errors found
+</p></div>
+
+</div>
+
+<div id="outline-container-9" class="outline-2">
+<h2 id="sec-9"><span class="section-number-2">9</span> class GPG(object) &nbsp;&nbsp;&nbsp;<span class="tag"><span class="exploitable">exploitable</span></span></h2>
+<div class="outline-text-2" id="text-9">
+
+
+</div>
+
+<div id="outline-container-9-1" class="outline-4">
+<h4 id="sec-9-1"><span class="section-number-4">9.1</span> L474: &nbsp;&nbsp;&nbsp;<span class="tag"><span class="cleanup">cleanup</span></span></h4>
+<div class="outline-text-4" id="text-9-1">
+
+<pre class="example">
+cls.__doc__
+</pre>
+
+<p> should go directly underneath class signature
+</p></div>
+
+</div>
+
+<div id="outline-container-9-1" class="outline-3">
+<h3 id="sec-9-1"><span class="section-number-3">9.1</span> def _<sub>init</sub>_<sub>(self, gpgbinary='gpg', gnupghome=None, verbose=False, use<sub>agent</sub>=False, keyring=None)</sub> &nbsp;&nbsp;&nbsp;<span class="tag"><span class="bug">bug</span></span></h3>
+<div class="outline-text-3" id="text-9-1">
+
+
+</div>
+
+<div id="outline-container-9-1-1" class="outline-4">
+<h4 id="sec-9-1-1"><span class="section-number-4">9.1.1</span> L494-495: &nbsp;&nbsp;&nbsp;<span class="tag"><span class="type_error">type_error</span></span></h4>
+<div class="outline-text-4" id="text-9-1-1">
+
+
+
+
+
+<pre class="src src-python"><span style="color: #00cdcd; font-weight: bold;">if</span> gnupghome <span style="color: #00cdcd; font-weight: bold;">and</span> <span style="color: #00cdcd; font-weight: bold;">not</span> os.path.isdir(<span style="color: #00cdcd; font-weight: bold;">self</span>.gnupghome):
+ os.makedirs(<span style="color: #00cdcd; font-weight: bold;">self</span>.gnupghome,0x1C0)
+</pre>
+
+
+
+<pre class="example">In [20]: os.makedirs?
+Type: function
+String Form:&lt;function makedirs at 0x7f8ddeb6cc08&gt;
+File: /usr/lib/python2.7/os.py
+Definition: os.makedirs(name, mode=511)
+Docstring:
+makedirs(path [, mode=0777])
+Super-mkdir; create a leaf directory and all intermediate ones.
+Works like mkdir, except that any intermediate path segment (not
+just the rightmost) will be created if it does not exist. This is
+recursive.
+
+setting mode=0x1c0 is equivalent to mode=hex(0700), which
+may cause bugs on some systems, see
+http://ubuntuforums.org/showthread.php?t=2044879
+
+this could be do to the complete lack of input validation in
+os.makedirs, and it's calling of the os.mkdir() built-in, which
+may vary depending on the python compilation:
+</pre>
+
+
+
+<pre class="src src-python">Source:
+<span style="color: #00cdcd; font-weight: bold;">def</span> <span style="color: #0000ee; font-weight: bold;">makedirs</span>(name, mode=0777):
+ <span style="color: #00cd00;">"""makedirs(path [, mode=0777])</span>
+
+<span style="color: #00cd00;"> Super-mkdir; create a leaf directory and all intermediate ones.</span>
+<span style="color: #00cd00;"> Works like mkdir, except that any intermediate path segment (not</span>
+<span style="color: #00cd00;"> just the rightmost) will be created if it does not exist. This is</span>
+<span style="color: #00cd00;"> recursive.</span>
+<span style="color: #00cd00;"> """</span>
+ <span style="color: #cdcd00;">head</span>, <span style="color: #cdcd00;">tail</span> = path.split(name)
+ <span style="color: #00cdcd; font-weight: bold;">if</span> <span style="color: #00cdcd; font-weight: bold;">not</span> tail:
+ <span style="color: #cdcd00;">head</span>, <span style="color: #cdcd00;">tail</span> = path.split(head)
+ <span style="color: #00cdcd; font-weight: bold;">if</span> head <span style="color: #00cdcd; font-weight: bold;">and</span> tail <span style="color: #00cdcd; font-weight: bold;">and</span> <span style="color: #00cdcd; font-weight: bold;">not</span> path.exists(head):
+ <span style="color: #00cdcd; font-weight: bold;">try</span>:
+ makedirs(head, mode)
+ <span style="color: #00cdcd; font-weight: bold;">except</span> <span style="color: #00cd00;">OSError</span>, e:
+ <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">be happy if someone already created the path</span>
+ <span style="color: #00cdcd; font-weight: bold;">if</span> e.errno != errno.EEXIST:
+ <span style="color: #00cdcd; font-weight: bold;">raise</span>
+ <span style="color: #00cdcd; font-weight: bold;">if</span> tail == curdir: <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">xxx/newdir/. exists if xxx/newdir exists</span>
+ <span style="color: #00cdcd; font-weight: bold;">return</span>
+ mkdir(name, mode)
+</pre>
+
+
+</div>
+</div>
+
+</div>
+
+<div id="outline-container-9-2" class="outline-3">
+<h3 id="sec-9-2"><span class="section-number-3">9.2</span> def <sub>open</sub><sub>subprocess</sub>(self, args, passphrase=False) &nbsp;&nbsp;&nbsp;<span class="tag"><span class="vuln">vuln</span></span></h3>
+<div class="outline-text-3" id="text-9-2">
+
+
+</div>
+
+<div id="outline-container-9-2-1" class="outline-4">
+<h4 id="sec-9-2-1"><span class="section-number-4">9.2.1</span> L515: &nbsp;&nbsp;&nbsp;<span class="tag"><span class="unvalidated_user_input">unvalidated_user_input</span></span></h4>
+<div class="outline-text-4" id="text-9-2-1">
+
+<pre class="example">
+cmd.extend(args)
+</pre>
+
+
+<p>
+ cmd is a list of strings, eventually joined with cmd=' '.join(cmd), and
+ the args are unvalidated in this function. Then this concatenation of args
+ is fed directly into subprocess.Popen(cmd, shell=True, stdin=PIPE,
+ stdout=PIPE, stderr=PIPE). THIS SHOULD BE PATCHED.
+</p>
+</div>
+</div>
+
+</div>
+
+<div id="outline-container-9-3" class="outline-3">
+<h3 id="sec-9-3"><span class="section-number-3">9.3</span> def <sub>collect</sub><sub>output</sub>(self, process, result, writer=None, stdin=None)</h3>
+<div class="outline-text-3" id="text-9-3">
+
+<p> sends stdout to self.<sub>read</sub><sub>data</sub>() and stderr to self.<sub>read</sub><sub>response</sub>()
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-9-4" class="outline-3">
+<h3 id="sec-9-4"><span class="section-number-3">9.4</span> def <sub>handle</sub><sub>io</sub>(self, args, file, result, passphrase=None, binary=False) &nbsp;&nbsp;&nbsp;<span class="tag"><span class="vuln">vuln</span>&nbsp;<span class="cleanup">cleanup</span></span></h3>
+<div class="outline-text-3" id="text-9-4">
+
+
+</div>
+
+<div id="outline-container-9-4-1" class="outline-4">
+<h4 id="sec-9-4-1"><span class="section-number-4">9.4.1</span> L601: &nbsp;&nbsp;&nbsp;<span class="tag"><span class="unvalidated_user_input">unvalidated_user_input</span>&nbsp;<span class="type_check_in_call">type_check_in_call</span></span></h4>
+<div class="outline-text-4" id="text-9-4-1">
+
+<pre class="example">
+p = self._open_subprocess(args, passphrase is not None)
+</pre>
+
+
+<p>
+ you shouldn't assign or type check in a function call
+</p>
+</div>
+</div>
+
+</div>
+
+<div id="outline-container-9-5" class="outline-3">
+<h3 id="sec-9-5"><span class="section-number-3">9.5</span> def sign(self, message, **kwargs) &nbsp;&nbsp;&nbsp;<span class="tag"><span class="cleanup">cleanup</span></span></h3>
+<div class="outline-text-3" id="text-9-5">
+
+
+</div>
+
+<div id="outline-container-9-5-1" class="outline-4">
+<h4 id="sec-9-5-1"><span class="section-number-4">9.5.1</span> L617-619: &nbsp;&nbsp;&nbsp;<span class="tag"><span class="hanging_fd">hanging_fd</span></span></h4>
+<div class="outline-text-4" id="text-9-5-1">
+
+<p> calls self.<sub>make</sub><sub>binary</sub><sub>stream</sub>(), which leaves the file descriptor for
+ the encoded message to be encrypted hanging between scopes.
+</p>
+</div>
+</div>
+
+</div>
+
+<div id="outline-container-9-6" class="outline-3">
+<h3 id="sec-9-6"><span class="section-number-3">9.6</span> def sign<sub>file</sub>(self, file, keyid=None, passphrase=None, clearsign=True, detach=False, binary=False) &nbsp;&nbsp;&nbsp;<span class="tag"><span class="cleanup">cleanup</span></span></h3>
+<div class="outline-text-3" id="text-9-6">
+
+
+</div>
+
+<div id="outline-container-9-6-1" class="outline-4">
+<h4 id="sec-9-6-1"><span class="section-number-4">9.6.1</span> L632-635: &nbsp;&nbsp;&nbsp;<span class="tag"><span class="bad_logic">bad_logic</span></span></h4>
+<div class="outline-text-4" id="text-9-6-1">
+
+
+
+
+<pre class="src src-python"><span style="color: #00cdcd; font-weight: bold;">if</span> detach:
+ args.append(<span style="color: #00cd00;">"--detach-sign"</span>)
+<span style="color: #00cdcd; font-weight: bold;">elif</span> clearsign:
+ args.append(<span style="color: #00cd00;">"--clearsign"</span>)
+</pre>
+
+
+<p>
+ the logic here allows that if a user erroneously specifies both options,
+ rather than doing what the system gnupg would do (that is, do &ndash;clearsign,
+ and ignore the &ndash;attach-sign), python-gnupg would ignore both.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-9-6-2" class="outline-4">
+<h4 id="sec-9-6-2"><span class="section-number-4">9.6.2</span> L626-641:</h4>
+<div class="outline-text-4" id="text-9-6-2">
+
+<p> input 'args' into self.<sub>open</sub><sub>subprocess</sub>() is defined as static strings.
+</p>
+</div>
+</div>
+
+</div>
+
+<div id="outline-container-9-7" class="outline-3">
+<h3 id="sec-9-7"><span class="section-number-3">9.7</span> def verify(self, data): &nbsp;&nbsp;&nbsp;<span class="tag"><span class="cleanup">cleanup</span></span></h3>
+<div class="outline-text-3" id="text-9-7">
+
+
+</div>
+
+<div id="outline-container-9-7-1" class="outline-4">
+<h4 id="sec-9-7-1"><span class="section-number-4">9.7.1</span> L668-670: &nbsp;&nbsp;&nbsp;<span class="tag"><span class="hanging_fd">hanging_fd</span></span></h4>
+<div class="outline-text-4" id="text-9-7-1">
+
+<p> same hanging file descriptor problem as in self.sign()
+</p>
+</div>
+</div>
+
+</div>
+
+<div id="outline-container-9-8" class="outline-3">
+<h3 id="sec-9-8"><span class="section-number-3">9.8</span> def verify<sub>file</sub>(self, file, data<sub>filename</sub>=None) &nbsp;&nbsp;&nbsp;<span class="tag"><span class="vuln">vuln</span>&nbsp;<span class="cleanup">cleanup</span></span></h3>
+<div class="outline-text-3" id="text-9-8">
+
+
+</div>
+
+<div id="outline-container-9-8-1" class="outline-4">
+<h4 id="sec-9-8-1"><span class="section-number-4">9.8.1</span> L683: &nbsp;&nbsp;&nbsp;<span class="tag"><span class="hanging_fd">hanging_fd</span></span></h4>
+<div class="outline-text-4" id="text-9-8-1">
+
+<p> more potentially hanging file descriptors&hellip;
+</p></div>
+
+</div>
+
+<div id="outline-container-9-8-2" class="outline-4">
+<h4 id="sec-9-8-2"><span class="section-number-4">9.8.2</span> L684: &nbsp;&nbsp;&nbsp;<span class="tag"><span class="hanging_fd">hanging_fd</span></span></h4>
+<div class="outline-text-4" id="text-9-8-2">
+
+<p> oh look, another hanging file descriptor. imagine that.
+</p></div>
+
+</div>
+
+<div id="outline-container-9-8-3" class="outline-4">
+<h4 id="sec-9-8-3"><span class="section-number-4">9.8.3</span> L690: &nbsp;&nbsp;&nbsp;<span class="tag"><span class="unvalidated_user_input">unvalidated_user_input</span></span></h4>
+<div class="outline-text-4" id="text-9-8-3">
+
+<pre class="example">
+args.append('"%s"' % data_filename)
+</pre>
+
+<p> well, there's the exploit. see included POC script.
+</p>
+</div>
+</div>
+
+</div>
+
+<div id="outline-container-9-9" class="outline-3">
+<h3 id="sec-9-9"><span class="section-number-3">9.9</span> def import<sub>keys</sub>(self, key<sub>data</sub>) &nbsp;&nbsp;&nbsp;<span class="tag"><span class="vuln">vuln</span></span></h3>
+<div class="outline-text-3" id="text-9-9">
+
+
+</div>
+
+<div id="outline-container-9-9-1" class="outline-4">
+<h4 id="sec-9-9-1"><span class="section-number-4">9.9.1</span> L749: &nbsp;&nbsp;&nbsp;<span class="tag"><span class="unvalidated_user_input">unvalidated_user_input</span></span></h4>
+<div class="outline-text-4" id="text-9-9-1">
+
+<p> this function could potentially allow an attacker with a GPG exploit to
+ use it, because it passes key generation parameter directly into the
+ internal packet parsers of GPG. however, without a GPG exploit for one of
+ the GPG packet parsers (for explanation of GPG packets look into pgpdump),
+ this function alone is not exploitable.
+</p>
+</div>
+</div>
+
+</div>
+
+<div id="outline-container-9-10" class="outline-3">
+<h3 id="sec-9-10"><span class="section-number-3">9.10</span> def recieve<sub>keys</sub>(self, keyserver, *keyids) &nbsp;&nbsp;&nbsp;<span class="tag"><span class="vuln">vuln</span></span></h3>
+<div class="outline-text-3" id="text-9-10">
+
+
+</div>
+
+<div id="outline-container-9-10-1" class="outline-4">
+<h4 id="sec-9-10-1"><span class="section-number-4">9.10.1</span> L770: &nbsp;&nbsp;&nbsp;<span class="tag"><span class="unvalidated_user_input">unvalidated_user_input</span></span></h4>
+<div class="outline-text-4" id="text-9-10-1">
+
+<pre class="example">
+args.extend(keyids)
+</pre>
+
+
+</div>
+</div>
+
+</div>
+
+<div id="outline-container-9-11" class="outline-3">
+<h3 id="sec-9-11"><span class="section-number-3">9.11</span> def export<sub>keys</sub>(self, keyids, secret=False) &nbsp;&nbsp;&nbsp;<span class="tag"><span class="vuln">vuln</span></span></h3>
+<div class="outline-text-3" id="text-9-11">
+
+
+</div>
+
+<div id="outline-container-9-11-1" class="outline-4">
+<h4 id="sec-9-11-1"><span class="section-number-4">9.11.1</span> L795-796: &nbsp;&nbsp;&nbsp;<span class="tag"><span class="unvalidated_user_input">unvalidated_user_input</span></span></h4>
+<div class="outline-text-4" id="text-9-11-1">
+
+<p> args problem again. exploitable though parameter ``keyids``.
+</p>
+</div>
+</div>
+
+</div>
+
+<div id="outline-container-9-12" class="outline-3">
+<h3 id="sec-9-12"><span class="section-number-3">9.12</span> def list<sub>keys</sub>(self, secret=False)</h3>
+<div class="outline-text-3" id="text-9-12">
+
+
+</div>
+
+<div id="outline-container-9-12-1" class="outline-4">
+<h4 id="sec-9-12-1"><span class="section-number-4">9.12.1</span> L827:</h4>
+<div class="outline-text-4" id="text-9-12-1">
+
+<p> args is static string.
+</p>
+</div>
+</div>
+
+</div>
+
+<div id="outline-container-9-13" class="outline-3">
+<h3 id="sec-9-13"><span class="section-number-3">9.13</span> def gen<sub>key</sub>(self, input) &nbsp;&nbsp;&nbsp;<span class="tag"><span class="cleanup">cleanup</span></span></h3>
+<div class="outline-text-3" id="text-9-13">
+
+
+</div>
+
+<div id="outline-container-9-13-1" class="outline-4">
+<h4 id="sec-9-13-1"><span class="section-number-4">9.13.1</span> L864:</h4>
+<div class="outline-text-4" id="text-9-13-1">
+
+<p> args, passed to self.<sub>handle</sub><sub>io</sub>(), which in turn passes args directly to
+ Popen(), is set to a static string. this function is halfway okay, though
+ it really could be more careful with the ``input`` parameter.
+</p>
+</div>
+</div>
+
+</div>
+
+<div id="outline-container-9-14" class="outline-3">
+<h3 id="sec-9-14"><span class="section-number-3">9.14</span> def gen<sub>key</sub><sub>input</sub>(self, **kwargs) &nbsp;&nbsp;&nbsp;<span class="tag"><span class="vuln">vuln</span></span></h3>
+<div class="outline-text-3" id="text-9-14">
+
+
+</div>
+
+<div id="outline-container-9-14-1" class="outline-4">
+<h4 id="sec-9-14-1"><span class="section-number-4">9.14.1</span> L981-983: &nbsp;&nbsp;&nbsp;<span class="tag"><span class="unvalidated_user_input">unvalidated_user_input</span></span></h4>
+<div class="outline-text-4" id="text-9-14-1">
+
+<p> this function could potentially allow an attacker with a GPG exploit to
+ use it, because it passes key generation parameter directly into the
+ internal packet parsers of GPG. however, without a GPG exploit for one of
+ the GPG packet parsers (for explanation of GPG packets look into pgpdump),
+ this function alone is not exploitable.
+</p>
+</div>
+</div>
+
+</div>
+
+<div id="outline-container-9-15" class="outline-3">
+<h3 id="sec-9-15"><span class="section-number-3">9.15</span> def encrypt<sub>file</sub>(self, file, recipiencts, sign=None, &hellip;) &nbsp;&nbsp;&nbsp;<span class="tag"><span class="vuln">vuln</span></span></h3>
+<div class="outline-text-3" id="text-9-15">
+
+
+</div>
+
+<div id="outline-container-9-15-1" class="outline-4">
+<h4 id="sec-9-15-1"><span class="section-number-4">9.15.1</span> L939: &nbsp;&nbsp;&nbsp;<span class="tag"><span class="unvalidated_user_input">unvalidated_user_input</span></span></h4>
+<div class="outline-text-4" id="text-9-15-1">
+
+<p> several of the inputs to this function are unvalidated, turned into
+ strings, and passed to Popen(). exploitable.
+</p>
+</div>
+</div>
+
+</div>
+
+<div id="outline-container-9-16" class="outline-3">
+<h3 id="sec-9-16"><span class="section-number-3">9.16</span> def encrypt(self, data, recipients, **kwargs): &nbsp;&nbsp;&nbsp;<span class="tag"><span class="vuln">vuln</span></span></h3>
+<div class="outline-text-3" id="text-9-16">
+
+
+</div>
+
+<div id="outline-container-9-16-1" class="outline-4">
+<h4 id="sec-9-16-1"><span class="section-number-4">9.16.1</span> L997: &nbsp;&nbsp;&nbsp;<span class="tag"><span class="unvalidated_user_input">unvalidated_user_input</span></span></h4>
+<div class="outline-text-4" id="text-9-16-1">
+
+<p> exploitable, passes kwargs to self.encrypt<sub>file</sub>()
+</p>
+</div>
+</div>
+
+</div>
+
+<div id="outline-container-9-17" class="outline-3">
+<h3 id="sec-9-17"><span class="section-number-3">9.17</span> def decrypt(self, message **kwargs): &nbsp;&nbsp;&nbsp;<span class="tag"><span class="vuln">vuln</span></span></h3>
+<div class="outline-text-3" id="text-9-17">
+
+
+</div>
+
+<div id="outline-container-9-17-1" class="outline-4">
+<h4 id="sec-9-17-1"><span class="section-number-4">9.17.1</span> L1003: &nbsp;&nbsp;&nbsp;<span class="tag"><span class="unvalidated_user_input">unvalidated_user_input</span></span></h4>
+<div class="outline-text-4" id="text-9-17-1">
+
+<p> kwargs are passed to self.decrypt<sub>file</sub>(), unvalidated, making this
+ function also exploitable
+</p>
+</div>
+</div>
+
+</div>
+
+<div id="outline-container-9-18" class="outline-3">
+<h3 id="sec-9-18"><span class="section-number-3">9.18</span> def decrypt<sub>file</sub>(self, file, always<sub>trust</sub>=False, passphrase=None, output=None) &nbsp;&nbsp;&nbsp;<span class="tag"><span class="vuln">vuln</span></span></h3>
+<div class="outline-text-3" id="text-9-18">
+
+
+</div>
+
+<div id="outline-container-9-18-1" class="outline-4">
+<h4 id="sec-9-18-1"><span class="section-number-4">9.18.1</span> L1013: &nbsp;&nbsp;&nbsp;<span class="tag"><span class="unvalidated_user_input">unvalidated_user_input</span></span></h4>
+<div class="outline-text-4" id="text-9-18-1">
+
+<p> unvalidated user input: this function is also exploitable
+</p>
+</div>
+</div>
+</div>
+
+</div>
+
+<div id="outline-container-10" class="outline-2">
+<h2 id="sec-10"><span class="section-number-2">10</span> POC</h2>
+<div class="outline-text-2" id="text-10">
+
+<p>CANNOT INCLUDE FILE ../python-gnupg-0.3.1/python-gnupg-exploit.py
+</p></div>
+</div>
+</div>
+
+<div id="postamble">
+<p class="date">Date: 2013-02-01 Fri</p>
+<p class="author">Author: isis</p>
+<p class="email"><a href="mailto:isis@leap.se">isis@leap.se</a></p>
+<p class="creator"><a href="http://orgmode.org">Org</a> version 7.9.2 with <a href="http://www.gnu.org/software/emacs/">Emacs</a> version 24</p>
+<a href="http://validator.w3.org/check?uri=referer">Validate XHTML 1.0</a>
+
+</div>
+</body>
+</html>
diff --git a/docs/NOTES-python-gnupg-3.1-audit.org b/docs/NOTES-python-gnupg-3.1-audit.org
new file mode 100644
index 0000000..b80fb39
--- /dev/null
+++ b/docs/NOTES-python-gnupg-3.1-audit.org
@@ -0,0 +1,232 @@
+#+TITLE: python-gnupg audit
+#+AUTHOR: isis
+#+EMAIL: isis@leap.se
+#+DATE: 2013-02-01 Fri
+#+DESCRIPTION:
+#+KEYWORDS:
+#+LANGUAGE: en
+#+OPTIONS: H:3 num:t toc:t \n:nil @:t ::t |:t ^:t -:t f:t *:t <:t
+#+OPTIONS: TeX:t LaTeX:t skip:nil d:nil todo:t pri:nil tags:not-in-toc
+#+INFOJS_OPT: view:nil toc:2 ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js
+#+EXPORT_SELECT_TAGS: export
+#+EXPORT_EXCLUDE_TAGS: noexport
+#+LINK_UP:
+#+LINK_HOME:
+#+XSLT:
+
+[2013-02-01 Fri]
+
+* gnugp.__main__()
+** comments
+L58 NullHandler?? see self._write_passphrase
+L61 there nifty check for p3k
+** def _copy_data(instream, outstream) :cleanup:
+ copies data from one stream to another, 1024 bytes at a time.
+*** L79: :bad_logic:
+ instream is apparently a file descriptor, but is not checked nor
+ encased in a try/except block.
+
+*** L78: :hanging_fd:bad_logic:
+ while True: loop, should be
+ : with open(instream) as instrm:
+*** L88: :bad_exception_handling:
+ : except:
+ should catch an IOError, or whatever specific error is raised for broken
+ pipes.
+** def _threaded_copy_data(instream, outstream):
+*** L99:
+ this just wraps self._copy_data in a thread
+** def _write_passphrase(stream, passphrase, encoding): :vuln:cleanup:
+*** L110: :writes_passphrase_to_disk:
+ logger writes passphrase into debug log. this should be patched.
+* class Verify(object)
+ basic parsing class, no errors found
+* class ImportResult(object)
+ basic parsing class, no errors found
+* class ListKeys(list):
+ basic parsing class, no errors found
+* class Crypt(Verify):
+ basic parsing class, no errors found
+** def __init__(self, gpg) :cleanup:
+*** L338 :mro_conflict:
+
+ #+BEGIN_SRC python
+ Verify.__init__(self,gpg)
+ #+END_SRC
+
+ should be changed to:
+
+ #+BEGIN_SRC python
+ super(Verify, self).__init__(gpg)
+ #+END_SRC
+* class GenKey(object)
+ basic parsing class, no errors found
+* class DeleteResult(object)
+ basic parsing class, no errors found
+* class Sign(object)
+ basic parsing class, no errors found
+* class GPG(object) :exploitable:
+*** L474: :cleanup:
+ : cls.__doc__
+ should go directly underneath class signature
+** def __init__(self, gpgbinary='gpg', gnupghome=None, verbose=False, use_agent=False, keyring=None) :bug:
+*** L494-495: :type_error:
+
+ #+BEGIN_SRC python
+ if gnupghome and not os.path.isdir(self.gnupghome):
+ os.makedirs(self.gnupghome,0x1C0)
+ #+END_SRC
+
+ #+BEGIN_EXAMPLE
+ In [20]: os.makedirs?
+ Type: function
+ String Form:<function makedirs at 0x7f8ddeb6cc08>
+ File: /usr/lib/python2.7/os.py
+ Definition: os.makedirs(name, mode=511)
+ Docstring:
+ makedirs(path [, mode=0777])
+ Super-mkdir; create a leaf directory and all intermediate ones.
+ Works like mkdir, except that any intermediate path segment (not
+ just the rightmost) will be created if it does not exist. This is
+ recursive.
+
+ setting mode=0x1c0 is equivalent to mode=hex(0700), which
+ may cause bugs on some systems, see
+ http://ubuntuforums.org/showthread.php?t=2044879
+
+ this could be do to the complete lack of input validation in
+ os.makedirs, and it's calling of the os.mkdir() built-in, which
+ may vary depending on the python compilation:
+ #+END_EXAMPLE
+
+ #+BEGIN_SRC python
+ Source:
+ def makedirs(name, mode=0777):
+ """makedirs(path [, mode=0777])
+
+ Super-mkdir; create a leaf directory and all intermediate ones.
+ Works like mkdir, except that any intermediate path segment (not
+ just the rightmost) will be created if it does not exist. This is
+ recursive.
+ """
+ head, tail = path.split(name)
+ if not tail:
+ head, tail = path.split(head)
+ if head and tail and not path.exists(head):
+ try:
+ makedirs(head, mode)
+ except OSError, e:
+ # be happy if someone already created the path
+ if e.errno != errno.EEXIST:
+ raise
+ if tail == curdir: # xxx/newdir/. exists if xxx/newdir exists
+ return
+ mkdir(name, mode)
+ #+END_SRC
+
+** def _open_subprocess(self, args, passphrase=False) :vuln:
+*** L515: :unvalidated_user_input:
+ : cmd.extend(args)
+
+ cmd is a list of strings, eventually joined with cmd=' '.join(cmd), and
+ the args are unvalidated in this function. Then this concatenation of args
+ is fed directly into subprocess.Popen(cmd, shell=True, stdin=PIPE,
+ stdout=PIPE, stderr=PIPE). THIS SHOULD BE PATCHED.
+
+** def _collect_output(self, process, result, writer=None, stdin=None)
+ sends stdout to self._read_data() and stderr to self._read_response()
+
+** def _handle_io(self, args, file, result, passphrase=None, binary=False) :vuln:cleanup:
+*** L601: :unvalidated_user_input:type_check_in_call:
+ : p = self._open_subprocess(args, passphrase is not None)
+
+ you shouldn't assign or type check in a function call
+
+** def sign(self, message, **kwargs) :cleanup:
+*** L617-619: :hanging_fd:
+ calls self._make_binary_stream(), which leaves the file descriptor for
+ the encoded message to be encrypted hanging between scopes.
+
+** def sign_file(self, file, keyid=None, passphrase=None, clearsign=True, detach=False, binary=False) :cleanup:
+*** L632-635: :bad_logic:
+ #+BEGIN_SRC python
+ if detach:
+ args.append("--detach-sign")
+ elif clearsign:
+ args.append("--clearsign")
+ #+END_SRC
+
+ the logic here allows that if a user erroneously specifies both options,
+ rather than doing what the system gnupg would do (that is, do --clearsign,
+ and ignore the --attach-sign), python-gnupg would ignore both.
+
+*** L626-641:
+ input 'args' into self._open_subprocess() is defined as static strings.
+
+** def verify(self, data): :cleanup:
+*** L668-670: :hanging_fd:
+ same hanging file descriptor problem as in self.sign()
+
+** def verify_file(self, file, data_filename=None) :vuln:cleanup:
+*** L683: :hanging_fd:
+ more potentially hanging file descriptors...
+*** L684: :hanging_fd:
+ oh look, another hanging file descriptor. imagine that.
+*** L690: :unvalidated_user_input:
+ : args.append('"%s"' % data_filename)
+ well, there's the exploit. see included POC script.
+
+** def import_keys(self, key_data) :vuln:
+*** L749: :unvalidated_user_input:
+ this function could potentially allow an attacker with a GPG exploit to
+ use it, because it passes key generation parameter directly into the
+ internal packet parsers of GPG. however, without a GPG exploit for one of
+ the GPG packet parsers (for explanation of GPG packets look into pgpdump),
+ this function alone is not exploitable.
+
+** def recieve_keys(self, keyserver, *keyids) :vuln:
+*** L770: :unvalidated_user_input:
+ : args.extend(keyids)
+
+** def export_keys(self, keyids, secret=False) :vuln:
+*** L795-796: :unvalidated_user_input:
+ args problem again. exploitable though parameter ``keyids``.
+
+** def list_keys(self, secret=False)
+*** L827:
+ args is static string.
+
+** def gen_key(self, input) :cleanup:
+*** L864:
+ args, passed to self._handle_io(), which in turn passes args directly to
+ Popen(), is set to a static string. this function is halfway okay, though
+ it really could be more careful with the ``input`` parameter.
+
+** def gen_key_input(self, **kwargs) :vuln:
+*** L981-983: :unvalidated_user_input:
+ this function could potentially allow an attacker with a GPG exploit to
+ use it, because it passes key generation parameter directly into the
+ internal packet parsers of GPG. however, without a GPG exploit for one of
+ the GPG packet parsers (for explanation of GPG packets look into pgpdump),
+ this function alone is not exploitable.
+
+** def encrypt_file(self, file, recipiencts, sign=None, ...) :vuln:
+*** L939: :unvalidated_user_input:
+ several of the inputs to this function are unvalidated, turned into
+ strings, and passed to Popen(). exploitable.
+
+** def encrypt(self, data, recipients, **kwargs): :vuln:
+*** L997: :unvalidated_user_input:
+ exploitable, passes kwargs to self.encrypt_file()
+
+** def decrypt(self, message **kwargs): :vuln:
+*** L1003: :unvalidated_user_input:
+ kwargs are passed to self.decrypt_file(), unvalidated, making this
+ function also exploitable
+
+** def decrypt_file(self, file, always_trust=False, passphrase=None, output=None) :vuln:
+*** L1013: :unvalidated_user_input:
+ unvalidated user input: this function is also exploitable
+
+* POC
+#+INCLUDE: "../python-gnupg-0.3.1/python-gnupg-exploit.py" python
diff --git a/docs/NOTES-python-openpgp-implementations.txt b/docs/NOTES-python-openpgp-implementations.txt
new file mode 100644
index 0000000..bf60728
--- /dev/null
+++ b/docs/NOTES-python-openpgp-implementations.txt
@@ -0,0 +1,31 @@
+-*- mode: org -*-
+
+* Other Python OpenPGP libraries and utilities:
+
+*** pygpgme - https://launchpad.net/pygpgme
+A limited set of Python wrappers around GPGME
+http://www.gnupg.org/documentation/manuals/gpgme/
+
+*** py-gnupg - https://github.com/kevinoid/py-gnupg/blob/master/GnuPGInterface.py
+Focuses mainly on using file handles to interact with GnuPG.
+
+*** OpenPGP-Python - https://github.com/singpolyma/OpenPGP-Python
+The commit messages are a bit worrysome and the code has some scary
+error-prone-looking method chaining going on, a five minute glance over the
+/OpenPGP/Crypto.py file and it appears this is actually a valid OpenPGP
+implementation, built using D.Litzenberger's PyCrypto library.
+https://github.com/dlitz/pycrypto
+
+This person also wrote OpenPGP-Haskell:
+https://github.com/singpolyma/OpenPGP-Haskell
+
+...and OpenPGP-PHP (/horrorface): https://github.com/singpolyma/openpgp-php and
+an HTTP server as a shell script with a pretty crazy pipe hack.
+
+...and kudos on this one, it's an attempt at a mnemnonic system for squaring
+Zooko's Triangle (L17 being a function named "countLeadingCrapAndZeros"):
+https://github.com/singpolyma/mnemonicode/blob/master/mnencode.c#L17
+
+* GnuPG unattended key generation scripts:
+
+*** mandos-keygen http://bzr.recompile.se/loggerhead/mandos/trunk/annotate/523/mandos-keygen?start_revid=616
diff --git a/docs/OpenPGP-keys-in-DNS.md b/docs/OpenPGP-keys-in-DNS.md
new file mode 100644
index 0000000..56cb542
--- /dev/null
+++ b/docs/OpenPGP-keys-in-DNS.md
@@ -0,0 +1,133 @@
+[Christoph Berg's Blog](../index.html)/
+
+[2007](../2007.html)/
+
+</span>
+<span class="title">
+OpenPGP keys in DNS
+
+</span>
+</span>
+
+</div>
+
+<div class="actions">
+
+* [RecentChanges](../recentchanges.html)
+* [History](http://svn.df7cb.de/viewcvs.cgi/trunk/2007/openpgp-dns.mdwn?root=blog&view=log)
+</div>
+
+</div>
+
+<div id="pagebody">
+
+<div id="content">
+
+The latest addition to the mutt CVS tree is PKA support via gpgme. While trying
+to figure out how that works in mutt (I haven't yet...) I configured my DNS
+server for PKA and CERT records.
+
+## PKA
+
+PKA (public key association) puts a pointer where to obtain a key into a TXT
+record. At the same time that can be used to verify that a key belongs to a
+mail address. The documentation is at the
+[g10code website](http://www.g10code.de/docs/pka-intro.de.pdf)
+(only in German so far). I put the following into the df7cb.de zone:
+
+<p>
+cb._pka IN TXT "v=pka1;fpr=D224C8B07E63A6946DA32E07C5AF774A58510B5A;uri=finger:cb@df7cb.de"
+
+<pre>
+$ host -t TXT cb._pka.df7cb.de
+cb._pka.df7cb.de descriptive text "v=pka1\;fpr=D224C8B07E63A6946DA32E07C5AF774A58510B5A\;uri=finger:cb@df7cb.de"
+</pre>
+
+Now gpg can be told to use PKA to find the key:
+
+<pre>
+$ echo foo | gpg --auto-key-locate pka --recipient cb@df7cb.de --encrypt -a
+gpg: no keyserver known (use option --keyserver)
+gpg: requesting key 58510B5A from finger:cb@df7cb.de
+gpg: key 58510B5A: public key "Christoph Berg " imported
+gpg: Total number processed: 1
+gpg: imported: 1
+gpg: automatically retrieved `cb@df7cb.de' via PKA
+</pre>
+
+## CERT
+
+CERT records work similarly. Records are generated by make-dns-cert (from the
+tools directory in the gnupg source). cb.gpg is a stripped-down gpg keyring
+(created with pgp-clean -s and converting from .asc to .gpg).
+
+<pre>
+$ ./make-dns-cert -f D224C8B07E63A6946DA32E07C5AF774A58510B5A -n cb
+cb TYPE37 \# 26 0006 0000 00 14 D224C8B07E63A6946DA32E07C5AF774A58510B5A
+$ ./make-dns-cert -k cb.gpg -n cb
+cb TYPE37 \# 1338 0003 0000 00 9901A20440 [...] 509C96D4BFF17B7
+</pre>
+
+With a new bind and host (backports.org!) the format looks a bit nicer, that's
+also what I copied into the zone file:
+
+<pre>
+$ host -t CERT cb.df7cb.de
+;; Truncated, retrying in TCP mode.
+cb.df7cb.de has CERT record PGP 0 0 mQGiBECBGdAR [...] UDlCcltS/8Xtw==
+cb.df7cb.de has CERT record 6 0 0 FNIkyLB+Y6aUbaMuB8Wvd0pYUQta
+</pre>
+
+Again, gpg can be told to use that:
+
+<pre>
+$ echo foo | gpg --auto-key-locate cert --recipient cb@df7cb.de --encrypt -a
+gpg: key 58510B5A: public key "Christoph Berg " imported
+gpg: Total number processed: 1
+gpg: imported: 1
+gpg: automatically retrieved `cb@df7cb.de' via DNS CERT
+</pre>
+
+Thanks to weasel for some hints on using CERT.
+
+## SSHFP
+
+I'm also mentioning SSHFP records here since it fits in the topic - I have been
+using them for some months now:
+
+<pre>
+$ host -t SSHFP tesla.df7cb.de
+tesla.df7cb.de has SSHFP record 1 1 EE49B803541293656C33B86ECD781BD8F1D78AB5
+tesla.df7cb.de has SSHFP record 2 1 3E82FB5EE8AA0205305F0D0186F94D6FB3E0E744
+$ ssh -o 'VerifyHostKeyDNS yes' tesla.df7cb.de
+The authenticity of host 'tesla.df7cb.de (88.198.227.218)' can't be established.
+RSA key fingerprint is 5a:c9:38:ca:c0:2b:11:c1:c8:fb:f1:ad:73:a1:9c:8b.
+Matching host key fingerprint found in DNS.
+Are you sure you want to continue connecting (yes/no)?
+</pre>
+
+The records are generated with ssh-keygen -r.
+
+</div>
+
+</div>
+
+<div id="footer" class="pagefooter">
+
+<div id="pageinfo">
+
+<div class="tags">
+Tags:
+
+[debian](../tag/debian.html)
+
+</div>
+
+<div class="pagedate">
+Last edited <span class="date">Do 17 Feb 2011 13:21:52 CET</span>
+<!-- Created <span class="date">Do 01 Mär 2007 20:01:27 CET</span> -->
+</div>
+
+</div>
+
+<!-- from Christoph Berg's Blog -->
diff --git a/docs/_static/DETAILS.html b/docs/_static/DETAILS.html
new file mode 100644
index 0000000..7b0b9f8
--- /dev/null
+++ b/docs/_static/DETAILS.html
@@ -0,0 +1,2677 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+<head>
+<title>GnuPG Details</title>
+<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
+<meta name="title" content="GnuPG Details"/>
+<meta name="generator" content="Org-mode"/>
+<meta name="generated" content="2013-07-03T09:52+0000"/>
+<meta name="author" content="isis"/>
+<meta name="description" content=""/>
+<meta name="keywords" content=""/>
+<style type="text/css">
+ <!--/*--><![CDATA[/*><!--*/
+ html { font-family: Times, serif; font-size: 12pt; }
+ .title { text-align: center; }
+ .todo { color: red; }
+ .done { color: green; }
+ .tag { background-color: #add8e6; font-weight:normal }
+ .target { }
+ .timestamp { color: #bebebe; }
+ .timestamp-kwd { color: #5f9ea0; }
+ .right {margin-left:auto; margin-right:0px; text-align:right;}
+ .left {margin-left:0px; margin-right:auto; text-align:left;}
+ .center {margin-left:auto; margin-right:auto; text-align:center;}
+ p.verse { margin-left: 3% }
+ pre {
+ border: 1pt solid #AEBDCC;
+ background-color: #F3F5F7;
+ padding: 5pt;
+ font-family: courier, monospace;
+ font-size: 90%;
+ overflow:auto;
+ }
+ table { border-collapse: collapse; }
+ td, th { vertical-align: top; }
+ th.right { text-align:center; }
+ th.left { text-align:center; }
+ th.center { text-align:center; }
+ td.right { text-align:right; }
+ td.left { text-align:left; }
+ td.center { text-align:center; }
+ dt { font-weight: bold; }
+ div.figure { padding: 0.5em; }
+ div.figure p { text-align: center; }
+ div.inlinetask {
+ padding:10px;
+ border:2px solid gray;
+ margin:10px;
+ background: #ffffcc;
+ }
+ textarea { overflow-x: auto; }
+ .linenr { font-size:smaller }
+ .code-highlighted {background-color:#ffff00;}
+ .org-info-js_info-navigation { border-style:none; }
+ #org-info-js_console-label { font-size:10px; font-weight:bold;
+ white-space:nowrap; }
+ .org-info-js_search-highlight {background-color:#ffff00; color:#000000;
+ font-weight:bold; }
+ /*]]>*/-->
+</style>
+<script type="text/javascript">
+/*
+@licstart The following is the entire license notice for the
+JavaScript code in this tag.
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+
+The JavaScript code in this tag is free software: you can
+redistribute it and/or modify it under the terms of the GNU
+General Public License (GNU GPL) as published by the Free Software
+Foundation, either version 3 of the License, or (at your option)
+any later version. The code is distributed WITHOUT ANY WARRANTY;
+without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU GPL for more details.
+
+As additional permission under GNU GPL version 3 section 7, you
+may distribute non-source (e.g., minimized or compacted) forms of
+that code without the copy of the GNU GPL normally required by
+section 4, provided you include this license notice and a URL
+through which recipients can access the Corresponding Source.
+
+
+@licend The above is the entire license notice
+for the JavaScript code in this tag.
+*/
+<!--/*--><![CDATA[/*><!--*/
+ function CodeHighlightOn(elem, id)
+ {
+ var target = document.getElementById(id);
+ if(null != target) {
+ elem.cacheClassElem = elem.className;
+ elem.cacheClassTarget = target.className;
+ target.className = "code-highlighted";
+ elem.className = "code-highlighted";
+ }
+ }
+ function CodeHighlightOff(elem, id)
+ {
+ var target = document.getElementById(id);
+ if(elem.cacheClassElem)
+ elem.className = elem.cacheClassElem;
+ if(elem.cacheClassTarget)
+ target.className = elem.cacheClassTarget;
+ }
+/*]]>*///-->
+</script>
+<script type="text/css" href="./agogo.css" />
+</head>
+<body>
+
+<div id="preamble">
+
+</div>
+
+<div id="content">
+<h1 class="title">GnuPG Details</h1>
+
+
+<p>
+This is the DETAILS file for GnuPG which specifies some internals and
+parts of the external API for GPG and GPGSM.
+</p>
+
+<div id="table-of-contents">
+<h2>Table of Contents</h2>
+<div id="text-table-of-contents">
+<ul>
+<li><a href="#sec-1">1 Format of the colon listings</a>
+<ul>
+<li><a href="#sec-1-1">1.1 Description of the fields</a>
+<ul>
+<li><a href="#sec-1-1-1">1.1.1 Field 1 - Type of record</a></li>
+<li><a href="#sec-1-1-2">1.1.2 Field 2 - Validity</a></li>
+<li><a href="#sec-1-1-3">1.1.3 Field 3 - Key length</a></li>
+<li><a href="#sec-1-1-4">1.1.4 Field 4 - Public key algorithm</a></li>
+<li><a href="#sec-1-1-5">1.1.5 Field 5 - KeyID</a></li>
+<li><a href="#sec-1-1-6">1.1.6 Field 6 - Creation date</a></li>
+<li><a href="#sec-1-1-7">1.1.7 Field 7 - Expiration date</a></li>
+<li><a href="#sec-1-1-8">1.1.8 Field 8 - Certificate S/N, UID hash, trust signature info</a></li>
+<li><a href="#sec-1-1-9">1.1.9 Field 9 - Ownertrust</a></li>
+<li><a href="#sec-1-1-10">1.1.10 Field 10 - User-ID</a></li>
+<li><a href="#sec-1-1-11">1.1.11 Field 11 - Signature class</a></li>
+<li><a href="#sec-1-1-12">1.1.12 Field 12 - Key capabilities</a></li>
+<li><a href="#sec-1-1-13">1.1.13 Field 13 - Issuer certificate fingerprint or other info</a></li>
+<li><a href="#sec-1-1-14">1.1.14 Field 14 - Flag field</a></li>
+<li><a href="#sec-1-1-15">1.1.15 Field 15 - S/N of a token</a></li>
+<li><a href="#sec-1-1-16">1.1.16 Field 16 - Hash algorithm</a></li>
+</ul>
+</li>
+<li><a href="#sec-1-2">1.2 Special fields</a>
+<ul>
+<li><a href="#sec-1-2-1">1.2.1 PKD - Public key data</a></li>
+<li><a href="#sec-1-2-2">1.2.2 TRU - Trust database information</a></li>
+<li><a href="#sec-1-2-3">1.2.3 SPK - Signature subpacket records</a></li>
+<li><a href="#sec-1-2-4">1.2.4 CFG - Configuration data</a></li>
+</ul></li>
+</ul>
+</li>
+<li><a href="#sec-2">2 Format of the &ndash;status-fd output</a>
+<ul>
+<li><a href="#sec-2-1">2.1 General status codes</a>
+<ul>
+<li><a href="#sec-2-1-1">2.1.1 NEWSIG</a></li>
+<li><a href="#sec-2-1-2">2.1.2 GOODSIG &lt;long_keyid_or_fpr&gt; &lt;username&gt;</a></li>
+<li><a href="#sec-2-1-3">2.1.3 EXPSIG &lt;long_keyid_or_fpr&gt; &lt;username&gt;</a></li>
+<li><a href="#sec-2-1-4">2.1.4 EXPKEYSIG &lt;long_keyid_or_fpr&gt; &lt;username&gt;</a></li>
+<li><a href="#sec-2-1-5">2.1.5 REVKEYSIG &lt;long_keyid_or_fpr&gt; &lt;username&gt;</a></li>
+<li><a href="#sec-2-1-6">2.1.6 BADSIG &lt;long_keyid_or_fpr&gt; &lt;username&gt;</a></li>
+<li><a href="#sec-2-1-7">2.1.7 ERRSIG &lt;keyid&gt; &lt;pkalgo&gt; &lt;hashalgo&gt; &lt;sig_class&gt; &lt;time&gt; &lt;rc&gt;</a></li>
+<li><a href="#sec-2-1-8">2.1.8 VALIDSIG &lt;args&gt;</a></li>
+<li><a href="#sec-2-1-9">2.1.9 SIG_ID &lt;radix64_string&gt; &lt;sig_creation_date&gt; &lt;sig-timestamp&gt;</a></li>
+<li><a href="#sec-2-1-10">2.1.10 ENC_TO &lt;long_keyid&gt; &lt;keytype&gt; &lt;keylength&gt;</a></li>
+<li><a href="#sec-2-1-11">2.1.11 BEGIN_DECRYPTION</a></li>
+<li><a href="#sec-2-1-12">2.1.12 END_DECRYPTION</a></li>
+<li><a href="#sec-2-1-13">2.1.13 DECRYPTION_INFO &lt;mdc_method&gt; &lt;sym_algo&gt;</a></li>
+<li><a href="#sec-2-1-14">2.1.14 DECRYPTION_FAILED</a></li>
+<li><a href="#sec-2-1-15">2.1.15 DECRYPTION_OKAY</a></li>
+<li><a href="#sec-2-1-16">2.1.16 SESSION_KEY &lt;algo&gt;:&lt;hexdigits&gt;</a></li>
+<li><a href="#sec-2-1-17">2.1.17 BEGIN_ENCRYPTION &lt;mdc_method&gt; &lt;sym_algo&gt;</a></li>
+<li><a href="#sec-2-1-18">2.1.18 END_ENCRYPTION</a></li>
+<li><a href="#sec-2-1-19">2.1.19 FILE_START &lt;what&gt; &lt;filename&gt;</a></li>
+<li><a href="#sec-2-1-20">2.1.20 FILE_DONE</a></li>
+<li><a href="#sec-2-1-21">2.1.21 BEGIN_SIGNING</a></li>
+<li><a href="#sec-2-1-22">2.1.22 ALREADY_SIGNED &lt;long-keyid&gt;</a></li>
+<li><a href="#sec-2-1-23">2.1.23 SIG_CREATED &lt;type&gt; &lt;pk_algo&gt; &lt;hash_algo&gt; &lt;class&gt; &lt;timestamp&gt; &lt;keyfpr&gt;</a></li>
+<li><a href="#sec-2-1-24">2.1.24 NOTATION_</a></li>
+<li><a href="#sec-2-1-25">2.1.25 POLICY_URL &lt;string&gt;</a></li>
+<li><a href="#sec-2-1-26">2.1.26 PLAINTEXT &lt;format&gt; &lt;timestamp&gt; &lt;filename&gt;</a></li>
+<li><a href="#sec-2-1-27">2.1.27 PLAINTEXT_LENGTH &lt;length&gt;</a></li>
+<li><a href="#sec-2-1-28">2.1.28 ATTRIBUTE &lt;arguments&gt;</a></li>
+<li><a href="#sec-2-1-29">2.1.29 SIG_SUBPACKET &lt;type&gt; &lt;flags&gt; &lt;len&gt; &lt;data&gt;</a></li>
+</ul>
+</li>
+<li><a href="#sec-2-2">2.2 Key related</a>
+<ul>
+<li><a href="#sec-2-2-1">2.2.1 INV_RECP, INV_SGNR</a></li>
+<li><a href="#sec-2-2-2">2.2.2 NO_RECP &lt;reserved&gt;</a></li>
+<li><a href="#sec-2-2-3">2.2.3 NO_SGNR &lt;reserved&gt;</a></li>
+<li><a href="#sec-2-2-4">2.2.4 KEYEXPIRED &lt;expire-timestamp&gt;</a></li>
+<li><a href="#sec-2-2-5">2.2.5 KEYREVOKED</a></li>
+<li><a href="#sec-2-2-6">2.2.6 NO_PUBKEY &lt;long keyid&gt;</a></li>
+<li><a href="#sec-2-2-7">2.2.7 NO_SECKEY &lt;long keyid&gt;</a></li>
+<li><a href="#sec-2-2-8">2.2.8 KEY_CREATED &lt;type&gt; &lt;fingerprint&gt; [&lt;handle&gt;]</a></li>
+<li><a href="#sec-2-2-9">2.2.9 KEY_NOT_CREATED [&lt;handle&gt;]</a></li>
+<li><a href="#sec-2-2-10">2.2.10 TRUST_</a></li>
+<li><a href="#sec-2-2-11">2.2.11 PKA_TRUST_</a></li>
+</ul>
+</li>
+<li><a href="#sec-2-3">2.3 Remote control</a>
+<ul>
+<li><a href="#sec-2-3-1">2.3.1 GET_BOOL, GET_LINE, GET_HIDDEN, GOT_IT</a></li>
+<li><a href="#sec-2-3-2">2.3.2 USERID_HINT &lt;long main keyid&gt; &lt;string&gt;</a></li>
+<li><a href="#sec-2-3-3">2.3.3 NEED_PASSPHRASE &lt;long keyid&gt; &lt;long main keyid&gt; &lt;keytype&gt; &lt;keylength&gt;</a></li>
+<li><a href="#sec-2-3-4">2.3.4 NEED_PASSPHRASE_SYM &lt;cipher_algo&gt; &lt;s2k_mode&gt; &lt;s2k_hash&gt;</a></li>
+<li><a href="#sec-2-3-5">2.3.5 NEED_PASSPHRASE_PIN &lt;card_type&gt; &lt;chvno&gt; [&lt;serialno&gt;]</a></li>
+<li><a href="#sec-2-3-6">2.3.6 MISSING_PASSPHRASE</a></li>
+<li><a href="#sec-2-3-7">2.3.7 BAD_PASSPHRASE &lt;long keyid&gt;</a></li>
+<li><a href="#sec-2-3-8">2.3.8 GOOD_PASSPHRASE</a></li>
+</ul>
+</li>
+<li><a href="#sec-2-4">2.4 Import/Export</a>
+<ul>
+<li><a href="#sec-2-4-1">2.4.1 IMPORT_CHECK &lt;long keyid&gt; &lt;fingerprint&gt; &lt;user ID&gt;</a></li>
+<li><a href="#sec-2-4-2">2.4.2 IMPORTED &lt;long keyid&gt; &lt;username&gt;</a></li>
+<li><a href="#sec-2-4-3">2.4.3 IMPORT_OK &lt;reason&gt; [&lt;fingerprint&gt;]</a></li>
+<li><a href="#sec-2-4-4">2.4.4 IMPORT_PROBLEM &lt;reason&gt; [&lt;fingerprint&gt;]</a></li>
+<li><a href="#sec-2-4-5">2.4.5 IMPORT_RES &lt;args&gt;</a></li>
+</ul>
+</li>
+<li><a href="#sec-2-5">2.5 Smartcard related</a>
+<ul>
+<li><a href="#sec-2-5-1">2.5.1 CARDCTRL &lt;what&gt; [&lt;serialno&gt;]</a></li>
+<li><a href="#sec-2-5-2">2.5.2 SC_OP_FAILURE [&lt;code&gt;]</a></li>
+<li><a href="#sec-2-5-3">2.5.3 SC_OP_SUCCESS</a></li>
+</ul>
+</li>
+<li><a href="#sec-2-6">2.6 Miscellaneous status codes</a>
+<ul>
+<li><a href="#sec-2-6-1">2.6.1 NODATA &lt;what&gt;</a></li>
+<li><a href="#sec-2-6-2">2.6.2 UNEXPECTED &lt;what&gt;</a></li>
+<li><a href="#sec-2-6-3">2.6.3 TRUNCATED &lt;maxno&gt;</a></li>
+<li><a href="#sec-2-6-4">2.6.4 ERROR &lt;error location&gt; &lt;error code&gt; [&lt;more&gt;]</a></li>
+<li><a href="#sec-2-6-5">2.6.5 SUCCESS [&lt;location&gt;]</a></li>
+<li><a href="#sec-2-6-6">2.6.6 BADARMOR</a></li>
+<li><a href="#sec-2-6-7">2.6.7 DELETE_PROBLEM &lt;reason_code&gt;</a></li>
+<li><a href="#sec-2-6-8">2.6.8 PROGRESS &lt;what&gt; &lt;char&gt; &lt;cur&gt; &lt;total&gt;</a></li>
+<li><a href="#sec-2-6-9">2.6.9 BACKUP_KEY_CREATED &lt;fingerprint&gt; &lt;fname&gt;</a></li>
+<li><a href="#sec-2-6-10">2.6.10 MOUNTPOINT &lt;name&gt;</a></li>
+<li><a href="#sec-2-6-11">2.6.11 PINENTRY_LAUNCHED &lt;pid&gt;</a></li>
+</ul>
+</li>
+<li><a href="#sec-2-7">2.7 Obsolete status codes</a>
+<ul>
+<li><a href="#sec-2-7-1">2.7.1 SIGEXPIRED</a></li>
+<li><a href="#sec-2-7-2">2.7.2 RSA_OR_IDEA</a></li>
+<li><a href="#sec-2-7-3">2.7.3 SHM_INFO, SHM_GET, SHM_GET_BOOL, SHM_GET_HIDDEN</a></li>
+<li><a href="#sec-2-7-4">2.7.4 BEGIN_STREAM, END_STREAM</a></li>
+</ul></li>
+</ul>
+</li>
+<li><a href="#sec-3">3 Format of the &ndash;attribute-fd output</a></li>
+<li><a href="#sec-4">4 Unattended key generation</a></li>
+<li><a href="#sec-5">5 Layout of the TrustDB</a></li>
+<li><a href="#sec-6">6 GNU extensions to the S2K algorithm</a></li>
+<li><a href="#sec-7">7 Keyserver helper message format</a></li>
+<li><a href="#sec-8">8 Object identifiers</a></li>
+<li><a href="#sec-9">9 Miscellaneous notes</a>
+<ul>
+<li><a href="#sec-9-1">9.1 v3 fingerprints</a></li>
+<li><a href="#sec-9-2">9.2 Simplified revocation certificates</a></li>
+<li><a href="#sec-9-3">9.3 Documentation on HKP (the http keyserver protocol):</a></li>
+</ul>
+</li>
+</ul>
+</div>
+</div>
+
+<div id="outline-container-1" class="outline-2">
+<h2 id="sec-1"><span class="section-number-2">1</span> Format of the colon listings</h2>
+<div class="outline-text-2" id="text-1">
+
+<p> The format is a based on colon separated record, each recods starts
+ with a tag string and extends to the end of the line. Here is an
+ example:
+</p>
+
+
+<pre class="example">$ gpg --with-colons --list-keys \
+ --with-fingerprint --with-fingerprint wk@gnupg.org
+pub:f:1024:17:6C7EE1B8621CC013:899817715:1055898235::m:::scESC:
+fpr:::::::::ECAF7590EB3443B5C7CF3ACB6C7EE1B8621CC013:
+uid:f::::::::Werner Koch &lt;wk@g10code.com&gt;:
+uid:f::::::::Werner Koch &lt;wk@gnupg.org&gt;:
+sub:f:1536:16:06AD222CADF6A6E1:919537416:1036177416:::::e:
+fpr:::::::::CF8BCC4B18DE08FCD8A1615906AD222CADF6A6E1:
+sub:r:1536:20:5CE086B5B5A18FF4:899817788:1025961788:::::esc:
+fpr:::::::::AB059359A3B81F410FCFF97F5CE086B5B5A18FF4:
+</pre>
+
+
+<p>
+The double <code>--with-fingerprint</code> prints the fingerprint for the subkeys
+too. Old versions of gpg used a lighly different format and required
+the use of the option <code>--fixed-list-mode</code> to conform to format
+described here.
+</p>
+
+</div>
+
+<div id="outline-container-1-1" class="outline-3">
+<h3 id="sec-1-1"><span class="section-number-3">1.1</span> Description of the fields</h3>
+<div class="outline-text-3" id="text-1-1">
+
+
+</div>
+
+<div id="outline-container-1-1-1" class="outline-4">
+<h4 id="sec-1-1-1"><span class="section-number-4">1.1.1</span> Field 1 - Type of record</h4>
+<div class="outline-text-4" id="text-1-1-1">
+
+
+<dl>
+<dt>pub</dt><dd>Public key
+</dd>
+<dt>crt</dt><dd>X.509 certificate
+</dd>
+<dt>crs</dt><dd>X.509 certificate and private key available
+</dd>
+<dt>sub</dt><dd>Subkey (secondary key)
+</dd>
+<dt>sec</dt><dd>Secret key
+</dd>
+<dt>ssb</dt><dd>Secret subkey (secondary key)
+</dd>
+<dt>uid</dt><dd>User id (only field 10 is used).
+</dd>
+<dt>uat</dt><dd>User attribute (same as user id except for field 10).
+</dd>
+<dt>sig</dt><dd>Signature
+</dd>
+<dt>rev</dt><dd>Revocation signature
+</dd>
+<dt>fpr</dt><dd>Fingerprint (fingerprint is in field 10)
+</dd>
+<dt>pkd</dt><dd>Public key data [*]
+</dd>
+<dt>grp</dt><dd>Keygrip
+</dd>
+<dt>rvk</dt><dd>Revocation key
+</dd>
+<dt>tru</dt><dd>Trust database information [*]
+</dd>
+<dt>spk</dt><dd>Signature subpacket [*]
+</dd>
+<dt>cfg</dt><dd>Configuration data [*]
+</dd>
+</dl>
+
+
+<p>
+ Records marked with an asterisk are described at <a href="#Special-field-formats">*Special fields</a>.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-1-1-2" class="outline-4">
+<h4 id="sec-1-1-2"><span class="section-number-4">1.1.2</span> Field 2 - Validity</h4>
+<div class="outline-text-4" id="text-1-1-2">
+
+
+<p>
+ This is a letter describing the computed validity of a key.
+ Currently this is a single letter, but be prepared that additional
+ information may follow in some future versions. Note that GnuPG &lt;
+ 2.1 does not set this field for secret key listings.
+</p>
+<dl>
+<dt>o</dt><dd>Unknown (this key is new to the system)
+</dd>
+<dt>i</dt><dd>The key is invalid (e.g. due to a missing self-signature)
+</dd>
+<dt>d</dt><dd>The key has been disabled
+ (deprecated - use the 'D' in field 12 instead)
+</dd>
+<dt>r</dt><dd>The key has been revoked
+</dd>
+<dt>e</dt><dd>The key has expired
+</dd>
+<dt>-</dt><dd>Unknown validity (i.e. no value assigned)
+</dd>
+<dt>q</dt><dd>Undefined validity. '-' and 'q' may safely be treated as
+ the same value for most purposes
+</dd>
+<dt>n</dt><dd>The key is not valid
+</dd>
+<dt>m</dt><dd>The key is marginal valid.
+</dd>
+<dt>f</dt><dd>The key is fully valid
+</dd>
+<dt>u</dt><dd>The key is ultimately valid. This often means that the
+ secret key is available, but any key may be marked as
+ ultimately valid.
+</dd>
+<dt>w</dt><dd>The key has a well known private part.
+</dd>
+<dt>s</dt><dd>The key has special validity. This means that it might be
+ self-signed and expected to be used in the STEED sytem.
+</dd>
+</dl>
+
+
+<p>
+ If the validity information is given for a UID or UAT record, it
+ describes the validity calculated based on this user ID. If given
+ for a key record it describes the validity taken from the best
+ rated user ID.
+</p>
+<p>
+ For X.509 certificates a 'u' is used for a trusted root
+ certificate (i.e. for the trust anchor) and an 'f' for all other
+ valid certificates.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-1-1-3" class="outline-4">
+<h4 id="sec-1-1-3"><span class="section-number-4">1.1.3</span> Field 3 - Key length</h4>
+<div class="outline-text-4" id="text-1-1-3">
+
+
+<p>
+ The length of key in bits.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-1-1-4" class="outline-4">
+<h4 id="sec-1-1-4"><span class="section-number-4">1.1.4</span> Field 4 - Public key algorithm</h4>
+<div class="outline-text-4" id="text-1-1-4">
+
+
+<p>
+ The values here are those from the OpenPGP specs or if they are
+ greather than 255 the algorithm ids as used by Libgcrypt.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-1-1-5" class="outline-4">
+<h4 id="sec-1-1-5"><span class="section-number-4">1.1.5</span> Field 5 - KeyID</h4>
+<div class="outline-text-4" id="text-1-1-5">
+
+
+<p>
+ This is the 64 bit keyid as specified by OpenPGP and the last 64
+ bit of the SHA-1 fingerprint of an X.509 certifciate.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-1-1-6" class="outline-4">
+<h4 id="sec-1-1-6"><span class="section-number-4">1.1.6</span> Field 6 - Creation date</h4>
+<div class="outline-text-4" id="text-1-1-6">
+
+
+<p>
+ The creation date of the key is given in UTC. For UID and UAT
+ records, this is used for the self-signature date. Note that the
+ date is usally printed in seconds since epoch, however, we are
+ migrating to an ISO 8601 format (e.g. "19660205T091500"). This is
+ currently only relevant for X.509. A simple way to detect the new
+ format is to scan for the 'T'. Note that old versions of gpg
+ without using the <code>--fixed-list-mode</code> option used a "yyyy-mm-tt"
+ format.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-1-1-7" class="outline-4">
+<h4 id="sec-1-1-7"><span class="section-number-4">1.1.7</span> Field 7 - Expiration date</h4>
+<div class="outline-text-4" id="text-1-1-7">
+
+
+<p>
+ Key or UID/UAT expiration date or empty if it does not expire.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-1-1-8" class="outline-4">
+<h4 id="sec-1-1-8"><span class="section-number-4">1.1.8</span> Field 8 - Certificate S/N, UID hash, trust signature info</h4>
+<div class="outline-text-4" id="text-1-1-8">
+
+
+<p>
+ Used for serial number in crt records. For UID and UAT records,
+ this is a hash of the user ID contents used to represent that
+ exact user ID. For trust signatures, this is the trust depth
+ seperated by the trust value by a space.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-1-1-9" class="outline-4">
+<h4 id="sec-1-1-9"><span class="section-number-4">1.1.9</span> Field 9 - Ownertrust</h4>
+<div class="outline-text-4" id="text-1-1-9">
+
+
+<p>
+ This is only used on primary keys. This is a single letter, but
+ be prepared that additional information may follow in future
+ versions. For trust signatures with a regular expression, this is
+ the regular expression value, quoted as in field 10.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-1-1-10" class="outline-4">
+<h4 id="sec-1-1-10"><span class="section-number-4">1.1.10</span> Field 10 - User-ID</h4>
+<div class="outline-text-4" id="text-1-1-10">
+
+<p> The value is quoted like a C string to avoid control characters
+ (the colon is quoted <code>\x3a</code>). For a "pub" record this field is
+ not used on &ndash;fixed-list-mode. A UAT record puts the attribute
+ subpacket count here, a space, and then the total attribute
+ subpacket size. In gpgsm the issuer name comes here. A FPR
+ record stores the fingerprint here. The fingerprint of a
+ revocation key is stored here.
+</p></div>
+
+</div>
+
+<div id="outline-container-1-1-11" class="outline-4">
+<h4 id="sec-1-1-11"><span class="section-number-4">1.1.11</span> Field 11 - Signature class</h4>
+<div class="outline-text-4" id="text-1-1-11">
+
+
+<p>
+ Signature class as per RFC-4880. This is a 2 digit hexnumber
+ followed by either the letter 'x' for an exportable signature or
+ the letter 'l' for a local-only signature. The class byte of an
+ revocation key is also given here, 'x' and 'l' is used the same
+ way. This field if not used for X.509.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-1-1-12" class="outline-4">
+<h4 id="sec-1-1-12"><span class="section-number-4">1.1.12</span> Field 12 - Key capabilities</h4>
+<div class="outline-text-4" id="text-1-1-12">
+
+
+<p>
+ The defined capabilities are:
+</p>
+<dl>
+<dt>e</dt><dd>Encrypt
+</dd>
+<dt>s</dt><dd>Sign
+</dd>
+<dt>c</dt><dd>Certify
+</dd>
+<dt>a</dt><dd>Authentication
+</dd>
+<dt>?</dt><dd>Unknown capability
+</dd>
+</dl>
+
+
+<p>
+ A key may have any combination of them in any order. In addition
+ to these letters, the primary key has uppercase versions of the
+ letters to denote the <span style="text-decoration:underline;">usable</span> capabilities of the entire key, and
+ a potential letter 'D' to indicate a disabled key.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-1-1-13" class="outline-4">
+<h4 id="sec-1-1-13"><span class="section-number-4">1.1.13</span> Field 13 - Issuer certificate fingerprint or other info</h4>
+<div class="outline-text-4" id="text-1-1-13">
+
+
+<p>
+ Used in FPR records for S/MIME keys to store the fingerprint of
+ the issuer certificate. This is useful to build the certificate
+ path based on certificates stored in the local key database it is
+ only filled if the issuer certificate is available. The root has
+ been reached if this is the same string as the fingerprint. The
+ advantage of using this value is that it is guaranteed to have
+ been been build by the same lookup algorithm as gpgsm uses.
+</p>
+<p>
+ For "uid" records this field lists the preferences in the same way
+ gpg's &ndash;edit-key menu does.
+</p>
+<p>
+ For "sig" records, this is the fingerprint of the key that issued
+ the signature. Note that this is only filled in if the signature
+ verified correctly. Note also that for various technical reasons,
+ this fingerprint is only available if &ndash;no-sig-cache is used.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-1-1-14" class="outline-4">
+<h4 id="sec-1-1-14"><span class="section-number-4">1.1.14</span> Field 14 - Flag field</h4>
+<div class="outline-text-4" id="text-1-1-14">
+
+
+<p>
+ Flag field used in the &ndash;edit menu output
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-1-1-15" class="outline-4">
+<h4 id="sec-1-1-15"><span class="section-number-4">1.1.15</span> Field 15 - S/N of a token</h4>
+<div class="outline-text-4" id="text-1-1-15">
+
+
+<p>
+ Used in sec/sbb to print the serial number of a token (internal
+ protect mode 1002) or a '#' if that key is a simple stub (internal
+ protect mode 1001)
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-1-1-16" class="outline-4">
+<h4 id="sec-1-1-16"><span class="section-number-4">1.1.16</span> Field 16 - Hash algorithm</h4>
+<div class="outline-text-4" id="text-1-1-16">
+
+
+<p>
+ For sig records, this is the used hash algorithm. For example:
+ 2 = SHA-1, 8 = SHA-256.
+</p>
+</div>
+</div>
+
+</div>
+
+<div id="outline-container-1-2" class="outline-3">
+<h3 id="sec-1-2"><span class="section-number-3">1.2</span> Special fields</h3>
+<div class="outline-text-3" id="text-1-2">
+
+
+
+</div>
+
+<div id="outline-container-1-2-1" class="outline-4">
+<h4 id="sec-1-2-1"><span class="section-number-4">1.2.1</span> PKD - Public key data</h4>
+<div class="outline-text-4" id="text-1-2-1">
+
+
+<p>
+ If field 1 has the tag "pkd", a listing looks like this:
+</p>
+
+
+<pre class="example">pkd:0:1024:B665B1435F4C2 .... FF26ABB:
+ ! ! !-- the value
+ ! !------ for information number of bits in the value
+ !--------- index (eg. DSA goes from 0 to 3: p,q,g,y)
+</pre>
+
+
+</div>
+
+</div>
+
+<div id="outline-container-1-2-2" class="outline-4">
+<h4 id="sec-1-2-2"><span class="section-number-4">1.2.2</span> TRU - Trust database information</h4>
+<div class="outline-text-4" id="text-1-2-2">
+
+<p> Example for a "tru" trust base record:
+</p>
+
+
+<pre class="example">tru:o:0:1166697654:1:3:1:5
+</pre>
+
+
+<dl>
+<dt>Field 2</dt><dd>Reason for staleness of trust. If this field is
+ empty, then the trustdb is not stale. This field may
+ have multiple flags in it:
+
+<dl>
+<dt>o</dt><dd>Trustdb is old
+</dd>
+<dt>t</dt><dd>Trustdb was built with a different trust model
+ than the one we are using now.
+
+</dd>
+</dl>
+
+</dd>
+<dt>Field 3</dt><dd>Trust model
+
+<dl>
+<dt>0</dt><dd>Classic trust model, as used in PGP 2.x.
+</dd>
+<dt>1</dt><dd>PGP trust model, as used in PGP 6 and later.
+ This is the same as the classic trust model,
+ except for the addition of trust signatures.
+
+</dd>
+</dl>
+
+<p> GnuPG before version 1.4 used the classic trust model
+ by default. GnuPG 1.4 and later uses the PGP trust
+ model by default.
+</p>
+</dd>
+<dt>Field 4</dt><dd>Date trustdb was created in seconds since Epoch.
+</dd>
+<dt>Field 5</dt><dd>Date trustdb will expire in seconds since Epoch.
+</dd>
+<dt>Field 6</dt><dd>Number of marginally trusted users to introduce a new
+ key signer (gpg's option &ndash;marginals-needed).
+</dd>
+<dt>Field 7</dt><dd>Number of completely trusted users to introduce a new
+ key signer. (gpg's option &ndash;completes-needed)
+
+</dd>
+<dt>Field 8</dt><dd>Maximum depth of a certification chain. (gpg's option
+ &ndash;max-cert-depth)
+</dd>
+</dl>
+
+
+</div>
+
+</div>
+
+<div id="outline-container-1-2-3" class="outline-4">
+<h4 id="sec-1-2-3"><span class="section-number-4">1.2.3</span> SPK - Signature subpacket records</h4>
+<div class="outline-text-4" id="text-1-2-3">
+
+
+<dl>
+<dt>Field 2</dt><dd>Subpacket number as per RFC-4880 and later.
+</dd>
+<dt>Field 3</dt><dd>Flags in hex. Currently the only two bits assigned
+ are 1, to indicate that the subpacket came from the
+ hashed part of the signature, and 2, to indicate the
+ subpacket was marked critical.
+</dd>
+<dt>Field 4</dt><dd>Length of the subpacket. Note that this is the
+ length of the subpacket, and not the length of field
+ 5 below. Due to the need for %-encoding, the length
+ of field 5 may be up to 3x this value.
+</dd>
+<dt>Field 5</dt><dd>The subpacket data. Printable ASCII is shown as
+ ASCII, but other values are rendered as %XX where XX
+ is the hex value for the byte.
+</dd>
+</dl>
+
+
+</div>
+
+</div>
+
+<div id="outline-container-1-2-4" class="outline-4">
+<h4 id="sec-1-2-4"><span class="section-number-4">1.2.4</span> CFG - Configuration data</h4>
+<div class="outline-text-4" id="text-1-2-4">
+
+
+<p>
+ &ndash;list-config outputs information about the GnuPG configuration
+ for the benefit of frontends or other programs that call GnuPG.
+ There are several list-config items, all colon delimited like the
+ rest of the &ndash;with-colons output. The first field is always "cfg"
+ to indicate configuration information. The second field is one of
+ (with examples):
+</p>
+<dl>
+<dt>version</dt><dd>The third field contains the version of GnuPG.
+
+<pre class="example">
+cfg:version:1.3.5
+</pre>
+
+
+</dd>
+<dt>pubkey</dt><dd>The third field contains the public key algorithms
+ this version of GnuPG supports, separated by
+ semicolons. The algorithm numbers are as specified in
+ RFC-4880. Note that in contrast to the &ndash;status-fd
+ interface these are <span style="text-decoration:underline;">not</span> the Libgcrypt identifiers.
+
+<pre class="example">
+cfg:pubkey:1;2;3;16;17
+</pre>
+
+
+</dd>
+<dt>cipher</dt><dd>The third field contains the symmetric ciphers this
+ version of GnuPG supports, separated by semicolons.
+ The cipher numbers are as specified in RFC-4880.
+
+<pre class="example">
+cfg:cipher:2;3;4;7;8;9;10
+</pre>
+
+
+</dd>
+<dt>digest</dt><dd>The third field contains the digest (hash) algorithms
+ this version of GnuPG supports, separated by
+ semicolons. The digest numbers are as specified in
+ RFC-4880.
+
+<pre class="example">
+cfg:digest:1;2;3;8;9;10
+</pre>
+
+
+</dd>
+<dt>compress</dt><dd>The third field contains the compression algorithms
+ this version of GnuPG supports, separated by
+ semicolons. The algorithm numbers are as specified
+ in RFC-4880.
+
+<pre class="example">
+cfg:compress:0;1;2;3
+</pre>
+
+
+</dd>
+<dt>group</dt><dd>The third field contains the name of the group, and the
+ fourth field contains the values that the group expands
+ to, separated by semicolons.
+
+<p>
+ For example, a group of:
+</p><pre class="example">
+group mynames = paige 0x12345678 joe patti
+</pre>
+
+<p> would result in:
+</p><pre class="example">
+cfg:group:mynames:patti;joe;0x12345678;paige
+</pre>
+
+</dd>
+</dl>
+
+
+
+</div>
+</div>
+</div>
+
+</div>
+
+<div id="outline-container-2" class="outline-2">
+<h2 id="sec-2"><span class="section-number-2">2</span> Format of the &ndash;status-fd output</h2>
+<div class="outline-text-2" id="text-2">
+
+
+<p>
+ Every line is prefixed with "[GNUPG:] ", followed by a keyword with
+ the type of the status line and some arguments depending on the type
+ (maybe none); an application should always be prepared to see more
+ arguments in future versions.
+</p>
+
+</div>
+
+<div id="outline-container-2-1" class="outline-3">
+<h3 id="sec-2-1"><span class="section-number-3">2.1</span> General status codes</h3>
+<div class="outline-text-3" id="text-2-1">
+
+
+</div>
+
+<div id="outline-container-2-1-1" class="outline-4">
+<h4 id="sec-2-1-1"><span class="section-number-4">2.1.1</span> NEWSIG</h4>
+<div class="outline-text-4" id="text-2-1-1">
+
+<p> May be issued right before a signature verification starts. This
+ is useful to define a context for parsing ERROR status messages.
+ No arguments are currently defined.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-1-2" class="outline-4">
+<h4 id="sec-2-1-2"><span class="section-number-4">2.1.2</span> GOODSIG &lt;long_keyid_or_fpr&gt; &lt;username&gt;</h4>
+<div class="outline-text-4" id="text-2-1-2">
+
+<p> The signature with the keyid is good. For each signature only one
+ of the codes GOODSIG, BADSIG, EXPSIG, EXPKEYSIG, REVKEYSIG or
+ ERRSIG will be emitted. In the past they were used as a marker
+ for a new signature; new code should use the NEWSIG status
+ instead. The username is the primary one encoded in UTF-8 and %XX
+ escaped. The fingerprint may be used instead of the long keyid if
+ it is available. This is the case with CMS and might eventually
+ also be available for OpenPGP.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-1-3" class="outline-4">
+<h4 id="sec-2-1-3"><span class="section-number-4">2.1.3</span> EXPSIG &lt;long_keyid_or_fpr&gt; &lt;username&gt;</h4>
+<div class="outline-text-4" id="text-2-1-3">
+
+<p> The signature with the keyid is good, but the signature is
+ expired. The username is the primary one encoded in UTF-8 and %XX
+ escaped. The fingerprint may be used instead of the long keyid if
+ it is available. This is the case with CMS and might eventually
+ also be available for OpenPGP.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-1-4" class="outline-4">
+<h4 id="sec-2-1-4"><span class="section-number-4">2.1.4</span> EXPKEYSIG &lt;long_keyid_or_fpr&gt; &lt;username&gt;</h4>
+<div class="outline-text-4" id="text-2-1-4">
+
+<p> The signature with the keyid is good, but the signature was made
+ by an expired key. The username is the primary one encoded in
+ UTF-8 and %XX escaped. The fingerprint may be used instead of the
+ long keyid if it is available. This is the case with CMS and
+ might eventually also be available for OpenPGP.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-1-5" class="outline-4">
+<h4 id="sec-2-1-5"><span class="section-number-4">2.1.5</span> REVKEYSIG &lt;long_keyid_or_fpr&gt; &lt;username&gt;</h4>
+<div class="outline-text-4" id="text-2-1-5">
+
+<p> The signature with the keyid is good, but the signature was made
+ by a revoked key. The username is the primary one encoded in UTF-8
+ and %XX escaped. The fingerprint may be used instead of the long
+ keyid if it is available. This is the case with CMS and might
+ eventually also beñ available for OpenPGP.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-1-6" class="outline-4">
+<h4 id="sec-2-1-6"><span class="section-number-4">2.1.6</span> BADSIG &lt;long_keyid_or_fpr&gt; &lt;username&gt;</h4>
+<div class="outline-text-4" id="text-2-1-6">
+
+<p> The signature with the keyid has not been verified okay. The
+ username is the primary one encoded in UTF-8 and %XX escaped. The
+ fingerprint may be used instead of the long keyid if it is
+ available. This is the case with CMS and might eventually also be
+ available for OpenPGP.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-1-7" class="outline-4">
+<h4 id="sec-2-1-7"><span class="section-number-4">2.1.7</span> ERRSIG &lt;keyid&gt; &lt;pkalgo&gt; &lt;hashalgo&gt; &lt;sig_class&gt; &lt;time&gt; &lt;rc&gt;</h4>
+<div class="outline-text-4" id="text-2-1-7">
+
+<p> It was not possible to check the signature. This may be caused by
+ a missing public key or an unsupported algorithm. A RC of 4
+ indicates unknown algorithm, a 9 indicates a missing public
+ key. The other fields give more information about this signature.
+ sig_class is a 2 byte hex-value. The fingerprint may be used
+ instead of the keyid if it is available. This is the case with
+ gpgsm and might eventually also be available for OpenPGP.
+</p>
+<p>
+ Note, that TIME may either be the number of seconds since Epoch or
+ the letter 'T'.
+ an ISO 8601 string. The latter can be detected by the presence of
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-1-8" class="outline-4">
+<h4 id="sec-2-1-8"><span class="section-number-4">2.1.8</span> VALIDSIG &lt;args&gt;</h4>
+<div class="outline-text-4" id="text-2-1-8">
+
+
+<p>
+ The args are:
+</p>
+<ul>
+<li>&lt;fingerprint_in_hex&gt;
+</li>
+<li>&lt;sig_creation_date&gt;
+</li>
+<li>&lt;sig-timestamp&gt;
+</li>
+<li>&lt;expire-timestamp&gt;
+</li>
+<li>&lt;sig-version&gt;
+</li>
+<li>&lt;reserved&gt;
+</li>
+<li>&lt;pubkey-algo&gt;
+</li>
+<li>&lt;hash-algo&gt;
+</li>
+<li>&lt;sig-class&gt;
+</li>
+<li>[ &lt;primary-key-fpr&gt; ]
+</li>
+</ul>
+
+
+<p>
+ This status indicates that the signature is good. This is the same
+ as GOODSIG but has the fingerprint as the argument. Both status
+ lines are emitted for a good signature. All arguments here are on
+ one long line. sig-timestamp is the signature creation time in
+ seconds after the epoch. expire-timestamp is the signature
+ expiration time in seconds after the epoch (zero means "does not
+ expire"). sig-version, pubkey-algo, hash-algo, and sig-class (a
+ 2-byte hex value) are all straight from the signature packet.
+ PRIMARY-KEY-FPR is the fingerprint of the primary key or identical
+ to the first argument. This is useful to get back to the primary
+ key without running gpg again for this purpose.
+</p>
+<p>
+ The primary-key-fpr parameter is used for OpenPGP and not
+ class is not defined for CMS and currently set to 0 and 00.
+ available for CMS signatures. The sig-version as well as the sig
+</p>
+<p>
+ Note, that *-TIMESTAMP may either be a number of seconds since
+ Epoch or an ISO 8601 string which can be detected by the presence
+ of the letter 'T'.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-1-9" class="outline-4">
+<h4 id="sec-2-1-9"><span class="section-number-4">2.1.9</span> SIG_ID &lt;radix64_string&gt; &lt;sig_creation_date&gt; &lt;sig-timestamp&gt;</h4>
+<div class="outline-text-4" id="text-2-1-9">
+
+<p> This is emitted only for signatures of class 0 or 1 which have
+ been verified okay. The string is a signature id and may be used
+ in applications to detect replay attacks of signed messages. Note
+ that only DLP algorithms give unique ids - others may yield
+ duplicated ones when they have been created in the same second.
+</p>
+<p>
+ Note, that SIG-TIMESTAMP may either be a number of seconds since
+ Epoch or an ISO 8601 string which can be detected by the presence
+ of the letter 'T'.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-1-10" class="outline-4">
+<h4 id="sec-2-1-10"><span class="section-number-4">2.1.10</span> ENC_TO &lt;long_keyid&gt; &lt;keytype&gt; &lt;keylength&gt;</h4>
+<div class="outline-text-4" id="text-2-1-10">
+
+<p> The message is encrypted to this LONG_KEYID. KEYTYPE is the
+ numerical value of the public key algorithm or 0 if it is not
+ known, KEYLENGTH is the length of the key or 0 if it is not known
+ (which is currently always the case). Gpg prints this line
+ always; Gpgsm only if it knows the certificate.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-1-11" class="outline-4">
+<h4 id="sec-2-1-11"><span class="section-number-4">2.1.11</span> BEGIN_DECRYPTION</h4>
+<div class="outline-text-4" id="text-2-1-11">
+
+<p> Mark the start of the actual decryption process. This is also
+ emitted when in &ndash;list-only mode.
+</p></div>
+
+</div>
+
+<div id="outline-container-2-1-12" class="outline-4">
+<h4 id="sec-2-1-12"><span class="section-number-4">2.1.12</span> END_DECRYPTION</h4>
+<div class="outline-text-4" id="text-2-1-12">
+
+<p> Mark the end of the actual decryption process. This are also
+ emitted when in &ndash;list-only mode.
+</p></div>
+
+</div>
+
+<div id="outline-container-2-1-13" class="outline-4">
+<h4 id="sec-2-1-13"><span class="section-number-4">2.1.13</span> DECRYPTION_INFO &lt;mdc_method&gt; &lt;sym_algo&gt;</h4>
+<div class="outline-text-4" id="text-2-1-13">
+
+<p> Print information about the symmetric encryption algorithm and the
+ MDC method. This will be emitted even if the decryption fails.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-1-14" class="outline-4">
+<h4 id="sec-2-1-14"><span class="section-number-4">2.1.14</span> DECRYPTION_FAILED</h4>
+<div class="outline-text-4" id="text-2-1-14">
+
+<p> The symmetric decryption failed - one reason could be a wrong
+ passphrase for a symmetrical encrypted message.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-1-15" class="outline-4">
+<h4 id="sec-2-1-15"><span class="section-number-4">2.1.15</span> DECRYPTION_OKAY</h4>
+<div class="outline-text-4" id="text-2-1-15">
+
+<p> The decryption process succeeded. This means, that either the
+ correct secret key has been used or the correct passphrase for a
+ conventional encrypted message was given. The program itself may
+ return an errorcode because it may not be possible to verify a
+ signature for some reasons.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-1-16" class="outline-4">
+<h4 id="sec-2-1-16"><span class="section-number-4">2.1.16</span> SESSION_KEY &lt;algo&gt;:&lt;hexdigits&gt;</h4>
+<div class="outline-text-4" id="text-2-1-16">
+
+<p> The session key used to decrypt the message. This message will
+ only be emitted when the special option &ndash;show-session-key is
+ used. The format is suitable to be passed to the option
+ &ndash;override-session-key
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-1-17" class="outline-4">
+<h4 id="sec-2-1-17"><span class="section-number-4">2.1.17</span> BEGIN_ENCRYPTION &lt;mdc_method&gt; &lt;sym_algo&gt;</h4>
+<div class="outline-text-4" id="text-2-1-17">
+
+<p> Mark the start of the actual encryption process.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-1-18" class="outline-4">
+<h4 id="sec-2-1-18"><span class="section-number-4">2.1.18</span> END_ENCRYPTION</h4>
+<div class="outline-text-4" id="text-2-1-18">
+
+<p> Mark the end of the actual encryption process.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-1-19" class="outline-4">
+<h4 id="sec-2-1-19"><span class="section-number-4">2.1.19</span> FILE_START &lt;what&gt; &lt;filename&gt;</h4>
+<div class="outline-text-4" id="text-2-1-19">
+
+<p> Start processing a file &lt;filename&gt;. &lt;what&gt; indicates the performed
+ operation:
+</p><dl>
+<dt>1</dt><dd>verify
+</dd>
+<dt>2</dt><dd>encrypt
+</dd>
+<dt>3</dt><dd>decrypt
+</dd>
+</dl>
+
+
+</div>
+
+</div>
+
+<div id="outline-container-2-1-20" class="outline-4">
+<h4 id="sec-2-1-20"><span class="section-number-4">2.1.20</span> FILE_DONE</h4>
+<div class="outline-text-4" id="text-2-1-20">
+
+<p> Marks the end of a file processing which has been started
+ by FILE_START.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-1-21" class="outline-4">
+<h4 id="sec-2-1-21"><span class="section-number-4">2.1.21</span> BEGIN_SIGNING</h4>
+<div class="outline-text-4" id="text-2-1-21">
+
+<p> Mark the start of the actual signing process. This may be used as
+ an indication that all requested secret keys are ready for use.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-1-22" class="outline-4">
+<h4 id="sec-2-1-22"><span class="section-number-4">2.1.22</span> ALREADY_SIGNED &lt;long-keyid&gt;</h4>
+<div class="outline-text-4" id="text-2-1-22">
+
+<p> Warning: This is experimental and might be removed at any time.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-1-23" class="outline-4">
+<h4 id="sec-2-1-23"><span class="section-number-4">2.1.23</span> SIG_CREATED &lt;type&gt; &lt;pk_algo&gt; &lt;hash_algo&gt; &lt;class&gt; &lt;timestamp&gt; &lt;keyfpr&gt;</h4>
+<div class="outline-text-4" id="text-2-1-23">
+
+<p> A signature has been created using these parameters.
+ Values for type &lt;type&gt; are:
+</p><dl>
+<dt>D</dt><dd>detached
+</dd>
+<dt>C</dt><dd>cleartext
+</dd>
+<dt>S</dt><dd>standard
+</dd>
+</dl>
+
+<p> (only the first character should be checked)
+</p>
+<p>
+ &lt;class&gt; are 2 hex digits with the OpenPGP signature class.
+</p>
+<p>
+ Note, that TIMESTAMP may either be a number of seconds since Epoch
+ or an ISO 8601 string which can be detected by the presence of the
+ letter 'T'.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-1-24" class="outline-4">
+<h4 id="sec-2-1-24"><span class="section-number-4">2.1.24</span> NOTATION_</h4>
+<div class="outline-text-4" id="text-2-1-24">
+
+<p> There are actually two related status codes to convey notation
+ data:
+</p>
+<ul>
+<li>NOTATION_NAME &lt;name&gt;
+</li>
+<li>NOTATION_DATA &lt;string&gt;
+</li>
+</ul>
+
+
+<p>
+ &lt;name&gt; and &lt;string&gt; are %XX escaped; the data may be split among
+ several NOTATION_DATA lines.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-1-25" class="outline-4">
+<h4 id="sec-2-1-25"><span class="section-number-4">2.1.25</span> POLICY_URL &lt;string&gt;</h4>
+<div class="outline-text-4" id="text-2-1-25">
+
+<p> Note that URL in &lt;string&gt; is %XX escaped.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-1-26" class="outline-4">
+<h4 id="sec-2-1-26"><span class="section-number-4">2.1.26</span> PLAINTEXT &lt;format&gt; &lt;timestamp&gt; &lt;filename&gt;</h4>
+<div class="outline-text-4" id="text-2-1-26">
+
+<p> This indicates the format of the plaintext that is about to be
+ written. The format is a 1 byte hex code that shows the format of
+ the plaintext: 62 ('b') is binary data, 74 ('t') is text data with
+ no character set specified, and 75 ('u') is text data encoded in
+ the UTF-8 character set. The timestamp is in seconds since the
+ epoch. If a filename is available it gets printed as the third
+ argument, percent-escaped as usual.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-1-27" class="outline-4">
+<h4 id="sec-2-1-27"><span class="section-number-4">2.1.27</span> PLAINTEXT_LENGTH &lt;length&gt;</h4>
+<div class="outline-text-4" id="text-2-1-27">
+
+<p> This indicates the length of the plaintext that is about to be
+ written. Note that if the plaintext packet has partial length
+ encoding it is not possible to know the length ahead of time. In
+ that case, this status tag does not appear.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-1-28" class="outline-4">
+<h4 id="sec-2-1-28"><span class="section-number-4">2.1.28</span> ATTRIBUTE &lt;arguments&gt;</h4>
+<div class="outline-text-4" id="text-2-1-28">
+
+<p> The list or argemnts are:
+</p><ul>
+<li>&lt;fpr&gt;
+</li>
+<li>&lt;octets&gt;
+</li>
+<li>&lt;type&gt;
+</li>
+<li>&lt;index&gt;
+</li>
+<li>&lt;count&gt;
+</li>
+<li>&lt;timestamp&gt;
+</li>
+<li>&lt;expiredate&gt;
+</li>
+<li>&lt;flags&gt;
+</li>
+</ul>
+
+
+<p>
+ This is one long line issued for each attribute subpacket when an
+ attribute packet is seen during key listing. &lt;fpr&gt; is the
+ fingerprint of the key. &lt;octets&gt; is the length of the attribute
+ subpacket. &lt;type&gt; is the attribute type (e.g. 1 for an image).
+ &lt;index&gt; and &lt;count&gt; indicate that this is the N-th indexed
+ subpacket of count total subpackets in this attribute packet.
+ &lt;timestamp&gt; and &lt;expiredate&gt; are from the self-signature on the
+ attribute packet. If the attribute packet does not have a valid
+ self-signature, then the timestamp is 0. &lt;flags&gt; are a bitwise OR
+ of:
+</p><dl>
+<dt>0x01</dt><dd>this attribute packet is a primary uid
+</dd>
+<dt>0x02</dt><dd>this attribute packet is revoked
+</dd>
+<dt>0x04</dt><dd>this attribute packet is expired
+</dd>
+</dl>
+
+
+</div>
+
+</div>
+
+<div id="outline-container-2-1-29" class="outline-4">
+<h4 id="sec-2-1-29"><span class="section-number-4">2.1.29</span> SIG_SUBPACKET &lt;type&gt; &lt;flags&gt; &lt;len&gt; &lt;data&gt;</h4>
+<div class="outline-text-4" id="text-2-1-29">
+
+<p> This indicates that a signature subpacket was seen. The format is
+ the same as the "spk" record above.
+</p>
+</div>
+</div>
+
+</div>
+
+<div id="outline-container-2-2" class="outline-3">
+<h3 id="sec-2-2"><span class="section-number-3">2.2</span> Key related</h3>
+<div class="outline-text-3" id="text-2-2">
+
+
+</div>
+
+<div id="outline-container-2-2-1" class="outline-4">
+<h4 id="sec-2-2-1"><span class="section-number-4">2.2.1</span> INV_RECP, INV_SGNR</h4>
+<div class="outline-text-4" id="text-2-2-1">
+
+<p> The two similar status codes:
+</p>
+<ul>
+<li>INV_RECP &lt;reason&gt; &lt;requested_recipient&gt;
+</li>
+<li>INV_SGNR &lt;reason&gt; &lt;requested_sender&gt;
+</li>
+</ul>
+
+
+<p>
+ are issued for each unusable recipient/sender. The reasons codes
+ currently in use are:
+</p>
+<dl>
+<dt>0</dt><dd>No specific reason given
+</dd>
+<dt>1</dt><dd>Not Found
+</dd>
+<dt>2</dt><dd>Ambigious specification
+</dd>
+<dt>3</dt><dd>Wrong key usage
+</dd>
+<dt>4</dt><dd>Key revoked
+</dd>
+<dt>5</dt><dd>Key expired
+</dd>
+<dt>6</dt><dd>No CRL known
+</dd>
+<dt>7</dt><dd>CRL too old
+</dd>
+<dt>8</dt><dd>Policy mismatch
+</dd>
+<dt>9</dt><dd>Not a secret key
+</dd>
+<dt>10</dt><dd>Key not trusted
+</dd>
+<dt>11</dt><dd>Missing certificate
+</dd>
+<dt>12</dt><dd>Missing issuer certificate
+</dd>
+</dl>
+
+
+<p>
+ Note that for historical reasons the INV_RECP status is also used
+ for gpgsm's SIGNER command where it relates to signer's of course.
+ Newer GnuPG versions are using INV_SGNR; applications should
+ ignore the INV_RECP during the sender's command processing once
+ they have seen an INV_SGNR. Different codes are used so that they
+ can be distinguish while doing an encrypt+sign operation.
+</p></div>
+
+</div>
+
+<div id="outline-container-2-2-2" class="outline-4">
+<h4 id="sec-2-2-2"><span class="section-number-4">2.2.2</span> NO_RECP &lt;reserved&gt;</h4>
+<div class="outline-text-4" id="text-2-2-2">
+
+<p> Issued if no recipients are usable.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-2-3" class="outline-4">
+<h4 id="sec-2-2-3"><span class="section-number-4">2.2.3</span> NO_SGNR &lt;reserved&gt;</h4>
+<div class="outline-text-4" id="text-2-2-3">
+
+<p> Issued if no senders are usable.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-2-4" class="outline-4">
+<h4 id="sec-2-2-4"><span class="section-number-4">2.2.4</span> KEYEXPIRED &lt;expire-timestamp&gt;</h4>
+<div class="outline-text-4" id="text-2-2-4">
+
+<p> The key has expired. expire-timestamp is the expiration time in
+ seconds since Epoch. This status line is not very useful because
+ it will also be emitted for expired subkeys even if this subkey is
+ not used. To check whether a key used to sign a message has
+ expired, the EXPKEYSIG status line is to be used.
+</p>
+<p>
+ Note, that the TIMESTAMP may either be a number of seconds since
+ Epoch or an ISO 8601 string which can be detected by the presence
+ of the letter 'T'.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-2-5" class="outline-4">
+<h4 id="sec-2-2-5"><span class="section-number-4">2.2.5</span> KEYREVOKED</h4>
+<div class="outline-text-4" id="text-2-2-5">
+
+<p> The used key has been revoked by its owner. No arguments yet.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-2-6" class="outline-4">
+<h4 id="sec-2-2-6"><span class="section-number-4">2.2.6</span> NO_PUBKEY &lt;long keyid&gt;</h4>
+<div class="outline-text-4" id="text-2-2-6">
+
+<p> The public key is not available
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-2-7" class="outline-4">
+<h4 id="sec-2-2-7"><span class="section-number-4">2.2.7</span> NO_SECKEY &lt;long keyid&gt;</h4>
+<div class="outline-text-4" id="text-2-2-7">
+
+<p> The secret key is not available
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-2-8" class="outline-4">
+<h4 id="sec-2-2-8"><span class="section-number-4">2.2.8</span> KEY_CREATED &lt;type&gt; &lt;fingerprint&gt; [&lt;handle&gt;]</h4>
+<div class="outline-text-4" id="text-2-2-8">
+
+<p> A key has been created. Values for &lt;type&gt; are:
+</p><dl>
+<dt>B</dt><dd>primary and subkey
+</dd>
+<dt>P</dt><dd>primary
+</dd>
+<dt>S</dt><dd>subkey
+</dd>
+</dl>
+
+<p> The fingerprint is one of the primary key for type B and P and the
+ one of the subkey for S. Handle is an arbitrary non-whitespace
+ string used to match key parameters from batch key creation run.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-2-9" class="outline-4">
+<h4 id="sec-2-2-9"><span class="section-number-4">2.2.9</span> KEY_NOT_CREATED [&lt;handle&gt;]</h4>
+<div class="outline-text-4" id="text-2-2-9">
+
+<p> The key from batch run has not been created due to errors.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-2-10" class="outline-4">
+<h4 id="sec-2-2-10"><span class="section-number-4">2.2.10</span> TRUST_</h4>
+<div class="outline-text-4" id="text-2-2-10">
+
+<p> These are several similar status codes:
+</p>
+<ul>
+<li>TRUST_UNDEFINED &lt;error_token&gt;
+</li>
+<li>TRUST_NEVER &lt;error_token&gt;
+</li>
+<li>TRUST_MARGINAL [0 [&lt;validation_model&gt;]]
+</li>
+<li>TRUST_FULLY [0 [&lt;validation_model&gt;]]
+</li>
+<li>TRUST_ULTIMATE [0 [&lt;validation_model&gt;]]
+</li>
+</ul>
+
+
+<p>
+ For good signatures one of these status lines are emitted to
+ indicate the validity of the key used to create the signature.
+ The error token values are currently only emitted by gpgsm.
+</p>
+<p>
+ VALIDATION_MODEL describes the algorithm used to check the
+ validity of the key. The defaults are the standard Web of Trust
+ model for gpg and the the standard X.509 model for gpgsm. The
+ defined values are
+</p>
+<dl>
+<dt>pgp </dt><dd>The standard PGP WoT.
+</dd>
+<dt>shell</dt><dd>The standard X.509 model.
+</dd>
+<dt>chain</dt><dd>The chain model.
+</dd>
+<dt>steed</dt><dd>The STEED model.
+</dd>
+</dl>
+
+
+<p>
+ Note that the term <code>TRUST_</code> in the status names is used for
+ historic reasons; we now speak of validity.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-2-11" class="outline-4">
+<h4 id="sec-2-2-11"><span class="section-number-4">2.2.11</span> PKA_TRUST_</h4>
+<div class="outline-text-4" id="text-2-2-11">
+
+<p> This is is one:
+</p>
+<ul>
+<li>PKA_TRUST_GOOD &lt;mailbox&gt;
+</li>
+<li>PKA_TRUST_BAD &lt;mailbox&gt;
+</li>
+</ul>
+
+
+<p>
+ Depending on the outcome of the PKA check one of the above status
+ codes is emitted in addition to a <code>TRUST_*</code> status.
+</p>
+</div>
+</div>
+
+</div>
+
+<div id="outline-container-2-3" class="outline-3">
+<h3 id="sec-2-3"><span class="section-number-3">2.3</span> Remote control</h3>
+<div class="outline-text-3" id="text-2-3">
+
+
+</div>
+
+<div id="outline-container-2-3-1" class="outline-4">
+<h4 id="sec-2-3-1"><span class="section-number-4">2.3.1</span> GET_BOOL, GET_LINE, GET_HIDDEN, GOT_IT</h4>
+<div class="outline-text-4" id="text-2-3-1">
+
+
+<p>
+ These status line are used with &ndash;command-fd for interactive
+ control of the process.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-3-2" class="outline-4">
+<h4 id="sec-2-3-2"><span class="section-number-4">2.3.2</span> USERID_HINT &lt;long main keyid&gt; &lt;string&gt;</h4>
+<div class="outline-text-4" id="text-2-3-2">
+
+<p> Give a hint about the user ID for a certain keyID.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-3-3" class="outline-4">
+<h4 id="sec-2-3-3"><span class="section-number-4">2.3.3</span> NEED_PASSPHRASE &lt;long keyid&gt; &lt;long main keyid&gt; &lt;keytype&gt; &lt;keylength&gt;</h4>
+<div class="outline-text-4" id="text-2-3-3">
+
+<p> Issued whenever a passphrase is needed. KEYTYPE is the numerical
+ value of the public key algorithm or 0 if this is not applicable,
+ KEYLENGTH is the length of the key or 0 if it is not known (this
+ is currently always the case).
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-3-4" class="outline-4">
+<h4 id="sec-2-3-4"><span class="section-number-4">2.3.4</span> NEED_PASSPHRASE_SYM &lt;cipher_algo&gt; &lt;s2k_mode&gt; &lt;s2k_hash&gt;</h4>
+<div class="outline-text-4" id="text-2-3-4">
+
+<p> Issued whenever a passphrase for symmetric encryption is needed.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-3-5" class="outline-4">
+<h4 id="sec-2-3-5"><span class="section-number-4">2.3.5</span> NEED_PASSPHRASE_PIN &lt;card_type&gt; &lt;chvno&gt; [&lt;serialno&gt;]</h4>
+<div class="outline-text-4" id="text-2-3-5">
+
+<p> Issued whenever a PIN is requested to unlock a card.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-3-6" class="outline-4">
+<h4 id="sec-2-3-6"><span class="section-number-4">2.3.6</span> MISSING_PASSPHRASE</h4>
+<div class="outline-text-4" id="text-2-3-6">
+
+<p> No passphrase was supplied. An application which encounters this
+ message may want to stop parsing immediately because the next
+ message will probably be a BAD_PASSPHRASE. However, if the
+ application is a wrapper around the key edit menu functionality it
+ might not make sense to stop parsing but simply ignoring the
+ following BAD_PASSPHRASE.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-3-7" class="outline-4">
+<h4 id="sec-2-3-7"><span class="section-number-4">2.3.7</span> BAD_PASSPHRASE &lt;long keyid&gt;</h4>
+<div class="outline-text-4" id="text-2-3-7">
+
+<p> The supplied passphrase was wrong or not given. In the latter
+ case you may have seen a MISSING_PASSPHRASE.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-3-8" class="outline-4">
+<h4 id="sec-2-3-8"><span class="section-number-4">2.3.8</span> GOOD_PASSPHRASE</h4>
+<div class="outline-text-4" id="text-2-3-8">
+
+<p> The supplied passphrase was good and the secret key material
+ is therefore usable.
+</p>
+</div>
+</div>
+
+</div>
+
+<div id="outline-container-2-4" class="outline-3">
+<h3 id="sec-2-4"><span class="section-number-3">2.4</span> Import/Export</h3>
+<div class="outline-text-3" id="text-2-4">
+
+
+</div>
+
+<div id="outline-container-2-4-1" class="outline-4">
+<h4 id="sec-2-4-1"><span class="section-number-4">2.4.1</span> IMPORT_CHECK &lt;long keyid&gt; &lt;fingerprint&gt; &lt;user ID&gt;</h4>
+<div class="outline-text-4" id="text-2-4-1">
+
+<p> This status is emitted in interactive mode right before
+ the "import.okay" prompt.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-4-2" class="outline-4">
+<h4 id="sec-2-4-2"><span class="section-number-4">2.4.2</span> IMPORTED &lt;long keyid&gt; &lt;username&gt;</h4>
+<div class="outline-text-4" id="text-2-4-2">
+
+<p> The keyid and name of the signature just imported
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-4-3" class="outline-4">
+<h4 id="sec-2-4-3"><span class="section-number-4">2.4.3</span> IMPORT_OK &lt;reason&gt; [&lt;fingerprint&gt;]</h4>
+<div class="outline-text-4" id="text-2-4-3">
+
+<p> The key with the primary key's FINGERPRINT has been imported.
+ REASON flags are:
+</p>
+<dl>
+<dt>0</dt><dd>Not actually changed
+</dd>
+<dt>1</dt><dd>Entirely new key.
+</dd>
+<dt>2</dt><dd>New user IDs
+</dd>
+<dt>4</dt><dd>New signatures
+</dd>
+<dt>8</dt><dd>New subkeys
+</dd>
+<dt>16</dt><dd>Contains private key.
+</dd>
+</dl>
+
+
+<p>
+ The flags may be ORed.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-4-4" class="outline-4">
+<h4 id="sec-2-4-4"><span class="section-number-4">2.4.4</span> IMPORT_PROBLEM &lt;reason&gt; [&lt;fingerprint&gt;]</h4>
+<div class="outline-text-4" id="text-2-4-4">
+
+<p> Issued for each import failure. Reason codes are:
+</p>
+<dl>
+<dt>0</dt><dd>No specific reason given.
+</dd>
+<dt>1</dt><dd>Invalid Certificate.
+</dd>
+<dt>2</dt><dd>Issuer Certificate missing.
+</dd>
+<dt>3</dt><dd>Certificate Chain too long.
+</dd>
+<dt>4</dt><dd>Error storing certificate.
+</dd>
+</dl>
+
+
+</div>
+
+</div>
+
+<div id="outline-container-2-4-5" class="outline-4">
+<h4 id="sec-2-4-5"><span class="section-number-4">2.4.5</span> IMPORT_RES &lt;args&gt;</h4>
+<div class="outline-text-4" id="text-2-4-5">
+
+<p> Final statistics on import process (this is one long line). The
+ args are a list of unsigned numbers separated by white space:
+</p>
+<ul>
+<li>&lt;count&gt;
+</li>
+<li>&lt;no_user_id&gt;
+</li>
+<li>&lt;imported&gt;
+</li>
+<li>&lt;imported_rsa&gt;
+</li>
+<li>&lt;unchanged&gt;
+</li>
+<li>&lt;n_uids&gt;
+</li>
+<li>&lt;n_subk&gt;
+</li>
+<li>&lt;n_sigs&gt;
+</li>
+<li>&lt;n_revoc&gt;
+</li>
+<li>&lt;sec_read&gt;
+</li>
+<li>&lt;sec_imported&gt;
+</li>
+<li>&lt;sec_dups&gt;
+</li>
+<li>&lt;skipped_new_keys&gt;
+</li>
+<li>&lt;not_imported&gt;
+</li>
+</ul>
+
+
+</div>
+</div>
+
+</div>
+
+<div id="outline-container-2-5" class="outline-3">
+<h3 id="sec-2-5"><span class="section-number-3">2.5</span> Smartcard related</h3>
+<div class="outline-text-3" id="text-2-5">
+
+
+</div>
+
+<div id="outline-container-2-5-1" class="outline-4">
+<h4 id="sec-2-5-1"><span class="section-number-4">2.5.1</span> CARDCTRL &lt;what&gt; [&lt;serialno&gt;]</h4>
+<div class="outline-text-4" id="text-2-5-1">
+
+<p> This is used to control smartcard operations. Defined values for
+ WHAT are:
+</p>
+<dl>
+<dt>1</dt><dd>Request insertion of a card. Serialnumber may be given
+ to request a specific card. Used by gpg 1.4 w/o
+ scdaemon
+</dd>
+<dt>2</dt><dd>Request removal of a card. Used by gpg 1.4 w/o scdaemon.
+</dd>
+<dt>3</dt><dd>Card with serialnumber detected
+</dd>
+<dt>4</dt><dd>No card available
+</dd>
+<dt>5</dt><dd>No card reader available
+</dd>
+<dt>6</dt><dd>No card support available
+</dd>
+</dl>
+
+
+</div>
+
+</div>
+
+<div id="outline-container-2-5-2" class="outline-4">
+<h4 id="sec-2-5-2"><span class="section-number-4">2.5.2</span> SC_OP_FAILURE [&lt;code&gt;]</h4>
+<div class="outline-text-4" id="text-2-5-2">
+
+<p> An operation on a smartcard definitely failed. Currently there is
+ no indication of the actual error code, but application should be
+ prepared to later accept more arguments. Defined values for
+ &lt;code&gt; are:
+</p>
+<dl>
+<dt>0</dt><dd>unspecified error (identically to a missing CODE)
+</dd>
+<dt>1</dt><dd>canceled
+</dd>
+<dt>2</dt><dd>bad PIN
+</dd>
+</dl>
+
+
+</div>
+
+</div>
+
+<div id="outline-container-2-5-3" class="outline-4">
+<h4 id="sec-2-5-3"><span class="section-number-4">2.5.3</span> SC_OP_SUCCESS</h4>
+<div class="outline-text-4" id="text-2-5-3">
+
+<p> A smart card operaion succeeded. This status is only printed for
+ certain operation and is mostly useful to check whether a PIN
+ change really worked.
+</p>
+</div>
+</div>
+
+</div>
+
+<div id="outline-container-2-6" class="outline-3">
+<h3 id="sec-2-6"><span class="section-number-3">2.6</span> Miscellaneous status codes</h3>
+<div class="outline-text-3" id="text-2-6">
+
+
+</div>
+
+<div id="outline-container-2-6-1" class="outline-4">
+<h4 id="sec-2-6-1"><span class="section-number-4">2.6.1</span> NODATA &lt;what&gt;</h4>
+<div class="outline-text-4" id="text-2-6-1">
+
+<p> No data has been found. Codes for WHAT are:
+</p>
+<dl>
+<dt>1</dt><dd>No armored data.
+</dd>
+<dt>2</dt><dd>Expected a packet but did not found one.
+</dd>
+<dt>3</dt><dd>Invalid packet found, this may indicate a non OpenPGP
+ message.
+</dd>
+<dt>4</dt><dd>Signature expected but not found
+</dd>
+</dl>
+
+
+<p>
+ You may see more than one of these status lines.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-6-2" class="outline-4">
+<h4 id="sec-2-6-2"><span class="section-number-4">2.6.2</span> UNEXPECTED &lt;what&gt;</h4>
+<div class="outline-text-4" id="text-2-6-2">
+
+<p> Unexpected data has been encountered. Codes for WHAT are:
+</p><dl>
+<dt>0</dt><dd>Not further specified
+</dd>
+</dl>
+
+
+</div>
+
+</div>
+
+<div id="outline-container-2-6-3" class="outline-4">
+<h4 id="sec-2-6-3"><span class="section-number-4">2.6.3</span> TRUNCATED &lt;maxno&gt;</h4>
+<div class="outline-text-4" id="text-2-6-3">
+
+<p> The output was truncated to MAXNO items. This status code is
+ issued for certain external requests.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-6-4" class="outline-4">
+<h4 id="sec-2-6-4"><span class="section-number-4">2.6.4</span> ERROR &lt;error location&gt; &lt;error code&gt; [&lt;more&gt;]</h4>
+<div class="outline-text-4" id="text-2-6-4">
+
+<p> This is a generic error status message, it might be followed by
+ error location specific data. &lt;error code&gt; and &lt;error_location&gt;
+ should not contain spaces. The error code is a either a string
+ commencing with a letter or such a string prefixed with a
+ numerical error code and an underscore; e.g.: "151011327_EOF".
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-6-5" class="outline-4">
+<h4 id="sec-2-6-5"><span class="section-number-4">2.6.5</span> SUCCESS [&lt;location&gt;]</h4>
+<div class="outline-text-4" id="text-2-6-5">
+
+<p> Postive confirimation that an operation succeeded. &lt;location&gt; is
+ optional but if given should not contain spaces. Used only with a
+ few commands.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-6-6" class="outline-4">
+<h4 id="sec-2-6-6"><span class="section-number-4">2.6.6</span> BADARMOR</h4>
+<div class="outline-text-4" id="text-2-6-6">
+
+<p> The ASCII armor is corrupted. No arguments yet.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-6-7" class="outline-4">
+<h4 id="sec-2-6-7"><span class="section-number-4">2.6.7</span> DELETE_PROBLEM &lt;reason_code&gt;</h4>
+<div class="outline-text-4" id="text-2-6-7">
+
+<p> Deleting a key failed. Reason codes are:
+</p><dl>
+<dt>1</dt><dd>No such key
+</dd>
+<dt>2</dt><dd>Must delete secret key first
+</dd>
+<dt>3</dt><dd>Ambigious specification
+</dd>
+</dl>
+
+
+</div>
+
+</div>
+
+<div id="outline-container-2-6-8" class="outline-4">
+<h4 id="sec-2-6-8"><span class="section-number-4">2.6.8</span> PROGRESS &lt;what&gt; &lt;char&gt; &lt;cur&gt; &lt;total&gt;</h4>
+<div class="outline-text-4" id="text-2-6-8">
+
+<p> Used by the primegen and Public key functions to indicate
+ progress. &lt;char&gt; is the character displayed with no &ndash;status-fd
+ enabled, with the linefeed replaced by an 'X'. &lt;cur&gt; is the
+ current amount done and &lt;total&gt; is amount to be done; a &lt;total&gt; of
+ 0 indicates that the total amount is not known. The condition
+</p><pre class="example">
+ TOTAL &amp;&amp; CUR == TOTAL
+</pre>
+
+<p> may be used to detect the end of an operation.
+</p>
+<p>
+ Well known values for WHAT are:
+</p>
+<dl>
+<dt>pk_dsa </dt><dd>DSA key generation
+</dd>
+<dt>pk_elg </dt><dd>Elgamal key generation
+</dd>
+<dt>primegen</dt><dd>Prime generation
+</dd>
+<dt>need_entropy</dt><dd>Waiting for new entropy in the RNG
+</dd>
+<dt>tick</dt><dd>Generic tick without any special meaning - useful
+ for letting clients know that the server is still
+ working.
+</dd>
+<dt>starting_agent</dt><dd>A gpg-agent was started because it is not
+ running as a daemon.
+</dd>
+<dt>learncard</dt><dd>Send by the agent and gpgsm while learing
+ the data of a smartcard.
+</dd>
+<dt>card_busy</dt><dd>A smartcard is still working
+</dd>
+</dl>
+
+
+</div>
+
+</div>
+
+<div id="outline-container-2-6-9" class="outline-4">
+<h4 id="sec-2-6-9"><span class="section-number-4">2.6.9</span> BACKUP_KEY_CREATED &lt;fingerprint&gt; &lt;fname&gt;</h4>
+<div class="outline-text-4" id="text-2-6-9">
+
+<p> A backup of a key identified by &lt;fingerprint&gt; has been writte to
+ the file &lt;fname&gt;; &lt;fname&gt; is percent-escaped.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-6-10" class="outline-4">
+<h4 id="sec-2-6-10"><span class="section-number-4">2.6.10</span> MOUNTPOINT &lt;name&gt;</h4>
+<div class="outline-text-4" id="text-2-6-10">
+
+<p> &lt;name&gt; is a percent-plus escaped filename describing the
+ mountpoint for the current operation (e.g. used by "g13 &ndash;mount").
+ This may either be the specified mountpoint or one randomly
+ choosen by g13.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-2-6-11" class="outline-4">
+<h4 id="sec-2-6-11"><span class="section-number-4">2.6.11</span> PINENTRY_LAUNCHED &lt;pid&gt;</h4>
+<div class="outline-text-4" id="text-2-6-11">
+
+<p> This status line is emitted by gpg to notify a client that a
+ Pinentry has been launched. &lt;pid&gt; is the PID of the Pinentry. It
+ may be used to display a hint to the user but can't be used to
+ synchronize with Pinentry. Note that there is also an Assuan
+ inquiry line with the same name used internally or, if enabled,
+ send to the client instead of this status line. Such an inquiry
+ may be used to sync with Pinentry
+</p>
+</div>
+</div>
+
+</div>
+
+<div id="outline-container-2-7" class="outline-3">
+<h3 id="sec-2-7"><span class="section-number-3">2.7</span> Obsolete status codes</h3>
+<div class="outline-text-3" id="text-2-7">
+
+
+</div>
+
+<div id="outline-container-2-7-1" class="outline-4">
+<h4 id="sec-2-7-1"><span class="section-number-4">2.7.1</span> SIGEXPIRED</h4>
+<div class="outline-text-4" id="text-2-7-1">
+
+<p> Removed on 2011-02-04. This is deprecated in favor of KEYEXPIRED.
+</p></div>
+
+</div>
+
+<div id="outline-container-2-7-2" class="outline-4">
+<h4 id="sec-2-7-2"><span class="section-number-4">2.7.2</span> RSA_OR_IDEA</h4>
+<div class="outline-text-4" id="text-2-7-2">
+
+<p> Obsolete. This status message used to be emitted for requests to
+ use the IDEA or RSA algorithms. It has been dropped from GnuPG
+ 2.1 after the respective patents expired.
+</p></div>
+
+</div>
+
+<div id="outline-container-2-7-3" class="outline-4">
+<h4 id="sec-2-7-3"><span class="section-number-4">2.7.3</span> SHM_INFO, SHM_GET, SHM_GET_BOOL, SHM_GET_HIDDEN</h4>
+<div class="outline-text-4" id="text-2-7-3">
+
+<p> These were used for the ancient shared memory based co-processing.
+</p></div>
+
+</div>
+
+<div id="outline-container-2-7-4" class="outline-4">
+<h4 id="sec-2-7-4"><span class="section-number-4">2.7.4</span> BEGIN_STREAM, END_STREAM</h4>
+<div class="outline-text-4" id="text-2-7-4">
+
+<p> Used to issued by the experimental pipemode.
+</p>
+
+</div>
+</div>
+</div>
+
+</div>
+
+<div id="outline-container-3" class="outline-2">
+<h2 id="sec-3"><span class="section-number-2">3</span> Format of the &ndash;attribute-fd output</h2>
+<div class="outline-text-2" id="text-3">
+
+
+<p>
+ When &ndash;attribute-fd is set, during key listings (&ndash;list-keys,
+ &ndash;list-secret-keys) GnuPG dumps each attribute packet to the file
+ descriptor specified. &ndash;attribute-fd is intended for use with
+ &ndash;status-fd as part of the required information is carried on the
+ ATTRIBUTE status tag (see above).
+</p>
+<p>
+ The contents of the attribute data is specified by RFC 4880. For
+ convenience, here is the Photo ID format, as it is currently the
+ only attribute defined:
+</p>
+<dl>
+<dt>Byte 0-1</dt><dd>The length of the image header. Due to a historical
+ accident (i.e. oops!) back in the NAI PGP days, this
+ is a little-endian number. Currently 16 (0x10 0x00).
+
+</dd>
+<dt>Byte 2</dt><dd>The image header version. Currently 0x01.
+
+</dd>
+<dt>Byte 3</dt><dd>Encoding format. 0x01 == JPEG.
+
+</dd>
+<dt>Byte 4-15</dt><dd>Reserved, and currently unused.
+</dd>
+</dl>
+
+
+<p>
+ All other data after this header is raw image (JPEG) data.
+</p>
+
+</div>
+
+</div>
+
+<div id="outline-container-4" class="outline-2">
+<h2 id="sec-4"><span class="section-number-2">4</span> Unattended key generation</h2>
+<div class="outline-text-2" id="text-4">
+
+
+<p>
+ Please see the GnuPG manual for a description.
+</p>
+
+</div>
+
+</div>
+
+<div id="outline-container-5" class="outline-2">
+<h2 id="sec-5"><span class="section-number-2">5</span> Layout of the TrustDB</h2>
+<div class="outline-text-2" id="text-5">
+
+
+<p>
+ The TrustDB is built from fixed length records, where the first byte
+ describes the record type. All numeric values are stored in network
+ byte order. The length of each record is 40 bytes. The first record
+ of the DB is always of type 1 and this is the only record of this
+ type.
+</p>
+<p>
+ FIXME: The layout changed, document it here.
+</p>
+
+
+<pre class="example">Record type 0:
+--------------
+ Unused record, can be reused for any purpose.
+
+Record type 1:
+--------------
+ Version information for this TrustDB. This is always the first
+ record of the DB and the only one with type 1.
+ 1 byte value 1
+ 3 bytes 'gpg' magic value
+ 1 byte Version of the TrustDB (2)
+ 1 byte marginals needed
+ 1 byte completes needed
+ 1 byte max_cert_depth
+ The three items are used to check whether the cached
+ validity value from the dir record can be used.
+ 1 u32 locked flags [not used]
+ 1 u32 timestamp of trustdb creation
+ 1 u32 timestamp of last modification which may affect the validity
+ of keys in the trustdb. This value is checked against the
+ validity timestamp in the dir records.
+ 1 u32 timestamp of last validation [currently not used]
+ (Used to keep track of the time, when this TrustDB was checked
+ against the pubring)
+ 1 u32 record number of keyhashtable [currently not used]
+ 1 u32 first free record
+ 1 u32 record number of shadow directory hash table [currently not used]
+ It does not make sense to combine this table with the key table
+ because the keyid is not in every case a part of the fingerprint.
+ 1 u32 record number of the trusthashtbale
+
+
+Record type 2: (directory record)
+--------------
+ Informations about a public key certificate.
+ These are static values which are never changed without user interaction.
+
+ 1 byte value 2
+ 1 byte reserved
+ 1 u32 LID . (This is simply the record number of this record.)
+ 1 u32 List of key-records (the first one is the primary key)
+ 1 u32 List of uid-records
+ 1 u32 cache record
+ 1 byte ownertrust
+ 1 byte dirflag
+ 1 byte maximum validity of all the user ids
+ 1 u32 time of last validity check.
+ 1 u32 Must check when this time has been reached.
+ (0 = no check required)
+
+
+Record type 3: (key record)
+--------------
+ Informations about a primary public key.
+ (This is mainly used to lookup a trust record)
+
+ 1 byte value 3
+ 1 byte reserved
+ 1 u32 LID
+ 1 u32 next - next key record
+ 7 bytes reserved
+ 1 byte keyflags
+ 1 byte pubkey algorithm
+ 1 byte length of the fingerprint (in bytes)
+ 20 bytes fingerprint of the public key
+ (This is the value we use to identify a key)
+
+Record type 4: (uid record)
+--------------
+ Informations about a userid
+ We do not store the userid but the hash value of the userid because that
+ is sufficient.
+
+ 1 byte value 4
+ 1 byte reserved
+ 1 u32 LID points to the directory record.
+ 1 u32 next next userid
+ 1 u32 pointer to preference record
+ 1 u32 siglist list of valid signatures
+ 1 byte uidflags
+ 1 byte validity of the key calculated over this user id
+ 20 bytes ripemd160 hash of the username.
+
+
+Record type 5: (pref record)
+--------------
+ This record type is not anymore used.
+
+ 1 byte value 5
+ 1 byte reserved
+ 1 u32 LID; points to the directory record (and not to the uid record!).
+ (or 0 for standard preference record)
+ 1 u32 next
+ 30 byte preference data
+
+Record type 6 (sigrec)
+-------------
+ Used to keep track of key signatures. Self-signatures are not
+ stored. If a public key is not in the DB, the signature points to
+ a shadow dir record, which in turn has a list of records which
+ might be interested in this key (and the signature record here
+ is one).
+
+ 1 byte value 6
+ 1 byte reserved
+ 1 u32 LID points back to the dir record
+ 1 u32 next next sigrec of this uid or 0 to indicate the
+ last sigrec.
+ 6 times
+ 1 u32 Local_id of signatures dir or shadow dir record
+ 1 byte Flag: Bit 0 = checked: Bit 1 is valid (we have a real
+ directory record for this)
+ 1 = valid is set (but may be revoked)
+
+
+
+Record type 8: (shadow directory record)
+--------------
+ This record is used to reserve a LID for a public key. We
+ need this to create the sig records of other keys, even if we
+ do not yet have the public key of the signature.
+ This record (the record number to be more precise) will be reused
+ as the dir record when we import the real public key.
+
+ 1 byte value 8
+ 1 byte reserved
+ 1 u32 LID (This is simply the record number of this record.)
+ 2 u32 keyid
+ 1 byte pubkey algorithm
+ 3 byte reserved
+ 1 u32 hintlist A list of records which have references to
+ this key. This is used for fast access to
+ signature records which are not yet checked.
+ Note, that this is only a hint and the actual records
+ may not anymore hold signature records for that key
+ but that the code cares about this.
+ 18 byte reserved
+
+
+
+Record Type 10 (hash table)
+--------------
+ Due to the fact that we use fingerprints to lookup keys, we can
+ implement quick access by some simple hash methods, and avoid
+ the overhead of gdbm. A property of fingerprints is that they can be
+ used directly as hash values. (They can be considered as strong
+ random numbers.)
+ What we use is a dynamic multilevel architecture, which combines
+ hashtables, record lists, and linked lists.
+
+ This record is a hashtable of 256 entries; a special property
+ is that all these records are stored consecutively to make one
+ big table. The hash value is simple the 1st, 2nd, ... byte of
+ the fingerprint (depending on the indirection level).
+
+ When used to hash shadow directory records, a different table is used
+ and indexed by the keyid.
+
+ 1 byte value 10
+ 1 byte reserved
+ n u32 recnum; n depends on the record length:
+ n = (reclen-2)/4 which yields 9 for the current record length
+ of 40 bytes.
+
+ the total number of such record which makes up the table is:
+ m = (256+n-1) / n
+ which is 29 for a record length of 40.
+
+ To look up a key we use the first byte of the fingerprint to get
+ the recnum from this hashtable and look up the addressed record:
+ - If this record is another hashtable, we use 2nd byte
+ to index this hash table and so on.
+ - if this record is a hashlist, we walk all entries
+ until we found one a matching one.
+ - if this record is a key record, we compare the
+ fingerprint and to decide whether it is the requested key;
+
+
+Record type 11 (hash list)
+--------------
+ see hash table for an explanation.
+ This is also used for other purposes.
+
+ 1 byte value 11
+ 1 byte reserved
+ 1 u32 next next hash list record
+ n times n = (reclen-5)/5
+ 1 u32 recnum
+
+ For the current record length of 40, n is 7
+
+
+
+Record type 254 (free record)
+---------------
+ All these records form a linked list of unused records.
+ 1 byte value 254
+ 1 byte reserved (0)
+ 1 u32 next_free
+</pre>
+
+
+
+</div>
+
+</div>
+
+<div id="outline-container-6" class="outline-2">
+<h2 id="sec-6"><span class="section-number-2">6</span> GNU extensions to the S2K algorithm</h2>
+<div class="outline-text-2" id="text-6">
+
+
+<p>
+ S2K mode 101 is used to identify these extensions.
+ After the hash algorithm the 3 bytes "GNU" are used to make
+ clear that these are extensions for GNU, the next bytes gives the
+ GNU protection mode - 1000. Defined modes are:
+</p><dl>
+<dt>1001</dt><dd>Do not store the secret part at all.
+</dd>
+<dt>1002</dt><dd>A stub to access smartcards (not used in 1.2.x)
+</dd>
+</dl>
+
+
+</div>
+
+</div>
+
+<div id="outline-container-7" class="outline-2">
+<h2 id="sec-7"><span class="section-number-2">7</span> Keyserver helper message format</h2>
+<div class="outline-text-2" id="text-7">
+
+
+<p>
+ The keyserver may be contacted by a Unix Domain socket or via TCP.
+</p>
+<p>
+ The format of a request is:
+</p>
+
+
+<pre class="example">command-tag
+"Content-length:" digits
+CRLF
+</pre>
+
+
+<p>
+ Where command-tag is
+</p>
+
+
+
+<pre class="example">NOOP
+GET &lt;user-name&gt;
+PUT
+DELETE &lt;user-name&gt;
+</pre>
+
+
+<p>
+The format of a response is:
+</p>
+
+
+
+<pre class="example">"GNUPG/1.0" status-code status-text
+"Content-length:" digits
+CRLF
+</pre>
+
+<p>
+followed by &lt;digits&gt; bytes of data
+</p>
+<p>
+Status codes are:
+</p>
+<dl>
+<dt>1xx</dt><dd>Informational - Request received, continuing process
+
+</dd>
+<dt>2xx</dt><dd>Success - The action was successfully received, understood,
+ and accepted
+
+</dd>
+<dt>4xx</dt><dd>Client Error - The request contains bad syntax or cannot be
+ fulfilled
+
+</dd>
+<dt>5xx</dt><dd>Server Error - The server failed to fulfill an apparently
+ valid request
+</dd>
+</dl>
+
+
+
+</div>
+
+</div>
+
+<div id="outline-container-8" class="outline-2">
+<h2 id="sec-8"><span class="section-number-2">8</span> Object identifiers</h2>
+<div class="outline-text-2" id="text-8">
+
+
+<p>
+ OIDs below the GnuPG arc:
+</p>
+
+
+
+<pre class="example">1.3.6.1.4.1.11591.2 GnuPG
+1.3.6.1.4.1.11591.2.1 notation
+1.3.6.1.4.1.11591.2.1.1 pkaAddress
+1.3.6.1.4.1.11591.2.2 X.509 extensions
+1.3.6.1.4.1.11591.2.2.1 standaloneCertificate
+1.3.6.1.4.1.11591.2.2.2 wellKnownPrivateKey
+1.3.6.1.4.1.11591.2.12242973 invalid encoded OID
+</pre>
+
+
+
+
+</div>
+
+</div>
+
+<div id="outline-container-9" class="outline-2">
+<h2 id="sec-9"><span class="section-number-2">9</span> Miscellaneous notes</h2>
+<div class="outline-text-2" id="text-9">
+
+
+
+</div>
+
+<div id="outline-container-9-1" class="outline-3">
+<h3 id="sec-9-1"><span class="section-number-3">9.1</span> v3 fingerprints</h3>
+<div class="outline-text-3" id="text-9-1">
+
+<p> For packet version 3 we calculate the keyids this way:
+</p><dl>
+<dt>RSA</dt><dd>Low 64 bits of n
+</dd>
+<dt>ELGAMAL</dt><dd>Build a v3 pubkey packet (with CTB 0x99) and
+ calculate a RMD160 hash value from it. This is used
+ as the fingerprint and the low 64 bits are the keyid.
+</dd>
+</dl>
+
+
+</div>
+
+</div>
+
+<div id="outline-container-9-2" class="outline-3">
+<h3 id="sec-9-2"><span class="section-number-3">9.2</span> Simplified revocation certificates</h3>
+<div class="outline-text-3" id="text-9-2">
+
+<p> Revocation certificates consist only of the signature packet;
+ "&ndash;import" knows how to handle this. The rationale behind it is to
+ keep them small.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-9-3" class="outline-3">
+<h3 id="sec-9-3"><span class="section-number-3">9.3</span> Documentation on HKP (the http keyserver protocol):</h3>
+<div class="outline-text-3" id="text-9-3">
+
+
+<p>
+ A minimalistic HTTP server on port 11371 recognizes a GET for
+ /pks/lookup. The standard http URL encoded query parameters are
+ this (always key=value):
+</p>
+<ul>
+<li>op=index (like pgp -kv), op=vindex (like pgp -kvv) and op=get (like
+ pgp -kxa)
+
+</li>
+<li>search=&lt;stringlist&gt;. This is a list of words that must occur in the key.
+ The words are delimited with space, points, @ and so on. The delimiters
+ are not searched for and the order of the words doesn't matter (but see
+ next option).
+
+</li>
+<li>exact=on. This switch tells the hkp server to only report exact matching
+ keys back. In this case the order and the "delimiters" are important.
+
+</li>
+<li>fingerprint=on. Also reports the fingerprints when used with 'index' or
+ 'vindex'
+</li>
+</ul>
+
+
+<p>
+ The keyserver also recognizes http-POSTs to /pks/add. Use this to upload
+ keys.
+</p>
+
+<p>
+ A better way to do this would be a request like:
+</p>
+<p>
+ /pks/lookup/&lt;gnupg_formatierte_user_id&gt;?op=&lt;operation&gt;
+</p>
+<p>
+ This can be implemented using Hurd's translator mechanism.
+ However, I think the whole key server stuff has to be re-thought;
+ I have some ideas and probably create a white paper.
+</p></div>
+</div>
+</div>
+</div>
+
+<div id="postamble">
+<p class="date">Date: 2013-07-03T09:52+0000</p>
+<p class="author">Author: isis</p>
+<p class="email"><a href="mailto:isis@wintermute.patternsinthevoid.net">isis@wintermute.patternsinthevoid.net</a></p>
+<p class="creator"><a href="http://orgmode.org">Org</a> version 7.9.2 with <a href="http://www.gnu.org/software/emacs/">Emacs</a> version 24</p>
+<a href="http://validator.w3.org/check?uri=referer">Validate XHTML 1.0</a>
+
+</div>
+</body>
+</html>
diff --git a/docs/_static/agogo.css b/docs/_static/agogo.css
new file mode 100644
index 0000000..2bdc26f
--- /dev/null
+++ b/docs/_static/agogo.css
@@ -0,0 +1,337 @@
+* {
+ margin: 0px;
+ padding: 0px;
+}
+
+body {
+ font-family: "Verdana", Arial, sans-serif;
+ line-height: 1.4em;
+ font-size: 14px;
+ color: black;
+ background-color: #eeeeec;
+}
+
+
+/* Page layout */
+
+div.header, div.content, div.footer {
+ width: 70em;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+div.header-wrapper {
+ background: url(bgtop.png) top left repeat-x;
+ border-bottom: 3px solid #2e3436;
+}
+
+div.headertitle a {
+ font-family: "Georgia", "Times New Roman", serif;
+ font-size: 2em;
+ color: rgb(252, 175, 62);
+ font-weight: normal;
+}
+
+h1 {
+ color: #204a87;
+}
+
+/* Default body styles */
+a {
+ text-decoration: none;
+ color: #ce5c00;
+}
+
+.clearer {
+ clear: both;
+}
+
+.left {
+ float: left;
+}
+
+.right {
+ float: right;
+}
+
+h1, h2, h3, h4 {
+ font-family: "Georgia", "Times New Roman", serif;
+ font-weight: normal;
+ color: #3465a4;
+ margin-bottom: .8em;
+}
+
+h1 {
+ color: #204a87;
+}
+
+h2 {
+ padding-bottom: .5em;
+ border-bottom: 1px solid #3465a4;
+}
+
+a.headerlink {
+ visibility: hidden;
+ color: #dddddd;
+ padding-left: .3em;
+}
+
+h1:hover > a.headerlink,
+h2:hover > a.headerlink,
+h3:hover > a.headerlink,
+h4:hover > a.headerlink,
+h5:hover > a.headerlink,
+h6:hover > a.headerlink,
+dt:hover > a.headerlink {
+ visibility: visible;
+}
+
+
+
+/* Header */
+
+div.header {
+ padding-top: 10px;
+ padding-bottom: 10px;
+}
+
+div.header h1 {
+ font-family: "Georgia", "Times New Roman", serif;
+ font-weight: normal;
+ font-size: 160%;
+ letter-spacing: .08em;
+}
+
+div.header h1 a {
+ color: white;
+}
+
+div.header div.rel {
+ margin-top: 1em;
+}
+
+div.header div.rel a {
+ color: #fcaf3e;
+ letter-spacing: .1em;
+ text-transform: uppercase;
+}
+
+
+/* Content */
+div.content-wrapper {
+ background-color: white;
+ padding-top: 20px;
+ padding-bottom: 20px;
+}
+
+div.document {
+ width: 50em;
+ float: left;
+}
+
+div.body {
+ padding-right: 2em;
+ text-align: justify;
+}
+
+div.document ul {
+ margin-left: 1.2em;
+ list-style-type: square;
+}
+
+div.document dd {
+ margin-left: 1.2em;
+ margin-top: .4em;
+ margin-bottom: 1em;
+}
+
+div.document .section {
+ margin-top: 1.7em;
+}
+div.document .section:first-child {
+ margin-top: 0px;
+}
+
+div.document div.highlight {
+ padding: 3px;
+ background-color: #eeeeec;
+ border-top: 2px solid #dddddd;
+ border-bottom: 2px solid #dddddd;
+ margin-top: .8em;
+ margin-bottom: .8em;
+}
+
+div.document h2 {
+ margin-top: .7em;
+}
+
+div.document p {
+ margin-bottom: .5em;
+}
+
+div.document li.toctree-l1 {
+ margin-bottom: 1em;
+}
+
+div.document .descname {
+ font-weight: bold;
+}
+
+div.document .docutils.literal {
+ background-color: #eeeeec;
+ padding: 1px;
+}
+
+div.document .docutils.xref.literal {
+ background-color: transparent;
+ padding: 0px;
+}
+
+
+/* Sidebar */
+
+div.sidebar {
+ width: 20em;
+ float: right;
+ font-size: .9em;
+}
+
+div.sidebar h3 {
+ color: #2e3436;
+ text-transform: uppercase;
+ font-size: 130%;
+ letter-spacing: .1em;
+}
+
+div.sidebar ul {
+ list-style-type: none;
+}
+
+div.sidebar li.toctree-l1 a {
+ display: block;
+ padding: 1px;
+ border: 1px solid #dddddd;
+ background-color: #eeeeec;
+ margin-bottom: .4em;
+ padding-left: 3px;
+ color: #2e3436;
+}
+
+div.sidebar li.toctree-l2 a {
+ background-color: transparent;
+ border: none;
+ border-bottom: 1px solid #dddddd;
+}
+
+div.sidebar li.toctree-l2:last-child a {
+ border-bottom: none;
+}
+
+div.sidebar li.toctree-l1.current a {
+ border-right: 5px solid #fcaf3e;
+}
+
+div.sidebar li.toctree-l1.current li.toctree-l2 a {
+ border-right: none;
+}
+
+
+/* Footer */
+
+div.footer-wrapper {
+ background: url(bgfooter.png) top left repeat-x;
+ border-top: 4px solid #babdb6;
+ padding-top: 10px;
+ padding-bottom: 10px;
+ min-height: 80px;
+}
+
+div.footer, div.footer a {
+ color: #888a85;
+}
+
+div.footer .right {
+ text-align: right;
+}
+
+div.footer .left {
+ text-transform: uppercase;
+}
+
+
+/* Styles copied form basic theme */
+
+/* -- search page ----------------------------------------------------------- */
+
+ul.search {
+ margin: 10px 0 0 20px;
+ padding: 0;
+}
+
+ul.search li {
+ padding: 5px 0 5px 20px;
+ background-image: url(file.png);
+ background-repeat: no-repeat;
+ background-position: 0 7px;
+}
+
+ul.search li a {
+ font-weight: bold;
+}
+
+ul.search li div.context {
+ color: #888;
+ margin: 2px 0 0 30px;
+ text-align: left;
+}
+
+ul.keywordmatches li.goodmatch a {
+ font-weight: bold;
+}
+
+/* -- index page ------------------------------------------------------------ */
+
+table.contentstable {
+ width: 90%;
+}
+
+table.contentstable p.biglink {
+ line-height: 150%;
+}
+
+a.biglink {
+ font-size: 1.3em;
+}
+
+span.linkdescr {
+ font-style: italic;
+ padding-top: 5px;
+ font-size: 90%;
+}
+
+/* -- general index --------------------------------------------------------- */
+
+table.indextable td {
+ text-align: left;
+ vertical-align: top;
+}
+
+table.indextable dl, table.indextable dd {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+table.indextable tr.pcap {
+ height: 10px;
+}
+
+table.indextable tr.cap {
+ margin-top: 10px;
+ background-color: #f2f2f2;
+}
+
+img.toggler {
+ margin-right: 3px;
+ margin-top: 3px;
+ cursor: pointer;
+}
diff --git a/docs/_static/pygments.css b/docs/_static/pygments.css
new file mode 100644
index 0000000..45bae6e
--- /dev/null
+++ b/docs/_static/pygments.css
@@ -0,0 +1,69 @@
+.hll { background-color: #ffffcc }
+.c { color: #8f5902; font-style: italic } /* Comment */
+.err { color: #a40000; border: 1px solid #ef2929 } /* Error */
+.g { color: #000000 } /* Generic */
+.k { color: #204a87; font-weight: bold } /* Keyword */
+.l { color: #000000 } /* Literal */
+.n { color: #000000 } /* Name */
+.o { color: #ce5c00; font-weight: bold } /* Operator */
+.x { color: #000000 } /* Other */
+.p { color: #000000; font-weight: bold } /* Punctuation */
+.cm { color: #8f5902; font-style: italic } /* Comment.Multiline */
+.cp { color: #8f5902; font-style: italic } /* Comment.Preproc */
+.c1 { color: #8f5902; font-style: italic } /* Comment.Single */
+.cs { color: #8f5902; font-style: italic } /* Comment.Special */
+.gd { color: #a40000 } /* Generic.Deleted */
+.ge { color: #000000; font-style: italic } /* Generic.Emph */
+.gr { color: #ef2929 } /* Generic.Error */
+.gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.gi { color: #00A000 } /* Generic.Inserted */
+.go { color: #000000; font-style: italic } /* Generic.Output */
+.gp { color: #8f5902 } /* Generic.Prompt */
+.gs { color: #000000; font-weight: bold } /* Generic.Strong */
+.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.gt { color: #a40000; font-weight: bold } /* Generic.Traceback */
+.kc { color: #204a87; font-weight: bold } /* Keyword.Constant */
+.kd { color: #204a87; font-weight: bold } /* Keyword.Declaration */
+.kn { color: #204a87; font-weight: bold } /* Keyword.Namespace */
+.kp { color: #204a87; font-weight: bold } /* Keyword.Pseudo */
+.kr { color: #204a87; font-weight: bold } /* Keyword.Reserved */
+.kt { color: #204a87; font-weight: bold } /* Keyword.Type */
+.ld { color: #000000 } /* Literal.Date */
+.m { color: #0000cf; font-weight: bold } /* Literal.Number */
+.s { color: #4e9a06 } /* Literal.String */
+.na { color: #c4a000 } /* Name.Attribute */
+.nb { color: #204a87 } /* Name.Builtin */
+.nc { color: #000000 } /* Name.Class */
+.no { color: #000000 } /* Name.Constant */
+.nd { color: #5c35cc; font-weight: bold } /* Name.Decorator */
+.ni { color: #ce5c00 } /* Name.Entity */
+.ne { color: #cc0000; font-weight: bold } /* Name.Exception */
+.nf { color: #000000 } /* Name.Function */
+.nl { color: #f57900 } /* Name.Label */
+.nn { color: #000000 } /* Name.Namespace */
+.nx { color: #000000 } /* Name.Other */
+.py { color: #000000 } /* Name.Property */
+.nt { color: #204a87; font-weight: bold } /* Name.Tag */
+.nv { color: #000000 } /* Name.Variable */
+.ow { color: #204a87; font-weight: bold } /* Operator.Word */
+.w { color: #f8f8f8; text-decoration: underline } /* Text.Whitespace */
+.mf { color: #0000cf; font-weight: bold } /* Literal.Number.Float */
+.mh { color: #0000cf; font-weight: bold } /* Literal.Number.Hex */
+.mi { color: #0000cf; font-weight: bold } /* Literal.Number.Integer */
+.mo { color: #0000cf; font-weight: bold } /* Literal.Number.Oct */
+.sb { color: #4e9a06 } /* Literal.String.Backtick */
+.sc { color: #4e9a06 } /* Literal.String.Char */
+.sd { color: #8f5902; font-style: italic } /* Literal.String.Doc */
+.s2 { color: #4e9a06 } /* Literal.String.Double */
+.se { color: #4e9a06 } /* Literal.String.Escape */
+.sh { color: #4e9a06 } /* Literal.String.Heredoc */
+.si { color: #4e9a06 } /* Literal.String.Interpol */
+.sx { color: #4e9a06 } /* Literal.String.Other */
+.sr { color: #4e9a06 } /* Literal.String.Regex */
+.s1 { color: #4e9a06 } /* Literal.String.Single */
+.ss { color: #4e9a06 } /* Literal.String.Symbol */
+.bp { color: #3465a4 } /* Name.Builtin.Pseudo */
+.vc { color: #000000 } /* Name.Variable.Class */
+.vg { color: #000000 } /* Name.Variable.Global */
+.vi { color: #000000 } /* Name.Variable.Instance */
+.il { color: #0000cf; font-weight: bold } /* Literal.Number.Integer.Long */
diff --git a/docs/change-license-emails.txt b/docs/change-license-emails.txt
new file mode 100644
index 0000000..7086089
--- /dev/null
+++ b/docs/change-license-emails.txt
@@ -0,0 +1,272 @@
+From: intrigeri <intrigeri@boum.org>
+To: Isis! <isis@patternsinthevoid.net>
+Subject: AGPL library, really?
+Date: Thu, 04 Jul 2013 17:38:46 +0000
+
+Hi isis,
+
+I see on https://pypi.python.org/pypi/gnupg that you released this
+library under AGPLv3. Is this correct?
+
+If it is, then you might be interested to have a look to this long
+ongoing thread on debian-devel mailing-list where I've seen explained
+(by people I trust on this topic) that AGPLv3 is really not well
+suited for libraries -- to start with, quite some of its terms are
+ambiguous when one tries to apply them to a library:
+https://lists.debian.org/debian-devel/2013/07/msg00031.html
+
+Cheers,
+--
+ intrigeri
+ | GnuPG key @ https://gaffer.ptitcanardnoir.org/intrigeri/intrigeri.asc
+ | OTR fingerprint @ https://gaffer.ptitcanardnoir.org/intrigeri/otr.asc
+
+
+From: isis agora lovecruft <isis@patternsinthevoid.net>
+To: intrigeri <intrigeri@boum.org>
+Subject: Re: AGPL library, really?
+Date: Sun, 07 Jul 2013 04:20:13 +0000
+
+Hi intrigeri!
+
+intrigeri transcribed 2.3K bytes:
+> I see on https://pypi.python.org/pypi/gnupg that you released this
+> library under AGPLv3. Is this correct?
+
+Yes, that it correct.
+
+> If it is, then you might be interested to have a look to this long
+> ongoing thread on debian-devel mailing-list where I've seen explained
+> (by people I trust on this topic) that AGPLv3 is really not well
+> suited for libraries -- to start with, quite some of its terms are
+> ambiguous when one tries to apply them to a library:
+> https://lists.debian.org/debian-devel/2013/07/msg00031.html
+
+Okay, thanks!
+
+/me reads…
+
+I think this message better describes why AGPL is bad for libraries:
+https://lists.debian.org/debian-devel/2013/07/msg00041.html or, at least, I
+understood that one better than the first.
+
+I certainly do not want to make problems for Debian, and now that a bunch of
+Tor, LEAP, CryptoParty, and Freebox projects, and perhaps soon Pip too, will
+be depending on this, I *really* don't want to make anyone else's license hell
+worse.
+
+Attached is an email from leap@lists.riseup.net where we had fisticuffs over
+licensing opinions, wherein I explained my preference for AGPL for
+everything. Essentially, I do not want people/corporations/etc. to use my work
+in a closed source application and then potentially make changes to patch
+found vulnerabilities without contributing those patches back to the main
+codebase.
+
+Though, you're correct, this doesn't make sense for a library, as a
+closed-source web-service frontend to this Python module likely isn't going to
+get anyone exploited except the person running the service. So it doesn't make
+as much sense.
+
+Do you know if it is okay for me to re-license it as regular GPL?
+
+Do you have any advice on which of GPLv(2|3)(\+)* that I should use?
+
+Thanks for pointing this out so quickly before it caused trouble, by the
+way. :)
+
+--
+ ♥Ⓐisis agora lovecruft
+_________________________________________________________
+GPG: 4096R/A3ADB67A2CDB8B35
+Current Keys: https://blog.patternsinthevoid.net/isis.txt
+
+--Attachment 1--
+ Date: Tue, 28 May 2013 04:13:56 +0000
+ From: isis agora lovecruft <isis@patternsinthevoid.net>
+ To: micah <micah@riseup.net>
+ Cc: leap@lists.riseup.net
+ X-GPG-Public-Key-URL: https://blog.patternsinthevoid.net/isis.txt
+ X-Louis-Lingg: In this hope do I say to you I despise you. I despise your
+ order, your laws, your force-propped authority. Hang me for it!
+ Subject: Re: [leap] license
+
+ micah transcribed 1.3K bytes:
+ > Tomas Touceda <chiiph@riseup.net> writes:
+ >
+ > > On 05/13/2013 05:32 PM, elijah wrote:
+ > >> if you have any wisdom or opinions regarding the ever joyful and
+ > >> uncontroversial topic of free software licenses, then please deposit
+ > >> said wisdom or opinions in this wiki:
+ > >>
+ > >> https://we.riseup.net/leap/license
+ > >>
+ > >> in a nutshell, we need to decide on a license for the client.
+ > >
+ > > Does anybody have license knowledge a priori? Or should I get started
+ > > reading licenses?
+ >
+ > I'm supposed to have a more than zero knowledge of what constitutes free
+ > licenses due to my debian training, and debian is world-renknowned for
+ > having a particularly nasty debian-legal mailing list where licenses are
+ > chewed up and spit out... but I personally hate the topic and tend to
+ > avoid it as much as possible.
+ >
+ > So basically my opinons are:
+ >
+ > 1. no license that is incompatible with the DFSG[0] (debian free
+ > software guidelines) - it seems like we are probably in agreement about
+ > this?
+
+ ACK
+
+ > 2. BSD multi-claused licenses and MIT are confusing and annoying, so I
+ > tend to think they should be avoided due to this
+ >
+
+ ACK
+
+ > 3. openssl derived works require granting an exception with GPL licenses
+ > (an exception is trivial), so I prefer gnutls code where possible
+ >
+
+ ACK
+
+ > 4. it seems weird to make things AGPL that aren't webapps
+ >
+
+ I started release everything I could AGPLv3 three years ago, after a
+ conversation with some other activist free-software devs:
+
+ Me: "I want a license which says 'If you are part of any governing body or
+ corporation which contracts to any private or public military entity, then
+ you should go fuck youself. And no, you cannot use my software -- I will
+ sue your pants off.'"
+
+ Them: "Isis, that is silly, and even na=C3=AFve. Universities are libraries are
+ often 'part of governing bodies', you don't want to exclude them, do you?
+ And also, you're like not going to see the blobs your code is included
+ in...it will get privately installed on custom military and law
+ enforcement hardware, and when they're done with it it'll go and rot
+ outside on a base or in a police confiscation parking lot somewhere."
+
+ Me: "Hum. I hate talking about licenses anyway."
+
+ Them: "Yeah, it sucks. But it's important for us to take this seriously,
+ because the tools we're working on have the potential for helping us
+ better organise at protests, as well as better help the cops kettle us
+ into paddy wagons." [one of the tools was a crisis mapping thing]
+
+ Different one of them: "Perhaps you both should read AGPL, and see if that
+ helps. I don't think using law against them is going to work, because we
+ can't assume they will play by the rules, but if we're arguing licenses
+ anyway..."
+
+ AGPL also seems useful when it seems possible that shady closed-source
+ startups are going to add a fancier UI or other feature to your code, and then
+ market it. This is especially worrying, not because they are "stealing users",
+ but because it's never clear if vulns discovered in your own code have been
+ fixed in theirs and vice versa. Or, it could get used in way that is
+ dangerous, or that it wasn't meant for. (For example, there is currently a
+ concern that a certain shell company is going to use OONI's code on these
+ little android-system-on-a-USB dongly thingies...and there are certain dangers
+ with Tor on Android that these people either don't understand or have no
+ intention of warning users about.)
+
+ Anyway. There is my argument for AGPL.
+
+ Though I also hate these discussions, don't care about laws, think reformism
+ is bunk, WTFPL is the only sane LICENSE, and all that jazz, so I'm going to go
+ stand over there ----------------------------------------------------------->
+ and watch everybody else duke it out. :)
+
+ --
+ ♥Ⓐ isis agora lovecruft
+ _________________________________________________________
+ GPG: 4096R/A3ADB67A2CDB8B35
+ Current Keys: https://blog.patternsinthevoid.net/isis.txt
+--End Attachment 1--
+
+From: intrigeri <intrigeri@boum.org>
+To: Isis! <isis@patternsinthevoid.net>
+Subject: Re: AGPL library, really?
+Date: Tue, 09 Jul 2013 18:30:46 +0000
+
+Hi isis,
+
+isis agora lovecruft wrote (07 Jul 2013 04:20:13 GMT) :
+> I think this message better describes why AGPL is bad for libraries:
+> https://lists.debian.org/debian-devel/2013/07/msg00041.html
+> or, at least, I understood that one better than the first.
+
+TBH, I've pointed you at the beginning of the thread because I was too
+lazy to go fetch the best email in there. I'm glad it helps anyway.
+
+> Do you know if it is okay for me to re-license it as regular GPL?
+
+I've just re-read a bit to confirm, and my conclusion is that: yeah,
+as the sole copyright holder (is this the case?) you can freely
+re-licence to whatever you want.
+
+> Do you have any advice on which of GPLv(2|3)(\+)* that I should use?
+
+I usually do GPL-3+, but I would not be able to defend it seriously
+against v2 or v2+.
+
+> Thanks for pointing this out so quickly before it caused trouble, by the
+> way. :)
+
+Np.
+
+Cheers!
+--
+ intrigeri
+ | GnuPG key @ https://gaffer.ptitcanardnoir.org/intrigeri/intrigeri.asc
+ | OTR fingerprint @ https://gaffer.ptitcanardnoir.org/intrigeri/otr.asc
+
+From: isis agora lovecruft <isis@patternsinthevoid.net>
+To: intrigeri <intrigeri@boum.org>
+Subject: Re: AGPL library, really?
+Date: Thu, 11 Jul 2013 09:24:12 +0000
+
+intrigeri transcribed 2.6K bytes:
+> isis agora lovecruft wrote (07 Jul 2013 04:20:13 GMT) :
+> > Do you know if it is okay for me to re-license it as regular GPL?
+>
+> I've just re-read a bit to confirm, and my conclusion is that: yeah,
+> as the sole copyright holder (is this the case?) you can freely
+> re-licence to whatever you want.
+
+Hey intrigeri,
+
+I've decided to re-license with your recommendation of GPL3+. Is it okay to
+credit you and/or publicly point to these emails as the basis for the
+rationale for the switch?
+
+--
+ ♥Ⓐ isis agora lovecruft
+_________________________________________________________
+GPG: 4096R/A3ADB67A2CDB8B35
+Current Keys: https://blog.patternsinthevoid.net/isis.txt
+
+From: intrigeri <intrigeri@boum.org>
+To: Isis! <isis@patternsinthevoid.net>
+Subject: Re: AGPL library, really?
+Date: Sun, 14 Jul 2013 22:33:35 +0000
+
+Hi isis,
+
+> Is it okay to credit you and/or publicly point to these emails as
+> the basis for the rationale for the switch?
+
+Feel free to credit me if you wish, but I certainly don't feel it's
+necessary.
+
+I feel a bit lazy to read this thread again to check if it's fine to
+publish stuff from there, so if you don't mind, I'd rather skip this
+part ;)
+
+Cheers,
+--
+ intrigeri
+ | GnuPG key @ https://gaffer.ptitcanardnoir.org/intrigeri/intrigeri.asc
+ | OTR fingerprint @ https://gaffer.ptitcanardnoir.org/intrigeri/otr.asc
diff --git a/docs/conf.py b/docs/conf.py
new file mode 100644
index 0000000..4986e0b
--- /dev/null
+++ b/docs/conf.py
@@ -0,0 +1,312 @@
+# -*- coding: utf-8 -*-
+#
+# python-gnupg documentation build configuration file, created by
+# sphinx-quickstart on Fri Apr 5 22:38:47 2013.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+import psutil
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+sys.path.insert(0, os.path.abspath('./../'))
+sys.path.insert(0, os.path.abspath('.'))
+
+# -- Autodoc settings ----------------------------------------------------------
+## trying to set this somewhere...
+autodoc_member_order = 'bysource'
+autodoc_default_flags = ['members', 'show-inheritance', 'undoc-members', 'show-hidden']
+autoclass_content = 'both'
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+needs_sphinx = '1.1'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.autodoc',
+ 'sphinx.ext.viewcode',
+ 'sphinx.ext.intersphinx',
+ 'sphinx.ext.doctest',
+ 'sphinxcontrib.fulltoc',
+ ]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_static']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'gnupg'
+copyright = u'2013, Isis Agora Lovecruft'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+import gnupg
+version = gnupg.__version__
+# The full version, including alpha/beta/rc tags.
+release = gnupg.__version__
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+today_fmt = '%d %B %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+add_module_names = False
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+show_authors = True
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'monokai'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+# Example configuration for intersphinx: refer to the Python standard library.
+intersphinx_mapping = {'http://docs.python.org/': None}
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+html_theme = 'scrolls'
+#html_theme = 'traditional'
+#html_theme = 'nature'
+#html_theme = 'pyramid'
+html_theme = 'agogo'
+#html_theme = 'haiku'
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+html_theme_options = {
+# 'stickysidebar': 'true',
+# 'rightsidebar':'true',
+ 'nosidebar': 'false',
+# 'full_logo': 'false'
+ 'sidebarwidth': '300'
+ }
+
+# Add any paths that contain custom themes here, relative to this directory.
+html_theme_path = ['_static']
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+html_short_title = "gnupg: Python Module Documentation"
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+html_last_updated_fmt = '%A, %d %B %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+html_file_suffix = '.html'
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'gnupgdoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('index', 'python-gnupg.tex', u'python-gnupg Documentation',
+ u'Isis Agora Lovecruft', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('index', 'gnupg Python Module Docs', u'gnupg Python Module Documentation',
+ [u'Isis Agora Lovecruft'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output ------------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ ('index', 'python-gnupg', u'python-gnupg Documentation',
+ u'Isis Agora Lovecruft', 'python-gnupg', 'One line description of project.',
+ 'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+
+# -- Options for Epub output ---------------------------------------------------
+
+# Bibliographic Dublin Core info.
+epub_title = u'python-gnupg'
+epub_author = u'Isis Agora Lovecruft'
+epub_publisher = u'Isis Agora Lovecruft'
+epub_copyright = u'2013, Isis Agora Lovecruft'
+
+# The language of the text. It defaults to the language option
+# or en if the language is not set.
+#epub_language = ''
+
+# The scheme of the identifier. Typical schemes are ISBN or URL.
+#epub_scheme = ''
+
+# The unique identifier of the text. This can be a ISBN number
+# or the project homepage.
+#epub_identifier = ''
+
+# A unique identification for the text.
+#epub_uid = ''
+
+# A tuple containing the cover image and cover page html template filenames.
+#epub_cover = ()
+
+# HTML files that should be inserted before the pages created by sphinx.
+# The format is a list of tuples containing the path and title.
+#epub_pre_files = []
+
+# HTML files shat should be inserted after the pages created by sphinx.
+# The format is a list of tuples containing the path and title.
+#epub_post_files = []
+
+# A list of files that should not be packed into the epub file.
+#epub_exclude_files = []
+
+# The depth of the table of contents in toc.ncx.
+#epub_tocdepth = 3
+
+# Allow duplicate toc entries.
+#epub_tocdup = True
diff --git a/docs/gnupg.rst b/docs/gnupg.rst
new file mode 100644
index 0000000..fc8a479
--- /dev/null
+++ b/docs/gnupg.rst
@@ -0,0 +1,131 @@
+gnupg package
+=============
+
+gnupg module
+------------
+
+This module contains public classes for working with GnuPG_. To get started,
+do:
+
+>>> import gnupg
+>>> gpg = gnupg.GPG()
+
+
+.. automodule:: gnupg
+ :members:
+ :undoc-members:
+ :private-members:
+ :show-inheritance:
+
+.. _meta:
+
+meta module
+-----------
+
+Contains the meta and base classes which :class:`gnupg.GPG` inherits
+from. Mostly, you shouldn't ever need to touch anything in here, unless you're
+doing some serious hacking.
+
+
+.. automodule:: gnupg._meta
+ :members:
+ :private-members:
+ :special-members:
+ :exclude-members: _agent_proc, __module__, __dict__, _decode_errors, init,
+ __weakref__, _result_map, __metaclass__
+ :show-inheritance:
+
+.. _parsers:
+
+parsers module
+--------------
+
+These are classes for parsing both user inputs and status file descriptor
+flags from GnuPG's output. The latter are used in order to determine what our
+GnuPG process is doing and retrieve information about its operations, which
+are stored in corresponding classes in
+:attr:`~gnupg._meta.GPGBase._result_map`. Some status flags aren't handled yet
+-- information on *all* of the flags (well, at least the documented ones…) can
+be found in the :file:`docs/DETAILS` file in GnuPG's source_, which has been
+included here_ as well.
+
+
+.. automodule:: gnupg._parsers
+ :members:
+ :undoc-members:
+ :private-members:
+ :show-inheritance:
+
+
+.. _util:
+
+util module
+-----------
+
+You shouldn't really need to mess with this module either, it mostly deals
+with low-level IO and file handling operations, de-/en- coding issues, and
+setting up basic package facilities such as logging.
+
+.. automodule:: gnupg._util
+ :members:
+ :undoc-members:
+ :private-members:
+ :show-inheritance:
+
+
+About this fork
+---------------
+
+This is a modified version of python-gnupg_, (forked from version 0.3.2) which
+was created by Vinay Sajip, which itself is a modification of GPG.py written
+by Steve Traugott, which in turn is a modification of the pycrypto GnuPG
+interface written by A.M. Kuchling.
+
+This version is patched to sanitize untrusted inputs, due to the necessity of
+executing ``subprocess.Popen([...], shell=True)`` in order to communicate with
+GnuPG. Several speed improvements were also made based on code profiling, and
+the API has been cleaned up to support an easier, more Pythonic, interaction.
+
+
+Previous Authors' Documentation
+-------------------------------
+
+Steve Traugott's documentation:
+ |
+ | Portions of this module are derived from A.M. Kuchling's well-designed
+ | GPG.py, using Richard Jones' updated version 1.3, which can be found in
+ | the pycrypto CVS repository on Sourceforge:
+ |
+ | http://pycrypto.cvs.sourceforge.net/viewvc/pycrypto/gpg/GPG.py
+ |
+ | This module is *not* forward-compatible with amk's; some of the old
+ | interface has changed. For instance, since I've added decrypt
+ | functionality, I elected to initialize with a 'gpghome' argument instead
+ | of 'keyring', so that gpg can find both the public and secret keyrings.
+ | I've also altered some of the returned objects in order for the caller to
+ | not have to know as much about the internals of the result classes.
+ |
+ | While the rest of ISconf is released under the GPL, I am releasing this
+ | single file under the same terms that A.M. Kuchling used for pycrypto.
+ |
+ | Steve Traugott, stevegt@terraluna.org
+ | Thu Jun 23 21:27:20 PDT 2005
+
+
+Vinay Sajip's documentation:
+ |
+ | This version of the module has been modified from Steve Traugott's version
+ | (see http://trac.t7a.org/isconf/browser/trunk/lib/python/isconf/GPG.py) by
+ | Vinay Sajip to make use of the subprocess module (Steve's version uses
+ | os.fork() and so does not work on Windows). Renamed to gnupg.py to avoid
+ | confusion with the previous versions.
+ |
+ | A unittest harness (test_gnupg.py) has also been added.
+ |
+ | Modifications Copyright (C) 2008-2012 Vinay Sajip. All rights reserved.
+
+
+.. _GnuPG: http://gnupg.org
+.. _python-gnupg: https://code.google.com/p/python-gnupg/
+.. _source: http://http://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=shortlog;h=refs/heads/master
+.. _here: ./_static/DETAILS.html
diff --git a/docs/gpg-migrate.txt b/docs/gpg-migrate.txt
new file mode 100644
index 0000000..1d07450
--- /dev/null
+++ b/docs/gpg-migrate.txt
@@ -0,0 +1,208 @@
+# taken from http://atom.smasher.org/gpg/gpg-migrate.txt on 8 Aug 2013
+
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA1
+
+HOW TO MIGRATE A (SUB)KEY INTO A NEW KEY
+
+this document [is intended to] explain how to migrate a key or subkey from
+one OpenPGP key into another OpenPGP key.
+
+here i'll walk you through the steps of migrating my old primary signing
+key (3D7D41E3) into my new key (D9F57808). the process of migrating
+encryption (and signing) subkeys is nearly identical. for the adventurous,
+you can even migrate several keys at once using this method (i recommend
+going through it once or twice with only one key).
+
+============================================================================
+
+doing this requires:
+ 1) basic knowledge of a *nix command line and how to use it
+ 2) advanced knowledge of gpg and how to use it
+ 3) common sense (BACKUP YOUR DATA!!)
+
+please note:
+ * this works for me. that does not necessarily mean that it will
+ work for you
+ * if you screw something up, it's *YOUR* problem, not mine
+ * this was tested with GnuPG 1.2.4, and written on or about
+ 12 May 2004
+ * updates, if there are any, will probably be noted above
+ * comments and suggestions about this tutorial should be sent to:
+ <atom {at} smasher.org>
+ * questions about gpg should be sent to the gnupg-users mailing
+ list: http://lists.gnupg.org/mailman/listinfo/gnupg-users
+
+============================================================================
+
+* old key: 3EBE 2810 30AE 601D 54B2 4A90 9C28 0BBF 3D7D 41E3
+
+pub 1024D/3D7D41E3 2003-10-04 Atom Smasher <atom@suspicious.org>
+uid Atom Smasher <atom@smasher.org>
+sub 2048g/1E88BF71 2003-10-04 [expires: 2005-01-26]
+
+================
+
+* new key: 762A 3B98 A3C3 96C9 C6B7 582A B88D 52E4 D9F5 7808
+
+pub 4096R/D9F57808 2004-05-11 Atom Smasher <atom@smasher.org>
+uid Atom Smasher <atom@suspicious.org>
+sub 1024D/3D7D41E3 2003-10-04 [expires: 2006-02-13]
+sub 2048g/1E88BF71 2003-10-04 [expires: 2006-01-26]
+
+===================================
+
+backup the new keys:
+ $ gpg --export D9F57808 > D9F57808_original.txt
+ $ gpg --export-secret-key D9F57808 > D9F57808_original_secret.txt
+
+and the old keys:
+ $ gpg --export 3D7D41E3 > 3D7D41E3_original.txt
+ $ gpg --export-secret-key 3D7D41E3 > 3D7D41E3_original_secret.txt
+
+break the old secret key into pieces:
+ $ gpg --export-secret-key 3D7D41E3 | gpgsplit -vp OLD_SEC
+
+===================================
+
+in this case, the old primary key needs to be converted into a subkey.
+pgpdump shows that it's a primary key:
+ $ pgpdump OLD_SEC000001-005.secret_key
+ Old: Secret Key Packet(tag 5)
+ <<snip>>
+
+only do this if you're converting a PRIMARY KEY into a SUBKEY: open that
+file in a hex editor and refer to RFC2440 4.2 & 4.3. i recommend setting
+the hex editor into a binary display. in this example the first byte is
+"10010101" and it needs to be changed to "10011101". the change can be
+confirmed with pgpdump:
+ $ pgpdump OLD_SEC000001-005.secret_key
+ Old: Secret Subkey Packet(tag 7)
+ <<snip>>
+
+we've now converted the old primary key into a subkey. if you're moving a
+subkey from one key to another, you don't have to do that.
+
+===================================
+
+use "edit-key" and add a subkey of the same type (DSA, for this example)
+and size to the new key. this subkey will be discarded, but we need to
+generate it for now: this seems to be the quickest way to generate a
+keybinding signature with the correct features.
+
+exit from "edit-key" and save.
+
+===================================
+
+split the current version of the new public key:
+ $ gpg --export D9F57808 | gpgsplit -vp TEMP_KEY1
+the only part we need from that split is the binding signature that was
+just generated.
+
+delete (from the keyring) both the private and public copies of the new
+key:
+ $ gpg --delete-secret-key D9F57808
+ $ gpg --delete-key D9F57808
+
+also delete (from the keyring) both the private and public copies of the
+old key.
+
+because the subkey that we're adding to the new key does not correspond to
+the subkey binding signature that was created for it, gpg will not allow
+the key to be imported. the way around that is to "force feed" the key into
+the keyring, bypassing the normal sanity checks. once it's in the keyring
+we can make it all work.
+
+* note: the actual file names that you're using may differ somewhat from
+mine. when in doubt (or rather, when you're not sure), use pgpdump to
+examine the contents of files.
+
+~import~ (directly into the secret keyring) the original copy of the new
+key (D9F57808_original_secret.txt), the edited copy of the old primary key
+(now a subkey, OLD_SEC000001-005.secret_key) and the binding signature of
+the subkey that we just generated (TEMP_KEY1000007-002.sig):
+ $ cat D9F57808_original_secret.txt \
+ OLD_SEC000001-005.secret_key \
+ TEMP_KEY1000007-002.sig >> ~/.gnupg/secring.gpg
+
+~import~ (directly into the public keyring) a public key by adding
+"| gpgsplit --no-split --secret-to-public" to the above command like this:
+ $ cat D9F57808_original_secret.txt \
+ OLD_SEC000001-005.secret_key \
+ TEMP_KEY1000007-002.sig \
+ | gpgsplit --no-split --secret-to-public >> ~/.gnupg/pubring.gpg
+
+now we have to make a *valid* keybinding signature for the subkey that we
+just added. use "edit-key", select the newly added subkey, and reset it's
+expiration date. that will generate a valid keybinding signature.
+
+while in "edit-key", reset the password. otherwise you may inadvertently
+create a key with multiple passwords, as described here -
+ http://atom.smasher.org/gpg/gpg-passwords.txt
+
+exit from "edit-key" and save.
+
+=========================
+
+this last part makes no sense to me (but it doesn't seem to work
+otherwise).
+
+back up (export) the latest version of the public and private keys:
+ $ gpg --export-secret-key D9F57808 > new-key.sec
+ $ gpg --export D9F57808 > new-key.pub
+
+delete (from the keyring) the private and public key:
+ $ gpg --delete-secret-key D9F57808
+ $ gpg --delete-key D9F57808
+
+also, delete (from the keyring) all copies of the old (sub)key that was
+just added to the new key.
+
+import the new public and private keys:
+ $ gpg --import new-key.sec new-key.pub
+
+=========================
+
+before you publish your new key:
+
+* make sure the key is "ultimately trusted". deleting and importing will
+have removed it from the trust db. since you own the key, ultimate trust
+seems reasonable.
+
+* check all expiration dates and preferences. some of these operations may
+have changed your expiration dates and preferences; reset as necessary.
+
+* test out all key components for creating and verifying signatures, and
+encryption/decryption. use the bang (!) to force each (sub)key:
+ create & verify signatures:
+ $ date | gpg -u 'D9F57808!' --clearsign | gpg -v --verify
+ $ date | gpg -u '3D7D41E3!' --clearsign | gpg -v --verify
+ encrypt/decrypt:
+ $ date | gpg -ear 'D9F57808!' | gpg -v --decrypt
+ $ date | gpg -ear '1E88BF71!' | gpg -v --decrypt
+
+* after testing out the keys locally, send your new public key to one or
+two people and test all key components (sending signed/encrypted messages
+to each other using all key components). make sure that they first delete
+(from their keyrings) your old key! and make sure that they understand that
+the key should NOT be circulated until all functions are verified to be
+working!
+
+* when putting the new key into circulation, it's probably a good idea to
+expire/revoke the old key. include a revocation comment that specifies the
+new key ID and instructions to delete the old key from the keyring.
+
+* note on key revocation: according to the OpenPGP standards a revocation
+generated by a sub key will be ignored, unless that subkey has been
+designated (by the primary key) as a revocation key. GnuPG seems to behave
+correctly, but some versions of PGP(tm) may not. if someone is claiming
+that your new key is revoked, have then remove all of your old and current
+keys from their keyring: then re-import your current key(s).
+
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.2.4 (FreeBSD)
+
+iD8DBQFApwlpnCgLvz19QeMRAhrpAJ4rhLrmVDjABh8CpPdTZ5jNMi7LsgCgp35S
+6qcUe4csx1p5AE2rAsvDi9c=
+=y7bA
+-----END PGP SIGNATURE-----
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644
index 0000000..c266353
--- /dev/null
+++ b/docs/index.rst
@@ -0,0 +1,44 @@
+.. gnupg documentation master file, created by
+ sphinx-quickstart on Fri Apr 5 22:38:47 2013.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+gnupg: Python Package Documentation
+===================================
+A Python interface for handling interactions with GnuPG, including keyfile
+generation, keyring maintainance, import and export, encryption and
+decryption, sending to and recieving from keyservers, and signing and
+verification.
+
+Contents:
+
+.. toctree::
+ :maxdepth: 2
+
+ gnupg
+
+
+Source, license, & bug reports
+==============================
+The source code which was used to generate this documentation is accessible by
+clicking the little `source` links next to the docs. Current source code can
+be found in this github repository_. The **master** branch always reflects the
+latest release, all releases are tagged with signed, annotated git tags, and
+the **develop** branch represents the state of the next release.
+
+This package is released under GPLv3_ or greater.
+
+If you find a bug, or would like to request a feature, please use our public
+bugtracker_ on github. Patches warmly welcome.
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
+.. _source: https://github.com/isislovecruft/python-gnupg
+.. _repository: https://github.com/isislovecruft/python-gnupg
+.. _GPLv3: https://www.gnu.org/licenses/gpl.txt
+.. _bugtracker: https://github.com/isislovecruft/python-gnupg/issues
diff --git a/docs/make.bat b/docs/make.bat
new file mode 100644
index 0000000..fa3950f
--- /dev/null
+++ b/docs/make.bat
@@ -0,0 +1,190 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+set I18NSPHINXOPTS=%SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+ set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+ set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+ :help
+ echo.Please use `make ^<target^>` where ^<target^> is one of
+ echo. html to make standalone HTML files
+ echo. dirhtml to make HTML files named index.html in directories
+ echo. singlehtml to make a single large HTML file
+ echo. pickle to make pickle files
+ echo. json to make JSON files
+ echo. htmlhelp to make HTML files and a HTML help project
+ echo. qthelp to make HTML files and a qthelp project
+ echo. devhelp to make HTML files and a Devhelp project
+ echo. epub to make an epub
+ echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+ echo. text to make text files
+ echo. man to make manual pages
+ echo. texinfo to make Texinfo files
+ echo. gettext to make PO message catalogs
+ echo. changes to make an overview over all changed/added/deprecated items
+ echo. linkcheck to check all external links for integrity
+ echo. doctest to run all doctests embedded in the documentation if enabled
+ goto end
+)
+
+if "%1" == "clean" (
+ for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+ del /q /s %BUILDDIR%\*
+ goto end
+)
+
+if "%1" == "html" (
+ %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+ goto end
+)
+
+if "%1" == "dirhtml" (
+ %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+ goto end
+)
+
+if "%1" == "singlehtml" (
+ %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+ goto end
+)
+
+if "%1" == "pickle" (
+ %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the pickle files.
+ goto end
+)
+
+if "%1" == "json" (
+ %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the JSON files.
+ goto end
+)
+
+if "%1" == "htmlhelp" (
+ %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+ goto end
+)
+
+if "%1" == "qthelp" (
+ %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+ echo.^> qcollectiongenerator %BUILDDIR%\qthelp\python-gnupg.qhcp
+ echo.To view the help file:
+ echo.^> assistant -collectionFile %BUILDDIR%\qthelp\python-gnupg.ghc
+ goto end
+)
+
+if "%1" == "devhelp" (
+ %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished.
+ goto end
+)
+
+if "%1" == "epub" (
+ %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The epub file is in %BUILDDIR%/epub.
+ goto end
+)
+
+if "%1" == "latex" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "text" (
+ %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The text files are in %BUILDDIR%/text.
+ goto end
+)
+
+if "%1" == "man" (
+ %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The manual pages are in %BUILDDIR%/man.
+ goto end
+)
+
+if "%1" == "texinfo" (
+ %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
+ goto end
+)
+
+if "%1" == "gettext" (
+ %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
+ goto end
+)
+
+if "%1" == "changes" (
+ %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.The overview file is in %BUILDDIR%/changes.
+ goto end
+)
+
+if "%1" == "linkcheck" (
+ %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+ goto end
+)
+
+if "%1" == "doctest" (
+ %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+ goto end
+)
+
+:end