initial source import
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