manuale
manuale copied to clipboard
Full elliptic curve support
Allow creation of certificates and accounts (if supported?) using EC keys. Also allow the user to specify the curve.
(Pull requests welcome!)
@veeti It turned out - for me at least - SSL handshake is faster on EC keys.
Is it possible that existing EC private keys are accepted by manuale? https://github.com/veeti/manuale/blob/master/manuale/crypto.py#L92-L98
Yes it is:
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
*
ASN1 OID: prime256v1
NIST CURVE: P-256
Yes, you can already bring your own EC key. This issue is for generating EC keys through the client.
Maybe we can make account using EC key through this way?
import copy
import json
import requests
# PyJWT
from jwt.algorithms import get_default_algorithms
from jwt.utils import base64url_encode, to_base64url_uint, force_bytes
# cryptography
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import ec
# generate ec key
pkey = ec.generate_private_key(curve=ec.SECP384R1(), backend=default_backend())
# get nonce & acme directory
r = requests.get('https://acme-staging.api.letsencrypt.org/directory')
nonce = r.headers['Replay-Nonce']
urls = r.json()
def sign_request(header, protected, payload, key, algorithm='ES384'):
"""JWS Sign Request"""
protected = base64url_encode(force_bytes(json.dumps(protected)))
payload = base64url_encode(force_bytes(json.dumps(payload)))
try:
alg_obj = get_default_algorithms()[algorithm]
key = alg_obj.prepare_key(key)
signing_input = b'.'.join((protected, payload))
signature = alg_obj.sign(signing_input, key)
except KeyError:
raise NotImplementedError('Algorithm not supported')
return {
'header': header,
'protected': protected.decode('ascii'),
'payload': payload.decode('ascii'),
'signature': base64url_encode(signature).decode('ascii'),
}
header = {
"alg": "ES384",
"jwk": {
"kty": "EC",
"crv": {
'secp256r1': 'P-256',
'secp384r1': 'P-384',
}[pkey.public_key().curve.name],
"x": to_base64url_uint(pkey.public_key().public_numbers().x).decode('ascii'),
"y": to_base64url_uint(pkey.public_key().public_numbers().y).decode('ascii'),
}
}
protected = copy.deepcopy(header)
protected['nonce'] = nonce
payload = {'resource':'new-reg', 'contact':['mailto:[email protected]']}
r = requests.post(urls['new-reg'], json=sign_request(header, protected, payload, pkey))
print(r.json())
Let's Encrypt only support curve P-256
and P-384
, and curve P-256
must signed with ES256
, P-384
must signed with ES384
.