diff options
author | Rob Austein <sra@hactrn.net> | 2007-07-07 17:04:37 +0000 |
---|---|---|
committer | Rob Austein <sra@hactrn.net> | 2007-07-07 17:04:37 +0000 |
commit | ed43d040bf72c2b8eb9d2cec3444556761b3c606 (patch) | |
tree | 57d47ba90cd2c6672f32f0a514c47058e23e3f90 /pow/POW-0.7/POW.c | |
parent | 2d5c53975e6ddaec9ac3d49a70278fcdd584273d (diff) |
Add pow
svn path=/pow/POW-0.7/PKG-INFO; revision=722
Diffstat (limited to 'pow/POW-0.7/POW.c')
-rw-r--r-- | pow/POW-0.7/POW.c | 7110 |
1 files changed, 7110 insertions, 0 deletions
diff --git a/pow/POW-0.7/POW.c b/pow/POW-0.7/POW.c new file mode 100644 index 00000000..f1bdf4f4 --- /dev/null +++ b/pow/POW-0.7/POW.c @@ -0,0 +1,7110 @@ +/*****************************************************************************/ +/* */ +/* Copyright (c) 2001, 2002, Peter Shannon */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions */ +/* are met: */ +/* */ +/* * Redistributions of source code must retain the above */ +/* copyright notice, this list of conditions and the following */ +/* disclaimer. */ +/* */ +/* * Redistributions in binary form must reproduce the above */ +/* copyright notice, this list of conditions and the following */ +/* disclaimer in the documentation and/or other materials */ +/* provided with the distribution. */ +/* */ +/* * The name of the contributors may be used to endorse or promote */ +/* products derived from this software without specific prior */ +/* written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ +/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS */ +/* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS */ +/* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ +/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ +/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ +/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ +/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ +/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/* */ +/*****************************************************************************/ + +#include <Python.h> + +#include <openssl/crypto.h> +#include <openssl/rand.h> +#include <openssl/asn1.h> +#include <openssl/x509.h> +#include <openssl/x509v3.h> +#include <openssl/pem.h> +#include <openssl/ssl.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/md5.h> +#include <openssl/md2.h> +#include <openssl/sha.h> +#include <openssl/hmac.h> + +#include <time.h> + +// semetric ciphers +#define DES_ECB 1 +#define DES_EDE 2 +#define DES_EDE3 3 +#define DES_CFB 4 +#define DES_EDE_CFB 5 +#define DES_EDE3_CFB 6 +#define DES_OFB 7 +#define DES_EDE_OFB 8 +#define DES_EDE3_OFB 9 +#define DES_CBC 10 +#define DES_EDE_CBC 11 +#define DES_EDE3_CBC 12 +#define DESX_CBC 13 +#define RC4 14 +#define RC4_40 15 +#define IDEA_ECB 16 +#define IDEA_CFB 17 +#define IDEA_OFB 18 +#define IDEA_CBC 19 +#define RC2_ECB 20 +#define RC2_CBC 21 +#define RC2_40_CBC 22 +#define RC2_CFB 23 +#define RC2_OFB 24 +#define BF_ECB 25 +#define BF_CBC 26 +#define BF_CFB 27 +#define BF_OFB 28 +#define CAST5_ECB 29 +#define CAST5_CBC 30 +#define CAST5_CFB 31 +#define CAST5_OFB 32 +#define RC5_32_12_16_CBC 33 +#define RC5_32_12_16_CFB 34 +#define RC5_32_12_16_ECB 35 +#define RC5_32_12_16_OFB 36 + +// SSL connection methods +#define SSLV2_SERVER_METHOD 1 +#define SSLV2_CLIENT_METHOD 2 +#define SSLV2_METHOD 3 +#define SSLV3_SERVER_METHOD 4 +#define SSLV3_CLIENT_METHOD 5 +#define SSLV3_METHOD 6 +#define TLSV1_SERVER_METHOD 7 +#define TLSV1_CLIENT_METHOD 8 +#define TLSV1_METHOD 9 +#define SSLV23_SERVER_METHOD 10 +#define SSLV23_CLIENT_METHOD 11 +#define SSLV23_METHOD 12 + +// SSL connection states + +// PEM encoded data types +#define RSA_PUBLIC_KEY 1 +#define RSA_PRIVATE_KEY 2 +#define DSA_PUBLIC_KEY 3 +#define DSA_PRIVATE_KEY 4 +#define DH_PUBLIC_KEY 5 +#define DH_PRIVATE_KEY 6 +#define X509_CERTIFICATE 7 +#define X_X509_CRL 8 //X509_CRL already used by OpenSSL library + +// asymmetric ciphers +#define RSA_CIPHER 1 +#define DSA_CIPHER 2 +#define DH_CIPHER 3 +#define NO_DSA +#define NO_DH + +// digests +#define MD2_DIGEST 1 +#define MD5_DIGEST 2 +#define SHA_DIGEST 3 +#define SHA1_DIGEST 4 +#define RIPEMD160_DIGEST 5 + +//object format +#define SHORTNAME_FORMAT 1 +#define LONGNAME_FORMAT 2 + +//output format +#define PEM_FORMAT 1 +#define DER_FORMAT 2 + +//object check functions +#define X_X509_Check(op) ((op)->ob_type == &x509type) +#define X_X509_store_Check(op) ((op)->ob_type == &x509_storetype) +#define X_X509_crl_Check(op) ((op)->ob_type == &x509_crltype) +#define X_X509_revoked_Check(op) ((op)->ob_type == &x509_revokedtype) +#define X_asymmetric_Check(op) ((op)->ob_type == &asymmetrictype) +#define X_symmetric_Check(op) ((op)->ob_type == &symmetrictype) +#define X_digest_Check(op) ((op)->ob_type == &digesttype) +#define X_hmac_Check(op) ((op)->ob_type == &hmactype) +#define X_ssl_Check(op) ((op)->ob_type == &ssltype) + +static char pow_module__doc__ [] = +"<moduleDescription>\n" +" <header>\n" +" <name>POW</name>\n" +" <author>Peter Shannon</author>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This third major release of POW addresses the most critical missing\n" +" parts of functionality, X509v3 support. Initially I thought adding\n" +" support via the OpenSSL code would be the easiest option but this\n" +" proved to be incorrect mainly due to the way I have chosen to handle\n" +" the complex data such as <classname>directoryNames</classname> and\n" +" <classname>generalNames</classname>. It is easier in python to\n" +" construct complex sets of data using lists and dictionaries than\n" +" coordinate large numbers of objects and method calls. This is no\n" +" criticism, it is just extremely easy. Coding complex data such as the\n" +" <classname>certificatePolicies</classname> coding coding routines in C\n" +" to handle the data proved laborous and ultimately error prone.\n" +" </para>\n" +" <para>\n" +" PKIX structures are supported by a few operations on the relevant POW\n" +" objects and through a Python library which is modelled on the DER\n" +" encoding rules. Modeling DER does expose some of the complexities of\n" +" the ASN1 specifications but avoids coding many assumptions into the\n" +" data structures and the interface for the objects. For an example of\n" +" overly complex definitions take a look at the\n" +" <classname>Name</classname> object in RFC3280. It is equally\n" +" important that modeling DER in the way leads to a library which is\n" +" trivial to extend to support new objects - simple objects are one\n" +" liners and complex objects only require the definition of a new\n" +" constructor.\n" +" </para>\n" +" <para>\n" +" functionality have been plugged. The <classname>Ssl</classname> class has received\n" +" several new features relating to security. Other areas have been\n" +" improved: PRNG support, certificate and CRL signing, certificate chain\n" +" and client verification. Many bugs have been fixed, and certain\n" +" parts of code re-written where necessary. I hope you enjoy using POW \n" +" and please feel free to send me feature requests and bug reports.\n" +" </para>\n" +" </body>\n" +"</moduleDescription>\n" +; + +/*========== Pre-definitions ==========*/ +static PyObject *SSLErrorObject; +static PyTypeObject x509type; +static PyTypeObject x509_storetype; +static PyTypeObject x509_crltype; +static PyTypeObject x509_revokedtype; +static PyTypeObject asymmetrictype; +static PyTypeObject symmetrictype; +static PyTypeObject digesttype; +static PyTypeObject hmactype; +static PyTypeObject ssltype; +/*========== Pre-definitions ==========*/ + +/*========== C stucts ==========*/ +typedef struct { + PyObject_HEAD + X509 *x509; +} x509_object; + +typedef struct { + PyObject_HEAD + X509_STORE *store; +} x509_store_object; + +typedef struct { + PyObject_HEAD + X509_CRL *crl; +} x509_crl_object; + +typedef struct { + PyObject_HEAD + X509_REVOKED *revoked; +} x509_revoked_object; + +typedef struct { + PyObject_HEAD + void *cipher; + int key_type; + int cipher_type; +} asymmetric_object; + +typedef struct { + PyObject_HEAD + EVP_CIPHER_CTX cipher_ctx; + int cipher_type; +} symmetric_object; + +typedef struct { + PyObject_HEAD + EVP_MD_CTX digest_ctx; + int digest_type; +} digest_object; + +typedef struct { + PyObject_HEAD + HMAC_CTX hmac_ctx; +} hmac_object; + +typedef struct { + PyObject_HEAD + int ctxset; + SSL *ssl; + SSL_CTX *ctx; +} ssl_object; +/*========== C stucts ==========*/ + +/*========== helper funcitons ==========*/ + +/* + Simple function to install a constant in the module name space. +*/ +static void +install_int_const( PyObject *d, char *name, int value ) +{ + PyObject *v = PyInt_FromLong( (long)value ); + if (!v || PyDict_SetItemString(d, name, v) ) + PyErr_Clear(); + + Py_XDECREF(v); +} + +int +docset_helper_add(PyObject *set, char *v) +{ + PyObject *value=NULL; + + if ( !(value = PyString_FromString(v) ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + if ( PyList_Append( set, value ) != 0) + goto error; + + return 1; + +error: + + Py_XDECREF(value); + return 0; +} + +/* + Generate an encrypion envelope. Saves a lot of space having thie case + statement in one place. +*/ +static EVP_CIPHER * +evp_cipher_factory(int cipher_type) +{ + switch(cipher_type) + { +#ifndef NO_DES + case DES_ECB: return EVP_des_ecb(); + case DES_EDE: return EVP_des_ede(); + case DES_EDE3: return EVP_des_ede3(); + case DES_CFB: return EVP_des_cfb(); + case DES_EDE_CFB: return EVP_des_ede_cfb(); + case DES_EDE3_CFB: return EVP_des_ede3_cfb(); + case DES_OFB: return EVP_des_ofb(); + case DES_EDE_OFB: return EVP_des_ede_ofb(); + case DES_EDE3_OFB: return EVP_des_ede3_ofb(); + case DES_CBC: return EVP_des_cbc(); + case DES_EDE_CBC: return EVP_des_ede_cbc(); + case DES_EDE3_CBC: return EVP_des_ede3_cbc(); + case DESX_CBC: return EVP_desx_cbc(); +#endif +#ifndef NO_RC4 + case RC4: return EVP_rc4(); + case RC4_40: return EVP_rc4_40(); +#endif +#ifndef NO_IDEA + case IDEA_ECB: return EVP_idea_ecb(); + case IDEA_CFB: return EVP_idea_cfb(); + case IDEA_OFB: return EVP_idea_ofb(); + case IDEA_CBC: return EVP_idea_cbc(); +#endif +#ifndef NO_RC2 + case RC2_ECB: return EVP_rc2_ecb(); + case RC2_CBC: return EVP_rc2_cbc(); + case RC2_40_CBC: return EVP_rc2_40_cbc(); + case RC2_CFB: return EVP_rc2_cfb(); + case RC2_OFB: return EVP_rc2_ofb(); +#endif +#ifndef NO_BF + case BF_ECB: return EVP_bf_ecb(); + case BF_CBC: return EVP_bf_cbc(); + case BF_CFB: return EVP_bf_cfb(); + case BF_OFB: return EVP_bf_ofb(); +#endif +#ifndef NO_CAST5 + case CAST5_ECB: return EVP_cast5_ecb(); + case CAST5_CBC: return EVP_cast5_cbc(); + case CAST5_CFB: return EVP_cast5_cfb(); + case CAST5_OFB: return EVP_cast5_ofb(); +#endif +#ifndef NO_RC5_32_12_16 + case RC5_32_12_16_CBC: return EVP_rc5_32_12_16_cbc(); + case RC5_32_12_16_CFB: return EVP_rc5_32_12_16_cfb(); + case RC5_32_12_16_ECB: return EVP_rc5_32_12_16_ecb(); + case RC5_32_12_16_OFB: return EVP_rc5_32_12_16_ofb(); +#endif + default: return NULL; + } +} + +static PyObject * +ssl_err_factory(int err) +{ + switch(err) + { + case SSL_ERROR_NONE: + return Py_BuildValue( "(is)", SSL_ERROR_NONE, "SSL_ERROR_NONE" ); + case SSL_ERROR_ZERO_RETURN: + return Py_BuildValue( "(is)", SSL_ERROR_ZERO_RETURN, "SSL_ERROR_ZERO_RETURN" ); + case SSL_ERROR_WANT_READ: + return Py_BuildValue( "(is)", SSL_ERROR_WANT_READ, "SSL_ERROR_WANT_READ" ); + case SSL_ERROR_WANT_WRITE: + return Py_BuildValue( "(is)", SSL_ERROR_WANT_WRITE, "SSL_ERROR_WANT_WRITE" ); + case SSL_ERROR_WANT_X509_LOOKUP: + return Py_BuildValue( "(is)", SSL_ERROR_WANT_X509_LOOKUP, "SSL_ERROR_WANT_X509_LOOKUP" ); + case SSL_ERROR_SYSCALL: + return Py_BuildValue( "(is)", SSL_ERROR_SYSCALL, "SSL_ERROR_SYSCALL" ); + case SSL_ERROR_SSL: + return Py_BuildValue( "(is)", SSL_ERROR_SSL, "SSL_ERROR_SSL" ); + + default: + return Py_BuildValue( "(is)", err, "UNKOWN_SSL_ERROR" ); + } +} + +static PyObject * +X509_object_helper_set_name(X509_NAME *name, PyObject *name_sequence) +{ + PyObject *pair = NULL; PyObject *type = NULL; PyObject *value = NULL; + int no_pairs = 0, i = 0, str_type = 0, nid; + char *valueptr = NULL, *typeptr = NULL; + + no_pairs = PySequence_Size( name_sequence ); + for (i=0; i < no_pairs; i++) + { + if ( ( pair = PySequence_GetItem( name_sequence, i ) ) == NULL ) + return NULL; + + if ( !( PyTuple_Check(pair) || PyList_Check(pair) ) ) + { PyErr_SetString( PyExc_TypeError, "inapropriate type" ); goto error; } + + if ( PySequence_Size(pair) != 2 ) + { PyErr_SetString( SSLErrorObject, "each name entry must have 2 elements" ); goto error; } + + if ( !(type = PySequence_GetItem( pair, 0 ) ) ) + { PyErr_SetString( PyExc_TypeError, "could not get type string" ); goto error; } + + if ( !PyString_Check(type) ) + { PyErr_SetString( PyExc_TypeError, "inapropriate type" ); goto error; } + + if ( !( value = PySequence_GetItem( pair, 1 ) ) ) + { PyErr_SetString( PyExc_TypeError, "could not get value string" ); goto error; } + + if ( !PyString_Check(value) ) + { PyErr_SetString( PyExc_TypeError, "inapropriate type" ); goto error; } + + typeptr = PyString_AsString(type); + valueptr = PyString_AsString(value); + + str_type = ASN1_PRINTABLE_type( valueptr, -1 ); + if ( !(nid = OBJ_ln2nid(typeptr)) ) + if ( !(nid = OBJ_sn2nid(typeptr)) ) + { PyErr_SetString( SSLErrorObject, "unknown ASN1 object" ); goto error; } + + if ( !X509_NAME_add_entry_by_NID( name, nid, str_type, valueptr, strlen(valueptr), -1, 0 ) ) + { PyErr_SetString( SSLErrorObject, "unable to add name entry" ); goto error; } + + Py_DECREF(pair); + Py_DECREF(type); + Py_DECREF(value); + pair = NULL; + type = NULL; + value = NULL; + } + return name_sequence; + +error: + + Py_XDECREF(pair); + Py_XDECREF(type); + Py_XDECREF(value); + + return NULL; +} + +static PyObject * +X509_object_helper_get_name(X509_NAME *name, int format) +{ + int no_entries=0, no_pairs=0, i=0, j=0, value_len=0, nid=0; + X509_NAME_ENTRY *entry=NULL; + char *value=NULL, long_name[512]; + const char *short_name; + + PyObject *result_list = NULL; + PyObject *pair = NULL; + PyObject *py_type = NULL; + PyObject *py_value = NULL; + + no_entries = X509_NAME_entry_count( name ); + + if ( !(result_list = PyTuple_New( no_entries ) ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + for(i=0; i<no_entries; i++) + { + if ( !(entry = X509_NAME_get_entry( name, i ) ) ) + { PyErr_SetString( SSLErrorObject, "could not get certificate name" ); goto error; } + + if (entry->value->length + 1 > value_len) + { + if (value) + free(value); + + if ( !(value = malloc( entry->value->length + 1 ) ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + value_len = entry->value->length + 1; + } + memcpy( value, entry->value->data, entry->value->length ); + value[ entry->value->length ] = 0; + + if ( !(i2t_ASN1_OBJECT(long_name, sizeof(long_name), entry->object) ) ) + { PyErr_SetString( SSLErrorObject, "could not object name" ); goto error; } + + if ( format == SHORTNAME_FORMAT ) + { + nid = OBJ_ln2nid( long_name ); + short_name = OBJ_nid2sn( nid ); + py_type = PyString_FromString(short_name); + } + else if ( format == LONGNAME_FORMAT ) + py_type = PyString_FromString(long_name); + else + { PyErr_SetString( SSLErrorObject, "unkown name format" ); goto error; } + + py_value = PyString_FromString(value); + + if ( !(pair = PyTuple_New( 2 ) ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + PyTuple_SetItem( pair, 0, py_type ); + PyTuple_SetItem( pair, 1, py_value ); + PyTuple_SetItem( result_list, i, pair ); + } + + if (value) + free(value); + + return result_list; + +error: + + if (value) + free(value); + + if (result_list) + { + no_pairs = PyTuple_Size( result_list ); + for (i=0; i < no_pairs; i++) + { + pair = PyTuple_GetItem( result_list, i ); + no_entries = PyTuple_Size( result_list ); + for (j=0; j < no_entries; j++) + { + py_value = PyTuple_GetItem( pair, i ); + Py_DECREF( py_value ); + } + } + } + + Py_XDECREF(py_type); + Py_XDECREF(py_value); + Py_XDECREF(result_list); + return NULL; +} +/*========== helper funcitons ==========*/ + +/*========== X509 code ==========*/ +static x509_object * +X509_object_new(void) +{ + x509_object *self; + + self = PyObject_New( x509_object, &x509type ); + if (self == NULL) + goto error; + + self->x509 = X509_new(); + return self; + +error: + + Py_XDECREF(self); + return NULL; +} + +/* + This function is pretty dumb. Most of the work is done by the module + function pow_module_pem_read(). +*/ +static x509_object * +X509_object_pem_read(BIO *in) +{ + x509_object *self; + + if ( !(self = PyObject_New( x509_object, &x509type ) ) ) + goto error; + + if( !(self->x509 = PEM_read_bio_X509( in, NULL, NULL, NULL ) ) ) + { PyErr_SetString( SSLErrorObject, "could not load PEM encoded certificate" ); goto error; } + + return self; + +error: + + Py_XDECREF(self); + return NULL; +} + +static x509_object * +X509_object_der_read(char *src, int len) +{ + x509_object *self; + unsigned char *ptr = src; + + if ( !(self = PyObject_New( x509_object, &x509type ) ) ) + goto error; + + self->x509 = X509_new(); + + if( !(d2i_X509( &self->x509, &ptr, len ) ) ) + { PyErr_SetString( SSLErrorObject, "could not load PEM encoded certificate" ); goto error; } + + return self; + +error: + + Py_XDECREF(self); + return NULL; +} + +/* + Unlike the previous function this creates the BIO itself. The BIO_s_mem + is used as a buffer which the certificate is read into, from this buffer + it is read into a char[] and returned as a string. +*/ +static PyObject * +X509_object_write_helper(x509_object *self, PyObject *args, int format) +{ + int len=0; + char *buf=NULL; + BIO *out_bio=NULL; + PyObject *cert=NULL; + + if (!PyArg_ParseTuple(args, "")) + return NULL; + + out_bio = BIO_new(BIO_s_mem()); + + if (format == DER_FORMAT) + { + if (!i2d_X509_bio(out_bio, self->x509) ) + { PyErr_SetString( SSLErrorObject, "unable to write certificate" ); goto error; } + } + else if (format == PEM_FORMAT) + { + if (!PEM_write_bio_X509(out_bio, self->x509) ) + { PyErr_SetString( SSLErrorObject, "unable to write certificate" ); goto error; } + } + else + { PyErr_SetString( SSLErrorObject, "internal error, unkown output format" ); goto error; } + + if ( !(len = BIO_ctrl_pending(out_bio) ) ) + { PyErr_SetString( SSLErrorObject, "unable to get bytes stored in bio" ); goto error; } + + if ( !(buf = malloc(len) ) ) + { PyErr_SetString( SSLErrorObject, "unable to allocate memory" ); goto error; } + + if ( BIO_read( out_bio, buf, len ) != len ) + { PyErr_SetString( SSLErrorObject, "unable to write out cert" ); goto error; } + + cert = Py_BuildValue("s#", buf, len); + + BIO_free(out_bio); + free(buf); + return cert; + +error: + + if (out_bio) + BIO_free(out_bio); + + if (buf) + free(buf); + + Py_XDECREF(cert); + return NULL; +} + +static char X509_object_pem_write__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509</memberof>\n" +" <name>pemWrite</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method returns a PEM encoded certificate as a\n" +" string.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +X509_object_pem_write(x509_object *self, PyObject *args) +{ + return X509_object_write_helper(self, args, PEM_FORMAT); +} + +static char X509_object_der_write__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509</memberof>\n" +" <name>derWrite</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method returns a DER encoded certificate as a\n" +" string.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +X509_object_der_write(x509_object *self, PyObject *args) +{ + return X509_object_write_helper(self, args, DER_FORMAT); +} + +/* + Currently this function only supports RSA keys. +*/ +static char X509_object_set_public_key__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509</memberof>\n" +" <name>setPublicKey</name>\n" +" <parameter>key</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method sets the public key for this certificate object. The\n" +" parameter <parameter>key</parameter> should be an instance of\n" +" <classname>Asymmetric</classname> containing a public key.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + + +static PyObject * +X509_object_set_public_key(x509_object *self, PyObject *args) +{ + EVP_PKEY *pkey=NULL; + asymmetric_object *asym; + + if (!PyArg_ParseTuple(args, "O!", &asymmetrictype, &asym)) + goto error; + + if ( !(pkey = EVP_PKEY_new() ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + if ( !(EVP_PKEY_assign_RSA(pkey, asym->cipher) ) ) + { PyErr_SetString( SSLErrorObject, "EVP_PKEY assignment error" ); goto error; } + + if ( !(X509_set_pubkey(self->x509,pkey) ) ) + { PyErr_SetString( SSLErrorObject, "could not set certificate's public key" ); goto error; } + + return Py_BuildValue(""); + +error: + + if (pkey) + EVP_PKEY_free(pkey); + + return NULL; + +} + +static char X509_object_sign__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509</memberof>\n" +" <name>sign</name>\n" +" <parameter>key</parameter>\n" +" <parameter>digest=MD5_DIGEST</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method signs a certificate with a private key. See the\n" +" example for the methods which should be invoked before signing a\n" +" certificate. <parameter>key</parameter> should be an instance of\n" +" <classname>Asymmetric</classname> containing a private key.\n" +" The optional parameter <parameter>digest</parameter> indicates \n" +" which digest function should be used to compute the hash to be \n" +" signed, it should be one of the following:\n" +" </para>\n" +" <simplelist>\n" +" <member><constant>MD2_DIGEST</constant></member>\n" +" <member><constant>MD5_DIGEST</constant></member>\n" +" <member><constant>SHA_DIGEST</constant></member>\n" +" <member><constant>SHA1_DIGEST</constant></member>\n" +" <member><constant>RIPEMD160_DIGEST</constant></member>\n" +" </simplelist>\n" +" </body>\n" +"</method>\n" +; + + +static PyObject * +X509_object_sign(x509_object *self, PyObject *args) +{ + EVP_PKEY *pkey=NULL; + asymmetric_object *asym; + int digest=MD5_DIGEST; + + if (!PyArg_ParseTuple(args, "O!|i", &asymmetrictype, &asym, &digest)) + goto error; + + if ( !(pkey = EVP_PKEY_new() ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + if (asym->key_type != RSA_PRIVATE_KEY) + { PyErr_SetString( SSLErrorObject, "cannot use this type of key" ); goto error; } + + if ( !(EVP_PKEY_assign_RSA(pkey, asym->cipher) ) ) + { PyErr_SetString( SSLErrorObject, "EVP_PKEY assignment error" ); goto error; } + + switch (digest) + { + case MD5_DIGEST: + { + if (!X509_sign(self->x509, pkey, EVP_md5() ) ) + { PyErr_SetString( SSLErrorObject, "could not sign certificate" ); goto error; } + break; + } + case MD2_DIGEST: + { + if (!X509_sign(self->x509, pkey, EVP_md2() ) ) + { PyErr_SetString( SSLErrorObject, "could not sign certificate" ); goto error; } + break; + } + case SHA_DIGEST: + { + if (!X509_sign(self->x509, pkey, EVP_sha() ) ) + { PyErr_SetString( SSLErrorObject, "could not sign certificate" ); goto error; } + break; + } + case SHA1_DIGEST: + { + if (!X509_sign(self->x509, pkey, EVP_sha1() ) ) + { PyErr_SetString( SSLErrorObject, "could not sign certificate" ); goto error; } + break; + } + case RIPEMD160_DIGEST: + { + if (!X509_sign(self->x509, pkey, EVP_ripemd160() ) ) + { PyErr_SetString( SSLErrorObject, "could not sign certificate" ); goto error; } + break; + } + } + + return Py_BuildValue(""); + +error: + + if (pkey) + EVP_PKEY_free(pkey); + + return NULL; + +} + +static char X509_object_get_version__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509</memberof>\n" +" <name>getVersion</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method returns the version number from the version field of\n" +" this certificate. \n" +" </para>\n" +" </body>\n" +"</method>\n" +; + + +static PyObject * +X509_object_get_version(x509_object *self, PyObject *args) +{ + long version=0; + + if (!PyArg_ParseTuple(args, "")) + goto error; + + if ( !(version = X509_get_version( self->x509 ) ) ) + { PyErr_SetString( SSLErrorObject, "could not get certificate version" ); goto error; } + + return Py_BuildValue("l", version); + +error: + + return NULL; +} + +static char X509_object_set_version__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509</memberof>\n" +" <name>setVersion</name>\n" +" <parameter>version</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method sets the version number in the version field of\n" +" this certificate. <parameter>version</parameter> should be an\n" +" integer.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +X509_object_set_version(x509_object *self, PyObject *args) +{ + long version=0; + + if (!PyArg_ParseTuple(args, "l", &version)) + goto error; + + if ( !X509_set_version( self->x509, version ) ) + { PyErr_SetString( SSLErrorObject, "could not set certificate version" ); goto error; } + + return Py_BuildValue(""); + +error: + + return NULL; +} + +static char X509_object_get_serial__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509</memberof>\n" +" <name>getSerial</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method get the serial number in the serial field of\n" +" this certificate.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +X509_object_get_serial(x509_object *self, PyObject *args) +{ + long serial=0; + ASN1_INTEGER *asn1i=NULL; + + if (!PyArg_ParseTuple(args, "")) + goto error; + + if ( !(asn1i = X509_get_serialNumber( self->x509 ) ) ) + { PyErr_SetString( SSLErrorObject, "could not get serial number" ); goto error; } + + if ( (serial = ASN1_INTEGER_get(asn1i) ) == -1 ) + { PyErr_SetString( SSLErrorObject, "could not convert ASN1 Integer to long" ); goto error; } + + return Py_BuildValue("l", serial); + +error: + + return NULL; +} + +static char X509_object_set_serial__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509</memberof>\n" +" <name>setSerial</name>\n" +" <parameter>serial</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method sets the serial number in the serial field of\n" +" this certificate. <parameter>serial</parameter> should ba an\n" +" integer.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +X509_object_set_serial(x509_object *self, PyObject *args) +{ + long serial=0; + ASN1_INTEGER *asn1i=NULL; + + if (!PyArg_ParseTuple(args, "l", &serial)) + goto error; + + if ( !(asn1i = ASN1_INTEGER_new() ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + if ( !ASN1_INTEGER_set( asn1i, serial ) ) + { PyErr_SetString( SSLErrorObject, "could not set ASN1 integer" ); goto error; } + + if ( !X509_set_serialNumber( self->x509, asn1i ) ) + { PyErr_SetString( SSLErrorObject, "could not set certificate serial" ); goto error; } + + ASN1_INTEGER_free(asn1i); + + return Py_BuildValue(""); + +error: + + if (asn1i) + ASN1_INTEGER_free(asn1i); + + return NULL; +} + +static char X509_object_get_issuer__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509</memberof>\n" +" <name>getIssuer</name>\n" +" <parameter>format=SHORTNAME_FORMAT</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method returns a tuple containing the issuers name. Each\n" +" element of the tuple is a tuple with 2 elements. The first tuple\n" +" is an object name and the second is it's value. Both issuer and\n" +" subject are names distinguished normally composed of a small\n" +" number of objects:\n" +" </para>\n" +" <simplelist>\n" +" <member><constant>c</constant> or <constant>countryName</constant></member>\n" +" <member><constant>st</constant> or <constant>stateOrProvinceName</constant></member>\n" +" <member><constant>o</constant> or <constant>organizationName</constant></member>\n" +" <member><constant>l</constant> or <constant>localityName</constant></member>\n" +" <member><constant>ou</constant> or <constant>organizationalUnitName</constant></member>\n" +" <member><constant>cn</constant> or <constant>commonName</constant></member>\n" +" </simplelist>\n" +" <para>\n" +" The data type varies from one object to another, however, all the\n" +" common objects are strings. It would be possible to specify any\n" +" kind of object but that would certainly adversely effect\n" +" portability and is not recommended.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +X509_object_get_issuer(x509_object *self, PyObject *args) +{ + PyObject *result_list = NULL; + X509_NAME *name = NULL; + int format=SHORTNAME_FORMAT; + + if (!PyArg_ParseTuple(args, "|i", &format)) + goto error; + + if ( !(name = X509_get_issuer_name( self->x509 ) ) ) + { PyErr_SetString( SSLErrorObject, "could not get issuers name" ); goto error; } + + if ( !(result_list = X509_object_helper_get_name(name, format) ) ) + { PyErr_SetString( SSLErrorObject, "failed to produce name list" ); goto error; } + + return result_list; + +error: + + return NULL; +} + +static char X509_object_get_subject__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509</memberof>\n" +" <name>getSubject</name>\n" +" <parameter>format=SHORTNAME_FORMAT</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method returns a tuple containing the subjects name. See\n" +" <function>getIssuer</function> for a description of the returned\n" +" object's format.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +X509_object_get_subject(x509_object *self, PyObject *args) +{ + PyObject *result_list = NULL; + X509_NAME *name = NULL; + int format=SHORTNAME_FORMAT; + + if (!PyArg_ParseTuple(args, "|i", &format)) + goto error; + + if ( !(name = X509_get_subject_name( self->x509 ) ) ) + { PyErr_SetString( SSLErrorObject, "could not get issuers name" ); goto error; } + + if ( !(result_list = X509_object_helper_get_name(name, format) ) ) + { PyErr_SetString( SSLErrorObject, "failed to produce name list" ); goto error; } + + return result_list; + +error: + + return NULL; +} + +static char X509_object_set_subject__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509</memberof>\n" +" <name>setSubject</name>\n" +" <parameter>name</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method is used to set the subjects name.\n" +" <parameter>name</parameter> can be comprised of lists or tuples in\n" +" the format described in the <function>getIssuer</function> method.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +X509_object_set_subject(x509_object *self, PyObject *args) +{ + PyObject *name_sequence = NULL; + X509_NAME *name = NULL; + + if (!PyArg_ParseTuple(args, "O", &name_sequence)) + goto error; + + if ( !( PyTuple_Check( name_sequence ) || PyList_Check(name_sequence) ) ) + { PyErr_SetString( PyExc_TypeError, "Inapropriate type" ); goto error; } + + if ( !(name = X509_NAME_new() ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + if ( !X509_object_helper_set_name(name, name_sequence) ) + { PyErr_SetString( SSLErrorObject, "unable to set new name" ); goto error; } + + if ( !X509_set_subject_name(self->x509,name) ) + { PyErr_SetString( SSLErrorObject, "unable to set name" ); goto error; } + + X509_NAME_free(name); + + return Py_BuildValue(""); + +error: + + return NULL; +} + +static char X509_object_set_issuer__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509</memberof>\n" +" <name>setIssuer</name>\n" +" <parameter>name</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method is used to set the issuers name.\n" +" <parameter>name</parameter> can be comprised of lists or tuples in\n" +" the format described in the <function>getissuer</function> method.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +X509_object_set_issuer(x509_object *self, PyObject *args) +{ + PyObject *name_sequence = NULL; + X509_NAME *name = NULL; + + if (!PyArg_ParseTuple(args, "O", &name_sequence)) + goto error; + + if ( !( PyTuple_Check( name_sequence ) || PyList_Check(name_sequence) ) ) + { PyErr_SetString( PyExc_TypeError, "Inapropriate type" ); goto error; } + + if ( !(name = X509_NAME_new() ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + if ( !X509_object_helper_set_name(name, name_sequence) ) + { PyErr_SetString( SSLErrorObject, "unable to set new name" ); goto error; } + + if ( !X509_set_issuer_name(self->x509,name) ) + { PyErr_SetString( SSLErrorObject, "unable to set name" ); goto error; } + + X509_NAME_free(name); + + return Py_BuildValue(""); + +error: + + if (name) + X509_NAME_free(name); + + return NULL; +} + +static char X509_object_get_not_before__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509</memberof>\n" +" <name>getNotBefore</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" In a change from previous releases, for reasons of portability\n" +" and to avoid hard to fix issues with problems in unreliable time\n" +" functions, this function returns a UTCTime string. You\n" +" can use the function <function>time2utc</function> to convert to a\n" +" string if you like and <function>utc2time</function> to back.\n" +" </para>\n" +" </body>\n" +"</method>\n" + +; + +static PyObject * +X509_object_get_not_before (x509_object *self, PyObject *args) +{ + ASN1_UTCTIME *time; + + if (!PyArg_ParseTuple(args, "")) + goto error; + + return Py_BuildValue("s", self->x509->cert_info->validity->notBefore->data); + +error: + + return NULL; +} + +static char X509_object_get_not_after__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509</memberof>\n" +" <name>getNotAfter</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" In a change from previous releases, for reasons of portability\n" +" and to avoid hard to fix issues with problems in unreliable time\n" +" functions, this function returns a UTCTime string. You\n" +" can use the function <function>time2utc</function> to convert to a\n" +" string if you like and <function>utc2time</function> to back.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +X509_object_get_not_after (x509_object *self, PyObject *args) +{ + ASN1_UTCTIME *time=NULL; + + if (!PyArg_ParseTuple(args, "")) + goto error; + + return Py_BuildValue("s", self->x509->cert_info->validity->notAfter->data); + +error: + + return NULL; +} + +static char X509_object_set_not_after__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509</memberof>\n" +" <name>setNotAfter</name>\n" +" <parameter>time</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" In a change from previous releases, for reasons of portability\n" +" and to avoid hard to fix issues with problems in unreliable time\n" +" functions, this accepts one parameter, a UTCTime string. You\n" +" can use the function <function>time2utc</function> to convert to a\n" +" string if you like and <function>utc2time</function> to back.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +X509_object_set_not_after (x509_object *self, PyObject *args) +{ + //int new_time = 0; + char *new_time=NULL; + + if (!PyArg_ParseTuple(args, "s", &new_time)) + goto error; + + if ( !ASN1_UTCTIME_set_string(self->x509->cert_info->validity->notAfter, new_time) ) + { PyErr_SetString( SSLErrorObject, "could not set time" ); goto error; } + + return Py_BuildValue(""); + +error: + + return NULL; +} + +static char X509_object_set_not_before__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509</memberof>\n" +" <name>setNotBefore</name>\n" +" <parameter>time</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" In a change from previous releases, for reasons of portability\n" +" and to avoid hard to fix issues with problems in unreliable time\n" +" functions, this accepts one parameter, a UTCTime string. You\n" +" can use the function <function>time2utc</function> to convert to a\n" +" string if you like and <function>utc2time</function> to back.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +X509_object_set_not_before (x509_object *self, PyObject *args) +{ + //int new_time = 0; + char *new_time=NULL; + + if (!PyArg_ParseTuple(args, "s", &new_time)) + goto error; + + if ( !ASN1_UTCTIME_set_string(self->x509->cert_info->validity->notBefore, new_time) ) + { PyErr_SetString( SSLErrorObject, "could not set time" ); goto error; } + + return Py_BuildValue(""); + +error: + + return NULL; +} + +static char X509_object_add_extension__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509</memberof>\n" +" <name>addExtension</name>\n" +" <parameter>extensionName</parameter>\n" +" <parameter>critical</parameter>\n" +" <parameter>extensionValue</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method adds an extension to this certificate.\n" +" <parameter>extensionName</parameter> should be the of the\n" +" extension. <parameter>critical</parameter> should an integer, 1\n" +" for true and 0 for false. <parameter>extensionValue</parameter>\n" +" should be a string, DER encoded value of the extension. The name\n" +" of the extension must be correct according to OpenSSL and can be\n" +" checked in the <constant>objects.h</constant> header file, part of\n" +" the OpenSSL source distribution. In the majority of cases they\n" +" are the same as those defined in <constant>POW._oids</constant>\n" +" but if you do encounter problems is may be worth checking.\n" +" </para>\n" +" <example>\n" +" <title><function>addExtension</function> method usage</title>\n" +" <programlisting>\n" +" basic = POW.pkix.BasicConstraints()\n" +" basic.set([1,5]) \n" +" serverCert.addExtension( 'basicConstraints', 0, basic.toString())\n" +" </programlisting>\n" +" </example>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +X509_object_add_extension(x509_object *self, PyObject *args) +{ + int critical=0, nid=0; + char *name=NULL, *buf=NULL; + ASN1_OCTET_STRING *octetString=NULL; + X509_EXTENSION *extn=NULL; + + if (!PyArg_ParseTuple(args, "sis", &name, &critical, &buf)) + goto error; + + if ( !(octetString = M_ASN1_OCTET_STRING_new() ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + if ( !ASN1_OCTET_STRING_set(octetString, buf, strlen(buf)) ) + { PyErr_SetString( SSLErrorObject, "could not set ASN1 Octect string" ); goto error; } + + if ( NID_undef == (nid = OBJ_txt2nid(name) ) ) + { PyErr_SetString( SSLErrorObject, "extension has unknown object identifier" ); goto error; } + + if ( !( extn = X509_EXTENSION_create_by_NID(NULL, nid, critical, octetString) ) ) + { PyErr_SetString( SSLErrorObject, "unable to create ASN1 X509 Extension object" ); goto error; } + + if (!self->x509->cert_info->extensions) + if ( !(self->x509->cert_info->extensions = sk_X509_EXTENSION_new_null() ) ) + { PyErr_SetString( SSLErrorObject, "unable to allocate memory" ); goto error; } + + if ( !sk_X509_EXTENSION_push(self->x509->cert_info->extensions, extn) ) + { PyErr_SetString( SSLErrorObject, "unable to add extension" ); goto error; } + + return Py_BuildValue(""); + +error: + + if(extn) + X509_EXTENSION_free(extn); + + return NULL; +} + +static char X509_object_clear_extensions__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509</memberof>\n" +" <name>clearExtensions</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method clears the structure which holds the extension for\n" +" this certificate.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +X509_object_clear_extensions(x509_object *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + goto error; + + if (self->x509->cert_info->extensions) + { + sk_X509_EXTENSION_free(self->x509->cert_info->extensions); + self->x509->cert_info->extensions=NULL; + } + + return Py_BuildValue(""); + +error: + + return NULL; +} + +static char X509_object_count_extensions__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509</memberof>\n" +" <name>countExtensions</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method returns the size of the structure which holds the\n" +" extension for this certificate.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +X509_object_count_extensions(x509_object *self, PyObject *args) +{ + int num=0; + if (!PyArg_ParseTuple(args, "")) + goto error; + + if (self->x509->cert_info->extensions) + { + num = sk_X509_EXTENSION_num(self->x509->cert_info->extensions); + return Py_BuildValue("i", num); + } + else + return Py_BuildValue("i", 0); + +error: + + return NULL; +} + +static char X509_object_get_extension__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509</memberof>\n" +" <name>getExtension</name>\n" +" <parameter>index</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method returns a tuple equivalent the parameters of\n" +" <function>addExtension</function>.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +X509_object_get_extension(x509_object *self, PyObject *args) +{ + int num=0, index=0, ext_nid=0; + char const *ext_ln=NULL; + char unknown_ext [] = "unkown"; + X509_EXTENSION *ext; + if (!PyArg_ParseTuple(args, "i", &index)) + goto error; + + if (self->x509->cert_info->extensions) + { + num = sk_X509_EXTENSION_num(self->x509->cert_info->extensions); + } + else + num = 0; + + if (index >= num) + { PyErr_SetString( SSLErrorObject, "certificate does not have that many extensions" ); goto error; } + + if ( !(ext = sk_X509_EXTENSION_value(self->x509->cert_info->extensions, index) ) ) + { PyErr_SetString( SSLErrorObject, "could not get extension" ); goto error; } + + if ( NID_undef == (ext_nid = OBJ_obj2nid(ext->object) ) ) + { PyErr_SetString( SSLErrorObject, "extension has unknown object identifier" ); goto error; } + + if ( NULL == (ext_ln = OBJ_nid2sn(ext_nid) ) ) + ext_ln = unknown_ext; + + return Py_BuildValue("sis", ext_ln, ext->critical, ext->value->data ); + +error: + + return NULL; +} + +static char x509_object_pprint__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509</memberof>\n" +" <name>pprint</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method returns a formatted string showing the information\n" +" held in the certificate.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +x509_object_pprint(x509_object *self, PyObject *args) +{ + int len=0, ret=0; + char *buf=NULL; + BIO *out_bio=NULL; + PyObject *cert=NULL; + + if (!PyArg_ParseTuple(args, "")) + goto error; + + out_bio = BIO_new(BIO_s_mem()); + + if (!X509_print(out_bio, self->x509) ) + { PyErr_SetString( SSLErrorObject, "unable to write crl" ); goto error; } + + if ( !(len = BIO_ctrl_pending(out_bio) ) ) + { PyErr_SetString( SSLErrorObject, "unable to get bytes stored in bio" ); goto error; } + + if ( !(buf = malloc(len) ) ) + { PyErr_SetString( SSLErrorObject, "unable to allocate memory" ); goto error; } + + if ( (ret = BIO_read( out_bio, buf, len ) ) != len ) + { PyErr_SetString( SSLErrorObject, "unable to write out cert" ); goto error; } + + cert = Py_BuildValue("s#", buf, len); + + BIO_free(out_bio); + free(buf); + return cert; + +error: + + if (out_bio) + BIO_free(out_bio); + + if (buf) + free(buf); + + return NULL; + +} + +static struct PyMethodDef X509_object_methods[] = { + {"pemWrite", (PyCFunction)X509_object_pem_write, METH_VARARGS, NULL}, + {"derWrite", (PyCFunction)X509_object_der_write, METH_VARARGS, NULL}, + {"sign", (PyCFunction)X509_object_sign, METH_VARARGS, NULL}, + {"setPublicKey", (PyCFunction)X509_object_set_public_key, METH_VARARGS, NULL}, + {"getVersion", (PyCFunction)X509_object_get_version, METH_VARARGS, NULL}, + {"setVersion", (PyCFunction)X509_object_set_version, METH_VARARGS, NULL}, + {"getSerial", (PyCFunction)X509_object_get_serial, METH_VARARGS, NULL}, + {"setSerial", (PyCFunction)X509_object_set_serial, METH_VARARGS, NULL}, + {"getIssuer", (PyCFunction)X509_object_get_issuer, METH_VARARGS, NULL}, + {"setIssuer", (PyCFunction)X509_object_set_issuer, METH_VARARGS, NULL}, + {"getSubject", (PyCFunction)X509_object_get_subject, METH_VARARGS, NULL}, + {"setSubject", (PyCFunction)X509_object_set_subject, METH_VARARGS, NULL}, + {"getNotBefore", (PyCFunction)X509_object_get_not_before, METH_VARARGS, NULL}, + {"getNotAfter", (PyCFunction)X509_object_get_not_after, METH_VARARGS, NULL}, + {"setNotAfter", (PyCFunction)X509_object_set_not_after, METH_VARARGS, NULL}, + {"setNotBefore", (PyCFunction)X509_object_set_not_before, METH_VARARGS, NULL}, + {"addExtension", (PyCFunction)X509_object_add_extension, METH_VARARGS, NULL}, + {"clearExtensions",(PyCFunction)X509_object_clear_extensions, METH_VARARGS, NULL}, + {"countExtensions",(PyCFunction)X509_object_count_extensions, METH_VARARGS, NULL}, + {"getExtension", (PyCFunction)X509_object_get_extension, METH_VARARGS, NULL}, + {"pprint", (PyCFunction)x509_object_pprint, METH_VARARGS, NULL}, + + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +X509_object_getattr(x509_object *self, char *name) +{ + return Py_FindMethod(X509_object_methods, (PyObject *)self, name); +} + +static void +X509_object_dealloc(x509_object *self, char *name) +{ + X509_free( self->x509 ); + PyObject_Del(self); +} + +static char x509type__doc__[] = +"<class>\n" +" <header>\n" +" <name>X509</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This class provides access to a significant proportion of X509 \n" +" functionality of OpenSSL.\n" +" </para>\n" +"\n" +" <example>\n" +" <title><classname>x509</classname> class usage</title>\n" +" <programlisting>\n" +" privateFile = open('test/private.key', 'r')\n" +" publicFile = open('test/public.key', 'r')\n" +" certFile = open('test/cacert.pem', 'w')\n" +"\n" +" publicKey = POW.pemRead(POW.RSA_PUBLIC_KEY, publicFile.read())\n" +" privateKey = POW.pemRead(POW.RSA_PRIVATE_KEY, privateFile.read(), 'pass')\n" +"\n" +" c = POW.X509()\n" +"\n" +" name = [ ['C', 'GB'], ['ST', 'Hertfordshire'], \n" +" ['O','The House'], ['CN', 'Peter Shannon'] ]\n" +"\n" +" c.setIssuer( name )\n" +" c.setSubject( name )\n" +" c.setSerial(0)\n" +" t1 = POW.pkix.time2utc( time.time() ) \n" +" t2 = POW.pkix.time2utc( time.time() + 60*60*24*365) \n" +" c.setNotBefore(t1)\n" +" c.setNotAfter(t2)\n" +" c.setPublicKey(publicKey)\n" +" c.sign(privateKey)\n" +"\n" +" certFile.write( c.pemWrite() )\n" +"\n" +" privateFile.close()\n" +" publicFile.close()\n" +" certFile.close()\n" +" </programlisting>\n" +" </example>\n" +"\n" +" </body>\n" +"</class>\n" +; + +static PyTypeObject x509type = { + PyObject_HEAD_INIT(0) + 0, /*ob_size*/ + "X509", /*tp_name*/ + sizeof(x509_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)X509_object_dealloc, /*tp_dealloc*/ + (printfunc)0, /*tp_print*/ + (getattrfunc)X509_object_getattr, /*tp_getattr*/ + (setattrfunc)0, /*tp_setattr*/ + (cmpfunc)0, /*tp_compare*/ + (reprfunc)0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + (hashfunc)0, /*tp_hash*/ + (ternaryfunc)0, /*tp_call*/ + (reprfunc)0, /*tp_str*/ + 0, + 0, + 0, + 0, + x509type__doc__ /* Documentation string */ +}; +/*========== X509 Code ==========*/ + +/*========== x509 store Code ==========*/ +static x509_store_object * +x509_store_object_new(void) +{ + x509_store_object *self=NULL; + + self = PyObject_New( x509_store_object, &x509_storetype ); + if (self == NULL) + goto error; + + self->store = X509_STORE_new(); + + return self; + +error: + + Py_XDECREF(self); + return NULL; +} + +static char x509_store_object_verify__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Store</memberof>\n" +" <name>verify</name>\n" +" <parameter>certificate</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" The <classname>X509Store</classname> method\n" +" <function>verify</function> is based on the\n" +" <function>X509_verify_cert</function>. It handles certain aspects\n" +" of verification but not others. The certificate will be verified\n" +" against <constant>notBefore</constant>, \n" +" <constant>notAfter</constant> and trusted certificates.\n" +" It crucially will not handle checking the certificate against\n" +" CRLs. This functionality will probably make it into OpenSSL\n" +" 0.9.7.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +x509_store_object_verify(x509_store_object *self, PyObject *args) +{ + X509_STORE_CTX csc; + x509_object *x509=NULL; + int result=0; + + if (!PyArg_ParseTuple(args, "O!", &x509type, &x509)) + goto error; + + X509_STORE_CTX_init( &csc, self->store, x509->x509, NULL ); + result = X509_verify_cert( &csc ); + + X509_STORE_CTX_cleanup( &csc ); + + return Py_BuildValue("i", result); + +error: + + return NULL; +} + +static char x509_store_object_verify_chain__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Store</memberof>\n" +" <name>verifyChain</name>\n" +" <parameter>certificate</parameter>\n" +" <parameter>chain</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" The <classname>X509Store</classname> method <function>verifyChain</function> \n" +" is based on the <function>X509_verify_cert</function> but is initialised \n" +" with a <classname>X509</classname> object to verify and list of \n" +" <classname>X509</classname> objects which form a chain to a trusted \n" +" certificate. Certain aspects of the verification are handled but not others. \n" +" The certificates will be verified against <constant>notBefore</constant>, \n" +" <constant>notAfter</constant> and trusted certificates. It crucially will \n" +" not handle checking the certificate against CRLs. This functionality will \n" +" probably make it into OpenSSL 0.9.7.\n" +" </para>\n" +" <para>\n" +" This may all sound quite straight forward but determining the \n" +" certificate associated with the signature on another certificate\n" +" can be very time consuming. The management aspects of\n" +" certificates are addressed by various V3 extensions which are not\n" +" currently supported.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +x509_store_object_verify_chain(x509_store_object *self, PyObject *args) +{ + PyObject *x509_sequence=NULL; + X509_STORE_CTX csc; + x509_object *x509=NULL, *tmpX509=NULL; + STACK_OF(X509) *x509_stack=NULL; + int result=0, size=0, i=0; + + if (!PyArg_ParseTuple(args, "O!O", &x509type, &x509, &x509_sequence)) + goto error; + + if ( !( PyTuple_Check( x509_sequence ) || PyList_Check(x509_sequence) ) ) + { PyErr_SetString( PyExc_TypeError, "inapropriate type" ); goto error; } + + size = PySequence_Size( x509_sequence ); + + if (!(x509_stack = sk_X509_new_null() ) ) + { PyErr_SetString( SSLErrorObject, "could not create new x509 stack" ); goto error; } + + for (i=0; i < size; i++) + { + if ( !( tmpX509 = (x509_object*)PySequence_GetItem( x509_sequence, i ) ) ) + goto error; + + if ( !X_X509_Check( tmpX509 ) ) + { PyErr_SetString( PyExc_TypeError, "inapropriate type" ); goto error; } + + if (!sk_X509_push( x509_stack, tmpX509->x509 ) ) + { PyErr_SetString( SSLErrorObject, "could not add x509 to stack" ); goto error; } + Py_DECREF(tmpX509); + tmpX509 = NULL; + } + + X509_STORE_CTX_init( &csc, self->store, x509->x509, x509_stack ); + result = X509_verify_cert( &csc ); + + X509_STORE_CTX_cleanup( &csc ); + sk_X509_free(x509_stack); + return Py_BuildValue("i", result); + +error: + + if(x509_stack) + sk_X509_free(x509_stack); + + Py_XDECREF(tmpX509); + + return NULL; +} + +static char x509_store_object_add_trust__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Store</memberof>\n" +" <name>addTrust</name>\n" +" <parameter>cert</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method adds a new certificate to the store to be used in the\n" +" verification process. <parameter>cert</parameter> should be an\n" +" instance of <classname>X509</classname>. Using trusted certificates to manage\n" +" verification is relatively primitive, more sophisticated systems\n" +" can be constructed at an application level by by constructing\n" +" certificate chains to verify. \n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +x509_store_object_add_trust(x509_store_object *self, PyObject *args) +{ + x509_object *x509=NULL; + + if (!PyArg_ParseTuple(args, "O!", &x509type, &x509)) + goto error; + + X509_STORE_add_cert( self->store, x509->x509 ); + + return Py_BuildValue(""); + +error: + + return NULL; +} + +static char x509_store_object_add_crl__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Store</memberof>\n" +" <name>addCrl</name>\n" +" <parameter>crl</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method adds a CRL to a store to be used for verification.\n" +" <parameter>crl</parameter> should be an instance of\n" +" <classname>X509Crl</classname>.\n" +" Unfortunately, the current stable release of OpenSSL does not\n" +" support CRL checking for certificate verification.\n" +" This functionality will probably make it into OpenSSL 0.9.7, until\n" +" it does this function is useless and CRL verification must be\n" +" implemented by the application.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +x509_store_object_add_crl(x509_store_object *self, PyObject *args) +{ + x509_crl_object *crl=NULL; + + if (!PyArg_ParseTuple(args, "O!", &x509_crltype, &crl)) + goto error; + + X509_STORE_add_crl( self->store, crl->crl ); + + return Py_BuildValue(""); + +error: + + return NULL; +} + +static struct PyMethodDef x509_store_object_methods[] = { + {"verify", (PyCFunction)x509_store_object_verify, METH_VARARGS, NULL}, + {"verifyChain", (PyCFunction)x509_store_object_verify_chain, METH_VARARGS, NULL}, + {"addTrust", (PyCFunction)x509_store_object_add_trust, METH_VARARGS, NULL}, + {"addCrl", (PyCFunction)x509_store_object_add_crl, METH_VARARGS, NULL}, + + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +x509_store_object_getattr(x509_store_object *self, char *name) +{ + return Py_FindMethod(x509_store_object_methods, (PyObject *)self, name); +} + +static void +x509_store_object_dealloc(x509_store_object *self, char *name) +{ + X509_STORE_free( self->store ); + PyObject_Del(self); +} + +static char x509_storetype__doc__[] = +"<class>\n" +" <header>\n" +" <name>X509Store</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This class provides preliminary access to OpenSSL X509 verification\n" +" facilities.\n" +" </para>\n" +"\n" +" <example>\n" +" <title><classname>x509_store</classname> class usage</title>\n" +" <programlisting>\n" +" store = POW.X509Store()\n" +"\n" +" caFile = open( 'test/cacert.pem', 'r' )\n" +" ca = POW.pemRead( POW.X509_CERTIFICATE, caFile.read() )\n" +" caFile.close()\n" +"\n" +" store.addTrust( ca )\n" +"\n" +" certFile = open( 'test/foocom.cert', 'r' )\n" +" x509 = POW.pemRead( POW.X509_CERTIFICATE, certFile.read() )\n" +" certFile.close()\n" +"\n" +" print x509.pprint()\n" +" \n" +" if store.verify( x509 ):\n" +" print 'Verified certificate!.'\n" +" else:\n" +" print 'Failed to verify certificate!.'\n" +" </programlisting>\n" +" </example>\n" +" </body>\n" +"</class>\n" +; + +static PyTypeObject x509_storetype = { + PyObject_HEAD_INIT(0) + 0, /*ob_size*/ + "X509Store", /*tp_name*/ + sizeof(x509_store_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)x509_store_object_dealloc, /*tp_dealloc*/ + (printfunc)0, /*tp_print*/ + (getattrfunc)x509_store_object_getattr, /*tp_getattr*/ + (setattrfunc)0, /*tp_setattr*/ + (cmpfunc)0, /*tp_compare*/ + (reprfunc)0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + (hashfunc)0, /*tp_hash*/ + (ternaryfunc)0, /*tp_call*/ + (reprfunc)0, /*tp_str*/ + 0, + 0, + 0, + 0, + x509_storetype__doc__ /* Documentation string */ +}; +/*========== x509 store Code ==========*/ + +/*========== x509 crl Code ==========*/ +static x509_crl_object * +x509_crl_object_new(void) +{ + x509_crl_object *self=NULL; + + self = PyObject_New( x509_crl_object, &x509_crltype ); + if (self == NULL) + goto error; + + self->crl = X509_CRL_new(); + + return self; + +error: + + Py_XDECREF(self); + return NULL; +} + +static x509_crl_object * +x509_crl_object_pem_read(BIO *in) +{ + x509_crl_object *self; + + self = PyObject_New( x509_crl_object, &x509_crltype ); + if (self == NULL) + goto error; + + if( !(self->crl = PEM_read_bio_X509_CRL( in, NULL, NULL, NULL ) ) ) + { PyErr_SetString( SSLErrorObject, "could not load certificate" ); goto error; } + + return self; + +error: + + Py_XDECREF(self); + return NULL; +} + +static x509_crl_object * +x509_crl_object_der_read(char *src, int len) +{ + x509_crl_object *self; + unsigned char* ptr = src; + + if ( !(self = PyObject_New( x509_crl_object, &x509_crltype ) ) ) + goto error; + + self->crl = X509_CRL_new(); + + if( !(d2i_X509_CRL( &self->crl, &ptr, len ) ) ) + { PyErr_SetString( SSLErrorObject, "could not load PEM encoded CRL" ); goto error; } + + return self; + +error: + + Py_XDECREF(self); + return NULL; +} + +static char x509_crl_object_get_version__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Crl</memberof>\n" +" <name>getVersion</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method returns the version number from the version field of\n" +" this CRL. \n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +x509_crl_object_get_version(x509_crl_object *self, PyObject *args) +{ + long version=0; + + if (!PyArg_ParseTuple(args, "")) + goto error; + + if ( (version = ASN1_INTEGER_get( self->crl->crl->version ) ) == -1 ) + { PyErr_SetString( SSLErrorObject, "could not get crl version" ); goto error; } + + return Py_BuildValue("l", version); + +error: + + return NULL; +} + +static char x509_crl_object_set_version__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Crl</memberof>\n" +" <name>setVersion</name>\n" +" <parameter>version</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method sets the version number in the version field of\n" +" this CRL. <parameter>version</parameter> should be an\n" +" integer.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +x509_crl_object_set_version(x509_crl_object *self, PyObject *args) +{ + long version=0; + ASN1_INTEGER *asn1_version=NULL; + + if (!PyArg_ParseTuple(args, "i", &version)) + goto error; + + if ( !(asn1_version = ASN1_INTEGER_new() ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + if ( !ASN1_INTEGER_set( asn1_version, version ) ) + { PyErr_SetString( SSLErrorObject, "could not get set version" ); goto error; } + + self->crl->crl->version = asn1_version; + + return Py_BuildValue(""); + +error: + + if (asn1_version) + ASN1_INTEGER_free(asn1_version); + + return NULL; +} + +static char x509_crl_object_get_issuer__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Crl</memberof>\n" +" <name>getIssuer</name>\n" +" <parameter>format=SHORTNAME_FORMAT</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method returns a tuple containing the issuers name. See the\n" +" <function>getIssuer</function> method of\n" +" <classname>X509</classname> for more details.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +x509_crl_object_get_issuer(x509_crl_object *self, PyObject *args) +{ + PyObject *result_list = NULL; + int format=SHORTNAME_FORMAT; + + if (!PyArg_ParseTuple(args, "|i", &format)) + goto error; + + if ( !(result_list = X509_object_helper_get_name(self->crl->crl->issuer, format) ) ) + { PyErr_SetString( SSLErrorObject, "failed to produce name list" ); goto error; } + + return result_list; + +error: + + return NULL; +} + +static char x509_crl_object_set_issuer__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Crl</memberof>\n" +" <name>setIssuer</name>\n" +" <parameter>name</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method is used to set the issuers name.\n" +" <parameter>name</parameter> can be comprised of lists or tuples in\n" +" the format described in the <function>getIssuer</function> method\n" +" of <classname>X509</classname>.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +x509_crl_object_set_issuer(x509_crl_object *self, PyObject *args) +{ + PyObject *name_sequence = NULL; + X509_NAME *name = NULL; + + if (!PyArg_ParseTuple(args, "O", &name_sequence)) + goto error; + + if ( !( PyTuple_Check( name_sequence ) || PyList_Check(name_sequence) ) ) + { PyErr_SetString( PyExc_TypeError, "Inapropriate type" ); goto error; } + + if ( !(name = X509_NAME_new() ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + if ( !X509_object_helper_set_name(name, name_sequence) ) + { PyErr_SetString( SSLErrorObject, "unable to set new name" ); goto error; } + + if ( !X509_NAME_set(&self->crl->crl->issuer,name ) ) + { PyErr_SetString( SSLErrorObject, "unable to set name" ); goto error; } + + X509_NAME_free(name); + + return Py_BuildValue(""); + +error: + + if (name) + X509_NAME_free(name); + + return NULL; +} + +static char x509_crl_object_set_this_update__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Crl</memberof>\n" +" <name>setThisUpdate</name>\n" +" <parameter>time</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" In a change from previous releases, for reasons of portability\n" +" and to avoid hard to fix issues with problems in unreliable time\n" +" functions, this accepts one parameter, a UTCTime string. You\n" +" can use the function <function>time2utc</function> to convert to a\n" +" string if you like and <function>utc2time</function> to back.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +x509_crl_object_set_this_update (x509_crl_object *self, PyObject *args) +{ + //int new_time = 0; + char *new_time=NULL; + + if (!PyArg_ParseTuple(args, "s", &new_time)) + goto error; + + if ( !ASN1_UTCTIME_set_string(self->crl->crl->lastUpdate,new_time) ) + { PyErr_SetString( SSLErrorObject, "could not set time" ); goto error; } + + return Py_BuildValue(""); + +error: + + return NULL; +} + +static char x509_crl_object_get_this_update__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Crl</memberof>\n" +" <name>getThisUpdate</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" In a change from previous releases, for reasons of portability\n" +" and to avoid hard to fix issues with problems in unreliable time\n" +" functions, this function returns a UTCTime string. You\n" +" can use the function <function>time2utc</function> to convert to a\n" +" string if you like and <function>utc2time</function> to back.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +x509_crl_object_get_this_update (x509_crl_object *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + goto error; + + return Py_BuildValue("s", self->crl->crl->lastUpdate->data); + +error: + + return NULL; +} + +static char x509_crl_object_set_next_update__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Crl</memberof>\n" +" <name>setNextUpdate</name>\n" +" <parameter>time</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" In a change from previous releases, for reasons of portability\n" +" and to avoid hard to fix issues with problems in unreliable time\n" +" functions, this accepts one parameter, a UTCTime string. You\n" +" can use the function <function>time2utc</function> to convert to a\n" +" string if you like and <function>utc2time</function> to back.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +x509_crl_object_set_next_update (x509_crl_object *self, PyObject *args) +{ + //int new_time = 0; + char *new_time=NULL; + ASN1_UTCTIME *time=NULL; + + if (!PyArg_ParseTuple(args, "s", &new_time)) + goto error; + + if (self->crl->crl->nextUpdate == NULL) + if ( !(time = ASN1_UTCTIME_new() ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + self->crl->crl->nextUpdate = time; + + if (!ASN1_UTCTIME_set_string(time, new_time) ) + { PyErr_SetString( SSLErrorObject, "could not set next update" ); goto error; } + + + return Py_BuildValue(""); + +error: + + return NULL; +} + +static char x509_crl_object_get_next_update__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Crl</memberof>\n" +" <name>getNextUpdate</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" In a change from previous releases, for reasons of portability\n" +" and to avoid hard to fix issues with problems in unreliable time\n" +" functions, this function returns a UTCTime string. You\n" +" can use the function <function>time2utc</function> to convert to a\n" +" string if you like and <function>utc2time</function> to back.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +x509_crl_object_get_next_update (x509_crl_object *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + goto error; + + return Py_BuildValue("s", self->crl->crl->nextUpdate->data); + +error: + + return NULL; +} + +static char x509_crl_object_set_revoked__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Crl</memberof>\n" +" <name>setRevoked</name>\n" +" <parameter>revoked</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method sets the sequence of revoked certificates in this CRL.\n" +" <parameter>revoked</parameter> should be a list or tuple of \n" +" <classname>X509Revoked</classname>.\n" +" </para>\n" +" <example>\n" +" <title><function>setRevoked</function> function usage</title>\n" +" <programlisting>\n" +" privateFile = open('test/private.key', 'r')\n" +" publicFile = open('test/public.key', 'r')\n" +" crlFile = open('test/crl.pem', 'w')\n" +"\n" +" publicKey = POW.pemRead(POW.RSA_PUBLIC_KEY, publicFile.read())\n" +" privateKey = POW.pemRead(POW.RSA_PRIVATE_KEY, privateFile.read(), 'pass')\n" +"\n" +" crl = POW.X509Crl()\n" +"\n" +" name = [ ['C', 'GB'], ['ST', 'Hertfordshire'], \n" +" ['O','The House'], ['CN', 'Peter Shannon'] ]\n" +"\n" +" t1 = POW.pkix.time2utc( time.time() ) \n" +" t2 = POW.pkix.time2utc( time.time() + 60*60*24*365) \n" +" crl.setIssuer( name )\n" +" rev = [ POW.X509Revoked(3, t1),\n" +" POW.X509Revoked(4, t1),\n" +" POW.X509Revoked(5, t1) ]\n" +"\n" +" crl.setRevoked( rev )\n" +" crl.setThisUpdate(t1)\n" +" crl.setNextUpdate(t2)\n" +" crl.sign(privateKey)\n" +"\n" +" crlFile.write( crl.pemWrite() )\n" +"\n" +" privateFile.close()\n" +" publicFile.close()\n" +" crlFile.close()\n" +" </programlisting>\n" +" </example>\n" +"\n" +" </body>\n" +"</method>\n" +; + +// added because we don't already have one! +static X509_REVOKED * +X509_REVOKED_dup(X509_REVOKED *rev) +{ + return((X509_REVOKED *)ASN1_dup((int (*)())i2d_X509_REVOKED, + (char *(*)())d2i_X509_REVOKED,(char *)rev)); +} + +static PyObject * +x509_crl_object_set_revoked(x509_crl_object *self, PyObject *args) +{ + PyObject *revoked_sequence = NULL; + x509_revoked_object *revoked = NULL; + STACK_OF(X509_REVOKED) *revoked_stack = NULL; + X509_REVOKED *tmp_revoked = NULL; + int i=0,size=0; + + if (!PyArg_ParseTuple(args, "O", &revoked_sequence)) + goto error; + + if ( !( PyTuple_Check( revoked_sequence ) || PyList_Check(revoked_sequence) ) ) + { PyErr_SetString( PyExc_TypeError, "inapropriate type" ); goto error; } + + revoked_stack = self->crl->crl->revoked; + + size = PySequence_Size( revoked_sequence ); + for (i=0; i < size; i++) + { + if ( !( revoked = (x509_revoked_object*)PySequence_GetItem( revoked_sequence, i ) ) ) + goto error; + + if ( !X_X509_revoked_Check( revoked ) ) + { PyErr_SetString( PyExc_TypeError, "inapropriate type" ); goto error; } + + if ( !(tmp_revoked = X509_REVOKED_dup( revoked->revoked ) ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + if (!sk_X509_REVOKED_push( revoked_stack, tmp_revoked ) ) + { PyErr_SetString( SSLErrorObject, "could not add revokation to stack" ); goto error; } + + Py_DECREF(revoked); + revoked = NULL; + } + + return Py_BuildValue(""); + +error: + + Py_XDECREF(revoked); + + return NULL; +} + +static PyObject * +x509_crl_object_helper_get_revoked(STACK_OF(X509_REVOKED) *revoked) +{ + int no_entries=0, inlist=0, i=0; + X509_REVOKED *revoke_tmp=NULL; + x509_revoked_object *revoke_obj=NULL; + PyObject *item=NULL, *result_list=NULL, *result_tuple=NULL; + + no_entries = sk_X509_REVOKED_num( revoked ); + + if ( !(result_list = PyList_New(0) ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + for(i=0; i<no_entries; i++) + { + if ( !(revoke_obj = PyObject_New( x509_revoked_object, &x509_revokedtype ) ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + if ( !(revoke_tmp = sk_X509_REVOKED_value( revoked, i ) ) ) + { PyErr_SetString( SSLErrorObject, "could not get revocation" ); goto error; } + + revoke_obj->revoked = revoke_tmp; + + if ( PyList_Append( result_list, (PyObject*)revoke_obj ) != 0) + goto error; + + revoke_obj = NULL; revoke_tmp = NULL; + } + + result_tuple = PyList_AsTuple( result_list ); + Py_DECREF(result_list); + + return Py_BuildValue("O", result_tuple); + +error: + + if (result_list) + { + inlist = PyList_Size( result_list ); + for (i=0; i < inlist; i++) + { + item = PyList_GetItem( result_list, i ); + Py_DECREF(item); + } + Py_DECREF(result_list); + } + + return NULL; +} + +static char x509_crl_object_get_revoked__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Crl</memberof>\n" +" <name>getRevoked</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method returns a tuple of <classname>X509Revoked</classname>\n" +" objects described in the CRL.\n" +" </para>\n" +" <example>\n" +" <title><function>getRevoked</function> function usage</title>\n" +" <programlisting>\n" +" publicFile = open('test/public.key', 'r')\n" +" crlFile = open('test/crl.pem', 'r')\n" +"\n" +" publicKey = POW.pemRead(POW.RSA_PUBLIC_KEY, publicFile.read())\n" +"\n" +" crl = POW.pemRead( POW.X509_CRL, crlFile.read() )\n" +"\n" +" print crl.pprint()\n" +" if crl.verify( publicKey ):\n" +" print 'signature ok!'\n" +" else:\n" +" print 'signature not ok!'\n" +"\n" +" revocations = crl.getRevoked()\n" +" for revoked in revocations:\n" +" print 'serial number:', revoked.getSerial()\n" +" print 'date:', time.ctime( revoked.getDate()[0] )\n" +"\n" +" publicFile.close()\n" +" crlFile.close()\n" +" </programlisting>\n" +" </example>\n" +"\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +x509_crl_object_get_revoked(x509_crl_object *self, PyObject *args) +{ + PyObject *revoked = NULL; + + if (!PyArg_ParseTuple(args, "")) + goto error; + + revoked = x509_crl_object_helper_get_revoked( X509_CRL_get_REVOKED(self->crl) ); + + return revoked; + +error: + + return NULL; +} + +static char X509_crl_object_add_extension__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Crl</memberof>\n" +" <name>addExtension</name>\n" +" <parameter>extensionName</parameter>\n" +" <parameter>critical</parameter>\n" +" <parameter>extensionValue</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method adds an extension to this CRL.\n" +" <parameter>extensionName</parameter> should be the of the\n" +" extension. <parameter>critical</parameter> should an integer, 1\n" +" for true and 0 for clase. <parameter>extensionValue</parameter>\n" +" should be a string, DER encoded value of the extension. The name\n" +" of the extension must be correct according to OpenSSL and can be\n" +" checkd in the <constant>objects.h</constant> header file, part of\n" +" the OpenSSL source distrobution. In the majority of cases they\n" +" are the same as those defined in <constant>POW._oids</constant>\n" +" but if you do encounter problems is may be worth checking.\n" +" </para>\n" +" <example>\n" +" <title><function>addExtension</function> method usage</title>\n" +" <programlisting>\n" +" oids = POW.pkix.OidData()\n" +" o2i = oids.obj2oid\n" +"\n" +" n1 = ('directoryName', ( (( o2i('countryName'), ('printableString', 'UK') ),), \n" +" (( o2i('stateOrProvinceName'), ('printableString', 'Herts') ),), \n" +" (( o2i('organizationName'), ('printableString', 'The House') ),),\n" +" (( o2i('commonName'), ('printableString', 'Shannon Works') ),) ) ) \n" +"\n" +" n2 = ('rfc822Name', 'peter_shannon@yahoo.com')\n" +" n3 = ('uri', 'http://www.p-s.org.uk') \n" +" n4 = ('iPAddress', (192,168,100,51)) \n" +"\n" +" issuer = POW.pkix.IssuerAltName()\n" +" issuer.set([n1,n2,n3,n4]) \n" +" crl.addExtension( 'issuerAltName', 0, issuer.toString() )\n" +" </programlisting>\n" +" </example>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +X509_crl_object_add_extension(x509_crl_object *self, PyObject *args) +{ + int critical=0, nid=0; + char *name=NULL, *buf=NULL; + ASN1_OCTET_STRING *octetString=NULL; + X509_EXTENSION *extn=NULL; + + if (!PyArg_ParseTuple(args, "sis", &name, &critical, &buf)) + goto error; + + if ( !(octetString = M_ASN1_OCTET_STRING_new() ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + if ( !ASN1_OCTET_STRING_set(octetString, buf, strlen(buf)) ) + { PyErr_SetString( SSLErrorObject, "could not set ASN1 Octect string" ); goto error; } + + if ( NID_undef == (nid = OBJ_txt2nid(name) ) ) + { PyErr_SetString( SSLErrorObject, "extension has unknown object identifier" ); goto error; } + + if ( !( extn = X509_EXTENSION_create_by_NID(NULL, nid, critical, octetString) ) ) + { PyErr_SetString( SSLErrorObject, "unable to create ASN1 X509 Extension object" ); goto error; } + + if (!self->crl->crl->extensions) + if ( !(self->crl->crl->extensions = sk_X509_EXTENSION_new_null() ) ) + { PyErr_SetString( SSLErrorObject, "unable to allocate memory" ); goto error; } + + if ( !sk_X509_EXTENSION_push(self->crl->crl->extensions, extn) ) + { PyErr_SetString( SSLErrorObject, "unable to add extension" ); goto error; } + + return Py_BuildValue(""); + +error: + + if(extn) + X509_EXTENSION_free(extn); + + return NULL; +} + +static char X509_crl_object_clear_extensions__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Crl</memberof>\n" +" <name>clearExtensions</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method clears the structure which holds the extension for\n" +" this CRL.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +X509_crl_object_clear_extensions(x509_crl_object *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + goto error; + + if (self->crl->crl->extensions) + { + sk_X509_EXTENSION_free(self->crl->crl->extensions); + self->crl->crl->extensions=NULL; + } + + return Py_BuildValue(""); + +error: + + return NULL; +} + +static char X509_crl_object_count_extensions__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Crl</memberof>\n" +" <name>countExtensions</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method returns the size of the structure which holds the\n" +" extension for this CRL.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +X509_crl_object_count_extensions(x509_crl_object *self, PyObject *args) +{ + int num=0; + if (!PyArg_ParseTuple(args, "")) + goto error; + + if (self->crl->crl->extensions) + { + num = sk_X509_EXTENSION_num(self->crl->crl->extensions); + return Py_BuildValue("i", num); + } + else + return Py_BuildValue("i", 0); + +error: + + return NULL; +} + +static char X509_crl_object_get_extension__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Crl</memberof>\n" +" <name>getExtension</name>\n" +" <parameter>index</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method returns a tuple equivalent the parameters of\n" +" <function>addExtension</function>.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +X509_crl_object_get_extension(x509_crl_object *self, PyObject *args) +{ + int num=0, index=0, ext_nid=0; + char const *ext_ln=NULL; + char unknown_ext [] = "unkown"; + X509_EXTENSION *ext; + if (!PyArg_ParseTuple(args, "i", &index)) + goto error; + + if (self->crl->crl->extensions) + { + num = sk_X509_EXTENSION_num(self->crl->crl->extensions); + } + else + num = 0; + + if (index >= num) + { PyErr_SetString( SSLErrorObject, "certificate does not have that many extensions" ); goto error; } + + if ( !(ext = sk_X509_EXTENSION_value(self->crl->crl->extensions, index) ) ) + { PyErr_SetString( SSLErrorObject, "could not get extension" ); goto error; } + + if ( NID_undef == (ext_nid = OBJ_obj2nid(ext->object) ) ) + { PyErr_SetString( SSLErrorObject, "extension has unknown object identifier" ); goto error; } + + if ( NULL == (ext_ln = OBJ_nid2sn(ext_nid) ) ) + ext_ln = unknown_ext; + + return Py_BuildValue("sis", ext_ln, ext->critical, ext->value->data ); + +error: + + return NULL; +} + +static char x509_crl_object_sign__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Crl</memberof>\n" +" <name>sign</name>\n" +" <parameter>key</parameter>\n" +" <parameter>digest=MD5_DIGEST</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" <parameter>key</parameter> should be an instance of\n" +" <classname>Asymmetric</classname> and contain a private key.\n" +" <parameter>digest</parameter> indicates \n" +" which digest function should be used to compute the hash to be \n" +" signed, it should be one of the following:\n" +" </para>\n" +" <simplelist>\n" +" <member><constant>MD2_DIGEST</constant></member>\n" +" <member><constant>MD5_DIGEST</constant></member>\n" +" <member><constant>SHA_DIGEST</constant></member>\n" +" <member><constant>SHA1_DIGEST</constant></member>\n" +" <member><constant>RIPEMD160_DIGEST</constant></member>\n" +" </simplelist>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +x509_crl_object_sign(x509_crl_object *self, PyObject *args) +{ + EVP_PKEY *pkey=NULL; + asymmetric_object *asym; + int digest=MD5_DIGEST; + + if (!PyArg_ParseTuple(args, "O!|i", &asymmetrictype, &asym, &digest)) + goto error; + + if ( !(pkey = EVP_PKEY_new() ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + if (asym->key_type != RSA_PRIVATE_KEY) + { PyErr_SetString( SSLErrorObject, "cannot use this type of key" ); goto error; } + + if ( !(EVP_PKEY_assign_RSA(pkey, asym->cipher) ) ) + { PyErr_SetString( SSLErrorObject, "EVP_PKEY assignment error" ); goto error; } + + switch (digest) + { + case MD5_DIGEST: + { + if (!X509_CRL_sign(self->crl, pkey, EVP_md5() ) ) + { PyErr_SetString( SSLErrorObject, "could not sign certificate" ); goto error; } + break; + } + case MD2_DIGEST: + { + if (!X509_CRL_sign(self->crl, pkey, EVP_md2() ) ) + { PyErr_SetString( SSLErrorObject, "could not sign certificate" ); goto error; } + break; + } + case SHA_DIGEST: + { + if (!X509_CRL_sign(self->crl, pkey, EVP_sha() ) ) + { PyErr_SetString( SSLErrorObject, "could not sign certificate" ); goto error; } + break; + } + case SHA1_DIGEST: + { + if (!X509_CRL_sign(self->crl, pkey, EVP_sha1() ) ) + { PyErr_SetString( SSLErrorObject, "could not sign certificate" ); goto error; } + break; + } + case RIPEMD160_DIGEST: + { + if (!X509_CRL_sign(self->crl, pkey, EVP_ripemd160() ) ) + { PyErr_SetString( SSLErrorObject, "could not sign certificate" ); goto error; } + break; + } + } + + return Py_BuildValue(""); + +error: + + if (pkey) + EVP_PKEY_free(pkey); + + return NULL; + +} + +static char x509_crl_object_verify__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Crl</memberof>\n" +" <name>verify</name>\n" +" <parameter>key</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" The <classname>X509Crl</classname> method\n" +" <function>verify</function> is based on the\n" +" <function>X509_CRL_verify</function> function. Unlike the\n" +" <classname>X509</classname> function of the same name, this\n" +" function simply checks the CRL was signed with the private key\n" +" which corresponds the parameter <parameter>key</parameter>.\n" +" <parameter>key</parameter> should be an instance of\n" +" <classname>Asymmetric</classname> and contain a public key.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +x509_crl_object_verify(x509_crl_object *self, PyObject *args) +{ + int result=0; + EVP_PKEY *pkey=NULL; + asymmetric_object *asym; + + if (!PyArg_ParseTuple(args, "O!", &asymmetrictype, &asym)) + goto error; + + if ( !(pkey = EVP_PKEY_new() ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + if ( !(EVP_PKEY_assign_RSA(pkey, asym->cipher) ) ) + { PyErr_SetString( SSLErrorObject, "EVP_PKEY assignment error" ); goto error; } + + result = X509_CRL_verify(self->crl,pkey); + + return Py_BuildValue("i", result); + +error: + + if (pkey) + EVP_PKEY_free(pkey); + + return NULL; + +} + +static PyObject * +x509_crl_object_write_helper(x509_crl_object *self, PyObject *args, int format) +{ + int len=0, ret=0; + char *buf=NULL; + BIO *out_bio=NULL; + PyObject *cert=NULL; + + if (!PyArg_ParseTuple(args, "")) + goto error; + + out_bio = BIO_new(BIO_s_mem()); + + if (format == DER_FORMAT) + { + if (!i2d_X509_CRL_bio(out_bio, self->crl) ) + { PyErr_SetString( SSLErrorObject, "unable to write certificate" ); goto error; } + } + else if (format == PEM_FORMAT) + { + if (!PEM_write_bio_X509_CRL(out_bio, self->crl) ) + { PyErr_SetString( SSLErrorObject, "unable to write certificate" ); goto error; } + } + else + { PyErr_SetString( SSLErrorObject, "internal error, unkown output format" ); goto error; } + + if ( !(len = BIO_ctrl_pending(out_bio) ) ) + { PyErr_SetString( SSLErrorObject, "unable to get bytes stored in bio" ); goto error; } + + if ( !(buf = malloc(len) ) ) + { PyErr_SetString( SSLErrorObject, "unable to allocate memory" ); goto error; } + + if ( (ret = BIO_read( out_bio, buf, len ) ) != len ) + { PyErr_SetString( SSLErrorObject, "unable to write out cert" ); goto error; } + + cert = Py_BuildValue("s#", buf, len); + + BIO_free(out_bio); + free(buf); + return cert; + +error: + + if (out_bio) + BIO_free(out_bio); + + if (buf) + free(buf); + + return NULL; +} + +static char x509_crl_object_pem_write__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Crl</memberof>\n" +" <name>pemWrite</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method returns a PEM encoded CRL as a\n" +" string.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +x509_crl_object_pem_write(x509_crl_object *self, PyObject *args) +{ + return x509_crl_object_write_helper(self, args, PEM_FORMAT); +} + +static char x509_crl_object_der_write__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Crl</memberof>\n" +" <name>derWrite</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method returns a DER encoded CRL as a string.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +x509_crl_object_der_write(x509_crl_object *self, PyObject *args) +{ + return x509_crl_object_write_helper(self, args, DER_FORMAT); +} + +static char x509_crl_object_pprint__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Crl</memberof>\n" +" <name>pprint</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method returns a formatted string showing the information\n" +" held in the CRL.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +x509_crl_object_pprint(x509_crl_object *self, PyObject *args) +{ + int len=0, ret=0; + char *buf=NULL; + BIO *out_bio=NULL; + PyObject *crl=NULL; + + if (!PyArg_ParseTuple(args, "")) + goto error; + + out_bio = BIO_new(BIO_s_mem()); + + if (!X509_CRL_print(out_bio, self->crl) ) + { PyErr_SetString( SSLErrorObject, "unable to write crl" ); goto error; } + + if ( !(len = BIO_ctrl_pending(out_bio) ) ) + { PyErr_SetString( SSLErrorObject, "unable to get bytes stored in bio" ); goto error; } + + if ( !(buf = malloc(len) ) ) + { PyErr_SetString( SSLErrorObject, "unable to allocate memory" ); goto error; } + + if ( (ret = BIO_read( out_bio, buf, len ) ) != len ) + { PyErr_SetString( SSLErrorObject, "unable to write out cert" ); goto error; } + + crl = Py_BuildValue("s#", buf, len); + + BIO_free(out_bio); + free(buf); + return crl; + +error: + + if (out_bio) + BIO_free(out_bio); + + if (buf) + free(buf); + + return NULL; + +} + +static struct PyMethodDef x509_crl_object_methods[] = { + {"sign", (PyCFunction)x509_crl_object_sign, METH_VARARGS, NULL}, + {"verify", (PyCFunction)x509_crl_object_verify, METH_VARARGS, NULL}, + {"getVersion", (PyCFunction)x509_crl_object_get_version, METH_VARARGS, NULL}, + {"setVersion", (PyCFunction)x509_crl_object_set_version, METH_VARARGS, NULL}, + {"getIssuer", (PyCFunction)x509_crl_object_get_issuer, METH_VARARGS, NULL}, + {"setIssuer", (PyCFunction)x509_crl_object_set_issuer, METH_VARARGS, NULL}, + {"getThisUpdate", (PyCFunction)x509_crl_object_get_this_update, METH_VARARGS, NULL}, + {"setThisUpdate", (PyCFunction)x509_crl_object_set_this_update, METH_VARARGS, NULL}, + {"getNextUpdate", (PyCFunction)x509_crl_object_get_next_update, METH_VARARGS, NULL}, + {"setNextUpdate", (PyCFunction)x509_crl_object_set_next_update, METH_VARARGS, NULL}, + {"setRevoked", (PyCFunction)x509_crl_object_set_revoked, METH_VARARGS, NULL}, + {"getRevoked", (PyCFunction)x509_crl_object_get_revoked, METH_VARARGS, NULL}, + {"addExtension", (PyCFunction)X509_crl_object_add_extension, METH_VARARGS, NULL}, + {"clearExtensions",(PyCFunction)X509_crl_object_clear_extensions, METH_VARARGS, NULL}, + {"countExtensions",(PyCFunction)X509_crl_object_count_extensions, METH_VARARGS, NULL}, + {"getExtension", (PyCFunction)X509_crl_object_get_extension, METH_VARARGS, NULL}, + {"pemWrite", (PyCFunction)x509_crl_object_pem_write, METH_VARARGS, NULL}, + {"derWrite", (PyCFunction)x509_crl_object_der_write, METH_VARARGS, NULL}, + {"pprint", (PyCFunction)x509_crl_object_pprint, METH_VARARGS, NULL}, + + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +x509_crl_object_getattr(x509_crl_object *self, char *name) +{ + return Py_FindMethod(x509_crl_object_methods, (PyObject *)self, name); +} + +static void +x509_crl_object_dealloc(x509_crl_object *self, char *name) +{ + X509_CRL_free( self->crl ); + PyObject_Del(self); +} + +static char x509_crltype__doc__[] = +"<class>\n" +" <header>\n" +" <name>X509Crl</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This class provides access to OpenSSL X509 CRL management\n" +" facilities.\n" +" </para>\n" +" </body>\n" +"</class>\n" +; + +static PyTypeObject x509_crltype = { + PyObject_HEAD_INIT(0) + 0, /*ob_size*/ + "X509Crl", /*tp_name*/ + sizeof(x509_crl_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)x509_crl_object_dealloc, /*tp_dealloc*/ + (printfunc)0, /*tp_print*/ + (getattrfunc)x509_crl_object_getattr, /*tp_getattr*/ + (setattrfunc)0, /*tp_setattr*/ + (cmpfunc)0, /*tp_compare*/ + (reprfunc)0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + (hashfunc)0, /*tp_hash*/ + (ternaryfunc)0, /*tp_call*/ + (reprfunc)0, /*tp_str*/ + 0, + 0, + 0, + 0, + x509_crltype__doc__ /* Documentation string */ +}; +/*========== x509 crl Code ==========*/ + +/*========== revoked Code ==========*/ +x509_revoked_object* x509_revoked_object_new(void) +{ + x509_revoked_object *self=NULL; + + if ( !(self = PyObject_New( x509_revoked_object, &x509_revokedtype ) ) ) + goto error; + + self->revoked = X509_REVOKED_new(); + + return self; + +error: + + Py_XDECREF(self); + return NULL; +} + +static char x509_revoked_object_set_serial__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Revoked</memberof>\n" +" <name>setSerial</name>\n" +" <parameter>serial</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method sets the serial number in the serial field of\n" +" this object. <parameter>serial</parameter> should be an\n" +" integer.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +x509_revoked_object_set_serial(x509_revoked_object *self, PyObject *args) +{ + int serial=0; + + if (!PyArg_ParseTuple(args, "i", &serial)) + goto error; + + if (!ASN1_INTEGER_set( self->revoked->serialNumber, serial ) ) + { PyErr_SetString( SSLErrorObject, "unable to set serial number" ); goto error; } + + return Py_BuildValue(""); + +error: + + return NULL; +} + +static char x509_revoked_object_get_serial__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Revoked</memberof>\n" +" <name>getSerial</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method gets the serial number in the serial field of\n" +" this object.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +x509_revoked_object_get_serial(x509_revoked_object *self, PyObject *args) +{ + int serial=0; + + if (!PyArg_ParseTuple(args, "")) + goto error; + + if ( (serial = ASN1_INTEGER_get( self->revoked->serialNumber ) ) == -1 ) + { PyErr_SetString( SSLErrorObject, "unable to get serial number" ); goto error; } + + return Py_BuildValue("i", serial); + +error: + + return NULL; +} + +static char x509_revoked_object_get_date__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Revoked</memberof>\n" +" <name>getDate</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" In a change from previous releases, for reasons of portability\n" +" and to avoid hard to fix issues with problems in unreliable time\n" +" functions, this function returns a UTCTime string. You\n" +" can use the function <function>time2utc</function> to convert to a\n" +" string if you like and <function>utc2time</function> to back.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +x509_revoked_object_get_date(x509_revoked_object *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + goto error; + + return Py_BuildValue("s", self->revoked->revocationDate->data); + +error: + + return NULL; +} + +static char x509_revoked_object_set_date__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Revoked</memberof>\n" +" <name>setDate</name>\n" +" <parameter>time</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" In a change from previous releases, for reasons of portability\n" +" and to avoid hard to fix issues with problems in unreliable time\n" +" functions, this accepts one parameter, a UTCTime string. You\n" +" can use the function <function>time2utc</function> to convert to a\n" +" string if you like and <function>utc2time</function> to back.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +x509_revoked_object_set_date(x509_revoked_object *self, PyObject *args) +{ + char *time=NULL; + + if (!PyArg_ParseTuple(args, "s", &time)) + goto error; + + if (!ASN1_UTCTIME_set_string( self->revoked->revocationDate, time )) + { PyErr_SetString( PyExc_TypeError, "could not set revocationDate" ); goto error; } + + return Py_BuildValue(""); + +error: + + return NULL; +} + +static char X509_revoked_object_add_extension__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Revoked</memberof>\n" +" <name>addExtension</name>\n" +" <parameter>extensionName</parameter>\n" +" <parameter>critical</parameter>\n" +" <parameter>extensionValue</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method adds an extension to this revocation.\n" +" <parameter>extensionName</parameter> should be the of the\n" +" extension. <parameter>critical</parameter> should an integer, 1\n" +" for true and 0 for clase. <parameter>extensionValue</parameter>\n" +" should be a string, DER encoded value of the extension. The name\n" +" of the extension must be correct according to OpenSSL and can be\n" +" checkd in the <constant>objects.h</constant> header file, part of\n" +" the OpenSSL source distrobution. In the majority of cases they\n" +" are the same as those defined in <constant>POW._oids</constant>\n" +" but if you do encounter problems is may be worth checking.\n" +" </para>\n" +" <example>\n" +" <title><function>addExtension</function> method usage</title>\n" +" <programlisting>\n" +" reason = POW.pkix.CrlReason()\n" +" reason.set(1) \n" +" revocation.addExtension( 'CRLReason', 0, reason.toString() )\n" +" </programlisting>\n" +" </example>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +X509_revoked_object_add_extension(x509_revoked_object *self, PyObject *args) +{ + int critical=0, nid=0; + char *name=NULL, *buf=NULL; + ASN1_OCTET_STRING *octetString=NULL; + X509_EXTENSION *extn=NULL; + + if (!PyArg_ParseTuple(args, "sis", &name, &critical, &buf)) + goto error; + + if ( !(octetString = M_ASN1_OCTET_STRING_new() ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + if ( !ASN1_OCTET_STRING_set(octetString, buf, strlen(buf)) ) + { PyErr_SetString( SSLErrorObject, "could not set ASN1 Octect string" ); goto error; } + + if ( NID_undef == (nid = OBJ_txt2nid(name) ) ) + { PyErr_SetString( SSLErrorObject, "extension has unknown object identifier" ); goto error; } + + if ( !( extn = X509_EXTENSION_create_by_NID(NULL, nid, critical, octetString) ) ) + { PyErr_SetString( SSLErrorObject, "unable to create ASN1 X509 Extension object" ); goto error; } + + if (!self->revoked->extensions) + if ( !(self->revoked->extensions = sk_X509_EXTENSION_new_null() ) ) + { PyErr_SetString( SSLErrorObject, "unable to allocate memory" ); goto error; } + + if ( !sk_X509_EXTENSION_push(self->revoked->extensions, extn) ) + { PyErr_SetString( SSLErrorObject, "unable to add extension" ); goto error; } + + return Py_BuildValue(""); + +error: + + if(extn) + X509_EXTENSION_free(extn); + + return NULL; +} + +static char X509_revoked_object_clear_extensions__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Revoked</memberof>\n" +" <name>clearExtensions</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method clears the structure which holds the extension for\n" +" this revocation.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +X509_revoked_object_clear_extensions(x509_revoked_object *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + goto error; + + if (self->revoked->extensions) + { + sk_X509_EXTENSION_free(self->revoked->extensions); + self->revoked->extensions=NULL; + } + + return Py_BuildValue(""); + +error: + + return NULL; +} + +static char X509_revoked_object_count_extensions__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Revoked</memberof>\n" +" <name>countExtensions</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method returns the size of the structure which holds the\n" +" extension for this revocation.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +X509_revoked_object_count_extensions(x509_revoked_object *self, PyObject *args) +{ + int num=0; + if (!PyArg_ParseTuple(args, "")) + goto error; + + if (self->revoked->extensions) + { + num = sk_X509_EXTENSION_num(self->revoked->extensions); + return Py_BuildValue("i", num); + } + else + return Py_BuildValue("i", 0); + +error: + + return NULL; +} + +static char X509_revoked_object_get_extension__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>X509Revoked</memberof>\n" +" <name>getExtension</name>\n" +" <parameter>index</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method returns a tuple equivalent the parameters of\n" +" <function>addExtension</function>.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +X509_revoked_object_get_extension(x509_revoked_object *self, PyObject *args) +{ + int num=0, index=0, ext_nid=0; + char const *ext_ln=NULL; + char unknown_ext [] = "unkown"; + X509_EXTENSION *ext; + if (!PyArg_ParseTuple(args, "i", &index)) + goto error; + + if (self->revoked->extensions) + { + num = sk_X509_EXTENSION_num(self->revoked->extensions); + } + else + num = 0; + + if (index >= num) + { PyErr_SetString( SSLErrorObject, "certificate does not have that many extensions" ); goto error; } + + if ( !(ext = sk_X509_EXTENSION_value(self->revoked->extensions, index) ) ) + { PyErr_SetString( SSLErrorObject, "could not get extension" ); goto error; } + + if ( NID_undef == (ext_nid = OBJ_obj2nid(ext->object) ) ) + { PyErr_SetString( SSLErrorObject, "extension has unknown object identifier" ); goto error; } + + if ( NULL == (ext_ln = OBJ_nid2sn(ext_nid) ) ) + ext_ln = unknown_ext; + + return Py_BuildValue("sis", ext_ln, ext->critical, ext->value->data ); + +error: + + return NULL; +} + +static struct PyMethodDef x509_revoked_object_methods[] = { + {"getSerial", (PyCFunction)x509_revoked_object_get_serial, METH_VARARGS, NULL}, + {"setSerial", (PyCFunction)x509_revoked_object_set_serial, METH_VARARGS, NULL}, + {"getDate", (PyCFunction)x509_revoked_object_get_date, METH_VARARGS, NULL}, + {"setDate", (PyCFunction)x509_revoked_object_set_date, METH_VARARGS, NULL}, + {"addExtension", (PyCFunction)X509_revoked_object_add_extension, METH_VARARGS, NULL}, + {"clearExtensions",(PyCFunction)X509_revoked_object_clear_extensions, METH_VARARGS, NULL}, + {"countExtensions",(PyCFunction)X509_revoked_object_count_extensions, METH_VARARGS, NULL}, + {"getExtension", (PyCFunction)X509_revoked_object_get_extension, METH_VARARGS, NULL}, + + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +x509_revoked_object_getattr(x509_revoked_object *self, char *name) +{ + return Py_FindMethod(x509_revoked_object_methods, (PyObject *)self, name); +} + +static void +x509_revoked_object_dealloc(x509_revoked_object *self, char *name) +{ + X509_REVOKED_free( self->revoked ); + PyObject_Del(self); +} + +static char x509_revokedtype__doc__[] = +"<class>\n" +" <header>\n" +" <name>X509Revoked</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This class provides a container for details of a revoked\n" +" certificate. It normally would only be used in association with\n" +" a CRL, its not much use by itself. Indeed the only reason this\n" +" class exists is because in the future POW is likely to be extended\n" +" to support extensions for certificates, CRLs and revocations.\n" +" <classname>X509Revoked</classname> existing as an object in its\n" +" own right will make adding this support easier, while avoiding\n" +" backwards compatibility issues.\n" +" </para>\n" +" </body>\n" +"</class>\n" +; + +static PyTypeObject x509_revokedtype = { + PyObject_HEAD_INIT(0) + 0, /*ob_size*/ + "X509Revoked", /*tp_name*/ + sizeof(x509_revoked_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)x509_revoked_object_dealloc, /*tp_dealloc*/ + (printfunc)0, /*tp_print*/ + (getattrfunc)x509_revoked_object_getattr, /*tp_getattr*/ + (setattrfunc)0, /*tp_setattr*/ + (cmpfunc)0, /*tp_compare*/ + (reprfunc)0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + (hashfunc)0, /*tp_hash*/ + (ternaryfunc)0, /*tp_call*/ + (reprfunc)0, /*tp_str*/ + 0, + 0, + 0, + 0, + x509_revokedtype__doc__ /* Documentation string */ +}; +/*========== x509 revoked Code ==========*/ + +/*========== ssl Code ==========*/ +static char ssl_object_use_certificate__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Ssl</memberof>\n" +" <name>useCertificate</name>\n" +" <parameter>cert</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" The parameter <parameter>cert</parameter> must be an\n" +" instance of the <classname>X590</classname> class and must be\n" +" called before <function>setFd</function>. \n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +ssl_object_use_certificate(ssl_object *self, PyObject *args) +{ + x509_object *x509=NULL; + + if (!PyArg_ParseTuple(args, "O!", &x509type, &x509)) + goto error; + + if (self->ctxset) + { PyErr_SetString( SSLErrorObject, "cannont be called after setFd()" ); goto error; } + + if ( !SSL_CTX_use_certificate(self->ctx, x509->x509) ) + { PyErr_SetString( SSLErrorObject, "could not use certificate" ); goto error; } + + return Py_BuildValue(""); + +error: + + return NULL; +} + +static char ssl_object_use_key__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Ssl</memberof>\n" +" <name>useKey</name>\n" +" <parameter>key</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" The parameter <parameter>key</parameter> must be an\n" +" instance of the <classname>Asymmetric</classname> class and\n" +" must contain the private key. This function cannot be called \n" +" after <function>useKey</function>.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +ssl_object_use_key(ssl_object *self, PyObject *args) +{ + asymmetric_object *asym=NULL; + EVP_PKEY *pkey=NULL; + + if (!PyArg_ParseTuple(args, "O!", &asymmetrictype, &asym)) + goto error; + + if (self->ctxset) + { PyErr_SetString( SSLErrorObject, "cannont be called after setFd()" ); goto error; } + + if ( !(pkey = EVP_PKEY_new() ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + if (asym->key_type != RSA_PRIVATE_KEY) + { PyErr_SetString( SSLErrorObject, "cannot use this type of key" ); goto error; } + + if ( !EVP_PKEY_assign_RSA(pkey, asym->cipher) ) + { PyErr_SetString( SSLErrorObject, "EVP_PKEY assignment error" ); goto error; } + + if ( !SSL_CTX_use_PrivateKey(self->ctx, pkey) ) + { PyErr_SetString( SSLErrorObject, "ctx key assignment error" ); goto error; } + + return Py_BuildValue(""); + +error: + + if(pkey) + EVP_PKEY_free(pkey); + + return NULL; +} + +static char ssl_object_check_key__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Ssl</memberof>\n" +" <name>checkKey</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This simple method will return 1 if the public key, contained in\n" +" the X509 certificate this <classname>Ssl</classname> instance is using,\n" +" matches the private key this <classname>Ssl</classname> instance is using.\n" +" Otherwise it will return 0.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +ssl_object_check_key(ssl_object *self, PyObject *args) +{ + if ( SSL_CTX_check_private_key(self->ctx) ) + return Py_BuildValue("i", 1); + else + return Py_BuildValue("i", 0); +} + +static char ssl_object_set_fd__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Ssl</memberof>\n" +" <name>setFd</name>\n" +" <parameter>descriptor</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This function is used to associate a file descriptor with a\n" +" <classname>Ssl</classname> object. The file descriptor should\n" +" belong to an open TCP connection. Once this function has\n" +" been called, calling <function>useKey</function> or\n" +" <function>useCertificate</function> will, fail rasing exceptions.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +ssl_object_set_fd(ssl_object *self, PyObject *args) +{ + int fd=0, self_index=0; + + if (!PyArg_ParseTuple(args, "i", &fd)) + goto error; + + if ( !(self->ssl = SSL_new( self->ctx ) ) ) + { PyErr_SetString( SSLErrorObject, "unable to create ssl sturcture" ); goto error; } + + if ( !SSL_set_fd( self->ssl, fd ) ) + { PyErr_SetString( SSLErrorObject, "unable to set file descriptor" ); goto error; } + + if ( (self_index = SSL_get_ex_new_index(0, "self_index", NULL, NULL, NULL) ) != -1 ) + SSL_set_ex_data(self->ssl, self_index, self); + else + { PyErr_SetString( SSLErrorObject, "unable to create ex data index" ); goto error; } + + self->ctxset = 1; + + return Py_BuildValue(""); + +error: + + return NULL; +} + +static char ssl_object_accept__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Ssl</memberof>\n" +" <name>accept</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This function will attempt the SSL level accept with a\n" +" client. The <classname>Ssl</classname> object must have been\n" +" created using a <constant>XXXXX_SERVER_METHOD</constant> or\n" +" a <constant>XXXXX_METHOD</constant> and this function should only be\n" +" called after <function>useKey</function>,\n" +" <function>useCertificate</function> and\n" +" <function>setFd</function> functions have been called.\n" +" </para>\n" +"\n" +" <example>\n" +" <title><function>accept</function> function usage</title>\n" +" <programlisting>\n" +" keyFile = open( 'test/private.key', 'r' )\n" +" certFile = open( 'test/cacert.pem', 'r' )\n" +"\n" +" rsa = POW.pemRead( POW.RSA_PRIVATE_KEY, keyFile.read(), 'pass' )\n" +" x509 = POW.pemRead( POW.X509_CERTIFICATE, certFile.read() )\n" +"\n" +" keyFile.close()\n" +" certFile.close()\n" +"\n" +" sl = POW.Ssl( POW.SSLV23_SERVER_METHOD )\n" +" sl.useCertificate( x509 )\n" +" sl.useKey( rsa )\n" +"\n" +" s = socket.socket( socket.AF_INET, socket.SOCK_STREAM )\n" +" s.bind( ('localhost', 1111) )\n" +" s.listen(5)\n" +" s2, addr = s.accept()\n" +"\n" +" s.close()\n" +"\n" +" sl.setFd( s2.fileno() )\n" +" sl.accept()\n" +" print sl.read(1024)\n" +" sl.write('Message from server to client...')\n" +"\n" +" s2.close() \n" +" </programlisting>\n" +" </example>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +ssl_object_accept(ssl_object *self, PyObject *args) +{ + int ret=0, err=0; + + if (!PyArg_ParseTuple(args, "")) + goto error; + + Py_BEGIN_ALLOW_THREADS + ret = SSL_accept( self->ssl ); + Py_END_ALLOW_THREADS + + if (ret <= 0) + { + err = SSL_get_error( self->ssl, ret ); + PyErr_SetObject(SSLErrorObject, ssl_err_factory( err ) ); + goto error; + } + return Py_BuildValue(""); + +error: + + return NULL; +} + +static char ssl_object_connect__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Ssl</memberof>\n" +" <name>connect</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This function will attempt the SSL level connection with a\n" +" server. The <classname>Ssl</classname> object must have been\n" +" created using a <constant>XXXXX_CLIENT_METHOD</constant> or\n" +" a <constant>XXXXX_METHOD</constant> and this function should only be\n" +" called after <function>setFd</function> has already been\n" +" called.\n" +" </para>\n" +"\n" +" <example>\n" +" <title><function>connect</function> function usage</title>\n" +" <programlisting>\n" +" s = socket.socket( socket.AF_INET, socket.SOCK_STREAM )\n" +" s.connect(('localhost', 1111))\n" +"\n" +" sl = POW.Ssl( POW.SSLV23_CLIENT_METHOD )\n" +" sl.setFd( s.fileno() )\n" +" sl.connect()\n" +" sl.write('Message from client to server...')\n" +" print sl.read(1024)\n" +" </programlisting>\n" +" </example>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +ssl_object_connect(ssl_object *self, PyObject *args) +{ + int ret, err=0; + + if (!PyArg_ParseTuple(args, "")) + goto error; + + Py_BEGIN_ALLOW_THREADS + ret = SSL_connect( self->ssl ); + Py_END_ALLOW_THREADS + + if (ret <= 0) + { + err = SSL_get_error( self->ssl, ret ); + PyErr_SetObject(SSLErrorObject, ssl_err_factory( err ) ); + goto error; + } + return Py_BuildValue(""); + +error: + + return NULL; +} + +static char ssl_object_write__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Ssl</memberof>\n" +" <name>write</name>\n" +" <parameter>string</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method writes the <parameter>string</parameter> to the\n" +" <classname>Ssl</classname> object, to be read by it's peer. This\n" +" function is analogous to the <classname>socket</classname>\n" +" classes <function>write</function> function.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +ssl_object_write(ssl_object *self, PyObject *args) +{ + char *msg; + int length=0, ret=0, err=0; + + if (!PyArg_ParseTuple(args, "s#", &msg, &length)) + goto error; + + Py_BEGIN_ALLOW_THREADS + ret = SSL_write( self->ssl, msg, length ); + Py_END_ALLOW_THREADS + + if (ret <= 0) + { + err = SSL_get_error( self->ssl, ret ); + PyErr_SetObject(SSLErrorObject, ssl_err_factory( err ) ); + goto error; + } + return Py_BuildValue("i", ret); + +error: + + return NULL; +} + +static char ssl_object_read__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Ssl</memberof>\n" +" <name>read</name>\n" +" <parameter>amount=1024</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method reads up to <parameter>amount</parameter> characters from the\n" +" <classname>Ssl</classname> object. This\n" +" function is analogous to the <classname>socket</classname>\n" +" classes <function>read</function> function.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +ssl_object_read(ssl_object *self, PyObject *args) +{ + PyObject *data; + char *msg=NULL; + int len = 1024, ret=0, err=0; + + if (!PyArg_ParseTuple(args, "|i", &len)) + goto error; + + if ( !(msg = malloc(len) ) ) + { PyErr_SetString( SSLErrorObject, "unable to allocate memory" ); goto error; } + + Py_BEGIN_ALLOW_THREADS + ret = SSL_read( self->ssl, msg, len ); + Py_END_ALLOW_THREADS + + if (ret <= 0) + { + free(msg); + err = SSL_get_error( self->ssl, ret ); + PyErr_SetObject(SSLErrorObject, ssl_err_factory( err ) ); + goto error; + } + else + data = Py_BuildValue("s#", msg, ret); + + free(msg); + return data; + +error: + + if (msg) + free(msg); + + return NULL; +} + +static char ssl_object_peer_certificate__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Ssl</memberof>\n" +" <name>peerCertificate</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method returns any peer certificate presented in the initial\n" +" SSL negotiation or <constant>None</constant>. If a certificate is\n" +" returned, it will be an instance of <classname>X509</classname>.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +ssl_object_peer_certificate(ssl_object *self, PyObject *args) +{ + X509 *x509=NULL; + x509_object *x509_obj=NULL; + + if (!PyArg_ParseTuple(args, "")) + goto error; + + if ( !(x509_obj = X509_object_new() ) ) + { PyErr_SetString( SSLErrorObject, "could not create x509 object" ); goto error; } + + x509 = SSL_get_peer_certificate( self->ssl ); + + if (x509) + { + X509_free( x509_obj->x509 ); + + if ( !(x509_obj->x509 = x509 ) ) + { PyErr_SetString( SSLErrorObject, "could not create x509 object" ); goto error; } + return Py_BuildValue("O", x509_obj); + } + else + { + Py_XDECREF( x509_obj ); + return Py_BuildValue(""); + } + +error: + + if (x509) + X509_free(x509); + + Py_XDECREF( x509_obj ); + return NULL; +} + +static char ssl_object_clear__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Ssl</memberof>\n" +" <name>clear</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method will clear the SSL session ready for\n" +" a new SSL connection. It will not effect the underlying socket.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +ssl_object_clear(ssl_object *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + goto error; + + if (!SSL_clear( self->ssl ) ) + { PyErr_SetString( SSLErrorObject, "failed to clear ssl connection" ); goto error; } + + return Py_BuildValue(""); + +error: + + return NULL; +} + +static char ssl_object_shutdown__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Ssl</memberof>\n" +" <name>shutdown</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method will issue a <constant>shutdown</constant> signal to it's peer. \n" +" If this connection's peer has already initiated a shutdown this call\n" +" will succeed, otherwise it will raise and exception. In order to\n" +" check the shutdown handshake was successful,\n" +" <function>shutdown</function> must be called again. If no\n" +" exception is raised, the handshake is complete. \n" +" </para>\n" +" <para>\n" +" The odd\n" +" implementation of this function reflects the underlying OpenSSL\n" +" function, which reflects the SSL protocol. Although rasing an\n" +" exception is a bit annoying, the alternative, returning true all\n" +" false will not tell you why the call failed and the exception\n" +" will, at least that is the theory. Look up the exact meaning\n" +" of the exceptions in the OpenSSL man page SSL_get_error.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +ssl_object_shutdown(ssl_object *self, PyObject *args) +{ + int ret=0, err=0; + + if (!PyArg_ParseTuple(args, "")) + goto error; + + ret = SSL_shutdown(self->ssl); + + if (ret <= 0) + { + err = SSL_get_error( self->ssl, ret ); + PyErr_SetObject(SSLErrorObject, ssl_err_factory( err ) ); + goto error; + } + + return Py_BuildValue(""); + +error: + + return NULL; +} + +static char ssl_object_get_shutdown__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Ssl</memberof>\n" +" <name>getShutdown</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This function returns an integer indicating the state of the\n" +" SSL connection. <constant>SSL_RECIEVED_SHUTDOWN</constant>\n" +" will be set the if it's peer sends a <constant>shutdown</constant>\n" +" signal or the underlying socket\n" +" receives a close notify . The possible values are:\n" +" </para>\n" +" <simplelist>\n" +" <member><constant>SSL_NO_SHUTDOWN</constant></member>\n" +" <member><constant>SSL_SENT_SHUTDOWN</constant></member>\n" +" <member><constant>SSL_RECIEVED_SHUTDOWN</constant></member>\n" +" <member><constant>SSL_SENT_SHUTDOWN</constant> | <constant>SSL_RECIEVED_SHUTDOWN</constant></member>\n" +" </simplelist>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +ssl_object_get_shutdown(ssl_object *self, PyObject *args) +{ + int state=0; + + if (!PyArg_ParseTuple(args, "")) + goto error; + + state = SSL_get_shutdown(self->ssl); + + return Py_BuildValue("i", state); + +error: + + return NULL; +} + +static char ssl_object_get_ciphers__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Ssl</memberof>\n" +" <name>getCiphers</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This function returns a list of available ciphers ordered from\n" +" most favored to least. This function must be called after\n" +" <function>setFd</function>. \n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +ssl_object_get_ciphers(ssl_object *self, PyObject *args) +{ + int inlist=0, i=0; + const char *cipher=NULL; + PyObject *list=NULL, *name=NULL; + + if (!PyArg_ParseTuple(args, "")) + goto error; + + if (!self->ctxset) + { PyErr_SetString( SSLErrorObject, "cannont be called before setFd()" ); goto error; } + + list = PyList_New(0); + + cipher = SSL_get_cipher_list(self->ssl, 0); + while (cipher) + { + if ( !(name = PyString_FromString(cipher) ) ) + goto error; + if ( PyList_Append( list, name ) != 0) + goto error; + cipher = SSL_get_cipher_list(self->ssl, ++i); + } + return Py_BuildValue("O", list); + +error: + + if (list) + { + inlist = PyList_Size( list ); + for (i=0; i < inlist; i++) + { + name = PyList_GetItem( list, i ); + Py_DECREF(name); + } + Py_DECREF(list); + } + + return NULL; +} + +static char ssl_object_set_ciphers__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Ssl</memberof>\n" +" <name>setCiphers</name>\n" +" <parameter>ciphers</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" <function>setCiphers</function>\n" +" can help protect against certain types of attacks which try to\n" +" coerce the server, client or both to negotiate a weak cipher. \n" +" <parameter>ciphers</parameter> should be a list of strings, as\n" +" produced by <function>getCiphers</function> and described in the\n" +" OpenSSL man page ciphers. <function>setCiphers</function> should\n" +" only be called after <function>setFd</function>.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +ssl_object_set_ciphers(ssl_object *self, PyObject *args) +{ + PyObject *ciphers=NULL; + PyObject *cipher=NULL; + int size=0, cipherstrlen=0, nextstrlen=0, i=0; + char *cipherstr=NULL; + + if (!PyArg_ParseTuple(args, "O", &ciphers)) + goto error; + + if ( !(PyList_Check(ciphers) || PyTuple_Check(ciphers)) ) + { PyErr_SetString( PyExc_TypeError, "inapropriate type" ); goto error; } + + if (!self->ctxset) + { PyErr_SetString( SSLErrorObject, "cannont be called before setFd()" ); goto error; } + + cipherstr = malloc(8); //very bogus, realloc dosn't work with out some + //previously allocated memory! Really should. + memset(cipherstr, 0, 8); + size = PySequence_Size(ciphers); + for (i=0; i < size; i++) + { + if ( !( cipher = PySequence_GetItem( ciphers, i ) ) ) + goto error; + + if ( !PyString_Check(cipher) ) + { PyErr_SetString( PyExc_TypeError, "inapropriate type" ); goto error; } + + cipherstrlen = strlen(cipherstr); + nextstrlen = strlen( PyString_AsString(cipher) ); + + if ( !(cipherstr = realloc( cipherstr, cipherstrlen + nextstrlen + 2)) ) + { PyErr_SetString( PyExc_TypeError, "could allocate memory" ); goto error; } + + if (cipherstrlen) + strcat( cipherstr, ":\0" ); + + strcat( cipherstr, PyString_AsString(cipher) ); + Py_DECREF(cipher); + cipher = NULL; + } + SSL_set_cipher_list( self->ssl, cipherstr ); + free(cipherstr); + return Py_BuildValue(""); + +error: + + if (cipherstr) + free(cipherstr); + + Py_XDECREF(cipher); + + return NULL; +} + +static char ssl_object_get_cipher__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Ssl</memberof>\n" +" <name>getCipher</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This function returns the current cipher in use.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +ssl_object_get_cipher(ssl_object *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + goto error; + + if (!self->ctxset) + { PyErr_SetString( SSLErrorObject, "cannont be called before setFd()" ); goto error; } + + return Py_BuildValue("s", SSL_get_cipher( self->ssl )); + +error: + + return NULL; +} + +static int stub_callback(int preverify_ok, X509_STORE_CTX *ctx) +{ + return 1; +} + +static char ssl_object_set_verify_mode__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Ssl</memberof>\n" +" <name>setVerifyMode</name>\n" +" <parameter>mode</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This function sets the behavior of the SSL handshake. The\n" +" parameter <parameter>mode</parameter> should be one of the\n" +" following:\n" +" </para>\n" +" <simplelist>\n" +" <member><constant>SSL_VERIFY_NONE</constant></member>\n" +" <member><constant>SSL_VERIFY_PEER</constant></member>\n" +" </simplelist>\n" +" <para>\n" +" See the OpenSSL man page <function>SSL_CTX_set_verify</function> \n" +" for details. This function must be called after <function>setfd</function> \n" +" has been called.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +ssl_object_set_verify_mode(ssl_object *self, PyObject *args) +{ + int mode=0; + + if (!PyArg_ParseTuple(args, "i", &mode)) + goto error; + + if (self->ctxset) + { PyErr_SetString( SSLErrorObject, "cannont be called after setfd()" ); goto error; } + + SSL_CTX_set_verify( self->ctx, mode, stub_callback ); + + return Py_BuildValue(""); + +error: + + return NULL; +} + +static struct PyMethodDef ssl_object_methods[] = { + {"useCertificate", (PyCFunction)ssl_object_use_certificate, METH_VARARGS, NULL}, + {"useKey", (PyCFunction)ssl_object_use_key, METH_VARARGS, NULL}, + {"checkKey", (PyCFunction)ssl_object_check_key, METH_VARARGS, NULL}, + {"setFd", (PyCFunction)ssl_object_set_fd, METH_VARARGS, NULL}, + {"connect", (PyCFunction)ssl_object_connect, METH_VARARGS, NULL}, + {"accept", (PyCFunction)ssl_object_accept, METH_VARARGS, NULL}, + {"write", (PyCFunction)ssl_object_write, METH_VARARGS, NULL}, + {"read", (PyCFunction)ssl_object_read, METH_VARARGS, NULL}, + {"peerCertificate", (PyCFunction)ssl_object_peer_certificate, METH_VARARGS, NULL}, + {"clear", (PyCFunction)ssl_object_clear, METH_VARARGS, NULL}, + {"shutdown", (PyCFunction)ssl_object_shutdown, METH_VARARGS, NULL}, + {"getShutdown", (PyCFunction)ssl_object_get_shutdown, METH_VARARGS, NULL}, + {"getCiphers", (PyCFunction)ssl_object_get_ciphers, METH_VARARGS, NULL}, + {"setCiphers", (PyCFunction)ssl_object_set_ciphers, METH_VARARGS, NULL}, + {"getCipher", (PyCFunction)ssl_object_get_cipher, METH_VARARGS, NULL}, + {"setVerifyMode", (PyCFunction)ssl_object_set_verify_mode, METH_VARARGS, NULL}, + + {NULL, NULL} /* sentinel */ +}; + +static ssl_object * +newssl_object(int type) +{ + ssl_object *self; + SSL_METHOD *method; + + + if ( !(self = PyObject_NEW(ssl_object, &ssltype) ) ) + goto error; + + self->ctxset = 0; + self->ssl = NULL; + + switch(type) + { + case SSLV2_SERVER_METHOD: method = SSLv2_server_method(); break; + case SSLV2_CLIENT_METHOD: method = SSLv2_client_method(); break; + case SSLV2_METHOD: method = SSLv2_method(); break; + case SSLV3_SERVER_METHOD: method = SSLv3_server_method(); break; + case SSLV3_CLIENT_METHOD: method = SSLv3_client_method(); break; + case SSLV3_METHOD: method = SSLv3_method(); break; + case TLSV1_SERVER_METHOD: method = TLSv1_server_method(); break; + case TLSV1_CLIENT_METHOD: method = TLSv1_client_method(); break; + case TLSV1_METHOD: method = TLSv1_method(); break; + case SSLV23_SERVER_METHOD: method = SSLv23_server_method(); break; + case SSLV23_CLIENT_METHOD: method = SSLv23_client_method(); break; + case SSLV23_METHOD: method = SSLv23_method(); break; + + default: + { PyErr_SetString( SSLErrorObject, "unkown ctx method" ); goto error; } + + } + + if ( !(self->ctx = SSL_CTX_new( method ) ) ) + { PyErr_SetString( SSLErrorObject, "unable to create new ctx" ); goto error; } + + return self; + +error: + + Py_XDECREF( self ); + return NULL; +} + +static PyObject * +ssl_object_getattr(ssl_object *self, char *name) +{ + return Py_FindMethod(ssl_object_methods, (PyObject *)self, name); +} + +static void +ssl_object_dealloc(ssl_object *self) +{ + SSL_free( self->ssl ); + SSL_CTX_free( self->ctx ); + PyObject_Del(self); +} + +static char ssltype__doc__[] = +"<class>\n" +" <header>\n" +" <name>Ssl</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This class provides access to the Secure Socket Layer\n" +" functionality of OpenSSL. It is designed to be a simple as\n" +" possible to use and is not designed for high performance\n" +" applications which handle many simultaneous connections. The\n" +" original motivation for writing this library was to provide a\n" +" security layer for network agents written in Python, for this\n" +" application, good performance with multiple concurrent connections\n" +" is not an issue. \n" +" </para>\n" +" </body>\n" +"</class>\n" +; + +static PyTypeObject ssltype = { + PyObject_HEAD_INIT(0) + 0, /*ob_size*/ + "Ssl", /*tp_name*/ + sizeof(ssl_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)ssl_object_dealloc, /*tp_dealloc*/ + (printfunc)0, /*tp_print*/ + (getattrfunc)ssl_object_getattr, /*tp_getattr*/ + (setattrfunc)0, /*tp_setattr*/ + (cmpfunc)0, /*tp_compare*/ + (reprfunc)0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + (hashfunc)0, /*tp_hash*/ + (ternaryfunc)0, /*tp_call*/ + (reprfunc)0, /*tp_str*/ + 0, + 0, + 0, + 0, + ssltype__doc__ /* Documentation string */ +}; +/*========== ssl Object ==========*/ + +/*========== asymmetric Object ==========*/ +static asymmetric_object * +asymmetric_object_new(int cipher_type, int key_size) +{ + asymmetric_object *self=NULL; + + self = PyObject_New( asymmetric_object, &asymmetrictype ); + if (self == NULL) + goto error; + + if (cipher_type != RSA_CIPHER) + { PyErr_SetString( SSLErrorObject, "unsupported cipher" ); goto error; } + + if ( !(self->cipher = RSA_generate_key(key_size,RSA_F4,NULL,NULL) ) ) + { PyErr_SetString( SSLErrorObject, "could not generate key" ); goto error; } + + self->key_type = RSA_PRIVATE_KEY; + self->cipher_type = RSA_CIPHER; + + return self; + +error: + + Py_XDECREF(self); + return NULL; +} + +static asymmetric_object * +asymmetric_object_pem_read(int key_type, BIO *in, char *pass) +{ + asymmetric_object *self=NULL; + + self = PyObject_New( asymmetric_object, &asymmetrictype ); + if (self == NULL) + goto error; + + switch (key_type) + { + case RSA_PUBLIC_KEY: + { + if( !(self->cipher = PEM_read_bio_RSA_PUBKEY( in, NULL, NULL, NULL ) ) ) + { PyErr_SetString( SSLErrorObject, "could not load public key" ); goto error; } + self->key_type = RSA_PUBLIC_KEY; + self->cipher_type = RSA_CIPHER; + break; + } + case RSA_PRIVATE_KEY: + { + if( !(self->cipher = PEM_read_bio_RSAPrivateKey( in, NULL, NULL, pass) ) ) + { PyErr_SetString( SSLErrorObject, "could not load private key" ); goto error; } + self->key_type = RSA_PRIVATE_KEY; + self->cipher_type = RSA_CIPHER; + break; + } + default: + { PyErr_SetString( SSLErrorObject, "unkown key type" ); goto error; } + } + + return self; + +error: + + Py_XDECREF(self); + return NULL; +} + +static asymmetric_object * +asymmetric_object_der_read(int key_type, char *src, int len) +{ + asymmetric_object *self=NULL; + unsigned char *ptr = src; + + self = PyObject_New( asymmetric_object, &asymmetrictype ); + if (self == NULL) + goto error; + + switch (key_type) + { + case RSA_PUBLIC_KEY: + { + if( !(self->cipher = d2i_RSAPublicKey( NULL, &ptr, len ) ) ) + { PyErr_SetString( SSLErrorObject, "could not load public key" ); goto error; } + + self->key_type = RSA_PUBLIC_KEY; + self->cipher_type = RSA_CIPHER; + break; + } + case RSA_PRIVATE_KEY: + { + if( !(self->cipher = d2i_RSAPrivateKey( NULL, &ptr, len ) ) ) + { PyErr_SetString( SSLErrorObject, "could not load private key" ); goto error; } + + self->key_type = RSA_PRIVATE_KEY; + self->cipher_type = RSA_CIPHER; + break; + } + default: + { PyErr_SetString( SSLErrorObject, "unkown key type" ); goto error; } + } + + return self; + +error: + + Py_XDECREF(self); + return NULL; +} + +static char asymmetric_object_pem_write__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Asymmetric</memberof>\n" +" <name>pemWrite</name>\n" +" <parameter>keytype</parameter>\n" +" <parameter>ciphertype=None</parameter>\n" +" <parameter>passphrase=None</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method is used to write <classname>Asymmetric</classname>\n" +" objects out as strings. The first argument should be either\n" +" <constant>RSA_PUBLIC_KEY</constant> or\n" +" <constant>RSA_PRIVATE_KEY</constant>. Private keys are often\n" +" saved in encrypted files to offer extra security above access\n" +" control mechanisms. If the <parameter>keytype</parameter> is\n" +" <constant>RSA_PRIVATE_KEY</constant> a\n" +" <parameter>ciphertype</parameter> and\n" +" <parameter>passphrase</parameter> can also be specified. The\n" +" <parameter>ciphertype</parameter> should be one of those listed in\n" +" the <classname>Symmetric</classname> class section.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +asymmetric_object_pem_write(asymmetric_object *self, PyObject *args) +{ + int key_type=0, cipher=0, len=0, ret=0; + char *kstr=NULL, *buf=NULL; + BIO *out_bio=NULL; + PyObject *asymmetric=NULL; + + if (!PyArg_ParseTuple(args, "|iis", &key_type, &cipher, &kstr)) + goto error; + + if (key_type == 0) + key_type = self->key_type; + + if ( !(out_bio = BIO_new(BIO_s_mem()) ) ) + { PyErr_SetString( SSLErrorObject, "unable to create new BIO" ); goto error; } + + if ( (kstr && !cipher) || (cipher && !kstr) ) + {PyErr_SetString(SSLErrorObject,"cipher type and key string must both be supplied");goto error;} + + + switch( key_type ) + { + case RSA_PRIVATE_KEY: + { + if (kstr && cipher) + { + if (!PEM_write_bio_RSAPrivateKey(out_bio, self->cipher, evp_cipher_factory(cipher), NULL, 0, NULL, kstr) ) + { PyErr_SetString( SSLErrorObject, "unable to write key" ); goto error; } + } + else + { + if (!PEM_write_bio_RSAPrivateKey(out_bio, self->cipher, NULL, NULL, 0, NULL, NULL) ) + { PyErr_SetString( SSLErrorObject, "unable to write key" ); goto error; } + } + break; + } + case RSA_PUBLIC_KEY: + { + if (kstr && cipher) + { PyErr_SetString( SSLErrorObject, "public keys should not encrypted" ); goto error; } + else + { + if (!PEM_write_bio_RSA_PUBKEY(out_bio, self->cipher) ) + { PyErr_SetString( SSLErrorObject, "unable to write key" ); goto error; } + } + break; + } + default: + { PyErr_SetString( SSLErrorObject, "unsupported key type" ); goto error; } + } + + if ( !(len = BIO_ctrl_pending(out_bio) ) ) + { PyErr_SetString( SSLErrorObject, "unable to get number of bytes in bio" ); goto error; } + + if ( !(buf = malloc(len) ) ) + { PyErr_SetString( SSLErrorObject, "unable to allocate memory" ); goto error; } + + if ( (ret = BIO_read( out_bio, buf, len ) ) != len ) + { PyErr_SetString( SSLErrorObject, "unable to write out key" ); goto error; } + + asymmetric = Py_BuildValue("s#", buf, len); + + BIO_free(out_bio); + free(buf); + return asymmetric; + +error: + + if (out_bio); + BIO_free(out_bio); + + if (buf) + free(buf); + + return NULL; +} + +static char asymmetric_object_der_write__doc__[] = +"<method>" +" <header>" +" <memberof>Asymmetric</memberof>" +" <name>derWrite</name>" +" <parameter>keytype</parameter>" +" </header>" +" <body>" +" <para>" +" This method is used to write <classname>Asymmetric</classname>" +" objects out as strings. The first argument should be either" +" <constant>RSA_PUBLIC_KEY</constant> or " +" <constant>RSA_PRIVATE_KEY</constant>." +" </para>" +" </body>" +"</method>" +; + +static PyObject * +asymmetric_object_der_write(asymmetric_object *self, PyObject *args) +{ + int len=0, key_type=0; + unsigned char *buf=NULL, *p=NULL; + PyObject *asymmetric=NULL; + + if (!PyArg_ParseTuple(args, "|i", &key_type)) + goto error; + + if (key_type == 0) + key_type = self->key_type; + + switch( key_type ) + { + case RSA_PRIVATE_KEY: + { + len = i2d_RSAPrivateKey(self->cipher, NULL); + if ( !(buf = malloc(len) ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + p = buf; + if (!i2d_RSAPrivateKey(self->cipher, &buf) ) + { PyErr_SetString( SSLErrorObject, "unable to write key" ); goto error; } + break; + } + case RSA_PUBLIC_KEY: + { + len = i2d_RSAPublicKey(self->cipher, NULL); + if ( !(buf = malloc(len) ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + p = buf; + if (!i2d_RSAPublicKey(self->cipher, &buf) ) + { PyErr_SetString( SSLErrorObject, "unable to write key" ); goto error; } + break; + } + default: + { PyErr_SetString( SSLErrorObject, "unsupported key type" ); goto error; } + } + + asymmetric = Py_BuildValue("s#", p, len); + + free(p); + return asymmetric; + +error: + + if (p) + free(p); + + return NULL; +} + +static char asymmetric_object_public_encrypt__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Asymmetric</memberof>\n" +" <name>publicEncrypt</name>\n" +" <parameter>plaintext</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method is used to encrypt the <parameter>plaintext</parameter>\n" +" using a public key. It should be noted; in practice this\n" +" function would be used almost exclusively to encrypt symmetric cipher\n" +" keys and not data since asymmetric cipher operations are very slow.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +asymmetric_object_public_encrypt(asymmetric_object *self, PyObject *args) +{ + char *plain_text=NULL, *cipher_text=NULL; + int len=0, size=0; + PyObject *obj=NULL; + + switch( self->cipher_type ) + { + case RSA_CIPHER: + { + if (!PyArg_ParseTuple(args, "s#", &plain_text, &len)) + goto error; + + size = RSA_size(self->cipher); + if ( len > size ) + { PyErr_SetString( SSLErrorObject, "plain text is too long" ); goto error; } + + if ( !(cipher_text = malloc( size + 16 ) ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + if ( (len = RSA_public_encrypt( len, plain_text, cipher_text, self->cipher, RSA_PKCS1_PADDING ) ) < 0 ) + { PyErr_SetString( SSLErrorObject, "could not encrypt plain text" ); goto error; } + break; + } + default: + { PyErr_SetString( SSLErrorObject, "unsupported cipher type" ); goto error; } + } + + obj = Py_BuildValue("s#", cipher_text, len); + free( cipher_text ); + return obj; + +error: + + if (cipher_text) + free(cipher_text); + + return NULL; +} + +static char asymmetric_object_private_encrypt__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Asymmetric</memberof>\n" +" <name>privateEncrypt</name>\n" +" <parameter>plaintext</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method is used to encrypt the <parameter>plaintext</parameter>\n" +" using a private key. It should be noted; in practice this\n" +" function would be used almost exclusively to encrypt symmetric cipher\n" +" keys and not data since asymmetric cipher operations are very slow.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +asymmetric_object_private_encrypt(asymmetric_object *self, PyObject *args) +{ + char *plain_text=NULL, *cipher_text=NULL; + int len=0, size=0; + PyObject *obj=NULL; + + if ( !(self->key_type == RSA_PRIVATE_KEY) ) + { PyErr_SetString( SSLErrorObject, "cannot perform private encryption with this key" ); goto error; } + + if (!PyArg_ParseTuple(args, "s#", &plain_text, &len) ) + goto error; + + size = RSA_size(self->cipher); + if ( len > size ) + { PyErr_SetString( SSLErrorObject, "plain text is too long" ); goto error; } + + if ( !(cipher_text = malloc( size + 16 ) ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + if ( (len = RSA_private_encrypt( len, plain_text, cipher_text, self->cipher, RSA_PKCS1_PADDING ) ) < 0 ) + { PyErr_SetString( SSLErrorObject, "could not encrypt plain text" ); goto error; } + + obj = Py_BuildValue("s#", cipher_text, len); + free( cipher_text ); + return obj; + +error: + + if (cipher_text) + free(cipher_text); + + return NULL; +} + +static char asymmetric_object_public_decrypt__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Asymmetric</memberof>\n" +" <name>publicDecrypt</name>\n" +" <parameter>ciphertext</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method is used to decrypt the\n" +" <parameter>ciphertext</parameter> which has been encrypted\n" +" using the corresponding private key and the\n" +" <function>privateEncrypt</function> function. \n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +asymmetric_object_public_decrypt(asymmetric_object *self, PyObject *args) +{ + char *plain_text=NULL, *cipher_text=NULL; + int len=0, size=0; + PyObject *obj=NULL; + + switch( self->cipher_type ) + { + case RSA_CIPHER: + { + if (!PyArg_ParseTuple(args, "s#", &cipher_text, &len)) + goto error; + + size = RSA_size(self->cipher); + if ( len > size ) + { PyErr_SetString( SSLErrorObject, "cipher text is too long" ); goto error; } + + if ( !(plain_text = malloc( size + 16 ) ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + if ( (len = RSA_public_decrypt( len, cipher_text, plain_text, self->cipher, RSA_PKCS1_PADDING ) ) < 0 ) + { PyErr_SetString( SSLErrorObject, "could not decrypt cipher text" ); goto error; } + break; + } + default: + { PyErr_SetString( SSLErrorObject, "unsupported cipher type" ); goto error; } + } + + obj = Py_BuildValue("s#", plain_text, len); + free( plain_text ); + return obj; + +error: + + if (plain_text) + free(plain_text); + + return NULL; +} + +static char asymmetric_object_private_decrypt__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Asymmetric</memberof>\n" +" <name>privateDecrypt</name>\n" +" <parameter>ciphertext</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method is used to decrypt ciphertext which has been encrypted\n" +" using the corresponding public key and the\n" +" <function>publicEncrypt</function> function. \n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +asymmetric_object_private_decrypt(asymmetric_object *self, PyObject *args) +{ + char *plain_text=NULL, *cipher_text=NULL; + int len=0, size=0; + PyObject *obj=NULL; + + if ( !(self->key_type == RSA_PRIVATE_KEY) ) + { PyErr_SetString( SSLErrorObject, "cannot perform private decryption with this key" ); goto error; } + + if (!PyArg_ParseTuple(args, "s#", &cipher_text, &len)) + goto error; + + size = RSA_size(self->cipher); + if ( len > size ) + { PyErr_SetString( SSLErrorObject, "cipher text is too long" ); goto error; } + + if ( !(plain_text = malloc( size + 16 ) ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + if ( (len = RSA_private_decrypt( len, cipher_text, plain_text, self->cipher, RSA_PKCS1_PADDING ) ) < 0 ) + { PyErr_SetString( SSLErrorObject, "could not decrypt cipher text" ); goto error; } + + obj = Py_BuildValue("s#", plain_text, len); + free( plain_text ); + return obj; + +error: + + if (plain_text) + free(plain_text); + return NULL; +} + +static char asymmetric_object_sign__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Asymmetric</memberof>\n" +" <name>sign</name>\n" +" <parameter>digesttext</parameter>\n" +" <parameter>digesttype</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method is used to produce a signed digest text. \n" +" This instance of\n" +" <classname>Asymmetric</classname> should be a private key used for\n" +" signing. The parameter\n" +" <parameter>digesttext</parameter> should be a digest of the \n" +" data to protect against alteration and\n" +" finally <parameter>digesttype</parameter> should be one of the\n" +" following:\n" +" </para>\n" +" <simplelist>\n" +" <member><constant>MD2_DIGEST</constant></member>\n" +" <member><constant>MD5_DIGEST</constant></member>\n" +" <member><constant>SHA_DIGEST</constant></member>\n" +" <member><constant>SHA1_DIGEST</constant></member>\n" +" <member><constant>RIPEMD160_DIGEST</constant></member>\n" +" </simplelist>\n" +" <para>\n" +" If the procedure was successful, a string containing the signed\n" +" digest is returned. \n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +asymmetric_object_sign(asymmetric_object *self, PyObject *args) +{ + char *digest_text=NULL, *signed_text=NULL; + int digest_len=0, digest_type=0, digest_nid=0, signed_len=0; + PyObject *obj=NULL; + + if (!PyArg_ParseTuple(args, "s#i", &digest_text, &digest_len, &digest_type)) + goto error; + + if (self->key_type != RSA_PRIVATE_KEY) + { PyErr_SetString( SSLErrorObject, "unsupported key type" ); goto error; } + + if ( !(signed_text = malloc( RSA_size(self->cipher) ) ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + switch(digest_type) + { + case MD2_DIGEST: + { digest_nid = NID_md2; digest_len = MD2_DIGEST_LENGTH; break; } + case MD5_DIGEST: + { digest_nid = NID_md5; digest_len = MD5_DIGEST_LENGTH; break; } + case SHA_DIGEST: + { digest_nid = NID_sha; digest_len = SHA_DIGEST_LENGTH; break; } + case SHA1_DIGEST: + { digest_nid = NID_sha1; digest_len = SHA_DIGEST_LENGTH; break; } + case RIPEMD160_DIGEST: + { digest_nid = NID_ripemd160; digest_len = RIPEMD160_DIGEST_LENGTH; break; } + default: + { PyErr_SetString( SSLErrorObject, "unsupported digest" ); goto error; } + } + if ( !(RSA_sign( digest_nid, digest_text, digest_len, signed_text, &signed_len, self->cipher ) ) ) + { PyErr_SetString( SSLErrorObject, "could not sign digest" ); goto error; } + + obj = Py_BuildValue("s#", signed_text, signed_len); + free(signed_text); + return obj; + +error: + + if (signed_text) + free(signed_text); + + return NULL; +} + +static char asymmetric_object_verify__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Asymmetric</memberof>\n" +" <name>verify</name>\n" +" <parameter>signedtext</parameter>\n" +" <parameter>digesttext</parameter>\n" +" <parameter>digesttype</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method is used to verify a signed digest text. \n" +" </para>\n" +" <example>\n" +" <title><function>verify</function> method usage</title>\n" +" <programlisting>\n" +" plain_text = 'Hello World!'\n" +" print '\tPlain text:', plain_text\n" +" digest = POW.Digest( POW.RIPEMD160_DIGEST )\n" +" digest.update( plain_text )\n" +" print '\tDigest text:', digest.digest()\n" +"\n" +" privateFile = open('test/private.key', 'r')\n" +" privateKey = POW.pemRead( POW.RSA_PRIVATE_KEY, privateFile.read(), 'pass' )\n" +" privateFile.close()\n" +" signed_text = privateKey.sign(digest.digest(), POW.RIPEMD160_DIGEST)\n" +" print '\tSigned text:', signed_text\n" +"\n" +" digest2 = POW.Digest( POW.RIPEMD160_DIGEST )\n" +" digest2.update( plain_text )\n" +" publicFile = open('test/public.key', 'r')\n" +" publicKey = POW.pemRead( POW.RSA_PUBLIC_KEY, publicFile.read() )\n" +" publicFile.close()\n" +" if publicKey.verify( signed_text, digest2.digest(), POW.RIPEMD160_DIGEST ):\n" +" print 'Signing verified!'\n" +" else:\n" +" print 'Signing gone wrong!'\n" +" </programlisting>\n" +" </example>\n" +" <para>\n" +" The parameter <parameter>signedtext</parameter> should be a \n" +" signed digest text. This instance of\n" +" <classname>Asymmetric</classname> should correspond to the private\n" +" key used to sign the digest. The parameter\n" +" <parameter>digesttext</parameter> should be a digest of the same\n" +" data used to produce the <parameter>signedtext</parameter> and\n" +" finally <parameter>digesttype</parameter> should be one of the\n" +" following:\n" +" </para>\n" +" <simplelist>\n" +" <member><constant>MD2_DIGEST</constant></member>\n" +" <member><constant>MD5_DIGEST</constant></member>\n" +" <member><constant>SHA_DIGEST</constant></member>\n" +" <member><constant>SHA1_DIGEST</constant></member>\n" +" <member><constant>RIPEMD160_DIGEST</constant></member>\n" +" </simplelist>\n" +" <para>\n" +" If the procedure was successful, 1 is returned, otherwise 0 is\n" +" returned.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; +static PyObject * +asymmetric_object_verify(asymmetric_object *self, PyObject *args) +{ + char *digest_text=NULL, *signed_text=NULL; + int digest_len=0, digest_type=0, digest_nid=0, signed_len=0, result=0; + + if (!PyArg_ParseTuple(args, "s#s#i", &signed_text, &signed_len, &digest_text, &digest_len, &digest_type)) + goto error; + + switch(digest_type) + { + case MD2_DIGEST: + { digest_len = MD2_DIGEST_LENGTH; digest_nid = NID_md2; break; } + case MD5_DIGEST: + { digest_len = MD5_DIGEST_LENGTH; digest_nid = NID_md5; break; } + case SHA_DIGEST: + { digest_len = SHA_DIGEST_LENGTH; digest_nid = NID_sha; break; } + case SHA1_DIGEST: + { digest_len = SHA_DIGEST_LENGTH; digest_nid = NID_sha1; break; } + case RIPEMD160_DIGEST: + { digest_len = RIPEMD160_DIGEST_LENGTH; digest_nid = NID_ripemd160; break; } + default: + { PyErr_SetString( SSLErrorObject, "unsupported digest" ); goto error; } + } + result = RSA_verify( digest_nid, digest_text, digest_len, signed_text, signed_len, self->cipher ); + + return Py_BuildValue("i", result); + +error: + + return NULL; +} + +static struct PyMethodDef asymmetric_object_methods[] = { + {"pemWrite", (PyCFunction)asymmetric_object_pem_write, METH_VARARGS, NULL}, + {"derWrite", (PyCFunction)asymmetric_object_der_write, METH_VARARGS, NULL}, + {"publicEncrypt", (PyCFunction)asymmetric_object_public_encrypt, METH_VARARGS, NULL}, + {"privateEncrypt",(PyCFunction)asymmetric_object_private_encrypt, METH_VARARGS, NULL}, + {"privateDecrypt",(PyCFunction)asymmetric_object_private_decrypt, METH_VARARGS, NULL}, + {"publicDecrypt", (PyCFunction)asymmetric_object_public_decrypt, METH_VARARGS, NULL}, + {"sign", (PyCFunction)asymmetric_object_sign, METH_VARARGS, NULL}, + {"verify", (PyCFunction)asymmetric_object_verify, METH_VARARGS, NULL}, + + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +asymmetric_object_getattr(asymmetric_object *self, char *name) +{ + return Py_FindMethod(asymmetric_object_methods, (PyObject *)self, name); +} + +static void +asymmetric_object_dealloc(asymmetric_object *self, char *name) +{ + switch( self->cipher_type ) + { + case RSA_CIPHER: + { + RSA_free( self->cipher ); + break; + } + } + PyObject_Del(self); +} + +static char asymmetrictype__doc__[] = +"<class>\n" +" <header>\n" +" <name>Asymmetric</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This class provides access to RSA asymmetric ciphers in OpenSSL.\n" +" Other ciphers will probably be supported in the future but this is\n" +" not a priority.\n" +" </para>\n" +" </body>\n" +"</class>\n" +; + +static PyTypeObject asymmetrictype = { + PyObject_HEAD_INIT(0) + 0, /*ob_size*/ + "Asymmetric", /*tp_name*/ + sizeof(asymmetric_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)asymmetric_object_dealloc, /*tp_dealloc*/ + (printfunc)0, /*tp_print*/ + (getattrfunc)asymmetric_object_getattr, /*tp_getattr*/ + (setattrfunc)0, /*tp_setattr*/ + (cmpfunc)0, /*tp_compare*/ + (reprfunc)0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + (hashfunc)0, /*tp_hash*/ + (ternaryfunc)0, /*tp_call*/ + (reprfunc)0, /*tp_str*/ + 0, + 0, + 0, + 0, + asymmetrictype__doc__ /* Documentation string */ +}; +/*========== asymmetric Code ==========*/ + +/*========== symmetric Code ==========*/ +static symmetric_object * +symmetric_object_new(int cipher_type) +{ + symmetric_object *self=NULL; + + self = PyObject_New( symmetric_object, &symmetrictype ); + if (self == NULL) + goto error; + + self->cipher_type = cipher_type; + EVP_CIPHER_CTX_init( &self->cipher_ctx ); + + return self; + +error: + + Py_XDECREF(self); + return NULL; +} + +static char symmetric_object_encrypt_init__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Symmetric</memberof>\n" +" <name>encryptInit</name>\n" +" <parameter>key</parameter>\n" +" <parameter>initialvalue=''</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method sets up the cipher object to start encrypting a stream\n" +" of data. The first parameter is the key used to encrypt the\n" +" data. The second, the <parameter>initialvalue</parameter> serves\n" +" a similar purpose the the salt supplied to the Unix\n" +" <function>crypt</function> function.\n" +" The <parameter>initialvalue</parameter> is normally chosen at random and \n" +" often transmitted with the encrypted data, its purpose is to prevent \n" +" two identical plain texts resulting in two identical cipher texts.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +symmetric_object_encrypt_init(symmetric_object *self, PyObject *args) +{ + char *key=NULL, *iv=NULL, nulliv [] = ""; + EVP_CIPHER *cipher=NULL; + + if (!PyArg_ParseTuple(args, "s|s", &key, &iv)) + goto error; + + if (!iv) + iv = nulliv; + + if ( !(cipher = evp_cipher_factory( self->cipher_type ) ) ) + { PyErr_SetString( SSLErrorObject, "unsupported cipher" ); goto error; } + + if ( !EVP_EncryptInit( &self->cipher_ctx, cipher, key, iv ) ) + { PyErr_SetString( SSLErrorObject, "could not initialise cipher" ); goto error; } + + return Py_BuildValue(""); + +error: + + return NULL; +} + +static char symmetric_object_decrypt_init__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Symmetric</memberof>\n" +" <name>decryptInit</name>\n" +" <parameter>key</parameter>\n" +" <parameter>initialvalue=''</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method sets up the cipher object to start decrypting a stream\n" +" of data. The first value must be the key used to encrypt the\n" +" data. The second parameter is the <parameter>initialvalue</parameter> \n" +" used to encrypt the data.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +symmetric_object_decrypt_init(symmetric_object *self, PyObject *args) +{ + char *key=NULL, *iv=NULL, nulliv [] = ""; + EVP_CIPHER *cipher=NULL; + + if (!PyArg_ParseTuple(args, "s|s", &key, &iv)) + goto error; + + if (!iv) + iv = nulliv; + + if ( !(cipher = evp_cipher_factory( self->cipher_type ) ) ) + { PyErr_SetString( SSLErrorObject, "unsupported cipher" ); goto error; } + + if ( !EVP_DecryptInit( &self->cipher_ctx, cipher, key, iv ) ) + { PyErr_SetString( SSLErrorObject, "could not initialise cipher" ); goto error; } + + return Py_BuildValue(""); + +error: + + return NULL; +} + +static char symmetric_object_update__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Symmetric</memberof>\n" +" <name>update</name>\n" +" <parameter>data</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method is used to process the bulk of data being encrypted\n" +" or decrypted by the cipher object. <parameter>data</parameter>\n" +" should be a string.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +symmetric_object_update(symmetric_object *self, PyObject *args) +{ + int inl=0, outl=0; + char *in=NULL, *out=NULL; + PyObject *py_out=NULL; + + if (!PyArg_ParseTuple(args, "s#", &in, &inl)) + goto error; + + if ( !(out = malloc( inl + EVP_CIPHER_CTX_block_size( &self->cipher_ctx) ) ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + if ( !EVP_CipherUpdate( &self->cipher_ctx, out, &outl, in, inl ) ) + { PyErr_SetString( SSLErrorObject, "could not update cipher" ); goto error; } + + if ( !(py_out = Py_BuildValue("s#", out, outl) ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + free(out); + return py_out; + +error: + + if (out) + free(out); + + return NULL; +} + +static char symmetric_object_final__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Symmetric</memberof>\n" +" <name>final</name>\n" +" <parameter>size=1024</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" Most ciphers are block ciphers, that is they encrypt or decrypt a block of\n" +" data at a time. Often the data being processed will not fill an\n" +" entire block, this method processes these half-empty blocks. A\n" +" string is returned of a maximum length <parameter>size</parameter>. \n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +symmetric_object_final(symmetric_object *self, PyObject *args) +{ + int outl=0, size=1024; + char *out=NULL; + PyObject *py_out=NULL; + + if (!PyArg_ParseTuple(args, "|i", &size)) + goto error; + + if ( !(out = malloc( size + EVP_CIPHER_CTX_block_size( &self->cipher_ctx) ) ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + if ( !EVP_CipherFinal( &self->cipher_ctx, out, &outl ) ) + { PyErr_SetString( SSLErrorObject, "could not update cipher" ); goto error; } + + if ( !(py_out = Py_BuildValue("s#", out, outl) ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + free(out); + return py_out; + +error: + + if (out) + free(out); + + return NULL; +} + +static struct PyMethodDef symmetric_object_methods[] = { + {"encryptInit", (PyCFunction)symmetric_object_encrypt_init, METH_VARARGS, NULL}, + {"decryptInit", (PyCFunction)symmetric_object_decrypt_init, METH_VARARGS, NULL}, + {"update", (PyCFunction)symmetric_object_update, METH_VARARGS, NULL}, + {"final", (PyCFunction)symmetric_object_final, METH_VARARGS, NULL}, + + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +symmetric_object_getattr(symmetric_object *self, char *name) +{ + return Py_FindMethod(symmetric_object_methods, (PyObject *)self, name); +} + +static void +symmetric_object_dealloc(symmetric_object *self, char *name) +{ + PyObject_Del(self); +} + +static char symmetrictype__doc__[] = +"<class>\n" +" <header>\n" +" <name>Symmetric</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This class provides access to all the symmetric ciphers in OpenSSL.\n" +" Initialisation of the cipher structures is performed late, only\n" +" when <function>encryptInit</function> or\n" +" <function>decryptInit</function> is called, the\n" +" constructor only records the cipher type. It is possible to reuse\n" +" the <classname>Symmetric</classname> objects by calling\n" +" <function>encryptInit</function> or <function>decryptInit</function>\n" +" again.\n" +" </para>\n" +" <example>\n" +" <title><classname>Symmetric</classname> class usage</title>\n" +" <programlisting>\n" +" passphrase = 'my silly passphrase'\n" +" md5 = POW.Digest( POW.MD5_DIGEST )\n" +" md5.update( passphrase )\n" +" password = md5.digest()[:8]\n" +"\n" +" plaintext = 'cast test message'\n" +" cast = POW.Symmetric( POW.CAST5_CFB ) \n" +" cast.encryptInit( password )\n" +" ciphertext = cast.update(plaintext) + cast.final()\n" +" print 'Cipher text:', ciphertext\n" +"\n" +" cast.decryptInit( password )\n" +" out = cast.update( ciphertext ) + cast.final()\n" +" print 'Deciphered text:', out\n" +" </programlisting>\n" +" </example>\n" +" </body>\n" +"</class>\n" +; + +static PyTypeObject symmetrictype = { + PyObject_HEAD_INIT(0) + 0, /*ob_size*/ + "Symmetric", /*tp_name*/ + sizeof(symmetric_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)symmetric_object_dealloc, /*tp_dealloc*/ + (printfunc)0, /*tp_print*/ + (getattrfunc)symmetric_object_getattr, /*tp_getattr*/ + (setattrfunc)0, /*tp_setattr*/ + (cmpfunc)0, /*tp_compare*/ + (reprfunc)0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + (hashfunc)0, /*tp_hash*/ + (ternaryfunc)0, /*tp_call*/ + (reprfunc)0, /*tp_str*/ + 0, + 0, + 0, + 0, + symmetrictype__doc__ /* Documentation string */ +}; +/*========== symmetric Code ==========*/ + +/*========== digest Code ==========*/ +static digest_object * +digest_object_new(int digest_type) +{ + digest_object *self=NULL; + + self = PyObject_New( digest_object, &digesttype ); + if (self == NULL) + goto error; + + switch(digest_type) + { + case MD2_DIGEST: + { self->digest_type = MD2_DIGEST; EVP_DigestInit( &self->digest_ctx, EVP_md2() ); break; } + case MD5_DIGEST: + { self->digest_type = MD5_DIGEST; EVP_DigestInit( &self->digest_ctx, EVP_md5() ); break; } + case SHA_DIGEST: + { self->digest_type = SHA_DIGEST; EVP_DigestInit( &self->digest_ctx, EVP_sha() ); break; } + case SHA1_DIGEST: + { self->digest_type = SHA1_DIGEST; EVP_DigestInit( &self->digest_ctx, EVP_sha1() ); break; } + case RIPEMD160_DIGEST: + { self->digest_type = RIPEMD160_DIGEST; EVP_DigestInit( &self->digest_ctx, EVP_ripemd160() ); break; } + default: + { PyErr_SetString( SSLErrorObject, "unsupported digest" ); goto error; } + } + + return self; + +error: + + Py_XDECREF(self); + return NULL; +} + +static char digest_object_update__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Digest</memberof>\n" +" <name>update</name>\n" +" <parameter>data</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method updates the internal structures of the \n" +" <classname>Digest</classname> object with <parameter>data</parameter>.\n" +" <parameter>data</parameter> should be a string.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +digest_object_update(digest_object *self, PyObject *args) +{ + char *data=NULL; + int len=0; + + if (!PyArg_ParseTuple(args, "s#", &data, &len)) + goto error; + + EVP_DigestUpdate( &self->digest_ctx, data, len ); + + return Py_BuildValue(""); + +error: + + return NULL; +} + +static char digest_object_copy__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Digest</memberof>\n" +" <name>copy</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method returns a copy of the <classname>Digest</classname>\n" +" object.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +digest_object_copy(digest_object *self, PyObject *args) +{ + digest_object *new=NULL; + + if ( !(new = PyObject_New( digest_object, &digesttype ) ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + new->digest_type = self->digest_type; + memcpy( &new->digest_ctx, &self->digest_ctx, sizeof(EVP_MD_CTX) ); + + return (PyObject*)new; + +error: + + Py_XDECREF(new); + return NULL; +} + +static char digest_object_digest__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Digest</memberof>\n" +" <name>digest</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method returns the digest of all the data which has been\n" +" processed. This function can be called at any time and will not\n" +" effect the internal structure of the <classname>digest</classname>\n" +" object.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +digest_object_digest(digest_object *self, PyObject *args) +{ + char digest_text[EVP_MAX_MD_SIZE]; + void *md_copy=NULL; + int digest_len=0; + + if (!PyArg_ParseTuple(args, "")) + goto error; + + if ( !(md_copy = malloc( sizeof(EVP_MD_CTX) ) ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + memcpy( md_copy, &self->digest_ctx, sizeof(EVP_MD_CTX) ); + EVP_DigestFinal( md_copy, digest_text, &digest_len ); + + free(md_copy); + return Py_BuildValue("s#", digest_text, digest_len); + +error: + + if (md_copy) + free(md_copy); + + return NULL; +} + +static struct PyMethodDef digest_object_methods[] = { + {"update", (PyCFunction)digest_object_update, METH_VARARGS, NULL}, + {"digest", (PyCFunction)digest_object_digest, METH_VARARGS, NULL}, + {"copy", (PyCFunction)digest_object_copy, METH_VARARGS, NULL}, + + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +digest_object_getattr(digest_object *self, char *name) +{ + return Py_FindMethod(digest_object_methods, (PyObject *)self, name); +} + +static void +digest_object_dealloc(digest_object *self, char *name) +{ + PyObject_Del(self); +} + +static char digesttype__doc__[] = +"<class>\n" +" <header>\n" +" <name>Digest</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This class provides access to the digest functionality of OpenSSL.\n" +" It emulates the digest modules in the Python Standard Library but\n" +" does not currently support the <function>hexdigest</function>\n" +" function.\n" +" </para>\n" +" <example>\n" +" <title><classname>digest</classname> class usage</title>\n" +" <programlisting>\n" +" plain_text = 'Hello World!'\n" +" sha1 = POW.Digest( POW.SHA1_DIGEST )\n" +" sha1.update( plain_text )\n" +" print '\tPlain text: Hello World! =>', sha1.digest()\n" +" </programlisting>\n" +" </example>\n" +" </body>\n" +"</class>\n" +; + +static PyTypeObject digesttype = { + PyObject_HEAD_INIT(0) + 0, /*ob_size*/ + "Digest", /*tp_name*/ + sizeof(digest_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)digest_object_dealloc, /*tp_dealloc*/ + (printfunc)0, /*tp_print*/ + (getattrfunc)digest_object_getattr, /*tp_getattr*/ + (setattrfunc)0, /*tp_setattr*/ + (cmpfunc)0, /*tp_compare*/ + (reprfunc)0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + (hashfunc)0, /*tp_hash*/ + (ternaryfunc)0, /*tp_call*/ + (reprfunc)0, /*tp_str*/ + 0, + 0, + 0, + 0, + digesttype__doc__ /* Documentation string */ +}; +/*========== digest Code ==========*/ + +/*========== hmac Code ==========*/ +static hmac_object * +hmac_object_new(int digest_type, char *key, int key_len) +{ + hmac_object *self=NULL; + EVP_MD *md=NULL; + + self = PyObject_New( hmac_object, &hmactype ); + if (self == NULL) + goto error; + + switch(digest_type) + { + case MD2_DIGEST: + { md = EVP_md2(); break; } + case MD5_DIGEST: + { md = EVP_md5(); break; } + case SHA_DIGEST: + { md = EVP_sha(); break; } + case SHA1_DIGEST: + { md = EVP_sha1(); break; } + case RIPEMD160_DIGEST: + { md = EVP_ripemd160(); break; } + default: + { PyErr_SetString( SSLErrorObject, "unsupported digest" ); goto error; } + } + + HMAC_Init( &self->hmac_ctx, key, key_len, md ); + + return self; + +error: + + Py_XDECREF(self); + return NULL; +} + +static char hmac_object_update__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Hmac</memberof>\n" +" <name>update</name>\n" +" <parameter>data</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method updates the internal structures of the \n" +" <classname>Hmac</classname> object with <parameter>data</parameter>.\n" +" <parameter>data</parameter> should be a string.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +hmac_object_update(hmac_object *self, PyObject *args) +{ + char *data=NULL; + int len=0; + + if (!PyArg_ParseTuple(args, "s#", &data, &len)) + goto error; + + HMAC_Update( &self->hmac_ctx, data, len ); + + return Py_BuildValue(""); + +error: + + return NULL; +} + +static char hmac_object_copy__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Hmac</memberof>\n" +" <name>copy</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method returns a copy of the <classname>Hmac</classname>\n" +" object.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +hmac_object_copy(hmac_object *self, PyObject *args) +{ + hmac_object *new=NULL; + + if ( !(new = PyObject_New( hmac_object, &hmactype ) ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + memcpy( &new->hmac_ctx, &self->hmac_ctx, sizeof(HMAC_CTX) ); + + return (PyObject*)new; + +error: + + Py_XDECREF(new); + return NULL; +} + +static char hmac_object_mac__doc__[] = +"<method>\n" +" <header>\n" +" <memberof>Hmac</memberof>\n" +" <name>mac</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This method returns the MAC of all the data which has been\n" +" processed. This function can be called at any time and will not\n" +" effect the internal structure of the <classname>Hmac</classname>\n" +" object.\n" +" </para>\n" +" </body>\n" +"</method>\n" +; + +static PyObject * +hmac_object_mac(hmac_object *self, PyObject *args) +{ + char hmac_text[EVP_MAX_MD_SIZE]; + void *hmac_copy=NULL; + int hmac_len=0; + + if (!PyArg_ParseTuple(args, "")) + goto error; + + if ( !(hmac_copy = malloc( sizeof(HMAC_CTX) ) ) ) + { PyErr_SetString( SSLErrorObject, "could not allocate memory" ); goto error; } + + memcpy( hmac_copy, &self->hmac_ctx, sizeof(HMAC_CTX) ); + HMAC_Final( hmac_copy, hmac_text, &hmac_len ); + + free(hmac_copy); + return Py_BuildValue("s#", hmac_text, hmac_len); + +error: + + if (hmac_copy) + free(hmac_copy); + + return NULL; +} + + +static struct PyMethodDef hmac_object_methods[] = { + {"update", (PyCFunction)hmac_object_update, METH_VARARGS, NULL}, + {"mac", (PyCFunction)hmac_object_mac, METH_VARARGS, NULL}, + {"copy", (PyCFunction)hmac_object_copy, METH_VARARGS, NULL}, + + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +hmac_object_getattr(hmac_object *self, char *name) +{ + return Py_FindMethod(hmac_object_methods, (PyObject *)self, name); +} + +static void +hmac_object_dealloc(hmac_object *self, char *name) +{ + PyObject_Del(self); +} + +static char hmactype__doc__[] = +"<class>\n" +" <header>\n" +" <name>Hmac</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This class provides access to the HMAC functionality of OpenSSL.\n" +" HMAC's are a variant on digest based MACs, which have the\n" +" interesting property of a provable level of security. HMAC is\n" +" discussed further in RFC 2104.\n" +" </para>\n" +" </body>\n" +"</class>\n" +; + +static PyTypeObject hmactype = { + PyObject_HEAD_INIT(0) + 0, /*ob_size*/ + "Hmac", /*tp_name*/ + sizeof(hmac_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)hmac_object_dealloc, /*tp_dealloc*/ + (printfunc)0, /*tp_print*/ + (getattrfunc)hmac_object_getattr, /*tp_getattr*/ + (setattrfunc)0, /*tp_setattr*/ + (cmpfunc)0, /*tp_compare*/ + (reprfunc)0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + (hashfunc)0, /*tp_hash*/ + (ternaryfunc)0, /*tp_call*/ + (reprfunc)0, /*tp_str*/ + 0, + 0, + 0, + 0, + hmactype__doc__ /* Documentation string */ +}; +/*========== hmac Code ==========*/ +/*========== module functions ==========*/ +static char pow_module_new_ssl__doc__[] = +"<constructor>\n" +" <header>\n" +" <memberof>Ssl</memberof>\n" +" <parameter>protocol=SSLV23METHOD</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This constructor creates a new <classname>Ssl</classname> object which will behave as a client\n" +" or server, depending on the <parameter>protocol</parameter> value passed. The\n" +" <parameter>protocol</parameter> also determines the protocol type\n" +" and version and should be one of the following:\n" +" </para>\n" +"\n" +" <simplelist>\n" +" <member><constant>SSLV2_SERVER_METHOD</constant></member>\n" +" <member><constant>SSLV2_CLIENT_METHOD</constant></member>\n" +" <member><constant>SSLV2_METHOD</constant></member>\n" +" <member><constant>SSLV3_SERVER_METHOD</constant></member>\n" +" <member><constant>SSLV3_CLIENT_METHOD</constant></member>\n" +" <member><constant>SSLV3_METHOD</constant></member>\n" +" <member><constant>TLSV1_SERVER_METHOD</constant></member>\n" +" <member><constant>TLSV1_CLIENT_METHOD</constant></member>\n" +" <member><constant>TLSV1_METHOD</constant></member>\n" +" <member><constant>SSLV23_SERVER_METHOD</constant></member>\n" +" <member><constant>SSLV23_CLIENT_METHOD</constant></member>\n" +" <member><constant>SSLV23_METHOD</constant></member>\n" +" </simplelist>\n" +" </body>\n" +"</constructor>\n" +; + +static PyObject * +pow_module_new_ssl (PyObject *self, PyObject *args) +{ + ssl_object *ssl=NULL; + int ctxtype=SSLV23_METHOD; + + if (!PyArg_ParseTuple(args, "|i", &ctxtype)) + goto error; + + if ( !(ssl = newssl_object(ctxtype) ) ) + goto error; + + return (PyObject*)ssl; + +error: + + return NULL; +} + +static char pow_module_new_x509__doc__[] = +"<constructor>\n" +" <header>\n" +" <memberof>X509</memberof>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This constructor creates a skeletal X509 certificate object.\n" +" It won't be any use at all until several structures \n" +" have been created using it's member functions. \n" +" </para>\n" +" </body>\n" +"</constructor>\n" +; + +static PyObject * +pow_module_new_x509 (PyObject *self, PyObject *args) +{ + x509_object *x509=NULL; + + if (!PyArg_ParseTuple(args, "")) + goto error; + + if ( !(x509 = X509_object_new() ) ) + { PyErr_SetString( SSLErrorObject, "could not create new x509 object" ); goto error; } + + return (PyObject*)x509; + +error: + + return NULL; +} + +static char pow_module_new_asymmetric__doc__[] = +"<constructor>\n" +" <header>\n" +" <memberof>Asymmetric</memberof>\n" +" <parameter>ciphertype=RSA_CIPHER</parameter>\n" +" <parameter>keylength=1024</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This constructor builds a new cipher object. Only RSA ciphers\n" +" are currently support, so the first argument should always be\n" +" <constant>RSA_CIPHER</constant>. The second argument,\n" +" <parameter>keylength</parameter>,\n" +" is normally 512, 768, 1024 or 2048. Key lengths as short as 512\n" +" bits are generally considered weak, and can be cracked by\n" +" determined attackers without tremendous expense.\n" +" </para>\n" +" <example>\n" +" <title><classname>asymmetric</classname> class usage</title>\n" +" <programlisting>\n" +" privateFile = open('test/private.key', 'w')\n" +" publicFile = open('test/public.key', 'w')\n" +"\n" +" passphrase = 'my silly passphrase'\n" +" md5 = POW.Digest( POW.MD5_DIGEST )\n" +" md5.update( passphrase )\n" +" password = md5.digest()\n" +"\n" +" rsa = POW.Asymmetric( POW.RSA_CIPHER, 1024 )\n" +" privateFile.write( rsa.pemWrite( \n" +" POW.RSA_PRIVATE_KEY, POW.DES_EDE3_CFB, password ) )\n" +" publicFile.write( rsa.pemWrite( POW.RSA_PUBLIC_KEY ) )\n" +"\n" +" privateFile.close()\n" +" publicFile.close()\n" +" </programlisting>\n" +" </example>\n" +" </body>\n" +"</constructor>\n" +; + +static PyObject * +pow_module_new_asymmetric (PyObject *self, PyObject *args) +{ + int cipher_type=RSA_CIPHER, key_size=1024; + + if (!PyArg_ParseTuple(args, "|ii", &cipher_type, &key_size)) + goto error; + + return (PyObject*)asymmetric_object_new( cipher_type, key_size ); + +error: + + return NULL; +} + +static char pow_module_new_digest__doc__[] = +"<constructor>\n" +" <header>\n" +" <memberof>Digest</memberof>\n" +" <parameter>type</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This constructor creates a new <classname>Digest</classname>\n" +" object. The parameter <parameter>type</parameter> specifies what kind\n" +" of digest to create and should be one of the following: \n" +" </para>\n" +" <simplelist>\n" +" <member><constant>MD2_DIGEST</constant></member>\n" +" <member><constant>MD5_DIGEST</constant></member>\n" +" <member><constant>SHA_DIGEST</constant></member>\n" +" <member><constant>SHA1_DIGEST</constant></member>\n" +" <member><constant>RIPEMD160_DIGEST</constant></member>\n" +" </simplelist>\n" +" </body>\n" +"</constructor>\n" +; + +static PyObject * +pow_module_new_digest (PyObject *self, PyObject *args) +{ + int digest_type=0; + + if (!PyArg_ParseTuple(args, "i", &digest_type)) + goto error; + + return (PyObject*)digest_object_new( digest_type ); + +error: + + return NULL; +} + +static char pow_module_new_hmac__doc__[] = +"<constructor>\n" +" <header>\n" +" <memberof>Hmac</memberof>\n" +" <parameter>type</parameter>\n" +" <parameter>key</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This constructor creates a new <classname>Hmac</classname>\n" +" object. The parameter <parameter>key</parameter> should be a\n" +" string and <parameter>type</parameter> should be one of the following: \n" +" </para>\n" +" <simplelist>\n" +" <member><constant>MD2_DIGEST</constant></member>\n" +" <member><constant>MD5_DIGEST</constant></member>\n" +" <member><constant>SHA_DIGEST</constant></member>\n" +" <member><constant>SHA1_DIGEST</constant></member>\n" +" <member><constant>RIPEMD160_DIGEST</constant></member>\n" +" </simplelist>\n" +" </body>\n" +"</constructor>\n" +; + +static PyObject * +pow_module_new_hmac (PyObject *self, PyObject *args) +{ + int digest_type=0, key_len=0; + char *key=NULL; + + if (!PyArg_ParseTuple(args, "is#", &digest_type, &key, &key_len)) + goto error; + + return (PyObject*)hmac_object_new( digest_type, key, key_len ); + +error: + + return NULL; +} + +static char pow_module_pem_read__doc__[] = +"<modulefunction>\n" +" <header>\n" +" <name>pemRead</name>\n" +" <parameter>type</parameter>\n" +" <parameter>string</parameter>\n" +" <parameter>pass=None</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This function attempts to parse the <parameter>string</parameter> according to the PEM\n" +" type passed. <parameter>type</parameter> should be one of the\n" +" following:\n" +" </para>\n" +" <simplelist>\n" +" <member><constant>RSA_PUBLIC_KEY</constant></member>\n" +" <member><constant>RSA_PRIVATE_KEY</constant></member>\n" +" <member><constant>X509_CERTIFICATE</constant></member>\n" +" <member><constant>X509_CRL</constant></member>\n" +" </simplelist>\n" +" <para>\n" +" <parameter>pass</parameter> should only be provided if an encrypted\n" +" <classname>Asymmetric</classname> is being loaded. If the password\n" +" is incorrect an exception will be raised, if no password is provided\n" +" and the PEM file is encrypted the user will be prompted. If this is\n" +" not desirable, always supply a password. The object returned will be \n" +" and instance of <classname>Asymmetric</classname>, \n" +" <classname>X509</classname> or <classname>X509Crl</classname>.\n" +" </para>\n" +" </body>\n" +"</modulefunction>\n" +; + +static PyObject * +pow_module_pem_read (PyObject *self, PyObject *args) +{ + BIO *in=NULL; + PyObject *obj=NULL; + int object_type=0, len=0; + char *pass=NULL, *src=NULL; + + if (!PyArg_ParseTuple(args, "is#|s", &object_type, &src, &len, &pass)) + goto error; + + if ( !(in = BIO_new_mem_buf(src, -1) ) ) + { PyErr_SetString( SSLErrorObject, "unable to create new BIO" ); goto error; } + + if ( !BIO_write( in, src, len ) ) + { PyErr_SetString( SSLErrorObject, "unable to write to BIO" ); goto error; } + + switch(object_type) + { + case RSA_PRIVATE_KEY: + { obj = (PyObject*)asymmetric_object_pem_read( object_type, in, pass ); break; } + case RSA_PUBLIC_KEY: + { obj = (PyObject*)asymmetric_object_pem_read( object_type, in, pass ); break; } + case X509_CERTIFICATE: + { obj = (PyObject*)X509_object_pem_read( in ); break ; } + case X_X509_CRL: + { obj = (PyObject*)x509_crl_object_pem_read( in ); break ; } + + default: + { PyErr_SetString( SSLErrorObject, "unknown pem encoding" ); goto error; } + } + + BIO_free(in); + + if (obj) + return obj; + +error: + + return NULL; +} + + + + +static char pow_module_der_read__doc__[] = +"<modulefunction>\n" +" <header>\n" +" <name>derRead</name>\n" +" <parameter>type</parameter>\n" +" <parameter>string</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This function attempts to parse the <parameter>string</parameter> according to the PEM\n" +" type passed. <parameter>type</parameter> should be one of the\n" +" following:\n" +" </para>\n" +" <simplelist>\n" +" <member><constant>RSA_PUBLIC_KEY</constant></member>\n" +" <member><constant>RSA_PRIVATE_KEY</constant></member>\n" +" <member><constant>X509_CERTIFICATE</constant></member>\n" +" <member><constant>X509_CRL</constant></member>\n" +" </simplelist>\n" +" <para>\n" +" As with the PEM operations, the object returned will be and instance \n" +" of <classname>Asymmetric</classname>, <classname>X509</classname> or \n" +" <classname>X509Crl</classname>.\n" +" </para>\n" +" </body>\n" +"</modulefunction>\n" +; + +static PyObject * +pow_module_der_read (PyObject *self, PyObject *args) +{ + PyObject *obj=NULL; + int object_type=0, len=0; + char *src=NULL; + + if (!PyArg_ParseTuple(args, "is#", &object_type, &src, &len)) + goto error; + + switch(object_type) + { + case RSA_PRIVATE_KEY: + { obj = (PyObject*)asymmetric_object_der_read( object_type, src, len ); break; } + case RSA_PUBLIC_KEY: + { obj = (PyObject*)asymmetric_object_der_read( object_type, src, len ); break; } + case X509_CERTIFICATE: + { obj = (PyObject*)X509_object_der_read( src, len ); break ; } + case X_X509_CRL: + { obj = (PyObject*)x509_crl_object_der_read( src, len ); break ; } + + default: + { PyErr_SetString( SSLErrorObject, "unknown der encoding" ); goto error; } + } + + if (obj) + return obj; + +error: + + return NULL; +} + +static char pow_module_new_x509_store__doc__[] = +"<constructor>\n" +" <header>\n" +" <memberof>X509Store</memberof>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This constructor takes no arguments. The\n" +" <classname>X509Store</classname> returned cannot be used for\n" +" verifying certificates until at least one trusted certificate has been\n" +" added.\n" +" </para>\n" +" </body>\n" +"</constructor>\n" +; + +static PyObject * +pow_module_new_x509_store (PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + goto error; + + return (PyObject*)x509_store_object_new(); + +error: + + return NULL; +} + +static char pow_module_new_symmetric__doc__[] = +"<constructor>\n" +" <header>\n" +" <memberof>Symmetric</memberof>\n" +" <parameter>type</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This constructor creates a new <classname>Symmetric</classname>\n" +" object. The parameter <parameter>type</parameter> specifies which kind\n" +" of cipher to create. <constant>type</constant> should be one of the following: \n" +" </para>\n" +" <simplelist columns=\"2\">\n" +" <member><constant>DES_ECB</constant></member> \n" +" <member><constant>DES_EDE</constant></member>\n" +" <member><constant>DES_EDE3</constant></member> \n" +" <member><constant>DES_CFB</constant></member> \n" +" <member><constant>DES_EDE_CFB</constant></member> \n" +" <member><constant>DES_EDE3_CFB</constant></member>\n" +" <member><constant>DES_OFB</constant></member>\n" +" <member><constant>DES_EDE_OFB</constant></member>\n" +" <member><constant>DES_EDE3_OFB</constant></member>\n" +" <member><constant>DES_CBC</constant></member>\n" +" <member><constant>DES_EDE_CBC</constant></member>\n" +" <member><constant>DES_EDE3_CBC</constant></member>\n" +" <member><constant>DESX_CBC</constant></member>\n" +" <member><constant>RC4</constant></member>\n" +" <member><constant>RC4_40</constant></member>\n" +" <member><constant>IDEA_ECB</constant></member>\n" +" <member><constant>IDEA_CFB</constant></member>\n" +" <member><constant>IDEA_OFB</constant></member>\n" +" <member><constant>IDEA_CBC</constant></member>\n" +" <member><constant>RC2_ECB</constant></member>\n" +" <member><constant>RC2_CBC</constant></member>\n" +" <member><constant>RC2_40_CBC</constant></member>\n" +" <member><constant>RC2_CFB</constant></member>\n" +" <member><constant>RC2_OFB</constant></member>\n" +" <member><constant>BF_ECB</constant></member>\n" +" <member><constant>BF_CBC</constant></member>\n" +" <member><constant>BF_CFB</constant></member>\n" +" <member><constant>BF_OFB</constant></member>\n" +" <member><constant>CAST5_ECB</constant></member>\n" +" <member><constant>CAST5_CBC</constant></member>\n" +" <member><constant>CAST5_CFB</constant></member>\n" +" <member><constant>CAST5_OFB</constant></member>\n" +" <member><constant>RC5_32_12_16_CBC</constant></member>\n" +" <member><constant>RC5_32_12_16_CFB</constant></member>\n" +" <member><constant>RC5_32_12_16_ECB</constant></member>\n" +" <member><constant>RC5_32_12_16_OFB</constant></member>\n" +" </simplelist>\n" +" <para>\n" +" Please note your version of OpenSSL might not have been compiled with\n" +" all the ciphers listed above. If that is the case, which is very\n" +" likely if you are using a stock binary, the unsuported ciphers will not even\n" +" be in the module namespace.\n" +" </para>\n" +" </body>\n" +"</constructor>\n" +; + +static PyObject * +pow_module_new_symmetric (PyObject *self, PyObject *args) +{ + int cipher_type=0; + + if (!PyArg_ParseTuple(args, "i", &cipher_type)) + goto error; + + return (PyObject*)symmetric_object_new(cipher_type); + +error: + + return NULL; +} + +static char pow_module_new_x509_crl__doc__[] = +"<constructor>\n" +" <header>\n" +" <memberof>x509_crl</memberof>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This constructor builds an empty CRL.\n" +" </para>\n" +" </body>\n" +"</constructor>\n" +; + +static PyObject * +pow_module_new_x509_crl (PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + goto error; + + return (PyObject*)x509_crl_object_new(); + +error: + + return NULL; +} + +static char pow_module_new_x509_revoked__doc__[] = +"<constructor>\n" +" <header>\n" +" <memberof>X509Revoked</memberof>\n" +" <parameter>serial</parameter>\n" +" <parameter>date</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This constructor builds a X509 Revoked structure. <parameter>serial</parameter>\n" +" should be an integer and <parameter>date</parameter> should be and\n" +" UTCTime string.\n" +" </para>\n" +" </body>\n" +"</constructor>\n" +; + +static PyObject * +pow_module_new_x509_revoked (PyObject *self, PyObject *args) +{ + int serial=-1; + char *date=NULL; + x509_revoked_object *revoke=NULL; + + if (!PyArg_ParseTuple(args, "|is", &serial, &date)) + goto error; + + revoke = x509_revoked_object_new(); + if (serial != -1) + if ( !ASN1_INTEGER_set( revoke->revoked->serialNumber, serial ) ) + { PyErr_SetString( SSLErrorObject, "unable to set serial number" ); goto error; } + + if (date != NULL) + if (!ASN1_UTCTIME_set_string( revoke->revoked->revocationDate, date )) + { PyErr_SetString( PyExc_TypeError, "could not set revocationDate" ); goto error; } + + return (PyObject*)revoke; + +error: + + return NULL; +} + +static char pow_module_add_object__doc__[] = +"<modulefunction>\n" +" <header>\n" +" <name>addObject</name>\n" +" <parameter>oid</parameter>\n" +" <parameter>shortName</parameter>\n" +" <parameter>longName</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This function can be used to dynamically add new objects to\n" +" OpenSSL. The <parameter>oid</parameter> should be a string of space separated numbers\n" +" and <parameter>shortName</parameter> and\n" +" <parameter>longName</parameter> are the names of the object, ie\n" +" 'cn' and 'commonName'.\n" +" </para>\n" +" </body>\n" +"</modulefunction>\n" +; + +static PyObject * +pow_module_add_object(PyObject *self, PyObject *args) +{ + char *oid=NULL, *sn=NULL, *ln=NULL; + + if (!PyArg_ParseTuple(args, "sss", &oid, &sn, &ln)) + goto error; + + if (!OBJ_create(oid, sn, ln) ) + {PyErr_SetString(SSLErrorObject, "unable to add object"); goto error;} + + return Py_BuildValue(""); + +error: + + return NULL; +} + +static char pow_module_get_error__doc__[] = +"<modulefunction>\n" +" <header>\n" +" <name>getError</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" Pops an error off the global error stack and returns it as a string.\n" +" </para>\n" +" </body>\n" +"</modulefunction>\n" +; + +static PyObject * +pow_module_get_error(PyObject *self, PyObject *args) +{ + unsigned long error; + char buf[256]; + + if (!PyArg_ParseTuple(args, "")) + goto error; + + error = ERR_get_error(); + ERR_error_string( error, buf ); + + return Py_BuildValue("s", buf); + +error: + + return NULL; +} + +static char pow_module_clear_error__doc__[] = +"<modulefunction>\n" +" <header>\n" +" <name>clearError</name>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" Removes all errors from the global error stack.\n" +" </para>\n" +" </body>\n" +"</modulefunction>\n" +; + +static PyObject * +pow_module_clear_error(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + goto error; + + ERR_clear_error(); + + return Py_BuildValue(""); + +error: + + return NULL; +} + +static char pow_module_seed__doc__[] = +"<modulefunction>\n" +" <header>\n" +" <name>seed</name>\n" +" <parameter>data</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" The <function>seed</function> function adds data to OpenSSLs PRNG\n" +" state. It is often said the hardest part of cryptography is\n" +" getting good random data, after all if you don't have good random\n" +" data, a 1024 bit key is no better than a 512 bit key and neither\n" +" would provide protection from a targeted brute force attack.\n" +" The <function>seed</function> and <function>add</function> are very\n" +" similar, except the entropy of the data is assumed to be equal to\n" +" the length for <function>seed</function>. I final point to be aware \n" +" of, only systems which support /dev/urandom are automatically seeded. \n" +" If your system does not support /dev/urandom it is your responsibility \n" +" to seed OpenSSL's PRNG.\n" +" </para>\n" +" </body>\n" +"</modulefunction>\n" +; + +static PyObject * +pow_module_seed(PyObject *self, PyObject *args) +{ + char *in=NULL; + int inl=0; + + if (!PyArg_ParseTuple(args, "s#", &in, &inl)) + goto error; + + RAND_seed( in, inl ); + + return Py_BuildValue(""); + +error: + + return NULL; +} + +static char pow_module_add__doc__[] = +"<modulefunction>\n" +" <header>\n" +" <name>add</name>\n" +" <parameter>data</parameter>\n" +" <parameter>entropy</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" The <function>add</function> function adds data to OpenSSLs PRNG\n" +" state. <parameter>data</parameter> should be data obtained from a\n" +" random source and <parameter>entropy</parameter> is an estimation of the number of random\n" +" bytes in <parameter>data</parameter>.\n" +" </para>\n" +" </body>\n" +"</modulefunction>\n" +; + +static PyObject * +pow_module_add(PyObject *self, PyObject *args) +{ + char *in=NULL; + int inl=0; + double entropy=0; + + if (!PyArg_ParseTuple(args, "s#d", &in, &inl, &entropy)) + goto error; + + RAND_add( in, inl, entropy ); + + return Py_BuildValue(""); + +error: + + return NULL; +} + +static char pow_module_write_random_file__doc__[] = +"<modulefunction>\n" +" <header>\n" +" <name>writeRandomFile</name>\n" +" <parameter>filename</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This function writes the current random state to a file. Clearly\n" +" this function should be used in conjunction with\n" +" <function>readRandomFile</function>.\n" +" </para>\n" +" </body>\n" +"</modulefunction>\n" +; + +static PyObject * +pow_module_write_random_file(PyObject *self, PyObject *args) +{ + char *file=NULL; + + if (!PyArg_ParseTuple(args, "s", &file)) + goto error; + + if ( RAND_write_file( file ) == -1 ) + {PyErr_SetString(SSLErrorObject, "could not write random file"); goto error;} + + return Py_BuildValue(""); + +error: + + return NULL; +} + +static char pow_module_read_random_file__doc__[] = +"<modulefunction>\n" +" <header>\n" +" <name>readRandomFile</name>\n" +" <parameter>filename</parameter>\n" +" </header>\n" +" <body>\n" +" <para>\n" +" This function reads a previously saved random state. It can be very\n" +" useful to improve the quality of random data used by an application.\n" +" The random data should be added to, using the\n" +" <function>add</function> function, with data from other\n" +" suitable random sources.\n" +" </para>\n" +" </body>\n" +"</modulefunction>\n" +; + +static PyObject * +pow_module_read_random_file(PyObject *self, PyObject *args) +{ + char *file=NULL; + int len=-1; + + if (!PyArg_ParseTuple(args, "s|i", &file, &len)) + goto error; + + if (!RAND_load_file( file, len ) ) + {PyErr_SetString(SSLErrorObject, "could not load random file"); goto error;} + + return Py_BuildValue(""); + +error: + + return NULL; +} + +static PyObject * +pow_module_docset(PyObject *self, PyObject *args) +{ + PyObject *docset; + + if (!PyArg_ParseTuple(args, "")) + goto error; + + docset = PyList_New(0); + // module documentation + docset_helper_add( docset, pow_module__doc__ ); + // constructors + docset_helper_add( docset, pow_module_new_symmetric__doc__ ); + docset_helper_add( docset, pow_module_new_asymmetric__doc__ ); + docset_helper_add( docset, pow_module_new_digest__doc__ ); + docset_helper_add( docset, pow_module_new_hmac__doc__ ); + docset_helper_add( docset, pow_module_new_ssl__doc__ ); + docset_helper_add( docset, pow_module_new_x509__doc__ ); + docset_helper_add( docset, pow_module_new_x509_store__doc__ ); + docset_helper_add( docset, pow_module_new_x509_crl__doc__ ); + docset_helper_add( docset, pow_module_new_x509_revoked__doc__ ); + // functions + docset_helper_add( docset, pow_module_pem_read__doc__ ); + docset_helper_add( docset, pow_module_der_read__doc__ ); + docset_helper_add( docset, pow_module_seed__doc__ ); + docset_helper_add( docset, pow_module_add__doc__ ); + docset_helper_add( docset, pow_module_read_random_file__doc__ ); + docset_helper_add( docset, pow_module_write_random_file__doc__ ); + docset_helper_add( docset, pow_module_get_error__doc__ ); + docset_helper_add( docset, pow_module_clear_error__doc__ ); + docset_helper_add( docset, pow_module_add_object__doc__ ); + + // ssl documentation + docset_helper_add( docset, ssltype__doc__ ); + docset_helper_add( docset, ssl_object_set_fd__doc__ ); + docset_helper_add( docset, ssl_object_accept__doc__ ); + docset_helper_add( docset, ssl_object_connect__doc__ ); + docset_helper_add( docset, ssl_object_write__doc__ ); + docset_helper_add( docset, ssl_object_read__doc__ ); + docset_helper_add( docset, ssl_object_peer_certificate__doc__ ); + docset_helper_add( docset, ssl_object_use_certificate__doc__ ); + docset_helper_add( docset, ssl_object_use_key__doc__ ); + docset_helper_add( docset, ssl_object_check_key__doc__ ); + docset_helper_add( docset, ssl_object_clear__doc__ ); + docset_helper_add( docset, ssl_object_shutdown__doc__ ); + docset_helper_add( docset, ssl_object_get_shutdown__doc__ ); + docset_helper_add( docset, ssl_object_get_ciphers__doc__ ); + docset_helper_add( docset, ssl_object_set_ciphers__doc__ ); + docset_helper_add( docset, ssl_object_get_cipher__doc__ ); + docset_helper_add( docset, ssl_object_set_verify_mode__doc__ ); + + // x509 documentation + docset_helper_add( docset, x509type__doc__ ); + docset_helper_add( docset, X509_object_pem_write__doc__ ); + docset_helper_add( docset, X509_object_der_write__doc__ ); + docset_helper_add( docset, X509_object_sign__doc__ ); + docset_helper_add( docset, X509_object_set_public_key__doc__ ); + docset_helper_add( docset, X509_object_get_version__doc__ ); + docset_helper_add( docset, X509_object_set_version__doc__ ); + docset_helper_add( docset, X509_object_get_serial__doc__ ); + docset_helper_add( docset, X509_object_set_serial__doc__ ); + docset_helper_add( docset, X509_object_get_issuer__doc__ ); + docset_helper_add( docset, X509_object_set_issuer__doc__ ); + docset_helper_add( docset, X509_object_get_subject__doc__ ); + docset_helper_add( docset, X509_object_set_subject__doc__ ); + docset_helper_add( docset, X509_object_get_not_before__doc__ ); + docset_helper_add( docset, X509_object_set_not_before__doc__ ); + docset_helper_add( docset, X509_object_get_not_after__doc__ ); + docset_helper_add( docset, X509_object_set_not_after__doc__ ); + docset_helper_add( docset, X509_object_add_extension__doc__ ); + docset_helper_add( docset, X509_object_clear_extensions__doc__ ); + docset_helper_add( docset, X509_object_count_extensions__doc__ ); + docset_helper_add( docset, X509_object_get_extension__doc__ ); + docset_helper_add( docset, x509_object_pprint__doc__ ); + + // x509_crl documentation + docset_helper_add( docset, x509_crltype__doc__ ); + docset_helper_add( docset, x509_crl_object_pem_write__doc__ ); + docset_helper_add( docset, x509_crl_object_der_write__doc__ ); + docset_helper_add( docset, x509_crl_object_get_version__doc__ ); + docset_helper_add( docset, x509_crl_object_set_version__doc__ ); + docset_helper_add( docset, x509_crl_object_get_issuer__doc__ ); + docset_helper_add( docset, x509_crl_object_set_issuer__doc__ ); + docset_helper_add( docset, x509_crl_object_get_this_update__doc__ ); + docset_helper_add( docset, x509_crl_object_set_this_update__doc__ ); + docset_helper_add( docset, x509_crl_object_get_next_update__doc__ ); + docset_helper_add( docset, x509_crl_object_set_next_update__doc__ ); + docset_helper_add( docset, x509_crl_object_get_revoked__doc__ ); + docset_helper_add( docset, x509_crl_object_set_revoked__doc__ ); + docset_helper_add( docset, x509_crl_object_verify__doc__ ); + docset_helper_add( docset, x509_crl_object_sign__doc__ ); + docset_helper_add( docset, X509_crl_object_add_extension__doc__ ); + docset_helper_add( docset, X509_crl_object_clear_extensions__doc__ ); + docset_helper_add( docset, X509_crl_object_count_extensions__doc__ ); + docset_helper_add( docset, X509_crl_object_get_extension__doc__ ); + docset_helper_add( docset, x509_crl_object_pprint__doc__ ); + + // x509_revoked documentation + docset_helper_add( docset, x509_revokedtype__doc__ ); + docset_helper_add( docset, x509_revoked_object_get_date__doc__ ); + docset_helper_add( docset, x509_revoked_object_set_date__doc__ ); + docset_helper_add( docset, x509_revoked_object_get_serial__doc__ ); + docset_helper_add( docset, x509_revoked_object_set_serial__doc__ ); + docset_helper_add( docset, X509_revoked_object_add_extension__doc__ ); + docset_helper_add( docset, X509_revoked_object_clear_extensions__doc__ ); + docset_helper_add( docset, X509_revoked_object_count_extensions__doc__ ); + docset_helper_add( docset, X509_revoked_object_get_extension__doc__ ); + + // x509_store documentation + docset_helper_add( docset, x509_storetype__doc__ ); + docset_helper_add( docset, x509_store_object_verify__doc__ ); + docset_helper_add( docset, x509_store_object_verify_chain__doc__ ); + docset_helper_add( docset, x509_store_object_add_trust__doc__ ); + docset_helper_add( docset, x509_store_object_add_crl__doc__ ); + + // digest documentation + docset_helper_add( docset, digesttype__doc__ ); + docset_helper_add( docset, digest_object_update__doc__ ); + docset_helper_add( docset, digest_object_copy__doc__ ); + docset_helper_add( docset, digest_object_digest__doc__ ); + + // hmac documentation + docset_helper_add( docset, hmactype__doc__ ); + docset_helper_add( docset, hmac_object_update__doc__ ); + docset_helper_add( docset, hmac_object_copy__doc__ ); + docset_helper_add( docset, hmac_object_mac__doc__ ); + + // symmetric documentation + docset_helper_add( docset, symmetrictype__doc__ ); + docset_helper_add( docset, symmetric_object_encrypt_init__doc__ ); + docset_helper_add( docset, symmetric_object_decrypt_init__doc__ ); + docset_helper_add( docset, symmetric_object_update__doc__ ); + docset_helper_add( docset, symmetric_object_final__doc__ ); + + // asymmetric documentation + docset_helper_add( docset, asymmetrictype__doc__ ); + docset_helper_add( docset, asymmetric_object_pem_write__doc__ ); + docset_helper_add( docset, asymmetric_object_der_write__doc__ ); + docset_helper_add( docset, asymmetric_object_public_encrypt__doc__ ); + docset_helper_add( docset, asymmetric_object_public_decrypt__doc__ ); + docset_helper_add( docset, asymmetric_object_private_encrypt__doc__ ); + docset_helper_add( docset, asymmetric_object_private_decrypt__doc__ ); + docset_helper_add( docset, asymmetric_object_sign__doc__ ); + docset_helper_add( docset, asymmetric_object_verify__doc__ ); + + return Py_BuildValue("O", docset); + +error: + + return NULL; +} + +static struct PyMethodDef pow_module_methods[] = { + {"Ssl", (PyCFunction)pow_module_new_ssl, METH_VARARGS, NULL}, + {"X509", (PyCFunction)pow_module_new_x509, METH_VARARGS, NULL}, + {"pemRead", (PyCFunction)pow_module_pem_read, METH_VARARGS, NULL}, + {"derRead", (PyCFunction)pow_module_der_read, METH_VARARGS, NULL}, + {"Digest", (PyCFunction)pow_module_new_digest, METH_VARARGS, NULL}, + {"Hmac", (PyCFunction)pow_module_new_hmac, METH_VARARGS, NULL}, + {"Asymmetric", (PyCFunction)pow_module_new_asymmetric, METH_VARARGS, NULL}, + {"Symmetric", (PyCFunction)pow_module_new_symmetric, METH_VARARGS, NULL}, + {"X509Store", (PyCFunction)pow_module_new_x509_store, METH_VARARGS, NULL}, + {"X509Crl", (PyCFunction)pow_module_new_x509_crl, METH_VARARGS, NULL}, + {"X509Revoked", (PyCFunction)pow_module_new_x509_revoked, METH_VARARGS, NULL}, + {"getError", (PyCFunction)pow_module_get_error, METH_VARARGS, NULL}, + {"clearError", (PyCFunction)pow_module_clear_error, METH_VARARGS, NULL}, + {"seed", (PyCFunction)pow_module_seed, METH_VARARGS, NULL}, + {"add", (PyCFunction)pow_module_add, METH_VARARGS, NULL}, + {"readRandomFile",(PyCFunction)pow_module_read_random_file, METH_VARARGS, NULL}, + {"writeRandomFile", (PyCFunction)pow_module_write_random_file, METH_VARARGS, NULL}, + {"addObject", (PyCFunction)pow_module_add_object, METH_VARARGS, NULL}, + + {"_docset", (PyCFunction)pow_module_docset, METH_VARARGS, NULL}, + + {NULL, (PyCFunction)NULL, 0, NULL} /* sentinel */ +}; +/*========== module functions ==========*/ + + +/*==========================================================================*/ +void +init_POW(void) +{ + PyObject *m, *d; + + x509type.ob_type = &PyType_Type; + x509_storetype.ob_type = &PyType_Type; + x509_crltype.ob_type = &PyType_Type; + x509_revokedtype.ob_type = &PyType_Type; + ssltype.ob_type = &PyType_Type; + asymmetrictype.ob_type = &PyType_Type; + symmetrictype.ob_type = &PyType_Type; + digesttype.ob_type = &PyType_Type; + hmactype.ob_type = &PyType_Type; + + m = Py_InitModule4("_POW", pow_module_methods, + pow_module__doc__, + (PyObject*)NULL,PYTHON_API_VERSION); + + d = PyModule_GetDict(m); + SSLErrorObject = PyString_FromString("POW.SSLError"); + PyDict_SetItemString(d, "SSLError", SSLErrorObject); + + // constants for SSL_get_error() + install_int_const( d, "SSL_ERROR_NONE", SSL_ERROR_NONE ); + install_int_const( d, "SSL_ERROR_ZERO_RETURN", SSL_ERROR_ZERO_RETURN ); + install_int_const( d, "SSL_ERROR_WANT_READ", SSL_ERROR_WANT_READ ); + install_int_const( d, "SSL_ERROR_WANT_WRITE", SSL_ERROR_WANT_WRITE ); + install_int_const( d, "SSL_ERROR_WANT_X509_LOOKUP",SSL_ERROR_WANT_X509_LOOKUP ); + install_int_const( d, "SSL_ERROR_SYSCALL", SSL_ERROR_SYSCALL ); + install_int_const( d, "SSL_ERROR_SSL", SSL_ERROR_SSL ); + + // constants for different types of connection methods + install_int_const( d, "SSLV2_SERVER_METHOD", SSLV2_SERVER_METHOD ); + install_int_const( d, "SSLV2_CLIENT_METHOD", SSLV2_CLIENT_METHOD ); + install_int_const( d, "SSLV2_METHOD", SSLV2_METHOD ); + install_int_const( d, "SSLV3_SERVER_METHOD", SSLV3_SERVER_METHOD ); + install_int_const( d, "SSLV3_CLIENT_METHOD", SSLV3_CLIENT_METHOD ); + install_int_const( d, "SSLV3_METHOD", SSLV3_METHOD ); + install_int_const( d, "SSLV23_SERVER_METHOD", SSLV23_SERVER_METHOD ); + install_int_const( d, "SSLV23_CLIENT_METHOD", SSLV23_CLIENT_METHOD ); + install_int_const( d, "SSLV23_METHOD", SSLV23_METHOD ); + install_int_const( d, "TLSV1_SERVER_METHOD", TLSV1_SERVER_METHOD ); + install_int_const( d, "TLSV1_CLIENT_METHOD", TLSV1_CLIENT_METHOD ); + install_int_const( d, "TLSV1_METHOD", TLSV1_METHOD ); + + install_int_const( d, "SSL_NO_SHUTDOWN", 0 ); + install_int_const( d, "SSL_SENT_SHUTDOWN", SSL_SENT_SHUTDOWN ); + install_int_const( d, "SSL_RECIEVED_SHUTDOWN", SSL_RECEIVED_SHUTDOWN ); + + // ssl verification mode + install_int_const( d, "SSL_VERIFY_NONE", SSL_VERIFY_NONE ); + install_int_const( d, "SSL_VERIFY_PEER", SSL_VERIFY_PEER ); + + // object format types + install_int_const( d, "LONGNAME_FORMAT", LONGNAME_FORMAT ); + install_int_const( d, "SHORTNAME_FORMAT", SHORTNAME_FORMAT ); + + // PEM encoded types +#ifndef NO_RSA + install_int_const( d, "RSA_PUBLIC_KEY", RSA_PUBLIC_KEY ); + install_int_const( d, "RSA_PRIVATE_KEY", RSA_PRIVATE_KEY ); +#endif +#ifndef NO_DSA + install_int_const( d, "DSA_PUBLIC_KEY", DSA_PUBLIC_KEY ); + install_int_const( d, "DSA_PRIVATE_KEY", DSA_PRIVATE_KEY ); +#endif +#ifndef NO_DH + install_int_const( d, "DH_PUBLIC_KEY", DH_PUBLIC_KEY ); + install_int_const( d, "DH_PRIVATE_KEY", DH_PRIVATE_KEY ); +#endif + install_int_const( d, "X509_CERTIFICATE", X509_CERTIFICATE ); + install_int_const( d, "X509_CRL", X_X509_CRL ); + + // asymmetric ciphers +#ifndef NO_RSA + install_int_const( d, "RSA_CIPHER", RSA_CIPHER ); +#endif +#ifndef NO_DSA + install_int_const( d, "DSA_CIPHER", DSA_CIPHER ); +#endif +#ifndef NO_DH + install_int_const( d, "DH_CIPHER", DH_CIPHER ); +#endif + + // symmetric ciphers +#ifndef NO_DES + install_int_const( d, "DES_ECB", DES_ECB ); + install_int_const( d, "DES_EDE", DES_EDE ); + install_int_const( d, "DES_EDE3", DES_EDE3 ); + install_int_const( d, "DES_CFB", DES_CFB ); + install_int_const( d, "DES_EDE_CFB", DES_EDE_CFB ); + install_int_const( d, "DES_EDE3_CFB", DES_EDE3_CFB ); + install_int_const( d, "DES_OFB", DES_OFB ); + install_int_const( d, "DES_EDE_OFB", DES_EDE_OFB ); + install_int_const( d, "DES_EDE3_OFB", DES_EDE3_OFB ); + install_int_const( d, "DES_CBC", DES_CBC ); + install_int_const( d, "DES_EDE_CBC", DES_EDE_CBC ); + install_int_const( d, "DES_EDE3_CBC", DES_EDE3_CBC ); + install_int_const( d, "DESX_CBC", DESX_CBC ); +#endif +#ifndef NO_RC4 + install_int_const( d, "RC4", RC4 ); + install_int_const( d, "RC4_40", RC4_40 ); +#endif +#ifndef NO_IDEA + install_int_const( d, "IDEA_ECB", IDEA_ECB ); + install_int_const( d, "IDEA_CFB", IDEA_CFB ); + install_int_const( d, "IDEA_OFB", IDEA_OFB ); + install_int_const( d, "IDEA_CBC", IDEA_CBC ); +#endif +#ifndef NO_RC2 + install_int_const( d, "RC2_ECB", RC2_ECB ); + install_int_const( d, "RC2_CBC", RC2_CBC ); + install_int_const( d, "RC2_40_CBC", RC2_40_CBC ); + install_int_const( d, "RC2_CFB", RC2_CFB ); + install_int_const( d, "RC2_OFB", RC2_OFB ); +#endif +#ifndef NO_BF + install_int_const( d, "BF_ECB", BF_ECB ); + install_int_const( d, "BF_CBC", BF_CBC ); + install_int_const( d, "BF_CFB", BF_CFB ); + install_int_const( d, "BF_OFB", BF_OFB ); +#endif + install_int_const( d, "CAST5_ECB", CAST5_ECB ); + install_int_const( d, "CAST5_CBC", CAST5_CBC ); + install_int_const( d, "CAST5_CFB", CAST5_CFB ); + install_int_const( d, "CAST5_OFB", CAST5_OFB ); +#ifndef NO_RC5_32_12_16 + install_int_const( d, "RC5_32_12_16_CBC", RC5_32_12_16_CBC ); + install_int_const( d, "RC5_32_12_16_CFB", RC5_32_12_16_CFB ); + install_int_const( d, "RC5_32_12_16_ECB", RC5_32_12_16_ECB ); + install_int_const( d, "RC5_32_12_16_OFB", RC5_32_12_16_OFB ); +#endif + + // message digests + install_int_const( d, "MD2_DIGEST", MD2_DIGEST ); + install_int_const( d, "MD5_DIGEST", MD5_DIGEST ); + install_int_const( d, "SHA_DIGEST", SHA_DIGEST ); + install_int_const( d, "SHA1_DIGEST", SHA1_DIGEST ); + install_int_const( d, "RIPEMD160_DIGEST", RIPEMD160_DIGEST ); + + // general name + install_int_const( d, "GEN_OTHERNAME", GEN_OTHERNAME ); + install_int_const( d, "GEN_EMAIL", GEN_EMAIL ); + install_int_const( d, "GEN_DNS", GEN_DNS ); + install_int_const( d, "GEN_X400", GEN_X400 ); + install_int_const( d, "GEN_DIRNAME", GEN_DIRNAME ); + install_int_const( d, "GEN_EDIPARTY", GEN_EDIPARTY ); + install_int_const( d, "GEN_URI", GEN_URI ); + install_int_const( d, "GEN_IPADD", GEN_IPADD ); + install_int_const( d, "GEN_RID", GEN_RID ); + + // initialise library + SSL_library_init(); + OpenSSL_add_all_algorithms(); + OpenSSL_add_all_ciphers(); + OpenSSL_add_all_digests(); + + // load error strings + SSL_load_error_strings(); + + if (PyErr_Occurred()) + Py_FatalError("can't initialize module pow"); +} +/*==========================================================================*/ |