Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
160 commits
Select commit Hold shift + click to select a range
cc18025
WIP/ENH: add dsa signature verification
SantiagoTorres Nov 16, 2017
cfce9dc
MAIN: gpg: force the use of gpgv2
SantiagoTorres Nov 16, 2017
9cb50de
FIX; gpg: fall back to default gpg , use sha256
SantiagoTorres Nov 16, 2017
bd4c27c
FIX: addresses review comments for the first round
SantiagoTorres Nov 28, 2017
0487fa8
Add format schemas for in_toto.gpg keys
Nov 28, 2017
7fb2b59
ENH: gpg: add subpacket parsing routines
SantiagoTorres Nov 28, 2017
aec11ff
Replace dash in gpg signature field other-headers
Nov 29, 2017
ab0e6dd
Re-add keyid to gpg signature dictionary
Nov 29, 2017
4c2326c
Remove debug print from gpg.common
Nov 30, 2017
3600196
Replace gpg with gpg2 command
Nov 30, 2017
1f06a12
Add gpg util function to get installed version
Dec 1, 2017
0977573
Add function to check if installed gpg2>=2.1.0
Dec 1, 2017
2dc7a44
Warn if parse_signature_packet can't derive keyid
Dec 1, 2017
71c56ad
Add workaround if gpg signing can't compute keyid
Dec 1, 2017
99cbc33
Add keyid schema check to gpg_export_pubkey
Dec 1, 2017
9f11f65
Raise exception when trying to parse empty pubkey
Dec 1, 2017
ec13412
Exlcude gpg version case handling from coverage
Dec 4, 2017
769afd1
Exclude gpg parsing errors from coverage
Dec 4, 2017
09a6a52
Move gpg_verify_signature to gpg.functions module
Dec 5, 2017
4dad40a
Add docstrings to gpg.functions
Dec 5, 2017
b5bf074
Fix docstring and whitespace in gpg subpackage
Dec 5, 2017
105fa7b
Add/update docstring in formats modules
Dec 8, 2017
0b3542f
Add gpg.exceptions module
Dec 8, 2017
090a38a
Replace item with module imports in gpg package
Dec 8, 2017
145157d
Replace package path with module name in doc header
Dec 8, 2017
88cb1f9
Modify gpg docstrings to indiciate used gpg cmd
Dec 8, 2017
be43e2f
Rename junk variable `_` to `junk`
Dec 8, 2017
3441dce
Sanitze inputs in gpg.gpg_verify_signature
Dec 8, 2017
aeb0c13
Add blanklines, remove ws, refine docs in gpg
Dec 18, 2017
ece2351
Add docstrings to gpg dsa/rsa verify functions
Dec 18, 2017
e85d6e0
ENH: gpg: update comments for signature type
SantiagoTorres Jan 8, 2018
a563a61
DOC: gpg: constants: describe hash constant values
SantiagoTorres Jan 8, 2018
eac46e8
DOC:gpg:util:describe subpacket length computation
SantiagoTorres Jan 8, 2018
94b1276
DOC:gpg:common: Improve exception message clarity
SantiagoTorres Jan 8, 2018
7700253
DOC:gpg:functions: update exception docstrings
SantiagoTorres Jan 8, 2018
a069098
DOC:gpg: move outdated comment common -> util
SantiagoTorres Jan 8, 2018
b639db0
ENH: gpg: add missing docstrings
SantiagoTorres Jan 8, 2018
8bd6d51
ENH: gpg: comment unused variables.
SantiagoTorres Jan 8, 2018
5028e68
Minor form fixes in GPG subpackage
Jan 8, 2018
724d8a9
Disable pylint import checks for distutils
Jan 8, 2018
e1eeef0
Replace filter/lambda with for loop in gpg.common
Jan 8, 2018
e49d5ba
Py2/3 use subprocess.Popen in textmode
Dec 6, 2017
e9428f2
Py2/3 decode gpg keyids using ascii
Dec 6, 2017
1849ac6
Add no coverage pragma to gpg version dependent if
Jan 18, 2018
e47f585
Refactor log module
Jan 31, 2018
6be8e39
Fix test log inundation
Jan 31, 2018
c05dbe2
FIX: gpg: s/pgp+SHA1/pgp+SHA2/
SantiagoTorres Feb 15, 2018
5e3d6d4
FIX:gpg: fix docstring
SantiagoTorres Feb 20, 2018
873d5c1
ENH:gpg: add constant for dsa
SantiagoTorres Feb 20, 2018
d9249b2
WIP: gpg: add signing subkey support
SantiagoTorres Feb 23, 2018
13aa42f
Add optional subkeys to gpg rsa/dsa pubkey schema
Feb 26, 2018
a5a9092
Add custom KeyNotFoundError error to gpg module
Feb 26, 2018
8c411bb
Add subkeys on gpg pubkey export
Feb 26, 2018
c24d9d9
Enable gpg subkey trust in signature verification
Feb 26, 2018
a6e90b2
Add gpg subkey to test files
Feb 26, 2018
5e87d2b
Add better rfc refs to gpg util function
Feb 28, 2018
2a1a39b
Add custom gpg packet parsing exceptions
Feb 28, 2018
92f4c32
Add gpg parse_pubkey_payload function
Feb 28, 2018
e152209
Add gpg parse_pubkey_bundle function
Feb 28, 2018
13462a9
Use parse bundle in gpg_export_pubkey
Feb 28, 2018
e7c758a
Remove obsolete gpg parse_pubkey_packet
Feb 28, 2018
f462506
Fix minor bug in gpg signature subpacket parser
Mar 1, 2018
b0d4018
Add optional short_keyid to gpg signature schema
Mar 1, 2018
7226e5d
Return short keyid from parse_signature_packet
Mar 1, 2018
fd4abd7
Update gpg_sign_object full keyid workaround
Mar 1, 2018
0865b23
Replace occurences of gpg main key with master key
Mar 9, 2018
b5fb66c
Add RFC4880 references comments to gpg constants
Mar 9, 2018
97c2c65
Rephrase comments for self-referential gpg formats
Mar 9, 2018
7af35cb
Update gpg.util.parse_packet_header docstring
Mar 9, 2018
f3dd862
Allow user-specified GPG executables (using patch from @SantiagoTorres)
trishankatdatadog Sep 13, 2018
507c1c4
Assume and test that gpg2 exists. Otherwise, assume gpg exists.
trishankatdatadog Sep 14, 2018
44b0afd
Minor edit: use double-quoted strings to be consistent.
trishankatdatadog Sep 14, 2018
6a8b64c
remove unused import
trishankatdatadog Sep 14, 2018
71d6a54
ENH: add windows support
RubyLiu206 Sep 19, 2018
d483e1d
FIX: gpg: functions: remove unused var 'errors'
SantiagoTorres Sep 20, 2018
3250c52
use subprocess32 on python2 by default
trishankatdatadog Sep 26, 2018
94d218e
Simpler code as per @ofek suggestion
trishankatdatadog Sep 29, 2018
3fcca3b
test on windows
trishankatdatadog Oct 2, 2018
7ade166
remove unused imports
trishankatdatadog Oct 2, 2018
7667e1e
Add shebang and doc header to process.py
Oct 4, 2018
ea86129
Refactor trishank's process.run wrapper
Oct 4, 2018
f493bc9
Add environment marker to install dependencies
Oct 4, 2018
55544be
Add debug statements to gpg commands
Nov 2, 2018
2777ab6
FIX: gpg/rsa: fix #171 signature length bug
SantiagoTorres Nov 19, 2018
3be3157
MAINT: gpg: remove log.debug statements to fix 171
SantiagoTorres Nov 20, 2018
12fea0e
Add subprocess run function that duplicates streams
Jan 22, 2019
ba85c6a
Close files used by subprocess in windows
Jan 25, 2019
612771e
Update gpg signature subpacket parsing
Feb 18, 2019
2bcda67
Fix gpg subpacket header length parsing
Feb 18, 2019
2192ea9
Support gpg new format packet length header
Feb 18, 2019
ed6bfa0
Exclude rare gpg packet lengths from coverage
Feb 19, 2019
1fa299b
Add partial SHA1 and SHA512 gpg signature support
Feb 20, 2019
79440e1
Update supported hash algos in signature parsing
Feb 20, 2019
242a935
Update supported types in signature parsing
Feb 20, 2019
3676387
Enhance gpg error messages and fix comments/docs
Feb 20, 2019
c457290
Add optional info to signature
Feb 20, 2019
5030a79
Update keyid handling in parse_signature_packet
Feb 27, 2019
0a7adee
Remove obsolete else clause in parse_pubkey_payload
Feb 27, 2019
5ed65e1
Add gpg self-certificate verification support
Feb 27, 2019
f2e5715
Init primary key as empty dict to fix pylint error
Feb 28, 2019
fcf734d
Clean up gpg.util.get_hashing_class
Mar 15, 2019
7b3f7f4
Raise/catch specific error in parse_pubkey_bundle
Mar 15, 2019
fbcc4dc
Use binary notation for bitmasks in gpg.util
Mar 15, 2019
57cb471
Remove stray whitespace before colon
Mar 15, 2019
49e7c61
Revert hash algo arg in gpg_verify_signature
Mar 18, 2019
10d1ea3
Remove unused import in gpg.rsa
Mar 18, 2019
c4be714
Remove underscores in numeric binary literals
Mar 18, 2019
ed90fb2
Change return values of gpg parse_packet_header
Mar 18, 2019
dba1ac6
Mark unreachable code in parse_packet_header
Mar 18, 2019
2aaa1cc
Add gpg.util.parse_packet_header tests
Mar 18, 2019
d9ff73a
Reactor gpg.util.parse_subpackets
Mar 19, 2019
c7621bd
Add gpg.common.parse_pubkey_payload tests
Mar 20, 2019
f08c54f
Re-organize gpg pubkey parsing functions
Mar 20, 2019
0dc1865
Update gpg raw pubkey bundle data format
Mar 21, 2019
a0c3f06
Update error handling in gpg pubkey parse helpers
Mar 21, 2019
2b01c6f
Add gpg.common._get_verified_subkeys tests
Mar 21, 2019
8043441
Add gpg.common.parse_signature_packet tests
Mar 21, 2019
1947cb2
Exclude full gpg keyid related code from coverage
Mar 21, 2019
8353b62
Fix blank lines at module head in gpg subpackage
Mar 22, 2019
cd9396c
Use set instead of list in `in` condition
Mar 22, 2019
74c5c18
Fix typos in gpg subpackage comments
Mar 22, 2019
8c1125b
Add TODO comment to commented out gpg block
Mar 22, 2019
dca4360
ENH: gpg:common: parse and verify expiration dates
michizhou Nov 21, 2018
2dd544e
Added signature information extraction for public keys
michizhou Mar 20, 2019
445bb5a
Remove trailing whitespace
Mar 22, 2019
13ff99a
Remove unused imports in gpg subpackage and test
Mar 22, 2019
b6f5370
Remove expiration parsing in parse_pubkey_payload
Mar 22, 2019
3821720
Remove obsolete SIGNATURE_TYPE_PARSING constant
Mar 22, 2019
d2de5b4
Rename gpg pubkey creation and expiration fields
Mar 22, 2019
a1efab1
Remove expiration parsing in get_pubkey_payload
Mar 22, 2019
ba85bdb
Remove gpg signature key_expire_time field
Mar 22, 2019
9f381cd
Refactor gpg certified key information assignment
Mar 22, 2019
18a5651
Replace default-key with local-user in gpg sign
Mar 27, 2019
6b1f02d
Raise custom CommandError in gpg_sign_object
Mar 28, 2019
5d6094c
Raise custom KeyExpirationError in gpg_verify_signature
Mar 28, 2019
d2853bd
Make gpg KeyExpirationError message timezone aware
Mar 28, 2019
19f5214
Adopt new gpg errors in caller docstrings
Mar 28, 2019
a3eec84
Fix _get_verified subkeys docstring and test
Mar 28, 2019
6e365b4
Make gpg signature creation subpacket mandatory
Apr 24, 2019
47a9d9a
gpg/common: warn when expiration subpacket is unhashed
kristelfung Jun 11, 2019
a1c2e3d
Refactor in-toto comments in gpg + process modules
Aug 9, 2019
b0e0d1d
Refactor in_toto.gpg import paths
Aug 9, 2019
5f1c6e9
Add timeout setting and use in process module
Aug 9, 2019
8f92e5a
Add basic string schemas and use in process module
Aug 9, 2019
b19fce3
Add subprocess32 dependency for process module
Aug 9, 2019
9116205
Drop Python 3.4 to support new process module
Aug 9, 2019
e272ce0
Add tests for process module
Aug 9, 2019
54b0ef1
Update process arg test to run over both functions
Aug 9, 2019
1dfa700
Add tests for gpg sub-package
Aug 9, 2019
ec96669
Copy and call in-toto's check_usable_gpg function
Aug 9, 2019
0639e36
Add rsa and dsa test gpg keyrings from in-toto
Aug 9, 2019
8c0e480
Add python-dateutil dependency for gpg sub-package
Aug 9, 2019
c3cf0b4
Exclude unrelated python files from coverage
Aug 9, 2019
a79667a
Add misc gpg test updates
Aug 9, 2019
3d71190
Merge gpg.formats into formats and rename
Aug 12, 2019
a4f434e
Use gpg schemas from formats in gpg subpackage
Aug 12, 2019
5cb71a6
Add minor renames and format fixes in gpg modules
Aug 13, 2019
047f81a
Add gpg documentation
Aug 13, 2019
ad996ea
Fix signing code snippets in documentation
Aug 13, 2019
9906acd
Clarify gpg subpacket comments
Sep 5, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
branch = True

omit =
*/python?.?/*
*/securesystemslib/_vendor/*
*/tests/*
*/site-packages/*
Expand Down
2 changes: 0 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ matrix:
include:
- python: "2.7"
env: TOXENV=py27
- python: "3.4"
env: TOXENV=py34
- python: "3.5"
env: TOXENV=py35
- python: "3.6"
Expand Down
40 changes: 38 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ Library. For key storage, RSA keys may be stored in PEM or JSON format, and
Ed25519 keys in JSON format. Generating, importing, and loading cryptographic
key files can be done with functions available in securesystemslib.

securesystemslib also provides an interface to the `GNU Privacy Guard (GPG)
<https://gnupg.org/>`_ command line tool, with functions to create RSA and DSA
signatures using private keys in a local gpg keychain; to export the
corresponding public keys in a *pythonic* format; and to verify the created
signatures using the exported keys. The latter does not require the gpg command
line tool to be installed, instead the `cryptography` library is used.

Installation
++++++++++++

Expand Down Expand Up @@ -166,7 +173,7 @@ cryptographic operations.

>>> from securesystemslib.keys import *

>>> data = 'The quick brown fox jumps over the lazy dog'
>>> data = b'The quick brown fox jumps over the lazy dog'
>>> ed25519_key = generate_ed25519_key()
>>> signature = create_signature(ed25519_key, data)
>>> rsa_key = generate_rsa_key(2048)
Expand All @@ -182,7 +189,7 @@ Verify ECDSA, Ed25519, and RSA Signatures

# Continuing from the previous sections . . .

>>> data = 'The quick brown fox jumps over the lazy dog'
>>> data = b'The quick brown fox jumps over the lazy dog'
>>> ed25519_key = generate_ed25519_key()
>>> signature = create_signature(ed25519_key, data)
>>> verify_signature(ed25519_key, signature, data)
Expand Down Expand Up @@ -327,3 +334,32 @@ Miscellaneous functions
>>> public_pem = ecdsa_key['keyval']['public']
>>> ecdsa_key2 = import_ecdsakey_from_pem(public_pem)




GnuPG interface
~~~~~~~~~~~~~~~

Signature creation and public key export requires installation of the `gpg` or
`gpg2` command line tool, which may be downloaded from
`https://gnupg.org/download <https://gnupg.org/>`_. It is
is also needed to generate the supported RSA or DSA signing keys (see `gpg` man
pages for detailed instructions). Sample keys are available in a test keyring
at `tests/gpg_keyrings/rsa`, which may be passed to the signing and export
functions using the `homedir` argument (if not passed the default keyring is
used).

::

>>> import securesystemslib.gpg.functions as gpg

>>> data = b"The quick brown fox jumps over the lazy dog"

>>> signing_key_id = "8465A1E2E0FB2B40ADB2478E18FB3F537E0C8A17"
>>> keyring = "tests/gpg_keyrings/rsa"

>>> signature = gpg.create_signature(data, signing_key_id, homedir=keyring)
>>> public_key = gpg.export_pubkey(non_default_signing_key, homedir=keyring)

>>> gpg.verify_signature(signature, public_key, data)
True
2 changes: 2 additions & 0 deletions ci-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ cryptography
pynacl
six
colorama
python-dateutil
subprocess32; python_version < '3'
mock; python_version < '3.3'
# Pin to versions supported by `coveralls` (see .travis.yml)
# https://github.com/coveralls-clients/coveralls-python/releases/tag/1.8.1
Expand Down
2 changes: 2 additions & 0 deletions dev-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,7 @@ coveralls==1.3.0
coverage==4.5.1
colorama==0.3.9
mock==2.0.0; python_version < '3.3'
subprocess32==3.5.4; python_version < '3'
python-dateutil==2.8.0

--editable .
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ cryptography
pynacl
six
colorama
python-dateutil==2.8.0
subprocess32; python_version < '3'
95 changes: 95 additions & 0 deletions securesystemslib/formats.py
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,101 @@
TIMESTAMP_SCHEMA, MIRROR_SCHEMA])


ANY_STRING_SCHEMA = SCHEMA.AnyString()
LIST_OF_ANY_STRING_SCHEMA = SCHEMA.ListOf(ANY_STRING_SCHEMA)

def _create_gpg_pubkey_with_subkey_schema(pubkey_schema):
"""Helper method to extend the passed public key schema with an optional
dictionary of sub public keys "subkeys" with the same schema."""
schema = pubkey_schema
subkey_schema_tuple = ("subkeys", SCHEMA.Optional(
SCHEMA.DictOf(
key_schema=KEYID_SCHEMA,
value_schema=pubkey_schema
)
)
)
# Any subclass of `securesystemslib.schema.Object` stores the schemas that
# define the attributes of the object in its `_required` property, even if
# such a schema is of type `Optional`.
# TODO: Find a way that does not require to access a protected member
schema._required.append(subkey_schema_tuple) # pylint: disable=protected-access
return schema

GPG_HASH_ALGORITHM_STRING = "pgp+SHA2"
GPG_RSA_PUBKEY_METHOD_STRING = "pgp+rsa-pkcsv1.5"
GPG_DSA_PUBKEY_METHOD_STRING = "pgp+dsa-fips-180-2"

GPG_RSA_PUBKEYVAL_SCHEMA = SCHEMA.Object(
object_name = "GPG_RSA_PUBKEYVAL_SCHEMA",
e = SCHEMA.AnyString(),
n = HEX_SCHEMA
)


# We have to define GPG_RSA_PUBKEY_SCHEMA in two steps, because it is
# self-referential. Here we define a shallow _GPG_RSA_PUBKEY_SCHEMA, which we
# use below to create the self-referential GPG_RSA_PUBKEY_SCHEMA.
_GPG_RSA_PUBKEY_SCHEMA = SCHEMA.Object(
object_name = "GPG_RSA_PUBKEY_SCHEMA",
type = SCHEMA.String("rsa"),
method = SCHEMA.String(GPG_RSA_PUBKEY_METHOD_STRING),
hashes = SCHEMA.ListOf(SCHEMA.String(GPG_HASH_ALGORITHM_STRING)),
creation_time = SCHEMA.Optional(UNIX_TIMESTAMP_SCHEMA),
validity_period = SCHEMA.Optional(SCHEMA.Integer(lo=0)),
keyid = KEYID_SCHEMA,
keyval = SCHEMA.Object(
public = GPG_RSA_PUBKEYVAL_SCHEMA,
private = SCHEMA.String("")
)
)
GPG_RSA_PUBKEY_SCHEMA = _create_gpg_pubkey_with_subkey_schema(
_GPG_RSA_PUBKEY_SCHEMA)


GPG_DSA_PUBKEYVAL_SCHEMA = SCHEMA.Object(
object_name = "GPG_DSA_PUBKEYVAL_SCHEMA",
y = HEX_SCHEMA,
p = HEX_SCHEMA,
q = HEX_SCHEMA,
g = HEX_SCHEMA
)


# We have to define GPG_DSA_PUBKEY_SCHEMA in two steps, because it is
# self-referential. Here we define a shallow _GPG_DSA_PUBKEY_SCHEMA, which we
# use below to create the self-referential GPG_DSA_PUBKEY_SCHEMA.
_GPG_DSA_PUBKEY_SCHEMA = SCHEMA.Object(
object_name = "GPG_DSA_PUBKEY_SCHEMA",
type = SCHEMA.String("dsa"),
method = SCHEMA.String(GPG_DSA_PUBKEY_METHOD_STRING),
hashes = SCHEMA.ListOf(SCHEMA.String(GPG_HASH_ALGORITHM_STRING)),
creation_time = SCHEMA.Optional(UNIX_TIMESTAMP_SCHEMA),
validity_period = SCHEMA.Optional(SCHEMA.Integer(lo=0)),
keyid = KEYID_SCHEMA,
keyval = SCHEMA.Object(
public = GPG_DSA_PUBKEYVAL_SCHEMA,
private = SCHEMA.String("")
)
)
GPG_DSA_PUBKEY_SCHEMA = _create_gpg_pubkey_with_subkey_schema(
_GPG_DSA_PUBKEY_SCHEMA)


GPG_PUBKEY_SCHEMA = SCHEMA.OneOf([GPG_RSA_PUBKEY_SCHEMA,
GPG_DSA_PUBKEY_SCHEMA])


GPG_SIGNATURE_SCHEMA = SCHEMA.Object(
object_name = "SIGNATURE_SCHEMA",
keyid = KEYID_SCHEMA,
short_keyid = SCHEMA.Optional(KEYID_SCHEMA),
other_headers = HEX_SCHEMA,
signature = HEX_SCHEMA,
info = SCHEMA.Optional(SCHEMA.Any()),
)



def datetime_to_unix_timestamp(datetime_object):
"""
Expand Down
23 changes: 23 additions & 0 deletions securesystemslib/gpg/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"""
<Module Name>
gpg

<Author>
Santiago Torres-Arias <[email protected]>

<Started>
Nov 15, 2017

<Copyright>
See LICENSE for licensing information.

<Purpose>
This module was written due to the lack of other python (such as pygpg)
modules that can provide an abstraction to the RFC4480 encoded messages from
GPG. The closest candidate we could find was the python bindings for gpgme,
we oped to use a Popen-based python-only construction given that gpgme is
often shipped separately and other popular tools using gpg (e.g., git) don't
use these bindings either. This is because users willing to use gpg signing
are almost guaranteed to have gpg installed, yet the same assumption can't be
made for the gpgme python bindings.
"""
Loading