Skip to content

Commit

Permalink
Merge pull request #206 from joshuagl/joshuagl/issue179-gpg
Browse files Browse the repository at this point in the history
Handle missing native dependencies in securesystemslib.gpg
  • Loading branch information
lukpueh authored Feb 10, 2020
2 parents d07141c + d6c3933 commit 883b82f
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 47 deletions.
4 changes: 4 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ matrix:
env: TOXENV=py27
- python: "2.7"
env: TOXENV=purepy27
before_install:
- sudo apt-get remove -y --allow-remove-essential gnupg gnupg2
- python: "3.5"
env: TOXENV=py35
- python: "3.6"
Expand All @@ -18,6 +20,8 @@ matrix:
env: TOXENV=py38
- python: "3.8"
env: TOXENV=purepy38
before_install:
- sudo apt-get remove -y --allow-remove-essential gnupg gnupg2

install:
- pip install -U tox coveralls
Expand Down
11 changes: 11 additions & 0 deletions securesystemslib/gpg/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
GPG_VERSION_COMMAND = GPG_COMMAND + " --version"
FULLY_SUPPORTED_MIN_VERSION = "2.1.0"

HAVE_GPG = True
NO_GPG_MSG = "GPG support requires a GPG command, {} version {} or newer is" \
" fully supported.".format(GPG_COMMAND, FULLY_SUPPORTED_MIN_VERSION)

try:
proc = process.run(GPG_VERSION_COMMAND, stdout=process.PIPE,
stderr=process.PIPE)
Expand All @@ -39,6 +43,13 @@
GPG_COMMAND = "gpg"
GPG_VERSION_COMMAND = GPG_COMMAND + " --version"

try:
proc = process.run(GPG_VERSION_COMMAND, stdout=process.PIPE,
stderr=process.PIPE)

except OSError:
HAVE_GPG = False

GPG_SIGN_COMMAND = GPG_COMMAND + \
" --detach-sign --digest-algo SHA256 {keyarg} {homearg}"
GPG_EXPORT_PUBKEY_COMMAND = GPG_COMMAND + " {homearg} --export {keyid}"
Expand Down
34 changes: 29 additions & 5 deletions securesystemslib/gpg/dsa.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,22 @@
"""
import binascii

import cryptography.hazmat.primitives.asymmetric.dsa as dsa
import cryptography.hazmat.backends as backends
import cryptography.hazmat.primitives.asymmetric.utils as dsautils
import cryptography.exceptions
CRYPTO = True
NO_CRYPTO_MSG = 'DSA key support for GPG requires the cryptography library'
try:
import cryptography.hazmat.primitives.asymmetric.dsa as dsa
import cryptography.hazmat.backends as backends
import cryptography.hazmat.primitives.asymmetric.utils as dsautils
import cryptography.exceptions
except ImportError:
CRYPTO = False

import securesystemslib.gpg.util
import securesystemslib.gpg.exceptions

import securesystemslib.exceptions
import securesystemslib.formats


def create_pubkey(pubkey_info):
"""
<Purpose>
Expand All @@ -41,11 +47,17 @@ def create_pubkey(pubkey_info):
securesystemslib.exceptions.FormatError if
pubkey_info does not match securesystemslib.formats.GPG_DSA_PUBKEY_SCHEMA
securesystemslib.exceptions.UnsupportedLibraryError if
the cryptography module is not available
<Returns>
A cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey based on the
passed pubkey_info.
"""
if not CRYPTO: # pragma: no cover
raise securesystemslib.exceptions.UnsupportedLibraryError(NO_CRYPTO_MSG)

securesystemslib.formats.GPG_DSA_PUBKEY_SCHEMA.check_match(pubkey_info)

y = int(pubkey_info['keyval']['public']['y'], 16)
Expand Down Expand Up @@ -138,12 +150,18 @@ def get_signature_params(data):
securesystemslib.gpg.exceptions.PacketParsingError:
if the public key parameters are malformed
securesystemslib.exceptions.UnsupportedLibraryError:
if the cryptography module is not available
<Side Effects>
None.
<Returns>
The decoded signature buffer
"""
if not CRYPTO: # pragma: no cover
return securesystemslib.exceptions.UnsupportedLibraryError(NO_CRYPTO_MSG)

ptr = 0
r_length = securesystemslib.gpg.util.get_mpi_length(data[ptr:ptr+2])
ptr += 2
Expand Down Expand Up @@ -198,6 +216,9 @@ def verify_signature(signature_object, pubkey_info, content,
signature_object does not match securesystemslib.formats.GPG_SIGNATURE_SCHEMA
pubkey_info does not match securesystemslib.formats.GPG_DSA_PUBKEY_SCHEMA
securesystemslib.exceptions.UnsupportedLibraryError if:
the cryptography module is not available
ValueError:
if the passed hash_algorithm_id is not supported (see
securesystemslib.gpg.util.get_hashing_class)
Expand All @@ -206,6 +227,9 @@ def verify_signature(signature_object, pubkey_info, content,
True if signature verification passes and False otherwise
"""
if not CRYPTO: # pragma: no cover
raise securesystemslib.exceptions.UnsupportedLibraryError(NO_CRYPTO_MSG)

securesystemslib.formats.GPG_SIGNATURE_SCHEMA.check_match(signature_object)
securesystemslib.formats.GPG_DSA_PUBKEY_SCHEMA.check_match(pubkey_info)

Expand Down
29 changes: 24 additions & 5 deletions securesystemslib/gpg/eddsa.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,19 @@
"""
import binascii
import struct
import securesystemslib.exceptions
import securesystemslib.gpg.util
import cryptography.hazmat.primitives.asymmetric.utils as pyca_utils
import cryptography.hazmat.primitives.asymmetric.ed25519 as pyca_ed25519
import cryptography.hazmat.backends as pyca_backends
import cryptography.hazmat.primitives.hashes as pyca_hashing
import cryptography.exceptions

CRYPTO = True
NO_CRYPTO_MSG = 'EdDSA key support for GPG requires the cryptography library'
try:
import cryptography.hazmat.primitives.asymmetric.utils as pyca_utils
import cryptography.hazmat.primitives.asymmetric.ed25519 as pyca_ed25519
import cryptography.hazmat.backends as pyca_backends
import cryptography.hazmat.primitives.hashes as pyca_hashing
import cryptography.exceptions
except ImportError:
CRYPTO = False

# ECC Curve OID (see RFC4880-bis8 9.2.)
ED25519_PUBLIC_KEY_OID = bytearray.fromhex("2B 06 01 04 01 DA 47 0F 01")
Expand Down Expand Up @@ -153,11 +160,17 @@ def create_pubkey(pubkey_info):
securesystemslib.exceptions.FormatError if
pubkey_info does not match securesystemslib.formats.GPG_DSA_PUBKEY_SCHEMA
securesystemslib.exceptions.UnsupportedLibraryError if
the cryptography module is unavailable
<Returns>
A cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PublicKey based
on the passed pubkey_info.
"""
if not CRYPTO: # pragma: no cover
raise securesystemslib.exceptions.UnsupportedLibraryError(NO_CRYPTO_MSG)

securesystemslib.formats.GPG_ED25519_PUBKEY_SCHEMA.check_match(pubkey_info)

public_bytes = binascii.unhexlify(pubkey_info["keyval"]["public"]["q"])
Expand Down Expand Up @@ -197,6 +210,9 @@ def verify_signature(signature_object, pubkey_info, content,
signature_object does not match securesystemslib.formats.GPG_SIGNATURE_SCHEMA
pubkey_info does not match securesystemslib.formats.GPG_ED25519_PUBKEY_SCHEMA
securesystemslib.exceptions.UnsupportedLibraryError if:
the cryptography module is unavailable
ValueError:
if the passed hash_algorithm_id is not supported (see
securesystemslib.gpg.util.get_hashing_class)
Expand All @@ -205,6 +221,9 @@ def verify_signature(signature_object, pubkey_info, content,
True if signature verification passes and False otherwise.
"""
if not CRYPTO: # pragma: no cover
raise securesystemslib.exceptions.UnsupportedLibraryError(NO_CRYPTO_MSG)

securesystemslib.formats.GPG_SIGNATURE_SCHEMA.check_match(signature_object)
securesystemslib.formats.GPG_ED25519_PUBKEY_SCHEMA.check_match(pubkey_info)

Expand Down
22 changes: 21 additions & 1 deletion securesystemslib/gpg/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
import logging
import time

import securesystemslib.exceptions
import securesystemslib.gpg.common
import securesystemslib.gpg.exceptions
from securesystemslib.gpg.constants import (GPG_EXPORT_PUBKEY_COMMAND,
GPG_SIGN_COMMAND, SIGNATURE_HANDLERS, FULLY_SUPPORTED_MIN_VERSION, SHA256)
GPG_SIGN_COMMAND, SIGNATURE_HANDLERS, FULLY_SUPPORTED_MIN_VERSION, SHA256,
HAVE_GPG, NO_GPG_MSG)

import securesystemslib.process
import securesystemslib.formats
Expand Down Expand Up @@ -66,6 +68,9 @@ def create_signature(content, keyid=None, homedir=None):
OSError:
If the gpg command is not present or non-executable.
securesystemslib.exceptions.UnsupportedLibraryError:
If the gpg command is not available
securesystemslib.gpg.exceptions.CommandError:
If the gpg command returned a non-zero exit code
Expand All @@ -81,6 +86,9 @@ def create_signature(content, keyid=None, homedir=None):
securesystemslib.formats.GPG_SIGNATURE_SCHEMA.
"""
if not HAVE_GPG: # pragma: no cover
raise securesystemslib.exceptions.UnsupportedLibraryError(NO_GPG_MSG)

keyarg = ""
if keyid:
securesystemslib.formats.KEYID_SCHEMA.check_match(keyid)
Expand Down Expand Up @@ -177,13 +185,19 @@ def verify_signature(signature_object, pubkey_info, content):
securesystemslib.gpg.exceptions.KeyExpirationError:
if the passed public key has expired
securesystemslib.exceptions.UnsupportedLibraryError:
If the gpg command is not available
<Side Effects>
None.
<Returns>
True if signature verification passes, False otherwise.
"""
if not HAVE_GPG: # pragma: no cover
raise securesystemslib.exceptions.UnsupportedLibraryError(NO_GPG_MSG)

securesystemslib.formats.GPG_PUBKEY_SCHEMA.check_match(pubkey_info)
securesystemslib.formats.GPG_SIGNATURE_SCHEMA.check_match(signature_object)

Expand Down Expand Up @@ -233,6 +247,9 @@ def export_pubkey(keyid, homedir=None):
ValueError:
if the keyid does not match the required format.
securesystemslib.exceptions.UnsupportedLibraryError:
If the gpg command is not available.
securesystemslib.gpg.execeptions.KeyNotFoundError:
if no key or subkey was found for that keyid.
Expand All @@ -245,6 +262,9 @@ def export_pubkey(keyid, homedir=None):
securesystemslib.formats.GPG_PUBKEY_SCHEMA.
"""
if not HAVE_GPG: # pragma: no cover
raise securesystemslib.exceptions.UnsupportedLibraryError(NO_GPG_MSG)

if not securesystemslib.formats.KEYID_SCHEMA.matches(keyid):
# FIXME: probably needs smarter parsing of what a valid keyid is so as to
# not export more than one pubkey packet.
Expand Down
28 changes: 23 additions & 5 deletions securesystemslib/gpg/rsa.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,20 @@
"""
import binascii

import cryptography.hazmat.primitives.asymmetric.rsa as rsa
import cryptography.hazmat.backends as backends
import cryptography.hazmat.primitives.asymmetric.padding as padding
import cryptography.hazmat.primitives.asymmetric.utils as utils
import cryptography.exceptions
CRYPTO = True
NO_CRYPTO_MSG = 'RSA key support for GPG requires the cryptography library'
try:
import cryptography.hazmat.primitives.asymmetric.rsa as rsa
import cryptography.hazmat.backends as backends
import cryptography.hazmat.primitives.asymmetric.padding as padding
import cryptography.hazmat.primitives.asymmetric.utils as utils
import cryptography.exceptions
except ImportError:
CRYPTO = False

import securesystemslib.gpg.util
import securesystemslib.gpg.exceptions
import securesystemslib.exceptions
import securesystemslib.formats


Expand All @@ -42,11 +48,17 @@ def create_pubkey(pubkey_info):
securesystemslib.exceptions.FormatError if
pubkey_info does not match securesystemslib.formats.GPG_RSA_PUBKEY_SCHEMA
securesystemslib.exceptions.UnsupportedLibraryError if
the cryptography module is unavailable
<Returns>
A cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey based on the
passed pubkey_info.
"""
if not CRYPTO: # pragma: no cover
raise securesystemslib.exceptions.UnsupportedLibraryError(NO_CRYPTO_MSG)

securesystemslib.formats.GPG_RSA_PUBKEY_SCHEMA.check_match(pubkey_info)

e = int(pubkey_info['keyval']['public']['e'], 16)
Expand Down Expand Up @@ -165,6 +177,9 @@ def verify_signature(signature_object, pubkey_info, content,
securesystemslib.formats.GPG_SIGNATURE_SCHEMA,
pubkey_info does not match securesystemslib.formats.GPG_RSA_PUBKEY_SCHEMA
securesystemslib.exceptions.UnsupportedLibraryError if:
the cryptography module is unavailable
ValueError:
if the passed hash_algorithm_id is not supported (see
securesystemslib.gpg.util.get_hashing_class)
Expand All @@ -173,6 +188,9 @@ def verify_signature(signature_object, pubkey_info, content,
True if signature verification passes and False otherwise
"""
if not CRYPTO: # pragma: no cover
raise securesystemslib.exceptions.UnsupportedLibraryError(NO_CRYPTO_MSG)

securesystemslib.formats.GPG_SIGNATURE_SCHEMA.check_match(signature_object)
securesystemslib.formats.GPG_RSA_PUBKEY_SCHEMA.check_match(pubkey_info)

Expand Down
Loading

0 comments on commit 883b82f

Please sign in to comment.