Merge pull request #792 from reaperhulk/rsa-pss-verify
RSA PSS Verify
diff --git a/.travis.yml b/.travis.yml
index b7fa090..7d5663d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -16,11 +16,13 @@
- TOX_ENV=py27
- TOX_ENV=py32
- TOX_ENV=py33
+ - TOX_ENV=py34
- TOX_ENV=pypy
- TOX_ENV=py26 OPENSSL=0.9.8
- TOX_ENV=py27 OPENSSL=0.9.8
- TOX_ENV=py32 OPENSSL=0.9.8
- TOX_ENV=py33 OPENSSL=0.9.8
+ - TOX_ENV=py34 OPENSSL=0.9.8
- TOX_ENV=pypy OPENSSL=0.9.8
- TOX_ENV=docs
- TOX_ENV=pep8
@@ -60,6 +62,9 @@
env: TOX_ENV=py33
compiler: gcc
- os: osx
+ env: TOX_ENV=py34
+ compiler: gcc
+ - os: osx
env: TOX_ENV=pypy
compiler: gcc
- os: osx
@@ -75,6 +80,9 @@
env: TOX_ENV=py33 OPENSSL=0.9.8
compiler: gcc
- os: osx
+ env: TOX_ENV=py34 OPENSSL=0.9.8
+ compiler: gcc
+ - os: osx
env: TOX_ENV=pypy OPENSSL=0.9.8
compiler: gcc
- os: osx
diff --git a/.travis/install.sh b/.travis/install.sh
index 7e77fc8..58d7404 100755
--- a/.travis/install.sh
+++ b/.travis/install.sh
@@ -52,8 +52,13 @@
pip install virtualenv
;;
py33)
- pyenv install 3.3.2
- pyenv global 3.3.2
+ pyenv install 3.3.5
+ pyenv global 3.3.5
+ pip install virtualenv
+ ;;
+ py34)
+ pyenv install 3.4.0
+ pyenv global 3.4.0
pip install virtualenv
;;
docs)
@@ -78,6 +83,9 @@
py33)
sudo apt-get install python3.3 python3.3-dev
;;
+ py34)
+ sudo apt-get install python3.4 python3.4-dev
+ ;;
py3pep8)
sudo apt-get install python3.3 python3.3-dev
;;
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 391427d..abbea9f 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -1,8 +1,10 @@
Changelog
=========
-0.3 - 2014-XX-XX
-~~~~~~~~~~~~~~~~
+0.3 - `master`_
+~~~~~~~~~~~~~~~
+
+.. note:: This version is not yet released and is under active development.
* Added :class:`~cryptography.hazmat.primitives.twofactor.hotp.HOTP`.
* Added :class:`~cryptography.hazmat.primitives.twofactor.totp.TOTP`.
@@ -40,3 +42,4 @@
* Initial release.
+.. _`master`: https://github.com/pyca/cryptography/
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py
index 9b8e8f0..7c058f5 100644
--- a/cryptography/hazmat/backends/openssl/backend.py
+++ b/cryptography/hazmat/backends/openssl/backend.py
@@ -16,6 +16,8 @@
import collections
import itertools
+import six
+
from cryptography import utils
from cryptography.exceptions import (
InvalidTag, InternalError, AlreadyFinalized, UnsupportedCipher,
@@ -262,11 +264,24 @@
)
def _bn_to_int(self, bn):
- hex_cdata = self._lib.BN_bn2hex(bn)
- assert hex_cdata != self._ffi.NULL
- hex_str = self._ffi.string(hex_cdata)
- self._lib.OPENSSL_free(hex_cdata)
- return int(hex_str, 16)
+ if six.PY3:
+ # Python 3 has constant time from_bytes, so use that.
+
+ bn_num_bytes = (self._lib.BN_num_bits(bn) + 7) // 8
+ bin_ptr = self._ffi.new("unsigned char[]", bn_num_bytes)
+ bin_len = self._lib.BN_bn2bin(bn, bin_ptr)
+ assert bin_len > 0
+ assert bin_ptr != self._ffi.NULL
+ return int.from_bytes(self._ffi.buffer(bin_ptr)[:bin_len], "big")
+
+ else:
+ # Under Python 2 the best we can do is hex()
+
+ hex_cdata = self._lib.BN_bn2hex(bn)
+ assert hex_cdata != self._ffi.NULL
+ hex_str = self._ffi.string(hex_cdata)
+ self._lib.OPENSSL_free(hex_cdata)
+ return int(hex_str, 16)
def _int_to_bn(self, num):
"""
@@ -275,12 +290,24 @@
ownership of the object). Be sure to register it for GC if it will
be discarded after use.
"""
- hex_num = hex(num).rstrip("L").lstrip("0x").encode("ascii") or b"0"
- bn_ptr = self._ffi.new("BIGNUM **")
- res = self._lib.BN_hex2bn(bn_ptr, hex_num)
- assert res != 0
- assert bn_ptr[0] != self._ffi.NULL
- return bn_ptr[0]
+
+ if six.PY3:
+ # Python 3 has constant time to_bytes, so use that.
+
+ binary = num.to_bytes(int(num.bit_length() / 8.0 + 1), "big")
+ bn_ptr = self._lib.BN_bin2bn(binary, len(binary), self._ffi.NULL)
+ assert bn_ptr != self._ffi.NULL
+ return bn_ptr
+
+ else:
+ # Under Python 2 the best we can do is hex()
+
+ hex_num = hex(num).rstrip("L").lstrip("0x").encode("ascii") or b"0"
+ bn_ptr = self._ffi.new("BIGNUM **")
+ res = self._lib.BN_hex2bn(bn_ptr, hex_num)
+ assert res != 0
+ assert bn_ptr[0] != self._ffi.NULL
+ return bn_ptr[0]
def generate_rsa_private_key(self, public_exponent, key_size):
if public_exponent < 3:
diff --git a/cryptography/hazmat/bindings/utils.py b/cryptography/hazmat/bindings/utils.py
index b825348..318b82b 100644
--- a/cryptography/hazmat/bindings/utils.py
+++ b/cryptography/hazmat/bindings/utils.py
@@ -13,6 +13,8 @@
from __future__ import absolute_import, division, print_function
+import binascii
+
import sys
import cffi
@@ -50,7 +52,8 @@
includes.append(module.INCLUDES)
customizations.append(module.CUSTOMIZATIONS)
- ffi.cdef("\n".join(types + functions + macros))
+ cdef_sources = types + functions + macros
+ ffi.cdef("\n".join(cdef_sources))
# We include functions here so that if we got any of their definitions
# wrong, the underlying C compiler will explode. In C you are allowed
@@ -60,14 +63,16 @@
# is legal, but the following will fail to compile:
# int foo(int);
# int foo(short);
+ source = "\n".join(
+ [pre_include] +
+ includes +
+ [post_include] +
+ functions +
+ customizations
+ )
lib = ffi.verify(
- source="\n".join(
- [pre_include] +
- includes +
- [post_include] +
- functions +
- customizations
- ),
+ source=source,
+ modulename=_create_modulename(cdef_sources, source, sys.version),
libraries=libraries,
ext_package="cryptography",
)
@@ -81,3 +86,20 @@
delattr(lib, name)
return ffi, lib
+
+
+def _create_modulename(cdef_sources, source, sys_version):
+ """
+ cffi creates a modulename internally that incorporates the cffi version.
+ This will cause cryptography's wheels to break when the version of cffi
+ the user has does not match what was used when building the wheel. To
+ resolve this we build our own modulename that uses most of the same code
+ from cffi but elides the version key.
+ """
+ key = '\x00'.join([sys_version[:3], source] + cdef_sources)
+ key = key.encode('utf-8')
+ k1 = hex(binascii.crc32(key[0::2]) & 0xffffffff)
+ k1 = k1.lstrip('0x').rstrip('L')
+ k2 = hex(binascii.crc32(key[1::2]) & 0xffffffff)
+ k2 = k2.lstrip('0').rstrip('L')
+ return '_Cryptography_cffi_{0}{1}'.format(k1, k2)
diff --git a/cryptography/hazmat/primitives/interfaces.py b/cryptography/hazmat/primitives/interfaces.py
index 3824bcd..eab48b4 100644
--- a/cryptography/hazmat/primitives/interfaces.py
+++ b/cryptography/hazmat/primitives/interfaces.py
@@ -367,6 +367,12 @@
class DSAPublicKey(six.with_metaclass(abc.ABCMeta)):
@abc.abstractproperty
+ def key_size(self):
+ """
+ The bit length of the prime modulus.
+ """
+
+ @abc.abstractproperty
def y(self):
"""
The public key.
diff --git a/docs/hazmat/primitives/interfaces.rst b/docs/hazmat/primitives/interfaces.rst
index cc2a300..cefd81a 100644
--- a/docs/hazmat/primitives/interfaces.rst
+++ b/docs/hazmat/primitives/interfaces.rst
@@ -323,7 +323,13 @@
.. versionadded:: 0.3
- A `DSA`_ private key.
+ A `DSA`_ public key.
+
+ .. attribute:: key_size
+
+ :type: int
+
+ The bit length of the modulus.
.. method:: parameters()
diff --git a/setup.py b/setup.py
index 7f7ba9e..f8b84a3 100644
--- a/setup.py
+++ b/setup.py
@@ -119,6 +119,7 @@
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.2",
"Programming Language :: Python :: 3.3",
+ "Programming Language :: Python :: 3.4",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
"Topic :: Security :: Cryptography",
diff --git a/tests/hazmat/bindings/test_utils.py b/tests/hazmat/bindings/test_utils.py
new file mode 100644
index 0000000..0d5b34d
--- /dev/null
+++ b/tests/hazmat/bindings/test_utils.py
@@ -0,0 +1,25 @@
+# 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.
+
+from __future__ import absolute_import, division, print_function
+
+from cryptography.hazmat.bindings import utils
+
+
+def test_create_modulename():
+ cdef_sources = ["cdef sources go here"]
+ source = "source code"
+ name = utils._create_modulename(cdef_sources, source, "2.7")
+ assert name == "_Cryptography_cffi_bcba7f4bx4a14b588"
+ name = utils._create_modulename(cdef_sources, source, "3.2")
+ assert name == "_Cryptography_cffi_a7462526x4a14b588"
diff --git a/tox.ini b/tox.ini
index 3ee449f..7288465 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = py26,py27,pypy,py32,py33,docs,pep8,py3pep8
+envlist = py26,py27,pypy,py32,py33,py34,docs,pep8,py3pep8
[testenv]
deps =