Hello community,
here is the log from the commit of package python-jwcrypto for openSUSE:Factory
checked in at 2020-09-09 17:48:09
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-jwcrypto (Old)
and /work/SRC/openSUSE:Factory/.python-jwcrypto.new.3399 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-jwcrypto"
Wed Sep 9 17:48:09 2020 rev:9 rq:832630 version:0.8
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-jwcrypto/python-jwcrypto.changes
2020-04-19 21:48:06.111916093 +0200
+++
/work/SRC/openSUSE:Factory/.python-jwcrypto.new.3399/python-jwcrypto.changes
2020-09-09 17:48:54.806522676 +0200
@@ -1,0 +2,17 @@
+Sun Sep 6 19:25:26 UTC 2020 - Tomáš Chvátal <[email protected]>
+
+- Use constraints on the cryptography dependency
+
+-------------------------------------------------------------------
+Sun Sep 6 14:51:40 UTC 2020 - Michael Ströder <[email protected]>
+
+- update to upstream release 0.8
+ * Fix some documentation typos
+ * Rename ambiguous variable
+ * Remove cap on sphinx version
+ * Fix okp key type import
+ * Add method to export Keys ans Sets as dictionaries
+ * Typo rectified
+ * Add secp256k1 curve
+
+-------------------------------------------------------------------
Old:
----
jwcrypto-0.7.tar.gz
New:
----
jwcrypto-0.8.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-jwcrypto.spec ++++++
--- /var/tmp/diff_new_pack.6SMsld/_old 2020-09-09 17:48:57.482524850 +0200
+++ /var/tmp/diff_new_pack.6SMsld/_new 2020-09-09 17:48:57.486524854 +0200
@@ -1,7 +1,7 @@
#
# spec file for package python-jwcrypto
#
-# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2020 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -18,19 +18,18 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-jwcrypto
-Version: 0.7
+Version: 0.8
Release: 0
Summary: Python module package implementing JOSE Web standards
License: LGPL-3.0-only
-Group: Development/Languages/Python
URL: https://github.com/latchset/jwcrypto
Source:
https://files.pythonhosted.org/packages/source/j/jwcrypto/jwcrypto-%{version}.tar.gz
-BuildRequires: %{python_module cryptography}
+BuildRequires: %{python_module cryptography >= 2.3}
BuildRequires: %{python_module pytest-runner}
BuildRequires: %{python_module setuptools}
BuildRequires: fdupes
BuildRequires: python-rpm-macros
-Requires: python-cryptography
+Requires: python-cryptography >= 2.3
BuildArch: noarch
%python_subpackages
@@ -55,7 +54,7 @@
%python_expand %fdupes %{buildroot}%{$python_sitelib}
%check
-%python_expand py.test-%{$python_bin_suffix} jwcrypto
+%pytest jwcrypto
%files %{python_files}
%{python_sitelib}/*
++++++ jwcrypto-0.7.tar.gz -> jwcrypto-0.8.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.7/PKG-INFO new/jwcrypto-0.8/PKG-INFO
--- old/jwcrypto-0.7/PKG-INFO 2020-02-19 18:17:34.000000000 +0100
+++ new/jwcrypto-0.8/PKG-INFO 2020-08-20 12:48:07.538233500 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 1.2
Name: jwcrypto
-Version: 0.7
+Version: 0.8
Summary: Implementation of JOSE Web standards
Home-page: https://github.com/latchset/jwcrypto
Maintainer: JWCrypto Project Contributors
@@ -13,6 +13,7 @@
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
Classifier: Intended Audience :: Developers
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Libraries :: Python Modules
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.7/README.md new/jwcrypto-0.8/README.md
--- old/jwcrypto-0.7/README.md 2018-06-27 08:24:18.000000000 +0200
+++ new/jwcrypto-0.8/README.md 2020-08-20 12:47:47.000000000 +0200
@@ -4,13 +4,13 @@
========
An implementation of the JOSE Working Group documents:
-RFC 7515 - JSON Web Signature (JWS)
-RFC 7516 - JSON Web Encryption (JWE)
-RFC 7517 - JSON Web Key (JWK)
-RFC 7518 - JSON Web Algorithms (JWA)
-RFC 7519 - JSON Web Token (JWT)
-RFC 7520 - Examples of Protecting Content Using JSON Object Signing and
-Encryption (JOSE)
+- RFC 7515 - JSON Web Signature (JWS)
+- RFC 7516 - JSON Web Encryption (JWE)
+- RFC 7517 - JSON Web Key (JWK)
+- RFC 7518 - JSON Web Algorithms (JWA)
+- RFC 7519 - JSON Web Token (JWT)
+- RFC 7520 - Examples of Protecting Content Using JSON Object Signing and
+ Encryption (JOSE)
Documentation
=============
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.7/jwcrypto/common.py
new/jwcrypto-0.8/jwcrypto/common.py
--- old/jwcrypto-0.7/jwcrypto/common.py 2020-02-19 17:12:20.000000000 +0100
+++ new/jwcrypto-0.8/jwcrypto/common.py 2020-08-20 12:47:47.000000000 +0200
@@ -91,7 +91,7 @@
"""Invalid JWE Key Type.
This exception is raised when the provided JWK Key does not match
- the type required by the sepcified algorithm.
+ the type required by the specified algorithm.
"""
def __init__(self, expected, obtained):
@@ -103,7 +103,7 @@
"""Invalid JWE Key Length.
This exception is raised when the provided JWK Key does not match
- the length required by the sepcified algorithm.
+ the length required by the specified algorithm.
"""
def __init__(self, expected, obtained):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.7/jwcrypto/jwa.py
new/jwcrypto-0.8/jwcrypto/jwa.py
--- old/jwcrypto-0.7/jwcrypto/jwa.py 2020-02-19 17:12:20.000000000 +0100
+++ new/jwcrypto-0.8/jwcrypto/jwa.py 2020-08-20 12:47:47.000000000 +0200
@@ -249,6 +249,18 @@
super(_ES256, self).__init__('P-256', hashes.SHA256())
+class _ES256K(_RawEC, JWAAlgorithm):
+
+ name = "ES256K"
+ description = "ECDSA using secp256k1 curve and SHA-256"
+ keysize = 256
+ algorithm_usage_location = 'alg'
+ algorithm_use = 'sig'
+
+ def __init__(self):
+ super(_ES256K, self).__init__('secp256k1', hashes.SHA256())
+
+
class _ES384(_RawEC, JWAAlgorithm):
name = "ES384"
@@ -1042,6 +1054,7 @@
'RS384': _RS384,
'RS512': _RS512,
'ES256': _ES256,
+ 'ES256K': _ES256K,
'ES384': _ES384,
'ES512': _ES512,
'PS256': _PS256,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.7/jwcrypto/jwe.py
new/jwcrypto-0.8/jwcrypto/jwe.py
--- old/jwcrypto-0.7/jwcrypto/jwe.py 2019-05-27 14:17:28.000000000 +0200
+++ new/jwcrypto-0.8/jwcrypto/jwe.py 2020-08-20 12:47:47.000000000 +0200
@@ -284,13 +284,13 @@
"is set" % invalid)
if 'protected' not in self.objects:
raise InvalidJWEOperation(
- "Can't use compat encoding without protected headers")
+ "Can't use compact encoding without protected headers")
else:
ph = json_decode(self.objects['protected'])
for required in 'alg', 'enc':
if required not in ph:
raise InvalidJWEOperation(
- "Can't use compat encoding, '%s' must be in the "
+ "Can't use compact encoding, '%s' must be in the "
"protected header" % required)
if 'recipients' in self.objects:
if len(self.objects['recipients']) != 1:
@@ -438,7 +438,7 @@
If a key is provided a decryption step will be attempted after
the object is successfully deserialized.
- :raises InvalidJWEData: if the raw object is an invaid JWE token.
+ :raises InvalidJWEData: if the raw object is an invalid JWE token.
:raises InvalidJWEOperation: if the decryption fails.
"""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.7/jwcrypto/jwk.py
new/jwcrypto-0.8/jwcrypto/jwk.py
--- old/jwcrypto-0.7/jwcrypto/jwk.py 2020-02-19 17:12:20.000000000 +0100
+++ new/jwcrypto-0.8/jwcrypto/jwk.py 2020-08-20 12:47:47.000000000 +0200
@@ -148,12 +148,14 @@
'x5t#S256': JWKParameter('X.509 Certificate SHA-256 Thumbprint',
True, None, None)
}
-"""Regstry of valid key parameters"""
+"""Registry of valid key parameters"""
# RFC 7518 - 7.6 , RFC 8037 - 5
+# secp256k1 - https://tools.ietf.org/html/draft-ietf-cose-webauthn-algorithms
JWKEllipticCurveRegistry = {'P-256': 'P-256 curve',
'P-384': 'P-384 curve',
'P-521': 'P-521 curve',
+ 'secp256k1': 'SECG secp256k1 curve',
'Ed25519': 'Ed25519 signature algorithm key pairs',
'Ed448': 'Ed448 signature algorithm key pairs',
'X25519': 'X25519 function key pairs',
@@ -180,7 +182,8 @@
JWKpycaCurveMap = {'secp256r1': 'P-256',
'secp384r1': 'P-384',
- 'secp521r1': 'P-521'}
+ 'secp521r1': 'P-521',
+ 'secp256k1': 'secp256k1'}
class InvalidJWKType(JWException):
@@ -278,7 +281,7 @@
always be provided and its value must be a valid one as defined
by the 'IANA JSON Web Key Types registry' and specified in the
:data:`JWKTypesRegistry` variable. The valid key parameters per
- key type are defined in the :data:`JWKValuesregistry` variable.
+ key type are defined in the :data:`JWKValuesRegistry` variable.
To generate a new random key call the class method generate() with
the appropriate 'kty' parameter, and other parameters as needed (key
@@ -287,13 +290,13 @@
Valid options per type, when generating new keys:
* oct: size(int)
* RSA: public_exponent(int), size(int)
- * EC: crv(str) (one of P-256, P-384, P-521)
+ * EC: crv(str) (one of P-256, P-384, P-521, secp256k1)
* OKP: crv(str) (one of Ed25519, Ed448, X25519, X448)
Deprecated:
Alternatively if the 'generate' parameter is provided, with a
valid key type as value then a new key will be generated according
- to the defaults or provided key strenght options (type specific).
+ to the defaults or provided key strength options (type specific).
:raises InvalidJWKType: if the key type is invalid
:raises InvalidJWKValue: if incorrect or inconsistent parameters
@@ -401,6 +404,8 @@
return ec.SECP384R1()
elif name == 'P-521':
return ec.SECP521R1()
+ elif name == 'secp256k1':
+ return ec.SECP256K1()
elif name in _OKP_CURVES_TABLE:
return name
else:
@@ -450,10 +455,16 @@
'OKP key type' % params['crv'])
self._import_pyca_pri_okp(key, **params)
+ def _okp_curve_from_pyca_key(self, key):
+ for name, val in iteritems(_OKP_CURVES_TABLE):
+ if isinstance(key, (val.pubkey, val.privkey)):
+ return name
+ raise InvalidJWKValue('Invalid OKP Key object %r' % key)
+
def _import_pyca_pri_okp(self, key, **params):
params.update(
kty='OKP',
- crv=params['crv'],
+ crv=self._okp_curve_from_pyca_key(key),
d=base64url_encode(key.private_bytes(
serialization.Encoding.Raw,
serialization.PrivateFormat.Raw,
@@ -467,10 +478,10 @@
def _import_pyca_pub_okp(self, key, **params):
params.update(
kty='OKP',
- crv=params['crv'],
+ crv=self._okp_curve_from_pyca_key(key),
x=base64url_encode(key.public_bytes(
serialization.Encoding.Raw,
- serialization.PrivateFormat.Raw))
+ serialization.PublicFormat.Raw))
)
self.import_key(**params)
@@ -565,10 +576,10 @@
obj.import_key(**jkey)
return obj
- def export(self, private_key=True):
+ def export(self, private_key=True, as_dict=False):
"""Exports the key in the standard JSON format.
Exports the key regardless of type, if private_key is False
- and the key is_symmetric an exceptionis raised.
+ and the key is_symmetric an exception is raised.
:param private_key(bool): Whether to export the private key.
Defaults to True.
@@ -576,16 +587,20 @@
if private_key is True:
# Use _export_all for backwards compatibility, as this
# function allows to export symmetrict keys too
- return self._export_all()
- else:
- return self.export_public()
+ return self._export_all(as_dict)
- def export_public(self):
+ return self.export_public(as_dict)
+
+ def export_public(self, as_dict=False):
"""Exports the public key in the standard JSON format.
It fails if one is not available like when this function
is called on a symmetric key.
+
+ :param as_dict(bool): If set to True export as python dict not JSON
"""
pub = self._public_params()
+ if as_dict is True:
+ return pub
return json_encode(pub)
def _public_params(self):
@@ -603,24 +618,28 @@
pub[param] = self._key[param]
return pub
- def _export_all(self):
+ def _export_all(self, as_dict=False):
d = dict()
d.update(self._params)
d.update(self._key)
d.update(self._unknown)
+ if as_dict is True:
+ return d
return json_encode(d)
- def export_private(self):
+ def export_private(self, as_dict=False):
"""Export the private key in the standard JSON format.
It fails for a JWK that has only a public key or is symmetric.
+
+ :param as_dict(bool): If set to True export as python dict not JSON
"""
if self.has_private:
- return self._export_all()
+ return self._export_all(as_dict)
raise InvalidJWKType("No private key available")
- def export_symmetric(self):
+ def export_symmetric(self, as_dict=False):
if self.is_symmetric:
- return self._export_all()
+ return self._export_all(as_dict)
raise InvalidJWKType("Not a symmetric key")
def public(self):
@@ -767,12 +786,12 @@
raise NotImplementedError
def get_op_key(self, operation=None, arg=None):
- """Get the key object associated to the requested opration.
+ """Get the key object associated to the requested operation.
For example the public RSA key for the 'verify' operation or
the private EC key for the 'decrypt' operation.
:param operation: The requested operation.
- The valid set of operations is availble in the
+ The valid set of operations is available in the
:data:`JWKOperationsRegistry` registry.
:param arg: an optional, context specific, argument
For example a curve name.
@@ -936,7 +955,7 @@
class JWKSet(dict):
"""A set of JWK objects.
- Inherits from the standard 'dict' bultin type.
+ Inherits from the standard 'dict' builtin type.
Creates a special key 'keys' that is of a type derived from 'set'
The 'keys' attribute accepts only :class:`jwcrypto.jwk.JWK` elements.
"""
@@ -964,26 +983,31 @@
def add(self, elem):
self['keys'].add(elem)
- def export(self, private_keys=True):
- """Exports a RFC 7517 keyset using the standard JSON format
+ def export(self, private_keys=True, as_dict=False):
+ """Exports a RFC 7517 key set.
+ Exports as json by default, or as dict if requested.
:param private_key(bool): Whether to export private keys.
Defaults to True.
+ :param as_dict(bool): Whether to return a dict instead of
+ a JSON object
"""
exp_dict = dict()
for k, v in iteritems(self):
if k == 'keys':
keys = list()
for jwk in v:
- keys.append(json_decode(jwk.export(private_keys)))
+ keys.append(jwk.export(private_keys, as_dict=True))
v = keys
exp_dict[k] = v
+ if as_dict is True:
+ return exp_dict
return json_encode(exp_dict)
def import_keyset(self, keyset):
- """Imports a RFC 7517 keyset using the standard JSON format.
+ """Imports a RFC 7517 key set using the standard JSON format.
- :param keyset: The RFC 7517 representation of a JOSE Keyset.
+ :param keyset: The RFC 7517 representation of a JOSE key set.
"""
try:
jwkset = json_decode(keyset)
@@ -1002,9 +1026,9 @@
@classmethod
def from_json(cls, keyset):
- """Creates a RFC 7517 keyset from the standard JSON format.
+ """Creates a RFC 7517 key set from the standard JSON format.
- :param keyset: The RFC 7517 representation of a JOSE Keyset.
+ :param keyset: The RFC 7517 representation of a JOSE key set.
"""
obj = cls()
obj.import_keyset(keyset)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.7/jwcrypto/jws.py
new/jwcrypto-0.8/jwcrypto/jws.py
--- old/jwcrypto-0.7/jwcrypto/jws.py 2020-02-19 17:12:20.000000000 +0100
+++ new/jwcrypto-0.8/jwcrypto/jws.py 2020-08-20 12:47:47.000000000 +0200
@@ -326,7 +326,7 @@
except Exception as e: # pylint: disable=broad-except
self.verifylog.append('Failed: [%s]' % repr(e))
else:
- raise InvalidJWSSignature('No signatures availble')
+ raise InvalidJWSSignature('No signatures available')
if not self.is_valid:
raise InvalidJWSSignature('Verification failed for all '
@@ -373,7 +373,7 @@
:param alg: The signing algorithm (optional). usually the algorithm
is known as it is provided with the JOSE Headers of the token.
- :raises InvalidJWSObject: if the raw object is an invaid JWS token.
+ :raises InvalidJWSObject: if the raw object is an invalid JWS token.
:raises InvalidJWSSignature: if the verification fails.
"""
self.objects = dict()
@@ -480,7 +480,9 @@
if alg is None:
raise ValueError('"alg" not specified')
- c = JWSCore(alg, key, protected, self.objects['payload'])
+ c = JWSCore(
+ alg, key, protected, self.objects['payload'], self.allowed_algs
+ )
sig = c.sign()
o = dict()
@@ -516,7 +518,7 @@
representation, otherwise generates a standard JSON format.
:raises InvalidJWSOperation: if the object cannot serialized
- with the compact representation and `compat` is True.
+ with the compact representation and `compact` is True.
:raises InvalidJWSSignature: if no signature has been added
to the object, or no valid signature can be found.
"""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.7/jwcrypto/jwt.py
new/jwcrypto-0.8/jwcrypto/jwt.py
--- old/jwcrypto-0.7/jwcrypto/jwt.py 2019-05-27 14:17:28.000000000 +0200
+++ new/jwcrypto-0.8/jwcrypto/jwt.py 2020-08-20 12:47:47.000000000 +0200
@@ -162,7 +162,7 @@
the token. A (:class:`jwcrypto.jwk.JWKSet`) can also be used.
:param algs: An optional list of allowed algorithms
:param default_claims: An optional dict with default values for
- registred claims. A None value for NumericDate type claims
+ registered claims. A None value for NumericDate type claims
will cause generation according to system time. Only the values
from RFC 7519 - 4.1 are evaluated.
:param check_claims: An optional dict of claims that must be
@@ -171,7 +171,7 @@
Note: either the header,claims or jwt,key parameters should be
provided as a deserialization operation (which occurs if the jwt
- is provided will wipe any header os claim provided by setting
+ is provided) will wipe any header or claim provided by setting
those obtained from the deserialization of the jwt token.
Note: if check_claims is not provided the 'exp' and 'nbf' claims
@@ -258,8 +258,8 @@
return self._leeway
@leeway.setter
- def leeway(self, l):
- self._leeway = int(l)
+ def leeway(self, lwy):
+ self._leeway = int(lwy)
@property
def validity(self):
@@ -418,12 +418,14 @@
Creates a JWS token with the header as the JWS protected header and
the claims as the payload. See (:class:`jwcrypto.jws.JWS`) for
- details on the exceptions that may be reaised.
+ details on the exceptions that may be raised.
:param key: A (:class:`jwcrypto.jwk.JWK`) key.
"""
t = JWS(self.claims)
+ if self._algs:
+ t.allowed_algs = self._algs
t.add_signature(key, protected=self.header)
self.token = t
@@ -432,7 +434,7 @@
Creates a JWE token with the header as the JWE protected header and
the claims as the plaintext. See (:class:`jwcrypto.jwe.JWE`) for
- details on the exceptions that may be reaised.
+ details on the exceptions that may be raised.
:param key: A (:class:`jwcrypto.jwk.JWK`) key.
"""
@@ -511,7 +513,7 @@
Note: the compact parameter is provided for general compatibility
with the serialize() functions of :class:`jwcrypto.jws.JWS` and
:class:`jwcrypto.jwe.JWE` so that these objects can all be used
- interchangeably. However the only valid JWT representtion is the
+ interchangeably. However the only valid JWT representation is the
compact representation.
"""
return self.token.serialize(compact)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.7/jwcrypto/tests.py
new/jwcrypto-0.8/jwcrypto/tests.py
--- old/jwcrypto-0.7/jwcrypto/tests.py 2020-02-19 17:12:20.000000000 +0100
+++ new/jwcrypto-0.8/jwcrypto/tests.py 2020-08-20 12:47:47.000000000 +0200
@@ -259,6 +259,39 @@
]
}
+PublicKeys_secp256k1 = {
+ "keys": [
+ {
+ "kty": "EC",
+ "crv": "secp256k1",
+ "x": "Ss6na3mcci8Ud4lQrjaB_T40sfKApEcl2RLIWOJdjow",
+ "y": "7l9qIKtKPW6oEiOYBt7r22Sm0mtFJU-yBkkvMvpscd8"
+ }
+ ]
+}
+
+PrivateKeys_secp256k1 = {
+ "keys": [
+ {
+ "kty": "EC",
+ "crv": "secp256k1",
+ "x": "Ss6na3mcci8Ud4lQrjaB_T40sfKApEcl2RLIWOJdjow",
+ "y": "7l9qIKtKPW6oEiOYBt7r22Sm0mtFJU-yBkkvMvpscd8",
+ "d": "GYhU2vrYGZrjLZn71Xniqm54Mi53xiYtaTLawzaf9dA"
+ },
+ ]
+}
+
+Ed25519PrivatePEM = b"""-----BEGIN PRIVATE KEY-----
+MC4CAQAwBQYDK2VwBCIEIEh4ImJiiZgSNg9J9I+Z5toHKh6LDO2MCbSYNZTkMXDU
+-----END PRIVATE KEY-----
+"""
+
+Ed25519PublicPEM = b"""-----BEGIN PUBLIC KEY-----
+MCowBQYDK2VwAyEAlsRcb1mVVIUcDjNqZU27N+iPXihH1EQDa/O3utHLtqc=
+-----END PUBLIC KEY-----
+"""
+
class TestJWK(unittest.TestCase):
def test_create_pubKeys(self):
@@ -319,6 +352,9 @@
# New param prevails
key = jwk.JWK.generate(kty='EC', curve='P-256', crv='P-521')
key.get_curve('P-521')
+ # New secp256k curve
+ key = jwk.JWK.generate(kty='EC', curve='secp256k1')
+ key.get_curve('secp256k1')
def test_generate_OKP_keys(self):
for crv in jwk.ImplementedOkpCurves:
@@ -364,7 +400,7 @@
ks3 = jwk.JWKSet.from_json(ks.export())
self.assertEqual(len(ks), len(ks3))
- # Test Keyset with mutiple keys
+ # Test key set with mutiple keys
ksm = jwk.JWKSet.from_json(json_encode(PrivateKeys))
num = 0
for item in ksm:
@@ -422,6 +458,21 @@
self.assertFalse(pubkey.has_private)
self.assertEqual(prikey.key_id, pubkey.key_id)
+ def test_export_as_dict(self):
+ key = jwk.JWK(**SymmetricKeys['keys'][1])
+ k = key.export_symmetric(as_dict=True)
+ self.assertEqual(k['kid'], SymmetricKeys['keys'][1]['kid'])
+ key = jwk.JWK.from_pem(PublicCert)
+ k = key.export_public(as_dict=True)
+ self.assertEqual(k['kid'], PublicCertThumbprint)
+ key = jwk.JWK.from_pem(RSAPrivatePEM, password=RSAPrivatePassword)
+ k = key.export_private(as_dict=True)
+ self.assertEqual(k['kid'],
+ u'x31vrbZceU2qOPLtrUwPkLa3PNakMn9tOsq_ntFVrJc')
+ keyset = jwk.JWKSet.from_json(json_encode(PrivateKeys))
+ ks = keyset.export(as_dict=True)
+ self.assertTrue('keys' in ks)
+
def test_public(self):
key = jwk.JWK.from_pem(RSAPrivatePEM, password=RSAPrivatePassword)
self.assertTrue(key.has_public)
@@ -451,6 +502,16 @@
for key in keylist:
jwk.JWK(**key)
+ def test_create_pubKeys_secp256k1(self):
+ keylist = PublicKeys_secp256k1['keys']
+ for key in keylist:
+ jwk.JWK(**key)
+
+ def test_create_priKeys_secp256k1(self):
+ keylist = PrivateKeys_secp256k1['keys']
+ for key in keylist:
+ jwk.JWK(**key)
+
def test_thumbprint_eddsa(self):
for i in range(0, len(PublicKeys_EdDsa['keys'])):
k = jwk.JWK(**PublicKeys_EdDsa['keys'][i])
@@ -458,6 +519,22 @@
k.thumbprint(),
PublicKeys_EdDsa['thumbprints'][i])
+ def test_pem_okp(self):
+ payload = b'Imported private Ed25519'
+ prikey = jwk.JWK.from_pem(Ed25519PrivatePEM)
+ self.assertTrue(prikey.has_private)
+ self.assertTrue(prikey.has_public)
+ s = jws.JWS(payload)
+ s.add_signature(prikey, None, {'alg': 'EdDSA'}, None)
+ sig = s.serialize()
+ pubkey = jwk.JWK.from_pem(Ed25519PublicPEM)
+ self.assertTrue(pubkey.has_public)
+ self.assertFalse(pubkey.has_private)
+ c = jws.JWS()
+ c.deserialize(sig, pubkey, alg="EdDSA")
+ self.assertTrue(c.objects['valid'])
+ self.assertEqual(c.payload, payload)
+
# RFC 7515 - A.1
A1_protected = \
@@ -786,6 +863,19 @@
self.assertEqual(jws_verify.payload.decode('utf-8'),
curve_example['payload'])
+ def test_secp256k1_signing_and_verification(self):
+ key = jwk.JWK(**PrivateKeys_secp256k1['keys'][0])
+ payload = bytes(bytearray(A1_payload))
+ jws_test = jws.JWS(payload)
+ jws_test.allowed_algs = ['ES256K']
+ jws_test.add_signature(key, None, json_encode({"alg": "ES256K"}), None)
+ jws_test_serialization_compact = jws_test.serialize(compact=True)
+ jws_verify = jws.JWS()
+ jws_verify.allowed_algs = ['ES256K']
+ jws_verify.deserialize(jws_test_serialization_compact)
+ jws_verify.verify(key.public())
+ self.assertEqual(jws_verify.payload, payload)
+
E_A1_plaintext = \
[84, 104, 101, 32, 116, 114, 117, 101, 32, 115, 105, 103, 110, 32,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.7/jwcrypto.egg-info/PKG-INFO
new/jwcrypto-0.8/jwcrypto.egg-info/PKG-INFO
--- old/jwcrypto-0.7/jwcrypto.egg-info/PKG-INFO 2020-02-19 18:17:34.000000000
+0100
+++ new/jwcrypto-0.8/jwcrypto.egg-info/PKG-INFO 2020-08-20 12:48:07.000000000
+0200
@@ -1,6 +1,6 @@
Metadata-Version: 1.2
Name: jwcrypto
-Version: 0.7
+Version: 0.8
Summary: Implementation of JOSE Web standards
Home-page: https://github.com/latchset/jwcrypto
Maintainer: JWCrypto Project Contributors
@@ -13,6 +13,7 @@
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
Classifier: Intended Audience :: Developers
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Libraries :: Python Modules
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.7/jwcrypto.egg-info/requires.txt
new/jwcrypto-0.8/jwcrypto.egg-info/requires.txt
--- old/jwcrypto-0.7/jwcrypto.egg-info/requires.txt 2020-02-19
18:17:34.000000000 +0100
+++ new/jwcrypto-0.8/jwcrypto.egg-info/requires.txt 2020-08-20
12:48:07.000000000 +0200
@@ -1 +1 @@
-cryptography>=1.5
+cryptography>=2.3
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.7/setup.py new/jwcrypto-0.8/setup.py
--- old/jwcrypto-0.7/setup.py 2020-02-19 18:15:54.000000000 +0100
+++ new/jwcrypto-0.8/setup.py 2020-08-20 12:47:47.000000000 +0200
@@ -6,7 +6,7 @@
setup(
name = 'jwcrypto',
- version = '0.7',
+ version = '0.8',
license = 'LGPLv3+',
maintainer = 'JWCrypto Project Contributors',
maintainer_email = '[email protected]',
@@ -19,12 +19,13 @@
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
+ 'Programming Language :: Python :: 3.8',
'Intended Audience :: Developers',
'Topic :: Security',
'Topic :: Software Development :: Libraries :: Python Modules'
],
data_files = [('share/doc/jwcrypto', ['LICENSE', 'README.md'])],
install_requires = [
- 'cryptography >= 1.5',
+ 'cryptography >= 2.3',
],
)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.7/tox.ini new/jwcrypto-0.8/tox.ini
--- old/jwcrypto-0.7/tox.ini 2020-02-19 17:12:20.000000000 +0100
+++ new/jwcrypto-0.8/tox.ini 2020-08-20 12:47:47.000000000 +0200
@@ -50,10 +50,10 @@
markdown_py README.md -f {toxworkdir}/README.md.html
[testenv:sphinx]
-basepython = python2.7
+basepython = python3
changedir = docs/source
deps =
- sphinx < 1.3.0
+ sphinx
commands =
sphinx-build -v -W -b html -d {envtmpdir}/doctrees . {envtmpdir}/html