API documentation¶
GnuPG API¶
Native Python / GPG API
This API was written to replace the GPGME bindings because the GPGME API has a few problems:
- it is arcane and difficult to grasp
- it is very closely bound to the internal GPG data and commandline structures, which are quite confusing
- GPGME doesn’t actually talk to a GPG library, but interacts with GPG through the commandline
- GPGME developers are not willing to extend GPGME to cover private key material management and consider this is outside the scope of the project.
The latter two points are especially problematic for this project, and I have therefore started working on a replacement.
Operations are performed mostly through the Keyring or KeyringTmp class (if you do not want to access your regular keyring but an empty temporary one).
This is how you can access keys, which are represented by the OpenPGPkey datastructure, but which will not look in your keyring or on the keyservers itself without the Keyring class.
It seems that I have missed a similar project that’s been around for quite a while (2008-2012):
https://code.google.com/p/python-gnupg/
The above project has a lot of similarities with this implementation, but is better because:
- it actually parses most status outputs from GPG, in a clean way
- uses threads so it doesn’t block
- supports streams
- supports verification, key generation and deletion
- has a cleaner and more complete test suite
However, the implementation here has:
- key signing support
- a cleaner API
Error handling is somewhat inconsistent here. Some functions rely on exceptions, other on boolean return values. We prefer exceptions as it allows us to propagate error messages to the UI, but make sure to generate a RuntimeError, and not a ProtocolError, which are unreadable to the user.
-
class
monkeysign.gpg.
Context
[source]¶ Python wrapper for GnuPG
This wrapper allows for a simpler interface than GPGME or PyME to GPG, and bypasses completely GPGME to interoperate directly with GPG as a process.
It uses the gpg-agent to prompt for passphrases and communicates with GPG over the stdin for commnads (–command-fd) and stdout for status (–status-fd).
-
build_command
(command)[source]¶ internal helper to build a proper gpg commandline
this will add relevant arguments around the gpg binary.
like the options arguments, the command is expected to be a regular gpg command with the – stripped. the – are added before being called. this is to make the code more readable, and eventually support other backends that actually make more sense.
this uses build_command to create a commandline out of the ‘options’ dictionary, and appends the provided command at the end. this is because order of certain options matter in gpg, where some options (like –recv-keys) are expected to be at the end.
it is here that the options dictionary is converted into a list. the command argument is expected to be a list of arguments that can be converted to strings. if it is not a list, it is cast into a list.
-
call_command
(command, stdin=None)[source]¶ internal wrapper to call a GPG commandline
this will call the command generated by build_command() and setup a regular pipe to the subcommand.
this assumes that we have the status-fd on stdout and command-fd on stdin, but could really be used in any other way.
we pass the stdin argument in the standard input of gpg and we keep the output in the stdout and stderr array. the exit code is in the returncode variable.
we can optionnally watch for a confirmation pattern on the statusfd.
-
expect
(fd, pattern)[source]¶ look for a specific GNUPG status on the next line of output
this is a stub for expect()
-
expect_pattern
(fd, pattern)[source]¶ make sure the next line matches the provided pattern
in contrast with seek_pattern(), this will not skip non-matching lines and instead raise an exception if such a line is found.
this therefore looks only at the next line, but may also hang like seek_pattern()
if the beginning of the line matches a pattern which is being ignored, it will skip it and look at the next line
-
gpg_binary
= 'gpg'¶
-
options
= {'batch': None, 'command-fd': 0, 'fixed-list-mode': None, 'list-options': 'show-sig-subpackets,show-uid-validity,show-unusable-uids,show-unusable-subkeys,show-keyring,show-sig-expire', 'no-tty': None, 'no-verbose': None, 'quiet': None, 'status-fd': 2, 'use-agent': None, 'with-colons': None, 'with-fingerprint': None}¶
-
seek
(fd, pattern)[source]¶ look for a specific GNUPG status line in the output
this is a stub for seek_pattern()
-
seek_pattern
(fd, pattern)[source]¶ iterate over file descriptor until certain pattern is found
fd is a file descriptor pattern a string describing a regular expression to match
this will skip lines not matching pattern until the pattern is found. it will raise an IOError if the pattern is not found and EOF is reached.
this may hang for streams that do not send EOF or are waiting for input.
-
-
exception
monkeysign.gpg.
GpgProtocolError
[source]¶ simple exception raised when we have trouble talking with GPG
we try to pass the subprocess.popen.returncode as an errorno and a significant description string
this error shouldn’t be propagated to the user, because it will contain mostly “expect” jargon from the DETAILS.txt file. the gpg module should instead raise a GpgRutimeError with a user-readable error message (e.g. “key not found”).
-
class
monkeysign.gpg.
Keyring
(homedir=None)[source]¶ Keyring functionalities.
This allows various operations (e.g. listing, signing, exporting data) on a keyring.
Concretely, we talk about a “keyring”, but we really mean a set of public and private keyrings and their trust databases. In practice, this is the equivalent of the GNUPGHOME or –homedir in GPG, and in fact this is implemented by setting a specific homedir to tell GPG to operate on a specific keyring.
We actually use the –homedir parameter to gpg to set the keyring we operate upon.
-
context
= None¶
-
decrypt_data
(data)[source]¶ decrypt data using asymetric encryption
returns the plaintext data or raise a GpgRuntimeError if it failed.
-
encrypt_data
(data, recipient)[source]¶ encrypt data using asymetric encryption
returns the encrypted data or raise a GpgRuntimeError if it fails
-
export_data
(fpr=None, secret=False)[source]¶ Export OpenPGP data blocks from the keyring.
This exports actual OpenPGP data, by default in binary format, but can also be exported asci-armored by setting the ‘armor’ option.
-
fetch_keys
(fpr, keyserver=None)[source]¶ Download keys from a keyserver into the local keyring
This expects a fingerprint (or a at least a key id).
Returns true if the command succeeded.
-
get_keys
(pattern=None, secret=False, public=True, keys=None)[source]¶ load keys matching a specific patterns
this uses the (rather poor) list-keys API to load keys information
-
import_data
(data)[source]¶ Import OpenPGP data blocks into the keyring.
This takes actual OpenPGP data, ascii-armored or not, gpg will gladly take it. This can be signatures, public, private keys, etc.
You may need to set import-flags to import non-exportable signatures, however.
-
sign_key
(pattern, signall=False, local=False)[source]¶ sign a OpenPGP public key
By default it looks up and signs a specific uid, but it can also sign all uids in one shot thanks to GPG’s optimization on that.
The pattern here should be a full user id if we sign a specific key (default) or any pattern (fingerprint, keyid, partial user id) that GPG will accept if we sign all uids.
@todo that this currently block if the pattern specifies an incomplete UID and we do not sign all keys.
-
-
class
monkeysign.gpg.
OpenPGPkey
(data=None)[source]¶ An OpenPGP key.
Some of this datastructure is taken verbatim from GPGME.
-
algo
= -1¶
-
creation
= 0¶
-
disabled
= False¶
-
expired
¶
-
expiry
¶ Returns a datetime from the _expiry field or None if the key does not expire
-
fpr
= None¶
-
invalid
= False¶
-
length
= None¶
-
purpose
= {}¶
-
qualified
= False¶
-
revoked
¶ Returns whether GnuPG thinks the key has been revoked
This is the second field of the result of the –list-key –with-colons call. Note that this information is only present on public keys, i.e. not on secret keys.
Returns None if it cannot be determined whether this key has been revoked.
-
secret
= False¶
-
subkeys
= {}¶
-
trust
= None¶
-
trust_map
= {'': 'empty', '-': 'unknown', 'd': 'disabled', 'e': 'expired', 'f': 'full', 'i': 'invalid', 'm': 'marginal', 'n': 'none', 'o': 'new', 'q': 'undefined', 'r': 'revoked', 'u': 'ultimate'}¶
-
uids
= {}¶
-
-
class
monkeysign.gpg.
OpenPGPuid
(uid, trust, creation=0, expire=None, uidhash='')[source]¶ -
-
revoked
¶ Whether this UID has been revoked
Note that, due to GnuPG not exporting that information for secret keys, UIDs of secret keys do not carry that information.
Return None if it cannot be determined whether this UID has been revoked. Try again with the public key.
-