Merge pull request #2831 from reaperhulk/110-patch-37

SSL_CIPHER_get_version gained a const return type in 1.1.0
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index aad8d93..63dab99 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -6,6 +6,8 @@
 
 .. note:: This version is not yet released and is under active development.
 
+* Added support for padding ANSI X.923 with
+  :class:`~cryptography.hazmat.primitives.padding.ANSIX923`.
 * Deprecated support for OpenSSL 0.9.8. Support will be removed in
   ``cryptography`` 1.4.
 * Added support for the :class:`~cryptography.x509.PolicyConstraints`
diff --git a/docs/hazmat/primitives/padding.rst b/docs/hazmat/primitives/padding.rst
index a60f5ac..0b76327 100644
--- a/docs/hazmat/primitives/padding.rst
+++ b/docs/hazmat/primitives/padding.rst
@@ -54,6 +54,49 @@
             provider.
 
 
+.. class:: ANSIX923(block_size)
+
+    .. versionadded:: 1.3
+
+    `ANSI X.923`_ padding works by appending ``N-1`` bytes with the value of
+    ``0`` and a last byte with the value of ``chr(N)``, where ``N`` is the
+    number of bytes required to make the final block of data the same size as
+    the block size. A simple example of padding is:
+
+    .. doctest::
+
+        >>> padder = padding.ANSIX923(128).padder()
+        >>> padded_data = padder.update(b"11111111111111112222222222")
+        >>> padded_data
+        '1111111111111111'
+        >>> padded_data += padder.finalize()
+        >>> padded_data
+        '11111111111111112222222222\x00\x00\x00\x00\x00\x06'
+        >>> unpadder = padding.ANSIX923(128).unpadder()
+        >>> data = unpadder.update(padded_data)
+        >>> data
+        '1111111111111111'
+        >>> data + unpadder.finalize()
+        '11111111111111112222222222'
+
+    :param block_size: The size of the block in bits that the data is being
+        padded to.
+    :raises ValueError: Raised if block size is not a multiple of 8 or is not
+        between 0 and 256.
+
+    .. method:: padder()
+
+        :returns: A padding
+            :class:`~cryptography.hazmat.primitives.padding.PaddingContext`
+            provider
+
+    .. method:: unpadder()
+
+        :returns: An unpadding
+            :class:`~cryptography.hazmat.primitives.padding.PaddingContext`
+            provider.
+
+
 .. class:: PaddingContext
 
     When calling ``padder()`` or ``unpadder()`` the result will conform to the
@@ -82,3 +125,5 @@
         :raises TypeError: Raised if data is not bytes.
         :raises ValueError: When trying to remove padding from incorrectly
                             padded data.
+
+.. _`ANSI X.923`: https://en.wikipedia.org/wiki/Padding_%28cryptography%29#ANSI_X.923
diff --git a/src/_cffi_src/hazmat_src/padding.c b/src/_cffi_src/hazmat_src/padding.c
index 570bad9..1a0c869 100644
--- a/src/_cffi_src/hazmat_src/padding.c
+++ b/src/_cffi_src/hazmat_src/padding.c
@@ -37,3 +37,27 @@
     /* Now check the low bit to see if it's set */
     return (mismatch & 1) == 0;
 }
+
+uint8_t Cryptography_check_ansix923_padding(const uint8_t *data,
+                                            uint8_t block_len) {
+    uint8_t i;
+    uint8_t pad_size = data[block_len - 1];
+    uint8_t mismatch = 0;
+    /* Skip the first one with the pad size */
+    for (i = 1; i < block_len; i++) {
+        unsigned int mask = Cryptography_constant_time_lt(i, pad_size);
+        uint8_t b = data[block_len - 1 - i];
+        mismatch |= (mask & b);
+    }
+
+    /* Check to make sure the pad_size was within the valid range. */
+    mismatch |= ~Cryptography_constant_time_lt(0, pad_size);
+    mismatch |= Cryptography_constant_time_lt(block_len, pad_size);
+
+    /* Make sure any bits set are copied to the lowest bit */
+    mismatch |= mismatch >> 4;
+    mismatch |= mismatch >> 2;
+    mismatch |= mismatch >> 1;
+    /* Now check the low bit to see if it's set */
+    return (mismatch & 1) == 0;
+}
diff --git a/src/_cffi_src/hazmat_src/padding.h b/src/_cffi_src/hazmat_src/padding.h
index 4d218b1..fb023c1 100644
--- a/src/_cffi_src/hazmat_src/padding.h
+++ b/src/_cffi_src/hazmat_src/padding.h
@@ -3,3 +3,4 @@
 // repository for complete details.
 
 uint8_t Cryptography_check_pkcs7_padding(const uint8_t *, uint8_t);
+uint8_t Cryptography_check_ansix923_padding(const uint8_t *, uint8_t);
diff --git a/src/_cffi_src/openssl/dsa.py b/src/_cffi_src/openssl/dsa.py
index 89511e4..69935c1 100644
--- a/src/_cffi_src/openssl/dsa.py
+++ b/src/_cffi_src/openssl/dsa.py
@@ -22,10 +22,6 @@
     BIGNUM *pub_key;
     ...;
 } DSA;
-typedef struct {
-    BIGNUM *r;
-    BIGNUM *s;
-} DSA_SIG;
 """
 
 FUNCTIONS = """
@@ -34,10 +30,6 @@
 int DSA_generate_key(DSA *);
 DSA *DSA_new(void);
 void DSA_free(DSA *);
-DSA_SIG *DSA_SIG_new(void);
-void DSA_SIG_free(DSA_SIG *);
-int i2d_DSA_SIG(const DSA_SIG *, unsigned char **);
-DSA_SIG *d2i_DSA_SIG(DSA_SIG **, const unsigned char **, long);
 int DSA_size(const DSA *);
 int DSA_sign(int, const unsigned char *, int, unsigned char *, unsigned int *,
              DSA *);
diff --git a/src/cryptography/hazmat/primitives/padding.py b/src/cryptography/hazmat/primitives/padding.py
index f6491eb..77fb8f8 100644
--- a/src/cryptography/hazmat/primitives/padding.py
+++ b/src/cryptography/hazmat/primitives/padding.py
@@ -28,14 +28,75 @@
         """
 
 
+def _byte_padding_check(block_size):
+    if not (0 <= block_size < 256):
+        raise ValueError("block_size must be in range(0, 256).")
+
+    if block_size % 8 != 0:
+        raise ValueError("block_size must be a multiple of 8.")
+
+
+def _byte_padding_update(buffer_, data, block_size):
+    if buffer_ is None:
+        raise AlreadyFinalized("Context was already finalized.")
+
+    if not isinstance(data, bytes):
+        raise TypeError("data must be bytes.")
+
+    buffer_ += data
+
+    finished_blocks = len(buffer_) // (block_size // 8)
+
+    result = buffer_[:finished_blocks * (block_size // 8)]
+    buffer_ = buffer_[finished_blocks * (block_size // 8):]
+
+    return buffer_, result
+
+
+def _byte_padding_pad(buffer_, block_size, paddingfn):
+    if buffer_ is None:
+        raise AlreadyFinalized("Context was already finalized.")
+
+    pad_size = block_size // 8 - len(buffer_)
+    return buffer_ + paddingfn(pad_size)
+
+
+def _byte_unpadding_update(buffer_, data, block_size):
+    if buffer_ is None:
+        raise AlreadyFinalized("Context was already finalized.")
+
+    if not isinstance(data, bytes):
+        raise TypeError("data must be bytes.")
+
+    buffer_ += data
+
+    finished_blocks = max(len(buffer_) // (block_size // 8) - 1, 0)
+
+    result = buffer_[:finished_blocks * (block_size // 8)]
+    buffer_ = buffer_[finished_blocks * (block_size // 8):]
+
+    return buffer_, result
+
+
+def _byte_unpadding_check(buffer_, block_size, checkfn):
+    if buffer_ is None:
+        raise AlreadyFinalized("Context was already finalized.")
+
+    if len(buffer_) != block_size // 8:
+        raise ValueError("Invalid padding bytes.")
+
+    valid = checkfn(buffer_, block_size // 8)
+
+    if not valid:
+        raise ValueError("Invalid padding bytes.")
+
+    pad_size = six.indexbytes(buffer_, -1)
+    return buffer_[:-pad_size]
+
+
 class PKCS7(object):
     def __init__(self, block_size):
-        if not (0 <= block_size < 256):
-            raise ValueError("block_size must be in range(0, 256).")
-
-        if block_size % 8 != 0:
-            raise ValueError("block_size must be a multiple of 8.")
-
+        _byte_padding_check(block_size)
         self.block_size = block_size
 
     def padder(self):
@@ -53,27 +114,16 @@
         self._buffer = b""
 
     def update(self, data):
-        if self._buffer is None:
-            raise AlreadyFinalized("Context was already finalized.")
-
-        if not isinstance(data, bytes):
-            raise TypeError("data must be bytes.")
-
-        self._buffer += data
-
-        finished_blocks = len(self._buffer) // (self.block_size // 8)
-
-        result = self._buffer[:finished_blocks * (self.block_size // 8)]
-        self._buffer = self._buffer[finished_blocks * (self.block_size // 8):]
-
+        self._buffer, result = _byte_padding_update(
+            self._buffer, data, self.block_size)
         return result
 
-    def finalize(self):
-        if self._buffer is None:
-            raise AlreadyFinalized("Context was already finalized.")
+    def _padding(self, size):
+        return six.int2byte(size) * size
 
-        pad_size = self.block_size // 8 - len(self._buffer)
-        result = self._buffer + six.int2byte(pad_size) * pad_size
+    def finalize(self):
+        result = _byte_padding_pad(
+            self._buffer, self.block_size, self._padding)
         self._buffer = None
         return result
 
@@ -86,39 +136,67 @@
         self._buffer = b""
 
     def update(self, data):
-        if self._buffer is None:
-            raise AlreadyFinalized("Context was already finalized.")
-
-        if not isinstance(data, bytes):
-            raise TypeError("data must be bytes.")
-
-        self._buffer += data
-
-        finished_blocks = max(
-            len(self._buffer) // (self.block_size // 8) - 1,
-            0
-        )
-
-        result = self._buffer[:finished_blocks * (self.block_size // 8)]
-        self._buffer = self._buffer[finished_blocks * (self.block_size // 8):]
-
+        self._buffer, result = _byte_unpadding_update(
+            self._buffer, data, self.block_size)
         return result
 
     def finalize(self):
-        if self._buffer is None:
-            raise AlreadyFinalized("Context was already finalized.")
-
-        if len(self._buffer) != self.block_size // 8:
-            raise ValueError("Invalid padding bytes.")
-
-        valid = lib.Cryptography_check_pkcs7_padding(
-            self._buffer, self.block_size // 8
-        )
-
-        if not valid:
-            raise ValueError("Invalid padding bytes.")
-
-        pad_size = six.indexbytes(self._buffer, -1)
-        res = self._buffer[:-pad_size]
+        result = _byte_unpadding_check(
+            self._buffer, self.block_size,
+            lib.Cryptography_check_pkcs7_padding)
         self._buffer = None
-        return res
+        return result
+
+
+class ANSIX923(object):
+    def __init__(self, block_size):
+        _byte_padding_check(block_size)
+        self.block_size = block_size
+
+    def padder(self):
+        return _ANSIX923PaddingContext(self.block_size)
+
+    def unpadder(self):
+        return _ANSIX923UnpaddingContext(self.block_size)
+
+
+@utils.register_interface(PaddingContext)
+class _ANSIX923PaddingContext(object):
+    def __init__(self, block_size):
+        self.block_size = block_size
+        # TODO: more copies than necessary, we should use zero-buffer (#193)
+        self._buffer = b""
+
+    def update(self, data):
+        self._buffer, result = _byte_padding_update(
+            self._buffer, data, self.block_size)
+        return result
+
+    def _padding(self, size):
+        return six.int2byte(0) * (size - 1) + six.int2byte(size)
+
+    def finalize(self):
+        result = _byte_padding_pad(
+            self._buffer, self.block_size, self._padding)
+        self._buffer = None
+        return result
+
+
+@utils.register_interface(PaddingContext)
+class _ANSIX923UnpaddingContext(object):
+    def __init__(self, block_size):
+        self.block_size = block_size
+        # TODO: more copies than necessary, we should use zero-buffer (#193)
+        self._buffer = b""
+
+    def update(self, data):
+        self._buffer, result = _byte_unpadding_update(
+            self._buffer, data, self.block_size)
+        return result
+
+    def finalize(self):
+        result = _byte_unpadding_check(
+            self._buffer, self.block_size,
+            lib.Cryptography_check_ansix923_padding)
+        self._buffer = None
+        return result
diff --git a/tests/hazmat/primitives/test_padding.py b/tests/hazmat/primitives/test_padding.py
index 392ea73..e934c0a 100644
--- a/tests/hazmat/primitives/test_padding.py
+++ b/tests/hazmat/primitives/test_padding.py
@@ -99,3 +99,95 @@
             unpadder.update(b"")
         with pytest.raises(AlreadyFinalized):
             unpadder.finalize()
+
+
+class TestANSIX923(object):
+    @pytest.mark.parametrize("size", [127, 4096, -2])
+    def test_invalid_block_size(self, size):
+        with pytest.raises(ValueError):
+            padding.ANSIX923(size)
+
+    @pytest.mark.parametrize(("size", "padded"), [
+        (128, b"1111"),
+        (128, b"1111111111111111"),
+        (128, b"111111111111111\x06"),
+        (128, b"1111111111\x06\x06\x06\x06\x06\x06"),
+        (128, b""),
+        (128, b"\x06" * 6),
+        (128, b"\x00" * 16),
+    ])
+    def test_invalid_padding(self, size, padded):
+        unpadder = padding.ANSIX923(size).unpadder()
+        with pytest.raises(ValueError):
+            unpadder.update(padded)
+            unpadder.finalize()
+
+    def test_non_bytes(self):
+        padder = padding.ANSIX923(128).padder()
+        with pytest.raises(TypeError):
+            padder.update(u"abc")
+        unpadder = padding.ANSIX923(128).unpadder()
+        with pytest.raises(TypeError):
+            unpadder.update(u"abc")
+
+    @pytest.mark.parametrize(("size", "unpadded", "padded"), [
+        (
+            128,
+            b"1111111111",
+            b"1111111111\x00\x00\x00\x00\x00\x06",
+        ),
+        (
+            128,
+            b"111111111111111122222222222222",
+            b"111111111111111122222222222222\x00\x02",
+        ),
+        (
+            128,
+            b"1" * 16,
+            b"1" * 16 + b"\x00" * 15 + b"\x10",
+        ),
+        (
+            128,
+            b"1" * 17,
+            b"1" * 17 + b"\x00" * 14 + b"\x0F",
+        )
+    ])
+    def test_pad(self, size, unpadded, padded):
+        padder = padding.ANSIX923(size).padder()
+        result = padder.update(unpadded)
+        result += padder.finalize()
+        assert result == padded
+
+    @pytest.mark.parametrize(("size", "unpadded", "padded"), [
+        (
+            128,
+            b"1111111111",
+            b"1111111111\x00\x00\x00\x00\x00\x06",
+        ),
+        (
+            128,
+            b"111111111111111122222222222222",
+            b"111111111111111122222222222222\x00\x02",
+        ),
+    ])
+    def test_unpad(self, size, unpadded, padded):
+        unpadder = padding.ANSIX923(size).unpadder()
+        result = unpadder.update(padded)
+        result += unpadder.finalize()
+        assert result == unpadded
+
+    def test_use_after_finalize(self):
+        padder = padding.ANSIX923(128).padder()
+        b = padder.finalize()
+        with pytest.raises(AlreadyFinalized):
+            padder.update(b"")
+        with pytest.raises(AlreadyFinalized):
+            padder.finalize()
+
+        unpadder = padding.ANSIX923(128).unpadder()
+        unpadder.update(b)
+        unpadder.finalize()
+        with pytest.raises(AlreadyFinalized):
+            unpadder.update(b"")
+        with pytest.raises(AlreadyFinalized):
+            unpadder.finalize()
diff --git a/tests/hypothesis/test_padding.py b/tests/hypothesis/test_padding.py
index 21c9a23..29d726f 100644
--- a/tests/hypothesis/test_padding.py
+++ b/tests/hypothesis/test_padding.py
@@ -5,7 +5,7 @@
 from hypothesis import given
 from hypothesis.strategies import binary, integers
 
-from cryptography.hazmat.primitives.padding import PKCS7
+from cryptography.hazmat.primitives.padding import ANSIX923, PKCS7
 
 
 @given(integers(min_value=1, max_value=31), binary())
@@ -19,3 +19,14 @@
     padded = padder.update(data) + padder.finalize()
 
     assert unpadder.update(padded) + unpadder.finalize() == data
+
+
+@given(integers(min_value=1, max_value=31), binary())
+def test_ansix923(block_size, data):
+    a = ANSIX923(block_size=block_size * 8)
+    padder = a.padder()
+    unpadder = a.unpadder()
+
+    padded = padder.update(data) + padder.finalize()
+
+    assert unpadder.update(padded) + unpadder.finalize() == data