diff options
-rw-r--r-- | AUTHORS.rst | 1 | ||||
-rw-r--r-- | cryptography/exceptions.py | 4 | ||||
-rw-r--r-- | cryptography/hazmat/backends/openssl/asn1.py | 20 | ||||
-rw-r--r-- | cryptography/hazmat/backends/openssl/backend.py | 1 | ||||
-rw-r--r-- | cryptography/hazmat/backends/openssl/bignum.py | 19 | ||||
-rw-r--r-- | cryptography/hazmat/backends/openssl/evp.py | 7 | ||||
-rw-r--r-- | cryptography/hazmat/backends/openssl/nid.py | 1 | ||||
-rw-r--r-- | cryptography/hazmat/backends/openssl/objects.py | 43 | ||||
-rw-r--r-- | cryptography/hazmat/backends/openssl/rsa.py | 2 | ||||
-rw-r--r-- | cryptography/hazmat/primitives/hmac.py | 11 | ||||
-rw-r--r-- | docs/exceptions.rst | 6 | ||||
-rw-r--r-- | docs/hazmat/primitives/hmac.rst | 8 | ||||
-rw-r--r-- | tests/hazmat/primitives/test_hmac.py | 27 |
13 files changed, 144 insertions, 6 deletions
diff --git a/AUTHORS.rst b/AUTHORS.rst index 0ef9958d..953ca55b 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -10,3 +10,4 @@ PGP key fingerprints are enclosed in parentheses. * Christian Heimes <christian@python.org> * Paul Kehrer <paul.l.kehrer@gmail.com> * Jarret Raim <jarito@gmail.com> +* Alex Stapleton <alexs@prol.etari.at> (A1C7 E50B 66DE 39ED C847 9665 8E3C 20D1 9BD9 5C4C) diff --git a/cryptography/exceptions.py b/cryptography/exceptions.py index e9d88199..44363c24 100644 --- a/cryptography/exceptions.py +++ b/cryptography/exceptions.py @@ -30,3 +30,7 @@ class NotYetFinalized(Exception): class InvalidTag(Exception): pass + + +class InvalidSignature(Exception): + pass diff --git a/cryptography/hazmat/backends/openssl/asn1.py b/cryptography/hazmat/backends/openssl/asn1.py index a186d592..6a309ee1 100644 --- a/cryptography/hazmat/backends/openssl/asn1.py +++ b/cryptography/hazmat/backends/openssl/asn1.py @@ -16,7 +16,24 @@ INCLUDES = """ """ TYPES = """ -typedef ... time_t; +/* + * TODO: This typedef is wrong. + * + * This is due to limitations of cffi. + * See https://bitbucket.org/cffi/cffi/issue/69 + * + * For another possible work-around (not used here because it involves more + * complicated use of the cffi API which falls outside the general pattern used + * by this package), see + * http://paste.pound-python.org/show/iJcTUMkKeBeS6yXpZWUU/ + * + * The work-around used here is to just be sure to declare a type that is at + * least as large as the real type. Maciej explains: + * + * <fijal> I think you want to declare your value too large (e.g. long) + * <fijal> that way you'll never pass garbage + */ +typedef uintptr_t time_t; typedef int ASN1_BOOLEAN; typedef ... ASN1_INTEGER; @@ -118,6 +135,7 @@ int ASN1_INTEGER_cmp(ASN1_INTEGER *, ASN1_INTEGER *); long ASN1_INTEGER_get(ASN1_INTEGER *); BIGNUM *ASN1_INTEGER_to_BN(ASN1_INTEGER *, BIGNUM *); +ASN1_INTEGER *BN_to_ASN1_INTEGER(const BIGNUM *, ASN1_INTEGER *); """ CUSTOMIZATIONS = """ diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index 7b67fb0b..6231aadb 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -85,6 +85,7 @@ class Backend(object): "evp", "hmac", "nid", + "objects", "opensslv", "pem", "pkcs7", diff --git a/cryptography/hazmat/backends/openssl/bignum.py b/cryptography/hazmat/backends/openssl/bignum.py index 68d0c3a2..599eadc8 100644 --- a/cryptography/hazmat/backends/openssl/bignum.py +++ b/cryptography/hazmat/backends/openssl/bignum.py @@ -17,7 +17,24 @@ INCLUDES = """ TYPES = """ typedef ... BIGNUM; -typedef ... BN_ULONG; +/* + * TODO: This typedef is wrong. + * + * This is due to limitations of cffi. + * See https://bitbucket.org/cffi/cffi/issue/69 + * + * For another possible work-around (not used here because it involves more + * complicated use of the cffi API which falls outside the general pattern used + * by this package), see + * http://paste.pound-python.org/show/iJcTUMkKeBeS6yXpZWUU/ + * + * The work-around used here is to just be sure to declare a type that is at + * least as large as the real type. Maciej explains: + * + * <fijal> I think you want to declare your value too large (e.g. long) + * <fijal> that way you'll never pass garbage + */ +typedef uintptr_t BN_ULONG; """ FUNCTIONS = """ diff --git a/cryptography/hazmat/backends/openssl/evp.py b/cryptography/hazmat/backends/openssl/evp.py index 0662b1ef..1f8901bf 100644 --- a/cryptography/hazmat/backends/openssl/evp.py +++ b/cryptography/hazmat/backends/openssl/evp.py @@ -24,7 +24,9 @@ typedef struct { ...; } EVP_CIPHER_CTX; typedef ... EVP_MD; -typedef struct env_md_ctx_st EVP_MD_CTX; +typedef struct env_md_ctx_st { + ...; +} EVP_MD_CTX; typedef struct evp_pkey_st { int type; @@ -32,6 +34,7 @@ typedef struct evp_pkey_st { } EVP_PKEY; static const int EVP_PKEY_RSA; static const int EVP_PKEY_DSA; +static const int EVP_MAX_MD_SIZE; static const int EVP_CTRL_GCM_SET_IVLEN; static const int EVP_CTRL_GCM_GET_TAG; static const int EVP_CTRL_GCM_SET_TAG; @@ -92,6 +95,8 @@ int EVP_VerifyInit(EVP_MD_CTX *, const EVP_MD *); int EVP_VerifyUpdate(EVP_MD_CTX *, const void *, size_t); int EVP_VerifyFinal(EVP_MD_CTX *, const unsigned char *, unsigned int, EVP_PKEY *); + +const EVP_MD *EVP_md5(); """ MACROS = """ diff --git a/cryptography/hazmat/backends/openssl/nid.py b/cryptography/hazmat/backends/openssl/nid.py index 111f82f9..40aed19f 100644 --- a/cryptography/hazmat/backends/openssl/nid.py +++ b/cryptography/hazmat/backends/openssl/nid.py @@ -37,6 +37,7 @@ static const int NID_ecdsa_with_SHA384; static const int NID_ecdsa_with_SHA512; static const int NID_crl_reason; static const int NID_pbe_WithSHA1And3_Key_TripleDES_CBC; +static const int NID_subject_alt_name; """ FUNCTIONS = """ diff --git a/cryptography/hazmat/backends/openssl/objects.py b/cryptography/hazmat/backends/openssl/objects.py new file mode 100644 index 00000000..ad1b8588 --- /dev/null +++ b/cryptography/hazmat/backends/openssl/objects.py @@ -0,0 +1,43 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +INCLUDES = """ +#include <openssl/objects.h> +""" + +TYPES = """ +""" + +FUNCTIONS = """ +ASN1_OBJECT *OBJ_nid2obj(int); +const char *OBJ_nid2ln(int); +const char *OBJ_nid2sn(int); +int OBJ_obj2nid(const ASN1_OBJECT *); +int OBJ_ln2nid(const char *); +int OBJ_sn2nid(const char *); +int OBJ_txt2nid(const char *); +ASN1_OBJECT *OBJ_txt2obj(const char *, int); +int OBJ_obj2txt(char *, int, const ASN1_OBJECT *, int); +int OBJ_cmp(const ASN1_OBJECT *, const ASN1_OBJECT *); +ASN1_OBJECT *OBJ_dup(const ASN1_OBJECT *); +int OBJ_create(const char *, const char *, const char *); +void OBJ_cleanup(); +""" + +MACROS = """ +""" + +CUSTOMIZATIONS = """ +""" + +CONDITIONAL_NAMES = {} diff --git a/cryptography/hazmat/backends/openssl/rsa.py b/cryptography/hazmat/backends/openssl/rsa.py index e3a24d0f..6cee569a 100644 --- a/cryptography/hazmat/backends/openssl/rsa.py +++ b/cryptography/hazmat/backends/openssl/rsa.py @@ -33,6 +33,7 @@ static const int RSA_SSLV23_PADDING; static const int RSA_NO_PADDING; static const int RSA_PKCS1_OAEP_PADDING; static const int RSA_X931_PADDING; +static const int RSA_F4; """ FUNCTIONS = """ @@ -50,6 +51,7 @@ int RSA_public_decrypt(int, const unsigned char *, unsigned char *, RSA *, int); int RSA_private_decrypt(int, const unsigned char *, unsigned char *, RSA *, int); +int RSA_print(BIO *, const RSA *, int); """ MACROS = """ diff --git a/cryptography/hazmat/primitives/hmac.py b/cryptography/hazmat/primitives/hmac.py index 618bccc5..76d658aa 100644 --- a/cryptography/hazmat/primitives/hmac.py +++ b/cryptography/hazmat/primitives/hmac.py @@ -16,8 +16,8 @@ from __future__ import absolute_import, division, print_function import six from cryptography import utils -from cryptography.exceptions import AlreadyFinalized -from cryptography.hazmat.primitives import interfaces +from cryptography.exceptions import AlreadyFinalized, InvalidSignature +from cryptography.hazmat.primitives import constant_time, interfaces @utils.register_interface(interfaces.HashContext) @@ -57,3 +57,10 @@ class HMAC(object): digest = self._ctx.finalize() self._ctx = None return digest + + def verify(self, signature): + if isinstance(signature, six.text_type): + raise TypeError("Unicode-objects must be encoded before verifying") + digest = self.finalize() + if not constant_time.bytes_eq(digest, signature): + raise InvalidSignature("Signature did not match digest.") diff --git a/docs/exceptions.rst b/docs/exceptions.rst index 087066b8..1fbd3267 100644 --- a/docs/exceptions.rst +++ b/docs/exceptions.rst @@ -8,6 +8,12 @@ Exceptions This is raised when a context is used after being finalized. +.. class:: InvalidSignature + + This is raised when the verify method of a hash context does not + compare equal. + + .. class:: NotYetFinalized This is raised when the AEAD tag property is accessed on a context diff --git a/docs/hazmat/primitives/hmac.rst b/docs/hazmat/primitives/hmac.rst index 0547b7d2..b8f94fd2 100644 --- a/docs/hazmat/primitives/hmac.rst +++ b/docs/hazmat/primitives/hmac.rst @@ -71,3 +71,11 @@ message. :return bytes: The message digest as bytes. :raises cryptography.exceptions.AlreadyFinalized: + + .. method:: verify(signature) + + Finalize the current context and securely compare digest to ``signature``. + + :param bytes signature: The bytes of the HMAC signature recieved. + :raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize` + :raises cryptography.exceptions.InvalidSignature: If signature does not match digest diff --git a/tests/hazmat/primitives/test_hmac.py b/tests/hazmat/primitives/test_hmac.py index 924e2167..04913af6 100644 --- a/tests/hazmat/primitives/test_hmac.py +++ b/tests/hazmat/primitives/test_hmac.py @@ -20,7 +20,9 @@ import pytest import six from cryptography import utils -from cryptography.exceptions import AlreadyFinalized, UnsupportedAlgorithm +from cryptography.exceptions import ( + AlreadyFinalized, UnsupportedAlgorithm, InvalidSignature +) from cryptography.hazmat.primitives import hashes, hmac, interfaces from .utils import generate_base_hmac_test @@ -76,6 +78,29 @@ class TestHMAC(object): with pytest.raises(AlreadyFinalized): h.finalize() + def test_verify(self, backend): + h = hmac.HMAC(b'', hashes.SHA1(), backend=backend) + digest = h.finalize() + + h = hmac.HMAC(b'', hashes.SHA1(), backend=backend) + h.verify(digest) + + with pytest.raises(AlreadyFinalized): + h.verify(b'') + + def test_invalid_verify(self, backend): + h = hmac.HMAC(b'', hashes.SHA1(), backend=backend) + with pytest.raises(InvalidSignature): + h.verify(b'') + + with pytest.raises(AlreadyFinalized): + h.verify(b'') + + def test_verify_reject_unicode(self, backend): + h = hmac.HMAC(b'', hashes.SHA1(), backend=backend) + with pytest.raises(TypeError): + h.verify(six.u('')) + def test_unsupported_hash(self, backend): with pytest.raises(UnsupportedAlgorithm): hmac.HMAC(b"key", UnsupportedDummyHash(), backend) |