initial source import
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;
+}
+