summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurens Van Houtven <_@lvh.io>2015-05-13 08:06:04 -0700
committerLaurens Van Houtven <_@lvh.io>2015-05-13 08:06:04 -0700
commite862023f212cfc59f564d02651c2e7280c991019 (patch)
tree4a06ce7262f98753e096f6c5b11fbc72b4cdd4e1
parentf7e552d0224e7bd904923d1b32a93356db105102 (diff)
parente9ae673b3999344a5aaa121bfe6925d172b61c13 (diff)
downloadpyopenssl-e862023f212cfc59f564d02651c2e7280c991019.tar.gz
Merge branch 'master' into test-metadata
-rw-r--r--.gitignore2
-rw-r--r--.travis.yml43
-rw-r--r--ChangeLog7
-rw-r--r--MANIFEST.in5
-rw-r--r--OpenSSL/__init__.py13
-rw-r--r--OpenSSL/crypto.py607
-rw-r--r--OpenSSL/version.py15
-rw-r--r--README.rst14
-rw-r--r--TODO8
-rw-r--r--doc/api/crypto.rst718
-rw-r--r--doc/conf.py39
-rw-r--r--examples/certgen.py12
-rw-r--r--examples/mk_simple_certs.py23
-rw-r--r--examples/simple/client.py13
-rw-r--r--examples/simple/server.py29
-rwxr-xr-xsetup.py127
-rw-r--r--tox.ini15
17 files changed, 758 insertions, 932 deletions
diff --git a/.gitignore b/.gitignore
index 288f2ad..7b18379 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,5 @@ __pycache__
doc/_build/
.coverage
.eggs
+examples/simple/*.cert
+examples/simple/*.pkey
diff --git a/.travis.yml b/.travis.yml
index c244622..0354895 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -10,33 +10,24 @@ matrix:
env: TOXENV=py26
- python: "2.7"
env: TOXENV=py27
- - python: "3.2"
- env: TOXENV=py32
- python: "3.3"
env: TOXENV=py33
- python: "3.4"
env: TOXENV=py34
- python: "pypy"
env: TOXENV=pypy
+
# Also run the tests against cryptography master.
- python: "2.6"
- env:
- CRYPTOGRAPHY_GIT_MASTER=true TOXENV=py26
+ env: TOXENV=py26-cryptographyMaster
- python: "2.7"
- env:
- CRYPTOGRAPHY_GIT_MASTER=true TOXENV=py27
- - python: "3.2"
- env:
- CRYPTOGRAPHY_GIT_MASTER=true TOXENV=py32
+ env: TOXENV=py27-cryptographyMaster
- python: "3.3"
- env:
- CRYPTOGRAPHY_GIT_MASTER=true TOXENV=py33
+ env: TOXENV=py33-cryptographyMaster
- python: "3.4"
- env:
- CRYPTOGRAPHY_GIT_MASTER=true TOXENV=py34
+ env: TOXENV=py34-cryptographyMaster
- python: "pypy"
- env:
- CRYPTOGRAPHY_GIT_MASTER=true TOXENV=pypy
+ env: TOXENV=pypy-cryptographyMaster
# Also run at least a little bit against an older version of OpenSSL.
- python: "2.7"
@@ -49,6 +40,14 @@ matrix:
packages:
- libssl-dev/lucid
+ # Meta
+ - python: "2.7"
+ env: TOXENV=check-manifest
+
+ - python: "2.7"
+ env: TOXENV=pypi-readme
+
+
# Let the cryptography master builds fail because they might be triggered by
# cryptography changes beyond our control.
# Also allow OS X and 0.9.8 to fail at the moment while we fix these new
@@ -57,17 +56,13 @@ matrix:
- language: generic
os: osx
env: TOXENV=py27
- - env: CRYPTOGRAPHY_GIT_MASTER=true TOXENV=py26
- - env: CRYPTOGRAPHY_GIT_MASTER=true TOXENV=py27
- - env: CRYPTOGRAPHY_GIT_MASTER=true TOXENV=py32
- - env: CRYPTOGRAPHY_GIT_MASTER=true TOXENV=py33
- - env: CRYPTOGRAPHY_GIT_MASTER=true TOXENV=py34
- - env: CRYPTOGRAPHY_GIT_MASTER=true TOXENV=pypy
+ - env: TOXENV=py26-cryptographyMaster
+ - env: TOXENV=py27-cryptographyMaster
+ - env: TOXENV=py33-cryptographyMaster
+ - env: TOXENV=py34-cryptographyMaster
+ - env: TOXENV=pypy-cryptographyMaster
- env: OPENSSL=0.9.8 TOXENV=py27
-before_install:
- - if [ -n "$CRYPTOGRAPHY_GIT_MASTER" ]; then pip install git+https://github.com/pyca/cryptography.git;fi
-
install:
- |
if [[ "$(uname -s)" == 'Darwin' ]]; then
diff --git a/ChangeLog b/ChangeLog
index 61bfa5d..ae02ef3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2015-05-02 Jim Shaver <dcypherd@gmail.com>
+
+ * .travis.yml, setup.py, tox.ini: Removed support for Python 3.2.
+ This version is rarely used and is now deprecated by a major
+ dependency of pyOpenSSL (cryptography). Affected users should upgrade
+ to Python 3.3+.
+
2015-04-15 Paul Kehrer <paul.l.kehrer@gmail.com>
* OpenSSL/crypto.py, OpenSSL/test/test_crypto.py: Switch to utf8string
diff --git a/MANIFEST.in b/MANIFEST.in
index 455af6d..7b6f3e7 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,8 +1,7 @@
-include LICENSE ChangeLog TODO MANIFEST.in OpenSSL/RATIONALE *.rst tox.ini memdbg.py runtests.py OpenSSL/test/README
-exclude leakcheck
+include LICENSE ChangeLog MANIFEST.in *.rst tox.ini memdbg.py runtests.py OpenSSL/test/README
+exclude leakcheck
recursive-include doc *
recursive-include examples *
recursive-include rpm *
recursive-exclude leakcheck *.py *.pem
-global-exclude *.pyc
prune doc/_build
diff --git a/OpenSSL/__init__.py b/OpenSSL/__init__.py
index db96e1f..fde6fa7 100644
--- a/OpenSSL/__init__.py
+++ b/OpenSSL/__init__.py
@@ -6,7 +6,16 @@ pyOpenSSL - A simple wrapper around the OpenSSL library
"""
from OpenSSL import rand, crypto, SSL
-from OpenSSL.version import __version__
+from OpenSSL.version import (
+ __author__, __copyright__, __email__, __license__, __summary__, __title__,
+ __uri__, __version__,
+)
+
+
__all__ = [
- 'rand', 'crypto', 'SSL', 'tsafe', '__version__']
+ "SSL", "crypto", "rand", "tsafe",
+
+ "__author__", "__copyright__", "__email__", "__license__", "__summary__",
+ "__title__", "__uri__", "__version__",
+]
diff --git a/OpenSSL/crypto.py b/OpenSSL/crypto.py
index c7bdabc..7bb2910 100644
--- a/OpenSSL/crypto.py
+++ b/OpenSSL/crypto.py
@@ -159,6 +159,9 @@ def _get_asn1_time(timestamp):
class PKey(object):
+ """
+ A class representing an DSA or RSA public key or key pair.
+ """
_only_public = False
_initialized = True
@@ -170,12 +173,19 @@ class PKey(object):
def generate_key(self, type, bits):
"""
- Generate a key of a given type, with a given number of a bits
+ Generate a key pair of the given type, with the given number of bits.
- :param type: The key type (TYPE_RSA or TYPE_DSA)
- :param bits: The number of bits
+ This generates a key "into" the this object.
- :return: None
+ :param type: The key type.
+ :type type: :py:data:`TYPE_RSA` or :py:data:`TYPE_DSA`
+ :param bits: The number of bits.
+ :type bits: :py:data:`int` ``>= 0``
+ :raises TypeError: If :py:data:`type` or :py:data:`bits` isn't
+ of the appropriate type.
+ :raises ValueError: If the number of bits isn't an integer of
+ the appropriate size.
+ :return: :py:const:`None`
"""
if not isinstance(type, int):
raise TypeError("type must be an integer")
@@ -232,6 +242,8 @@ class PKey(object):
"""
Check the consistency of an RSA private key.
+ This is the Python equivalent of OpenSSL's ``RSA_check_key``.
+
:return: True if key is consistent.
:raise Error: if the key is inconsistent.
:raise TypeError: if the key is of a type which cannot be checked.
@@ -422,11 +434,35 @@ def get_elliptic_curve(name):
class X509Name(object):
+ """
+ An X.509 Distinguished Name.
+
+ :ivar countryName: The country of the entity.
+ :ivar C: Alias for :py:attr:`countryName`.
+
+ :ivar stateOrProvinceName: The state or province of the entity.
+ :ivar ST: Alias for :py:attr:`stateOrProvinceName`.
+
+ :ivar localityName: The locality of the entity.
+ :ivar L: Alias for :py:attr:`localityName`.
+
+ :ivar organizationName: The organization name of the entity.
+ :ivar O: Alias for :py:attr:`organizationName`.
+
+ :ivar organizationalUnitName: The organizational unit of the entity.
+ :ivar OU: Alias for :py:attr:`organizationalUnitName`
+
+ :ivar commonName: The common name of the entity.
+ :ivar CN: Alias for :py:attr:`commonName`.
+
+ :ivar emailAddress: The e-mail address of the entity.
+ """
def __init__(self, name):
"""
Create a new X509Name, copying the given X509Name instance.
- :param name: An X509Name object to copy
+ :param name: The name to copy.
+ :type name: :py:class:`X509Name`
"""
name = _lib.X509_NAME_dup(name._name)
self._name = _ffi.gc(name, _lib.X509_NAME_free)
@@ -545,19 +581,23 @@ class X509Name(object):
def hash(self):
"""
- Return the hash value of this name
+ Return an integer representation of the first four bytes of the
+ MD5 digest of the DER representation of the name.
+
+ This is the Python equivalent of OpenSSL's ``X509_NAME_hash``.
- :return: None
+ :return: The (integer) hash of this name.
+ :rtype: :py:class:`int`
"""
return _lib.X509_NAME_hash(self._name)
def der(self):
"""
- Return the DER encoding of this name
+ Return the DER encoding of this name.
- :return: A :py:class:`bytes` instance giving the DER encoded form of
- this name.
+ :return: The DER encoded form of this name.
+ :rtype: :py:class:`bytes`
"""
result_buffer = _ffi.new('unsigned char**')
encode_result = _lib.i2d_X509_NAME(self._name, result_buffer)
@@ -572,9 +612,10 @@ class X509Name(object):
def get_components(self):
"""
- Returns the split-up components of this name.
+ Returns the components of this name, as a sequence of 2-tuples.
- :return: List of tuples (name, value).
+ :return: The components of this name.
+ :rtype: :py:class:`list` of ``name, value`` tuples.
"""
result = []
for i in range(_lib.X509_NAME_entry_count(self._name)):
@@ -593,27 +634,35 @@ class X509Name(object):
_lib.ASN1_STRING_length(fval))))
return result
+
+
+
X509NameType = X509Name
+
class X509Extension(object):
+ """
+ An X.509 v3 certificate extension.
+ """
def __init__(self, type_name, critical, value, subject=None, issuer=None):
"""
- :param typename: The name of the extension to create.
+ Initializes an X509 extension.
+
+ :param typename: The name of the type of extension to create. See
+ http://openssl.org/docs/apps/x509v3_config.html#STANDARD_EXTENSIONS
:type typename: :py:data:`str`
- :param critical: A flag indicating whether this is a critical extension.
+ :param bool 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.
+ :param subject: Optional X509 certificate to use as subject.
:type subject: :py:class:`X509`
- :param issuer: Optional X509 cert to use as issuer.
+ :param issuer: Optional X509 certificate to use as issuer.
:type issuer: :py:class:`X509`
-
- :return: The X509Extension object
"""
ctx = _ffi.new("X509V3_CTX*")
@@ -684,6 +733,7 @@ class X509Extension(object):
"GENERAL_NAMES*",
method.d2i(_ffi.NULL, payloadptr, length))
+ names = _ffi.gc(names, _lib.GENERAL_NAMES_free)
parts = []
for i in range(_lib.sk_GENERAL_NAME_num(names)):
name = _lib.sk_GENERAL_NAME_value(names, i)
@@ -718,7 +768,7 @@ class X509Extension(object):
def get_critical(self):
"""
- Returns the critical field of the X509Extension
+ Returns the critical field of this X.509 extension.
:return: The critical field.
"""
@@ -727,9 +777,14 @@ class X509Extension(object):
def get_short_name(self):
"""
- Returns the short version of the type name of the X509Extension
+ Returns the short type name of this X.509 extension.
+
+ The result is a byte string such as :py:const:`b"basicConstraints"`.
:return: The short type name.
+ :rtype: :py:data:`bytes`
+
+ .. versionadded:: 0.12
"""
obj = _lib.X509_EXTENSION_get_object(self._extension)
nid = _lib.OBJ_obj2nid(obj)
@@ -738,9 +793,12 @@ class X509Extension(object):
def get_data(self):
"""
- Returns the data of the X509Extension
+ Returns the data of the X509 extension, encoded as ASN.1.
- :return: A :py:data:`str` giving the X509Extension's ASN.1 encoded data.
+ :return: The ASN.1 encoded data of this X509 extension.
+ :rtype: :py:data:`bytes`
+
+ .. versionadded:: 0.12
"""
octet_result = _lib.X509_EXTENSION_get_data(self._extension)
string_result = _ffi.cast('ASN1_STRING*', octet_result)
@@ -748,10 +806,16 @@ class X509Extension(object):
result_length = _lib.ASN1_STRING_length(string_result)
return _ffi.buffer(char_result, result_length)[:]
+
+
X509ExtensionType = X509Extension
+
class X509Req(object):
+ """
+ An X.509 certificate signing requests.
+ """
def __init__(self):
req = _lib.X509_REQ_new()
self._req = _ffi.gc(req, _lib.X509_REQ_free)
@@ -759,10 +823,12 @@ class X509Req(object):
def set_pubkey(self, pkey):
"""
- Set the public key of the certificate request
+ Set the public key of the certificate signing request.
- :param pkey: The public key to use
- :return: None
+ :param pkey: The public key to use.
+ :type pkey: :py:class:`PKey`
+
+ :return: :py:const:`None`
"""
set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey)
if not set_result:
@@ -772,9 +838,10 @@ class X509Req(object):
def get_pubkey(self):
"""
- Get the public key from the certificate request
+ Get the public key of the certificate signing request.
- :return: The public key
+ :return: The public key.
+ :rtype: :py:class:`PKey`
"""
pkey = PKey.__new__(PKey)
pkey._pkey = _lib.X509_REQ_get_pubkey(self._req)
@@ -791,8 +858,8 @@ class X509Req(object):
Set the version subfield (RFC 2459, section 4.1.2.1) of the certificate
request.
- :param version: The version number
- :return: None
+ :param int version: The version number.
+ :return: :py:const:`None`
"""
set_result = _lib.X509_REQ_set_version(self._req, version)
if not set_result:
@@ -804,16 +871,21 @@ class X509Req(object):
Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate
request.
- :return: an integer giving the value of the version subfield
+ :return: The value of the version subfield.
+ :rtype: :py:class:`int`
"""
return _lib.X509_REQ_get_version(self._req)
def get_subject(self):
"""
- Create an X509Name object for the subject of the certificate request
+ Return the subject of this certificate signing request.
+
+ This creates a new :py:class:`X509Name`: modifying it does not affect
+ this request.
- :return: An X509Name object
+ :return: The subject of this certificate signing request.
+ :rtype: :py:class:`X509Name`
"""
name = X509Name.__new__(X509Name)
name._name = _lib.X509_REQ_get_subject_name(self._req)
@@ -830,10 +902,11 @@ class X509Req(object):
def add_extensions(self, extensions):
"""
- Add extensions to the request.
+ Add extensions to the certificate signing request.
- :param extensions: a sequence of X509Extension objects
- :return: None
+ :param extensions: The X.509 extensions to add.
+ :type extensions: iterable of :py:class:`X509Extension`
+ :return: :py:const:`None`
"""
stack = _lib.sk_X509_EXTENSION_new_null()
if stack == _ffi.NULL:
@@ -857,9 +930,12 @@ class X509Req(object):
def get_extensions(self):
"""
- Get extensions to the request.
+ Get X.509 extensions in the certificate signing request.
+
+ :return: The X.509 extensions in this request.
+ :rtype: :py:class:`list` of :py:class:`X509Extension` objects.
- :return: A :py:class:`list` of :py:class:`X509Extension` objects.
+ .. versionadded:: 0.15
"""
exts = []
native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
@@ -872,11 +948,14 @@ class X509Req(object):
def sign(self, pkey, digest):
"""
- Sign the certificate request using the supplied key and digest
+ Sign the certificate signing request with this key and digest type.
- :param pkey: The key to sign with
- :param digest: The message digest to use
- :return: None
+ :param pkey: The key pair to sign with.
+ :type pkey: :py:class:`PKey`
+ :param digest: The name of the message digest to use for the signature,
+ e.g. :py:data:`b"sha1"`.
+ :type digest: :py:class:`bytes`
+ :return: :py:const:`None`
"""
if pkey._only_public:
raise ValueError("Key has only public part")
@@ -896,12 +975,13 @@ class X509Req(object):
def verify(self, pkey):
"""
- Verifies a certificate request using the supplied public key
-
- :param key: a public key
- :return: True if the signature is correct.
+ Verifies the signature on this certificate signing request.
- :raise OpenSSL.crypto.Error: If the signature is invalid or there is a
+ :param key: A public key.
+ :type key: :py:class:`PKey`
+ :return: :py:data:`True` if the signature is correct.
+ :rtype: :py:class:`bool`
+ :raises Error: If the signature is invalid or there is a
problem verifying the signature.
"""
if not isinstance(pkey, PKey):
@@ -914,11 +994,15 @@ class X509Req(object):
return result
+
X509ReqType = X509Req
class X509(object):
+ """
+ An X.509 certificate.
+ """
def __init__(self):
# TODO Allocation failure? And why not __new__ instead of __init__?
x509 = _lib.X509_new()
@@ -927,12 +1011,12 @@ class X509(object):
def set_version(self, version):
"""
- Set version number of the certificate
+ Set the version number of the certificate.
- :param version: The version number
+ :param version: The version number of the certificate.
:type version: :py:class:`int`
- :return: None
+ :return: :py:const:`None`
"""
if not isinstance(version, int):
raise TypeError("version must be an integer")
@@ -942,18 +1026,20 @@ class X509(object):
def get_version(self):
"""
- Return version number of the certificate
+ Return the version number of the certificate.
- :return: Version number as a Python integer
+ :return: The version number of the certificate.
+ :rtype: :py:class:`int`
"""
return _lib.X509_get_version(self._x509)
def get_pubkey(self):
"""
- Get the public key of the certificate
+ Get the public key of the certificate.
- :return: The public key
+ :return: The public key.
+ :rtype: :py:class:`PKey`
"""
pkey = PKey.__new__(PKey)
pkey._pkey = _lib.X509_get_pubkey(self._x509)
@@ -966,11 +1052,12 @@ class X509(object):
def set_pubkey(self, pkey):
"""
- Set the public key of the certificate
+ Set the public key of the certificate.
- :param pkey: The public key
+ :param pkey: The public key.
+ :type pkey: :py:class:`PKey`
- :return: None
+ :return: :py:data:`None`
"""
if not isinstance(pkey, PKey):
raise TypeError("pkey must be a PKey instance")
@@ -982,11 +1069,15 @@ class X509(object):
def sign(self, pkey, digest):
"""
- Sign the certificate using the supplied key and digest
+ Sign the certificate with this key and digest type.
+
+ :param pkey: The key to sign with.
+ :type pkey: :py:class:`PKey`
- :param pkey: The key to sign with
- :param digest: The message digest to use
- :return: None
+ :param digest: The name of the message digest to use.
+ :type digest: :py:class:`bytes`
+
+ :return: :py:data:`None`
"""
if not isinstance(pkey, PKey):
raise TypeError("pkey must be a PKey instance")
@@ -1008,11 +1099,14 @@ class X509(object):
def get_signature_algorithm(self):
"""
- Retrieve the signature algorithm used in the certificate
+ Return the signature algorithm used in the certificate.
+
+ :return: The name of the algorithm.
+ :rtype: :py:class:`bytes`
+
+ :raises ValueError: If the signature algorithm is undefined.
- :return: A byte string giving the name of the signature algorithm used in
- the certificate.
- :raise ValueError: If the signature algorithm is undefined.
+ .. versionadded:: 0.13
"""
alg = self._x509.cert_info.signature.algorithm
nid = _lib.OBJ_obj2nid(alg)
@@ -1028,7 +1122,9 @@ class X509(object):
:param digest_name: The name of the digest algorithm to use.
:type digest_name: :py:class:`bytes`
- :return: The digest of the object
+ :return: The digest of the object, formatted as
+ :py:const:`b":"`-delimited hex pairs.
+ :rtype: :py:class:`bytes`
"""
digest = _lib.EVP_get_digestbyname(_byte_string(digest_name))
if digest == _ffi.NULL:
@@ -1055,18 +1151,19 @@ class X509(object):
Return the hash of the X509 subject.
:return: The hash of the subject.
+ :rtype: :py:class:`bytes`
"""
return _lib.X509_subject_name_hash(self._x509)
def set_serial_number(self, serial):
"""
- Set serial number of the certificate
+ Set the serial number of the certificate.
- :param serial: The serial number
+ :param serial: The new serial number.
:type serial: :py:class:`int`
- :return: None
+ :return: :py:data`None`
"""
if not isinstance(serial, _integer_types):
raise TypeError("serial must be an integer")
@@ -1103,9 +1200,10 @@ class X509(object):
def get_serial_number(self):
"""
- Return serial number of the certificate
+ Return the serial number of this certificate.
- :return: Serial number as a Python integer
+ :return: The serial number.
+ :rtype: :py:class:`int`
"""
asn1_serial = _lib.X509_get_serialNumber(self._x509)
bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL)
@@ -1123,13 +1221,12 @@ class X509(object):
def gmtime_adj_notAfter(self, amount):
"""
- Adjust the time stamp for when the certificate stops being valid
+ Adjust the time stamp on which the certificate stops being valid.
- :param amount: The number of seconds by which to adjust the ending
- validity time.
+ :param amount: The number of seconds by which to adjust the timestamp.
:type amount: :py:class:`int`
- :return: None
+ :return: :py:const:`None`
"""
if not isinstance(amount, int):
raise TypeError("amount must be an integer")
@@ -1140,12 +1237,10 @@ class X509(object):
def gmtime_adj_notBefore(self, amount):
"""
- Change the timestamp for when the certificate starts being valid to the current
- time plus an offset.
+ Adjust the timestamp on which the certificate starts being valid.
- :param amount: The number of seconds by which to adjust the starting validity
- time.
- :return: None
+ :param amount: The number of seconds by which to adjust the timestamp.
+ :return: :py:const:`None`
"""
if not isinstance(amount, int):
raise TypeError("amount must be an integer")
@@ -1158,7 +1253,9 @@ class X509(object):
"""
Check whether the certificate has expired.
- :return: True if the certificate has expired, false otherwise
+ :return: :py:const:`True` if the certificate has expired,
+ :py:const:`False` otherwise.
+ :rtype: :py:class:`bool`
"""
now = int(time())
notAfter = _lib.X509_get_notAfter(self._x509)
@@ -1172,15 +1269,16 @@ class X509(object):
def get_notBefore(self):
"""
- Retrieve the time stamp for when the certificate starts being valid
+ Get the timestamp at which the certificate starts being valid.
- :return: A string giving the timestamp, in the format::
+ The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
- YYYYMMDDhhmmssZ
- YYYYMMDDhhmmss+hhmm
- YYYYMMDDhhmmss-hhmm
+ YYYYMMDDhhmmssZ
+ YYYYMMDDhhmmss+hhmm
+ YYYYMMDDhhmmss-hhmm
- or None if there is no value set.
+ :return: A timestamp string, or :py:const:`None` if there is none.
+ :rtype: :py:class:`bytes` or :py:const:`None`
"""
return self._get_boundary_time(_lib.X509_get_notBefore)
@@ -1191,47 +1289,52 @@ class X509(object):
def set_notBefore(self, when):
"""
- Set the time stamp for when the certificate starts being valid
+ Set the timestamp at which the certificate starts being valid.
- :param when: A string giving the timestamp, in the format:
+ The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
- YYYYMMDDhhmmssZ
- YYYYMMDDhhmmss+hhmm
- YYYYMMDDhhmmss-hhmm
+ YYYYMMDDhhmmssZ
+ YYYYMMDDhhmmss+hhmm
+ YYYYMMDDhhmmss-hhmm
+
+ :param when: A timestamp string.
:type when: :py:class:`bytes`
- :return: None
+ :return: :py:const:`None`
"""
return self._set_boundary_time(_lib.X509_get_notBefore, when)
def get_notAfter(self):
"""
- Retrieve the time stamp for when the certificate stops being valid
+ Get the timestamp at which the certificate stops being valid.
- :return: A string giving the timestamp, in the format::
+ The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
- YYYYMMDDhhmmssZ
- YYYYMMDDhhmmss+hhmm
- YYYYMMDDhhmmss-hhmm
+ YYYYMMDDhhmmssZ
+ YYYYMMDDhhmmss+hhmm
+ YYYYMMDDhhmmss-hhmm
- or None if there is no value set.
+ :return: A timestamp string, or :py:const:`None` if there is none.
+ :rtype: :py:class:`bytes` or :py:const:`None`
"""
return self._get_boundary_time(_lib.X509_get_notAfter)
def set_notAfter(self, when):
"""
- Set the time stamp for when the certificate stops being valid
+ Set the timestamp at which the certificate stops being valid.
+
+ The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
- :param when: A string giving the timestamp, in the format:
+ YYYYMMDDhhmmssZ
+ YYYYMMDDhhmmss+hhmm
+ YYYYMMDDhhmmss-hhmm
- YYYYMMDDhhmmssZ
- YYYYMMDDhhmmss+hhmm
- YYYYMMDDhhmmss-hhmm
+ :param when: A timestamp string.
:type when: :py:class:`bytes`
- :return: None
+ :return: :py:const:`None`
"""
return self._set_boundary_time(_lib.X509_get_notAfter, when)
@@ -1261,50 +1364,62 @@ class X509(object):
def get_issuer(self):
"""
- Create an X509Name object for the issuer of the certificate
+ Return the issuer of this certificate.
+
+ This creates a new :py:class:`X509Name`: modifying it does not affect
+ this certificate.
- :return: An X509Name object
+ :return: The issuer of this certificate.
+ :rtype: :py:class:`X509Name`
"""
return self._get_name(_lib.X509_get_issuer_name)
def set_issuer(self, issuer):
"""
- Set the issuer of the certificate
+ Set the issuer of this certificate.
- :param issuer: The issuer name
+ :param issuer: The issuer.
:type issuer: :py:class:`X509Name`
- :return: None
+ :return: :py:const:`None`
"""
return self._set_name(_lib.X509_set_issuer_name, issuer)
def get_subject(self):
"""
- Create an X509Name object for the subject of the certificate
+ Return the subject of this certificate.
- :return: An X509Name object
+ This creates a new :py:class:`X509Name`: modifying it does not affect
+ this certificate.
+
+ :return: The subject of this certificate.
+ :rtype: :py:class:`X509Name`
"""
return self._get_name(_lib.X509_get_subject_name)
def set_subject(self, subject):
"""
- Set the subject of the certificate
+ Set the subject of this certificate.
- :param subject: The subject name
+ :param subject: The subject.
:type subject: :py:class:`X509Name`
- :return: None
+
+ :return: :py:const:`None`
"""
return self._set_name(_lib.X509_set_subject_name, subject)
def get_extension_count(self):
"""
- Get the number of extensions on the certificate.
+ Get the number of extensions on this certificate.
+
+ :return: The number of extensions.
+ :rtype: :py:class:`int`
- :return: The number of extensions as an integer.
+ .. versionadded:: 0.12
"""
return _lib.X509_get_ext_count(self._x509)
@@ -1313,8 +1428,9 @@ class X509(object):
"""
Add extensions to the certificate.
- :param extensions: a sequence of X509Extension objects
- :return: None
+ :param extensions: The extensions to add.
+ :type extensions: An iterable of :py:class:`X509Extension` objects.
+ :return: :py:const:`None`
"""
for ext in extensions:
if not isinstance(ext, X509Extension):
@@ -1329,8 +1445,15 @@ class X509(object):
"""
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.
+ Extensions on a certificate are kept in order. The index
+ parameter selects which extension will be returned.
+
+ :param int index: The index of the extension to retrieve.
+ :return: The extension at the specified index.
+ :rtype: :py:class:`X509Extension`
+ :raises IndexError: If the extension index was out of bounds.
+
+ .. versionadded:: 0.12
"""
ext = X509Extension.__new__(X509Extension)
ext._extension = _lib.X509_get_ext(self._x509, index)
@@ -1341,17 +1464,32 @@ class X509(object):
ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
return ext
+
+
X509Type = X509
class X509Store(object):
+ """
+ An X509 certificate store.
+ """
def __init__(self):
store = _lib.X509_STORE_new()
self._store = _ffi.gc(store, _lib.X509_STORE_free)
def add_cert(self, cert):
+ """
+ Adds the certificate :py:data:`cert` to this store.
+
+ This is the Python equivalent of OpenSSL's ``X509_STORE_add_cert``.
+
+ :param X509 cert: The certificate to add to this store.
+ :raises TypeError: If the certificate is not an :py:class:`X509`.
+ :raises Error: If OpenSSL was unhappy with your certificate.
+ :return: :py:data:`None` if the certificate was added successfully.
+ """
if not isinstance(cert, X509):
raise TypeError()
@@ -1621,6 +1759,9 @@ def _X509_REVOKED_dup(original):
class Revoked(object):
+ """
+ A certificate revocation.
+ """
# http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_
# which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches
# OCSP_crl_reason_str. We use the latter, just like the command line
@@ -1643,11 +1784,15 @@ class Revoked(object):
def set_serial(self, hex_str):
"""
- Set the serial number of a revoked Revoked structure
+ Set the serial number.
+
+ The serial number is formatted as a hexadecimal number encoded in
+ ASCII.
:param hex_str: The new serial number.
- :type hex_str: :py:data:`str`
- :return: None
+ :type hex_str: :py:class:`bytes`
+
+ :return: :py:const:`None`
"""
bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free)
bignum_ptr = _ffi.new("BIGNUM**")
@@ -1664,9 +1809,13 @@ class Revoked(object):
def get_serial(self):
"""
- Return the serial number of a Revoked structure
+ Get the serial number.
+
+ The serial number is formatted as a hexadecimal number encoded in
+ ASCII.
- :return: The serial number as a string
+ :return: The serial number.
+ :rtype: :py:class:`bytes`
"""
bio = _new_mem_buf()
@@ -1690,13 +1839,19 @@ class Revoked(object):
def set_reason(self, reason):
"""
- Set the reason of a Revoked object.
+ Set the reason of this revocation.
- If :py:data:`reason` is :py:data:`None`, delete the reason instead.
+ If :py:data:`reason` is :py:const:`None`, delete the reason instead.
:param reason: The reason string.
- :type reason: :py:class:`str` or :py:class:`NoneType`
- :return: None
+ :type reason: :py:class:`bytes` or :py:class:`NoneType`
+
+ :return: :py:const:`None`
+
+ .. seealso::
+
+ :py:meth:`all_reasons`, which gives you a list of all supported
+ reasons which you might pass to this method.
"""
if reason is None:
self._delete_reason()
@@ -1728,9 +1883,15 @@ class Revoked(object):
def get_reason(self):
"""
- Return the reason of a Revoked object.
+ Set the reason of this revocation.
+
+ :return: The reason, or :py:const:`None` if there is none.
+ :rtype: :py:class:`bytes` or :py:class:`NoneType`
+
+ .. seealso::
- :return: The reason as a string
+ :py:meth:`all_reasons`, which gives you a list of all supported
+ reasons this method might return.
"""
extensions = self._revoked.extensions
for i in range(_lib.sk_X509_EXTENSION_num(extensions)):
@@ -1752,44 +1913,44 @@ class Revoked(object):
"""
Return a list of all the supported reason strings.
+ This list is a copy; modifying it does not change the supported reason
+ strings.
+
:return: A list of reason strings.
+ :rtype: :py:class:`list` of :py:class:`bytes`
"""
return self._crl_reasons[:]
def set_rev_date(self, when):
"""
- Set the revocation timestamp
-
- :param when: A string giving the timestamp, in the format:
-
- YYYYMMDDhhmmssZ
- YYYYMMDDhhmmss+hhmm
- YYYYMMDDhhmmss-hhmm
+ Set the revocation timestamp.
- :return: None
+ :param when: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
+ :type when: :py:class:`bytes`
+ :return: :py:const:`None`
"""
return _set_asn1_time(self._revoked.revocationDate, when)
def get_rev_date(self):
"""
- Retrieve the revocation date
-
- :return: A string giving the timestamp, in the format:
+ Get the revocation timestamp.
- YYYYMMDDhhmmssZ
- YYYYMMDDhhmmss+hhmm
- YYYYMMDDhhmmss-hhmm
+ :return: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
+ :rtype: :py:class:`bytes`
"""
return _get_asn1_time(self._revoked.revocationDate)
class CRL(object):
+ """
+ A certificate revocation list.
+ """
def __init__(self):
"""
- Create a new empty CRL object.
+ Create a new empty certificate revocation list.
"""
crl = _lib.X509_CRL_new()
self._crl = _ffi.gc(crl, _lib.X509_CRL_free)
@@ -1797,9 +1958,13 @@ class CRL(object):
def get_revoked(self):
"""
- Return revoked portion of the CRL structure (by value not reference).
+ Return the revocations in this certificate revocation list.
+
+ These revocations will be provided by value, not by reference.
+ That means it's okay to mutate them: it won't affect this CRL.
- :return: A tuple of Revoked objects.
+ :return: The revocations in this CRL.
+ :rtype: :py:class:`tuple` of :py:class:`Revocation`
"""
results = []
revoked_stack = self._crl.crl.revoked
@@ -1817,10 +1982,14 @@ class CRL(object):
"""
Add a revoked (by value not reference) to the CRL structure
- :param revoked: The new revoked.
- :type revoked: :class:`X509`
+ This revocation will be added by value, not by reference. That
+ means it's okay to mutate it after adding: it won't affect
+ this CRL.
- :return: None
+ :param revoked: The new revocation.
+ :type revoked: :class:`Revoked`
+
+ :return: :py:const:`None`
"""
copy = _X509_REVOKED_dup(revoked._revoked)
if copy == _ffi.NULL:
@@ -1836,13 +2005,13 @@ class CRL(object):
def export(self, cert, key, type=FILETYPE_PEM, days=100,
digest=_UNSPECIFIED):
"""
- export a CRL as a string
+ Export a CRL as a string.
- :param cert: Used to sign CRL.
- :type cert: :class:`X509`
+ :param cert: The certificate used to sign the CRL.
+ :type cert: :py:class:`X509`
- :param key: Used to sign CRL.
- :type key: :class:`PKey`
+ :param key: The key used to sign the CRL.
+ :type key: :py:class:`PKey`
:param type: The export format, either :py:data:`FILETYPE_PEM`,
:py:data:`FILETYPE_ASN1`, or :py:data:`FILETYPE_TEXT`.
@@ -1976,6 +2145,9 @@ PKCS7Type = PKCS7
class PKCS12(object):
+ """
+ A PKCS #12 archive.
+ """
def __init__(self):
self._pkey = None
self._cert = None
@@ -1985,20 +2157,22 @@ class PKCS12(object):
def get_certificate(self):
"""
- Return certificate portion of the PKCS12 structure
+ Get the certificate in the PKCS #12 structure.
- :return: X509 object containing the certificate
+ :return: The certificate, or :py:const:`None` if there is none.
+ :rtype: :py:class:`X509` or :py:const:`None`
"""
return self._cert
def set_certificate(self, cert):
"""
- Replace the certificate portion of the PKCS12 structure
+ Set the certificate in the PKCS #12 structure.
+
+ :param cert: The new certificate, or :py:const:`None` to unset it.
+ :type cert: :py:class:`X509` or :py:const:`None`
- :param cert: The new certificate.
- :type cert: :py:class:`X509` or :py:data:`None`
- :return: None
+ :return: :py:const:`None`
"""
if not isinstance(cert, X509):
raise TypeError("cert must be an X509 instance")
@@ -2007,20 +2181,22 @@ class PKCS12(object):
def get_privatekey(self):
"""
- Return private key portion of the PKCS12 structure
+ Get the private key in the PKCS #12 structure.
- :returns: PKey object containing the private key
+ :return: The private key, or :py:const:`None` if there is none.
+ :rtype: :py:class:`PKey`
"""
return self._pkey
def set_privatekey(self, pkey):
"""
- Replace or set the certificate portion of the PKCS12 structure
+ Set the certificate portion of the PKCS #12 structure.
- :param pkey: The new private key.
- :type pkey: :py:class:`PKey`
- :return: None
+ :param pkey: The new private key, or :py:const:`None` to unset it.
+ :type pkey: :py:class:`PKey` or :py:const:`None`
+
+ :return: :py:const:`None`
"""
if not isinstance(pkey, PKey):
raise TypeError("pkey must be a PKey instance")
@@ -2029,10 +2205,11 @@ class PKCS12(object):
def get_ca_certificates(self):
"""
- Return CA certificates within of the PKCS12 object
+ Get the CA certificates in the PKCS #12 structure.
- :return: A newly created tuple containing the CA certificates in the chain,
- if any are present, or None if no CA certificates are present.
+ :return: A tuple with the CA certificates in the chain, or
+ :py:const:`None` if there are none.
+ :rtype: :py:class:`tuple` of :py:class:`X509` or :py:const:`None`
"""
if self._cacerts is not None:
return tuple(self._cacerts)
@@ -2042,9 +2219,11 @@ class PKCS12(object):
"""
Replace or set the CA certificates within the PKCS12 object.
- :param cacerts: The new CA certificates.
- :type cacerts: :py:data:`None` or an iterable of :py:class:`X509`
- :return: None
+ :param cacerts: The new CA certificates, or :py:const:`None` to unset
+ them.
+ :type cacerts: An iterable of :py:class:`X509` or :py:const:`None`
+
+ :return: :py:const:`None`
"""
if cacerts is None:
self._cacerts = None
@@ -2058,11 +2237,12 @@ class PKCS12(object):
def set_friendlyname(self, name):
"""
- Replace or set the certificate portion of the PKCS12 structure
+ Set the friendly name in the PKCS #12 structure.
+
+ :param name: The new friendly name, or :py:const:`None` to unset.
+ :type name: :py:class:`bytes` or :py:const:`None`
- :param name: The new friendly name.
- :type name: :py:class:`bytes`
- :return: None
+ :return: :py:const:`None`
"""
if name is None:
self._friendlyname = None
@@ -2073,27 +2253,33 @@ class PKCS12(object):
def get_friendlyname(self):
"""
- Return friendly name portion of the PKCS12 structure
+ Get the friendly name in the PKCS# 12 structure.
- :returns: String containing the friendlyname
+ :returns: The friendly name, or :py:const:`None` if there is none.
+ :rtype: :py:class:`bytes` or :py:const:`None`
"""
return self._friendlyname
def export(self, passphrase=None, iter=2048, maciter=1):
"""
- Dump a PKCS12 object as a string. See also "man PKCS12_create".
+ Dump a PKCS12 object as a string.
- :param passphrase: used to encrypt the PKCS12
+ For more information, see the :c:func:`PKCS12_create` man page.
+
+ :param passphrase: The passphrase used to encrypt the structure. Unlike
+ some other passphrase arguments, this *must* be a string, not a
+ callback.
:type passphrase: :py:data:`bytes`
- :param iter: How many times to repeat the encryption
+ :param iter: Number of times to repeat the encryption step.
:type iter: :py:data:`int`
- :param maciter: How many times to repeat the MAC
+ :param maciter: Number of times to repeat the MAC step.
:type maciter: :py:data:`int`
- :return: The string containing the PKCS12
+ :return: The string representation of the PKCS #12 structure.
+ :rtype:
"""
passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
@@ -2135,11 +2321,16 @@ class PKCS12(object):
_lib.i2d_PKCS12_bio(bio, pkcs12)
return _bio_to_string(bio)
+
+
PKCS12Type = PKCS12
class NetscapeSPKI(object):
+ """
+ A Netscape SPKI object.
+ """
def __init__(self):
spki = _lib.NETSCAPE_SPKI_new()
self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
@@ -2147,11 +2338,15 @@ class NetscapeSPKI(object):
def sign(self, pkey, digest):
"""
- Sign the certificate request using the supplied key and digest
+ Sign the certificate request with this key and digest type.
+
+ :param pkey: The private key to sign with.
+ :type pkey: :py:class:`PKey`
- :param pkey: The key to sign with
- :param digest: The message digest to use
- :return: None
+ :param digest: The message digest to use.
+ :type digest: :py:class:`bytes`
+
+ :return: :py:const:`None`
"""
if pkey._only_public:
raise ValueError("Key has only public part")
@@ -2171,12 +2366,16 @@ class NetscapeSPKI(object):
def verify(self, key):
"""
- Verifies a certificate request using the supplied public key
+ Verifies a signature on a certificate request.
- :param key: a public key
- :return: True if the signature is correct.
- :raise OpenSSL.crypto.Error: If the signature is invalid or there is a
- problem verifying the signature.
+ :param key: The public key that signature is supposedly from.
+ :type pkey: :py:class:`PKey`
+
+ :return: :py:const:`True` if the signature is correct.
+ :rtype: :py:class:`bool`
+
+ :raises Error: If the signature is invalid, or there was a problem
+ verifying the signature.
"""
answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
if answer <= 0:
@@ -2186,9 +2385,10 @@ class NetscapeSPKI(object):
def b64_encode(self):
"""
- Generate a base64 encoded string from an SPKI
+ Generate a base64 encoded representation of this SPKI object.
- :return: The base64 encoded string
+ :return: The base64 encoded string.
+ :rtype: :py:class:`bytes`
"""
encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
result = _ffi.string(encoded)
@@ -2198,9 +2398,10 @@ class NetscapeSPKI(object):
def get_pubkey(self):
"""
- Get the public key of the certificate
+ Get the public key of this certificate.
- :return: The public key
+ :return: The public key.
+ :rtype: :py:class:`PKey`
"""
pkey = PKey.__new__(PKey)
pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
@@ -2217,15 +2418,19 @@ class NetscapeSPKI(object):
Set the public key of the certificate
:param pkey: The public key
- :return: None
+ :return: :py:const:`None`
"""
set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
if not set_result:
# TODO: This is untested.
_raise_current_error()
+
+
+
NetscapeSPKIType = NetscapeSPKI
+
class _PassphraseHelper(object):
def __init__(self, type, passphrase, more_args=False, truncate=False):
if type != FILETYPE_PEM and passphrase is not None:
@@ -2422,13 +2627,13 @@ def sign(pkey, data, digest):
def verify(cert, signature, data, digest):
"""
- Verify a signature
+ Verify a signature.
:param cert: signing certificate (X509 object)
:param signature: signature returned by sign function
:param data: data to be verified
:param digest: message digest to use
- :return: None if the signature is correct, raise exception otherwise
+ :return: :py:const:`None` if the signature is correct, raise exception otherwise
"""
data = _text_to_bytes_and_warn("data", data)
diff --git a/OpenSSL/version.py b/OpenSSL/version.py
index eb3b736..f284b04 100644
--- a/OpenSSL/version.py
+++ b/OpenSSL/version.py
@@ -6,4 +6,17 @@
pyOpenSSL - A simple wrapper around the OpenSSL library
"""
-__version__ = '0.15.1'
+__all__ = [
+ "__author__", "__copyright__", "__email__", "__license__", "__summary__",
+ "__title__", "__uri__", "__version__",
+]
+
+__version__ = "0.16.dev0"
+
+__title__ = "pyOpenSSL"
+__uri__ = "https://github.com/pyca/pyopenssl"
+__summary__ = "Python wrapper module around the OpenSSL library"
+__author__ = "The pyOpenSSL developers"
+__email__ = "cryptography-dev@python.org"
+__license__ = "Apache License, Version 2.0"
+__copyright__ = "Copyright 2001-2015 {0}".format(__author__)
diff --git a/README.rst b/README.rst
index cac341f..4b479c8 100644
--- a/README.rst
+++ b/README.rst
@@ -1,6 +1,5 @@
-
-pyOpenSSL - A Python wrapper around the OpenSSL library
--------------------------------------------------------
+pyOpenSSL -- A Python wrapper around the OpenSSL library
+--------------------------------------------------------
.. image:: https://coveralls.io/repos/pyca/pyopenssl/badge.svg
:target: https://coveralls.io/r/pyca/pyopenssl
@@ -12,6 +11,15 @@ pyOpenSSL - A Python wrapper around the OpenSSL library
.. image:: https://travis-ci.org/pyca/pyopenssl.svg?branch=master
:target: https://travis-ci.org/pyca/pyopenssl
+
+High-level wrapper around a subset of the OpenSSL library. Includes
+
+* SSL.Connection objects, wrapping the methods of Python's portable sockets
+* Callbacks written in Python
+* Extensive error-handling mechanism, mirroring OpenSSL's error codes
+
+... and much more.
+
See the file INSTALL.rst for installation instructions.
See https://github.com/pyca/pyopenssl for development.
diff --git a/TODO b/TODO
deleted file mode 100644
index cbcf642..0000000
--- a/TODO
+++ /dev/null
@@ -1,8 +0,0 @@
-TODO list
-
-* Think more carefully about the relation between X509 and X509_NAME
- _set_{subject,issuer} dup the new name and free the old one.
-* Consider Pyrex
-* Updated docs! (rpm, ...)
-* _Somehow_ get makefile to work!
-* httpslib, imapslib, ftpslib?
diff --git a/doc/api/crypto.rst b/doc/api/crypto.rst
index 57a60f3..101f3bd 100644
--- a/doc/api/crypto.rst
+++ b/doc/api/crypto.rst
@@ -6,128 +6,8 @@
.. py:module:: OpenSSL.crypto
:synopsis: Generic cryptographic module
-
-.. py:data:: X509Type
-
- See :py:class:`X509`.
-
-
-.. py:class:: X509()
-
- A class representing X.509 certificates.
-
-
-.. py:data:: X509NameType
-
- See :py:class:`X509Name`.
-
-
-.. py:class:: X509Name(x509name)
-
- A class representing X.509 Distinguished Names.
-
- This constructor creates a copy of *x509name* which should be an
- instance of :py:class:`X509Name`.
-
-
-.. py:data:: X509ReqType
-
- See :py:class:`X509Req`.
-
-
-.. py:class:: X509Req()
-
- A class representing X.509 certificate requests.
-
-
-.. py:data:: X509StoreType
-
- See :py:class:`X509Store`
-
-
-.. py:data X509Store
-
- A class representing the X.509 store.
-
-
-.. py:data:: X509StoreContext
-
- A class representing the X.509 store context.
-
-
-.. py:data:: PKeyType
-
- See :py:class:`PKey`.
-
-
-.. py:class:: PKey()
-
- A class representing DSA or RSA keys.
-
-
-.. py:data:: PKCS7Type
-
- A Python type object representing the PKCS7 object type.
-
-
-.. py:data:: PKCS12Type
-
- A Python type object representing the PKCS12 object type.
-
-
-.. py:data:: X509ExtensionType
-
- See :py:class:`X509Extension`.
-
-
-.. py:class:: X509Extension(typename, critical, value[, subject][, issuer])
-
- A class representing an X.509 v3 certificate extensions. See
- http://openssl.org/docs/apps/x509v3_config.html#STANDARD_EXTENSIONS for
- *typename* strings and their options. Optional parameters *subject* and
- *issuer* must be X509 objects.
-
-
-.. py:data:: NetscapeSPKIType
-
- See :py:class:`NetscapeSPKI`.
-
-
-.. py:class:: NetscapeSPKI([enc])
-
- A class representing Netscape SPKI objects.
-
- If the *enc* argument is present, it should be a base64-encoded string
- representing a NetscapeSPKI object, as returned by the :py:meth:`b64_encode`
- method.
-
-
-.. py:class:: CRL()
-
- A class representing Certifcate Revocation List objects.
-
-
-.. py:class:: Revoked()
-
- A class representing Revocation objects of CRL.
-
-
-.. py:data:: FILETYPE_PEM
- FILETYPE_ASN1
-
- File type constants.
-
-
-.. py:data:: TYPE_RSA
- TYPE_DSA
-
- Key type constants.
-
-
-.. py:exception:: Error
-
- Generic exception used in the :py:mod:`.crypto` module.
-
+Elliptic curves
+---------------
.. py:function:: get_elliptic_curves
@@ -151,17 +31,43 @@
If the named curve is not supported then :py:class:`ValueError` is raised.
+Serialization and deserialization
+---------------------------------
+
+The following serialization functions take one of these constants to
+determine the format:
+
+.. py:data:: FILETYPE_PEM
+ FILETYPE_ASN1
+
+Certificates
+~~~~~~~~~~~~
+
.. py:function:: dump_certificate(type, cert)
Dump the certificate *cert* into a buffer string encoded with the type
*type*.
+.. py:function:: load_certificate(type, buffer)
+
+ Load a certificate (X509) from the string *buffer* encoded with the
+ type *type*.
+
+Certificate signing requests
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. py:function:: dump_certificate_request(type, req)
Dump the certificate request *req* into a buffer string encoded with the
type *type*.
+.. py:function:: load_certificate_request(type, buffer)
+
+ Load a certificate request (X509Req) from the string *buffer* encoded with
+ the type *type*.
+
+Private keys
+~~~~~~~~~~~~
.. py:function:: dump_privatekey(type, pkey[, cipher, passphrase])
@@ -172,19 +78,6 @@
*passphrase* must be either a string or a callback for providing the
pass phrase.
-
-.. py:function:: load_certificate(type, buffer)
-
- Load a certificate (X509) from the string *buffer* encoded with the
- type *type*.
-
-
-.. py:function:: load_certificate_request(type, buffer)
-
- Load a certificate request (X509Req) from the string *buffer* encoded with
- the type *type*.
-
-
.. py:function:: load_privatekey(type, buffer[, passphrase])
Load a private key (PKey) from the string *buffer* encoded with the type
@@ -194,6 +87,8 @@
*passphrase* must be either a string or a callback for providing the pass
phrase.
+Certificate revocation lists
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. py:function:: load_crl(type, buffer)
@@ -204,7 +99,9 @@
.. py:function:: load_pkcs7_data(type, buffer)
- Load pkcs7 data from the string *buffer* encoded with the type *type*.
+ Load pkcs7 data from the string *buffer* encoded with the type
+ *type*. The type *type* must either :py:const:`FILETYPE_PEM` or
+ :py:const:`FILETYPE_ASN1`).
.. py:function:: load_pkcs12(buffer[, passphrase])
@@ -215,6 +112,8 @@
See also the man page for the C function :py:func:`PKCS12_parse`.
+Signing and verifying signatures
+--------------------------------
.. py:function:: sign(key, data, digest)
@@ -245,296 +144,36 @@
X509 objects
------------
-X509 objects have the following methods:
-
-.. py:method:: X509.get_issuer()
-
- Return an X509Name object representing the issuer of the certificate.
-
-
-.. py:method:: X509.get_pubkey()
-
- Return a :py:class:`PKey` object representing the public key of the certificate.
-
-
-.. py:method:: X509.get_serial_number()
-
- Return the certificate serial number.
-
-
-.. py:method:: X509.get_signature_algorithm()
-
- Return the signature algorithm used in the certificate. If the algorithm is
- undefined, raise :py:data:`ValueError`.
-
- .. versionadded:: 0.13
-
-
-.. py:method:: X509.get_subject()
-
- Return an :py:class:`X509Name` object representing the subject of the certificate.
-
-
-.. py:method:: X509.get_version()
-
- Return the certificate version.
-
-
-.. py:method:: X509.get_notBefore()
-
- Return a string giving the time before which the certificate is not valid. The
- string is formatted as an ASN1 GENERALIZEDTIME::
-
- YYYYMMDDhhmmssZ
- YYYYMMDDhhmmss+hhmm
- YYYYMMDDhhmmss-hhmm
-
- If no value exists for this field, :py:data:`None` is returned.
-
-
-.. py:method:: X509.get_notAfter()
-
- Return a string giving the time after which the certificate is not valid. The
- string is formatted as an ASN1 GENERALIZEDTIME::
-
- YYYYMMDDhhmmssZ
- YYYYMMDDhhmmss+hhmm
- YYYYMMDDhhmmss-hhmm
-
- If no value exists for this field, :py:data:`None` is returned.
-
-
-.. py:method:: X509.set_notBefore(when)
-
- Change the time before which the certificate is not valid. *when* is a
- string formatted as an ASN1 GENERALIZEDTIME::
-
- YYYYMMDDhhmmssZ
- YYYYMMDDhhmmss+hhmm
- YYYYMMDDhhmmss-hhmm
-
-
-.. py:method:: X509.set_notAfter(when)
-
- Change the time after which the certificate is not valid. *when* is a
- string formatted as an ASN1 GENERALIZEDTIME::
-
- YYYYMMDDhhmmssZ
- YYYYMMDDhhmmss+hhmm
- YYYYMMDDhhmmss-hhmm
-
-
-
-.. py:method:: X509.gmtime_adj_notBefore(time)
-
- Adjust the timestamp (in GMT) when the certificate starts being valid.
-
-
-.. py:method:: X509.gmtime_adj_notAfter(time)
-
- Adjust the timestamp (in GMT) when the certificate stops being valid.
-
-
-.. py:method:: X509.has_expired()
-
- Checks the certificate's time stamp against current time. Returns true if the
- certificate has expired and false otherwise.
-
-
-.. py:method:: X509.set_issuer(issuer)
-
- Set the issuer of the certificate to *issuer*.
-
-
-.. py:method:: X509.set_pubkey(pkey)
-
- Set the public key of the certificate to *pkey*.
-
-
-.. py:method:: X509.set_serial_number(serialno)
-
- Set the serial number of the certificate to *serialno*.
-
-
-.. py:method:: X509.set_subject(subject)
-
- Set the subject of the certificate to *subject*.
-
-
-.. py:method:: X509.set_version(version)
-
- Set the certificate version to *version*.
-
-
-.. py:method:: X509.sign(pkey, digest)
-
- Sign the certificate, using the key *pkey* and the message digest algorithm
- identified by the string *digest*.
-
-
-.. py:method:: X509.subject_name_hash()
-
- Return the hash of the certificate subject.
-
-.. py:method:: X509.digest(digest_name)
-
- Return a digest of the certificate, using the *digest_name* method.
- *digest_name* must be a string describing a digest algorithm supported
- by OpenSSL (by EVP_get_digestbyname, specifically). For example,
- :py:const:`"md5"` or :py:const:`"sha1"`.
-
-
-.. py:method:: X509.add_extensions(extensions)
-
- Add the extensions in the sequence *extensions* to the certificate.
-
-
-.. py:method:: X509.get_extension_count()
-
- Return the number of extensions on this certificate.
-
- .. versionadded:: 0.12
-
-
-.. py:method:: X509.get_extension(index)
-
- Retrieve the extension on this certificate at the given index.
-
- Extensions on a certificate are kept in order. The index parameter selects
- which extension will be returned. The returned object will be an
- :py:class:`X509Extension` instance.
-
- .. versionadded:: 0.12
-
+.. autoclass:: X509
+ :members:
.. _openssl-x509name:
X509Name objects
----------------
-X509Name objects have the following methods:
-
-.. py:method:: X509Name.hash()
-
- Return an integer giving the first four bytes of the MD5 digest of the DER
- representation of the name.
-
-
-.. py:method:: X509Name.der()
-
- Return a string giving the DER representation of the name.
-
-
-.. py:method:: X509Name.get_components()
-
- Return a list of two-tuples of strings giving the components of the name.
-
-
-X509Name objects have the following members:
-
-.. py:attribute:: X509Name.countryName
-
- The country of the entity. :py:attr:`C` may be used as an alias for
- :py:attr:`countryName`.
-
-
-.. py:attribute:: X509Name.stateOrProvinceName
-
- The state or province of the entity. :py:attr:`ST` may be used as an alias for
- :py:attr:`stateOrProvinceName`.
-
-
-.. py:attribute:: X509Name.localityName
-
- The locality of the entity. :py:attr:`L` may be used as an alias for
- :py:attr:`localityName`.
-
-
-.. py:attribute:: X509Name.organizationName
-
- The organization name of the entity. :py:attr:`O` may be used as an alias for
- :py:attr:`organizationName`.
-
-
-.. py:attribute:: X509Name.organizationalUnitName
-
- The organizational unit of the entity. :py:attr:`OU` may be used as an alias for
- :py:attr:`organizationalUnitName`.
-
-
-.. py:attribute:: X509Name.commonName
-
- The common name of the entity. :py:attr:`CN` may be used as an alias for
- :py:attr:`commonName`.
-
-
-.. py:attribute:: X509Name.emailAddress
-
- The e-mail address of the entity.
-
+.. autoclass:: X509Name
+ :members:
+ :special-members:
+ :exclude-members: __repr__, __getattr__, __weakref__
.. _openssl-x509req:
X509Req objects
---------------
-X509Req objects have the following methods:
-
-.. py:method:: X509Req.get_pubkey()
-
- Return a :py:class:`PKey` object representing the public key of the certificate request.
-
-
-.. py:method:: X509Req.get_subject()
-
- Return an :py:class:`X509Name` object representing the subject of the certificate.
-
-
-.. py:method:: X509Req.set_pubkey(pkey)
-
- Set the public key of the certificate request to *pkey*.
-
-
-.. py:method:: X509Req.sign(pkey, digest)
-
- Sign the certificate request, using the key *pkey* and the message digest
- algorithm identified by the string *digest*.
-
-
-.. py:method:: X509Req.verify(pkey)
-
- Verify a certificate request using the public key *pkey*.
-
-
-.. py:method:: X509Req.set_version(version)
-
- Set the version (RFC 2459, 4.1.2.1) of the certificate request to
- *version*.
-
-
-.. py:method:: X509Req.get_version()
-
- Get the version (RFC 2459, 4.1.2.1) of the certificate request.
-
-
-.. py:method:: X509Req.get_extensions()
-
- Get extensions to the request.
-
- .. versionadded:: 0.15
-
+.. autoclass:: X509Req
+ :members:
+ :special-members:
+ :exclude-members: __weakref__
.. _openssl-x509store:
X509Store objects
-----------------
-The X509Store object has currently just one method:
-
-.. py:method:: X509Store.add_cert(cert)
-
- Add the certificate *cert* to the certificate store.
-
+.. autoclass:: X509Store
+ :members:
X509StoreContextError objects
-----------------------------
@@ -547,8 +186,8 @@ The certificate for which the verification error was detected is given by the
``certificate`` attribute of the exception instance as a :class:`X509`
instance.
-Details about the verification error are given in the exception's ``args`` attribute.
-
+Details about the verification error are given in the exception's
+``args`` attribute.
X509StoreContext objects
------------------------
@@ -565,38 +204,20 @@ of trusted certificates.
.. versionadded:: 0.15
-
.. _openssl-pkey:
PKey objects
------------
-The PKey object has the following methods:
-
-.. py:method:: PKey.bits()
-
- Return the number of bits of the key.
-
-
-.. py:method:: PKey.generate_key(type, bits)
-
- Generate a public/private key pair of the type *type* (one of
- :py:const:`TYPE_RSA` and :py:const:`TYPE_DSA`) with the size *bits*.
-
+.. autoclass:: PKey
+ :members:
-.. py:method:: PKey.type()
-
- Return the type of the key.
-
-
-.. py:method:: PKey.check()
-
- Check the consistency of this key, returning True if it is consistent and
- raising an exception otherwise. This is only valid for RSA keys. See the
- OpenSSL RSA_check_key man page for further limitations.
+.. _openssl-pkcs7:
+.. py:data:: TYPE_RSA
+ TYPE_DSA
-.. _openssl-pkcs7:
+ Key type constants.
PKCS7 objects
-------------
@@ -607,217 +228,118 @@ PKCS7 objects have the following methods:
FIXME
-
.. py:method:: PKCS7.type_is_enveloped()
FIXME
-
.. py:method:: PKCS7.type_is_signedAndEnveloped()
FIXME
-
.. py:method:: PKCS7.type_is_data()
FIXME
-
.. py:method:: PKCS7.get_type_name()
Get the type name of the PKCS7.
-
.. _openssl-pkcs12:
PKCS12 objects
--------------
-PKCS12 objects have the following methods:
-
-.. py:method:: PKCS12.export([passphrase=None][, iter=2048][, maciter=1])
-
- Returns a PKCS12 object as a string.
-
- The optional *passphrase* must be a string not a callback.
-
- See also the man page for the C function :py:func:`PKCS12_create`.
-
-
-.. py:method:: PKCS12.get_ca_certificates()
-
- Return CA certificates within the PKCS12 object as a tuple. Returns
- :py:const:`None` if no CA certificates are present.
-
-
-.. py:method:: PKCS12.get_certificate()
-
- Return certificate portion of the PKCS12 structure.
-
-
-.. py:method:: PKCS12.get_friendlyname()
-
- Return friendlyName portion of the PKCS12 structure.
-
-
-.. py:method:: PKCS12.get_privatekey()
-
- Return private key portion of the PKCS12 structure
-
-
-.. py:method:: PKCS12.set_ca_certificates(cacerts)
-
- Replace or set the CA certificates within the PKCS12 object with the sequence *cacerts*.
-
- Set *cacerts* to :py:const:`None` to remove all CA certificates.
-
-
-.. py:method:: PKCS12.set_certificate(cert)
-
- Replace or set the certificate portion of the PKCS12 structure.
-
-
-.. py:method:: PKCS12.set_friendlyname(name)
-
- Replace or set the friendlyName portion of the PKCS12 structure.
-
-
-.. py:method:: PKCS12.set_privatekey(pkey)
-
- Replace or set private key portion of the PKCS12 structure
-
+.. autoclass:: PKCS12
+ :members:
.. _openssl-509ext:
X509Extension objects
---------------------
-X509Extension objects have several methods:
-
-.. py:method:: X509Extension.get_critical()
-
- Return the critical field of the extension object.
-
-
-.. py:method:: X509Extension.get_short_name()
-
- Retrieve the short descriptive name for this extension.
-
- The result is a byte string like :py:const:`basicConstraints`.
-
- .. versionadded:: 0.12
-
-
-.. py:method:: X509Extension.get_data()
-
- Retrieve the data for this extension.
-
- The result is the ASN.1 encoded form of the extension data as a byte string.
-
- .. versionadded:: 0.12
-
+.. autoclass:: X509Extension
+ :members:
+ :special-members:
+ :exclude-members: __weakref__
.. _openssl-netscape-spki:
NetscapeSPKI objects
--------------------
-NetscapeSPKI objects have the following methods:
-
-.. py:method:: NetscapeSPKI.b64_encode()
-
- Return a base64-encoded string representation of the object.
-
-
-.. py:method:: NetscapeSPKI.get_pubkey()
-
- Return the public key of object.
-
-
-.. py:method:: NetscapeSPKI.set_pubkey(key)
-
- Set the public key of the object to *key*.
-
-
-.. py:method:: NetscapeSPKI.sign(key, digest_name)
-
- Sign the NetscapeSPKI object using the given *key* and *digest_name*.
- *digest_name* must be a string describing a digest algorithm supported by
- OpenSSL (by EVP_get_digestbyname, specifically). For example,
- :py:const:`"md5"` or :py:const:`"sha1"`.
-
-
-.. py:method:: NetscapeSPKI.verify(key)
-
- Verify the NetscapeSPKI object using the given *key*.
-
+.. autoclass:: NetscapeSPKI
+ :members:
+ :special-members:
+ :exclude-members: __weakref__
.. _crl:
CRL objects
-----------
-CRL objects have the following methods:
-
-.. py:method:: CRL.add_revoked(revoked)
-
- Add a Revoked object to the CRL, by value not reference.
-
-
-.. py:method:: CRL.export(cert, key[, type=FILETYPE_PEM][, days=100][, digest=b'md5'])
-
- Use *cert* and *key* to sign the CRL and return the CRL as a string.
- *days* is the number of days before the next CRL is due.
- *digest* is the algorithm that will be used to sign CRL.
-
-
-.. py:method:: CRL.get_revoked()
-
- Return a tuple of Revoked objects, by value not reference.
-
+.. autoclass:: CRL
+ :members:
+ :special-members:
+ :exclude-members: __weakref__
.. _revoked:
Revoked objects
---------------
-Revoked objects have the following methods:
-
-.. py:method:: Revoked.all_reasons()
-
- Return a list of all supported reasons.
-
-
-.. py:method:: Revoked.get_reason()
-
- Return the revocation reason as a str. Can be
- None, which differs from "Unspecified".
-
-
-.. py:method:: Revoked.get_rev_date()
+.. autoclass:: Revoked
+ :members:
- Return the revocation date as a str.
- The string is formatted as an ASN1 GENERALIZEDTIME.
+Exceptions
+----------
+.. py:exception:: Error
-.. py:method:: Revoked.get_serial()
-
- Return a str containing a hex number of the serial of the revoked certificate.
-
-
-.. py:method:: Revoked.set_reason(reason)
-
- Set the revocation reason. *reason* must be None or a string, but the
- values are limited. Spaces and case are ignored. See
- :py:meth:`all_reasons`.
-
-
-.. py:method:: Revoked.set_rev_date(date)
-
- Set the revocation date.
- The string is formatted as an ASN1 GENERALIZEDTIME.
-
+ Generic exception used in the :py:mod:`.crypto` module.
-.. py:method:: Revoked.set_serial(serial)
+Digest names
+------------
- *serial* is a string containing a hex number of the serial of the revoked certificate.
+Several of the functions and methods in this module take a digest
+name. These must be strings describing a digest algorithm supported by
+OpenSSL (by ``EVP_get_digestbyname``, specifically). For example,
+:py:const:`b"md5"` or :py:const:`b"sha1"`.
+
+More information and a list of these digest names can be found in the
+``EVP_DigestInit(3)`` man page of your OpenSSL installation. This page
+can be found online for the latest version of OpenSSL:
+https://www.openssl.org/docs/crypto/EVP_DigestInit.html
+
+Backwards compatible type names
+-------------------------------
+
+When PyOpenSSL was originally written, the most current version of
+Python was 2.1. It made a distinction between classes and types. None
+of the versions of Python currently supported by PyOpenSSL still
+enforce that distinction: the type of an instance of an
+:py:class:`X509` object is now simply :py:class:`X509`. Originally,
+the type would have been :py:class:`X509Type`. These days,
+:py:class:`X509Type` and :py:class:`X509` are literally the same
+object. PyOpenSSL maintains these old names for backwards
+compatibility.
+
+Here's a table of these backwards-compatible names:
+
+========================= =============================
+Type name Backwards-compatible name
+========================= =============================
+:py:class:`X509` :py:class:`X509Type`
+:py:class:`X509Name` :py:class:`X509NameType`
+:py:class:`X509Req` :py:class:`X509ReqType`
+:py:class:`X509Store` :py:class:`X509StoreType`
+:py:class:`X509Extension` :py:class:`X509ExtensionType`
+:py:class:`PKey` :py:class:`PKeyType`
+:py:class:`PKCS7` :py:class:`PKCS7Type`
+:py:class:`PKCS12` :py:class:`PKCS12Type`
+:py:class:`NetscapeSPKI` :py:class:`NetscapeSPKIType`
+:py:class:`CRL` :py:class:`CRLType`
+========================= =============================
+
+Some objects, such as :py:class`Revoked`, don't have ``Type``
+equivalents, because they were added after the restriction had been
+lifted.
diff --git a/doc/conf.py b/doc/conf.py
index b13925f..dd6a334 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -11,7 +11,33 @@
# All configuration values have a default; values that are commented out
# serve to show the default.
-import sys, os
+import datetime
+import codecs
+import os
+import re
+import sys
+
+
+HERE = os.path.abspath(os.path.dirname(__file__))
+
+
+def read_file(*parts):
+ """
+ Build an absolute path from *parts* and and return the contents of the
+ resulting file. Assume UTF-8 encoding.
+ """
+ with codecs.open(os.path.join(HERE, *parts), "rb", "ascii") as f:
+ return f.read()
+
+
+def find_version(*file_paths):
+ version_file = read_file(*file_paths)
+ version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]",
+ version_file, re.M)
+ if version_match:
+ return version_match.group(1)
+ raise RuntimeError("Unable to find version string.")
+
DOC_DIR = os.path.abspath(os.path.dirname(__file__))
sys.path.insert(0, os.path.abspath(os.path.join(DOC_DIR, "..")))
@@ -28,7 +54,7 @@ needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = []
+extensions = ["sphinx.ext.autodoc"]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
@@ -44,14 +70,15 @@ master_doc = 'index'
# General information about the project.
project = u'pyOpenSSL'
-copyright = u'2011, Jean-Paul Calderone'
+authors = u"The pyOpenSSL developers"
+copyright = u"2001-{0}, {1}".format(datetime.date.today().year, authors)
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
-version = '0.15.1'
+version = find_version("../OpenSSL/version.py")
# The full version, including alpha/beta/rc tags.
release = version
@@ -182,7 +209,7 @@ htmlhelp_basename = 'pyOpenSSLdoc'
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'pyOpenSSL.tex', u'pyOpenSSL Documentation',
- u'Jean-Paul Calderone', 'manual'),
+ authors, 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
@@ -215,5 +242,5 @@ latex_documents = [
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'pyopenssl', u'pyOpenSSL Documentation',
- [u'Jean-Paul Calderone'], 1)
+ [authors], 1)
]
diff --git a/examples/certgen.py b/examples/certgen.py
index f157235..53c19b1 100644
--- a/examples/certgen.py
+++ b/examples/certgen.py
@@ -25,12 +25,12 @@ def createKeyPair(type, bits):
pkey.generate_key(type, bits)
return pkey
-def createCertRequest(pkey, digest="md5", **name):
+def createCertRequest(pkey, digest="sha256", **name):
"""
Create a certificate request.
Arguments: pkey - The key to associate with the request
- digest - Digestion method to use for signing, default is md5
+ digest - Digestion method to use for signing, default is sha256
**name - The name of the subject of the request, possible
arguments are:
C - Country name
@@ -45,14 +45,14 @@ def createCertRequest(pkey, digest="md5", **name):
req = crypto.X509Req()
subj = req.get_subject()
- for (key,value) in name.items():
+ for key, value in name.items():
setattr(subj, key, value)
req.set_pubkey(pkey)
req.sign(pkey, digest)
return req
-def createCertificate(req, (issuerCert, issuerKey), serial, (notBefore, notAfter), digest="md5"):
+def createCertificate(req, issuerCertKey, serial, validityPeriod, digest="sha256"):
"""
Generate a certificate given a certificate request.
@@ -64,9 +64,11 @@ def createCertificate(req, (issuerCert, issuerKey), serial, (notBefore, notAfter
starts being valid
notAfter - Timestamp (relative to now) when the certificate
stops being valid
- digest - Digest method to use for signing, default is md5
+ digest - Digest method to use for signing, default is sha256
Returns: The signed certificate in an X509 object
"""
+ issuerCert, issuerKey = issuerCertKey
+ notBefore, notAfter = validityPeriod
cert = crypto.X509()
cert.set_serial_number(serial)
cert.gmtime_adj_notBefore(notBefore)
diff --git a/examples/mk_simple_certs.py b/examples/mk_simple_certs.py
index 9dfdd2e..7129f13 100644
--- a/examples/mk_simple_certs.py
+++ b/examples/mk_simple_certs.py
@@ -4,14 +4,25 @@ Create certificates and private keys for the 'simple' example.
from OpenSSL import crypto
from certgen import * # yes yes, I know, I'm lazy
-cakey = createKeyPair(TYPE_RSA, 1024)
+cakey = createKeyPair(TYPE_RSA, 2048)
careq = createCertRequest(cakey, CN='Certificate Authority')
cacert = createCertificate(careq, (careq, cakey), 0, (0, 60*60*24*365*5)) # five years
-open('simple/CA.pkey', 'w').write(crypto.dump_privatekey(crypto.FILETYPE_PEM, cakey))
-open('simple/CA.cert', 'w').write(crypto.dump_certificate(crypto.FILETYPE_PEM, cacert))
+
+print('Creating Certificate Authority private key in "simple/CA.pkey"')
+with open('simple/CA.pkey', 'w') as capkey:
+ capkey.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, cakey).decode('utf-8'))
+print('Creating Certificate Authority certificate in "simple/CA.cert"')
+with open('simple/CA.cert', 'w') as ca:
+ ca.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cacert).decode('utf-8'))
+
for (fname, cname) in [('client', 'Simple Client'), ('server', 'Simple Server')]:
- pkey = createKeyPair(TYPE_RSA, 1024)
+ pkey = createKeyPair(TYPE_RSA, 2048)
req = createCertRequest(pkey, CN=cname)
cert = createCertificate(req, (cacert, cakey), 1, (0, 60*60*24*365*5)) # five years
- open('simple/%s.pkey' % (fname,), 'w').write(crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey))
- open('simple/%s.cert' % (fname,), 'w').write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
+ print('Creating Certificate %s private key in "simple/%s.pkey"' % (fname, fname))
+ with open('simple/%s.pkey' % (fname,), 'w') as leafpkey:
+ leafpkey.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey).decode('utf-8'))
+ print('Creating Certificate %s certificate in "simple/%s.cert"' % (fname, fname))
+ with open('simple/%s.cert' % (fname,), 'w') as leafcert:
+ leafcert.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert).decode('utf-8'))
+
diff --git a/examples/simple/client.py b/examples/simple/client.py
index 0247c67..36c37cd 100644
--- a/examples/simple/client.py
+++ b/examples/simple/client.py
@@ -8,16 +8,17 @@
Simple SSL client, using blocking I/O
"""
-from OpenSSL import SSL
+from OpenSSL import SSL, crypto
import sys, os, select, socket
def verify_cb(conn, cert, errnum, depth, ok):
- # This obviously has to be updated
- print 'Got certificate: %s' % cert.get_subject()
+ certsubject = crypto.X509Name(cert.get_subject())
+ commonname = certsubject.commonName
+ print('Got certificate: ' + commonname)
return ok
if len(sys.argv) < 3:
- print 'Usage: python[2] client.py HOST PORT'
+ print('Usage: python client.py HOST PORT')
sys.exit(1)
dir = os.path.dirname(sys.argv[0])
@@ -41,10 +42,10 @@ while 1:
break
try:
sock.send(line)
- sys.stdout.write(sock.recv(1024))
+ sys.stdout.write(sock.recv(1024).decode('utf-8'))
sys.stdout.flush()
except SSL.Error:
- print 'Connection died unexpectedly'
+ print('Connection died unexpectedly')
break
diff --git a/examples/simple/server.py b/examples/simple/server.py
index 37e36dd..df7c5a4 100644
--- a/examples/simple/server.py
+++ b/examples/simple/server.py
@@ -8,17 +8,18 @@
Simple echo server, using nonblocking I/O
"""
-from OpenSSL import SSL
+from OpenSSL import SSL, crypto
import sys, os, select, socket
def verify_cb(conn, cert, errnum, depth, ok):
- # This obviously has to be updated
- print 'Got certificate: %s' % cert.get_subject()
+ certsubject = crypto.X509Name(cert.get_subject())
+ commonname = certsubject.commonName
+ print(('Got certificate: ' + commonname))
return ok
if len(sys.argv) < 2:
- print 'Usage: python[2] server.py PORT'
+ print('Usage: python server.py PORT')
sys.exit(1)
dir = os.path.dirname(sys.argv[0])
@@ -44,12 +45,12 @@ writers = {}
def dropClient(cli, errors=None):
if errors:
- print 'Client %s left unexpectedly:' % (clients[cli],)
- print ' ', errors
+ print('Client %s left unexpectedly:' % (clients[cli],))
+ print(' ', errors)
else:
- print 'Client %s left politely' % (clients[cli],)
+ print('Client %s left politely' % (clients[cli],))
del clients[cli]
- if writers.has_key(cli):
+ if cli in writers:
del writers[cli]
if not errors:
cli.shutdown()
@@ -57,27 +58,27 @@ def dropClient(cli, errors=None):
while 1:
try:
- r,w,_ = select.select([server]+clients.keys(), writers.keys(), [])
+ r, w, _ = select.select([server] + list(clients.keys()), list(writers.keys()), [])
except:
break
for cli in r:
if cli == server:
cli,addr = server.accept()
- print 'Connection from %s' % (addr,)
+ print('Connection from %s' % (addr,))
clients[cli] = addr
else:
try:
- ret = cli.recv(1024)
+ ret = cli.recv(1024).decode('utf-8')
except (SSL.WantReadError, SSL.WantWriteError, SSL.WantX509LookupError):
pass
except SSL.ZeroReturnError:
dropClient(cli)
- except SSL.Error, errors:
+ except SSL.Error as errors:
dropClient(cli, errors)
else:
- if not writers.has_key(cli):
+ if cli not in writers:
writers[cli] = ''
writers[cli] = writers[cli] + ret
@@ -88,7 +89,7 @@ while 1:
pass
except SSL.ZeroReturnError:
dropClient(cli)
- except SSL.Error, errors:
+ except SSL.Error as errors:
dropClient(cli, errors)
else:
writers[cli] = writers[cli][ret:]
diff --git a/setup.py b/setup.py
index c4fbbd5..f742c1e 100755
--- a/setup.py
+++ b/setup.py
@@ -5,17 +5,45 @@
#
"""
-Installation script for the OpenSSL module
+Installation script for the OpenSSL module.
"""
+import codecs
+import os
+import re
import sys
from setuptools import setup
from setuptools.command.test import test as TestCommand
-# XXX Deduplicate this
-__version__ = '0.15.1'
+HERE = os.path.abspath(os.path.dirname(__file__))
+META_PATH = os.path.join("OpenSSL", "version.py")
+
+
+def read_file(*parts):
+ """
+ Build an absolute path from *parts* and and return the contents of the
+ resulting file. Assume UTF-8 encoding.
+ """
+ with codecs.open(os.path.join(HERE, *parts), "rb", "ascii") as f:
+ return f.read()
+
+
+META_FILE = read_file(META_PATH)
+
+
+def find_meta(meta):
+ """
+ Extract __*meta*__ from META_FILE.
+ """
+ meta_match = re.search(
+ r"^__{meta}__ = ['\"]([^'\"]*)['\"]".format(meta=meta),
+ META_FILE, re.M
+ )
+ if meta_match:
+ return meta_match.group(1)
+ raise RuntimeError("Unable to find __{meta}__ string.".format(meta=meta))
class PyTest(TestCommand):
@@ -38,38 +66,18 @@ class PyTest(TestCommand):
sys.exit(errno)
-setup(name='pyOpenSSL', version=__version__,
- packages = ['OpenSSL'],
- package_dir = {'OpenSSL': 'OpenSSL'},
- py_modules = ['OpenSSL.__init__',
- 'OpenSSL.tsafe',
- 'OpenSSL.rand',
- 'OpenSSL.crypto',
- 'OpenSSL.SSL',
- 'OpenSSL.version',
- 'OpenSSL.test.__init__',
- 'OpenSSL.test.util',
- 'OpenSSL.test.test_crypto',
- 'OpenSSL.test.test_rand',
- 'OpenSSL.test.test_ssl',
- 'OpenSSL.test.test_tsafe',
- 'OpenSSL.test.test_util',],
- description = 'Python wrapper module around the OpenSSL library',
- author = 'Jean-Paul Calderone',
- author_email = 'exarkun@twistedmatrix.com',
- maintainer = 'Jean-Paul Calderone',
- maintainer_email = 'exarkun@twistedmatrix.com',
- url = 'https://github.com/pyca/pyopenssl',
- license = 'APL2',
- install_requires=["cryptography>=0.7", "six>=1.5.2"],
- long_description = """\
-High-level wrapper around a subset of the OpenSSL library, includes
- * SSL.Connection objects, wrapping the methods of Python's portable
- sockets
- * Callbacks written in Python
- * Extensive error-handling mechanism, mirroring OpenSSL's error codes
-... and much more ;)""",
- classifiers = [
+setup(
+ name=find_meta("title"),
+ version=find_meta("version"),
+ description=find_meta("summary"),
+ long_description=read_file("README.rst"),
+ author=find_meta("author"),
+ author_email=find_meta("email"),
+ maintainer="Hynek Schlawack",
+ maintainer_email="hs@ox.cx",
+ url=find_meta("uri"),
+ license=find_meta("license"),
+ classifiers=[
'Development Status :: 6 - Mature',
'Intended Audience :: Developers',
'License :: OSI Approved :: Apache Software License',
@@ -77,20 +85,10 @@ High-level wrapper around a subset of the OpenSSL library, includes
'Operating System :: Microsoft :: Windows',
'Operating System :: POSIX',
- # General classifiers to indicate "this project supports Python 2" and
- # "this project supports Python 3".
'Programming Language :: Python :: 2',
- # In particular, this makes pyOpenSSL show up on
- # https://pypi.python.org/pypi?:action=browse&c=533&show=all and is in
- # accordance with
- # http://docs.python.org/2/howto/pyporting.html#universal-bits-of-advice
- 'Programming Language :: Python :: 3',
-
- # More specific classifiers to indicate more precisely which versions
- # of those languages the project supports.
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
- 'Programming Language :: Python :: 3.2',
+ 'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: Implementation :: CPython',
@@ -98,11 +96,32 @@ High-level wrapper around a subset of the OpenSSL library, includes
'Topic :: Security :: Cryptography',
'Topic :: Software Development :: Libraries :: Python Modules',
'Topic :: System :: Networking',
- ],
- test_suite="OpenSSL",
- tests_require=[
- "pytest",
- ],
- cmdclass={
- "test": PyTest,
- })
+ ],
+
+ packages=['OpenSSL'],
+ package_dir={'OpenSSL': 'OpenSSL'},
+ py_modules=['OpenSSL.__init__',
+ 'OpenSSL.tsafe',
+ 'OpenSSL.rand',
+ 'OpenSSL.crypto',
+ 'OpenSSL.SSL',
+ 'OpenSSL.version',
+ 'OpenSSL.test.__init__',
+ 'OpenSSL.test.util',
+ 'OpenSSL.test.test_crypto',
+ 'OpenSSL.test.test_rand',
+ 'OpenSSL.test.test_ssl',
+ 'OpenSSL.test.test_tsafe',
+ 'OpenSSL.test.test_util',],
+ install_requires=[
+ "cryptography>=0.7",
+ "six>=1.5.2"
+ ],
+ test_suite="OpenSSL",
+ tests_require=[
+ "pytest",
+ ],
+ cmdclass={
+ "test": PyTest,
+ }
+)
diff --git a/tox.ini b/tox.ini
index 8eb6910..ebf598e 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,16 +1,18 @@
[tox]
-envlist = pypy,py26,py27,py32,py33,py34,meta
+envlist = {pypy,py26,py27,py33,py34}{,-cryptographyMaster},pypi-readme,check-manifest,meta
[testenv]
deps =
setuptools>=7.0 # older setuptools pollute CWD with egg files of dependencies
coverage
+ cryptographyMaster: git+https://github.com/pyca/cryptography.git
setenv =
# Do not allowed the executing environment to pollute the test environment
# with extra packages.
PYTHONPATH=
commands =
python -c "import OpenSSL.SSL; print(OpenSSL.SSL.SSLeay_version(OpenSSL.SSL.SSLEAY_VERSION))"
+ python -c "import cryptography; print(cryptography.__version__)"
coverage run --branch --source=OpenSSL setup.py test
coverage report -m
@@ -26,3 +28,14 @@ commands =
pip-review
pyroma -d .
+[testenv:pypi-readme]
+deps =
+ readme
+commands =
+ python setup.py check -r -s
+
+[testenv:check-manifest]
+deps =
+ check-manifest
+commands =
+ check-manifest