new branch is changes lp:~rick-fdd/pyopenssl/pkcs12_mod_and_export applied to trunk
diff --git a/src/crypto/crypto.c b/src/crypto/crypto.c
index 21501c1..4a25eae 100644
--- a/src/crypto/crypto.c
+++ b/src/crypto/crypto.c
@@ -12,6 +12,7 @@
 #include <Python.h>
 #define crypto_MODULE
 #include "crypto.h"
+#include "pkcs12.h"
 
 static char crypto_doc[] = "\n\
 Main file of crypto sub module.\n\
@@ -493,7 +494,6 @@
 static PyObject *
 crypto_load_pkcs12(PyObject *spam, PyObject *args)
 {
-    crypto_PKCS12Obj *crypto_PKCS12_New(PKCS12 *, char *);
     int len;
     char *buffer, *passphrase = NULL;
     BIO *bio;
@@ -515,6 +515,23 @@
 }
 
 
+static char crypto_PKCS12_doc[] = "\n\
+The factory function inserted in the module dictionary to create PKCS12\n\
+objects\n\
+\n\
+Arguments: spam - Always NULL\n\
+           args - The Python argument tuple, should be empty\n\
+Returns:   The PKCS12 object\n\
+";
+
+static crypto_PKCS12Obj *
+crypto_PKCS12(PyObject *spam, PyObject *args)
+{
+    if (!PyArg_ParseTuple(args, ":PKCS12"))
+        return NULL;
+    return crypto_PKCS12_New(NULL, NULL);
+}
+
 static char crypto_X509_verify_cert_error_string_doc[] = "\n\
 Get X509 verify certificate error string.\n\
 \n\
@@ -559,6 +576,7 @@
     { "load_pkcs12", (PyCFunction)crypto_load_pkcs12, METH_VARARGS, crypto_load_pkcs12_doc },
     { "X509_verify_cert_error_string", (PyCFunction)crypto_X509_verify_cert_error_string, METH_VARARGS, crypto_X509_verify_cert_error_string_doc },
     { "_exception_from_error_queue", (PyCFunction)crypto_exception_from_error_queue, METH_NOARGS, crypto_exception_from_error_queue_doc },
+    { "PKCS12",    (PyCFunction)crypto_PKCS12, METH_VARARGS|METH_VARARGS, crypto_PKCS12_doc },
     { NULL, NULL }
 };
 
diff --git a/src/crypto/pkcs12.c b/src/crypto/pkcs12.c
index 28ea2fe..de844d9 100644
--- a/src/crypto/pkcs12.c
+++ b/src/crypto/pkcs12.c
@@ -36,19 +36,86 @@
     return self->cert;
 }
 
+static char crypto_PKCS12_set_certificate_doc[] = "\n\
+Replace or set the certificate portion of the PKCS12 structure\n\
+\n\
+Arguments: self - The PKCS12 object\n\
+           args - The Python argument tuple \n\
+             cert - The new certificate\n\
+Returns:   self\n\
+";
+static crypto_PKCS12Obj *
+crypto_PKCS12_set_certificate(crypto_PKCS12Obj *self, PyObject *args, PyObject *keywds)
+{
+    PyObject *cert = NULL;
+    static char *kwlist[] = {"cert", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, keywds, "O:set_certificate", 
+        kwlist, &cert))
+        return NULL;
+
+    if (cert != Py_None && ! PyObject_IsInstance(cert, (PyObject *) &crypto_X509_Type)) { 
+        PyErr_SetString(PyExc_TypeError, "cert must be type X509 or None");
+        return NULL;
+    }
+
+    Py_INCREF(cert);  /* Make consistent before calling Py_DECREF() */
+    if(self->cert) {
+        Py_DECREF(self->cert);
+    }
+    self->cert = cert;
+
+    Py_INCREF(self);
+    return self;
+}
+
 static char crypto_PKCS12_get_privatekey_doc[] = "\n\
 Return private key portion of the PKCS12 structure\n\
 \n\
 @returns: PKey object containing the private key\n\
 ";
-static PyObject *
+//static PyObject *
+static crypto_PKeyObj *
 crypto_PKCS12_get_privatekey(crypto_PKCS12Obj *self, PyObject *args)
 {
     if (!PyArg_ParseTuple(args, ":get_privatekey"))
         return NULL;
 
     Py_INCREF(self->key);
-    return self->key;
+    return (PyObject *) self->key;
+}
+
+static char crypto_PKCS12_set_privatekey_doc[] = "\n\
+Replace or set the privatekey portion of the PKCS12 structure\n\
+\n\
+Arguments: self - The PKCS12 object\n\
+           args - The Python argument tuple \n\
+             pkey - The new private key\n\
+Returns:   self\n\
+";
+static crypto_PKCS12Obj *
+crypto_PKCS12_set_privatekey(crypto_PKCS12Obj *self, PyObject *args, PyObject *keywds)
+{
+    PyObject *pkey = NULL;
+    static char *kwlist[] = {"pkey", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, keywds, "O:set_privatekey", 
+        kwlist, &pkey))
+        return NULL;
+
+    if (pkey != Py_None && ! PyObject_IsInstance(pkey, (PyObject *) &crypto_PKey_Type)) { 
+        PyErr_SetString(PyExc_TypeError, "pkey must be type X509 or None");
+        return NULL;
+    }
+
+    Py_INCREF(pkey);  /* Make consistent before calling Py_DECREF() */
+    if(self->key) {
+        Py_DECREF(self->key);
+    }
+    self->key = pkey;
+
+    Py_INCREF(self);
+    return self;
 }
 
 static char crypto_PKCS12_get_ca_certificates_doc[] = "\n\
@@ -67,6 +134,119 @@
     return self->cacerts;
 }
 
+static char crypto_PKCS12_set_ca_certificates_doc[] = "\n\
+Replace or set the ca_certificates portion of the PKCS12 structure\n\
+\n\
+Arguments: self - The PKCS12 object\n\
+           args - The Python argument tuple \n\
+             cacerts - The new ca_certificates\n\
+Returns:   self\n\
+";
+static crypto_PKCS12Obj *
+crypto_PKCS12_set_ca_certificates(crypto_PKCS12Obj *self, PyObject *args, PyObject *keywds)
+{
+    PyObject *cacerts;
+    static char *kwlist[] = {"cacerts", NULL};
+    int i;
+
+    if (!PyArg_ParseTupleAndKeywords(args, keywds, "O:set_ca_certificates", 
+        kwlist, &cacerts))
+        return NULL;
+    if (cacerts == Py_None) {
+        /* We are good. */
+    } else if (PySequence_Check(cacerts)) {  /* is iterable */
+        for(i = 0;i < PySequence_Length(cacerts);i++) {  /* For each CA cert */
+            PyObject *obj;
+            obj = PySequence_GetItem(cacerts, i);
+            if (PyObject_Type(obj) != (PyObject *) &crypto_X509_Type) {
+                Py_DECREF(obj);
+                PyErr_SetString(PyExc_TypeError, "cacerts iterable must only contain X509Type");
+                return NULL;
+            }
+            Py_DECREF(obj);
+        }
+    } else {
+        PyErr_SetString(PyExc_TypeError, "cacerts must be an iterable or None");
+        return NULL;
+    }
+
+    Py_INCREF(cacerts); /* Make consistent before calling Py_DECREF() */
+    if(self->cacerts) {
+        Py_DECREF(self->cacerts);
+    }
+    self->cacerts = cacerts;
+
+    Py_INCREF(self);
+    return self;
+}
+
+static char crypto_PKCS12_export_doc[] = "\n\
+Dump a PKCS12 object to a buffer string\n\
+\n\
+Arguments: self - The PKCS12 object\n\
+           args - The Python argument tuple, should be:\n\
+             passphrase - (optional) for encrypting the PKCS12 string\n\
+                           using 3DES-CBC\n\
+             friendly_name - stored in the file for display\n\
+             iter - number of iterations to use when encrypting\n\
+             maciter - number of iterations to use when creating the MAC.\n\
+                       A special value of -1 means no MAC.\n\
+Returns:   The buffer with the dumped pkcs12 in it\n\
+";
+
+static PyObject *
+crypto_PKCS12_export(crypto_PKCS12Obj *self, PyObject *args, PyObject *keywds)
+{
+    int buf_len;
+    PyObject *buffer;
+    char *temp, *passphrase = NULL, *friendly_name = NULL;
+    BIO *bio;
+    PKCS12 *p12;
+    EVP_PKEY *pkey = NULL; 
+    STACK_OF(X509) *cacerts = NULL;
+    X509 *x509 = NULL;
+    int iter = PKCS12_DEFAULT_ITER;
+    int maciter = 0; 
+    static char *kwlist[] = {"passphrase", "friendly_name", "iter", "maciter", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, keywds, "|zzii:export", 
+        kwlist, &passphrase, &friendly_name, &iter, &maciter))
+        return NULL;
+
+    if (self->key && self->key != Py_None) {
+        pkey = ((crypto_PKeyObj*) self->key)->pkey;
+    }
+    if (self->cert && self->cert != Py_None) {
+        x509 = ((crypto_X509Obj*) self->cert)->x509;
+    }
+    cacerts = sk_X509_new_null();
+    if (self->cacerts && self->cacerts != Py_None) {
+        int i;
+        PyObject *obj;
+        for(i = 0;i < PySequence_Length(self->cacerts);i++) {  /* For each CA cert */
+            obj = PySequence_GetItem(self->cacerts, i);
+            /* assert(PyObject_IsInstance(obj, (PyObject *) &crypto_X509_Type )); */
+            sk_X509_push(cacerts, (( crypto_X509Obj* ) obj)->x509);
+            Py_DECREF(obj);
+        }
+    }
+
+    p12 = PKCS12_create(passphrase, friendly_name, pkey, x509, cacerts, 
+                        NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
+                        NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
+                        iter, maciter, 0);
+    if( p12 == NULL ) {
+        exception_from_error_queue(crypto_Error);
+        return NULL;
+    }
+    bio = BIO_new(BIO_s_mem());
+    i2d_PKCS12_bio(bio, p12);
+    buf_len = BIO_get_mem_data(bio, &temp);
+    buffer = PyString_FromStringAndSize(temp, buf_len);
+    BIO_free(bio);
+    return buffer;
+}
+
 /*
  * ADD_METHOD(name) expands to a correct PyMethodDef declaration
  *   {  'name', (PyCFunction)crypto_PKCS12_name, METH_VARARGS, crypto_PKCS12_name_doc }
@@ -74,11 +254,17 @@
  */
 #define ADD_METHOD(name)        \
     { #name, (PyCFunction)crypto_PKCS12_##name, METH_VARARGS, crypto_PKCS12_##name##_doc }
+#define ADD_KW_METHOD(name)        \
+    { #name, (PyCFunction)crypto_PKCS12_##name, METH_VARARGS | METH_KEYWORDS, crypto_PKCS12_##name##_doc }
 static PyMethodDef crypto_PKCS12_methods[] =
 {
     ADD_METHOD(get_certificate),
+    ADD_KW_METHOD(set_certificate),
     ADD_METHOD(get_privatekey),
+    ADD_KW_METHOD(set_privatekey),
     ADD_METHOD(get_ca_certificates),
+    ADD_KW_METHOD(set_ca_certificates),
+    ADD_KW_METHOD(export),
     { NULL, NULL }
 };
 #undef ADD_METHOD
@@ -108,7 +294,7 @@
     cacerts = sk_X509_new_null();
 
     /* parse the PKCS12 lump */
-    if (!(cacerts && PKCS12_parse(p12, passphrase, &pkey, &cert, &cacerts)))
+    if (p12 && !(cacerts && PKCS12_parse(p12, passphrase, &pkey, &cert, &cacerts)))
     {
         exception_from_error_queue(crypto_Error);
         return NULL;
@@ -122,11 +308,20 @@
     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;
+    if (cert == NULL) {
+        Py_INCREF(Py_None);
+        self->cert = Py_None;
+    } else {
+        if ((self->cert = (PyObject *)crypto_X509_New(cert, 1)) == NULL)
+            goto error;
+    } 
+    if (pkey == NULL) {
+        Py_INCREF(Py_None);
+        self->key = Py_None;
+    } else {
+        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);
diff --git a/src/crypto/pkcs12.h b/src/crypto/pkcs12.h
index 32c9ec4..0e724a9 100644
--- a/src/crypto/pkcs12.h
+++ b/src/crypto/pkcs12.h
@@ -27,4 +27,7 @@
     PyObject            *cacerts;
 } crypto_PKCS12Obj;
 
+crypto_PKCS12Obj *
+crypto_PKCS12_New(PKCS12 *p12, char *passphrase);
+
 #endif