diff options
author | Andre Caron <andre.l.caron@gmail.com> | 2015-05-18 10:23:28 -0400 |
---|---|---|
committer | Andre Caron <andre.l.caron@gmail.com> | 2015-05-18 10:25:30 -0400 |
commit | 476c5df3f12967b397a3e02e303db774cfa95915 (patch) | |
tree | 1872dff9ebd507e8c7ae304f693a0a7b0e9e469c | |
parent | 0b0179f7311162084f2b8dc6a028e301ca2eb7b2 (diff) | |
download | cryptography-476c5df3f12967b397a3e02e303db774cfa95915.tar.gz cryptography-476c5df3f12967b397a3e02e303db774cfa95915.tar.bz2 cryptography-476c5df3f12967b397a3e02e303db774cfa95915.zip |
Adds support for writing CSRs.
-rw-r--r-- | docs/x509.rst | 11 | ||||
-rw-r--r-- | src/cryptography/hazmat/backends/openssl/x509.py | 19 | ||||
-rw-r--r-- | src/cryptography/x509.py | 6 | ||||
-rw-r--r-- | tests/test_x509.py | 66 |
4 files changed, 100 insertions, 2 deletions
diff --git a/docs/x509.rst b/docs/x509.rst index 850e3df1..8e762ef1 100644 --- a/docs/x509.rst +++ b/docs/x509.rst @@ -366,6 +366,17 @@ X.509 CSR (Certificate Signing Request) Object >>> isinstance(csr.signature_hash_algorithm, hashes.SHA1) True + .. method:: public_bytes(encoding) + + :param encoding: The + :class:`~cryptography.hazmat.primitives.serialization.Encoding` + that will be used to serialize the certificate request. + + :return bytes: The data that can be written to a file or sent + over the network to be signed by the certificate + authority. + + .. class:: Name .. versionadded:: 0.8 diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index 6db6fc9c..67d0d51a 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -25,7 +25,7 @@ from six.moves import urllib_parse from cryptography import utils, x509 from cryptography.exceptions import UnsupportedAlgorithm -from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives import hashes, serialization def _obj2txt(backend, obj): @@ -689,3 +689,20 @@ class _CertificateSigningRequest(object): extensions.append(x509.Extension(oid, critical, value)) return x509.Extensions(extensions) + + def public_bytes(self, encoding): + if not isinstance(encoding, serialization.Encoding): + raise TypeError("encoding must be an item from the Encoding enum") + + # TODO: make text prelude optional. + bio = self._backend._create_mem_bio() + if encoding is serialization.Encoding.PEM: + res = self._backend._lib.X509_REQ_print(bio, self._x509_req) + assert res == 1 + res = self._backend._lib.PEM_write_bio_X509_REQ( + bio, self._x509_req + ) + elif encoding is serialization.Encoding.DER: + res = self._backend._lib.i2d_X509_REQ_bio(bio, self._x509_req) + assert res == 1 + return self._backend._read_mem_bio(bio) diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py index ccb9f6de..c449b7ed 100644 --- a/src/cryptography/x509.py +++ b/src/cryptography/x509.py @@ -1190,3 +1190,9 @@ class CertificateSigningRequest(object): """ Returns the extensions in the signing request. """ + + @abc.abstractmethod + def public_bytes(self, encoding): + """ + Encodes the request to PEM or DER format. + """ diff --git a/tests/test_x509.py b/tests/test_x509.py index 47c1c647..bef761e5 100644 --- a/tests/test_x509.py +++ b/tests/test_x509.py @@ -15,7 +15,7 @@ from cryptography.exceptions import UnsupportedAlgorithm from cryptography.hazmat.backends.interfaces import ( DSABackend, EllipticCurveBackend, RSABackend, X509Backend ) -from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa from .hazmat.primitives.test_ec import _skip_curve_unsupported @@ -471,6 +471,70 @@ class TestRSACertificate(object): ), ] + def test_encode_pem(self, backend): + # Load an existing CSR. + request = _load_cert( + os.path.join("x509", "requests", "rsa_sha1.pem"), + x509.load_pem_x509_csr, + backend + ) + + # Encode it to PEM and load it back. + request = x509.load_pem_x509_csr(request.public_bytes( + encoding=serialization.Encoding.PEM, + ), backend) + + # We should recover what we had to start with. + assert isinstance(request.signature_hash_algorithm, hashes.SHA1) + public_key = request.public_key() + assert isinstance(public_key, rsa.RSAPublicKey) + subject = request.subject + assert isinstance(subject, x509.Name) + assert list(subject) == [ + x509.NameAttribute(x509.OID_COUNTRY_NAME, 'US'), + x509.NameAttribute(x509.OID_STATE_OR_PROVINCE_NAME, 'Texas'), + x509.NameAttribute(x509.OID_LOCALITY_NAME, 'Austin'), + x509.NameAttribute(x509.OID_ORGANIZATION_NAME, 'PyCA'), + x509.NameAttribute(x509.OID_COMMON_NAME, 'cryptography.io'), + ] + + def test_encode_der(self, backend): + # Load an existing CSR. + request = _load_cert( + os.path.join("x509", "requests", "rsa_sha1.pem"), + x509.load_pem_x509_csr, + backend + ) + + # Encode it to DER and load it back. + request = x509.load_der_x509_csr(request.public_bytes( + encoding=serialization.Encoding.DER, + ), backend) + + # We should recover what we had to start with. + assert isinstance(request.signature_hash_algorithm, hashes.SHA1) + public_key = request.public_key() + assert isinstance(public_key, rsa.RSAPublicKey) + subject = request.subject + assert isinstance(subject, x509.Name) + assert list(subject) == [ + x509.NameAttribute(x509.OID_COUNTRY_NAME, 'US'), + x509.NameAttribute(x509.OID_STATE_OR_PROVINCE_NAME, 'Texas'), + x509.NameAttribute(x509.OID_LOCALITY_NAME, 'Austin'), + x509.NameAttribute(x509.OID_ORGANIZATION_NAME, 'PyCA'), + x509.NameAttribute(x509.OID_COMMON_NAME, 'cryptography.io'), + ] + + def test_encode_invalid_encoding(self, backend): + request = _load_cert( + os.path.join("x509", "requests", "rsa_sha1.pem"), + x509.load_pem_x509_csr, + backend + ) + + with pytest.raises(TypeError): + request.public_bytes('NotAnEncoding') + @pytest.mark.requires_backend_interface(interface=DSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) |