aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Kehrer <paul.l.kehrer@gmail.com>2016-11-13 14:30:11 -0800
committerAlex Gaynor <alex.gaynor@gmail.com>2016-11-13 17:30:11 -0500
commit3a15b03e92c9fdeadff04ddd2ce505028b279b86 (patch)
treee314732deed27d3f3f4dba9b4c1f40dcca3e54fa
parentd862933de5c344fcdf99ab2f43f3bf8da65f3e41 (diff)
downloadcryptography-3a15b03e92c9fdeadff04ddd2ce505028b279b86.tar.gz
cryptography-3a15b03e92c9fdeadff04ddd2ce505028b279b86.tar.bz2
cryptography-3a15b03e92c9fdeadff04ddd2ce505028b279b86.zip
Add a bytes method to get the DER ASN.1 encoding of an X509 name. (#3236)
* Add a bytes method to get the DER ASN.1 encoding of an X509 name. This is useful for creating an OpenSSL style subject_name_hash (#3011) * add to backend interface and update multibackend * bytes -> public_bytes
-rw-r--r--CHANGELOG.rst1
-rw-r--r--docs/hazmat/backends/interfaces.rst8
-rw-r--r--docs/x509/reference.rst10
-rw-r--r--src/cryptography/hazmat/backends/interfaces.py6
-rw-r--r--src/cryptography/hazmat/backends/multibackend.py9
-rw-r--r--src/cryptography/hazmat/backends/openssl/backend.py11
-rw-r--r--src/cryptography/x509/name.py3
-rw-r--r--tests/hazmat/backends/test_multibackend.py6
-rw-r--r--tests/test_x509.py11
9 files changed, 65 insertions, 0 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 1c92cebf..9ca4c120 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -26,6 +26,7 @@ Changelog
:meth:`~cryptography.x509.random_serial_number`.
* Added support for encoding ``IPv4Network`` and ``IPv6Network`` in X.509
certificates for use with :class:`~cryptography.x509.NameConstraints`.
+* Added :meth:`~cryptography.x509.Name.public_bytes`.
* Added :class:`~cryptography.x509.RelativeDistinguishedName`
* :class:`~cryptography.x509.DistributionPoint` now accepts
:class:`~cryptography.x509.RelativeDistinguishedName` for
diff --git a/docs/hazmat/backends/interfaces.rst b/docs/hazmat/backends/interfaces.rst
index 0a0d1456..942a359c 100644
--- a/docs/hazmat/backends/interfaces.rst
+++ b/docs/hazmat/backends/interfaces.rst
@@ -585,6 +585,14 @@ A specific ``backend`` may provide one or more of these interfaces.
:returns: A new instance of
:class:`~cryptography.x509.RevokedCertificate`.
+ .. method:: x509_name_bytes(name)
+
+ .. versionadded:: 1.6
+
+ :param name: An instance of :class:`~cryptography.x509.Name`.
+
+ :return bytes: The DER encoded bytes.
+
.. class:: DHBackend
.. versionadded:: 0.9
diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst
index bc408ae6..d3e72c0a 100644
--- a/docs/x509/reference.rst
+++ b/docs/x509/reference.rst
@@ -1142,6 +1142,16 @@ X.509 CSR (Certificate Signing Request) Builder Object
>>> cert.subject.get_attributes_for_oid(NameOID.COMMON_NAME)
[<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.3, name=commonName)>, value=u'Good CA')>]
+ .. method:: public_bytes(backend)
+
+ .. versionadded:: 1.6
+
+ :param backend: A backend supporting the
+ :class:`~cryptography.hazmat.backends.interfaces.X509Backend`
+ interface.
+
+ :return bytes: The DER encoded name.
+
.. class:: Version
.. versionadded:: 0.7
diff --git a/src/cryptography/hazmat/backends/interfaces.py b/src/cryptography/hazmat/backends/interfaces.py
index ad4a4364..7417f6ca 100644
--- a/src/cryptography/hazmat/backends/interfaces.py
+++ b/src/cryptography/hazmat/backends/interfaces.py
@@ -312,6 +312,12 @@ class X509Backend(object):
object.
"""
+ @abc.abstractmethod
+ def x509_name_bytes(self, name):
+ """
+ Compute the DER encoded bytes of an X509 Name object.
+ """
+
@six.add_metaclass(abc.ABCMeta)
class DHBackend(object):
diff --git a/src/cryptography/hazmat/backends/multibackend.py b/src/cryptography/hazmat/backends/multibackend.py
index ab9127f7..36a83537 100644
--- a/src/cryptography/hazmat/backends/multibackend.py
+++ b/src/cryptography/hazmat/backends/multibackend.py
@@ -424,6 +424,15 @@ class MultiBackend(object):
_Reasons.UNSUPPORTED_X509
)
+ def x509_name_bytes(self, name):
+ for b in self._filtered_backends(X509Backend):
+ return b.x509_name_bytes(name)
+
+ raise UnsupportedAlgorithm(
+ "This backend does not support X.509.",
+ _Reasons.UNSUPPORTED_X509
+ )
+
def derive_scrypt(self, key_material, salt, length, n, r, p):
for b in self._filtered_backends(ScryptBackend):
return b.derive_scrypt(key_material, salt, length, n, r, p)
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
index 79914293..b8e407b0 100644
--- a/src/cryptography/hazmat/backends/openssl/backend.py
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -1729,6 +1729,17 @@ class Backend(object):
serialization._ssh_write_string(public_numbers.encode_point())
)
+ def x509_name_bytes(self, name):
+ x509_name = _encode_name_gc(self, name)
+ pp = self._ffi.new("unsigned char **")
+ res = self._lib.i2d_X509_NAME(x509_name, pp)
+ self.openssl_assert(pp[0] != self._ffi.NULL)
+ pp = self._ffi.gc(
+ pp, lambda pointer: self._lib.OPENSSL_free(pointer[0])
+ )
+ self.openssl_assert(res > 0)
+ return self._ffi.buffer(pp[0], res)[:]
+
def derive_scrypt(self, key_material, salt, length, n, r, p):
buf = self._ffi.new("unsigned char[]", length)
res = self._lib.EVP_PBE_scrypt(key_material, len(key_material), salt,
diff --git a/src/cryptography/x509/name.py b/src/cryptography/x509/name.py
index fedfd78f..277128fa 100644
--- a/src/cryptography/x509/name.py
+++ b/src/cryptography/x509/name.py
@@ -109,6 +109,9 @@ class Name(object):
def rdns(self):
return self._attributes
+ def public_bytes(self, backend):
+ return backend.x509_name_bytes(self)
+
def __eq__(self, other):
if not isinstance(other, Name):
return NotImplemented
diff --git a/tests/hazmat/backends/test_multibackend.py b/tests/hazmat/backends/test_multibackend.py
index 319edf7d..7ffc4236 100644
--- a/tests/hazmat/backends/test_multibackend.py
+++ b/tests/hazmat/backends/test_multibackend.py
@@ -240,6 +240,9 @@ class DummyX509Backend(object):
def create_x509_revoked_certificate(self, builder):
pass
+ def x509_name_bytes(self, name):
+ pass
+
@utils.register_interface(ScryptBackend)
class DummyScryptBackend(object):
@@ -554,6 +557,7 @@ class TestMultiBackend(object):
backend.create_x509_certificate(object(), b"privatekey", hashes.SHA1())
backend.create_x509_crl(object(), b"privatekey", hashes.SHA1())
backend.create_x509_revoked_certificate(object())
+ backend.x509_name_bytes(object())
backend = MultiBackend([DummyBackend()])
with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_X509):
@@ -580,6 +584,8 @@ class TestMultiBackend(object):
)
with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_X509):
backend.create_x509_revoked_certificate(object())
+ with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_X509):
+ backend.x509_name_bytes(object())
def test_scrypt(self):
backend = MultiBackend([DummyScryptBackend()])
diff --git a/tests/test_x509.py b/tests/test_x509.py
index f375ac55..5d334242 100644
--- a/tests/test_x509.py
+++ b/tests/test_x509.py
@@ -3842,6 +3842,17 @@ class TestName(object):
with pytest.raises(TypeError):
x509.Name(["not-a-NameAttribute"])
+ @pytest.mark.requires_backend_interface(interface=X509Backend)
+ def test_bytes(self, backend):
+ name = x509.Name([
+ x509.NameAttribute(NameOID.COMMON_NAME, u'cryptography.io'),
+ x509.NameAttribute(NameOID.ORGANIZATION_NAME, u'PyCA'),
+ ])
+ assert name.public_bytes(backend) == binascii.unhexlify(
+ b"30293118301606035504030c0f63727970746f6772617068792e696f310d300"
+ b"b060355040a0c0450794341"
+ )
+
def test_random_serial_number(monkeypatch):
sample_data = os.urandom(20)