mirror of
https://github.com/moepman/acertmgr.git
synced 2024-12-29 09:21:51 +01:00
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:
parent
1f5ef9322b
commit
4df74d67d5
@ -12,7 +12,7 @@ Requirements
|
|||||||
------------
|
------------
|
||||||
|
|
||||||
* Python (2.7+ and 3.5+ should work)
|
* 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)
|
Optional packages (required to use specified features)
|
||||||
------------------------------------------------------
|
------------------------------------------------------
|
||||||
@ -21,7 +21,7 @@ Optional packages (required to use specified features)
|
|||||||
* dnspython: used by dns.* challenge handlers
|
* dnspython: used by dns.* challenge handlers
|
||||||
* idna: to allow automatic conversion of unicode domain names to their IDNA2008 counterparts
|
* 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)
|
* cryptography>=2.1: for creating certificates with the OCSP must-staple flag (cert_must_staple)
|
||||||
|
|
||||||
Setup
|
Setup
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
@ -17,8 +17,10 @@ import traceback
|
|||||||
from cryptography import x509
|
from cryptography import x509
|
||||||
from cryptography.hazmat.backends import default_backend
|
from cryptography.hazmat.backends import default_backend
|
||||||
from cryptography.hazmat.primitives import hashes, serialization
|
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.x509.oid import NameOID, ExtensionOID
|
||||||
|
from cryptography.utils import int_to_bytes
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from urllib.request import urlopen, Request # Python 3
|
from urllib.request import urlopen, Request # Python 3
|
||||||
@ -241,6 +243,24 @@ def get_key_alg_and_jwk(key):
|
|||||||
return "RS256", {"kty": "RSA",
|
return "RS256", {"kty": "RSA",
|
||||||
"e": bytes_to_base64url(number_to_byte_format(numbers.e)),
|
"e": bytes_to_base64url(number_to_byte_format(numbers.e)),
|
||||||
"n": bytes_to_base64url(number_to_byte_format(numbers.n))}
|
"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:
|
else:
|
||||||
raise ValueError("Unsupported key: {}".format(key))
|
raise ValueError("Unsupported key: {}".format(key))
|
||||||
|
|
||||||
@ -251,6 +271,19 @@ def signature_of_str(key, string):
|
|||||||
data = string.encode('utf8')
|
data = string.encode('utf8')
|
||||||
if alg == 'RS256':
|
if alg == 'RS256':
|
||||||
return key.sign(data, padding.PKCS1v15(), hashes.SHA256())
|
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:
|
else:
|
||||||
raise ValueError("Unsupported signature algorithm: {}".format(alg))
|
raise ValueError("Unsupported signature algorithm: {}".format(alg))
|
||||||
|
|
||||||
|
@ -6,11 +6,11 @@ pkgdesc='An automated certificate manager using ACME/letsencrypt'
|
|||||||
arch=('any')
|
arch=('any')
|
||||||
url='https://github.com/moepman/acertmgr'
|
url='https://github.com/moepman/acertmgr'
|
||||||
license=('ISC')
|
license=('ISC')
|
||||||
depends=('python-cryptography')
|
depends=('python-cryptography>=0.6')
|
||||||
optdepends=('python-yaml: Support config files in YAML format'
|
optdepends=('python-yaml: Support config files in YAML format'
|
||||||
'python-idna: Support conversion of unicode domains'
|
'python-idna: Support conversion of unicode domains'
|
||||||
'python-dnspython: Support for dns challenge handlers'
|
'python-dnspython: Support for dns challenge handlers'
|
||||||
'python-cryptography>=2.1: Support for the OCSP must-staple flag'
|
'python-cryptography>=2.1: Support for the OCSP must-staple flag'
|
||||||
)
|
)
|
||||||
makedepends=('git')
|
makedepends=('git')
|
||||||
conflicts=('python-acertmgr')
|
conflicts=('python-acertmgr')
|
||||||
|
@ -6,11 +6,11 @@ pkgdesc='An automated certificate manager using ACME/letsencrypt'
|
|||||||
arch=('any')
|
arch=('any')
|
||||||
url='https://github.com/moepman/acertmgr'
|
url='https://github.com/moepman/acertmgr'
|
||||||
license=('ISC')
|
license=('ISC')
|
||||||
depends=('python2-cryptography')
|
depends=('python2-cryptography>=0.6')
|
||||||
optdepends=('python2-yaml: Support config files in YAML format'
|
optdepends=('python2-yaml: Support config files in YAML format'
|
||||||
'python2-idna: Support conversion of unicode domains'
|
'python2-idna: Support conversion of unicode domains'
|
||||||
'python2-dnspython: Support for dns challenge handlers'
|
'python2-dnspython: Support for dns challenge handlers'
|
||||||
'python2-cryptography>=2.1: Support for the OCSP must-staple flag'
|
'python2-cryptography>=2.1: Support for the OCSP must-staple flag'
|
||||||
)
|
)
|
||||||
makedepends=('git')
|
makedepends=('git')
|
||||||
conflicts=('python-acertmgr')
|
conflicts=('python-acertmgr')
|
||||||
|
5
setup.py
5
setup.py
@ -65,7 +65,7 @@ setup(
|
|||||||
"License :: OSI Approved :: ISC License",
|
"License :: OSI Approved :: ISC License",
|
||||||
],
|
],
|
||||||
install_requires=[
|
install_requires=[
|
||||||
"cryptography",
|
"cryptography>=0.6",
|
||||||
],
|
],
|
||||||
extras_require={
|
extras_require={
|
||||||
"dns": [
|
"dns": [
|
||||||
@ -80,6 +80,9 @@ setup(
|
|||||||
"ocsp-must-staple": [
|
"ocsp-must-staple": [
|
||||||
"cryptography>=2.1",
|
"cryptography>=2.1",
|
||||||
],
|
],
|
||||||
|
"ed25519": [
|
||||||
|
"cryptography>=2.6",
|
||||||
|
],
|
||||||
},
|
},
|
||||||
entry_points={
|
entry_points={
|
||||||
'console_scripts': [
|
'console_scripts': [
|
||||||
|
Loading…
Reference in New Issue
Block a user