#include <Python.h>

#include <openssl/asn1.h>
#include <openssl/rsa.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>

#define SERIAL_RAND_BITS  128

static void delcsr(void *ptr)
{
    X509_REQ_free((X509_REQ *)ptr);
}

static void delcert(void *ptr)
{
    X509_free((X509 *)ptr);
}

static void delrsa(void *ptr)
{
    RSA_free((RSA *)ptr);
}


/***********************************************************************
 **
 ** Functions below this header are referenced from outside this file,
 ** i.e. they appear in the list of methods exported from the module
 **
 **********************************************************************/
static PyObject *
readCert(PyObject *self, PyObject *args)
{
    X509 *cert = NULL;
    char *fn = NULL;
    BIO *in = NULL;
    PyObject *rv = NULL;

    if (!PyArg_ParseTuple(args, "z", &fn))
        return NULL;

    if (!fn) {
        PyErr_SetString(PyExc_ValueError, "Filename MUST be supplied");
        return NULL;
    }

    in = BIO_new(BIO_s_file());
    if (!in) {
        PyErr_SetString(PyExc_MemoryError, "failed to create a BIO");
        return NULL;
    }
    BIO_read_filename(in, fn);
    cert = PEM_read_bio_X509_AUX(in, NULL, NULL, NULL);
    (void) BIO_free_all(in);

    if (cert)
        return PyCObject_FromVoidPtr(cert, delcert);

    PyErr_SetString(PyExc_IOError, "Failed to read certificate file");
    return rv;
}

static PyObject *
readCSR(PyObject *self, PyObject *args)
{
    X509_REQ *req=NULL;
    BIO *in = NULL;
    char *fn = NULL;

    if (! PyArg_ParseTuple(args, "s", &fn))
        return NULL;

    if (! fn)
        return NULL;

    in = BIO_new(BIO_s_file());
    if (!in) {
        PyErr_SetString(PyExc_MemoryError, "Unable to create a BIO object");
        return NULL;
    }
    
    if (BIO_read_filename(in, fn) <= 0) {
        BIO_free_all(in);
        PyErr_SetString(PyExc_IOError, "Unable to read CSR from filename");
        return NULL;
    }

    /* We expect the CSR to be in PEM format, so try that first... */
    req = PEM_read_bio_X509_REQ(in, NULL, NULL, NULL);
    /* If that fails, see if it was in ASN1 format */
    if (!req)
        req = d2i_X509_REQ_bio(in, NULL);

    BIO_free_all(in);

    if (!req) {
        PyErr_SetString(PyExc_IOError, "Unable to get REQ object from file");
        return NULL;
    }
    return PyCObject_FromVoidPtr(req, delcsr);
}


static PyMethodDef TestMethods[] = {
    { "readCert", readCert, METH_VARARGS, "Read a certificate from a file" },
    { "readCSR", readCSR, METH_VARARGS, "Read a certificate request from a file" },
    { NULL, NULL, 0, NULL },
};

PyMODINIT_FUNC
inittest(void)
{
    PyObject *mod = NULL;

    /* init OpenSSL */
    CRYPTO_malloc_init();
    ERR_load_crypto_strings(); 
    OpenSSL_add_all_algorithms();

    mod = Py_InitModule("test", TestMethods);
}

