Full elliptic curve support
veeti opened this issue · comments
Veeti Paananen commented
Allow creation of certificates and accounts (if supported?) using EC keys. Also allow the user to specify the curve.
(Pull requests welcome!)
Viktor Szépe commented
@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
Viktor Szépe commented
Yes it is:
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
*
ASN1 OID: prime256v1
NIST CURVE: P-256
Veeti Paananen commented
Yes, you can already bring your own EC key. This issue is for generating EC keys through the client.
Xiangsong Zeng commented
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:someone@example.com']}
r = requests.post(urls['new-reg'], json=sign_request(header, protected, payload, pkey))
print(r.json())
Xiangsong Zeng commented
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
.