aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.rst2
-rw-r--r--cryptography/hazmat/backends/multibackend.py20
-rw-r--r--cryptography/hazmat/bindings/openssl/evp.py11
-rw-r--r--cryptography/hazmat/bindings/openssl/x509.py44
-rw-r--r--docs/hazmat/backends/openssl.rst2
-rw-r--r--docs/hazmat/primitives/mac/cmac.rst4
-rw-r--r--tests/hazmat/backends/test_multibackend.py34
7 files changed, 109 insertions, 8 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 9e89e563..106e0ab2 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -11,6 +11,8 @@ Changelog
to :class:`~cryptography.hazmat.primitives.asymmetric.padding.PSS`. It will be
removed from ``MGF1`` in two releases per our :doc:`/api-stability` policy.
+* Added :class:`~cryptography.hazmat.primitives.cmac.CMAC`.
+
0.3 - 2014-03-27
~~~~~~~~~~~~~~~~
diff --git a/cryptography/hazmat/backends/multibackend.py b/cryptography/hazmat/backends/multibackend.py
index 86cded85..981a60bd 100644
--- a/cryptography/hazmat/backends/multibackend.py
+++ b/cryptography/hazmat/backends/multibackend.py
@@ -16,11 +16,12 @@ from __future__ import absolute_import, division, print_function
from cryptography import utils
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
from cryptography.hazmat.backends.interfaces import (
- CipherBackend, DSABackend, HMACBackend, HashBackend, PBKDF2HMACBackend,
- RSABackend
+ CMACBackend, CipherBackend, DSABackend, HMACBackend, HashBackend,
+ PBKDF2HMACBackend, RSABackend
)
+@utils.register_interface(CMACBackend)
@utils.register_interface(CipherBackend)
@utils.register_interface(HashBackend)
@utils.register_interface(HMACBackend)
@@ -156,3 +157,18 @@ class MultiBackend(object):
return b.generate_dsa_private_key(parameters)
raise UnsupportedAlgorithm("DSA is not supported by the backend",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
+
+ def cmac_algorithm_supported(self, algorithm):
+ return any(
+ b.cmac_algorithm_supported(algorithm)
+ for b in self._filtered_backends(CMACBackend)
+ )
+
+ def create_cmac_ctx(self, algorithm):
+ for b in self._filtered_backends(CMACBackend):
+ try:
+ return b.create_cmac_ctx(algorithm)
+ except UnsupportedAlgorithm:
+ pass
+ raise UnsupportedAlgorithm("This backend does not support CMAC",
+ _Reasons.UNSUPPORTED_CIPHER)
diff --git a/cryptography/hazmat/bindings/openssl/evp.py b/cryptography/hazmat/bindings/openssl/evp.py
index 963537c8..b3d958e6 100644
--- a/cryptography/hazmat/bindings/openssl/evp.py
+++ b/cryptography/hazmat/bindings/openssl/evp.py
@@ -87,6 +87,8 @@ int EVP_PKEY_type(int);
int EVP_PKEY_bits(EVP_PKEY *);
int EVP_PKEY_size(EVP_PKEY *);
RSA *EVP_PKEY_get1_RSA(EVP_PKEY *);
+DSA *EVP_PKEY_get1_DSA(EVP_PKEY *);
+DH *EVP_PKEY_get1_DH(EVP_PKEY *);
int EVP_SignInit(EVP_MD_CTX *, const EVP_MD *);
int EVP_SignUpdate(EVP_MD_CTX *, const void *, size_t);
@@ -104,6 +106,7 @@ int PKCS5_PBKDF2_HMAC_SHA1(const char *, int, const unsigned char *, int, int,
int EVP_PKEY_set1_RSA(EVP_PKEY *, struct rsa_st *);
int EVP_PKEY_set1_DSA(EVP_PKEY *, struct dsa_st *);
+int EVP_PKEY_set1_DH(EVP_PKEY *, DH *);
int EVP_PKEY_get_attr_count(const EVP_PKEY *);
int EVP_PKEY_get_attr_by_NID(const EVP_PKEY *, int, int);
@@ -123,7 +126,11 @@ MACROS = """
void OpenSSL_add_all_algorithms(void);
int EVP_PKEY_assign_RSA(EVP_PKEY *, RSA *);
int EVP_PKEY_assign_DSA(EVP_PKEY *, DSA *);
+
int EVP_PKEY_assign_EC_KEY(EVP_PKEY *, EC_KEY *);
+EC_KEY *EVP_PKEY_get1_EC_KEY(EVP_PKEY *);
+int EVP_PKEY_set1_EC_KEY(EVP_PKEY *, EC_KEY *);
+
int EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *);
int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *, int, int, void *);
@@ -215,6 +222,8 @@ int (*Cryptography_EVP_PKEY_decrypt)(EVP_PKEY_CTX *, unsigned char *, size_t *,
#endif
#ifdef OPENSSL_NO_EC
int (*EVP_PKEY_assign_EC_KEY)(EVP_PKEY *, EC_KEY *) = NULL;
+EC_KEY *(*EVP_PKEY_get1_EC_KEY)(EVP_PKEY *) = NULL;
+int (*EVP_PKEY_set1_EC_KEY)(EVP_PKEY *, EC_KEY *) = NULL;
#endif
"""
@@ -245,5 +254,7 @@ CONDITIONAL_NAMES = {
],
"Cryptography_HAS_EC": [
"EVP_PKEY_assign_EC_KEY",
+ "EVP_PKEY_get1_EC_KEY",
+ "EVP_PKEY_set1_EC_KEY",
]
}
diff --git a/cryptography/hazmat/bindings/openssl/x509.py b/cryptography/hazmat/bindings/openssl/x509.py
index e800d272..92870369 100644
--- a/cryptography/hazmat/bindings/openssl/x509.py
+++ b/cryptography/hazmat/bindings/openssl/x509.py
@@ -160,6 +160,8 @@ X509_REQ *d2i_X509_REQ_bio(BIO *, X509_REQ **);
int i2d_PrivateKey_bio(BIO *, EVP_PKEY *);
EVP_PKEY *d2i_PrivateKey_bio(BIO *, EVP_PKEY **);
+int i2d_PUBKEY_bio(BIO *, EVP_PKEY *);
+EVP_PKEY *d2i_PUBKEY_bio(BIO *, EVP_PKEY **);
ASN1_INTEGER *X509_get_serialNumber(X509 *);
int X509_set_serialNumber(X509 *, ASN1_INTEGER *);
@@ -178,6 +180,22 @@ const char *X509_get_default_cert_file(void);
const char *X509_get_default_cert_dir_env(void);
const char *X509_get_default_cert_file_env(void);
const char *X509_get_default_private_dir(void);
+
+int i2d_RSA_PUBKEY(RSA *, unsigned char **);
+RSA *d2i_RSA_PUBKEY(RSA **, const unsigned char **, long);
+int i2d_DSA_PUBKEY(DSA *, unsigned char **);
+DSA *d2i_DSA_PUBKEY(DSA **, const unsigned char **, long);
+
+RSA *d2i_RSAPrivateKey_bio(BIO *, RSA **);
+int i2d_RSAPrivateKey_bio(BIO *, RSA *);
+RSA *d2i_RSAPublicKey_bio(BIO *, RSA **);
+int i2d_RSAPublicKey_bio(BIO *, RSA *);
+RSA *d2i_RSA_PUBKEY_bio(BIO *, RSA **);
+int i2d_RSA_PUBKEY_bio(BIO *, RSA *);
+DSA *d2i_DSA_PUBKEY_bio(BIO *, DSA **);
+int i2d_DSA_PUBKEY_bio(BIO *, DSA *);
+DSA *d2i_DSAPrivateKey_bio(BIO *, DSA **);
+int i2d_DSAPrivateKey_bio(BIO *, DSA *);
"""
MACROS = """
@@ -213,6 +231,13 @@ int X509_CRL_set_nextUpdate(X509_CRL *, ASN1_TIME *);
RHEL/CentOS 5 we should move these back to FUNCTIONS. */
int X509_REQ_add_extensions(X509_REQ *, X509_EXTENSIONS *);
X509_EXTENSIONS *X509_REQ_get_extensions(X509_REQ *);
+
+int i2d_EC_PUBKEY(EC_KEY *, unsigned char **);
+EC_KEY *d2i_EC_PUBKEY(EC_KEY **, const unsigned char **, long);
+EC_KEY *d2i_EC_PUBKEY_bio(BIO *, EC_KEY **);
+int i2d_EC_PUBKEY_bio(BIO *, EC_KEY *);
+EC_KEY *d2i_ECPrivateKey_bio(BIO *, EC_KEY **);
+int i2d_ECPrivateKey_bio(BIO *, EC_KEY *);
"""
CUSTOMIZATIONS = """
@@ -220,6 +245,23 @@ CUSTOMIZATIONS = """
#if OPENSSL_VERSION_NUMBER <= 0x0090805fL
typedef STACK_OF(X509_EXTENSION) X509_EXTENSIONS;
#endif
+#ifdef OPENSSL_NO_EC
+int (*i2d_EC_PUBKEY)(EC_KEY *, unsigned char **) = NULL;
+EC_KEY *(*d2i_EC_PUBKEY)(EC_KEY **, const unsigned char **, long) = NULL;
+EC_KEY *(*d2i_EC_PUBKEY_bio)(BIO *, EC_KEY **) = NULL;
+int (*i2d_EC_PUBKEY_bio)(BIO *, EC_KEY *) = NULL;
+EC_KEY *(*d2i_ECPrivateKey_bio)(BIO *, EC_KEY **) = NULL;
+int (*i2d_ECPrivateKey_bio)(BIO *, EC_KEY *) = NULL;
+#endif
"""
-CONDITIONAL_NAMES = {}
+CONDITIONAL_NAMES = {
+ "Cryptography_HAS_EC": [
+ "i2d_EC_PUBKEY",
+ "d2i_EC_PUBKEY",
+ "d2i_EC_PUBKEY_bio",
+ "i2d_EC_PUBKEY_bio",
+ "d2i_ECPrivateKey_bio",
+ "i2d_ECPrivateKey_bio",
+ ]
+}
diff --git a/docs/hazmat/backends/openssl.rst b/docs/hazmat/backends/openssl.rst
index fdfadf0b..43e5d8f3 100644
--- a/docs/hazmat/backends/openssl.rst
+++ b/docs/hazmat/backends/openssl.rst
@@ -73,6 +73,6 @@ from the same pool as ``/dev/random``.
.. _`OpenSSL`: https://www.openssl.org/
-.. _`initializing the RNG`: http://en.wikipedia.org/wiki/OpenSSL#Vulnerability_in_the_Debian_implementation
+.. _`initializing the RNG`: https://en.wikipedia.org/wiki/OpenSSL#Predictable_keys_.28Debian-specific.29
.. _`Yarrow`: http://en.wikipedia.org/wiki/Yarrow_algorithm
.. _`Microsoft documentation`: http://msdn.microsoft.com/en-us/library/windows/desktop/aa379942(v=vs.85).aspx
diff --git a/docs/hazmat/primitives/mac/cmac.rst b/docs/hazmat/primitives/mac/cmac.rst
index 8b88a3ce..a6b048b5 100644
--- a/docs/hazmat/primitives/mac/cmac.rst
+++ b/docs/hazmat/primitives/mac/cmac.rst
@@ -19,10 +19,12 @@ A subset of CMAC with the AES-128 algorithm is described in :rfc:`4493`.
.. class:: CMAC(algorithm, backend)
+ .. versionadded:: 0.4
+
CMAC objects take a
:class:`~cryptography.hazmat.primitives.interfaces.BlockCipherAlgorithm` provider.
- .. code-block:: pycon
+ .. doctest::
>>> from cryptography.hazmat.backends import default_backend
>>> from cryptography.hazmat.primitives import cmac
diff --git a/tests/hazmat/backends/test_multibackend.py b/tests/hazmat/backends/test_multibackend.py
index f46009d4..d8c09bd7 100644
--- a/tests/hazmat/backends/test_multibackend.py
+++ b/tests/hazmat/backends/test_multibackend.py
@@ -18,11 +18,11 @@ from cryptography.exceptions import (
UnsupportedAlgorithm, _Reasons
)
from cryptography.hazmat.backends.interfaces import (
- CipherBackend, DSABackend, HMACBackend, HashBackend, PBKDF2HMACBackend,
- RSABackend
+ CMACBackend, CipherBackend, DSABackend, HMACBackend, HashBackend,
+ PBKDF2HMACBackend, RSABackend
)
from cryptography.hazmat.backends.multibackend import MultiBackend
-from cryptography.hazmat.primitives import hashes, hmac
+from cryptography.hazmat.primitives import cmac, hashes, hmac
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
@@ -108,6 +108,19 @@ class DummyDSABackend(object):
pass
+@utils.register_interface(CMACBackend)
+class DummyCMACBackend(object):
+ def __init__(self, supported_algorithms):
+ self._algorithms = supported_algorithms
+
+ def cmac_algorithm_supported(self, algorithm):
+ return type(algorithm) in self._algorithms
+
+ def create_cmac_ctx(self, algorithm):
+ if not self.cmac_algorithm_supported(algorithm):
+ raise UnsupportedAlgorithm("", _Reasons.UNSUPPORTED_CIPHER)
+
+
class TestMultiBackend(object):
def test_ciphers(self):
backend = MultiBackend([
@@ -224,3 +237,18 @@ class TestMultiBackend(object):
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
):
backend.generate_dsa_private_key(parameters)
+
+ def test_cmac(self):
+ backend = MultiBackend([
+ DummyCMACBackend([algorithms.AES])
+ ])
+
+ fake_key = b"\x00" * 16
+
+ assert backend.cmac_algorithm_supported(
+ algorithms.AES(fake_key)) is True
+
+ cmac.CMAC(algorithms.AES(fake_key), backend)
+
+ with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_CIPHER):
+ cmac.CMAC(algorithms.TripleDES(fake_key), backend)