tools: add support for EC account keys

Allows usage of pre-generated EC account keys (P-256, P-384, P-521)
in addition to already supported RSA keys.
This commit is contained in:
Kishi85 2019-04-05 21:27:32 +02:00
parent 1f5ef9322b
commit 4df74d67d5
5 changed files with 46 additions and 10 deletions

View File

@ -12,7 +12,7 @@ Requirements
------------
* Python (2.7+ and 3.5+ should work)
* cryptography (includes the optional idna module)
* cryptography>=0.6 (includes the optional idna module)
Optional packages (required to use specified features)
------------------------------------------------------
@ -21,7 +21,7 @@ Optional packages (required to use specified features)
* dnspython: used by dns.* challenge handlers
* idna: to allow automatic conversion of unicode domain names to their IDNA2008 counterparts
* cryptography>=2.1: for creating certificates with the OCSP must-staple flag (cert_must_staple)
Setup
-----

View File

@ -17,8 +17,10 @@ import traceback
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives.asymmetric import rsa, ec, padding
from cryptography.hazmat.primitives.asymmetric.utils import decode_dss_signature
from cryptography.x509.oid import NameOID, ExtensionOID
from cryptography.utils import int_to_bytes
try:
from urllib.request import urlopen, Request # Python 3
@ -241,6 +243,24 @@ def get_key_alg_and_jwk(key):
return "RS256", {"kty": "RSA",
"e": bytes_to_base64url(number_to_byte_format(numbers.e)),
"n": bytes_to_base64url(number_to_byte_format(numbers.n))}
elif isinstance(key, ec.EllipticCurvePrivateKey):
# See https://tools.ietf.org/html/rfc7518#section-6.2
numbers = key.public_key().public_numbers()
if isinstance(numbers.curve, ec.SECP256R1):
alg = 'ES256'
crv = 'P-256'
elif isinstance(numbers.curve, ec.SECP384R1):
alg = 'ES384'
crv = 'P-384'
elif isinstance(numbers.curve, ec.SECP521R1):
alg = 'ES512'
crv = 'P-521'
else:
raise ValueError("Unsupported EC curve in key: {}".format(key))
full_octets = (int(crv[2:]) + 7) // 8
return alg, {"kty": "EC", "crv": crv,
"x": bytes_to_base64url(int_to_bytes(numbers.x, full_octets)),
"y": bytes_to_base64url(int_to_bytes(numbers.y, full_octets))}
else:
raise ValueError("Unsupported key: {}".format(key))
@ -251,6 +271,19 @@ def signature_of_str(key, string):
data = string.encode('utf8')
if alg == 'RS256':
return key.sign(data, padding.PKCS1v15(), hashes.SHA256())
elif alg.startswith('ES'):
full_octets = (int(alg[2:]) + 7) // 8
if alg == 'ES256':
der_sig = key.sign(data, ec.ECDSA(hashes.SHA256()))
elif alg == 'ES384':
der_sig = key.sign(data, ec.ECDSA(hashes.SHA384()))
elif alg == 'ES512':
der_sig = key.sign(data, ec.ECDSA(hashes.SHA512()))
else:
raise ValueError("Unsupported EC signature algorithm: {}".format(alg))
# convert DER signature to RAW format (https://tools.ietf.org/html/rfc7518#section-3.4)
r, s = decode_dss_signature(der_sig)
return int_to_bytes(r, full_octets) + int_to_bytes(s, full_octets)
else:
raise ValueError("Unsupported signature algorithm: {}".format(alg))

View File

@ -6,11 +6,11 @@ pkgdesc='An automated certificate manager using ACME/letsencrypt'
arch=('any')
url='https://github.com/moepman/acertmgr'
license=('ISC')
depends=('python-cryptography')
depends=('python-cryptography>=0.6')
optdepends=('python-yaml: Support config files in YAML format'
'python-idna: Support conversion of unicode domains'
'python-dnspython: Support for dns challenge handlers'
'python-cryptography>=2.1: Support for the OCSP must-staple flag'
'python-dnspython: Support for dns challenge handlers'
'python-cryptography>=2.1: Support for the OCSP must-staple flag'
)
makedepends=('git')
conflicts=('python-acertmgr')

View File

@ -6,11 +6,11 @@ pkgdesc='An automated certificate manager using ACME/letsencrypt'
arch=('any')
url='https://github.com/moepman/acertmgr'
license=('ISC')
depends=('python2-cryptography')
depends=('python2-cryptography>=0.6')
optdepends=('python2-yaml: Support config files in YAML format'
'python2-idna: Support conversion of unicode domains'
'python2-dnspython: Support for dns challenge handlers'
'python2-cryptography>=2.1: Support for the OCSP must-staple flag'
'python2-dnspython: Support for dns challenge handlers'
'python2-cryptography>=2.1: Support for the OCSP must-staple flag'
)
makedepends=('git')
conflicts=('python-acertmgr')

View File

@ -65,7 +65,7 @@ setup(
"License :: OSI Approved :: ISC License",
],
install_requires=[
"cryptography",
"cryptography>=0.6",
],
extras_require={
"dns": [
@ -80,6 +80,9 @@ setup(
"ocsp-must-staple": [
"cryptography>=2.1",
],
"ed25519": [
"cryptography>=2.6",
],
},
entry_points={
'console_scripts': [