initial source import
diff --git a/src/RATIONALE b/src/RATIONALE
new file mode 100644
index 0000000..a0e389c
--- /dev/null
+++ b/src/RATIONALE
@@ -0,0 +1,61 @@
+ RATIONALE
+
+The reason this module exists at all is that the SSL support in the socket
+module in the Python 2.1 distribution (which is what we used, of course I
+cannot speak for later versions) is severely limited.
+
+<FIXME> Update this list whenever needed! The communications module isn't
+written yet, so we don't know exactly how this'll work! </FIXME>
+This is a list of things we need from an OpenSSL module:
+ + Context objects (in OpenSSL called SSL_CTX) that can be manipulated from
+ Python modules. They must support a number of operations:
+ - Loading certificates from file and memory, both the client
+ certificate and the certificates used for the verification chain.
+ - Loading private keys from file and memory.
+ - Setting the verification mode (basically VERIFY_NONE and
+ VERIFY_PEER).
+ - Callbacks mechanism for prompting for pass phrases and verifying
+ certificates. The callbacks have to work under a multi-threaded
+ environment (see the comment in ssl/context.c). Of course the
+ callbacks will have to be written in Python!
+ + The Connection objects (in OpenSSL called SSL) have to support a few
+ things:
+ - Renegotiation, this is really important, especially for connections
+ that are up and running for a long time, since renegotiation
+ generates new encryption keys.
+ - Server-side SSL must work! As far as I know this doesn't work in
+ the SSL support of the socket module as of Python 2.1.
+ - Wrapping the methods of the underlying transport object is nice, so
+ you don't have to keep track of more than one object per connection.
+ This could of course be done a lot better than the way it works now,
+ so more transport layers than sockets are possible!
+ + A well-organized error system that mimics OpenSSL's error system is
+ desireable. Specifically there has to be a way to find out wether the
+ operation was successful, or if it failed, why it failed, so some sort
+ of interface to OpenSSL's error queue mechanism is needed.
+ + Certificate objects (X509) and certificate name objects (X509_NAME) are
+ needed, especially for verification purposes. Certificates will
+ probably also be generated by the server which is another reason for
+ them to exist. The same thing goes for key objects (EVP_PKEY)
+ + Since this is an OpenSSL module, there has to be an interface to the
+ OpenSSL PRNG, so it can be seeded in a good way.
+
+When asking about SSL on the comp.lang.python newsgroup (or on
+python-list@python.org) people usually pointed you to the M2Crypto package.
+The M2Crypto.SSL module does implement a lot of OpenSSL's functionality but
+unfortunately its error handling system does not seem to be finished,
+especially for non-blocking I/O. I think that much of the reason for this
+is that M2Crypto is developed using SWIG. This makes it awkward to create
+functions that e.g. can return both an integer and NULL since (as far as I
+know) you basically write C functions and SWIG makes wrapper functions that
+parses the Python argument list and calls your C function, and finally
+transforms your return value to a Python object.
+
+Finally, a good book on the topic of SSL (that I read and learned a lot
+from) is "SSL and TLS - Designing and Building Secure Systems" (ISBN
+0201615983) by Eric Rescorla. A good mailinglist to subscribe to is the
+openssl-users@openssl.org list.
+
+This comment was written July 2001, discussing Python 2.1. Feel free to
+modify it as the SSL support in the socket module changes.
+
diff --git a/src/crypto/crypto.c b/src/crypto/crypto.c
new file mode 100644
index 0000000..4fed5ba
--- /dev/null
+++ b/src/crypto/crypto.c
@@ -0,0 +1,738 @@
+/*
+ * crypto.c
+ *
+ * Copyright (C) AB Strakt 2001, All rights reserved
+ *
+ * Main file of crypto sub module.
+ * See the file RATIONALE for a short explanation of why this module was written.
+ *
+ * Reviewed 2001-07-23
+ */
+#include <Python.h>
+#define crypto_MODULE
+#include "crypto.h"
+
+static char crypto_doc[] = "\n\
+Main file of crypto sub module.\n\
+See the file RATIONALE for a short explanation of why this module was written.\n\
+";
+
+static char *CVSid = "@(#) $Id: crypto.c,v 1.28 2004/08/09 14:56:05 martin Exp $";
+
+void **ssl_API;
+
+PyObject *crypto_Error;
+
+static int
+global_passphrase_callback(char *buf, int len, int rwflag, void *cb_arg)
+{
+ PyObject *func, *argv, *ret;
+ int nchars;
+
+ func = (PyObject *)cb_arg;
+ argv = Py_BuildValue("(i)", rwflag);
+ ret = PyEval_CallObject(func, argv);
+ Py_DECREF(argv);
+ if (ret == NULL)
+ return 0;
+ if (!PyString_Check(ret))
+ {
+ PyErr_SetString(PyExc_ValueError, "String expected");
+ return 0;
+ }
+ nchars = PyString_Size(ret);
+ if (nchars > len)
+ nchars = len;
+ strncpy(buf, PyString_AsString(ret), nchars);
+ return nchars;
+}
+
+static char crypto_load_privatekey_doc[] = "\n\
+Load a private key from a buffer\n\
+\n\
+Arguments: spam - Always NULL\n\
+ args - The Python argument tuple, should be:\n\
+ type - The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\
+ buffer - The buffer the key is stored in\n\
+ passphrase - (optional) if encrypted PEM format, this can be\n\
+ either the passphrase to use, or a callback for\n\
+ providing the passphrase.\n\
+Returns: The PKey object\n\
+";
+
+static PyObject *
+crypto_load_privatekey(PyObject *spam, PyObject *args)
+{
+ crypto_PKeyObj *crypto_PKey_New(EVP_PKEY *, int);
+ int type, len;
+ char *buffer;
+ PyObject *pw = NULL;
+ pem_password_cb *cb = NULL;
+ void *cb_arg = NULL;
+ BIO *bio;
+ EVP_PKEY *pkey;
+
+ if (!PyArg_ParseTuple(args, "is#|O:load_privatekey", &type, &buffer, &len, &pw))
+ return NULL;
+
+ if (pw != NULL)
+ {
+ if (PyString_Check(pw))
+ {
+ cb = NULL;
+ cb_arg = PyString_AsString(pw);
+ }
+ else if (PyCallable_Check(pw))
+ {
+ cb = global_passphrase_callback;
+ cb_arg = pw;
+ }
+ else
+ {
+ PyErr_SetString(PyExc_TypeError, "Last argument must be string or callable");
+ return NULL;
+ }
+ }
+
+ bio = BIO_new_mem_buf(buffer, len);
+ switch (type)
+ {
+ case X509_FILETYPE_PEM:
+ pkey = PEM_read_bio_PrivateKey(bio, NULL, cb, cb_arg);
+ break;
+
+ case X509_FILETYPE_ASN1:
+ pkey = d2i_PrivateKey_bio(bio, NULL);
+ break;
+
+ default:
+ PyErr_SetString(PyExc_ValueError, "type argument must be FILETYPE_PEM or FILETYPE_ASN1");
+ BIO_free(bio);
+ return NULL;
+ }
+ BIO_free(bio);
+
+ if (pkey == NULL)
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+
+ return (PyObject *)crypto_PKey_New(pkey, 1);
+}
+
+static char crypto_dump_privatekey_doc[] = "\n\
+Dump a private key to a buffer\n\
+\n\
+Arguments: spam - Always NULL\n\
+ args - The Python argument tuple, should be:\n\
+ type - The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\
+ pkey - The PKey to dump\n\
+ cipher - (optional) if encrypted PEM format, the cipher to\n\
+ use\n\
+ passphrase - (optional) if encrypted PEM format, this can be either\n\
+ the passphrase to use, or a callback for providing the\n\
+ passphrase.\n\
+Returns: The buffer with the dumped key in\n\
+";
+
+static PyObject *
+crypto_dump_privatekey(PyObject *spam, PyObject *args)
+{
+ int type, ret, buf_len;
+ char *temp;
+ PyObject *buffer;
+ char *cipher_name = NULL;
+ const EVP_CIPHER *cipher = NULL;
+ PyObject *pw = NULL;
+ pem_password_cb *cb = NULL;
+ void *cb_arg = NULL;
+ BIO *bio;
+ crypto_PKeyObj *pkey;
+
+ if (!PyArg_ParseTuple(args, "iO!|sO:dump_privatekey", &type,
+ &crypto_PKey_Type, &pkey, &cipher_name, &pw))
+ return NULL;
+
+ if (cipher_name != NULL && pw == NULL)
+ {
+ PyErr_SetString(PyExc_ValueError, "Illegal number of arguments");
+ return NULL;
+ }
+ if (cipher_name != NULL)
+ {
+ cipher = EVP_get_cipherbyname(cipher_name);
+ if (cipher == NULL)
+ {
+ PyErr_SetString(PyExc_ValueError, "Invalid cipher name");
+ return NULL;
+ }
+ if (PyString_Check(pw))
+ {
+ cb = NULL;
+ cb_arg = PyString_AsString(pw);
+ }
+ else if (PyCallable_Check(pw))
+ {
+ cb = global_passphrase_callback;
+ cb_arg = pw;
+ }
+ else
+ {
+ PyErr_SetString(PyExc_TypeError, "Last argument must be string or callable");
+ return NULL;
+ }
+ }
+
+ bio = BIO_new(BIO_s_mem());
+ switch (type)
+ {
+ case X509_FILETYPE_PEM:
+ ret = PEM_write_bio_PrivateKey(bio, pkey->pkey, cipher, NULL, 0, cb, cb_arg);
+ if (PyErr_Occurred())
+ {
+ BIO_free(bio);
+ return NULL;
+ }
+ break;
+
+ case X509_FILETYPE_ASN1:
+ ret = i2d_PrivateKey_bio(bio, pkey->pkey);
+ break;
+
+ default:
+ PyErr_SetString(PyExc_ValueError, "type argument must be FILETYPE_PEM or FILETYPE_ASN1");
+ BIO_free(bio);
+ return NULL;
+ }
+
+ if (ret == 0)
+ {
+ BIO_free(bio);
+ exception_from_error_queue();
+ return NULL;
+ }
+
+ buf_len = BIO_get_mem_data(bio, &temp);
+ buffer = PyString_FromStringAndSize(temp, buf_len);
+ BIO_free(bio);
+
+ return buffer;
+}
+
+static char crypto_load_certificate_doc[] = "\n\
+Load a certificate from a buffer\n\
+\n\
+Arguments: spam - Always NULL\n\
+ args - The Python argument tuple, should be:\n\
+ type - The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\
+ buffer - The buffer the certificate is stored in\n\
+Returns: The X509 object\n\
+";
+
+static PyObject *
+crypto_load_certificate(PyObject *spam, PyObject *args)
+{
+ crypto_X509Obj *crypto_X509_New(X509 *, int);
+ int type, len;
+ char *buffer;
+ BIO *bio;
+ X509 *cert;
+
+ if (!PyArg_ParseTuple(args, "is#:load_certificate", &type, &buffer, &len))
+ return NULL;
+
+ bio = BIO_new_mem_buf(buffer, len);
+ switch (type)
+ {
+ case X509_FILETYPE_PEM:
+ cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+ break;
+
+ case X509_FILETYPE_ASN1:
+ cert = d2i_X509_bio(bio, NULL);
+ break;
+
+ default:
+ PyErr_SetString(PyExc_ValueError, "type argument must be FILETYPE_PEM or FILETYPE_ASN1");
+ BIO_free(bio);
+ return NULL;
+ }
+ BIO_free(bio);
+
+ if (cert == NULL)
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+
+ return (PyObject *)crypto_X509_New(cert, 1);
+}
+
+static char crypto_dump_certificate_doc[] = "\n\
+Dump a certificate to a buffer\n\
+\n\
+Arguments: spam - Always NULL\n\
+ args - The Python argument tuple, should be:\n\
+ type - The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\
+ cert - The certificate to dump\n\
+Returns: The buffer with the dumped certificate in\n\
+";
+
+static PyObject *
+crypto_dump_certificate(PyObject *spam, PyObject *args)
+{
+ int type, ret, buf_len;
+ char *temp;
+ PyObject *buffer;
+ BIO *bio;
+ crypto_X509Obj *cert;
+
+ if (!PyArg_ParseTuple(args, "iO!:dump_certificate", &type,
+ &crypto_X509_Type, &cert))
+ return NULL;
+
+ bio = BIO_new(BIO_s_mem());
+ switch (type)
+ {
+ case X509_FILETYPE_PEM:
+ ret = PEM_write_bio_X509(bio, cert->x509);
+ break;
+
+ case X509_FILETYPE_ASN1:
+ ret = i2d_X509_bio(bio, cert->x509);
+ break;
+
+ default:
+ PyErr_SetString(PyExc_ValueError, "type argument must be FILETYPE_PEM or FILETYPE_ASN1");
+ BIO_free(bio);
+ return NULL;
+ }
+
+ if (ret == 0)
+ {
+ BIO_free(bio);
+ exception_from_error_queue();
+ return NULL;
+ }
+
+ buf_len = BIO_get_mem_data(bio, &temp);
+ buffer = PyString_FromStringAndSize(temp, buf_len);
+ BIO_free(bio);
+
+ return buffer;
+}
+
+static char crypto_load_certificate_request_doc[] = "\n\
+Load a certificate request from a buffer\n\
+\n\
+Arguments: spam - Always NULL\n\
+ args - The Python argument tuple, should be:\n\
+ type - The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\
+ buffer - The buffer the certificate request is stored in\n\
+Returns: The X509Req object\n\
+";
+
+static PyObject *
+crypto_load_certificate_request(PyObject *spam, PyObject *args)
+{
+ crypto_X509ReqObj *crypto_X509Req_New(X509_REQ *, int);
+ int type, len;
+ char *buffer;
+ BIO *bio;
+ X509_REQ *req;
+
+ if (!PyArg_ParseTuple(args, "is#:load_certificate_request", &type, &buffer, &len))
+ return NULL;
+
+ bio = BIO_new_mem_buf(buffer, len);
+ switch (type)
+ {
+ case X509_FILETYPE_PEM:
+ req = PEM_read_bio_X509_REQ(bio, NULL, NULL, NULL);
+ break;
+
+ case X509_FILETYPE_ASN1:
+ req = d2i_X509_REQ_bio(bio, NULL);
+ break;
+
+ default:
+ PyErr_SetString(PyExc_ValueError, "type argument must be FILETYPE_PEM or FILETYPE_ASN1");
+ BIO_free(bio);
+ return NULL;
+ }
+ BIO_free(bio);
+
+ if (req == NULL)
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+
+ return (PyObject *)crypto_X509Req_New(req, 1);
+}
+
+static char crypto_dump_certificate_request_doc[] = "\n\
+Dump a certificate request to a buffer\n\
+\n\
+Arguments: spam - Always NULL\n\
+ args - The Python argument tuple, should be:\n\
+ type - The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\
+ req - The certificate request to dump\n\
+Returns: The buffer with the dumped certificate request in\n\
+";
+
+static PyObject *
+crypto_dump_certificate_request(PyObject *spam, PyObject *args)
+{
+ int type, ret, buf_len;
+ char *temp;
+ PyObject *buffer;
+ BIO *bio;
+ crypto_X509ReqObj *req;
+
+ if (!PyArg_ParseTuple(args, "iO!:dump_certificate_request", &type,
+ &crypto_X509Req_Type, &req))
+ return NULL;
+
+ bio = BIO_new(BIO_s_mem());
+ switch (type)
+ {
+ case X509_FILETYPE_PEM:
+ ret = PEM_write_bio_X509_REQ(bio, req->x509_req);
+ break;
+
+ case X509_FILETYPE_ASN1:
+ ret = i2d_X509_REQ_bio(bio, req->x509_req);
+ break;
+
+ default:
+ PyErr_SetString(PyExc_ValueError, "type argument must be FILETYPE_PEM or FILETYPE_ASN1");
+ BIO_free(bio);
+ return NULL;
+ }
+
+ if (ret == 0)
+ {
+ BIO_free(bio);
+ exception_from_error_queue();
+ return NULL;
+ }
+
+ buf_len = BIO_get_mem_data(bio, &temp);
+ buffer = PyString_FromStringAndSize(temp, buf_len);
+ BIO_free(bio);
+
+ return buffer;
+}
+
+static char crypto_load_pkcs7_data_doc[] = "\n\
+Load pkcs7 data from a buffer\n\
+\n\
+Arguments: spam - Always NULL\n\
+ args - The argument tuple, should be:\n\
+ type - The file type (one of FILETYPE_PEM or FILETYPE_ASN1)\n\
+ buffer - The buffer with the pkcs7 data.\n\
+Returns: The PKCS7 object\n\
+";
+
+static PyObject *
+crypto_load_pkcs7_data(PyObject *spam, PyObject *args)
+{
+ int type, len;
+ char *buffer;
+ BIO *bio;
+ PKCS7 *pkcs7 = NULL;
+
+ if (!PyArg_ParseTuple(args, "is#:load_pkcs7_data", &type, &buffer, &len))
+ return NULL;
+
+ /*
+ * Try to read the pkcs7 data from the bio
+ */
+ bio = BIO_new_mem_buf(buffer, len);
+ switch (type)
+ {
+ case X509_FILETYPE_PEM:
+ pkcs7 = PEM_read_bio_PKCS7(bio, NULL, NULL, NULL);
+ break;
+
+ case X509_FILETYPE_ASN1:
+ pkcs7 = d2i_PKCS7_bio(bio, NULL);
+ break;
+
+ default:
+ PyErr_SetString(PyExc_ValueError,
+ "type argument must be FILETYPE_PEM or FILETYPE_ASN1");
+ return NULL;
+ }
+ BIO_free(bio);
+
+ /*
+ * Check if we got a PKCS7 structure
+ */
+ if (pkcs7 == NULL)
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+
+ return (PyObject *)crypto_PKCS7_New(pkcs7, 1);
+}
+
+static char crypto_load_pkcs12_doc[] = "\n\
+Load a PKCS12 object from a buffer\n\
+\n\
+Arguments: spam - Always NULL\n\
+ args - The Python argument tuple, should be:\n\
+ buffer - The buffer the certificate is stored in\n\
+ passphrase (Optional) - The password to decrypt the PKCS12 lump\n\
+Returns: The PKCS12 object\n\
+";
+
+static PyObject *
+crypto_load_pkcs12(PyObject *spam, PyObject *args)
+{
+ crypto_PKCS12Obj *crypto_PKCS12_New(PKCS12 *, char *);
+ int len;
+ char *buffer, *passphrase = NULL;
+ BIO *bio;
+ PKCS12 *p12;
+
+ if (!PyArg_ParseTuple(args, "s#|s:load_pkcs12", &buffer, &len, &passphrase))
+ return NULL;
+
+ bio = BIO_new_mem_buf(buffer, len);
+ if ((p12 = d2i_PKCS12_bio(bio, NULL)) == NULL)
+ {
+ BIO_free(bio);
+ exception_from_error_queue();
+ return NULL;
+ }
+ BIO_free(bio);
+
+ return (PyObject *)crypto_PKCS12_New(p12, passphrase);
+}
+
+
+static char crypto_X509_doc[] = "\n\
+The factory function inserted in the module dictionary to create X509\n\
+objects\n\
+\n\
+Arguments: spam - Always NULL\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: The X509 object\n\
+";
+
+static PyObject *
+crypto_X509(PyObject *spam, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":X509"))
+ return NULL;
+
+ return (PyObject *)crypto_X509_New(X509_new(), 1);
+}
+
+static char crypto_X509Name_doc[] = "\n\
+The factory function inserted in the module dictionary as a copy\n\
+constructor for X509Name objects.\n\
+\n\
+Arguments: spam - Always NULL\n\
+ args - The Python argument tuple, should be:\n\
+ name - An X509Name object to copy\n\
+Returns: The X509Name object\n\
+";
+
+static PyObject *
+crypto_X509Name(PyObject *spam, PyObject *args)
+{
+ crypto_X509NameObj *name;
+
+ if (!PyArg_ParseTuple(args, "O!:X509Name", &crypto_X509Name_Type, &name))
+ return NULL;
+
+ return (PyObject *)crypto_X509Name_New(X509_NAME_dup(name->x509_name), 1);
+}
+
+static char crypto_X509Req_doc[] = "\n\
+The factory function inserted in the module dictionary to create X509Req\n\
+objects\n\
+\n\
+Arguments: spam - Always NULL\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: The X509Req object\n\
+";
+
+static PyObject *
+crypto_X509Req(PyObject *spam, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":X509Req"))
+ return NULL;
+
+ return (PyObject *)crypto_X509Req_New(X509_REQ_new(), 1);
+}
+
+static char crypto_PKey_doc[] = "\n\
+The factory function inserted in the module dictionary to create PKey\n\
+objects\n\
+\n\
+Arguments: spam - Always NULL\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: The PKey object\n\
+";
+
+static PyObject *
+crypto_PKey(PyObject *spam, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":PKey"))
+ return NULL;
+
+ return (PyObject *)crypto_PKey_New(EVP_PKEY_new(), 1);
+}
+
+static char crypto_X509Extension_doc[] = "\n\
+The factory function inserted in the module dictionary to create\n\
+X509Extension objects.\n\
+\n\
+Arguments: spam - Always NULL\n\
+ args - The Python argument tuple, should be\n\
+ typename - ???\n\
+ critical - ???\n\
+ value - ???\n\
+Returns: The X509Extension object\n\
+";
+
+static PyObject *
+crypto_X509Extension(PyObject *spam, PyObject *args)
+{
+ char *type_name, *value;
+ int critical;
+
+ if (!PyArg_ParseTuple(args, "sis:X509Extension", &type_name, &critical,
+ &value))
+ return NULL;
+
+ return (PyObject *)crypto_X509Extension_New(type_name, critical, value);
+}
+
+static char crypto_NetscapeSPKI_doc[] = "\n\
+The factory function inserted in the module dictionary to create NetscapeSPKI\n\
+objects\n\
+\n\
+Arguments: spam - Always NULL\n\
+ args - The Python argument tuple, should be empty or, optionally\n\
+ enc - Base64 encoded NetscapeSPKI object.\n\
+Returns: The NetscapeSPKI object\n\
+";
+
+static PyObject *
+crypto_NetscapeSPKI(PyObject *spam, PyObject *args)
+{
+ char *enc = NULL;
+ int enc_len = -1;
+ NETSCAPE_SPKI *spki;
+
+ if (!PyArg_ParseTuple(args, "|s#:NetscapeSPKI", &enc, &enc_len))
+ return NULL;
+
+ if (enc_len >= 0)
+ spki = NETSCAPE_SPKI_b64_decode(enc, enc_len);
+ else
+ spki = NETSCAPE_SPKI_new();
+ if (spki == NULL)
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+ return (PyObject *)crypto_NetscapeSPKI_New(spki, 1);
+}
+
+/* Methods in the OpenSSL.crypto module (i.e. none) */
+static PyMethodDef crypto_methods[] = {
+ /* Module functions */
+ { "load_privatekey", (PyCFunction)crypto_load_privatekey, METH_VARARGS, crypto_load_privatekey_doc },
+ { "dump_privatekey", (PyCFunction)crypto_dump_privatekey, METH_VARARGS, crypto_dump_privatekey_doc },
+ { "load_certificate", (PyCFunction)crypto_load_certificate, METH_VARARGS, crypto_load_certificate_doc },
+ { "dump_certificate", (PyCFunction)crypto_dump_certificate, METH_VARARGS, crypto_dump_certificate_doc },
+ { "load_certificate_request", (PyCFunction)crypto_load_certificate_request, METH_VARARGS, crypto_load_certificate_request_doc },
+ { "dump_certificate_request", (PyCFunction)crypto_dump_certificate_request, METH_VARARGS, crypto_dump_certificate_request_doc },
+ { "load_pkcs7_data", (PyCFunction)crypto_load_pkcs7_data, METH_VARARGS, crypto_load_pkcs7_data_doc },
+ { "load_pkcs12", (PyCFunction)crypto_load_pkcs12, METH_VARARGS, crypto_load_pkcs12_doc },
+ /* Factory functions */
+ { "X509", (PyCFunction)crypto_X509, METH_VARARGS, crypto_X509_doc },
+ { "X509Name",(PyCFunction)crypto_X509Name,METH_VARARGS, crypto_X509Name_doc },
+ { "X509Req", (PyCFunction)crypto_X509Req, METH_VARARGS, crypto_X509Req_doc },
+ { "PKey", (PyCFunction)crypto_PKey, METH_VARARGS, crypto_PKey_doc },
+ { "X509Extension", (PyCFunction)crypto_X509Extension, METH_VARARGS, crypto_X509Extension_doc },
+ { "NetscapeSPKI", (PyCFunction)crypto_NetscapeSPKI, METH_VARARGS, crypto_NetscapeSPKI_doc },
+ { NULL, NULL }
+};
+
+/*
+ * Initialize crypto sub module
+ *
+ * Arguments: None
+ * Returns: None
+ */
+void
+initcrypto(void)
+{
+ static void *crypto_API[crypto_API_pointers];
+ PyObject *c_api_object;
+ PyObject *module, *dict;
+
+ ERR_load_crypto_strings();
+ OpenSSL_add_all_algorithms();
+
+ if ((module = Py_InitModule3("crypto", crypto_methods, crypto_doc)) == NULL)
+ return;
+
+ /* Initialize the C API pointer array */
+ crypto_API[crypto_X509_New_NUM] = (void *)crypto_X509_New;
+ crypto_API[crypto_X509Name_New_NUM] = (void *)crypto_X509Name_New;
+ crypto_API[crypto_X509Req_New_NUM] = (void *)crypto_X509Req_New;
+ crypto_API[crypto_X509Store_New_NUM] = (void *)crypto_X509Store_New;
+ crypto_API[crypto_PKey_New_NUM] = (void *)crypto_PKey_New;
+ crypto_API[crypto_X509Extension_New_NUM] = (void *)crypto_X509Extension_New;
+ crypto_API[crypto_PKCS7_New_NUM] = (void *)crypto_PKCS7_New;
+ crypto_API[crypto_NetscapeSPKI_New_NUM] = (void *)crypto_NetscapeSPKI_New;
+ c_api_object = PyCObject_FromVoidPtr((void *)crypto_API, NULL);
+ if (c_api_object != NULL)
+ PyModule_AddObject(module, "_C_API", c_api_object);
+
+ crypto_Error = PyErr_NewException("OpenSSL.crypto.Error", NULL, NULL);
+ if (crypto_Error == NULL)
+ goto error;
+ if (PyModule_AddObject(module, "Error", crypto_Error) != 0)
+ goto error;
+
+ PyModule_AddIntConstant(module, "FILETYPE_PEM", X509_FILETYPE_PEM);
+ PyModule_AddIntConstant(module, "FILETYPE_ASN1", X509_FILETYPE_ASN1);
+
+ PyModule_AddIntConstant(module, "TYPE_RSA", crypto_TYPE_RSA);
+ PyModule_AddIntConstant(module, "TYPE_DSA", crypto_TYPE_DSA);
+
+ dict = PyModule_GetDict(module);
+ if (!init_crypto_x509(dict))
+ goto error;
+ if (!init_crypto_x509name(dict))
+ goto error;
+ if (!init_crypto_x509store(dict))
+ goto error;
+ if (!init_crypto_x509req(dict))
+ goto error;
+ if (!init_crypto_pkey(dict))
+ goto error;
+ if (!init_crypto_x509extension(dict))
+ goto error;
+ if (!init_crypto_pkcs7(dict))
+ goto error;
+ if (!init_crypto_pkcs12(dict))
+ goto error;
+ if (!init_crypto_netscape_spki(dict))
+ goto error;
+
+error:
+ ;
+}
+
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
new file mode 100644
index 0000000..0a71d2a
--- /dev/null
+++ b/src/crypto/crypto.h
@@ -0,0 +1,120 @@
+/*
+ * crypto.h
+ *
+ * Copyright (C) AB Strakt 2001, All rights reserved
+ *
+ * Exports from crypto.c.
+ * See the file RATIONALE for a short explanation of why this module was written.
+ *
+ * Reviewed 2001-07-23
+ *
+ * @(#) $Id: crypto.h,v 1.14 2004/08/09 13:41:25 martin Exp $
+ */
+#ifndef PyOpenSSL_CRYPTO_H_
+#define PyOpenSSL_CRYPTO_H_
+
+#include <Python.h>
+#include "x509.h"
+#include "x509name.h"
+#include "netscape_spki.h"
+#include "x509store.h"
+#include "x509req.h"
+#include "pkey.h"
+#include "x509ext.h"
+#include "pkcs7.h"
+#include "pkcs12.h"
+#include "../util.h"
+
+extern PyObject *crypto_Error;
+
+#ifdef exception_from_error_queue
+# undef exception_from_error_queue
+#endif
+#define exception_from_error_queue() do { \
+ PyObject *errlist = error_queue_to_list(); \
+ PyErr_SetObject(crypto_Error, errlist); \
+ Py_DECREF(errlist); \
+} while (0)
+
+#define crypto_X509_New_NUM 0
+#define crypto_X509_New_RETURN crypto_X509Obj *
+#define crypto_X509_New_PROTO (X509 *, int)
+
+#define crypto_X509Req_New_NUM 1
+#define crypto_X509Req_New_RETURN crypto_X509ReqObj *
+#define crypto_X509Req_New_PROTO (X509_REQ *, int)
+
+#define crypto_X509Store_New_NUM 2
+#define crypto_X509Store_New_RETURN crypto_X509StoreObj *
+#define crypto_X509Store_New_PROTO (X509_STORE *, int)
+
+#define crypto_PKey_New_NUM 3
+#define crypto_PKey_New_RETURN crypto_PKeyObj *
+#define crypto_PKey_New_PROTO (EVP_PKEY *, int)
+
+#define crypto_X509Name_New_NUM 4
+#define crypto_X509Name_New_RETURN crypto_X509NameObj *
+#define crypto_X509Name_New_PROTO (X509_NAME *, int)
+
+#define crypto_X509Extension_New_NUM 5
+#define crypto_X509Extension_New_RETURN crypto_X509ExtensionObj *
+#define crypto_X509Extension_New_PROTO (char *, int, char *)
+
+#define crypto_PKCS7_New_NUM 6
+#define crypto_PKCS7_New_RETURN crypto_PKCS7Obj *
+#define crypto_PKCS7_New_PROTO (PKCS7 *, int)
+
+#define crypto_NetscapeSPKI_New_NUM 7
+#define crypto_NetscapeSPKI_New_RETURN crypto_NetscapeSPKIObj *
+#define crypto_NetscapeSPKI_New_PROTO (NETSCAPE_SPKI *, int)
+
+#define crypto_API_pointers 8
+
+#ifdef crypto_MODULE
+
+extern crypto_X509_New_RETURN crypto_X509_New crypto_X509_New_PROTO;
+extern crypto_X509Name_New_RETURN crypto_X509Name_New crypto_X509Name_New_PROTO;
+extern crypto_X509Req_New_RETURN crypto_X509Req_New crypto_X509Req_New_PROTO;
+extern crypto_X509Store_New_RETURN crypto_X509Store_New crypto_X509Store_New_PROTO;
+extern crypto_PKey_New_RETURN crypto_PKey_New crypto_PKey_New_PROTO;
+extern crypto_X509Extension_New_RETURN crypto_X509Extension_New crypto_X509Extension_New_PROTO;
+extern crypto_PKCS7_New_RETURN crypto_PKCS7_New crypto_PKCS7_New_PROTO;
+extern crypto_NetscapeSPKI_New_RETURN crypto_NetscapeSPKI_New crypto_NetscapeSPKI_New_PROTO;
+
+#else /* crypto_MODULE */
+
+extern void **crypto_API;
+
+#define crypto_X509_New \
+ (*(crypto_X509_New_RETURN (*)crypto_X509_New_PROTO) crypto_API[crypto_X509_New_NUM])
+#define crypto_X509Name_New \
+ (*(crypto_X509Name_New_RETURN (*)crypto_X509Name_New_PROTO) crypto_API[crypto_X509Name_New_NUM])
+#define crypto_X509Req_New \
+ (*(crypto_X509Req_New_RETURN (*)crypto_X509Req_New_PROTO) crypto_API[crypto_X509Req_New_NUM])
+#define crypto_X509Store_New \
+ (*(crypto_X509Store_New_RETURN (*)crypto_X509Store_New_PROTO) crypto_API[crypto_X509Store_New_NUM])
+#define crypto_PKey_New \
+ (*(crypto_PKey_New_RETURN (*)crypto_PKey_New_PROTO) crypto_API[crypto_PKey_New_NUM])
+#define crypto_X509Extension_New\
+ (*(crypto_X509Extension_New_RETURN (*)crypto_X509Extension_New_PROTO) crypto_API[crypto_X509Extension_New_NUM])
+#define crypto_PKCS7_New \
+ (*(crypto_PKCS7_New_RETURN (*)crypto_PKCS7_New_PROTO) crypto_API[crypto_PKCS7_New_NUM])
+#define crypto_NetscapeSPKI_New \
+ (*(crypto_NetscapeSPKI_New_RETURN (*)crypto_NetscapeSPKI_New_PROTO) crypto_API[crypto_NetscapeSPKI_New_NUM])
+
+#define import_crypto() \
+{ \
+ PyObject *crypto_module = PyImport_ImportModule("OpenSSL.crypto"); \
+ if (crypto_module != NULL) { \
+ PyObject *crypto_dict, *crypto_api_object; \
+ crypto_dict = PyModule_GetDict(crypto_module); \
+ crypto_api_object = PyDict_GetItemString(crypto_dict, "_C_API"); \
+ if (PyCObject_Check(crypto_api_object)) { \
+ crypto_API = (void **)PyCObject_AsVoidPtr(crypto_api_object); \
+ } \
+ } \
+}
+
+#endif /* crypto_MODULE */
+
+#endif /* PyOpenSSL_CRYPTO_H_ */
diff --git a/src/crypto/netscape_spki.c b/src/crypto/netscape_spki.c
new file mode 100644
index 0000000..cc54783
--- /dev/null
+++ b/src/crypto/netscape_spki.c
@@ -0,0 +1,257 @@
+/*
+ * netscape_spki.c
+ *
+ * Copyright (C) Tollef Fog Heen 2003
+ *
+ * Netscape SPKI handling, thin wrapper
+ */
+#include <Python.h>
+#define crypto_MODULE
+#include "crypto.h"
+
+static char *CVSid = "@(#) $Id: netscape_spki.c,v 1.1 2004/08/09 13:41:25 martin Exp $";
+
+
+/*
+ * Constructor for Nestcape_SPKI, never called by Python code directly
+ *
+ * Arguments: name - A "real" NetscapeSPKI object
+ * dealloc - Boolean value to specify whether the destructor should
+ * free the "real" NetscapeSPKI object
+ * Returns: The newly created NetscapeSPKI object
+ */
+crypto_NetscapeSPKIObj *
+crypto_NetscapeSPKI_New(NETSCAPE_SPKI *name, int dealloc)
+{
+ crypto_NetscapeSPKIObj *self;
+
+ self = PyObject_New(crypto_NetscapeSPKIObj, &crypto_NetscapeSPKI_Type);
+
+ if (self == NULL)
+ return NULL;
+
+ self->netscape_spki = name;
+ self->dealloc = dealloc;
+
+ return self;
+}
+
+/*
+ * Deallocate the memory used by the NetscapeSPKI object
+ *
+ * Arguments: self - The NetscapeSPKI object
+ * Returns: None
+ */
+static void
+crypto_NetscapeSPKI_dealloc(crypto_NetscapeSPKIObj *self)
+{
+ /* Sometimes we don't have to dealloc this */
+ if (self->dealloc)
+ NETSCAPE_SPKI_free(self->netscape_spki);
+
+ PyObject_Del(self);
+}
+
+static char crypto_NetscapeSPKI_sign_doc[] = "\n\
+Sign the certificate request using the supplied key and digest\n\
+\n\
+Arguments: self - The NetscapeSPKI object\n\
+ args - The Python argument tuple, should be:\n\
+ pkey - The key to sign with\n\
+ digest - The message digest to use\n\
+Returns: None\n\
+";
+
+static PyObject *
+crypto_NetscapeSPKI_sign(crypto_NetscapeSPKIObj *self, PyObject *args)
+{
+ crypto_PKeyObj *pkey;
+ char *digest_name;
+ const EVP_MD *digest;
+
+ if (!PyArg_ParseTuple(args, "O!s:sign", &crypto_PKey_Type, &pkey,
+ &digest_name))
+ return NULL;
+
+ if ((digest = EVP_get_digestbyname(digest_name)) == NULL)
+ {
+ PyErr_SetString(PyExc_ValueError, "No such digest method");
+ return NULL;
+ }
+
+ if (!NETSCAPE_SPKI_sign(self->netscape_spki, pkey->pkey, digest))
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char crypto_NetscapeSPKI_verify_doc[] = "\n\
+Verifies a certificate request using the supplied public key\n\
+ \n\
+Arguments: self - NetscapeSPKI object\n\
+ args - The Python argument tuple, should be:\n\
+ key - a public key\n\
+Returns: True, if the signature is correct, 0 otherwise.\n\
+";
+
+PyObject *
+crypto_NetscapeSPKI_verify(crypto_NetscapeSPKIObj *self, PyObject *args)
+{
+ crypto_PKeyObj *pkey;
+ int answer;
+
+ if (!PyArg_ParseTuple(args, "O!:verify", &crypto_PKey_Type, &pkey))
+ return NULL;
+
+ if ((answer = NETSCAPE_SPKI_verify(self->netscape_spki, pkey->pkey)) < 0)
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+
+ return PyInt_FromLong((long)answer);
+}
+
+static char crypto_NetscapeSPKI_b64_encode_doc[] = "\n\
+Generate a base64 encoded string from an SPKI\n\
+ \n\
+Arguments: self - NetscapeSPKI object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: The base64 encoded string\n\
+";
+
+PyObject *
+crypto_NetscapeSPKI_b64_encode(crypto_NetscapeSPKIObj *self, PyObject *args)
+{
+ char *str;
+
+ if (!PyArg_ParseTuple(args, ":b64_encode"))
+ return NULL;
+
+ str = NETSCAPE_SPKI_b64_encode(self->netscape_spki);
+ return PyString_FromString(str);
+}
+
+
+static char crypto_NetscapeSPKI_get_pubkey_doc[] = "\n\
+Get the public key of the certificate\n\
+\n\
+Arguments: self - The NETSCAPE_SPKI object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: The public key\n\
+";
+
+static PyObject *
+crypto_NetscapeSPKI_get_pubkey(crypto_NetscapeSPKIObj *self, PyObject *args)
+{
+ crypto_PKeyObj *crypto_PKey_New(EVP_PKEY *, int);
+ EVP_PKEY *pkey;
+
+ if (!PyArg_ParseTuple(args, ":get_pubkey"))
+ return NULL;
+
+ if ((pkey = NETSCAPE_SPKI_get_pubkey(self->netscape_spki)) == NULL)
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+
+ return (PyObject *)crypto_PKey_New(pkey, 0);
+}
+
+static char crypto_NetscapeSPKI_set_pubkey_doc[] = "\n\
+Set the public key of the certificate\n\
+\n\
+Arguments: self - The Netscape SPKI object\n\
+ args - The Python argument tuple, should be:\n\
+ pkey - The public key\n\
+Returns: None\n\
+";
+
+static PyObject *
+crypto_NetscapeSPKI_set_pubkey(crypto_NetscapeSPKIObj *self, PyObject *args)
+{
+ crypto_PKeyObj *pkey;
+
+ if (!PyArg_ParseTuple(args, "O!:set_pubkey", &crypto_PKey_Type, &pkey))
+ return NULL;
+
+ if (!NETSCAPE_SPKI_set_pubkey(self->netscape_spki, pkey->pkey))
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/*
+ * ADD_METHOD(name) expands to a correct PyMethodDef declaration
+ * { 'name', (PyCFunction)crypto_NetscapeSPKI_name, METH_VARARGS }
+ * for convenience
+ */
+#define ADD_METHOD(name) \
+ { #name, (PyCFunction)crypto_NetscapeSPKI_##name, METH_VARARGS, crypto_NetscapeSPKI_##name##_doc }
+static PyMethodDef crypto_NetscapeSPKI_methods[] =
+{
+ ADD_METHOD(get_pubkey),
+ ADD_METHOD(set_pubkey),
+ ADD_METHOD(b64_encode),
+ ADD_METHOD(sign),
+ ADD_METHOD(verify),
+ { NULL, NULL }
+};
+#undef ADD_METHOD
+
+/*
+ * Find attribute
+ *
+ * Arguments: self - The NetscapeSPKI object
+ * name - The attribute name
+ * Returns: A Python object for the attribute, or NULL if something went
+ * wrong
+ */
+static PyObject *
+crypto_NetscapeSPKI_getattr(crypto_NetscapeSPKIObj *self, char *name)
+{
+ return Py_FindMethod(crypto_NetscapeSPKI_methods, (PyObject *)self, name);
+}
+
+PyTypeObject crypto_NetscapeSPKI_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "NetscapeSPKI",
+ sizeof(crypto_NetscapeSPKIObj),
+ 0,
+ (destructor)crypto_NetscapeSPKI_dealloc,
+ NULL, /* print */
+ (getattrfunc)crypto_NetscapeSPKI_getattr,
+ NULL, /* setattr */
+ NULL, /* compare */
+ NULL, /* repr */
+ NULL, /* as_number */
+ NULL, /* as_sequence */
+ NULL, /* as_mapping */
+ NULL /* hash */
+};
+
+
+/*
+ * Initialize the X509Name part of the crypto module
+ *
+ * Arguments: dict - The crypto module dictionary
+ * Returns: None
+ */
+int
+init_crypto_netscape_spki(PyObject *dict)
+{
+ crypto_NetscapeSPKI_Type.ob_type = &PyType_Type;
+ Py_INCREF(&crypto_NetscapeSPKI_Type);
+ PyDict_SetItemString(dict, "NetscapeSPKIType", (PyObject *)&crypto_NetscapeSPKI_Type);
+ return 1;
+}
diff --git a/src/crypto/netscape_spki.h b/src/crypto/netscape_spki.h
new file mode 100644
index 0000000..19389d8
--- /dev/null
+++ b/src/crypto/netscape_spki.h
@@ -0,0 +1,29 @@
+/*
+ * netscape_spki.h
+ *
+ * Copyright (C) Tollef Fog Heen 2003, All rights reserved
+ *
+ * Handle Netscape SPKI (challenge response) certificate requests.
+ *
+ *
+ */
+#ifndef PyOpenSSL_crypto_Netscape_SPKI_H_
+#define PyOpenSSL_crypto_Netscape_SPKI_H_
+
+#include <Python.h>
+#include <openssl/ssl.h>
+
+extern int init_crypto_netscape_spki (PyObject *);
+
+extern PyTypeObject crypto_NetscapeSPKI_Type;
+
+#define crypto_NetscapeSPKI_Check(v) ((v)->ob_type == &crypto_NetscapeSPKI_Type)
+
+typedef struct {
+ PyObject_HEAD
+ NETSCAPE_SPKI *netscape_spki;
+ int dealloc;
+} crypto_NetscapeSPKIObj;
+
+
+#endif
diff --git a/src/crypto/pkcs12.c b/src/crypto/pkcs12.c
new file mode 100644
index 0000000..ab7562d
--- /dev/null
+++ b/src/crypto/pkcs12.c
@@ -0,0 +1,275 @@
+/*
+ * pkcs12.c
+ *
+ * Copyright (C) AB Strakt 2001, All rights reserved
+ *
+ * Certificate transport (PKCS12) handling code,
+ * mostly thin wrappers around OpenSSL.
+ * See the file RATIONALE for a short explanation of why
+ * this module was written.
+ *
+ * Reviewed 2001-07-23
+ */
+#include <Python.h>
+#define crypto_MODULE
+#include "crypto.h"
+
+static char *CVSid = "@(#) $Id: pkcs12.c,v 1.3 2003/01/09 17:08:32 martin Exp $";
+
+/*
+ * PKCS12 is a standard exchange format for digital certificates.
+ * See e.g. the OpenSSL homepage http://www.openssl.org/ for more information
+ */
+
+static void crypto_PKCS12_dealloc(crypto_PKCS12Obj *self);
+
+static char crypto_PKCS12_get_certificate_doc[] = "\n\
+Return certificate portion of the PKCS12 structure\n\
+\n\
+Arguments: self - The PKCS12 object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: X509 object containing the certificate\n\
+";
+static PyObject *
+crypto_PKCS12_get_certificate(crypto_PKCS12Obj *self, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":get_certificate"))
+ return NULL;
+
+ Py_INCREF(self->cert);
+ return self->cert;
+}
+
+static char crypto_PKCS12_get_privatekey_doc[] = "\n\
+Return private key portion of the PKCS12 structure\n\
+\n\
+Arguments: self - The PKCS12 object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: PKey object containing the private key\n\
+";
+static PyObject *
+crypto_PKCS12_get_privatekey(crypto_PKCS12Obj *self, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":get_privatekey"))
+ return NULL;
+
+ Py_INCREF(self->key);
+ return self->key;
+}
+
+static char crypto_PKCS12_get_ca_certificates_doc[] = "\n\
+Return CA certificates within of the PKCS12 object\n\
+\n\
+Arguments: self - The PKCS12 object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: A newly created tuple containing the CA certificates in the chain,\n\
+ if any are present, or None if no CA certificates are present.\n\
+";
+static PyObject *
+crypto_PKCS12_get_ca_certificates(crypto_PKCS12Obj *self, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":get_ca_certificates"))
+ return NULL;
+
+ Py_INCREF(self->cacerts);
+ return self->cacerts;
+}
+
+/*
+ * ADD_METHOD(name) expands to a correct PyMethodDef declaration
+ * { 'name', (PyCFunction)crypto_PKCS12_name, METH_VARARGS, crypto_PKCS12_name_doc }
+ * for convenience
+ */
+#define ADD_METHOD(name) \
+ { #name, (PyCFunction)crypto_PKCS12_##name, METH_VARARGS, crypto_PKCS12_##name##_doc }
+static PyMethodDef crypto_PKCS12_methods[] =
+{
+ ADD_METHOD(get_certificate),
+ ADD_METHOD(get_privatekey),
+ ADD_METHOD(get_ca_certificates),
+ { NULL, NULL }
+};
+#undef ADD_METHOD
+
+/*
+ * Constructor for PKCS12 objects, never called by Python code directly.
+ * The strategy for this object is to create all the Python objects
+ * corresponding to the cert/key/CA certs right away
+ *
+ * Arguments: p12 - A "real" PKCS12 object
+ * passphrase - Passphrase to use when decrypting the PKCS12 object
+ * Returns: The newly created PKCS12 object
+ */
+crypto_PKCS12Obj *
+crypto_PKCS12_New(PKCS12 *p12, char *passphrase)
+{
+ crypto_PKCS12Obj *self;
+ PyObject *cacertobj = NULL;
+
+ X509 *cert = NULL;
+ EVP_PKEY *pkey = NULL;
+ STACK_OF(X509) *cacerts = NULL;
+
+ int i, cacert_count = 0;
+
+ /* allocate space for the CA cert stack */
+ cacerts = sk_X509_new_null();
+
+ /* parse the PKCS12 lump */
+ if (!(cacerts && PKCS12_parse(p12, passphrase, &pkey, &cert, &cacerts)))
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+
+ if (!(self = PyObject_GC_New(crypto_PKCS12Obj, &crypto_PKCS12_Type)))
+ return NULL;
+
+ self->cert = NULL;
+ self->key = NULL;
+ Py_INCREF(Py_None);
+ self->cacerts = Py_None;
+
+ if ((self->cert = (PyObject *)crypto_X509_New(cert, 1)) == NULL)
+ goto error;
+
+ if ((self->key = (PyObject *)crypto_PKey_New(pkey, 1)) == NULL)
+ goto error;
+
+ /* Make a tuple for the CA certs */
+ cacert_count = sk_X509_num(cacerts);
+ if (cacert_count > 0)
+ {
+ Py_DECREF(self->cacerts);
+ if ((self->cacerts = PyTuple_New(cacert_count)) == NULL)
+ goto error;
+
+ for (i = 0; i < cacert_count; i++)
+ {
+ cert = sk_X509_value(cacerts, i);
+ if ((cacertobj = (PyObject *)crypto_X509_New(cert, 1)) == NULL)
+ goto error;
+ PyTuple_SET_ITEM(self->cacerts, i, cacertobj);
+ }
+ }
+
+ sk_X509_free(cacerts); /* don't free the certs, just the stack */
+ PyObject_GC_Track(self);
+
+ return self;
+error:
+ crypto_PKCS12_dealloc(self);
+ return NULL;
+}
+
+/*
+ * Find attribute
+ *
+ * Arguments: self - The PKCS12 object
+ * name - The attribute name
+ * Returns: A Python object for the attribute, or NULL if something went
+ * wrong
+ */
+static PyObject *
+crypto_PKCS12_getattr(crypto_PKCS12Obj *self, char *name)
+{
+ return Py_FindMethod(crypto_PKCS12_methods, (PyObject *)self, name);
+}
+
+/*
+ * Call the visitproc on all contained objects.
+ *
+ * Arguments: self - The PKCS12 object
+ * visit - Function to call
+ * arg - Extra argument to visit
+ * Returns: 0 if all goes well, otherwise the return code from the first
+ * call that gave non-zero result.
+ */
+static int
+crypto_PKCS12_traverse(crypto_PKCS12Obj *self, visitproc visit, void *arg)
+{
+ int ret = 0;
+
+ if (ret == 0 && self->cert != NULL)
+ ret = visit(self->cert, arg);
+ if (ret == 0 && self->key != NULL)
+ ret = visit(self->key, arg);
+ if (ret == 0 && self->cacerts != NULL)
+ ret = visit(self->cacerts, arg);
+ return ret;
+}
+
+/*
+ * Decref all contained objects and zero the pointers.
+ *
+ * Arguments: self - The PKCS12 object
+ * Returns: Always 0.
+ */
+static int
+crypto_PKCS12_clear(crypto_PKCS12Obj *self)
+{
+ Py_XDECREF(self->cert);
+ self->cert = NULL;
+ Py_XDECREF(self->key);
+ self->key = NULL;
+ Py_XDECREF(self->cacerts);
+ self->cacerts = NULL;
+ return 0;
+}
+
+/*
+ * Deallocate the memory used by the PKCS12 object
+ *
+ * Arguments: self - The PKCS12 object
+ * Returns: None
+ */
+static void
+crypto_PKCS12_dealloc(crypto_PKCS12Obj *self)
+{
+ PyObject_GC_UnTrack(self);
+ crypto_PKCS12_clear(self);
+ PyObject_GC_Del(self);
+}
+
+PyTypeObject crypto_PKCS12_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "PKCS12",
+ sizeof(crypto_PKCS12Obj),
+ 0,
+ (destructor)crypto_PKCS12_dealloc,
+ NULL, /* print */
+ (getattrfunc)crypto_PKCS12_getattr,
+ NULL, /* setattr */
+ NULL, /* compare */
+ NULL, /* repr */
+ NULL, /* as_number */
+ NULL, /* as_sequence */
+ NULL, /* as_mapping */
+ NULL, /* hash */
+ NULL, /* call */
+ NULL, /* str */
+ NULL, /* getattro */
+ NULL, /* setattro */
+ NULL, /* as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
+ NULL, /* doc */
+ (traverseproc)crypto_PKCS12_traverse,
+ (inquiry)crypto_PKCS12_clear,
+};
+
+/*
+ * Initialize the PKCS12 part of the crypto sub module
+ *
+ * Arguments: dict - The crypto module dictionary
+ * Returns: None
+ */
+int
+init_crypto_pkcs12(PyObject *dict)
+{
+ crypto_PKCS12_Type.ob_type = &PyType_Type;
+ Py_INCREF(&crypto_PKCS12_Type);
+ PyDict_SetItemString(dict, "PKCS12Type", (PyObject *)&crypto_PKCS12_Type);
+ return 1;
+}
+
diff --git a/src/crypto/pkcs12.h b/src/crypto/pkcs12.h
new file mode 100644
index 0000000..32c9ec4
--- /dev/null
+++ b/src/crypto/pkcs12.h
@@ -0,0 +1,30 @@
+/*
+ * pkcs12.h
+ *
+ * Copyright (C) AB Strakt 2001, All rights reserved
+ *
+ * Export PKCS12 functions and data structure.
+ *
+ * @(#) $$
+ */
+#ifndef PyOpenSSL_crypto_PKCS12_H_
+#define PyOpenSSL_crypto_PKCS12_H_
+
+#include <Python.h>
+#include <openssl/pkcs12.h>
+#include <openssl/asn1.h>
+
+extern int init_crypto_pkcs12 (PyObject *);
+
+extern PyTypeObject crypto_PKCS12_Type;
+
+#define crypto_PKCS12_Check(v) ((v)->ob_type == &crypto_PKCS12_Type)
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *cert;
+ PyObject *key;
+ PyObject *cacerts;
+} crypto_PKCS12Obj;
+
+#endif
diff --git a/src/crypto/pkcs7.c b/src/crypto/pkcs7.c
new file mode 100644
index 0000000..1fb20a9
--- /dev/null
+++ b/src/crypto/pkcs7.c
@@ -0,0 +1,223 @@
+/*
+ * pkcs7.c
+ *
+ * Copyright (C) AB Strakt 2002, All rights reserved
+ *
+ * PKCS7 handling code, mostly thin wrappers around OpenSSL.
+ * See the file RATIONALE for a short explanation of why this module was written.
+ *
+ */
+#include <Python.h>
+#define crypto_MODULE
+#include "crypto.h"
+
+static char *CVSid = "@(#) $Id: pkcs7.c,v 1.2 2002/07/09 12:55:13 martin Exp $";
+
+static char crypto_PKCS7_type_is_signed_doc[] = "\n\
+Check if this NID_pkcs7_signed object\n\
+\n\
+Arguments: self - The PKCS7 object\n\
+ args - An empty argument tuple\n\
+Returns: True if the PKCS7 is of type signed\n\
+";
+
+static PyObject *
+crypto_PKCS7_type_is_signed(crypto_PKCS7Obj *self, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":type_is_signed"))
+ return NULL;
+
+ if (PKCS7_type_is_signed(self->pkcs7))
+ return PyInt_FromLong(1L);
+ else
+ return PyInt_FromLong(0L);
+}
+
+static char crypto_PKCS7_type_is_enveloped_doc[] = "\n\
+Check if this NID_pkcs7_enveloped object\n\
+\n\
+Arguments: self - The PKCS7 object\n\
+ args - An empty argument tuple\n\
+Returns: True if the PKCS7 is of type enveloped\n\
+";
+
+static PyObject *
+crypto_PKCS7_type_is_enveloped(crypto_PKCS7Obj *self, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":type_is_enveloped"))
+ return NULL;
+
+ if (PKCS7_type_is_enveloped(self->pkcs7))
+ return PyInt_FromLong(1L);
+ else
+ return PyInt_FromLong(0L);
+}
+
+static char crypto_PKCS7_type_is_signedAndEnveloped_doc[] = "\n\
+Check if this NID_pkcs7_signedAndEnveloped object\n\
+\n\
+Arguments: self - The PKCS7 object\n\
+ args - An empty argument tuple\n\
+Returns: True if the PKCS7 is of type signedAndEnveloped\n\
+";
+
+static PyObject *
+crypto_PKCS7_type_is_signedAndEnveloped(crypto_PKCS7Obj *self, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":type_is_signedAndEnveloped"))
+ return NULL;
+
+ if (PKCS7_type_is_signedAndEnveloped(self->pkcs7))
+ return PyInt_FromLong(1L);
+ else
+ return PyInt_FromLong(0L);
+}
+
+static char crypto_PKCS7_type_is_data_doc[] = "\n\
+Check if this NID_pkcs7_data object\n\
+\n\
+Arguments: self - The PKCS7 object\n\
+ args - An empty argument tuple\n\
+Returns: True if the PKCS7 is of type data\n\
+";
+
+static PyObject *
+crypto_PKCS7_type_is_data(crypto_PKCS7Obj *self, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":type_is_data"))
+ return NULL;
+
+ if (PKCS7_type_is_data(self->pkcs7))
+ return PyInt_FromLong(1L);
+ else
+ return PyInt_FromLong(0L);
+}
+
+static char crypto_PKCS7_get_type_name_doc[] = "\n\
+Returns the type name of the PKCS7 structure\n\
+\n\
+Arguments: self - The PKCS7 object\n\
+ args - An empty argument tuple\n\
+Returns: A string with the typename\n\
+";
+
+static PyObject *
+crypto_PKCS7_get_type_name(crypto_PKCS7Obj *self, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":get_type_name"))
+ return NULL;
+
+ /*
+ * return a string with the typename
+ */
+ return PyString_FromString(OBJ_nid2sn(OBJ_obj2nid(self->pkcs7->type)));
+}
+
+/*
+ * ADD_METHOD(name) expands to a correct PyMethodDef declaration
+ * { 'name', (PyCFunction)crypto_PKCS7_name, METH_VARARGS }
+ * for convenience
+ */
+#define ADD_METHOD(name) \
+ { #name, (PyCFunction)crypto_PKCS7_##name, METH_VARARGS, crypto_PKCS7_##name##_doc }
+static PyMethodDef crypto_PKCS7_methods[] =
+{
+ ADD_METHOD(type_is_signed),
+ ADD_METHOD(type_is_enveloped),
+ ADD_METHOD(type_is_signedAndEnveloped),
+ ADD_METHOD(type_is_data),
+ ADD_METHOD(get_type_name),
+ { NULL, NULL }
+};
+#undef ADD_METHOD
+
+
+/*
+ * Constructor for PKCS7 objects, never called by Python code directly
+ *
+ * Arguments: pkcs7 - A "real" pkcs7 certificate object
+ * dealloc - Boolean value to specify whether the destructor should
+ * free the "real" pkcs7 object
+ * Returns: The newly created pkcs7 object
+ */
+crypto_PKCS7Obj *
+crypto_PKCS7_New(PKCS7 *pkcs7, int dealloc)
+{
+ crypto_PKCS7Obj *self;
+
+ self = PyObject_New(crypto_PKCS7Obj, &crypto_PKCS7_Type);
+
+ if (self == NULL)
+ return NULL;
+
+ self->pkcs7 = pkcs7;
+ self->dealloc = dealloc;
+
+ return self;
+}
+
+/*
+ * Deallocate the memory used by the PKCS7 object
+ *
+ * Arguments: self - The PKCS7 object
+ * Returns: None
+ */
+static void
+crypto_PKCS7_dealloc(crypto_PKCS7Obj *self)
+{
+ /* Sometimes we don't have to dealloc the "real" PKCS7 pointer ourselves */
+ if (self->dealloc)
+ PKCS7_free(self->pkcs7);
+
+ PyObject_Del(self);
+}
+
+/*
+ * Find attribute
+ *
+ * Arguments: self - The PKCS7 object
+ * name - The attribute name
+ * Returns: A Python object for the attribute, or NULL if something went
+ * wrong
+ */
+static PyObject *
+crypto_PKCS7_getattr(crypto_PKCS7Obj *self, char *name)
+{
+ return Py_FindMethod(crypto_PKCS7_methods, (PyObject *)self, name);
+}
+
+PyTypeObject crypto_PKCS7_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "PKCS7",
+ sizeof(crypto_PKCS7Obj),
+ 0,
+ (destructor)crypto_PKCS7_dealloc,
+ NULL, /* print */
+ (getattrfunc)crypto_PKCS7_getattr,
+ NULL, /* setattr */
+ NULL, /* compare */
+ NULL, /* repr */
+ NULL, /* as_number */
+ NULL, /* as_sequence */
+ NULL, /* as_mapping */
+ NULL, /* hash */
+ NULL, /* call */
+ NULL /* str */
+};
+
+/*
+ * Initialize the PKCS7 part of the crypto sub module
+ *
+ * Arguments: dict - The crypto module dictionary
+ * Returns: None
+ */
+int
+init_crypto_pkcs7(PyObject *dict)
+{
+ crypto_PKCS7_Type.ob_type = &PyType_Type;
+ Py_INCREF(&crypto_PKCS7_Type);
+ PyDict_SetItemString(dict, "PKCS7Type", (PyObject *)&crypto_PKCS7_Type);
+ return 1;
+}
+
diff --git a/src/crypto/pkcs7.h b/src/crypto/pkcs7.h
new file mode 100644
index 0000000..bdbb425
--- /dev/null
+++ b/src/crypto/pkcs7.h
@@ -0,0 +1,30 @@
+/*
+ * pkcs7.h
+ *
+ * Copyright (C) AB Strakt 2002, All rights reserved
+ *
+ * Export pkcs7 functions and data structure.
+ * See the file RATIONALE for a short explanation of why this module was written.
+ *
+ * @(#) $Id: pkcs7.h,v 1.2 2002/09/04 22:24:59 iko Exp $
+ */
+#ifndef PyOpenSSL_crypto_PKCS7_H_
+#define PyOpenSSL_crypto_PKCS7_H_
+
+#include <Python.h>
+#include <openssl/pkcs7.h>
+
+extern int init_crypto_pkcs7 (PyObject *);
+
+extern PyTypeObject crypto_PKCS7_Type;
+
+#define crypto_PKCS7_Check(v) ((v)->ob_type == &crypto_PKCS7_Type)
+
+typedef struct {
+ PyObject_HEAD
+ PKCS7 *pkcs7;
+ int dealloc;
+} crypto_PKCS7Obj;
+
+
+#endif
diff --git a/src/crypto/pkey.c b/src/crypto/pkey.c
new file mode 100644
index 0000000..201960f
--- /dev/null
+++ b/src/crypto/pkey.c
@@ -0,0 +1,215 @@
+/*
+ * pkey.c
+ *
+ * Copyright (C) AB Strakt 2001, All rights reserved
+ *
+ * Public/rivate key handling code, mostly thin wrappers around OpenSSL.
+ * See the file RATIONALE for a short explanation of why this module was written.
+ *
+ */
+#include <Python.h>
+#define crypto_MODULE
+#include "crypto.h"
+
+static char *CVSid = "@(#) $Id: pkey.c,v 1.9 2002/07/09 13:47:21 martin Exp $";
+
+/*
+ * This is done every time something fails, so turning it into a macro is
+ * really nice.
+ *
+ * Arguments: None
+ * Returns: Doesn't return
+ */
+#define FAIL() \
+do { \
+ exception_from_error_queue(); \
+ return NULL; \
+} while (0)
+
+
+static char crypto_PKey_generate_key_doc[] = "\n\
+Generate a key of a given type, with a given number of a bits\n\
+\n\
+Arguments: self - The PKey object\n\
+ args - The Python argument tuple, should be:\n\
+ type - The key type (TYPE_RSA or TYPE_DSA)\n\
+ bits - The number of bits\n\
+Returns: None\n\
+";
+
+static PyObject *
+crypto_PKey_generate_key(crypto_PKeyObj *self, PyObject *args)
+{
+ int type, bits;
+ RSA *rsa;
+ DSA *dsa;
+
+ if (!PyArg_ParseTuple(args, "ii:generate_key", &type, &bits))
+ return NULL;
+
+ switch (type)
+ {
+ case crypto_TYPE_RSA:
+ if ((rsa = RSA_generate_key(bits, 0x10001, NULL, NULL)) == NULL)
+ FAIL();
+ if (!EVP_PKEY_assign_RSA(self->pkey, rsa))
+ FAIL();
+ Py_INCREF(Py_None);
+ return Py_None;
+
+ case crypto_TYPE_DSA:
+ if ((dsa = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, NULL, NULL)) == NULL)
+ FAIL();
+ if (!DSA_generate_key(dsa))
+ FAIL();
+ if (!EVP_PKEY_assign_DSA(self->pkey, dsa))
+ FAIL();
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ PyErr_SetString(crypto_Error, "No such key type");
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char crypto_PKey_bits_doc[] = "\n\
+Returns the number of bits of the key\n\
+\n\
+Arguments: self - The PKey object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: The number of bits of the key.\n\
+";
+
+static PyObject *
+crypto_PKey_bits(crypto_PKeyObj *self, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":bits"))
+ return NULL;
+
+ return PyInt_FromLong(EVP_PKEY_bits(self->pkey));
+}
+
+static char crypto_PKey_type_doc[] = "\n\
+Returns the type of the key\n\
+\n\
+Arguments: self - The PKey object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: The type of the key.\n\
+";
+
+static PyObject *
+crypto_PKey_type(crypto_PKeyObj *self, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":type"))
+ return NULL;
+
+ return PyInt_FromLong(self->pkey->type);
+}
+
+
+/*
+ * ADD_METHOD(name) expands to a correct PyMethodDef declaration
+ * { 'name', (PyCFunction)crypto_PKey_name, METH_VARARGS }
+ * for convenience
+ */
+#define ADD_METHOD(name) \
+ { #name, (PyCFunction)crypto_PKey_##name, METH_VARARGS, crypto_PKey_##name##_doc }
+static PyMethodDef crypto_PKey_methods[] =
+{
+ ADD_METHOD(generate_key),
+ ADD_METHOD(bits),
+ ADD_METHOD(type),
+ { NULL, NULL }
+};
+#undef ADD_METHOD
+
+
+/*
+ * Constructor for PKey objects, never called by Python code directly
+ *
+ * Arguments: pkey - A "real" EVP_PKEY object
+ * dealloc - Boolean value to specify whether the destructor should
+ * free the "real" EVP_PKEY object
+ * Returns: The newly created PKey object
+ */
+crypto_PKeyObj *
+crypto_PKey_New(EVP_PKEY *pkey, int dealloc)
+{
+ crypto_PKeyObj *self;
+
+ self = PyObject_New(crypto_PKeyObj, &crypto_PKey_Type);
+
+ if (self == NULL)
+ return NULL;
+
+ self->pkey = pkey;
+ self->dealloc = dealloc;
+
+ return self;
+}
+
+/*
+ * Deallocate the memory used by the PKey object
+ *
+ * Arguments: self - The PKey object
+ * Returns: None
+ */
+static void
+crypto_PKey_dealloc(crypto_PKeyObj *self)
+{
+ /* Sometimes we don't have to dealloc the "real" EVP_PKEY pointer ourselves */
+ if (self->dealloc)
+ EVP_PKEY_free(self->pkey);
+
+ PyObject_Del(self);
+}
+
+/*
+ * Find attribute
+ *
+ * Arguments: self - The PKey object
+ * name - The attribute name
+ * Returns: A Python object for the attribute, or NULL if something went
+ * wrong
+ */
+static PyObject *
+crypto_PKey_getattr(crypto_PKeyObj *self, char *name)
+{
+ return Py_FindMethod(crypto_PKey_methods, (PyObject *)self, name);
+}
+
+PyTypeObject crypto_PKey_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "PKey",
+ sizeof(crypto_PKeyObj),
+ 0,
+ (destructor)crypto_PKey_dealloc,
+ NULL, /* print */
+ (getattrfunc)crypto_PKey_getattr,
+ NULL, /* setattr */
+ NULL, /* compare */
+ NULL, /* repr */
+ NULL, /* as_number */
+ NULL, /* as_sequence */
+ NULL, /* as_mapping */
+ NULL, /* hash */
+};
+
+
+/*
+ * Initialize the PKey part of the crypto sub module
+ *
+ * Arguments: dict - The crypto module dictionary
+ * Returns: None
+ */
+int
+init_crypto_pkey(PyObject *dict)
+{
+ crypto_PKey_Type.ob_type = &PyType_Type;
+ Py_INCREF(&crypto_PKey_Type);
+ PyDict_SetItemString(dict, "PKeyType", (PyObject *)&crypto_PKey_Type);
+ return 1;
+}
+
diff --git a/src/crypto/pkey.h b/src/crypto/pkey.h
new file mode 100644
index 0000000..d46e360
--- /dev/null
+++ b/src/crypto/pkey.h
@@ -0,0 +1,29 @@
+/*
+ * pkey.h
+ *
+ * Copyright (C) AB Strakt 2001, All rights reserved
+ *
+ * Export pkey functions and data structure.
+ * See the file RATIONALE for a short explanation of why this module was written.
+ *
+ * @(#) $Id: pkey.h,v 1.5 2002/09/04 22:24:59 iko Exp $
+ */
+#ifndef PyOpenSSL_crypto_PKEY_H_
+#define PyOpenSSL_crypto_PKEY_H_
+
+extern int init_crypto_pkey (PyObject *);
+
+extern PyTypeObject crypto_PKey_Type;
+
+#define crypto_PKey_Check(v) ((v)->ob_type == &crypto_PKey_Type)
+
+typedef struct {
+ PyObject_HEAD
+ EVP_PKEY *pkey;
+ int dealloc;
+} crypto_PKeyObj;
+
+#define crypto_TYPE_RSA EVP_PKEY_RSA
+#define crypto_TYPE_DSA EVP_PKEY_DSA
+
+#endif
diff --git a/src/crypto/x509.c b/src/crypto/x509.c
new file mode 100644
index 0000000..bcae5f6
--- /dev/null
+++ b/src/crypto/x509.c
@@ -0,0 +1,591 @@
+/*
+ * x509.c
+ *
+ * Copyright (C) AB Strakt 2001, All rights reserved
+ *
+ * Certificate (X.509) handling code, mostly thin wrappers around OpenSSL.
+ * See the file RATIONALE for a short explanation of why this module was written.
+ *
+ * Reviewed 2001-07-23
+ */
+#include <Python.h>
+#define crypto_MODULE
+#include "crypto.h"
+
+static char *CVSid = "@(#) $Id: x509.c,v 1.20 2004/08/10 10:37:31 martin Exp $";
+
+/*
+ * X.509 is a standard for digital certificates. See e.g. the OpenSSL homepage
+ * http://www.openssl.org/ for more information
+ */
+
+static char crypto_X509_get_version_doc[] = "\n\
+Return version number of the certificate\n\
+\n\
+Arguments: self - The X509 object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: Version number as a Python integer\n\
+";
+
+static PyObject *
+crypto_X509_get_version(crypto_X509Obj *self, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":get_version"))
+ return NULL;
+
+ return PyInt_FromLong((long)X509_get_version(self->x509));
+}
+
+static char crypto_X509_set_version_doc[] = "\n\
+Set version number of the certificate\n\
+\n\
+Arguments: self - The X509 object\n\
+ args - The Python argument tuple, should be:\n\
+ version - The version number\n\
+Returns: None\n\
+";
+
+static PyObject *
+crypto_X509_set_version(crypto_X509Obj *self, PyObject *args)
+{
+ int version;
+
+ if (!PyArg_ParseTuple(args, "i:set_version", &version))
+ return NULL;
+
+ X509_set_version(self->x509, version);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char crypto_X509_get_serial_number_doc[] = "\n\
+Return serial number of the certificate\n\
+\n\
+Arguments: self - The X509 object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: Serial number as a Python integer\n\
+";
+
+static PyObject *
+crypto_X509_get_serial_number(crypto_X509Obj *self, PyObject *args)
+{
+ ASN1_INTEGER *asn1_i;
+
+ if (!PyArg_ParseTuple(args, ":get_serial_number"))
+ return NULL;
+
+ asn1_i = X509_get_serialNumber(self->x509);
+ return PyInt_FromLong(ASN1_INTEGER_get(asn1_i));
+}
+
+static char crypto_X509_set_serial_number_doc[] = "\n\
+Set serial number of the certificate\n\
+\n\
+Arguments: self - The X509 object\n\
+ args - The Python argument tuple, should be:\n\
+ serial - The serial number\n\
+Returns: None\n\
+";
+
+static PyObject *
+crypto_X509_set_serial_number(crypto_X509Obj *self, PyObject *args)
+{
+ long serial;
+
+ if (!PyArg_ParseTuple(args, "l:set_serial_number", &serial))
+ return NULL;
+
+ ASN1_INTEGER_set(X509_get_serialNumber(self->x509), serial);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char crypto_X509_get_issuer_doc[] = "\n\
+Create an X509Name object for the issuer of the certificate\n\
+\n\
+Arguments: self - The X509 object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: An X509Name object\n\
+";
+
+static PyObject *
+crypto_X509_get_issuer(crypto_X509Obj *self, PyObject *args)
+{
+ crypto_X509NameObj *pyname;
+ X509_NAME *name;
+
+ if (!PyArg_ParseTuple(args, ":get_issuer"))
+ return NULL;
+
+ name = X509_get_issuer_name(self->x509);
+ pyname = crypto_X509Name_New(name, 0);
+ if (pyname != NULL)
+ {
+ pyname->parent_cert = (PyObject *)self;
+ Py_INCREF(self);
+ }
+ return (PyObject *)pyname;
+}
+
+static char crypto_X509_set_issuer_doc[] = "\n\
+Set the issuer of the certificate\n\
+\n\
+Arguments: self - The X509 object\n\
+ args - The Python argument tuple, should be:\n\
+ issuer - The issuer name\n\
+Returns: None\n\
+";
+
+static PyObject *
+crypto_X509_set_issuer(crypto_X509Obj *self, PyObject *args)
+{
+ crypto_X509NameObj *issuer;
+
+ if (!PyArg_ParseTuple(args, "O!:set_issuer", &crypto_X509Name_Type,
+ &issuer))
+ return NULL;
+
+ if (!X509_set_issuer_name(self->x509, issuer->x509_name))
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char crypto_X509_get_subject_doc[] = "\n\
+Create an X509Name object for the subject of the certificate\n\
+\n\
+Arguments: self - The X509 object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: An X509Name object\n\
+";
+
+static PyObject *
+crypto_X509_get_subject(crypto_X509Obj *self, PyObject *args)
+{
+ crypto_X509NameObj *pyname;
+ X509_NAME *name;
+
+ if (!PyArg_ParseTuple(args, ":get_subject"))
+ return NULL;
+
+ name = X509_get_subject_name(self->x509);
+ pyname = crypto_X509Name_New(name, 0);
+ if (pyname != NULL)
+ {
+ pyname->parent_cert = (PyObject *)self;
+ Py_INCREF(self);
+ }
+ return (PyObject *)pyname;
+}
+
+static char crypto_X509_set_subject_doc[] = "\n\
+Set the subject of the certificate\n\
+\n\
+Arguments: self - The X509 object\n\
+ args - The Python argument tuple, should be:\n\
+ subject - The subject name\n\
+Returns: None\n\
+";
+
+static PyObject *
+crypto_X509_set_subject(crypto_X509Obj *self, PyObject *args)
+{
+ crypto_X509NameObj *subject;
+
+ if (!PyArg_ParseTuple(args, "O!:set_subject", &crypto_X509Name_Type,
+ &subject))
+ return NULL;
+
+ if (!X509_set_subject_name(self->x509, subject->x509_name))
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char crypto_X509_get_pubkey_doc[] = "\n\
+Get the public key of the certificate\n\
+\n\
+Arguments: self - The X509 object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: The public key\n\
+";
+
+static PyObject *
+crypto_X509_get_pubkey(crypto_X509Obj *self, PyObject *args)
+{
+ crypto_PKeyObj *crypto_PKey_New(EVP_PKEY *, int);
+ EVP_PKEY *pkey;
+
+ if (!PyArg_ParseTuple(args, ":get_pubkey"))
+ return NULL;
+
+ if ((pkey = X509_get_pubkey(self->x509)) == NULL)
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+
+ return (PyObject *)crypto_PKey_New(pkey, 0);
+}
+
+static char crypto_X509_set_pubkey_doc[] = "\n\
+Set the public key of the certificate\n\
+\n\
+Arguments: self - The X509 object\n\
+ args - The Python argument tuple, should be:\n\
+ pkey - The public key\n\
+Returns: None\n\
+";
+
+static PyObject *
+crypto_X509_set_pubkey(crypto_X509Obj *self, PyObject *args)
+{
+ crypto_PKeyObj *pkey;
+
+ if (!PyArg_ParseTuple(args, "O!:set_pubkey", &crypto_PKey_Type, &pkey))
+ return NULL;
+
+ if (!X509_set_pubkey(self->x509, pkey->pkey))
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char crypto_X509_gmtime_adj_notBefore_doc[] = "\n\
+Adjust the time stamp for when the certificate starts being valid\n\
+\n\
+Arguments: self - The X509 object\n\
+ args - The Python argument tuple, should be:\n\
+ i - The adjustment\n\
+Returns: None\n\
+";
+
+static PyObject *
+crypto_X509_gmtime_adj_notBefore(crypto_X509Obj *self, PyObject *args)
+{
+ long i;
+
+ if (!PyArg_ParseTuple(args, "l:gmtime_adj_notBefore", &i))
+ return NULL;
+
+ X509_gmtime_adj(X509_get_notBefore(self->x509), i);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char crypto_X509_gmtime_adj_notAfter_doc[] = "\n\
+Adjust the time stamp for when the certificate stops being valid\n\
+\n\
+Arguments: self - The X509 object\n\
+ args - The Python argument tuple, should be:\n\
+ i - The adjustment\n\
+Returns: None\n\
+";
+
+static PyObject *
+crypto_X509_gmtime_adj_notAfter(crypto_X509Obj *self, PyObject *args)
+{
+ long i;
+
+ if (!PyArg_ParseTuple(args, "l:gmtime_adj_notAfter", &i))
+ return NULL;
+
+ X509_gmtime_adj(X509_get_notAfter(self->x509), i);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char crypto_X509_sign_doc[] = "\n\
+Sign the certificate using the supplied key and digest\n\
+\n\
+Arguments: self - The X509 object\n\
+ args - The Python argument tuple, should be:\n\
+ pkey - The key to sign with\n\
+ digest - The message digest to use\n\
+Returns: None\n\
+";
+
+static PyObject *
+crypto_X509_sign(crypto_X509Obj *self, PyObject *args)
+{
+ crypto_PKeyObj *pkey;
+ char *digest_name;
+ const EVP_MD *digest;
+
+ if (!PyArg_ParseTuple(args, "O!s:sign", &crypto_PKey_Type, &pkey,
+ &digest_name))
+ return NULL;
+
+ if ((digest = EVP_get_digestbyname(digest_name)) == NULL)
+ {
+ PyErr_SetString(PyExc_ValueError, "No such digest method");
+ return NULL;
+ }
+
+ if (!X509_sign(self->x509, pkey->pkey, digest))
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char crypto_X509_has_expired_doc[] = "\n\
+Check whether the certificate has expired.\n\
+\n\
+Arguments: self - The X509 object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: True if the certificate has expired, false otherwise\n\
+";
+
+static PyObject *
+crypto_X509_has_expired(crypto_X509Obj *self, PyObject *args)
+{
+ time_t tnow;
+
+ if (!PyArg_ParseTuple(args, ":has_expired"))
+ return NULL;
+
+ tnow = time(NULL);
+ if (ASN1_UTCTIME_cmp_time_t(X509_get_notAfter(self->x509), tnow) < 0)
+ return PyInt_FromLong(1L);
+ else
+ return PyInt_FromLong(0L);
+}
+
+static char crypto_X509_subject_name_hash_doc[] = "\n\
+Return the hash of the X509 subject.\n\
+\n\
+Arguments: self - The X509 object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: The hash of the subject\n\
+";
+
+static PyObject *
+crypto_X509_subject_name_hash(crypto_X509Obj *self, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":subject_name_hash"))
+ return NULL;
+
+ return PyLong_FromLong(X509_subject_name_hash(self->x509));
+}
+
+static char crypto_X509_digest_doc[] = "\n\
+Return the digest of the X509 object.\n\
+\n\
+Arguments: self - The X509 object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: The digest of the object\n\
+";
+
+static PyObject *
+crypto_X509_digest(crypto_X509Obj *self, PyObject *args)
+{
+ unsigned char fp[EVP_MAX_MD_SIZE];
+ char *tmp;
+ char *digest_name;
+ int len,i;
+ PyObject *ret;
+ const EVP_MD *digest;
+
+ if (!PyArg_ParseTuple(args, "s:digest", &digest_name))
+ return NULL;
+
+ if ((digest = EVP_get_digestbyname(digest_name)) == NULL)
+ {
+ PyErr_SetString(PyExc_ValueError, "No such digest method");
+ return NULL;
+ }
+
+ if (!X509_digest(self->x509,digest,fp,&len))
+ {
+ exception_from_error_queue();
+ }
+ tmp = malloc(3*len+1);
+ memset(tmp, 0, 3*len+1);
+ for (i = 0; i < len; i++) {
+ sprintf(tmp+i*3,"%02X:",fp[i]);
+ }
+ tmp[3*len-1] = 0;
+ ret = PyString_FromStringAndSize(tmp,3*len-1);
+ free(tmp);
+ return ret;
+}
+
+
+static char crypto_X509_add_extensions_doc[] = "\n\
+Add extensions to the certificate.\n\
+\n\
+Arguments: self - X509 object\n\
+ args - The Python argument tuple, should be:\n\
+ extensions - a sequence of X509Extension objects\n\
+Returns: None\n\
+";
+
+static PyObject *
+crypto_X509_add_extensions(crypto_X509Obj *self, PyObject *args)
+{
+ PyObject *extensions, *seq;
+ crypto_X509ExtensionObj *ext;
+ int nr_of_extensions, i;
+
+ if (!PyArg_ParseTuple(args, "O:add_extensions", &extensions))
+ return NULL;
+
+ seq = PySequence_Fast(extensions, "Expected a sequence");
+ if (seq == NULL)
+ return NULL;
+
+ nr_of_extensions = PySequence_Fast_GET_SIZE(seq);
+
+ for (i = 0; i < nr_of_extensions; i++)
+ {
+ ext = (crypto_X509ExtensionObj *)PySequence_Fast_GET_ITEM(seq, i);
+ if (!crypto_X509Extension_Check(ext))
+ {
+ Py_DECREF(seq);
+ PyErr_SetString(PyExc_ValueError,
+ "One of the elements is not an X509Extension");
+ return NULL;
+ }
+ if (!X509_add_ext(self->x509, ext->x509_extension, -1))
+ {
+ Py_DECREF(seq);
+ exception_from_error_queue();
+ return NULL;
+ }
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/*
+ * ADD_METHOD(name) expands to a correct PyMethodDef declaration
+ * { 'name', (PyCFunction)crypto_X509_name, METH_VARARGS }
+ * for convenience
+ */
+#define ADD_METHOD(name) \
+ { #name, (PyCFunction)crypto_X509_##name, METH_VARARGS, crypto_X509_##name##_doc }
+static PyMethodDef crypto_X509_methods[] =
+{
+ ADD_METHOD(get_version),
+ ADD_METHOD(set_version),
+ ADD_METHOD(get_serial_number),
+ ADD_METHOD(set_serial_number),
+ ADD_METHOD(get_issuer),
+ ADD_METHOD(set_issuer),
+ ADD_METHOD(get_subject),
+ ADD_METHOD(set_subject),
+ ADD_METHOD(get_pubkey),
+ ADD_METHOD(set_pubkey),
+ ADD_METHOD(gmtime_adj_notBefore),
+ ADD_METHOD(gmtime_adj_notAfter),
+ ADD_METHOD(sign),
+ ADD_METHOD(has_expired),
+ ADD_METHOD(subject_name_hash),
+ ADD_METHOD(digest),
+ ADD_METHOD(add_extensions),
+ { NULL, NULL }
+};
+#undef ADD_METHOD
+
+
+/*
+ * Constructor for X509 objects, never called by Python code directly
+ *
+ * Arguments: cert - A "real" X509 certificate object
+ * dealloc - Boolean value to specify whether the destructor should
+ * free the "real" X509 object
+ * Returns: The newly created X509 object
+ */
+crypto_X509Obj *
+crypto_X509_New(X509 *cert, int dealloc)
+{
+ crypto_X509Obj *self;
+
+ self = PyObject_New(crypto_X509Obj, &crypto_X509_Type);
+
+ if (self == NULL)
+ return NULL;
+
+ self->x509 = cert;
+ self->dealloc = dealloc;
+
+ return self;
+}
+
+/*
+ * Deallocate the memory used by the X509 object
+ *
+ * Arguments: self - The X509 object
+ * Returns: None
+ */
+static void
+crypto_X509_dealloc(crypto_X509Obj *self)
+{
+ /* Sometimes we don't have to dealloc the "real" X509 pointer ourselves */
+ if (self->dealloc)
+ X509_free(self->x509);
+
+ PyObject_Del(self);
+}
+
+/*
+ * Find attribute
+ *
+ * Arguments: self - The X509 object
+ * name - The attribute name
+ * Returns: A Python object for the attribute, or NULL if something went
+ * wrong
+ */
+static PyObject *
+crypto_X509_getattr(crypto_X509Obj *self, char *name)
+{
+ return Py_FindMethod(crypto_X509_methods, (PyObject *)self, name);
+}
+
+PyTypeObject crypto_X509_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "X509",
+ sizeof(crypto_X509Obj),
+ 0,
+ (destructor)crypto_X509_dealloc,
+ NULL, /* print */
+ (getattrfunc)crypto_X509_getattr,
+};
+
+/*
+ * Initialize the X509 part of the crypto sub module
+ *
+ * Arguments: dict - The crypto module dictionary
+ * Returns: None
+ */
+int
+init_crypto_x509(PyObject *dict)
+{
+ crypto_X509_Type.ob_type = &PyType_Type;
+ Py_INCREF(&crypto_X509_Type);
+ PyDict_SetItemString(dict, "X509Type", (PyObject *)&crypto_X509_Type);
+ return 1;
+}
+
diff --git a/src/crypto/x509.h b/src/crypto/x509.h
new file mode 100644
index 0000000..40768cf
--- /dev/null
+++ b/src/crypto/x509.h
@@ -0,0 +1,32 @@
+/*
+ * x509.h
+ *
+ * Copyright (C) AB Strakt 2001, All rights reserved
+ *
+ * Export x509 functions and data structure.
+ * See the file RATIONALE for a short explanation of why this module was written.
+ *
+ * Reviewed 2001-07-23
+ *
+ * @(#) $Id: x509.h,v 1.9 2002/09/04 22:24:59 iko Exp $
+ */
+#ifndef PyOpenSSL_crypto_X509_H_
+#define PyOpenSSL_crypto_X509_H_
+
+#include <Python.h>
+#include <openssl/ssl.h>
+
+extern int init_crypto_x509 (PyObject *);
+
+extern PyTypeObject crypto_X509_Type;
+
+#define crypto_X509_Check(v) ((v)->ob_type == &crypto_X509_Type)
+
+typedef struct {
+ PyObject_HEAD
+ X509 *x509;
+ int dealloc;
+} crypto_X509Obj;
+
+
+#endif
diff --git a/src/crypto/x509ext.c b/src/crypto/x509ext.c
new file mode 100644
index 0000000..9a628c3
--- /dev/null
+++ b/src/crypto/x509ext.c
@@ -0,0 +1,254 @@
+/*
+ * x509ext.c
+ *
+ * Export X.509 extension functions and data structures.
+ * See the file RATIONALE for a short explanation of why this module was written.
+ *
+ * @(#) $Id: x509ext.c,v 1.1 2002/07/09 13:34:46 martin Exp $
+ */
+
+#include <Python.h>
+#define crypto_MODULE
+#include "crypto.h"
+
+static char *CVSid = "@(#) $Id: x509ext.c,v 1.1 2002/07/09 13:34:46 martin Exp $";
+
+static char crypto_X509Extension_get_critical_doc[] = "\n\
+Returns the critical field of the X509Extension\n\
+\n\
+Arguments: self - The X509Extension object\n\
+ args - The argument tuple, should be empty\n\
+Returns: The critical field.\n\
+";
+
+static PyObject *
+crypto_X509Extension_get_critical(crypto_X509ExtensionObj *self, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":get_critical"))
+ return NULL;
+
+ return PyInt_FromLong(X509_EXTENSION_get_critical(self->x509_extension));
+}
+
+/*
+ * ADD_METHOD(name) expands to a correct PyMethodDef declaration
+ * { 'name', (PyCFunction)crypto_X509Extension_name, METH_VARARGS }
+ * for convenience
+ */
+#define ADD_METHOD(name) \
+{ #name, (PyCFunction)crypto_X509Extension_##name, METH_VARARGS, crypto_X509Extension_##name##_doc }
+static PyMethodDef crypto_X509Extension_methods[] =
+{
+ ADD_METHOD(get_critical),
+ { NULL, NULL }
+};
+#undef ADD_METHOD
+
+/*
+ * Constructor for X509Extension, never called by Python code directly
+ *
+ * Arguments: type_name - ???
+ * critical - ???
+ * value - ???
+ * Returns: The newly created X509Extension object
+ */
+crypto_X509ExtensionObj *
+crypto_X509Extension_New(char *type_name, int critical, char *value)
+{
+ crypto_X509ExtensionObj *self;
+ int ext_len, ext_nid;
+ unsigned char *ext_der;
+ X509V3_EXT_METHOD *ext_method = NULL;
+ ASN1_OCTET_STRING *ext_oct;
+ STACK_OF(CONF_VALUE) *nval;
+ void * ext_struct;
+ X509_EXTENSION *extension = NULL;
+
+ self = PyObject_New(crypto_X509ExtensionObj, &crypto_X509Extension_Type);
+
+ if (self == NULL)
+ return NULL;
+
+ /* Try to get a NID for the name */
+ if ((ext_nid = OBJ_sn2nid(type_name)) == NID_undef)
+ {
+ PyErr_SetString(PyExc_ValueError, "Unknown extension name");
+ return NULL;
+ }
+
+ /* Lookup the extension method structure */
+ if (!(ext_method = X509V3_EXT_get_nid(ext_nid)))
+ {
+ PyErr_SetString(PyExc_ValueError, "Unknown extension");
+ return NULL;
+ }
+
+ /* Look if it has a function to convert value to an
+ * internal structure.
+ */
+ if (!ext_method->v2i)
+ {
+ PyErr_SetString(PyExc_ValueError, "Can't initialize exception");
+ return NULL;
+ }
+
+ /* Parse the value */
+ nval = X509V3_parse_list(value);
+ if (!nval)
+ {
+ PyErr_SetString(PyExc_ValueError, "Invalid extension string");
+ return NULL;
+ }
+
+ /* And use it to get the internal structure */
+ if(!(ext_struct = ext_method->v2i(ext_method, NULL, nval))) {
+ exception_from_error_queue();
+ return NULL;
+ }
+
+ /* Deallocate the configuration value stack */
+ sk_CONF_VALUE_pop_free(nval, X509V3_conf_free);
+
+ /* Find out how much memory we need */
+
+
+ /* Convert internal representation to DER */
+ /* and Allocate */
+ if (ext_method->it) {
+ ext_der = NULL;
+ ext_len = ASN1_item_i2d(ext_struct, &ext_der, ASN1_ITEM_ptr(ext_method->it));
+ if (ext_len < 0) {
+ PyErr_SetString(PyExc_MemoryError, "Could not allocate memory");
+ return NULL;
+ }
+ } else {
+ unsigned char *p;
+ ext_len = ext_method->i2d(ext_struct, NULL);
+ if(!(ext_der = malloc(ext_len))) {
+ PyErr_SetString(PyExc_MemoryError, "Could not allocate memory");
+ return NULL;
+ }
+ p = ext_der;
+ ext_method->i2d(ext_struct, &p);
+ }
+
+ /* And create the ASN1_OCTET_STRING */
+ if(!(ext_oct = M_ASN1_OCTET_STRING_new())) {
+ exception_from_error_queue();
+ return NULL;
+ }
+
+ ext_oct->data = ext_der;
+ ext_oct->length = ext_len;
+
+ /* Now that we got all ingredients, make the extension */
+ extension = X509_EXTENSION_create_by_NID(NULL, ext_nid, critical, ext_oct);
+ if (extension == NULL)
+ {
+ exception_from_error_queue();
+ M_ASN1_OCTET_STRING_free(ext_oct);
+ ext_method->ext_free(ext_struct);
+ return NULL;
+ }
+
+ M_ASN1_OCTET_STRING_free(ext_oct);
+ //ext_method->ext_free(ext_struct);
+
+ self->x509_extension = extension;
+ self->dealloc = 1;
+
+ return self;
+}
+
+/*
+ * Deallocate the memory used by the X509Extension object
+ *
+ * Arguments: self - The X509Extension object
+ * Returns: None
+ */
+static void
+crypto_X509Extension_dealloc(crypto_X509ExtensionObj *self)
+{
+ /* Sometimes we don't have to dealloc this */
+ if (self->dealloc)
+ X509_EXTENSION_free(self->x509_extension);
+
+ PyObject_Del(self);
+}
+
+/*
+ * Find attribute
+ *
+ * Arguments: self - The X509Extension object
+ * name - The attribute name
+ * Returns: A Python object for the attribute, or NULL if something
+ * went wrong.
+ */
+static PyObject *
+crypto_X509Extension_getattr(crypto_X509ExtensionObj *self, char *name)
+{
+ return Py_FindMethod(crypto_X509Extension_methods, (PyObject *)self, name);
+}
+
+/*
+ * Print a nice text representation of the certificate request.
+ */
+static PyObject *
+crypto_X509Extension_str(crypto_X509ExtensionObj *self)
+{
+ int str_len;
+ char *tmp_str;
+ PyObject *str;
+ BIO *bio = BIO_new(BIO_s_mem());
+
+ if (!X509V3_EXT_print(bio, self->x509_extension, 0, 0))
+ {
+ BIO_free(bio);
+ exception_from_error_queue();
+ return NULL;
+ }
+
+ str_len = BIO_get_mem_data(bio, &tmp_str);
+ str = PyString_FromStringAndSize(tmp_str, str_len);
+
+ BIO_free(bio);
+
+ return str;
+}
+
+PyTypeObject crypto_X509Extension_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "X509Extension",
+ sizeof(crypto_X509ExtensionObj),
+ 0,
+ (destructor)crypto_X509Extension_dealloc,
+ NULL, /* print */
+ (getattrfunc)crypto_X509Extension_getattr,
+ NULL, /* setattr (setattrfunc)crypto_X509Name_setattr, */
+ NULL, /* compare */
+ NULL, /* repr */
+ NULL, /* as_number */
+ NULL, /* as_sequence */
+ NULL, /* as_mapping */
+ NULL, /* hash */
+ NULL, /* call */
+ (reprfunc)crypto_X509Extension_str /* str */
+};
+
+/*
+ * Initialize the X509Extension part of the crypto module
+ *
+ * Arguments: dict - The crypto module dictionary
+ * Returns: None
+ */
+int
+init_crypto_x509extension(PyObject *dict)
+{
+ crypto_X509Extension_Type.ob_type = &PyType_Type;
+ Py_INCREF(&crypto_X509Extension_Type);
+ PyDict_SetItemString(dict, "X509ExtensionType",
+ (PyObject *)&crypto_X509Extension_Type);
+ return 1;
+}
+
diff --git a/src/crypto/x509ext.h b/src/crypto/x509ext.h
new file mode 100644
index 0000000..f20e562
--- /dev/null
+++ b/src/crypto/x509ext.h
@@ -0,0 +1,32 @@
+/*
+ * x509ext.h
+ *
+ * Copyright (C) Awanim 2002, All rights reserved
+ *
+ * Export X.509 extension functions and data structures.
+ * See the file RATIONALE for a short explanation of why this module was written.
+ *
+ * @(#) $Id: x509ext.h,v 1.2 2002/09/04 22:24:59 iko Exp $
+ */
+#ifndef PyOpenSSL_crypto_X509EXTENSION_H_
+#define PyOpenSSL_crypto_X509EXTENSION_H_
+
+#include <Python.h>
+#include <openssl/ssl.h>
+#include <openssl/x509v3.h>
+
+extern int init_crypto_x509extension (PyObject *);
+
+extern PyTypeObject crypto_X509Extension_Type;
+
+#define crypto_X509Extension_Check(v) ((v)->ob_type == \
+ &crypto_X509Extension_Type)
+
+typedef struct {
+ PyObject_HEAD
+ X509_EXTENSION *x509_extension;
+ int dealloc;
+} crypto_X509ExtensionObj;
+
+#endif
+
diff --git a/src/crypto/x509name.c b/src/crypto/x509name.c
new file mode 100644
index 0000000..b9c0233
--- /dev/null
+++ b/src/crypto/x509name.c
@@ -0,0 +1,307 @@
+/*
+ * x509name.c
+ *
+ * Copyright (C) AB Strakt 2001, All rights reserved
+ *
+ * X.509 Name handling, mostly thin wrapping.
+ * See the file RATIONALE for a short explanation of why this module was written.
+ *
+ * Reviewed 2001-07-23
+ */
+#include <Python.h>
+#define crypto_MODULE
+#include "crypto.h"
+
+static char *CVSid = "@(#) $Id: x509name.c,v 1.16 2003/01/09 17:08:32 martin Exp $";
+
+
+/*
+ * Constructor for X509Name, never called by Python code directly
+ *
+ * Arguments: name - A "real" X509_NAME object
+ * dealloc - Boolean value to specify whether the destructor should
+ * free the "real" X509_NAME object
+ * Returns: The newly created X509Name object
+ */
+crypto_X509NameObj *
+crypto_X509Name_New(X509_NAME *name, int dealloc)
+{
+ crypto_X509NameObj *self;
+
+ self = PyObject_GC_New(crypto_X509NameObj, &crypto_X509Name_Type);
+
+ if (self == NULL)
+ return NULL;
+
+ self->x509_name = name;
+ self->dealloc = dealloc;
+ self->parent_cert = NULL;
+
+ PyObject_GC_Track(self);
+ return self;
+}
+
+/*
+ * Return a name string given a X509_NAME object and a name identifier. Used
+ * by the getattr function.
+ *
+ * Arguments: name - The X509_NAME object
+ * nid - The name identifier
+ * Returns: The name as a Python string object
+ */
+static int
+get_name_by_nid(X509_NAME *name, int nid, char **utf8string)
+{
+ int entry_idx;
+ X509_NAME_ENTRY *entry;
+ ASN1_STRING *data;
+ int len;
+
+ if ((entry_idx = X509_NAME_get_index_by_NID(name, nid, -1)) == -1)
+ {
+ return 0;
+ }
+ entry = X509_NAME_get_entry(name, entry_idx);
+ data = X509_NAME_ENTRY_get_data(entry);
+ if ((len = ASN1_STRING_to_UTF8((unsigned char **)utf8string, data)) < 0)
+ {
+ exception_from_error_queue();
+ return -1;
+ }
+
+ return len;
+}
+
+/*
+ * Given a X509_NAME object and a name identifier, set the corresponding
+ * attribute to the given string. Used by the setattr function.
+ *
+ * Arguments: name - The X509_NAME object
+ * nid - The name identifier
+ * value - The string to set
+ * Returns: 0 for success, -1 on failure
+ */
+static int
+set_name_by_nid(X509_NAME *name, int nid, char *utf8string)
+{
+ X509_NAME_ENTRY *ne;
+ int i, entry_count, temp_nid;
+
+ /* If there's an old entry for this NID, remove it */
+ entry_count = X509_NAME_entry_count(name);
+ for (i = 0; i < entry_count; i++)
+ {
+ ne = X509_NAME_get_entry(name, i);
+ temp_nid = OBJ_obj2nid(X509_NAME_ENTRY_get_object(ne));
+ if (temp_nid == nid)
+ {
+ ne = X509_NAME_delete_entry(name, i);
+ X509_NAME_ENTRY_free(ne);
+ break;
+ }
+ }
+
+ /* Add the new entry */
+ if (!X509_NAME_add_entry_by_NID(name, nid, MBSTRING_UTF8, utf8string,
+ -1, -1, 0))
+ {
+ exception_from_error_queue();
+ return -1;
+ }
+ return 0;
+}
+
+
+/*
+ * Find attribute. An X509Name object has the following attributes:
+ * countryName (alias C), stateOrProvince (alias ST), locality (alias L),
+ * organization (alias O), organizationalUnit (alias OU), commonName (alias
+ * CN) and more...
+ *
+ * Arguments: self - The X509Name object
+ * name - The attribute name
+ * Returns: A Python object for the attribute, or NULL if something went
+ * wrong
+ */
+static PyObject *
+crypto_X509Name_getattr(crypto_X509NameObj *self, char *name)
+{
+ int nid, len;
+ char *utf8string;
+
+ if ((nid = OBJ_txt2nid(name)) == NID_undef)
+ {
+ PyErr_SetString(PyExc_AttributeError, "No such attribute");
+ return NULL;
+ }
+
+ len = get_name_by_nid(self->x509_name, nid, &utf8string);
+ if (len < 0)
+ return NULL;
+ else if (len == 0)
+ {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ else
+ return PyUnicode_Decode(utf8string, len, "utf-8", NULL);
+}
+
+/*
+ * Set attribute
+ *
+ * Arguments: self - The X509Name object
+ * name - The attribute name
+ * value - The value to set
+ */
+static int
+crypto_X509Name_setattr(crypto_X509NameObj *self, char *name, PyObject *value)
+{
+ int nid;
+ char *buffer;
+
+ if ((nid = OBJ_txt2nid(name)) == NID_undef)
+ {
+ PyErr_SetString(PyExc_AttributeError, "No such attribute");
+ return -1;
+ }
+
+ /* Something of a hack to get nice unicode behaviour */
+ if (!PyArg_Parse(value, "es:setattr", "utf-8", &buffer))
+ return -1;
+
+ return set_name_by_nid(self->x509_name, nid, buffer);
+}
+
+/*
+ * Compare two X509Name structures.
+ *
+ * Arguments: n - The first X509Name
+ * m - The second X509Name
+ * Returns: <0 if n < m, 0 if n == m and >0 if n > m
+ */
+static int
+crypto_X509Name_compare(crypto_X509NameObj *n, crypto_X509NameObj *m)
+{
+ return X509_NAME_cmp(n->x509_name, m->x509_name);
+}
+
+/*
+ * String representation of an X509Name
+ *
+ * Arguments: self - The X509Name object
+ * Returns: A string representation of the object
+ */
+static PyObject *
+crypto_X509Name_repr(crypto_X509NameObj *self)
+{
+ char tmpbuf[512] = "";
+ char realbuf[512+64];
+
+ if (X509_NAME_oneline(self->x509_name, tmpbuf, 512) == NULL)
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+ else
+ {
+ /* This is safe because tmpbuf is max 512 characters */
+ sprintf(realbuf, "<X509Name object '%s'>", tmpbuf);
+ return PyString_FromString(realbuf);
+ }
+}
+
+/*
+ * Call the visitproc on all contained objects.
+ *
+ * Arguments: self - The Connection object
+ * visit - Function to call
+ * arg - Extra argument to visit
+ * Returns: 0 if all goes well, otherwise the return code from the first
+ * call that gave non-zero result.
+ */
+static int
+crypto_X509Name_traverse(crypto_X509NameObj *self, visitproc visit, void *arg)
+{
+ int ret = 0;
+
+ if (ret == 0 && self->parent_cert != NULL)
+ ret = visit(self->parent_cert, arg);
+ return ret;
+}
+
+/*
+ * Decref all contained objects and zero the pointers.
+ *
+ * Arguments: self - The Connection object
+ * Returns: Always 0.
+ */
+static int
+crypto_X509Name_clear(crypto_X509NameObj *self)
+{
+ Py_XDECREF(self->parent_cert);
+ self->parent_cert = NULL;
+ return 0;
+}
+
+/*
+ * Deallocate the memory used by the X509Name object
+ *
+ * Arguments: self - The X509Name object
+ * Returns: None
+ */
+static void
+crypto_X509Name_dealloc(crypto_X509NameObj *self)
+{
+ PyObject_GC_UnTrack(self);
+ /* Sometimes we don't have to dealloc this */
+ if (self->dealloc)
+ X509_NAME_free(self->x509_name);
+
+ crypto_X509Name_clear(self);
+
+ PyObject_GC_Del(self);
+}
+
+PyTypeObject crypto_X509Name_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "X509Name",
+ sizeof(crypto_X509NameObj),
+ 0,
+ (destructor)crypto_X509Name_dealloc,
+ NULL, /* print */
+ (getattrfunc)crypto_X509Name_getattr,
+ (setattrfunc)crypto_X509Name_setattr,
+ (cmpfunc)crypto_X509Name_compare,
+ (reprfunc)crypto_X509Name_repr,
+ NULL, /* as_number */
+ NULL, /* as_sequence */
+ NULL, /* as_mapping */
+ NULL, /* hash */
+ NULL, /* call */
+ NULL, /* str */
+ NULL, /* getattro */
+ NULL, /* setattro */
+ NULL, /* as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
+ NULL, /* doc */
+ (traverseproc)crypto_X509Name_traverse,
+ (inquiry)crypto_X509Name_clear,
+};
+
+
+/*
+ * Initialize the X509Name part of the crypto module
+ *
+ * Arguments: dict - The crypto module dictionary
+ * Returns: None
+ */
+int
+init_crypto_x509name(PyObject *dict)
+{
+ crypto_X509Name_Type.ob_type = &PyType_Type;
+ Py_INCREF(&crypto_X509Name_Type);
+ PyDict_SetItemString(dict, "X509NameType", (PyObject *)&crypto_X509Name_Type);
+ return 1;
+}
diff --git a/src/crypto/x509name.h b/src/crypto/x509name.h
new file mode 100644
index 0000000..362ce35
--- /dev/null
+++ b/src/crypto/x509name.h
@@ -0,0 +1,33 @@
+/*
+ * x509name.h
+ *
+ * Copyright (C) AB Strakt 2001, All rights reserved
+ *
+ * Export X.509 name functions and data structures.
+ * See the file RATIONALE for a short explanation of why this module was written.
+ *
+ * Reviewed 2001-07-23
+ *
+ * @(#) $Id: x509name.h,v 1.8 2002/09/04 22:24:59 iko Exp $
+ */
+#ifndef PyOpenSSL_crypto_X509NAME_H_
+#define PyOpenSSL_crypto_X509NAME_H_
+
+#include <Python.h>
+#include <openssl/ssl.h>
+
+extern int init_crypto_x509name (PyObject *);
+
+extern PyTypeObject crypto_X509Name_Type;
+
+#define crypto_X509Name_Check(v) ((v)->ob_type == &crypto_X509Name_Type)
+
+typedef struct {
+ PyObject_HEAD
+ X509_NAME *x509_name;
+ int dealloc;
+ PyObject *parent_cert;
+} crypto_X509NameObj;
+
+
+#endif
diff --git a/src/crypto/x509req.c b/src/crypto/x509req.c
new file mode 100644
index 0000000..d551de4
--- /dev/null
+++ b/src/crypto/x509req.c
@@ -0,0 +1,324 @@
+/*
+ * x509req.c
+ *
+ * Copyright (C) AB Strakt 2001, All rights reserved
+ *
+ * X.509 Request handling, mostly thin wrapping.
+ * See the file RATIONALE for a short explanation of why this module was written.
+ */
+#include <Python.h>
+#define crypto_MODULE
+#include "crypto.h"
+
+static char *CVSid = "@(#) $Id: x509req.c,v 1.15 2002/09/04 22:24:59 iko Exp $";
+
+
+static char crypto_X509Req_get_subject_doc[] = "\n\
+Create an X509Name object for the subject of the certificate request\n\
+\n\
+Arguments: self - The X509Req object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: An X509Name object\n\
+";
+
+static PyObject *
+crypto_X509Req_get_subject(crypto_X509ReqObj *self, PyObject *args)
+{
+ crypto_X509NameObj *crypto_X509Name_New(X509_NAME *, int);
+ X509_NAME *name;
+
+ if (!PyArg_ParseTuple(args, ":get_subject"))
+ return NULL;
+
+ if ((name = X509_REQ_get_subject_name(self->x509_req)) == NULL)
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+
+ return (PyObject *)crypto_X509Name_New(name, 0);
+}
+
+static char crypto_X509Req_get_pubkey_doc[] = "\n\
+Get the public key from the certificate request\n\
+\n\
+Arguments: self - The X509Req object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: The public key\n\
+";
+
+static PyObject *
+crypto_X509Req_get_pubkey(crypto_X509ReqObj *self, PyObject *args)
+{
+ crypto_PKeyObj *crypto_PKey_New(EVP_PKEY *, int);
+ EVP_PKEY *pkey;
+
+ if (!PyArg_ParseTuple(args, ":get_pubkey"))
+ return NULL;
+
+ if ((pkey = X509_REQ_get_pubkey(self->x509_req)) == NULL)
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+
+ return (PyObject *)crypto_PKey_New(pkey, 1);
+}
+
+static char crypto_X509Req_set_pubkey_doc[] = "\n\
+Set the public key of the certificate request\n\
+\n\
+Arguments: self - The X509Req object\n\
+ args - The Python argument tuple, should be:\n\
+ pkey - The public key to use\n\
+Returns: None\n\
+";
+
+static PyObject *
+crypto_X509Req_set_pubkey(crypto_X509ReqObj *self, PyObject *args)
+{
+ crypto_PKeyObj *pkey;
+
+ if (!PyArg_ParseTuple(args, "O!:set_pubkey", &crypto_PKey_Type, &pkey))
+ return NULL;
+
+ if (!X509_REQ_set_pubkey(self->x509_req, pkey->pkey))
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char crypto_X509Req_sign_doc[] = "\n\
+Sign the certificate request using the supplied key and digest\n\
+\n\
+Arguments: self - The X509Req object\n\
+ args - The Python argument tuple, should be:\n\
+ pkey - The key to sign with\n\
+ digest - The message digest to use\n\
+Returns: None\n\
+";
+
+static PyObject *
+crypto_X509Req_sign(crypto_X509ReqObj *self, PyObject *args)
+{
+ crypto_PKeyObj *pkey;
+ char *digest_name;
+ const EVP_MD *digest;
+
+ if (!PyArg_ParseTuple(args, "O!s:sign", &crypto_PKey_Type, &pkey,
+ &digest_name))
+ return NULL;
+
+ if ((digest = EVP_get_digestbyname(digest_name)) == NULL)
+ {
+ PyErr_SetString(PyExc_ValueError, "No such digest method");
+ return NULL;
+ }
+
+ if (!X509_REQ_sign(self->x509_req, pkey->pkey, digest))
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char crypto_X509Req_verify_doc[] = "\n\
+Verifies a certificate request using the supplied public key\n\
+ \n\
+Arguments: self - X509Req object\n\
+ args - The Python argument tuple, should be:\n\
+ key - a public key\n\
+Returns: True, if the signature is correct, 0 otherwise.\n\
+";
+
+PyObject *
+crypto_X509Req_verify(crypto_X509ReqObj *self, PyObject *args)
+{
+ PyObject *obj;
+ crypto_PKeyObj *key;
+ int answer;
+
+ if (!PyArg_ParseTuple(args, "O!:verify", &crypto_PKey_Type, &obj))
+ return NULL;
+
+ key = (crypto_PKeyObj *)obj;
+
+ if ((answer = X509_REQ_verify(self->x509_req, key->pkey)) < 0)
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+
+ return PyInt_FromLong(answer);
+}
+
+static char crypto_X509Req_add_extensions_doc[] = "\n\
+Add extensions to the request.\n\
+\n\
+Arguments: self - X509Req object\n\
+ args - The Python argument tuple, should be:\n\
+ extensions - a sequence of X509Extension objects\n\
+Returns: None\n\
+";
+
+static PyObject *
+crypto_X509Req_add_extensions(crypto_X509ReqObj *self, PyObject *args)
+{
+ PyObject *extensions;
+ crypto_X509ExtensionObj *ext;
+ STACK_OF(X509_EXTENSION) *exts;
+ int nr_of_extensions, i;
+
+ if (!PyArg_ParseTuple(args, "O:add_extensions", &extensions))
+ return NULL;
+
+ if (!PySequence_Check(extensions))
+ {
+ PyErr_SetString(PyExc_TypeError, "Expected a sequence");
+ return NULL;
+ }
+
+ /* Make a STACK_OF(X509_EXTENSION) from sequence */
+ if ((exts = sk_X509_EXTENSION_new_null()) == NULL)
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+
+ /* Put the extensions in a stack */
+ nr_of_extensions = PySequence_Length(extensions);
+
+ for (i = 0; i < nr_of_extensions; i++)
+ {
+ ext = (crypto_X509ExtensionObj *)PySequence_GetItem(extensions, i);
+ if (!(crypto_X509Extension_Check(ext)))
+ {
+ PyErr_SetString(PyExc_ValueError,
+ "One of the elements is not an X509Extension");
+ sk_X509_EXTENSION_free(exts);
+ return NULL;
+ }
+ sk_X509_EXTENSION_push(exts, ext->x509_extension);
+ }
+
+ if (!X509_REQ_add_extensions(self->x509_req, exts))
+ {
+ sk_X509_EXTENSION_free(exts);
+ exception_from_error_queue();
+ return NULL;
+ }
+
+ sk_X509_EXTENSION_free(exts);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/*
+ * ADD_METHOD(name) expands to a correct PyMethodDef declaration
+ * { 'name', (PyCFunction)crypto_X509Req_name, METH_VARARGS }
+ * for convenience
+ */
+#define ADD_METHOD(name) \
+ { #name, (PyCFunction)crypto_X509Req_##name, METH_VARARGS, crypto_X509Req_##name##_doc }
+static PyMethodDef crypto_X509Req_methods[] =
+{
+ ADD_METHOD(get_subject),
+ ADD_METHOD(get_pubkey),
+ ADD_METHOD(set_pubkey),
+ ADD_METHOD(sign),
+ ADD_METHOD(verify),
+ ADD_METHOD(add_extensions),
+ { NULL, NULL }
+};
+#undef ADD_METHOD
+
+
+/*
+ * Constructor for X509Req, never called by Python code directly
+ *
+ * Arguments: name - A "real" X509_REQ object
+ * dealloc - Boolean value to specify whether the destructor should
+ * free the "real" X509_REQ object
+ * Returns: The newly created X509Req object
+ */
+crypto_X509ReqObj *
+crypto_X509Req_New(X509_REQ *req, int dealloc)
+{
+ crypto_X509ReqObj *self;
+
+ self = PyObject_New(crypto_X509ReqObj, &crypto_X509Req_Type);
+
+ if (self == NULL)
+ return NULL;
+
+ self->x509_req = req;
+ self->dealloc = dealloc;
+
+ return self;
+}
+
+/*
+ * Deallocate the memory used by the X509Req object
+ *
+ * Arguments: self - The X509Req object
+ * Returns: None
+ */
+static void
+crypto_X509Req_dealloc(crypto_X509ReqObj *self)
+{
+ /* Sometimes we don't have to dealloc this */
+ if (self->dealloc)
+ X509_REQ_free(self->x509_req);
+
+ PyObject_Del(self);
+}
+
+
+/*
+ * Find attribute.
+ *
+ * Arguments: self - The X509Req object
+ * name - The attribute name
+ * Returns: A Python object for the attribute, or NULL if something went
+ * wrong
+ */
+static PyObject *
+crypto_X509Req_getattr(crypto_X509ReqObj *self, char *name)
+{
+ return Py_FindMethod(crypto_X509Req_methods, (PyObject *)self, name);
+}
+
+PyTypeObject crypto_X509Req_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "X509Req",
+ sizeof(crypto_X509ReqObj),
+ 0,
+ (destructor)crypto_X509Req_dealloc,
+ NULL, /* print */
+ (getattrfunc)crypto_X509Req_getattr,
+};
+
+
+/*
+ * Initialize the X509Req part of the crypto module
+ *
+ * Arguments: dict - The crypto module dictionary
+ * Returns: None
+ */
+int
+init_crypto_x509req(PyObject *dict)
+{
+ crypto_X509Req_Type.ob_type = &PyType_Type;
+ Py_INCREF(&crypto_X509Req_Type);
+ PyDict_SetItemString(dict, "X509ReqType", (PyObject *)&crypto_X509Req_Type);
+ return 1;
+}
diff --git a/src/crypto/x509req.h b/src/crypto/x509req.h
new file mode 100644
index 0000000..db8043c
--- /dev/null
+++ b/src/crypto/x509req.h
@@ -0,0 +1,30 @@
+/*
+ * x509req.h
+ *
+ * Copyright (C) AB Strakt 2001, All rights reserved
+ *
+ * Export X509 request functions and data structures.
+ * See the file RATIONALE for a short explanation of why this module was written.
+ *
+ * @(#) $Id: x509req.h,v 1.6 2002/09/04 22:24:59 iko Exp $
+ */
+#ifndef PyOpenSSL_SSL_X509REQ_H_
+#define PyOpenSSL_SSL_X509REQ_H_
+
+#include <Python.h>
+#include <openssl/ssl.h>
+
+extern int init_crypto_x509req (PyObject *);
+
+extern PyTypeObject crypto_X509Req_Type;
+
+#define crypto_X509Req_Check(v) ((v)->ob_type == &crypto_X509Req_Type)
+
+typedef struct {
+ PyObject_HEAD
+ X509_REQ *x509_req;
+ int dealloc;
+} crypto_X509ReqObj;
+
+
+#endif
diff --git a/src/crypto/x509store.c b/src/crypto/x509store.c
new file mode 100644
index 0000000..bd81f0a
--- /dev/null
+++ b/src/crypto/x509store.c
@@ -0,0 +1,145 @@
+/*
+ * x509store.c
+ *
+ * Copyright (C) AB Strakt 2001, All rights reserved
+ *
+ * X.509 Store handling, mostly thin wrapping.
+ * See the file RATIONALE for a short explanation of why this module was written.
+ */
+#include <Python.h>
+#define crypto_MODULE
+#include "crypto.h"
+
+static char *CVSid = "@(#) $Id: x509store.c,v 1.9 2002/09/04 22:24:59 iko Exp $";
+
+static char crypto_X509Store_add_cert_doc[] = "\n\
+Add a certificate\n\
+\n\
+Arguments: self - The X509Store object\n\
+ args - The Python argument tuple, should be:\n\
+ cert - The certificate to add\n\
+Returns: None\n\
+";
+
+static PyObject *
+crypto_X509Store_add_cert(crypto_X509StoreObj *self, PyObject *args)
+{
+ crypto_X509Obj *cert;
+
+ if (!PyArg_ParseTuple(args, "O!:add_cert", &crypto_X509_Type, &cert))
+ return NULL;
+
+ if (!X509_STORE_add_cert(self->x509_store, cert->x509))
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+/*
+ * ADD_METHOD(name) expands to a correct PyMethodDef declaration
+ * { 'name', (PyCFunction)crypto_X509Store_name, METH_VARARGS }
+ * for convenience
+ */
+#define ADD_METHOD(name) \
+ { #name, (PyCFunction)crypto_X509Store_##name, METH_VARARGS, crypto_X509Store_##name##_doc }
+static PyMethodDef crypto_X509Store_methods[] =
+{
+ ADD_METHOD(add_cert),
+ { NULL, NULL }
+};
+#undef ADD_METHOD
+
+
+/*
+ * Constructor for X509Store, never called by Python code directly
+ *
+ * Arguments: name - A "real" X509_STORE object
+ * dealloc - Boolean value to specify whether the destructor should
+ * free the "real" X509_STORE object
+ * Returns: The newly created X509Store object
+ */
+crypto_X509StoreObj *
+crypto_X509Store_New(X509_STORE *store, int dealloc)
+{
+ crypto_X509StoreObj *self;
+
+ self = PyObject_New(crypto_X509StoreObj, &crypto_X509Store_Type);
+
+ if (self == NULL)
+ return NULL;
+
+ self->x509_store = store;
+ self->dealloc = dealloc;
+
+ return self;
+}
+
+/*
+ * Deallocate the memory used by the X509Store object
+ *
+ * Arguments: self - The X509Store object
+ * Returns: None
+ */
+static void
+crypto_X509Store_dealloc(crypto_X509StoreObj *self)
+{
+ /* Sometimes we don't have to dealloc this */
+ if (self->dealloc)
+ X509_STORE_free(self->x509_store);
+
+ PyObject_Del(self);
+}
+
+
+/*
+ * Find attribute.
+ *
+ * Arguments: self - The X509Store object
+ * name - The attribute name
+ * Returns: A Python object for the attribute, or NULL if something went
+ * wrong
+ */
+static PyObject *
+crypto_X509Store_getattr(crypto_X509StoreObj *self, char *name)
+{
+ return Py_FindMethod(crypto_X509Store_methods, (PyObject *)self, name);
+}
+
+PyTypeObject crypto_X509Store_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "X509Store",
+ sizeof(crypto_X509StoreObj),
+ 0,
+ (destructor)crypto_X509Store_dealloc,
+ NULL, /* print */
+ (getattrfunc)crypto_X509Store_getattr,
+ NULL, /* setattr */
+ NULL, /* compare */
+ NULL, /* repr */
+ NULL, /* as_number */
+ NULL, /* as_sequence */
+ NULL, /* as_mapping */
+ NULL /* hash */
+};
+
+
+/*
+ * Initialize the X509Store part of the crypto module
+ *
+ * Arguments: dict - The crypto module dictionary
+ * Returns: None
+ */
+int
+init_crypto_x509store(PyObject *dict)
+{
+ crypto_X509Store_Type.ob_type = &PyType_Type;
+ Py_INCREF(&crypto_X509Store_Type);
+ PyDict_SetItemString(dict, "X509StoreType", (PyObject *)&crypto_X509Store_Type);
+ return 1;
+}
diff --git a/src/crypto/x509store.h b/src/crypto/x509store.h
new file mode 100644
index 0000000..9ed5073
--- /dev/null
+++ b/src/crypto/x509store.h
@@ -0,0 +1,30 @@
+/*
+ * x509store.h
+ *
+ * Copyright (C) AB Strakt 2001, All rights reserved
+ *
+ * Export X509 store functions and data structures.
+ * See the file RATIONALE for a short explanation of why this module was written.
+ *
+ * @(#) $Id: x509store.h,v 1.4 2002/09/04 22:24:59 iko Exp $
+ */
+#ifndef PyOpenSSL_SSL_X509STORE_H_
+#define PyOpenSSL_SSL_X509STORE_H_
+
+#include <Python.h>
+#include <openssl/ssl.h>
+
+extern int init_crypto_x509store (PyObject *);
+
+extern PyTypeObject crypto_X509Store_Type;
+
+#define crypto_X509Store_Check(v) ((v)->ob_type == &crypto_X509Store_Type)
+
+typedef struct {
+ PyObject_HEAD
+ X509_STORE *x509_store;
+ int dealloc;
+} crypto_X509StoreObj;
+
+
+#endif
diff --git a/src/pymemcompat.h b/src/pymemcompat.h
new file mode 100644
index 0000000..24221ec
--- /dev/null
+++ b/src/pymemcompat.h
@@ -0,0 +1,86 @@
+/* The idea of this file is that you bundle it with your extension,
+ #include it, program to Python 2.3's memory API and have your
+ extension build with any version of Python from 1.5.2 through to
+ 2.3 (and hopefully beyond). */
+
+#ifndef Py_PYMEMCOMPAT_H
+#define Py_PYMEMCOMPAT_H
+
+#include "Python.h"
+
+/* There are three "families" of memory API: the "raw memory", "object
+ memory" and "object" families. (This is ignoring the matter of the
+ cycle collector, about which more is said below).
+
+ Raw Memory:
+
+ PyMem_Malloc, PyMem_Realloc, PyMem_Free
+
+ Object Memory:
+
+ PyObject_Malloc, PyObject_Realloc, PyObject_Free
+
+ Object:
+
+ PyObject_New, PyObject_NewVar, PyObject_Del
+
+ The raw memory and object memory allocators both mimic the
+ malloc/realloc/free interface from ANSI C, but the object memory
+ allocator can (and, since 2.3, does by default) use a different
+ allocation strategy biased towards lots of lots of "small"
+ allocations.
+
+ The object family is used for allocating Python objects, and the
+ initializers take care of some basic initialization (setting the
+ refcount to 1 and filling out the ob_type field) as well as having
+ a somewhat different interface.
+
+ Do not mix the families! E.g. do not allocate memory with
+ PyMem_Malloc and free it with PyObject_Free. You may get away with
+ it quite a lot of the time, but there *are* scenarios where this
+ will break. You Have Been Warned.
+
+ Also, in many versions of Python there are an insane amount of
+ memory interfaces to choose from. Use the ones described above. */
+
+#if PY_VERSION_HEX < 0x01060000
+/* raw memory interface already present */
+
+/* there is no object memory interface in 1.5.2 */
+#define PyObject_Malloc PyMem_Malloc
+#define PyObject_Realloc PyMem_Realloc
+#define PyObject_Free PyMem_Free
+
+/* the object interface is there, but the names have changed */
+#define PyObject_New PyObject_NEW
+#define PyObject_NewVar PyObject_NEW_VAR
+#define PyObject_Del PyMem_Free
+#endif
+
+/* If your object is a container you probably want to support the
+ cycle collector, which was new in Python 2.0.
+
+ Unfortunately, the interface to the collector that was present in
+ Python 2.0 and 2.1 proved to be tricky to use, and so changed in
+ 2.2 -- in a way that can't easily be papered over with macros.
+
+ This file contains macros that let you program to the 2.2 GC API.
+ Your module will compile against any Python since version 1.5.2,
+ but the type will only participate in the GC in versions 2.2 and
+ up. Some work is still necessary on your part to only fill out the
+ tp_traverse and tp_clear fields when they exist and set tp_flags
+ appropriately.
+
+ It is possible to support both the 2.0 and 2.2 GC APIs, but it's
+ not pretty and this comment block is too narrow to contain a
+ desciption of what's required... */
+
+#if PY_VERSION_HEX < 0x020200B1
+#define PyObject_GC_New PyObject_New
+#define PyObject_GC_NewVar PyObject_NewVar
+#define PyObject_GC_Del PyObject_Del
+#define PyObject_GC_Track(op)
+#define PyObject_GC_UnTrack(op)
+#endif
+
+#endif /* !Py_PYMEMCOMPAT_H */
diff --git a/src/rand/rand.c b/src/rand/rand.c
new file mode 100644
index 0000000..a87f2f9
--- /dev/null
+++ b/src/rand/rand.c
@@ -0,0 +1,240 @@
+/*
+ * rand.c
+ *
+ * Copyright (C) AB Strakt 2001, All rights reserved
+ *
+ * PRNG management routines, thin wrappers.
+ * See the file RATIONALE for a short explanation of why this module was written.
+ *
+ * Reviewed 2001-07-23
+ */
+#include <Python.h>
+
+/*
+ * In order to get the RAND_screen definition from the rand.h
+ * WIN32 or WINDOWS needs to be defined, otherwise we get a
+ * warning.
+ */
+#ifdef MS_WINDOWS
+#define WIN32
+#endif
+#include <openssl/rand.h>
+
+static char rand_doc[] = "\n\
+PRNG management routines, thin wrappers.\n\
+See the file RATIONALE for a short explanation of why this module was written.\n\
+";
+
+static char *CVSid = "@(#) $Id: rand.c,v 1.10 2002/07/08 11:06:01 martin Exp $";
+
+static char rand_add_doc[] = "\n\
+Add data with a given entropy to the PRNG\n\
+\n\
+Arguments: spam - Always NULL\n\
+ args - The Python argument tuple, should be:\n\
+ buffer - Buffer with random data\n\
+ entropy - The entropy (in bytes) measurement of the buffer\n\
+Returns: None\n\
+";
+
+static PyObject *
+rand_add(PyObject *spam, PyObject *args)
+{
+ char *buf;
+ int size;
+ double entropy;
+
+ if (!PyArg_ParseTuple(args, "s#d:add", &buf, &size, &entropy))
+ return NULL;
+
+ RAND_add(buf, size, entropy);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char rand_seed_doc[] = "\n\
+Alias for rand_add, with entropy equal to length\n\
+\n\
+Arguments: spam - Always NULL\n\
+ args - The Python argument tuple, should be:\n\
+ buffer - Buffer with random data\n\
+Returns: None\n\
+";
+
+static PyObject *
+rand_seed(PyObject *spam, PyObject *args)
+{
+ char *buf;
+ int size;
+
+ if (!PyArg_ParseTuple(args, "s#:seed", &buf, &size))
+ return NULL;
+
+ RAND_seed(buf, size);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char rand_status_doc[] = "\n\
+Retrieve the status of the PRNG\n\
+\n\
+Arguments: spam - Always NULL\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: True if the PRNG is seeded enough, false otherwise\n\
+";
+
+static PyObject *
+rand_status(PyObject *spam, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":status"))
+ return NULL;
+
+ return PyInt_FromLong((long)RAND_status());
+}
+
+#ifdef MS_WINDOWS
+static char rand_screen_doc[] = "\n\
+Add the current contents of the screen to the PRNG state. Availability:\n\
+Windows.\n\
+\n\
+Arguments: spam - Always NULL\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: None\n\
+";
+
+static PyObject *
+rand_screen(PyObject *spam, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":screen"))
+ return NULL;
+
+ RAND_screen();
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+#endif
+
+static char rand_egd_doc[] = "\n\
+Query an entropy gathering daemon (EGD) for random data and add it to the\n\
+PRNG. I haven't found any problems when the socket is missing, the function\n\
+just returns 0.\n\
+\n\
+Arguments: spam - Always NULL\n\
+ args - The Python argument tuple, should be:\n\
+ path - The path to the EGD socket\n\
+ bytes - (optional) The number of bytes to read, default is 255\n\
+Returns: The number of bytes read (NB: a value of 0 isn't necessarily an\n\
+ error, check rand.status())\n\
+";
+
+static PyObject *
+rand_egd(PyObject *spam, PyObject *args)
+{
+ char *path;
+ int bytes = 255;
+
+ if (!PyArg_ParseTuple(args, "s|i:egd", &path, &bytes))
+ return NULL;
+
+ return PyInt_FromLong((long)RAND_egd_bytes(path, bytes));
+}
+
+static char rand_cleanup_doc[] = "\n\
+Erase the memory used by the PRNG.\n\
+\n\
+Arguments: spam - Always NULL\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: None\n\
+";
+
+static PyObject *
+rand_cleanup(PyObject *spam, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":cleanup"))
+ return NULL;
+
+ RAND_cleanup();
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char rand_load_file_doc[] = "\n\
+Seed the PRNG with data from a file\n\
+\n\
+Arguments: spam - Always NULL\n\
+ args - The Python argument tuple, should be:\n\
+ filename - The file to read data from\n\
+ maxbytes - (optional) The number of bytes to read, default is\n\
+ to read the entire file\n\
+Returns: The number of bytes read\n\
+";
+
+static PyObject *
+rand_load_file(PyObject *spam, PyObject *args)
+{
+ char *filename;
+ int maxbytes = -1;
+
+ if (!PyArg_ParseTuple(args, "s|i:load_file", &filename, &maxbytes))
+ return NULL;
+
+ return PyInt_FromLong((long)RAND_load_file(filename, maxbytes));
+}
+
+static char rand_write_file_doc[] = "\n\
+Save PRNG state to a file\n\
+\n\
+Arguments: spam - Always NULL\n\
+ args - The Python argument tuple, should be:\n\
+ filename - The file to write data to\n\
+Returns: The number of bytes written\n\
+";
+
+static PyObject *
+rand_write_file(PyObject *spam, PyObject *args)
+{
+ char *filename;
+
+ if (!PyArg_ParseTuple(args, "s:write_file", &filename))
+ return NULL;
+
+ return PyInt_FromLong((long)RAND_write_file(filename));
+}
+
+
+/* Methods in the OpenSSL.rand module */
+static PyMethodDef rand_methods[] = {
+ { "add", (PyCFunction)rand_add, METH_VARARGS, rand_add_doc },
+ { "seed", (PyCFunction)rand_seed, METH_VARARGS, rand_seed_doc },
+ { "status", (PyCFunction)rand_status, METH_VARARGS, rand_status_doc },
+#ifdef MS_WINDOWS
+ { "screen", (PyCFunction)rand_screen, METH_VARARGS, rand_screen_doc },
+#endif
+ { "egd", (PyCFunction)rand_egd, METH_VARARGS, rand_egd_doc },
+ { "cleanup", (PyCFunction)rand_cleanup, METH_VARARGS, rand_cleanup_doc },
+ { "load_file", (PyCFunction)rand_load_file, METH_VARARGS, rand_load_file_doc },
+ { "write_file",(PyCFunction)rand_write_file, METH_VARARGS, rand_write_file_doc },
+ { NULL, NULL }
+};
+
+
+/*
+ * Initialize the rand sub module
+ *
+ * Arguments: None
+ * Returns: None
+ */
+void
+initrand(void)
+{
+ PyObject *module;
+
+ ERR_load_RAND_strings();
+
+ if ((module = Py_InitModule3("rand", rand_methods, rand_doc)) == NULL)
+ return;
+}
+
diff --git a/src/ssl/connection.c b/src/ssl/connection.c
new file mode 100755
index 0000000..96111aa
--- /dev/null
+++ b/src/ssl/connection.c
@@ -0,0 +1,1076 @@
+/*
+ * connection.c
+ *
+ * Copyright (C) AB Strakt 2001, All rights reserved
+ *
+ * SSL Connection objects and methods.
+ * See the file RATIONALE for a short explanation of why this module was written.
+ *
+ * Reviewed 2001-07-23
+ */
+#include <Python.h>
+#define SSL_MODULE
+#include <openssl/err.h>
+#include "ssl.h"
+
+#ifndef MS_WINDOWS
+# include <sys/socket.h>
+# include <netinet/in.h>
+# if !(defined(__BEOS__) || defined(__CYGWIN__))
+# include <netinet/tcp.h>
+# endif
+#else
+# include <winsock.h>
+#endif
+
+static char *CVSid = "@(#) $Id: connection.c,v 1.28 2004/08/06 10:21:56 martin Exp $";
+
+
+/**
+ * If we are on UNIX, fine, just use PyErr_SetFromErrno. If we are on Windows,
+ * apply some black winsock voodoo. This is basically just copied from Python's
+ * socketmodule.c
+ *
+ * Arguments: None
+ * Returns: None
+ */
+static void
+syscall_from_errno(void)
+{
+#ifdef MS_WINDOWS
+ int errnum = WSAGetLastError();
+ if (errnum)
+ {
+ static struct { int num; const char *msg; } *msgp, msgs[] = {
+ { WSAEINTR, "Interrupted system call" },
+ { WSAEBADF, "Bad file descriptor" },
+ { WSAEACCES, "Permission denied" },
+ { WSAEFAULT, "Bad address" },
+ { WSAEINVAL, "Invalid argument" },
+ { WSAEMFILE, "Too many open files" },
+ { WSAEWOULDBLOCK, "The socket operation could not complete "
+ "without blocking" },
+ { WSAEINPROGRESS, "Operation now in progress" },
+ { WSAEALREADY, "Operation already in progress" },
+ { WSAENOTSOCK, "Socket operation on non-socket" },
+ { WSAEDESTADDRREQ, "Destination address required" },
+ { WSAEMSGSIZE, "Message too long" },
+ { WSAEPROTOTYPE, "Protocol wrong type for socket" },
+ { WSAENOPROTOOPT, "Protocol not available" },
+ { WSAEPROTONOSUPPORT, "Protocol not supported" },
+ { WSAESOCKTNOSUPPORT, "Socket type not supported" },
+ { WSAEOPNOTSUPP, "Operation not supported" },
+ { WSAEPFNOSUPPORT, "Protocol family not supported" },
+ { WSAEAFNOSUPPORT, "Address family not supported" },
+ { WSAEADDRINUSE, "Address already in use" },
+ { WSAEADDRNOTAVAIL, "Can't assign requested address" },
+ { WSAENETDOWN, "Network is down" },
+ { WSAENETUNREACH, "Network is unreachable" },
+ { WSAENETRESET, "Network dropped connection on reset" },
+ { WSAECONNABORTED, "Software caused connection abort" },
+ { WSAECONNRESET, "Connection reset by peer" },
+ { WSAENOBUFS, "No buffer space available" },
+ { WSAEISCONN, "Socket is already connected" },
+ { WSAENOTCONN, "Socket is not connected" },
+ { WSAESHUTDOWN, "Can't send after socket shutdown" },
+ { WSAETOOMANYREFS, "Too many references: can't splice" },
+ { WSAETIMEDOUT, "Operation timed out" },
+ { WSAECONNREFUSED, "Connection refused" },
+ { WSAELOOP, "Too many levels of symbolic links" },
+ { WSAENAMETOOLONG, "File name too long" },
+ { WSAEHOSTDOWN, "Host is down" },
+ { WSAEHOSTUNREACH, "No route to host" },
+ { WSAENOTEMPTY, "Directory not empty" },
+ { WSAEPROCLIM, "Too many processes" },
+ { WSAEUSERS, "Too many users" },
+ { WSAEDQUOT, "Disc quota exceeded" },
+ { WSAESTALE, "Stale NFS file handle" },
+ { WSAEREMOTE, "Too many levels of remote in path" },
+ { WSASYSNOTREADY, "Network subsystem is unvailable" },
+ { WSAVERNOTSUPPORTED, "WinSock version is not supported" },
+ { WSANOTINITIALISED, "Successful WSAStartup() not yet performed" },
+ { WSAEDISCON, "Graceful shutdown in progress" },
+ /* Resolver errors */
+ { WSAHOST_NOT_FOUND, "No such host is known" },
+ { WSATRY_AGAIN, "Host not found, or server failed" },
+ { WSANO_RECOVERY, "Unexpected server error encountered" },
+ { WSANO_DATA, "Valid name without requested data" },
+ { WSANO_ADDRESS, "No address, look for MX record" },
+ { 0, NULL }
+ };
+ PyObject *v;
+ const char *msg = "winsock error";
+
+ for (msgp = msgs; msgp->msg; msgp++)
+ {
+ if (errnum == msgp->num)
+ {
+ msg = msgp->msg;
+ break;
+ }
+ }
+
+ v = Py_BuildValue("(is)", errnum, msg);
+ if (v != NULL)
+ {
+ PyErr_SetObject(ssl_SysCallError, v);
+ Py_DECREF(v);
+ }
+ return;
+ }
+#else
+ PyErr_SetFromErrno(ssl_SysCallError);
+#endif
+}
+
+/*
+ * Handle errors raised by SSL I/O functions. NOTE: Not SSL_shutdown ;)
+ *
+ * Arguments: ssl - The SSL object
+ * err - The return code from SSL_get_error
+ * ret - The return code from the SSL I/O function
+ * Returns: None, the calling function should return NULL
+ */
+static void
+handle_ssl_errors(SSL *ssl, int err, int ret)
+{
+ switch (err)
+ {
+ /*
+ * Strange as it may seem, ZeroReturn is not an error per se. It means
+ * that the SSL Connection has been closed correctly (note, not the
+ * transport layer!), i.e. closure alerts have been exchanged. This is
+ * an exception since
+ * + There's an SSL "error" code for it
+ * + You have to deal with it in any case, close the transport layer
+ * etc
+ */
+ case SSL_ERROR_ZERO_RETURN:
+ PyErr_SetNone(ssl_ZeroReturnError);
+ break;
+
+ /*
+ * The WantXYZ exceptions don't mean that there's an error, just that
+ * nothing could be read/written just now, maybe because the transport
+ * layer would block on the operation, or that there's not enough data
+ * available to fill an entire SSL record.
+ */
+ case SSL_ERROR_WANT_READ:
+ PyErr_SetNone(ssl_WantReadError);
+ break;
+
+ case SSL_ERROR_WANT_WRITE:
+ PyErr_SetNone(ssl_WantWriteError);
+ break;
+
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ PyErr_SetNone(ssl_WantX509LookupError);
+ break;
+
+ case SSL_ERROR_SYSCALL:
+ if (ERR_peek_error() == 0)
+ {
+ if (ret < 0)
+ {
+ syscall_from_errno();
+ }
+ else
+ {
+ PyObject *v;
+
+ v = Py_BuildValue("(is)", -1, "Unexpected EOF");
+ if (v != NULL)
+ {
+ PyErr_SetObject(ssl_SysCallError, v);
+ Py_DECREF(v);
+ }
+ }
+ break;
+ }
+
+ /* NOTE: Fall-through here, we don't want to duplicate code, right? */
+
+ case SSL_ERROR_SSL:
+ ;
+ default:
+ exception_from_error_queue();
+ break;
+ }
+}
+
+/*
+ * Here be member methods of the Connection "class"
+ */
+
+static char ssl_Connection_get_context_doc[] = "\n\
+Get session context\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: A Context object\n\
+";
+static PyObject *
+ssl_Connection_get_context(ssl_ConnectionObj *self, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":get_context"))
+ return NULL;
+
+ Py_INCREF(self->context);
+ return (PyObject *)self->context;
+}
+
+static char ssl_Connection_pending_doc[] = "\n\
+Get the number of bytes that can be safely read from the connection\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: \n\
+";
+static PyObject *
+ssl_Connection_pending(ssl_ConnectionObj *self, PyObject *args)
+{
+ int ret;
+
+ if (!PyArg_ParseTuple(args, ":pending"))
+ return NULL;
+
+ ret = SSL_pending(self->ssl);
+ return PyInt_FromLong((long)ret);
+}
+
+static char ssl_Connection_send_doc[] = "\n\
+Send data on the connection. NOTE: If you get one of the WantRead,\n\
+WantWrite or WantX509Lookup exceptions on this, you have to call the\n\
+method again with the SAME buffer.\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be:\n\
+ buf - The string to send\n\
+ flags - (optional) Included for compatability with the socket\n\
+ API, the value is ignored\n\
+Returns: The number of bytes written\n\
+";
+static PyObject *
+ssl_Connection_send(ssl_ConnectionObj *self, PyObject *args)
+{
+ char *buf;
+ int len, ret, err, flags;
+
+ if (!PyArg_ParseTuple(args, "s#|i:send", &buf, &len, &flags))
+ return NULL;
+
+ MY_BEGIN_ALLOW_THREADS(self->tstate)
+ ret = SSL_write(self->ssl, buf, len);
+ MY_END_ALLOW_THREADS(self->tstate)
+
+ if (PyErr_Occurred())
+ {
+ flush_error_queue();
+ return NULL;
+ }
+
+ err = SSL_get_error(self->ssl, ret);
+ if (err == SSL_ERROR_NONE)
+ {
+ return PyInt_FromLong((long)ret);
+ }
+ else
+ {
+ handle_ssl_errors(self->ssl, err, ret);
+ return NULL;
+ }
+}
+
+static char ssl_Connection_sendall_doc[] = "\n\
+Send \"all\" data on the connection. This calls send() repeatedly until\n\
+all data is sent. If an error occurs, it's impossible to tell how much data\n\
+has been sent.\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be:\n\
+ buf - The string to send\n\
+ flags - (optional) Included for compatability with the socket\n\
+ API, the value is ignored\n\
+Returns: The number of bytes written\n\
+";
+static PyObject *
+ssl_Connection_sendall(ssl_ConnectionObj *self, PyObject *args)
+{
+ char *buf;
+ int len, ret, err, flags;
+ PyObject *pyret = Py_None;
+
+ if (!PyArg_ParseTuple(args, "s#|i:sendall", &buf, &len, &flags))
+ return NULL;
+
+ do {
+ MY_BEGIN_ALLOW_THREADS(self->tstate)
+ ret = SSL_write(self->ssl, buf, len);
+ MY_END_ALLOW_THREADS(self->tstate)
+ if (PyErr_Occurred())
+ {
+ flush_error_queue();
+ pyret = NULL;
+ break;
+ }
+ err = SSL_get_error(self->ssl, ret);
+ if (err == SSL_ERROR_NONE)
+ {
+ buf += ret;
+ len -= ret;
+ }
+ else if (err == SSL_ERROR_SSL || err == SSL_ERROR_SYSCALL ||
+ err == SSL_ERROR_ZERO_RETURN)
+ {
+ handle_ssl_errors(self->ssl, err, ret);
+ pyret = NULL;
+ break;
+ }
+ } while (len > 0);
+
+ Py_XINCREF(pyret);
+ return pyret;
+}
+
+static char ssl_Connection_recv_doc[] = "\n\
+Receive data on the connection. NOTE: If you get one of the WantRead,\n\
+WantWrite or WantX509Lookup exceptions on this, you have to call the\n\
+method again with the SAME buffer.\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be:\n\
+ bufsiz - The maximum number of bytes to read\n\
+ flags - (optional) Included for compatability with the socket\n\
+ API, the value is ignored\n\
+Returns: The number of bytes read\n\
+";
+static PyObject *
+ssl_Connection_recv(ssl_ConnectionObj *self, PyObject *args)
+{
+ int bufsiz, ret, err, flags;
+ PyObject *buf;
+
+ if (!PyArg_ParseTuple(args, "i|i:recv", &bufsiz, &flags))
+ return NULL;
+
+ buf = PyString_FromStringAndSize(NULL, bufsiz);
+ if (buf == NULL)
+ return NULL;
+
+ MY_BEGIN_ALLOW_THREADS(self->tstate)
+ ret = SSL_read(self->ssl, PyString_AsString(buf), bufsiz);
+ MY_END_ALLOW_THREADS(self->tstate)
+
+ if (PyErr_Occurred())
+ {
+ Py_DECREF(buf);
+ flush_error_queue();
+ return NULL;
+ }
+
+ err = SSL_get_error(self->ssl, ret);
+ if (err == SSL_ERROR_NONE)
+ {
+ if (ret != bufsiz && _PyString_Resize(&buf, ret) < 0)
+ return NULL;
+ return buf;
+ }
+ else
+ {
+ handle_ssl_errors(self->ssl, err, ret);
+ Py_DECREF(buf);
+ return NULL;
+ }
+}
+
+static char ssl_Connection_renegotiate_doc[] = "\n\
+Renegotiate the session\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: True if the renegotiation can be started, false otherwise\n\
+";
+static PyObject *
+ssl_Connection_renegotiate(ssl_ConnectionObj *self, PyObject *args)
+{
+ int ret;
+
+ if (!PyArg_ParseTuple(args, ":renegotiate"))
+ return NULL;
+
+ MY_BEGIN_ALLOW_THREADS(self->tstate);
+ ret = SSL_renegotiate(self->ssl);
+ MY_END_ALLOW_THREADS(self->tstate);
+
+ if (PyErr_Occurred())
+ {
+ flush_error_queue();
+ return NULL;
+ }
+
+ return PyInt_FromLong((long)ret);
+}
+
+static char ssl_Connection_do_handshake_doc[] = "\n\
+Perform an SSL handshake (usually called after renegotiate() or one of\n\
+set_*_state()). This can raise the same exceptions as send and recv.\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: None.\n\
+";
+static PyObject *
+ssl_Connection_do_handshake(ssl_ConnectionObj *self, PyObject *args)
+{
+ int ret, err;
+
+ if (!PyArg_ParseTuple(args, ":do_handshake"))
+ return NULL;
+
+ MY_BEGIN_ALLOW_THREADS(self->tstate);
+ ret = SSL_do_handshake(self->ssl);
+ MY_END_ALLOW_THREADS(self->tstate);
+
+ if (PyErr_Occurred())
+ {
+ flush_error_queue();
+ return NULL;
+ }
+
+ err = SSL_get_error(self->ssl, ret);
+ if (err == SSL_ERROR_NONE)
+ {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ else
+ {
+ handle_ssl_errors(self->ssl, err, ret);
+ return NULL;
+ }
+}
+
+#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x00907000L
+static char ssl_Connection_renegotiate_pending_doc[] = "\n\
+Check if there's a renegotiation in progress, it will return false once\n\
+a renegotiation is finished.\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: Whether there's a renegotiation in progress\n\
+";
+static PyObject *
+ssl_Connection_renegotiate_pending(ssl_ConnectionObj *self, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":renegotiate_pending"))
+ return NULL;
+
+ return PyInt_FromLong((long)SSL_renegotiate_pending(self->ssl));
+}
+#endif
+
+static char ssl_Connection_total_renegotiations_doc[] = "\n\
+Find out the total number of renegotiations.\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: The number of renegotiations.\n\
+";
+static PyObject *
+ssl_Connection_total_renegotiations(ssl_ConnectionObj *self, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":total_renegotiations"))
+ return NULL;
+
+ return PyInt_FromLong(SSL_total_renegotiations(self->ssl));
+}
+
+static char ssl_Connection_set_accept_state_doc[] = "\n\
+Set the connection to work in server mode. The handshake will be handled\n\
+automatically by read/write.\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: None\n\
+";
+static PyObject *
+ssl_Connection_set_accept_state(ssl_ConnectionObj *self, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":set_accept_state"))
+ return NULL;
+
+ SSL_set_accept_state(self->ssl);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char ssl_Connection_set_connect_state_doc[] = "\n\
+Set the connection to work in client mode. The handshake will be handled\n\
+automatically by read/write.\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: None\n\
+";
+static PyObject *
+ssl_Connection_set_connect_state(ssl_ConnectionObj *self, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":set_connect_state"))
+ return NULL;
+
+ SSL_set_connect_state(self->ssl);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char ssl_Connection_connect_doc[] = "\n\
+Connect to remote host and set up client-side SSL\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be:\n\
+ addr - A remote address\n\
+Returns: What the socket's connect method returns\n\
+";
+static PyObject *
+ssl_Connection_connect(ssl_ConnectionObj *self, PyObject *args)
+{
+ PyObject *meth, *ret;
+
+ if ((meth = PyObject_GetAttrString(self->socket, "connect")) == NULL)
+ return NULL;
+
+ SSL_set_connect_state(self->ssl);
+
+ ret = PyEval_CallObject(meth, args);
+ Py_DECREF(meth);
+ if (ret == NULL)
+ return NULL;
+
+ return ret;
+}
+
+static char ssl_Connection_connect_ex_doc[] = "\n\
+Connect to remote host and set up client-side SSL. Note that if the socket's\n\
+connect_ex method doesn't return 0, SSL won't be initialized.\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be:\n\
+ addr - A remove address\n\
+Returns: What the socket's connect_ex method returns\n\
+";
+static PyObject *
+ssl_Connection_connect_ex(ssl_ConnectionObj *self, PyObject *args)
+{
+ PyObject *meth, *ret;
+
+ if ((meth = PyObject_GetAttrString(self->socket, "connect_ex")) == NULL)
+ return NULL;
+
+ SSL_set_connect_state(self->ssl);
+
+ ret = PyEval_CallObject(meth, args);
+ Py_DECREF(meth);
+ if (ret == NULL)
+ return NULL;
+ if (PyInt_Check(ret) && PyInt_AsLong(ret) != 0)
+ return ret;
+
+ return ret;
+}
+
+static char ssl_Connection_accept_doc[] = "\n\
+Accept incoming connection and set up SSL on it\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: A (conn,addr) pair where conn is a Connection and addr is an\n\
+ address\n\
+";
+static PyObject *
+ssl_Connection_accept(ssl_ConnectionObj *self, PyObject *args)
+{
+ PyObject *tuple, *socket, *address, *meth;
+ ssl_ConnectionObj *conn;
+
+ if ((meth = PyObject_GetAttrString(self->socket, "accept")) == NULL)
+ return NULL;
+ tuple = PyEval_CallObject(meth, args);
+ Py_DECREF(meth);
+ if (tuple == NULL)
+ return NULL;
+
+ socket = PyTuple_GetItem(tuple, 0);
+ Py_INCREF(socket);
+ address = PyTuple_GetItem(tuple, 1);
+ Py_INCREF(address);
+ Py_DECREF(tuple);
+
+ conn = ssl_Connection_New(self->context, socket);
+ Py_DECREF(socket);
+ if (conn == NULL)
+ {
+ Py_DECREF(address);
+ return NULL;
+ }
+
+ SSL_set_accept_state(conn->ssl);
+
+ tuple = Py_BuildValue("(OO)", conn, address);
+
+ Py_DECREF(conn);
+ Py_DECREF(address);
+
+ return tuple;
+}
+
+static char ssl_Connection_shutdown_doc[] = "\n\
+Send closure alert\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: True if the shutdown completed successfully (i.e. both sides\n\
+ have sent closure alerts), false otherwise (i.e. you have to\n\
+ wait for a ZeroReturnError on a recv() method call\n\
+";
+static PyObject *
+ssl_Connection_shutdown(ssl_ConnectionObj *self, PyObject *args)
+{
+ int ret;
+
+ if (!PyArg_ParseTuple(args, ":shutdown"))
+ return NULL;
+
+ MY_BEGIN_ALLOW_THREADS(self->tstate)
+ ret = SSL_shutdown(self->ssl);
+ MY_END_ALLOW_THREADS(self->tstate)
+
+ if (PyErr_Occurred())
+ {
+ flush_error_queue();
+ return NULL;
+ }
+
+ if (ret < 0)
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+ else if (ret > 0)
+ {
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ else
+ {
+ Py_INCREF(Py_False);
+ return Py_False;
+ }
+}
+
+static char ssl_Connection_get_cipher_list_doc[] = "\n\
+Get the session cipher list\n\
+WARNING: API change! This used to take an optional argument, and return a\n\
+string.\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: A list of cipher strings\n\
+";
+static PyObject *
+ssl_Connection_get_cipher_list(ssl_ConnectionObj *self, PyObject *args)
+{
+ int idx = 0;
+ const char *ret;
+ PyObject *lst, *item;
+
+ if (!PyArg_ParseTuple(args, ":get_cipher_list"))
+ return NULL;
+
+ lst = PyList_New(0);
+ while ((ret = SSL_get_cipher_list(self->ssl, idx)) != NULL)
+ {
+ item = PyString_FromString(ret);
+ PyList_Append(lst, item);
+ Py_DECREF(item);
+ idx++;
+ }
+ return lst;
+}
+
+static char ssl_Connection_makefile_doc[] = "\n\
+The makefile() method is not implemented, since there is no dup semantics\n\
+for SSL connections\n\
+XXX: Return self instead?\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: NULL\n\
+";
+static PyObject *
+ssl_Connection_makefile(ssl_ConnectionObj *self, PyObject *args)
+{
+ PyErr_SetString(PyExc_NotImplementedError, "Cannot make file object of SSL.Connection");
+ return NULL;
+}
+
+static char ssl_Connection_get_app_data_doc[] = "\n\
+Get application data\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: The application data\n\
+";
+static PyObject *
+ssl_Connection_get_app_data(ssl_ConnectionObj *self, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":get_app_data"))
+ return NULL;
+
+ Py_INCREF(self->app_data);
+ return self->app_data;
+}
+
+static char ssl_Connection_set_app_data_doc[] = "\n\
+Set application data\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be\n\
+ data - The application data\n\
+Returns: None\n\
+";
+static PyObject *
+ssl_Connection_set_app_data(ssl_ConnectionObj *self, PyObject *args)
+{
+ PyObject *data;
+
+ if (!PyArg_ParseTuple(args, "O:set_app_data", &data))
+ return NULL;
+
+ Py_DECREF(self->app_data);
+ Py_INCREF(data);
+ self->app_data = data;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char ssl_Connection_state_string_doc[] = "\n\
+Get a verbose state description\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: A string representing the state\n\
+";
+static PyObject *
+ssl_Connection_state_string(ssl_ConnectionObj *self, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":state_string"))
+ return NULL;
+
+ return PyString_FromString(SSL_state_string_long(self->ssl));
+}
+
+static char ssl_Connection_sock_shutdown_doc[] = "\n\
+See shutdown(2)\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be whatever the\n\
+ socket's shutdown() method expects\n\
+Returns: What the socket's shutdown() method returns\n\
+";
+static PyObject *
+ssl_Connection_sock_shutdown(ssl_ConnectionObj *self, PyObject *args)
+{
+ PyObject *meth, *ret;
+
+ if ((meth = PyObject_GetAttrString(self->socket, "shutdown")) == NULL)
+ return NULL;
+ ret = PyEval_CallObject(meth, args);
+ Py_DECREF(meth);
+ return ret;
+}
+
+static char ssl_Connection_get_peer_certificate_doc[] = "\n\
+Retrieve the other side's certificate (if any)\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: The peer's certificate\n\
+";
+static PyObject *
+ssl_Connection_get_peer_certificate(ssl_ConnectionObj *self, PyObject *args)
+{
+ X509 *cert;
+
+ if (!PyArg_ParseTuple(args, ":get_peer_certificate"))
+ return NULL;
+
+ cert = SSL_get_peer_certificate(self->ssl);
+ if (cert != NULL)
+ {
+ return (PyObject *)crypto_X509_New(cert, 1);
+ }
+ else
+ {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+}
+
+static char ssl_Connection_want_read_doc[] = "\n\
+Checks if more data has to be read from the transport layer to complete an\n\
+operation.\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: True iff more data has to be read\n\
+";
+static PyObject *
+ssl_Connection_want_read(ssl_ConnectionObj *self, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":want_read"))
+ return NULL;
+
+ return PyInt_FromLong((long)SSL_want_read(self->ssl));
+}
+
+static char ssl_Connection_want_write_doc[] = "\n\
+Checks if there is data to write to the transport layer to complete an\n\
+operation.\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: True iff there is data to write\n\
+";
+static PyObject *
+ssl_Connection_want_write(ssl_ConnectionObj *self, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":want_write"))
+ return NULL;
+
+ return PyInt_FromLong((long)SSL_want_write(self->ssl));
+}
+
+/*
+ * Member methods in the Connection object
+ * ADD_METHOD(name) expands to a correct PyMethodDef declaration
+ * { 'name', (PyCFunction)ssl_Connection_name, METH_VARARGS }
+ * for convenience
+ * ADD_ALIAS(name,real) creates an "alias" of the ssl_Connection_real
+ * function with the name 'name'
+ */
+#define ADD_METHOD(name) \
+ { #name, (PyCFunction)ssl_Connection_##name, METH_VARARGS, ssl_Connection_##name##_doc }
+#define ADD_ALIAS(name,real) \
+ { #name, (PyCFunction)ssl_Connection_##real, METH_VARARGS, ssl_Connection_##real##_doc }
+static PyMethodDef ssl_Connection_methods[] =
+{
+ ADD_METHOD(get_context),
+ ADD_METHOD(pending),
+ ADD_METHOD(send),
+ ADD_ALIAS (write, send),
+ ADD_METHOD(sendall),
+ ADD_METHOD(recv),
+ ADD_ALIAS (read, recv),
+ ADD_METHOD(renegotiate),
+ ADD_METHOD(do_handshake),
+#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x00907000L
+ ADD_METHOD(renegotiate_pending),
+#endif
+ ADD_METHOD(total_renegotiations),
+ ADD_METHOD(connect),
+ ADD_METHOD(connect_ex),
+ ADD_METHOD(accept),
+ ADD_METHOD(shutdown),
+ ADD_METHOD(get_cipher_list),
+ ADD_METHOD(makefile),
+ ADD_METHOD(get_app_data),
+ ADD_METHOD(set_app_data),
+ ADD_METHOD(state_string),
+ ADD_METHOD(sock_shutdown),
+ ADD_METHOD(get_peer_certificate),
+ ADD_METHOD(want_read),
+ ADD_METHOD(want_write),
+ ADD_METHOD(set_accept_state),
+ ADD_METHOD(set_connect_state),
+ { NULL, NULL }
+};
+#undef ADD_ALIAS
+#undef ADD_METHOD
+
+
+/*
+ * Constructor for Connection objects
+ *
+ * Arguments: ctx - An SSL Context to use for this connection
+ * sock - The socket to use for transport layer
+ * Returns: The newly created Connection object
+ */
+ssl_ConnectionObj *
+ssl_Connection_New(ssl_ContextObj *ctx, PyObject *sock)
+{
+ ssl_ConnectionObj *self;
+ int fd;
+
+ self = PyObject_GC_New(ssl_ConnectionObj, &ssl_Connection_Type);
+ if (self == NULL)
+ return NULL;
+
+ Py_INCREF(ctx);
+ self->context = ctx;
+
+ Py_INCREF(sock);
+ self->socket = sock;
+
+ self->ssl = NULL;
+
+ Py_INCREF(Py_None);
+ self->app_data = Py_None;
+
+ self->tstate = NULL;
+
+ fd = PyObject_AsFileDescriptor(self->socket);
+ if (fd < 0)
+ {
+ Py_DECREF(self);
+ return NULL;
+ }
+
+ self->ssl = SSL_new(self->context->ctx);
+ SSL_set_app_data(self->ssl, self);
+ SSL_set_fd(self->ssl, (SOCKET_T)fd);
+
+ PyObject_GC_Track(self);
+
+ return self;
+}
+
+/*
+ * Find attribute
+ *
+ * Arguments: self - The Connection object
+ * name - The attribute name
+ * Returns: A Python object for the attribute, or NULL if something went
+ * wrong
+ */
+static PyObject *
+ssl_Connection_getattr(ssl_ConnectionObj *self, char *name)
+{
+ PyObject *meth;
+
+ meth = Py_FindMethod(ssl_Connection_methods, (PyObject *)self, name);
+
+ if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_AttributeError))
+ {
+ PyErr_Clear();
+ /* Try looking it up in the "socket" instead. */
+ meth = PyObject_GetAttrString(self->socket, name);
+ }
+
+ return meth;
+}
+
+/*
+ * Call the visitproc on all contained objects.
+ *
+ * Arguments: self - The Connection object
+ * visit - Function to call
+ * arg - Extra argument to visit
+ * Returns: 0 if all goes well, otherwise the return code from the first
+ * call that gave non-zero result.
+ */
+static int
+ssl_Connection_traverse(ssl_ConnectionObj *self, visitproc visit, void *arg)
+{
+ int ret = 0;
+
+ if (ret == 0 && self->context != NULL)
+ ret = visit((PyObject *)self->context, arg);
+ if (ret == 0 && self->socket != NULL)
+ ret = visit(self->socket, arg);
+ if (ret == 0 && self->app_data != NULL)
+ ret = visit(self->app_data, arg);
+ return ret;
+}
+
+/*
+ * Decref all contained objects and zero the pointers.
+ *
+ * Arguments: self - The Connection object
+ * Returns: Always 0.
+ */
+static int
+ssl_Connection_clear(ssl_ConnectionObj *self)
+{
+ Py_XDECREF(self->context);
+ self->context = NULL;
+ Py_XDECREF(self->socket);
+ self->socket = NULL;
+ Py_XDECREF(self->app_data);
+ self->app_data = NULL;
+ return 0;
+}
+
+/*
+ * Deallocate the memory used by the Connection object
+ *
+ * Arguments: self - The Connection object
+ * Returns: None
+ */
+static void
+ssl_Connection_dealloc(ssl_ConnectionObj *self)
+{
+ PyObject_GC_UnTrack(self);
+ if (self->ssl != NULL)
+ SSL_free(self->ssl);
+ ssl_Connection_clear(self);
+ PyObject_GC_Del(self);
+}
+
+PyTypeObject ssl_Connection_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "Connection",
+ sizeof(ssl_ConnectionObj),
+ 0,
+ (destructor)ssl_Connection_dealloc,
+ NULL, /* print */
+ (getattrfunc)ssl_Connection_getattr,
+ NULL, /* setattr */
+ NULL, /* compare */
+ NULL, /* repr */
+ NULL, /* as_number */
+ NULL, /* as_sequence */
+ NULL, /* as_mapping */
+ NULL, /* hash */
+ NULL, /* call */
+ NULL, /* str */
+ NULL, /* getattro */
+ NULL, /* setattro */
+ NULL, /* as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
+ NULL, /* doc */
+ (traverseproc)ssl_Connection_traverse,
+ (inquiry)ssl_Connection_clear,
+};
+
+
+/*
+ * Initiailze the Connection part of the SSL sub module
+ *
+ * Arguments: dict - Dictionary of the OpenSSL.SSL module
+ * Returns: 1 for success, 0 otherwise
+ */
+int
+init_ssl_connection(PyObject *dict)
+{
+ ssl_Connection_Type.ob_type = &PyType_Type;
+ Py_INCREF(&ssl_Connection_Type);
+ if (PyDict_SetItemString(dict, "ConnectionType", (PyObject *)&ssl_Connection_Type) != 0)
+ return 0;
+
+ return 1;
+}
+
diff --git a/src/ssl/connection.h b/src/ssl/connection.h
new file mode 100644
index 0000000..dedb73e
--- /dev/null
+++ b/src/ssl/connection.h
@@ -0,0 +1,52 @@
+/*
+ * connection.h
+ *
+ * Copyright (C) AB Strakt 2001, All rights reserved
+ *
+ * Export SSL Connection data structures and functions.
+ * See the file RATIONALE for a short explanation of why this module was written.
+ *
+ * Reviewed 2001-07-23
+ *
+ * @(#) $Id: connection.h,v 1.11 2002/09/04 22:24:59 iko Exp $
+ */
+#ifndef PyOpenSSL_SSL_CONNECTION_H_
+#define PyOpenSSL_SSL_CONNECTION_H_
+
+#include <Python.h>
+#include <openssl/ssl.h>
+
+/* shamelessly stolen from socketmodule.c */
+#ifdef MS_WINDOWS
+# include <winsock.h>
+typedef SOCKET SOCKET_T;
+# ifdef MS_WIN64
+# define SIZEOF_SOCKET_T 8
+# else
+# define SIZEOF_SOCKET_T 4
+# endif
+#else
+typedef int SOCKET_T;
+# define SIZEOF_SOCKET_T SIZEOF_INT
+#endif
+
+
+extern int init_ssl_connection (PyObject *);
+
+extern PyTypeObject ssl_Connection_Type;
+
+#define ssl_Connection_Check(v) ((v)->ob_type == &ssl_Connection_Type)
+
+typedef struct {
+ PyObject_HEAD
+ SSL *ssl;
+ ssl_ContextObj *context;
+ PyObject *socket;
+ PyThreadState *tstate;
+ PyObject *app_data;
+} ssl_ConnectionObj;
+
+
+
+#endif
+
diff --git a/src/ssl/context.c b/src/ssl/context.c
new file mode 100644
index 0000000..93f1c83
--- /dev/null
+++ b/src/ssl/context.c
@@ -0,0 +1,1074 @@
+/*
+ * context.c
+ *
+ * Copyright (C) AB Strakt 2001, All rights reserved
+ *
+ * SSL Context objects and their methods.
+ * See the file RATIONALE for a short explanation of why this module was written.
+ *
+ * Reviewed 2001-07-23
+ */
+#include <Python.h>
+#define SSL_MODULE
+#include "ssl.h"
+
+static char *CVSid = "@(#) $Id: context.c,v 1.17 2004/08/06 10:21:56 martin Exp $";
+
+/*
+ * CALLBACKS
+ *
+ * Callbacks work like this: We provide a "global" callback in C which
+ * transforms the arguments into a Python argument tuple and calls the
+ * corresponding Python callback, and then parsing the return value back into
+ * things the C function can return.
+ *
+ * Three caveats:
+ * + How do we find the Context object where the Python callbacks are stored?
+ * + What about multithreading and execution frames?
+ * + What about Python callbacks that raise exceptions?
+ *
+ * The solution to the first issue is trivial if the callback provides
+ * "userdata" functionality. Since the only callbacks that don't provide
+ * userdata do provide a pointer to an SSL structure, we can associate an SSL
+ * object and a Connection one-to-one via the SSL_set/get_app_data()
+ * functions.
+ *
+ * The solution to the other issue is to rewrite the Py_BEGIN_ALLOW_THREADS
+ * macro allowing it (or rather a new macro) to specify where to save the
+ * thread state (in our case, as a member of the Connection/Context object) so
+ * we can retrieve it again before calling the Python callback.
+ */
+
+/*
+ * Globally defined passphrase callback.
+ *
+ * Arguments: buf - Buffer to store the returned passphrase in
+ * maxlen - Maximum length of the passphrase
+ * verify - If true, the passphrase callback should ask for a
+ * password twice and verify they're equal. If false, only
+ * ask once.
+ * arg - User data, always a Context object
+ * Returns: The length of the password if successful, 0 otherwise
+ */
+static int
+global_passphrase_callback(char *buf, int maxlen, int verify, void *arg)
+{
+ int len;
+ char *str;
+ PyObject *argv, *ret = NULL;
+ ssl_ContextObj *ctx = (ssl_ContextObj *)arg;
+
+ /* The Python callback is called with a (maxlen,verify,userdata) tuple */
+ argv = Py_BuildValue("(iiO)", maxlen, verify, ctx->passphrase_userdata);
+ if (ctx->tstate != NULL)
+ {
+ /* We need to get back our thread state before calling the callback */
+ MY_END_ALLOW_THREADS(ctx->tstate);
+ ret = PyEval_CallObject(ctx->passphrase_callback, argv);
+ MY_BEGIN_ALLOW_THREADS(ctx->tstate);
+ }
+ else
+ {
+ ret = PyEval_CallObject(ctx->passphrase_callback, argv);
+ }
+ Py_DECREF(argv);
+
+ if (ret == NULL)
+ return 0;
+
+ if (!PyObject_IsTrue(ret))
+ {
+ Py_DECREF(ret);
+ return 0;
+ }
+
+ if (!PyString_Check(ret))
+ {
+ Py_DECREF(ret);
+ return 0;
+ }
+
+ len = PyString_Size(ret);
+ if (len > maxlen)
+ len = maxlen;
+
+ str = PyString_AsString(ret);
+ strncpy(buf, str, len);
+ Py_XDECREF(ret);
+
+ return len;
+}
+
+/*
+ * Globally defined verify callback
+ *
+ * Arguments: ok - True everything is OK "so far", false otherwise
+ * x509_ctx - Contains the certificate being checked, the current
+ * error number and depth, and the Connection we're
+ * dealing with
+ * Returns: True if everything is okay, false otherwise
+ */
+static int
+global_verify_callback(int ok, X509_STORE_CTX *x509_ctx)
+{
+ PyObject *argv, *ret;
+ SSL *ssl;
+ ssl_ConnectionObj *conn;
+ crypto_X509Obj *cert;
+ int errnum, errdepth, c_ret;
+
+ cert = crypto_X509_New(X509_STORE_CTX_get_current_cert(x509_ctx), 0);
+ errnum = X509_STORE_CTX_get_error(x509_ctx);
+ errdepth = X509_STORE_CTX_get_error_depth(x509_ctx);
+ ssl = (SSL *)X509_STORE_CTX_get_app_data(x509_ctx);
+ conn = (ssl_ConnectionObj *)SSL_get_app_data(ssl);
+
+ argv = Py_BuildValue("(OOiii)", (PyObject *)conn, (PyObject *)cert,
+ errnum, errdepth, ok);
+ Py_DECREF(cert);
+ if (conn->tstate != NULL)
+ {
+ /* We need to get back our thread state before calling the callback */
+ MY_END_ALLOW_THREADS(conn->tstate);
+ ret = PyEval_CallObject(conn->context->verify_callback, argv);
+ MY_BEGIN_ALLOW_THREADS(conn->tstate);
+ }
+ else
+ {
+ ret = PyEval_CallObject(conn->context->verify_callback, argv);
+ }
+ Py_DECREF(argv);
+
+ if (ret == NULL)
+ return 0;
+
+ if (PyObject_IsTrue(ret))
+ {
+ X509_STORE_CTX_set_error(x509_ctx, X509_V_OK);
+ c_ret = 1;
+ }
+ else
+ c_ret = 0;
+
+ Py_DECREF(ret);
+
+ return c_ret;
+}
+
+/*
+ * Globally defined info callback
+ *
+ * Arguments: ssl - The Connection
+ * where - The part of the SSL code that called us
+ * _ret - The return code of the SSL function that called us
+ * Returns: None
+ */
+static void
+global_info_callback(SSL *ssl, int where, int _ret)
+{
+ ssl_ConnectionObj *conn = (ssl_ConnectionObj *)SSL_get_app_data(ssl);
+ PyObject *argv, *ret;
+
+ argv = Py_BuildValue("(Oii)", (PyObject *)conn, where, _ret);
+ if (conn->tstate != NULL)
+ {
+ /* We need to get back our thread state before calling the callback */
+ MY_END_ALLOW_THREADS(conn->tstate);
+ ret = PyEval_CallObject(conn->context->info_callback, argv);
+ if (ret == NULL)
+ PyErr_Clear();
+ else
+ Py_DECREF(ret);
+ MY_BEGIN_ALLOW_THREADS(conn->tstate);
+ }
+ else
+ {
+ ret = PyEval_CallObject(conn->context->info_callback, argv);
+ if (ret == NULL)
+ PyErr_Clear();
+ else
+ Py_DECREF(ret);
+ }
+ Py_DECREF(argv);
+
+ return;
+}
+
+
+
+
+static char ssl_Context_load_verify_locations_doc[] = "\n\
+Let SSL know where we can find trusted certificates for the certificate\n\
+chain\n\
+\n\
+Arguments: self - The Context object\n\
+ args - The Python argument tuple, should be:\n\
+ cafile - Which file we can find the certificates\n\
+Returns: None\n\
+";
+static PyObject *
+ssl_Context_load_verify_locations(ssl_ContextObj *self, PyObject *args)
+{
+ char *cafile;
+
+ if (!PyArg_ParseTuple(args, "s:load_verify_locations", &cafile))
+ return NULL;
+
+ if (!SSL_CTX_load_verify_locations(self->ctx, cafile, NULL))
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+ else
+ {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+}
+
+static char ssl_Context_set_passwd_cb_doc[] = "\n\
+Set the passphrase callback\n\
+\n\
+Arguments: self - The Context object\n\
+ args - The Python argument tuple, should be:\n\
+ callback - The Python callback to use\n\
+ userdata - (optional) A Python object which will be given as\n\
+ argument to the callback\n\
+Returns: None\n\
+";
+static PyObject *
+ssl_Context_set_passwd_cb(ssl_ContextObj *self, PyObject *args)
+{
+ PyObject *callback = NULL, *userdata = Py_None;
+
+ if (!PyArg_ParseTuple(args, "O|O:set_passwd_cb", &callback, &userdata))
+ return NULL;
+
+ if (!PyCallable_Check(callback))
+ {
+ PyErr_SetString(PyExc_TypeError, "expected PyCallable");
+ return NULL;
+ }
+
+ Py_DECREF(self->passphrase_callback);
+ Py_INCREF(callback);
+ self->passphrase_callback = callback;
+ SSL_CTX_set_default_passwd_cb(self->ctx, global_passphrase_callback);
+
+ Py_DECREF(self->passphrase_userdata);
+ Py_INCREF(userdata);
+ self->passphrase_userdata = userdata;
+ SSL_CTX_set_default_passwd_cb_userdata(self->ctx, (void *)self);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char ssl_Context_use_certificate_chain_file_doc[] = "\n\
+Load a certificate chain from a file\n\
+\n\
+Arguments: self - The Context object\n\
+ args - The Python argument tuple, should be:\n\
+ certfile - The name of the certificate chain file\n\
+Returns: None\n\
+";
+static PyObject *
+ssl_Context_use_certificate_chain_file(ssl_ContextObj *self, PyObject *args)
+{
+ char *certfile;
+
+ if (!PyArg_ParseTuple(args, "s:use_certificate_chain_file", &certfile))
+ return NULL;
+
+ if (!SSL_CTX_use_certificate_chain_file(self->ctx, certfile))
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+ else
+ {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+}
+
+
+static char ssl_Context_use_certificate_file_doc[] = "\n\
+Load a certificate from a file\n\
+\n\
+Arguments: self - The Context object\n\
+ args - The Python argument tuple, should be:\n\
+ certfile - The name of the certificate file\n\
+ filetype - (optional) The encoding of the file, default is PEM\n\
+Returns: None\n\
+";
+static PyObject *
+ssl_Context_use_certificate_file(ssl_ContextObj *self, PyObject *args)
+{
+ char *certfile;
+ int filetype = SSL_FILETYPE_PEM;
+
+ if (!PyArg_ParseTuple(args, "s|i:use_certificate_file", &certfile, &filetype))
+ return NULL;
+
+ if (!SSL_CTX_use_certificate_file(self->ctx, certfile, filetype))
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+ else
+ {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+}
+
+static char ssl_Context_use_certificate_doc[] = "\n\
+Load a certificate from a X509 object\n\
+\n\
+Arguments: self - The Context object\n\
+ args - The Python argument tuple, should be:\n\
+ cert - The X509 object\n\
+Returns: None\n\
+";
+static PyObject *
+ssl_Context_use_certificate(ssl_ContextObj *self, PyObject *args)
+{
+ static PyTypeObject *crypto_X509_type = NULL;
+ crypto_X509Obj *cert;
+
+ /* We need to check that cert really is an X509 object before
+ we deal with it. The problem is we can't just quickly verify
+ the type (since that comes from another module). This should
+ do the trick (reasonably well at least): Once we have one
+ verified object, we use it's type object for future
+ comparisons. */
+
+ if (!crypto_X509_type)
+ {
+ if (!PyArg_ParseTuple(args, "O:use_certificate", &cert))
+ return NULL;
+
+ if (strcmp(cert->ob_type->tp_name, "X509") != 0 ||
+ cert->ob_type->tp_basicsize != sizeof(crypto_X509Obj))
+ {
+ PyErr_SetString(PyExc_TypeError, "Expected an X509 object");
+ return NULL;
+ }
+
+ crypto_X509_type = cert->ob_type;
+ }
+ else
+ if (!PyArg_ParseTuple(args, "O!:use_certificate", crypto_X509_type,
+ &cert))
+ return NULL;
+
+ if (!SSL_CTX_use_certificate(self->ctx, cert->x509))
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+ else
+ {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+}
+
+static char ssl_Context_use_privatekey_file_doc[] = "\n\
+Load a private key from a file\n\
+\n\
+Arguments: self - The Context object\n\
+ args - The Python argument tuple, should be:\n\
+ keyfile - The name of the key file\n\
+ filetype - (optional) The encoding of the file, default is PEM\n\
+Returns: None\n\
+";
+static PyObject *
+ssl_Context_use_privatekey_file(ssl_ContextObj *self, PyObject *args)
+{
+ char *keyfile;
+ int filetype = SSL_FILETYPE_PEM, ret;
+
+ if (!PyArg_ParseTuple(args, "s|i:use_privatekey_file", &keyfile, &filetype))
+ return NULL;
+
+ MY_BEGIN_ALLOW_THREADS(self->tstate);
+ ret = SSL_CTX_use_PrivateKey_file(self->ctx, keyfile, filetype);
+ MY_END_ALLOW_THREADS(self->tstate);
+
+ if (PyErr_Occurred())
+ {
+ flush_error_queue();
+ return NULL;
+ }
+
+ if (!ret)
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+ else
+ {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+}
+
+static char ssl_Context_use_privatekey_doc[] = "\n\
+Load a private key from a PKey object\n\
+\n\
+Arguments: self - The Context object\n\
+ args - The Python argument tuple, should be:\n\
+ pkey - The PKey object\n\
+Returns: None\n\
+";
+static PyObject *
+ssl_Context_use_privatekey(ssl_ContextObj *self, PyObject *args)
+{
+ static PyTypeObject *crypto_PKey_type = NULL;
+ crypto_PKeyObj *pkey;
+
+ /* We need to check that cert really is a PKey object before
+ we deal with it. The problem is we can't just quickly verify
+ the type (since that comes from another module). This should
+ do the trick (reasonably well at least): Once we have one
+ verified object, we use it's type object for future
+ comparisons. */
+
+ if (!crypto_PKey_type)
+ {
+ if (!PyArg_ParseTuple(args, "O:use_privatekey", &pkey))
+ return NULL;
+
+ if (strcmp(pkey->ob_type->tp_name, "PKey") != 0 ||
+ pkey->ob_type->tp_basicsize != sizeof(crypto_PKeyObj))
+ {
+ PyErr_SetString(PyExc_TypeError, "Expected a PKey object");
+ return NULL;
+ }
+
+ crypto_PKey_type = pkey->ob_type;
+ }
+ else
+ if (!PyArg_ParseTuple(args, "O!:use_privatekey", crypto_PKey_type, &pkey))
+ return NULL;
+
+ if (!SSL_CTX_use_PrivateKey(self->ctx, pkey->pkey))
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+ else
+ {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+}
+
+static char ssl_Context_check_privatekey_doc[] = "\n\
+Check that the private key and certificate match up\n\
+\n\
+Arguments: self - The Context object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: None (raises an exception if something's wrong)\n\
+";
+static PyObject *
+ssl_Context_check_privatekey(ssl_ContextObj *self, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":check_privatekey"))
+ return NULL;
+
+ if (!SSL_CTX_check_private_key(self->ctx))
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+ else
+ {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+}
+
+static char ssl_Context_load_client_ca_doc[] = "\n\
+Load the trusted certificates that will be sent to the client (basically\n\
+telling the client \"These are the guys I trust\")\n\
+\n\
+Arguments: self - The Context object\n\
+ args - The Python argument tuple, should be:\n\
+ cafile - The name of the certificates file\n\
+Returns: None\n\
+";
+static PyObject *
+ssl_Context_load_client_ca(ssl_ContextObj *self, PyObject *args)
+{
+ char *cafile;
+
+ if (!PyArg_ParseTuple(args, "s:load_client_ca", &cafile))
+ return NULL;
+
+ SSL_CTX_set_client_CA_list(self->ctx, SSL_load_client_CA_file(cafile));
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char ssl_Context_set_session_id_doc[] = "\n\
+Set the session identifier, this is needed if you want to do session\n\
+resumption (which, ironically, isn't implemented yet)\n\
+\n\
+Arguments: self - The Context object\n\
+ args - The Python argument tuple, should be:\n\
+ buf - A Python object that can be safely converted to a string\n\
+Returns: None\n\
+";
+static PyObject *
+ssl_Context_set_session_id(ssl_ContextObj *self, PyObject *args)
+{
+ char *buf;
+ int len;
+
+ if (!PyArg_ParseTuple(args, "s#:set_session_id", &buf, &len))
+ return NULL;
+
+ if (!SSL_CTX_set_session_id_context(self->ctx, buf, len))
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+ else
+ {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+}
+
+static char ssl_Context_set_verify_doc[] = "\n\
+Set the verify mode and verify callback\n\
+\n\
+Arguments: self - The Context object\n\
+ args - The Python argument tuple, should be:\n\
+ mode - The verify mode, this is either SSL_VERIFY_NONE or\n\
+ SSL_VERIFY_PEER combined with possible other flags\n\
+ callback - The Python callback to use\n\
+Returns: None\n\
+";
+static PyObject *
+ssl_Context_set_verify(ssl_ContextObj *self, PyObject *args)
+{
+ int mode;
+ PyObject *callback = NULL;
+
+ if (!PyArg_ParseTuple(args, "iO:set_verify", &mode, &callback))
+ return NULL;
+
+ if (!PyCallable_Check(callback))
+ {
+ PyErr_SetString(PyExc_TypeError, "expected PyCallable");
+ return NULL;
+ }
+
+ Py_DECREF(self->verify_callback);
+ Py_INCREF(callback);
+ self->verify_callback = callback;
+ SSL_CTX_set_verify(self->ctx, mode, global_verify_callback);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char ssl_Context_set_verify_depth_doc[] = "\n\
+Set the verify depth\n\
+\n\
+Arguments: self - The Context object\n\
+ args - The Python argument tuple, should be:\n\
+ depth - An integer specifying the verify depth\n\
+Returns: None\n\
+";
+static PyObject *
+ssl_Context_set_verify_depth(ssl_ContextObj *self, PyObject *args)
+{
+ int depth;
+
+ if (!PyArg_ParseTuple(args, "i:set_verify_depth", &depth))
+ return NULL;
+
+ SSL_CTX_set_verify_depth(self->ctx, depth);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char ssl_Context_get_verify_mode_doc[] = "\n\
+Get the verify mode\n\
+\n\
+Arguments: self - The Context object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: The verify mode\n\
+";
+static PyObject *
+ssl_Context_get_verify_mode(ssl_ContextObj *self, PyObject *args)
+{
+ int mode;
+
+ if (!PyArg_ParseTuple(args, ":get_verify_mode"))
+ return NULL;
+
+ mode = SSL_CTX_get_verify_mode(self->ctx);
+ return PyInt_FromLong((long)mode);
+}
+
+static char ssl_Context_get_verify_depth_doc[] = "\n\
+Get the verify depth\n\
+\n\
+Arguments: self - The Context object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: The verify depth\n\
+";
+static PyObject *
+ssl_Context_get_verify_depth(ssl_ContextObj *self, PyObject *args)
+{
+ int depth;
+
+ if (!PyArg_ParseTuple(args, ":get_verify_depth"))
+ return NULL;
+
+ depth = SSL_CTX_get_verify_depth(self->ctx);
+ return PyInt_FromLong((long)depth);
+}
+
+static char ssl_Context_load_tmp_dh_doc[] = "\n\
+Load parameters for Ephemeral Diffie-Hellman\n\
+\n\
+Arguments: self - The Context object\n\
+ args - The Python argument tuple, should be:\n\
+ dhfile - The file to load EDH parameters from\n\
+Returns: None\n\
+";
+static PyObject *
+ssl_Context_load_tmp_dh(ssl_ContextObj *self, PyObject *args)
+{
+ char *dhfile;
+ BIO *bio;
+ DH *dh;
+
+ if (!PyArg_ParseTuple(args, "s:load_tmp_dh", &dhfile))
+ return NULL;
+
+ bio = BIO_new_file(dhfile, "r");
+ if (bio == NULL)
+ return PyErr_NoMemory();
+
+ dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
+ SSL_CTX_set_tmp_dh(self->ctx, dh);
+ DH_free(dh);
+ BIO_free(bio);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char ssl_Context_set_cipher_list_doc[] = "\n\
+Change the cipher list\n\
+\n\
+Arguments: self - The Context object\n\
+ args - The Python argument tuple, should be:\n\
+ cipher_list - A cipher list, see ciphers(1)\n\
+Returns: None\n\
+";
+static PyObject *
+ssl_Context_set_cipher_list(ssl_ContextObj *self, PyObject *args)
+{
+ char *cipher_list;
+
+ if (!PyArg_ParseTuple(args, "s:set_cipher_list", &cipher_list))
+ return NULL;
+
+ if (!SSL_CTX_set_cipher_list(self->ctx, cipher_list))
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+ else
+ {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+}
+
+static char ssl_Context_set_timeout_doc[] = "\n\
+Set session timeout\n\
+\n\
+Arguments: self - The Context object\n\
+ args - The Python argument tuple, should be:\n\
+ t - The timeout in seconds\n\
+Returns: The previous session timeout\n\
+";
+static PyObject *
+ssl_Context_set_timeout(ssl_ContextObj *self, PyObject *args)
+{
+ long t, ret;
+
+ if (!PyArg_ParseTuple(args, "l:set_timeout", &t))
+ return NULL;
+
+ ret = SSL_CTX_set_timeout(self->ctx, t);
+ return PyLong_FromLong(ret);
+}
+
+static char ssl_Context_get_timeout_doc[] = "\n\
+Get the session timeout\n\
+\n\
+Arguments: self - The Context object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: The session timeout\n\
+";
+static PyObject *
+ssl_Context_get_timeout(ssl_ContextObj *self, PyObject *args)
+{
+ long ret;
+
+ if (!PyArg_ParseTuple(args, ":get_timeout"))
+ return NULL;
+
+ ret = SSL_CTX_get_timeout(self->ctx);
+ return PyLong_FromLong(ret);
+}
+
+static char ssl_Context_set_info_callback_doc[] = "\n\
+Set the info callback\n\
+\n\
+Arguments: self - The Context object\n\
+ args - The Python argument tuple, should be:\n\
+ callback - The Python callback to use\n\
+Returns: None\n\
+";
+static PyObject *
+ssl_Context_set_info_callback(ssl_ContextObj *self, PyObject *args)
+{
+ PyObject *callback;
+
+ if (!PyArg_ParseTuple(args, "O:set_info_callback", &callback))
+ return NULL;
+
+ if (!PyCallable_Check(callback))
+ {
+ PyErr_SetString(PyExc_TypeError, "expected PyCallable");
+ return NULL;
+ }
+
+ Py_DECREF(self->info_callback);
+ Py_INCREF(callback);
+ self->info_callback = callback;
+ SSL_CTX_set_info_callback(self->ctx, global_info_callback);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char ssl_Context_get_app_data_doc[] = "\n\
+Get the application data (supplied via set_app_data())\n\
+\n\
+Arguments: self - The Context object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: The application data\n\
+";
+static PyObject *
+ssl_Context_get_app_data(ssl_ContextObj *self, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":get_app_data"))
+ return NULL;
+
+ Py_INCREF(self->app_data);
+ return self->app_data;
+}
+
+static char ssl_Context_set_app_data_doc[] = "\n\
+Set the application data (will be returned from get_app_data())\n\
+\n\
+Arguments: self - The Context object\n\
+ args - The Python argument tuple, should be:\n\
+ data - Any Python object\n\
+Returns: None\n\
+";
+static PyObject *
+ssl_Context_set_app_data(ssl_ContextObj *self, PyObject *args)
+{
+ PyObject *data;
+
+ if (!PyArg_ParseTuple(args, "O:set_app_data", &data))
+ return NULL;
+
+ Py_DECREF(self->app_data);
+ Py_INCREF(data);
+ self->app_data = data;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char ssl_Context_get_cert_store_doc[] = "\n\
+Get the certificate store for the context\n\
+\n\
+Arguments: self - The Context object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: A X509Store object\n\
+";
+static PyObject *
+ssl_Context_get_cert_store(ssl_ContextObj *self, PyObject *args)
+{
+ X509_STORE *store;
+
+ if (!PyArg_ParseTuple(args, ":get_cert_store"))
+ return NULL;
+
+ if ((store = SSL_CTX_get_cert_store(self->ctx)) == NULL)
+ {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ else
+ {
+ return (PyObject *)crypto_X509Store_New(store, 0);
+ }
+}
+
+static char ssl_Context_set_options_doc[] = "\n\
+Add options. Options set before are not cleared!\n\
+\n\
+Arguments: self - The Context object\n\
+ args - The Python argument tuple, should be:\n\
+ options - The options to add.\n\
+Returns: The new option bitmask.\n\
+";
+static PyObject *
+ssl_Context_set_options(ssl_ContextObj *self, PyObject *args)
+{
+ long options;
+
+ if (!PyArg_ParseTuple(args, "l:set_options", &options))
+ return NULL;
+
+ return PyInt_FromLong(SSL_CTX_set_options(self->ctx, options));
+}
+
+
+/*
+ * Member methods in the Context object
+ * ADD_METHOD(name) expands to a correct PyMethodDef declaration
+ * { 'name', (PyCFunction)ssl_Context_name, METH_VARARGS }
+ * for convenience
+ * ADD_ALIAS(name,real) creates an "alias" of the ssl_Context_real
+ * function with the name 'name'
+ */
+#define ADD_METHOD(name) { #name, (PyCFunction)ssl_Context_##name, METH_VARARGS, ssl_Context_##name##_doc }
+static PyMethodDef ssl_Context_methods[] = {
+ ADD_METHOD(load_verify_locations),
+ ADD_METHOD(set_passwd_cb),
+ ADD_METHOD(use_certificate_chain_file),
+ ADD_METHOD(use_certificate_file),
+ ADD_METHOD(use_certificate),
+ ADD_METHOD(use_privatekey_file),
+ ADD_METHOD(use_privatekey),
+ ADD_METHOD(check_privatekey),
+ ADD_METHOD(load_client_ca),
+ ADD_METHOD(set_session_id),
+ ADD_METHOD(set_verify),
+ ADD_METHOD(set_verify_depth),
+ ADD_METHOD(get_verify_mode),
+ ADD_METHOD(get_verify_depth),
+ ADD_METHOD(load_tmp_dh),
+ ADD_METHOD(set_cipher_list),
+ ADD_METHOD(set_timeout),
+ ADD_METHOD(get_timeout),
+ ADD_METHOD(set_info_callback),
+ ADD_METHOD(get_app_data),
+ ADD_METHOD(set_app_data),
+ ADD_METHOD(get_cert_store),
+ ADD_METHOD(set_options),
+ { NULL, NULL }
+};
+#undef ADD_METHOD
+
+
+/* Constructor, takes an int specifying which method to use */
+/*
+ * Constructor for Context objects
+ *
+ * Arguments: i_method - The SSL method to use, one of the SSLv2_METHOD,
+ * SSLv3_METHOD, SSLv23_METHOD and TLSv1_METHOD
+ * constants.
+ * Returns: The newly created Context object
+ */
+ssl_ContextObj *
+ssl_Context_New(int i_method)
+{
+ SSL_METHOD *method;
+ ssl_ContextObj *self;
+
+ switch (i_method)
+ {
+ /* Too bad TLSv1 servers can't accept SSLv3 clients */
+ case ssl_SSLv2_METHOD: method = SSLv2_method(); break;
+ case ssl_SSLv23_METHOD: method = SSLv23_method(); break;
+ case ssl_SSLv3_METHOD: method = SSLv3_method(); break;
+ case ssl_TLSv1_METHOD: method = TLSv1_method(); break;
+ default:
+ PyErr_SetString(PyExc_ValueError, "No such protocol");
+ return NULL;
+ }
+
+ self = PyObject_GC_New(ssl_ContextObj, &ssl_Context_Type);
+ if (self == NULL)
+ return (ssl_ContextObj *)PyErr_NoMemory();
+
+ self->ctx = SSL_CTX_new(method);
+ Py_INCREF(Py_None);
+ self->passphrase_callback = Py_None;
+ Py_INCREF(Py_None);
+ self->verify_callback = Py_None;
+ Py_INCREF(Py_None);
+ self->info_callback = Py_None;
+
+ Py_INCREF(Py_None);
+ self->passphrase_userdata = Py_None;
+
+ Py_INCREF(Py_None);
+ self->app_data = Py_None;
+
+ /* Some initialization that's required to operate smoothly in Python */
+ SSL_CTX_set_app_data(self->ctx, self);
+ SSL_CTX_set_mode(self->ctx, SSL_MODE_ENABLE_PARTIAL_WRITE |
+ SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER |
+ SSL_MODE_AUTO_RETRY);
+
+ self->tstate = NULL;
+ PyObject_GC_Track((PyObject *)self);
+
+ return self;
+}
+
+/*
+ * Find attribute
+ *
+ * Arguments: self - The Context object
+ * name - The attribute name
+ * Returns: A Python object for the attribute, or NULL if something went
+ * wrong
+ */
+static PyObject *
+ssl_Context_getattr(ssl_ContextObj *self, char *name)
+{
+ return Py_FindMethod(ssl_Context_methods, (PyObject *)self, name);
+}
+
+/*
+ * Call the visitproc on all contained objects.
+ *
+ * Arguments: self - The Context object
+ * visit - Function to call
+ * arg - Extra argument to visit
+ * Returns: 0 if all goes well, otherwise the return code from the first
+ * call that gave non-zero result.
+ */
+static int
+ssl_Context_traverse(ssl_ContextObj *self, visitproc visit, void *arg)
+{
+ int ret = 0;
+
+ if (ret == 0 && self->passphrase_callback != NULL)
+ ret = visit((PyObject *)self->passphrase_callback, arg);
+ if (ret == 0 && self->passphrase_userdata != NULL)
+ ret = visit((PyObject *)self->passphrase_userdata, arg);
+ if (ret == 0 && self->verify_callback != NULL)
+ ret = visit((PyObject *)self->verify_callback, arg);
+ if (ret == 0 && self->info_callback != NULL)
+ ret = visit((PyObject *)self->info_callback, arg);
+ if (ret == 0 && self->app_data != NULL)
+ ret = visit(self->app_data, arg);
+ return ret;
+}
+
+/*
+ * Decref all contained objects and zero the pointers.
+ *
+ * Arguments: self - The Context object
+ * Returns: Always 0.
+ */
+static int
+ssl_Context_clear(ssl_ContextObj *self)
+{
+ Py_XDECREF(self->passphrase_callback);
+ self->passphrase_callback = NULL;
+ Py_XDECREF(self->passphrase_userdata);
+ self->passphrase_userdata = NULL;
+ Py_XDECREF(self->verify_callback);
+ self->verify_callback = NULL;
+ Py_XDECREF(self->info_callback);
+ self->info_callback = NULL;
+ Py_XDECREF(self->app_data);
+ self->app_data = NULL;
+ return 0;
+}
+
+/*
+ * Deallocate the memory used by the Context object
+ *
+ * Arguments: self - The Context object
+ * Returns: None
+ */
+static void
+ssl_Context_dealloc(ssl_ContextObj *self)
+{
+ PyObject_GC_UnTrack((PyObject *)self);
+ SSL_CTX_free(self->ctx);
+ ssl_Context_clear(self);
+ PyObject_GC_Del(self);
+}
+
+
+PyTypeObject ssl_Context_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "Context",
+ sizeof(ssl_ContextObj),
+ 0,
+ (destructor)ssl_Context_dealloc,
+ NULL, /* print */
+ (getattrfunc)ssl_Context_getattr,
+ NULL, /* setattr */
+ NULL, /* compare */
+ NULL, /* repr */
+ NULL, /* as_number */
+ NULL, /* as_sequence */
+ NULL, /* as_mapping */
+ NULL, /* hash */
+ NULL, /* call */
+ NULL, /* str */
+ NULL, /* getattro */
+ NULL, /* setattro */
+ NULL, /* as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
+ NULL, /* doc */
+ (traverseproc)ssl_Context_traverse,
+ (inquiry)ssl_Context_clear,
+};
+
+
+/*
+ * Initialize the Context part of the SSL sub module
+ *
+ * Arguments: dict - Dictionary of the OpenSSL.SSL module
+ * Returns: 1 for success, 0 otherwise
+ */
+int
+init_ssl_context(PyObject *dict)
+{
+ ssl_Context_Type.ob_type = &PyType_Type;
+ Py_INCREF(&ssl_Context_Type);
+ if (PyDict_SetItemString(dict, "ContextType", (PyObject *)&ssl_Context_Type) != 0)
+ return 0;
+
+ return 1;
+}
+
diff --git a/src/ssl/context.h b/src/ssl/context.h
new file mode 100644
index 0000000..b52acf1
--- /dev/null
+++ b/src/ssl/context.h
@@ -0,0 +1,42 @@
+/*
+ * context.h
+ *
+ * Copyright (C) AB Strakt 2001, All rights reserved
+ *
+ * Export SSL Context object data structures and functions.
+ * See the file RATIONALE for a short explanation of why this module was written.
+ *
+ * Reviewed 2001-07-23
+ *
+ * @(#) $Id: context.h,v 1.6 2002/09/04 22:24:59 iko Exp $
+ */
+#ifndef PyOpenSSL_SSL_CONTEXT_H_
+#define PyOpenSSL_SSL_CONTEXT_H_
+
+#include <Python.h>
+#include <openssl/ssl.h>
+
+extern int init_ssl_context (PyObject *);
+
+extern PyTypeObject ssl_Context_Type;
+
+#define ssl_Context_Check(v) ((v)->ob_type == &ssl_Context_Type)
+
+typedef struct {
+ PyObject_HEAD
+ SSL_CTX *ctx;
+ PyObject *passphrase_callback,
+ *passphrase_userdata,
+ *verify_callback,
+ *info_callback,
+ *app_data;
+ PyThreadState *tstate;
+} ssl_ContextObj;
+
+#define ssl_SSLv2_METHOD (1)
+#define ssl_SSLv3_METHOD (2)
+#define ssl_SSLv23_METHOD (3)
+#define ssl_TLSv1_METHOD (4)
+
+
+#endif
diff --git a/src/ssl/ssl.c b/src/ssl/ssl.c
new file mode 100644
index 0000000..9d3abd2
--- /dev/null
+++ b/src/ssl/ssl.c
@@ -0,0 +1,191 @@
+/*
+ * ssl.c
+ *
+ * Copyright (C) AB Strakt 2001, All rights reserved
+ *
+ * Main file of the SSL sub module.
+ * See the file RATIONALE for a short explanation of why this module was written.
+ *
+ * Reviewed 2001-07-23
+ */
+#include <Python.h>
+#define SSL_MODULE
+#include "ssl.h"
+
+static char ssl_doc[] = "\n\
+Main file of the SSL sub module.\n\
+See the file RATIONALE for a short explanation of hy this module was written.\n\
+";
+
+static char *CVSid = "@(#) $Id: ssl.c,v 1.12 2004/08/10 21:42:51 martin Exp $";
+
+void **crypto_API;
+
+/* Exceptions defined by the SSL submodule */
+PyObject *ssl_Error, /* Base class */
+ *ssl_ZeroReturnError, /* Used with SSL_get_error */
+ *ssl_WantReadError, /* ... */
+ *ssl_WantWriteError, /* ... */
+ *ssl_WantX509LookupError, /* ... */
+ *ssl_SysCallError; /* Uses (errno,errstr) */
+
+static char ssl_Context_doc[] = "\n\
+The factory function inserted in the module dictionary to create Context\n\
+objects\n\
+\n\
+Arguments: spam - Always NULL\n\
+ args - The Python argument tuple, should be:\n\
+ method - The SSL method to use\n\
+Returns: The Context object\n\
+";
+
+static PyObject *
+ssl_Context(PyObject *spam, PyObject *args)
+{
+ int method;
+
+ if (!PyArg_ParseTuple(args, "i:Context", &method))
+ return NULL;
+
+ return (PyObject *)ssl_Context_New(method);
+}
+
+static char ssl_Connection_doc[] = "\n\
+The factory function inserted in the module dictionary to create Connection\n\
+objects\n\
+\n\
+Arguments: spam - Always NULL\n\
+ args - The Python argument tuple, should be:\n\
+ ctx - An SSL Context to use for this connection\n\
+ sock - The socket to use for transport layer\n\
+Returns: The Connection object\n\
+";
+
+static PyObject *
+ssl_Connection(PyObject *spam, PyObject *args)
+{
+ ssl_ContextObj *ctx;
+ PyObject *sock;
+
+ if (!PyArg_ParseTuple(args, "O!O:Connection", &ssl_Context_Type, &ctx, &sock))
+ return NULL;
+
+ return (PyObject *)ssl_Connection_New(ctx, sock);
+}
+
+
+/* Methods in the OpenSSL.SSL module */
+static PyMethodDef ssl_methods[] = {
+ { "Context", ssl_Context, METH_VARARGS, ssl_Context_doc },
+ { "Connection", ssl_Connection, METH_VARARGS, ssl_Connection_doc },
+ { NULL, NULL }
+};
+
+/*
+ * Initialize SSL sub module
+ *
+ * Arguments: None
+ * Returns: None
+ */
+void
+initSSL(void)
+{
+ static void *ssl_API[ssl_API_pointers];
+ PyObject *ssl_api_object;
+ PyObject *module, *dict;
+
+ SSL_library_init();
+ ERR_load_SSL_strings();
+
+ import_crypto();
+
+ if ((module = Py_InitModule3("SSL", ssl_methods, ssl_doc)) == NULL)
+ return;
+
+ /* Initialize the C API pointer array */
+ ssl_API[ssl_Context_New_NUM] = (void *)ssl_Context_New;
+ ssl_API[ssl_Connection_New_NUM] = (void *)ssl_Connection_New;
+ ssl_api_object = PyCObject_FromVoidPtr((void *)ssl_API, NULL);
+ if (ssl_api_object != NULL)
+ PyModule_AddObject(module, "_C_API", ssl_api_object);
+
+ /* Exceptions */
+/*
+ * ADD_EXCEPTION(dict,name,base) expands to a correct Exception declaration,
+ * inserting OpenSSL.SSL.name into dict, derviving the exception from base.
+ */
+#define ADD_EXCEPTION(_name, _base) \
+do { \
+ ssl_##_name = PyErr_NewException("OpenSSL.SSL."#_name, _base, NULL);\
+ if (ssl_##_name == NULL) \
+ goto error; \
+ if (PyModule_AddObject(module, #_name, ssl_##_name) != 0) \
+ goto error; \
+} while (0)
+
+ ssl_Error = PyErr_NewException("OpenSSL.SSL.Error", NULL, NULL);
+ if (ssl_Error == NULL)
+ goto error;
+ if (PyModule_AddObject(module, "Error", ssl_Error) != 0)
+ goto error;
+
+ ADD_EXCEPTION(ZeroReturnError, ssl_Error);
+ ADD_EXCEPTION(WantReadError, ssl_Error);
+ ADD_EXCEPTION(WantWriteError, ssl_Error);
+ ADD_EXCEPTION(WantX509LookupError, ssl_Error);
+ ADD_EXCEPTION(SysCallError, ssl_Error);
+#undef ADD_EXCEPTION
+
+ /* Method constants */
+ PyModule_AddIntConstant(module, "SSLv2_METHOD", ssl_SSLv2_METHOD);
+ PyModule_AddIntConstant(module, "SSLv3_METHOD", ssl_SSLv3_METHOD);
+ PyModule_AddIntConstant(module, "SSLv23_METHOD", ssl_SSLv23_METHOD);
+ PyModule_AddIntConstant(module, "TLSv1_METHOD", ssl_TLSv1_METHOD);
+
+ /* Verify constants */
+ PyModule_AddIntConstant(module, "VERIFY_NONE", SSL_VERIFY_NONE);
+ PyModule_AddIntConstant(module, "VERIFY_PEER", SSL_VERIFY_PEER);
+ PyModule_AddIntConstant(module, "VERIFY_FAIL_IF_NO_PEER_CERT",
+ SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
+ PyModule_AddIntConstant(module, "VERIFY_CLIENT_ONCE",
+ SSL_VERIFY_CLIENT_ONCE);
+
+ /* File type constants */
+ PyModule_AddIntConstant(module, "FILETYPE_PEM", SSL_FILETYPE_PEM);
+ PyModule_AddIntConstant(module, "FILETYPE_ASN1", SSL_FILETYPE_ASN1);
+
+ /* SSL option constants */
+ PyModule_AddIntConstant(module, "OP_SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE);
+ PyModule_AddIntConstant(module, "OP_EPHEMERAL_RSA", SSL_OP_EPHEMERAL_RSA);
+ PyModule_AddIntConstant(module, "OP_NO_SSLv2", SSL_OP_NO_SSLv2);
+ PyModule_AddIntConstant(module, "OP_NO_SSLv3", SSL_OP_NO_SSLv3);
+ PyModule_AddIntConstant(module, "OP_NO_TLSv1", SSL_OP_NO_TLSv1);
+
+ /* More SSL option constants */
+ PyModule_AddIntConstant(module, "OP_MICROSOFT_SESS_ID_BUG", SSL_OP_MICROSOFT_SESS_ID_BUG);
+ PyModule_AddIntConstant(module, "OP_NETSCAPE_CHALLENGE_BUG", SSL_OP_NETSCAPE_CHALLENGE_BUG);
+ PyModule_AddIntConstant(module, "OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG);
+ PyModule_AddIntConstant(module, "OP_SSLREF2_REUSE_CERT_TYPE_BUG", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG);
+ PyModule_AddIntConstant(module, "OP_MICROSOFT_BIG_SSLV3_BUFFER", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER);
+ PyModule_AddIntConstant(module, "OP_MSIE_SSLV2_RSA_PADDING", SSL_OP_MSIE_SSLV2_RSA_PADDING);
+ PyModule_AddIntConstant(module, "OP_SSLEAY_080_CLIENT_DH_BUG", SSL_OP_SSLEAY_080_CLIENT_DH_BUG);
+ PyModule_AddIntConstant(module, "OP_TLS_D5_BUG", SSL_OP_TLS_D5_BUG);
+ PyModule_AddIntConstant(module, "OP_TLS_BLOCK_PADDING_BUG", SSL_OP_TLS_BLOCK_PADDING_BUG);
+ PyModule_AddIntConstant(module, "OP_DONT_INSERT_EMPTY_FRAGMENTS", SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
+ PyModule_AddIntConstant(module, "OP_ALL", SSL_OP_ALL);
+ PyModule_AddIntConstant(module, "OP_CIPHER_SERVER_PREFERENCE", SSL_OP_CIPHER_SERVER_PREFERENCE);
+ PyModule_AddIntConstant(module, "OP_TLS_ROLLBACK_BUG", SSL_OP_TLS_ROLLBACK_BUG);
+ PyModule_AddIntConstant(module, "OP_PKCS1_CHECK_1", SSL_OP_PKCS1_CHECK_1);
+ PyModule_AddIntConstant(module, "OP_PKCS1_CHECK_2", SSL_OP_PKCS1_CHECK_2);
+ PyModule_AddIntConstant(module, "OP_NETSCAPE_CA_DN_BUG", SSL_OP_NETSCAPE_CA_DN_BUG);
+ PyModule_AddIntConstant(module, "OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG);
+
+ dict = PyModule_GetDict(module);
+ if (!init_ssl_context(dict))
+ goto error;
+ if (!init_ssl_connection(dict))
+ goto error;
+
+error:
+ ;
+}
diff --git a/src/ssl/ssl.h b/src/ssl/ssl.h
new file mode 100644
index 0000000..e8d3e93
--- /dev/null
+++ b/src/ssl/ssl.h
@@ -0,0 +1,76 @@
+/*
+ * ssl.h
+ *
+ * Copyright (C) AB Strakt 2001, All rights reserved
+ *
+ * Export functions and exceptions from the SSL sub module.
+ * See the file RATIONALE for a short explanation of why this module was written.
+ *
+ * Reviewed 2001-07-23
+ *
+ * @(#) $Id: ssl.h,v 1.6 2002/04/08 19:25:43 martin Exp $
+ */
+#ifndef PyOpenSSL_SSL_H_
+#define PyOpenSSL_SSL_H_
+
+#include <Python.h>
+#include "context.h"
+#include "connection.h"
+#include "../util.h"
+#include "../crypto/crypto.h"
+
+extern PyObject *ssl_Error, /* Base class */
+ *ssl_ZeroReturnError, /* Used with SSL_get_erorr */
+ *ssl_WantReadError, /* ... */
+ *ssl_WantWriteError, /* ... */
+ *ssl_WantX509LookupError, /* ... */
+ *ssl_SysCallError; /* Uses (errno,errstr) */
+
+#ifdef exception_from_error_queue
+# undef exception_from_error_queue
+#endif
+#define exception_from_error_queue() do { \
+ PyObject *errlist = error_queue_to_list(); \
+ PyErr_SetObject(ssl_Error, errlist); \
+ Py_DECREF(errlist); \
+} while (0)
+
+#define ssl_Context_New_NUM 0
+#define ssl_Context_New_RETURN ssl_ContextObj *
+#define ssl_Context_New_PROTO (int method)
+
+#define ssl_Connection_New_NUM 1
+#define ssl_Connection_New_RETURN ssl_ConnectionObj *
+#define ssl_Connection_New_PROTO (ssl_ContextObj *ctx, PyObject *sock)
+
+#define ssl_API_pointers 2
+
+#ifdef SSL_MODULE
+
+extern ssl_Context_New_RETURN ssl_Context_New ssl_Context_New_PROTO;
+extern ssl_Connection_New_RETURN ssl_Connection_New ssl_Connection_New_PROTO;
+
+#else /* SSL_MODULE */
+
+extern void **ssl_API;
+
+#define ssl_Context_New \
+ (*(ssl_Context_New_RETURN (*)ssl_Context_New_PROTO) ssl_API[ssl_Context_New_NUM])
+#define ssl_Connection_New \
+ (*(ssl_Connection_New_RETURN (*)ssl_Connection_New_PROTO) ssl_API[ssl_Connection_New_NUM])
+
+#define import_SSL() \
+{ \
+ PyObject *module = PyImport_ImportModule("OpenSSL.SSL"); \
+ if (module != NULL) { \
+ PyObject *module_dict = PyModule_GetDict(module); \
+ PyObject *c_api_object = PyDict_GetItemString(module_dict, "_C_API"); \
+ if (PyCObject_Check(c_api_object)) { \
+ ssl_API = (void **)PyCObject_AsVoidPtr(c_api_object); \
+ } \
+ } \
+}
+
+#endif /* SSL_MODULE */
+
+#endif /* PyOpenSSL_SSL_H_ */
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..3ae72c6
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,55 @@
+/*
+ * util.c
+ *
+ * Copyright (C) AB Strakt 2001, All rights reserved
+ *
+ * Utility functions.
+ * See the file RATIONALE for a short explanation of why this module was written.
+ *
+ * Reviewed 2001-07-23
+ */
+#include <Python.h>
+#include "util.h"
+
+static char *CVSid = "@(#) $Id: util.c,v 1.5 2001/08/09 11:26:36 martin Exp $";
+
+
+/*
+ * Flush OpenSSL's error queue and return a list of errors (a (library,
+ * function, reason) string tuple)
+ *
+ * Arguments: None
+ * Returns: A list of errors (new reference)
+ */
+PyObject *
+error_queue_to_list(void)
+{
+ PyObject *errlist, *tuple;
+ long err;
+
+ errlist = PyList_New(0);
+
+ while ((err = ERR_get_error()) != 0)
+ {
+ tuple = Py_BuildValue("(sss)", ERR_lib_error_string(err),
+ ERR_func_error_string(err),
+ ERR_reason_error_string(err));
+ PyList_Append(errlist, tuple);
+ Py_DECREF(tuple);
+ }
+
+ return errlist;
+}
+
+/*
+ * Flush OpenSSL's error queue and ignore the result
+ *
+ * Arguments: None
+ * Returns: None
+ */
+void
+flush_error_queue(void)
+{
+ Py_DECREF(error_queue_to_list());
+}
+
diff --git a/src/util.h b/src/util.h
new file mode 100644
index 0000000..592660e
--- /dev/null
+++ b/src/util.h
@@ -0,0 +1,111 @@
+/*
+ * util.h
+ *
+ * Copyright (C) AB Strakt 2001, All rights reserved
+ *
+ * Export utility functions and macros.
+ * See the file RATIONALE for a short explanation of why this module was written.
+ *
+ * Reviewed 2001-07-23
+ *
+ * @(#) $Id: util.h,v 1.8 2002/08/16 10:08:09 martin Exp $
+ */
+#ifndef PyOpenSSL_UTIL_H_
+#define PyOpenSSL_UTIL_H_
+
+#include <Python.h>
+#include <openssl/err.h>
+
+/*
+ * pymemcompat written by Michael Hudson and lets you program to the
+ * Python 2.3 memory API while keeping backwards compatability.
+ */
+#include "pymemcompat.h"
+
+extern PyObject *error_queue_to_list(void);
+extern void flush_error_queue(void);
+
+/*
+ * These are needed because there is no "official" way to specify
+ * WHERE to save the thread state.
+ */
+#ifdef WITH_THREAD
+# define MY_BEGIN_ALLOW_THREADS(st) \
+ { st = PyEval_SaveThread(); }
+# define MY_END_ALLOW_THREADS(st) \
+ { PyEval_RestoreThread(st); st = NULL; }
+#else
+# define MY_BEGIN_ALLOW_THREADS(st)
+# define MY_END_ALLOW_THREADS(st) { st = NULL; }
+#endif
+
+#if !defined(PY_MAJOR_VERSION) || PY_VERSION_HEX < 0x02000000
+static int
+PyModule_AddObject(PyObject *m, char *name, PyObject *o)
+{
+ PyObject *dict;
+ if (!PyModule_Check(m) || o == NULL)
+ return -1;
+ dict = PyModule_GetDict(m);
+ if (dict == NULL)
+ return -1;
+ if (PyDict_SetItemString(dict, name, o))
+ return -1;
+ Py_DECREF(o);
+ return 0;
+}
+
+static int
+PyModule_AddIntConstant(PyObject *m, char *name, long value)
+{
+ return PyModule_AddObject(m, name, PyInt_FromLong(value));
+}
+
+static int PyObject_AsFileDescriptor(PyObject *o)
+{
+ int fd;
+ PyObject *meth;
+
+ if (PyInt_Check(o)) {
+ fd = PyInt_AsLong(o);
+ }
+ else if (PyLong_Check(o)) {
+ fd = PyLong_AsLong(o);
+ }
+ else if ((meth = PyObject_GetAttrString(o, "fileno")) != NULL)
+ {
+ PyObject *fno = PyEval_CallObject(meth, NULL);
+ Py_DECREF(meth);
+ if (fno == NULL)
+ return -1;
+
+ if (PyInt_Check(fno)) {
+ fd = PyInt_AsLong(fno);
+ Py_DECREF(fno);
+ }
+ else if (PyLong_Check(fno)) {
+ fd = PyLong_AsLong(fno);
+ Py_DECREF(fno);
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError, "fileno() returned a non-integer");
+ Py_DECREF(fno);
+ return -1;
+ }
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError, "argument must be an int, or have a fileno() method.");
+ return -1;
+ }
+
+ if (fd < 0) {
+ PyErr_Format(PyExc_ValueError, "file descriptor cannot be a negative integer (%i)", fd);
+ return -1;
+ }
+ return fd;
+}
+#endif
+
+
+
+#endif