aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndre Caron <andre.l.caron@gmail.com>2015-05-18 10:23:28 -0400
committerAndre Caron <andre.l.caron@gmail.com>2015-05-18 10:25:30 -0400
commit476c5df3f12967b397a3e02e303db774cfa95915 (patch)
tree1872dff9ebd507e8c7ae304f693a0a7b0e9e469c
parent0b0179f7311162084f2b8dc6a028e301ca2eb7b2 (diff)
downloadcryptography-476c5df3f12967b397a3e02e303db774cfa95915.tar.gz
cryptography-476c5df3f12967b397a3e02e303db774cfa95915.tar.bz2
cryptography-476c5df3f12967b397a3e02e303db774cfa95915.zip
Adds support for writing CSRs.
-rw-r--r--docs/x509.rst11
-rw-r--r--src/cryptography/hazmat/backends/openssl/x509.py19
-rw-r--r--src/cryptography/x509.py6
-rw-r--r--tests/test_x509.py66
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)