aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/_cffi_src/openssl/asn1.py1
-rw-r--r--src/_cffi_src/openssl/x509v3.py3
-rw-r--r--src/cryptography/hazmat/backends/openssl/backend.py58
-rw-r--r--tests/test_x509.py44
4 files changed, 102 insertions, 4 deletions
diff --git a/src/_cffi_src/openssl/asn1.py b/src/_cffi_src/openssl/asn1.py
index 01d6f4c2..5f8ca697 100644
--- a/src/_cffi_src/openssl/asn1.py
+++ b/src/_cffi_src/openssl/asn1.py
@@ -157,6 +157,7 @@ int ASN1_UTCTIME_check(ASN1_UTCTIME *);
int ASN1_STRING_set_default_mask_asc(char *);
int i2d_ASN1_TYPE(ASN1_TYPE *, unsigned char **);
+ASN1_TYPE *d2i_ASN1_TYPE(ASN1_TYPE **, const unsigned char **, long);
"""
CUSTOMIZATIONS = """
diff --git a/src/_cffi_src/openssl/x509v3.py b/src/_cffi_src/openssl/x509v3.py
index 0f5306d0..8e42b65d 100644
--- a/src/_cffi_src/openssl/x509v3.py
+++ b/src/_cffi_src/openssl/x509v3.py
@@ -193,6 +193,9 @@ void AUTHORITY_KEYID_free(AUTHORITY_KEYID *);
NAME_CONSTRAINTS *NAME_CONSTRAINTS_new(void);
void NAME_CONSTRAINTS_free(NAME_CONSTRAINTS *);
+OTHERNAME *OTHERNAME_new(void);
+void OTHERNAME_free(OTHERNAME *);
+
void *X509V3_set_ctx_nodb(X509V3_CTX *);
int i2d_GENERAL_NAMES(GENERAL_NAMES *, unsigned char **);
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
index d6493778..637b28cc 100644
--- a/src/cryptography/hazmat/backends/openssl/backend.py
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -83,14 +83,22 @@ def _encode_asn1_str(backend, data, length):
Create an ASN1_OCTET_STRING from a Python byte string.
"""
s = backend._lib.ASN1_OCTET_STRING_new()
+ res = backend._lib.ASN1_OCTET_STRING_set(s, data, length)
+ assert res == 1
+ return s
+
+
+def _encode_asn1_str_gc(backend, data, length):
+ s = _encode_asn1_str(backend, data, length)
s = backend._ffi.gc(s, backend._lib.ASN1_OCTET_STRING_free)
- backend._lib.ASN1_OCTET_STRING_set(s, data, length)
return s
def _encode_name(backend, attributes):
+ """
+ The X509_NAME created will not be gc'd. Use _encode_name_gc if needed.
+ """
subject = backend._lib.X509_NAME_new()
- subject = backend._ffi.gc(subject, backend._lib.X509_NAME_free)
for attribute in attributes:
value = attribute.value.encode('utf8')
obj = _txt2obj(backend, attribute.oid.dotted_string)
@@ -105,6 +113,12 @@ def _encode_name(backend, attributes):
return subject
+def _encode_name_gc(backend, attributes):
+ subject = _encode_name(backend, attributes)
+ subject = backend._ffi.gc(subject, backend._lib.X509_NAME_free)
+ return subject
+
+
def _txt2obj(backend, name):
"""
Converts a Python string with an ASN.1 object ID in dotted form to a
@@ -171,6 +185,42 @@ def _encode_subject_alt_name(backend, san):
)
assert obj != backend._ffi.NULL
gn.d.registeredID = obj
+ elif isinstance(alt_name, x509.DirectoryName):
+ gn = backend._lib.GENERAL_NAME_new()
+ assert gn != backend._ffi.NULL
+ name = _encode_name(backend, alt_name.value)
+ gn.type = backend._lib.GEN_DIRNAME
+ gn.d.directoryName = name
+ elif isinstance(alt_name, x509.IPAddress):
+ gn = backend._lib.GENERAL_NAME_new()
+ assert gn != backend._ffi.NULL
+ ipaddr = _encode_asn1_str(
+ backend, alt_name.value.packed, len(alt_name.value.packed)
+ )
+ gn.type = backend._lib.GEN_IPADD
+ gn.d.iPAddress = ipaddr
+ elif isinstance(alt_name, x509.OtherName):
+ gn = backend._lib.GENERAL_NAME_new()
+ assert gn != backend._ffi.NULL
+ other_name = backend._lib.OTHERNAME_new()
+ assert other_name != backend._ffi.NULL
+
+ type_id = backend._lib.OBJ_txt2obj(
+ alt_name.type_id.dotted_string.encode('ascii'), 1
+ )
+ assert type_id != backend._ffi.NULL
+ data = backend._ffi.new("unsigned char[]", alt_name.value)
+ data_ptr_ptr = backend._ffi.new("unsigned char **")
+ data_ptr_ptr[0] = data
+ value = backend._lib.d2i_ASN1_TYPE(
+ backend._ffi.NULL, data_ptr_ptr, len(alt_name.value)
+ )
+ if value == backend._ffi.NULL:
+ raise ValueError("Invalid ASN.1 data")
+ other_name.type_id = type_id
+ other_name.value = value
+ gn.type = backend._lib.GEN_OTHERNAME
+ gn.d.otherName = other_name
else:
raise NotImplementedError(
"Only DNSName and RegisteredID supported right now"
@@ -874,7 +924,7 @@ class Backend(object):
# Set subject name.
res = self._lib.X509_REQ_set_subject_name(
- x509_req, _encode_name(self, builder._subject_name)
+ x509_req, _encode_name_gc(self, builder._subject_name)
)
assert res == 1
@@ -905,7 +955,7 @@ class Backend(object):
self._ffi.NULL,
obj,
1 if extension.critical else 0,
- _encode_asn1_str(self, pp[0], r),
+ _encode_asn1_str_gc(self, pp[0], r),
)
assert extension != self._ffi.NULL
res = self._lib.sk_X509_EXTENSION_push(extensions, extension)
diff --git a/tests/test_x509.py b/tests/test_x509.py
index 9c97e969..cb617268 100644
--- a/tests/test_x509.py
+++ b/tests/test_x509.py
@@ -6,6 +6,7 @@ from __future__ import absolute_import, division, print_function
import binascii
import datetime
+import ipaddress
import os
import pytest
@@ -995,6 +996,18 @@ class TestCertificateSigningRequestBuilder(object):
x509.DNSName(u"example.com"),
x509.DNSName(u"*.example.com"),
x509.RegisteredID(x509.ObjectIdentifier("1.2.3.4.5.6.7")),
+ x509.DirectoryName(x509.Name([
+ x509.NameAttribute(x509.OID_COMMON_NAME, u'PyCA'),
+ x509.NameAttribute(
+ x509.OID_ORGANIZATION_NAME, u'We heart UTF8!\u2122'
+ )
+ ])),
+ x509.IPAddress(ipaddress.ip_address(u"127.0.0.1")),
+ x509.IPAddress(ipaddress.ip_address(u"ff::")),
+ x509.OtherName(
+ type_id=x509.ObjectIdentifier("1.2.3.3.3.3"),
+ value=b"0\x03\x02\x01\x05"
+ ),
]),
critical=False,
).sign(private_key, hashes.SHA256(), backend)
@@ -1009,8 +1022,39 @@ class TestCertificateSigningRequestBuilder(object):
x509.DNSName(u"example.com"),
x509.DNSName(u"*.example.com"),
x509.RegisteredID(x509.ObjectIdentifier("1.2.3.4.5.6.7")),
+ x509.DirectoryName(x509.Name([
+ x509.NameAttribute(x509.OID_COMMON_NAME, u'PyCA'),
+ x509.NameAttribute(
+ x509.OID_ORGANIZATION_NAME, u'We heart UTF8!\u2122'
+ ),
+ ])),
+ x509.IPAddress(ipaddress.ip_address(u"127.0.0.1")),
+ x509.IPAddress(ipaddress.ip_address(u"ff::")),
+ x509.OtherName(
+ type_id=x509.ObjectIdentifier("1.2.3.3.3.3"),
+ value=b"0\x03\x02\x01\x05"
+ ),
]
+ def test_invalid_asn1_othername(self, backend):
+ private_key = RSA_KEY_2048.private_key(backend)
+
+ builder = x509.CertificateSigningRequestBuilder().subject_name(
+ x509.Name([
+ x509.NameAttribute(x509.OID_COMMON_NAME, u"SAN"),
+ ])
+ ).add_extension(
+ x509.SubjectAlternativeName([
+ x509.OtherName(
+ type_id=x509.ObjectIdentifier("1.2.3.3.3.3"),
+ value=b"\x01\x02\x01\x05"
+ ),
+ ]),
+ critical=False,
+ )
+ with pytest.raises(ValueError):
+ builder.sign(private_key, hashes.SHA256(), backend)
+
def test_subject_alt_name_unsupported_general_name(self, backend):
private_key = RSA_KEY_2048.private_key(backend)