Commit e4a7c409 authored by Simo Sorce's avatar Simo Sorce

Generate a JWK from a cryptography (pyca) key

If the key in input is a known python crypography key type then a
corresponding JWK set is generated from that key.
Signed-off-by: default avatarSimo Sorce <simo@redhat.com>
Reviewed-by: default avatarNathaniel McCallum <npmccallum@redhat.com>
Closes #34
Closes #35
parent e5c4cbb1
......@@ -72,6 +72,10 @@ JWKOperationsRegistry = {'sign': 'Compute digital Signature or MAC',
'deriveBits': 'Derive bits not to be used as a key'}
"""Registry of allowed operations"""
JWKpycaCurveMap = {'secp256r1': 'P-256',
'secp384r1': 'P-384',
'secp521r1': 'P-521'}
class InvalidJWKType(Exception):
"""Invalid JWK Type Exception.
......@@ -243,8 +247,11 @@ class JWK(object):
size = params['size']
del params['size']
key = rsa.generate_private_key(pubexp, size, default_backend())
self._import_pyca_pri_rsa(key)
def _import_pyca_pri_rsa(self, key):
pn = key.private_numbers()
params['kty'] = 'RSA'
params = {'kty': 'RSA'}
params['n'] = self._encode_int(pn.public_numbers.n)
params['e'] = self._encode_int(pn.public_numbers.e)
params['d'] = self._encode_int(pn.d)
......@@ -255,6 +262,13 @@ class JWK(object):
params['qi'] = self._encode_int(pn.iqmp)
self.import_key(**params)
def _import_pyca_pub_rsa(self, key):
pn = key.public_numbers()
params = {'kty': 'RSA'}
params['n'] = self._encode_int(pn.n)
params['e'] = self._encode_int(pn.e)
self.import_key(**params)
def _get_curve_by_name(self, name):
if name == 'P-256':
return ec.SECP256R1()
......@@ -277,14 +291,25 @@ class JWK(object):
del params['crv']
curve_name = self._get_curve_by_name(curve)
key = ec.generate_private_key(curve_name, default_backend())
self._import_pyca_pri_ec(key)
def _import_pyca_pri_ec(self, key):
pn = key.private_numbers()
params['kty'] = 'EC'
params['crv'] = curve
params = {'kty': 'EC'}
params['crv'] = JWKpycaCurveMap[key.curve.name]
params['x'] = self._encode_int(pn.public_numbers.x)
params['y'] = self._encode_int(pn.public_numbers.y)
params['d'] = self._encode_int(pn.private_value)
self.import_key(**params)
def _import_pyca_pub_ec(self, key):
pn = key.public_numbers()
params = {'kty': 'EC'}
params['crv'] = JWKpycaCurveMap[key.curve.name]
params['x'] = self._encode_int(pn.x)
params['y'] = self._encode_int(pn.y)
self.import_key(**params)
def import_key(self, **kwargs):
names = list(kwargs.keys())
......@@ -496,6 +521,24 @@ class JWK(object):
else:
raise NotImplementedError
def import_from_pyca(self, key):
if isinstance(key, rsa.RSAPrivateKey):
self._import_pyca_pri_rsa(key)
elif isinstance(key, rsa.RSAPublicKey):
self._import_pyca_pub_rsa(key)
elif isinstance(key, ec.EllipticCurvePrivateKey):
self._import_pyca_pri_ec(key)
elif isinstance(key, ec.EllipticCurvePublicKey):
self._import_pyca_pub_ec(key)
else:
raise InvalidJWKValue('Unknown key object %r' % key)
@classmethod
def from_pyca(cls, key):
obj = cls()
obj.import_from_pyca(key)
return obj
class _jwkset(set):
......
......@@ -2,6 +2,9 @@
from __future__ import unicode_literals
import copy
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives.asymmetric import ec
from jwcrypto.common import base64url_decode, base64url_encode
from jwcrypto.common import json_decode, json_encode
from jwcrypto import jwk
......@@ -216,6 +219,22 @@ class TestJWK(unittest.TestCase):
key = jwk.JWK.generate(kty='EC', curve='P-256', crv='P-521')
key.get_curve('P-521')
def test_import_pyca_keys(self):
rsa1 = rsa.generate_private_key(65537, 1024, default_backend())
krsa1 = jwk.JWK.from_pyca(rsa1)
self.assertEqual(krsa1.key_type, 'RSA')
krsa2 = jwk.JWK.from_pyca(rsa1.public_key())
self.assertEqual(krsa1.get_op_key('verify').public_numbers().n,
krsa2.get_op_key('verify').public_numbers().n)
ec1 = ec.generate_private_key(ec.SECP256R1(), default_backend())
kec1 = jwk.JWK.from_pyca(ec1)
self.assertEqual(kec1.key_type, 'EC')
kec2 = jwk.JWK.from_pyca(ec1.public_key())
self.assertEqual(kec1.get_op_key('verify').public_numbers().x,
kec2.get_op_key('verify').public_numbers().x)
self.assertRaises(jwk.InvalidJWKValue,
jwk.JWK.from_pyca, dict())
def test_jwkset(self):
k = jwk.JWK(**RSAPrivateKey)
ks = jwk.JWKSet()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment