All of X509Tests passing !
diff --git a/OpenSSL/crypto.py b/OpenSSL/crypto.py
index 4f12916..f0ceeb3 100644
--- a/OpenSSL/crypto.py
+++ b/OpenSSL/crypto.py
@@ -275,6 +275,63 @@
X509NameType = X509Name
+class X509Extension(object):
+ def __init__(self, type_name, critical, value, subject=None, issuer=None):
+ """
+ :param typename: The name of the extension to create.
+ :type typename: :py:data:`str`
+
+ :param critical: A flag indicating whether this is a critical extension.
+
+ :param value: The value of the extension.
+ :type value: :py:data:`str`
+
+ :param subject: Optional X509 cert to use as subject.
+ :type subject: :py:class:`X509`
+
+ :param issuer: Optional X509 cert to use as issuer.
+ :type issuer: :py:class:`X509`
+
+ :return: The X509Extension object
+ """
+ ctx = _api.new("X509V3_CTX*")
+ _api.X509V3_set_ctx(ctx, _api.NULL, _api.NULL, _api.NULL, _api.NULL, 0)
+ _api.X509V3_set_ctx_nodb(ctx)
+
+ if critical:
+ # There are other OpenSSL APIs which would let us pass in critical
+ # separately, but they're harder to use, and since value is already
+ # a pile of crappy junk smuggling a ton of utterly important
+ # structured data, what's the point of trying to avoid nasty stuff
+ # with strings? (However, X509V3_EXT_i2d in particular seems like it
+ # would be a better API to invoke. I do not know where to get the
+ # ext_struc it desires for its last parameter, though.)
+ value = "critical," + value
+
+ self._extension = _api.X509V3_EXT_nconf(
+ _api.NULL, ctx, type_name, value)
+
+
+ def get_critical(self):
+ """
+ Returns the critical field of the X509Extension
+
+ :return: The critical field.
+ """
+ return _api.X509_EXTENSION_get_critical(self._extension)
+
+
+ def get_short_name(self):
+ """
+ Returns the short version of the type name of the X509Extension
+
+ :return: The short type name.
+ """
+ obj = _api.X509_EXTENSION_get_object(self._extension)
+ nid = _api.OBJ_obj2nid(obj)
+ return _api.string(_api.OBJ_nid2sn(nid))
+
+
class X509(object):
def __init__(self):
@@ -631,6 +688,8 @@
def _set_name(self, which, name):
+ if not isinstance(name, X509Name):
+ raise TypeError("name must be an X509Name")
set_result = which(self._x509, name._name)
if not set_result:
1/0
@@ -675,6 +734,48 @@
:return: None
"""
return self._set_name(_api.X509_set_subject_name, subject)
+
+
+ def get_extension_count(self):
+ """
+ Get the number of extensions on the certificate.
+
+ :return: The number of extensions as an integer.
+ """
+ return _api.X509_get_ext_count(self._x509)
+
+
+ def add_extensions(self, extensions):
+ """
+ Add extensions to the certificate.
+
+ :param extensions: a sequence of X509Extension objects
+ :return: None
+ """
+ for ext in extensions:
+ if not isinstance(ext, X509Extension):
+ raise ValueError("One of the elements is not an X509Extension")
+
+ add_result = _api.X509_add_ext(self._x509, ext._extension, -1)
+ if not add_result:
+ _raise_current_error()
+
+
+ def get_extension(self, index):
+ """
+ Get a specific extension of the certificate by index.
+
+ :param index: The index of the extension to retrieve.
+ :return: The X509Extension object at the specified index.
+ """
+ ext = X509Extension.__new__(X509Extension)
+ ext._extension = _api.X509_get_ext(self._x509, index)
+ if ext._extension == _api.NULL:
+ raise IndexError("extension index out of bounds")
+
+ ext._extension = _api.X509_EXTENSION_dup(ext._extension)
+ return ext
+
X509Type = X509