diff options
Diffstat (limited to 'OpenSSL/crypto/revoked.c')
-rw-r--r-- | OpenSSL/crypto/revoked.c | 445 |
1 files changed, 445 insertions, 0 deletions
diff --git a/OpenSSL/crypto/revoked.c b/OpenSSL/crypto/revoked.c new file mode 100644 index 0000000..3042c4d --- /dev/null +++ b/OpenSSL/crypto/revoked.c @@ -0,0 +1,445 @@ +#include <Python.h> +#define crypto_MODULE +#include "crypto.h" + +#ifdef _WIN32 +#define strcasecmp(string1, string2) _stricmp(string1, string2) +#endif + +/* http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_ */ +/* which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches */ +/* OCSP_crl_reason_str. We use the latter, just like the command line program. */ +static const char *crl_reasons[] = { + "unspecified", + "keyCompromise", + "CACompromise", + "affiliationChanged", + "superseded", + "cessationOfOperation", + "certificateHold", + NULL, + "removeFromCRL", +}; + +#define NUM_REASONS (sizeof(crl_reasons) / sizeof(char *)) + +static char crypto_Revoked_all_reasons_doc[] = "\n\ +Return a list of all the supported reason strings.\n\ +\n\ +@return: A list of reason strings.\n\ +"; +static PyObject * +crypto_Revoked_all_reasons(crypto_RevokedObj *self, PyObject *args) { + PyObject *list, *str; + int j; + + list = PyList_New(0); + for (j = 0; j < NUM_REASONS; j++) { + if(crl_reasons[j]) { + str = PyString_FromString(crl_reasons[j]); + PyList_Append(list, str); + Py_DECREF(str); + } + } + return list; +} + +static PyObject * +X509_EXTENSION_value_to_PyString(X509_EXTENSION *ex) { + BIO *bio = NULL; + PyObject *str = NULL; + int str_len; + char *tmp_str; + + /* Create a openssl BIO buffer */ + bio = BIO_new(BIO_s_mem()); + if (bio == NULL) { + goto err; + } + + /* These are not the droids you are looking for. */ + if (!X509V3_EXT_print(bio, ex, 0, 0)) { + if (M_ASN1_OCTET_STRING_print(bio, ex->value) == 0) { + goto err; + } + } + + /* Convert to a Python string. */ + str_len = BIO_get_mem_data(bio, &tmp_str); + str = PyString_FromStringAndSize(tmp_str, str_len); + + /* Cleanup */ + BIO_free(bio); + return str; + + err: + if (bio) { + BIO_free(bio); + } + if (str) { + Py_DECREF(str); + } + return NULL; +} + +static void +delete_reason(STACK_OF(X509_EXTENSION) *sk) { + X509_EXTENSION * ext; + int j; + + for (j = 0; j < sk_X509_EXTENSION_num(sk); j++) { + ext = sk_X509_EXTENSION_value(sk, j); + if (OBJ_obj2nid(ext->object) == NID_crl_reason) { + X509_EXTENSION_free(ext); + (void) sk_X509_EXTENSION_delete(sk, j); + break; + } + } +} + +static int +reason_str_to_code(const char * reason_str) { + int reason_code = -1, j; + char *spaceless_reason, * sp; + + /* Remove spaces so that the responses of + * get_reason() work in set_reason() */ + if ((spaceless_reason = strdup(reason_str)) == NULL) { + return -1; + } + + while ((sp = strchr(spaceless_reason, ' '))) { + memmove(sp, sp+1, strlen(sp)); + } + + for (j = 0; j < NUM_REASONS; j++) { + if(crl_reasons[j] && !strcasecmp(spaceless_reason, crl_reasons[j])) { + reason_code = j; + break; + } + } + free(spaceless_reason); + return reason_code; +} + +static char crypto_Revoked_set_reason_doc[] = "\n\ +Set the reason of a Revoked object.\n\ +\n\ +@param reason: The reason string.\n\ +@type reason: L{str}\n\ +@return: None\n\ +"; +static PyObject * +crypto_Revoked_set_reason(crypto_RevokedObj *self, PyObject *args, PyObject *keywds) { + static char *kwlist[] = {"reason", NULL}; + const char *reason_str = NULL; + int reason_code; + ASN1_ENUMERATED *rtmp = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, keywds, "z:set_reason", + kwlist, &reason_str)) { + return NULL; + } + + if(reason_str == NULL) { + delete_reason(self->revoked->extensions); + goto done; + } + + reason_code = reason_str_to_code(reason_str); + if (reason_code == -1) { + PyErr_SetString(PyExc_ValueError, "bad reason string"); + return NULL; + } + + rtmp = ASN1_ENUMERATED_new(); + if (!rtmp || !ASN1_ENUMERATED_set(rtmp, reason_code)) { + goto err; + } + delete_reason(self->revoked->extensions); + if (!X509_REVOKED_add1_ext_i2d(self->revoked, NID_crl_reason, rtmp, 0, 0)) { + goto err; + } + + done: + Py_INCREF(Py_None); + return Py_None; + + err: + exception_from_error_queue(crypto_Error); + return NULL; +} + + +static char crypto_Revoked_get_reason_doc[] = "\n\ +Return the reason of a Revoked object.\n\ +\n\ +@return: The reason as a string\n\ +"; +static PyObject * +crypto_Revoked_get_reason(crypto_RevokedObj *self, PyObject *args) { + X509_EXTENSION * ext; + int j; + STACK_OF(X509_EXTENSION) *sk = NULL; + + if (!PyArg_ParseTuple(args, ":get_reason")) { + return NULL; + } + + sk = self->revoked->extensions; + for (j = 0; j < sk_X509_EXTENSION_num(sk); j++) { + ext = sk_X509_EXTENSION_value(sk, j); + if (OBJ_obj2nid(ext->object) == NID_crl_reason) { + return X509_EXTENSION_value_to_PyString(ext); + } + } + + Py_INCREF(Py_None); + return Py_None; +} + + +static char crypto_Revoked_get_rev_date_doc[] = "\n\ +Retrieve the revocation date\n\ +\n\ +@return: A string giving the timestamp, in the format:\n\ +\n\ + YYYYMMDDhhmmssZ\n\ + YYYYMMDDhhmmss+hhmm\n\ + YYYYMMDDhhmmss-hhmm\n\ +"; + +static PyObject* +crypto_Revoked_get_rev_date(crypto_RevokedObj *self, PyObject *args) { + /* returns a borrowed reference. */ + return _get_asn1_time( + ":get_rev_date", self->revoked->revocationDate, args); +} + +static char crypto_Revoked_set_rev_date_doc[] = "\n\ +Set the revocation timestamp\n\ +\n\ +@param when: A string giving the timestamp, in the format:\n\ +\n\ + YYYYMMDDhhmmssZ\n\ + YYYYMMDDhhmmss+hhmm\n\ + YYYYMMDDhhmmss-hhmm\n\ +\n\ +@return: None\n\ +"; + +static PyObject* +crypto_Revoked_set_rev_date(crypto_RevokedObj *self, PyObject *args) { + return _set_asn1_time( + "s:set_rev_date", self->revoked->revocationDate, args); +} + +/* The integer is converted to an upper-case hex string + * without a '0x' prefix. */ +static PyObject * +ASN1_INTEGER_to_PyString(ASN1_INTEGER *asn1_int) { + BIO *bio = NULL; + PyObject *str = NULL; + int str_len; + char *tmp_str; + + /* Create a openssl BIO buffer */ + bio = BIO_new(BIO_s_mem()); + if (bio == NULL) { + goto err; + } + + /* Write the integer to the BIO as a hex string. */ + if (i2a_ASN1_INTEGER(bio, asn1_int) < 0) { + goto err; + } + + /* Convert to a Python string. */ + str_len = BIO_get_mem_data(bio, &tmp_str); + str = PyString_FromStringAndSize(tmp_str, str_len); + + /* Cleanup */ + BIO_free(bio); + return str; + + err: + if (bio) { + BIO_free(bio); + } + if (str) { + Py_DECREF(str); + } + return NULL; +} + + +static char crypto_Revoked_get_serial_doc[] = "\n\ +Return the serial number of a Revoked structure\n\ +\n\ +@return: The serial number as a string\n\ +"; +static PyObject * +crypto_Revoked_get_serial(crypto_RevokedObj *self, PyObject *args) { + if (!PyArg_ParseTuple(args, ":get_serial")) { + return NULL; + } + + if (self->revoked->serialNumber == NULL) { + /* never happens */ + Py_INCREF(Py_None); + return Py_None; + } else { + return ASN1_INTEGER_to_PyString(self->revoked->serialNumber); + } +} + +static char crypto_Revoked_set_serial_doc[] = "\n\ +Set the serial number of a revoked Revoked structure\n\ +\n\ +@param hex_str: The new serial number.\n\ +@type hex_str: L{str}\n\ +@return: None\n\ +"; +static PyObject * +crypto_Revoked_set_serial(crypto_RevokedObj *self, PyObject *args, PyObject *keywds) { + static char *kwlist[] = {"hex_str", NULL}; + const char *hex_str = NULL; + BIGNUM *serial = NULL; + ASN1_INTEGER *tmpser = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, keywds, "s:set_serial", + kwlist, &hex_str)) { + return NULL; + } + + if (!BN_hex2bn(&serial, hex_str) ) { + PyErr_SetString(PyExc_ValueError, "bad hex string"); + return NULL; + } + + tmpser = BN_to_ASN1_INTEGER(serial, NULL); + BN_free(serial); + serial = NULL; + X509_REVOKED_set_serialNumber(self->revoked, tmpser); + ASN1_INTEGER_free(tmpser); + + Py_INCREF(Py_None); + return Py_None; +} + + +crypto_RevokedObj * +crypto_Revoked_New(X509_REVOKED *revoked) { + crypto_RevokedObj *self; + + self = PyObject_New(crypto_RevokedObj, &crypto_Revoked_Type); + if (self == NULL) { + return NULL; + } + self->revoked = revoked; + return self; +} + +/* + * ADD_METHOD(name) expands to a correct PyMethodDef declaration + * { 'name', (PyCFunction)crypto_Revoked_name, METH_VARARGS, crypto_Revoked_name_doc } + * for convenience + */ +#define ADD_METHOD(name) \ + { #name, (PyCFunction)crypto_Revoked_##name, METH_VARARGS, crypto_Revoked_##name##_doc } +#define ADD_KW_METHOD(name) \ + { #name, (PyCFunction)crypto_Revoked_##name, METH_VARARGS | METH_KEYWORDS, crypto_Revoked_##name##_doc } +static PyMethodDef crypto_Revoked_methods[] = { + ADD_METHOD(all_reasons), + ADD_METHOD(get_reason), + ADD_KW_METHOD(set_reason), + ADD_METHOD(get_rev_date), + ADD_METHOD(set_rev_date), + ADD_METHOD(get_serial), + ADD_KW_METHOD(set_serial), + { NULL, NULL } +}; +#undef ADD_METHOD + + +static PyObject * +crypto_Revoked_getattr(crypto_RevokedObj *self, char *name) { + return Py_FindMethod(crypto_Revoked_methods, (PyObject *)self, name); +} + +static void +crypto_Revoked_dealloc(crypto_RevokedObj *self) { + X509_REVOKED_free(self->revoked); + self->revoked = NULL; + + PyObject_Del(self); +} + +static char crypto_Revoked_doc[] = "\n\ +Revoked() -> Revoked instance\n\ +\n\ +Create a new empty Revoked object.\n\ +\n\ +@returns: The Revoked object\n\ +"; + +static PyObject* crypto_Revoked_new(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) { + if (!PyArg_ParseTuple(args, ":Revoked")) { + return NULL; + } + + return (PyObject *)crypto_Revoked_New(X509_REVOKED_new()); +} + +PyTypeObject crypto_Revoked_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "Revoked", + sizeof(crypto_RevokedObj), + 0, + (destructor)crypto_Revoked_dealloc, + NULL, /* print */ + (getattrfunc)crypto_Revoked_getattr, + NULL, /* setattr */ + NULL, /* compare */ + NULL, /* repr */ + NULL, /* as_number */ + NULL, /* as_sequence */ + NULL, /* as_mapping */ + NULL, /* hash */ + NULL, /* call */ + NULL, /* str */ + NULL, /* getattro */ + NULL, /* setattro */ + NULL, /* as_buffer */ + Py_TPFLAGS_DEFAULT, + crypto_Revoked_doc, /* doc */ + NULL, /* traverse */ + NULL, /* clear */ + NULL, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + NULL, /* tp_iter */ + NULL, /* tp_iternext */ + crypto_Revoked_methods, /* tp_methods */ + NULL, /* tp_members */ + NULL, /* tp_getset */ + NULL, /* tp_base */ + NULL, /* tp_dict */ + NULL, /* tp_descr_get */ + NULL, /* tp_descr_set */ + 0, /* tp_dictoffset */ + NULL, /* tp_init */ + NULL, /* tp_alloc */ + crypto_Revoked_new, /* tp_new */ +}; + +int init_crypto_revoked(PyObject *module) { + if(PyType_Ready(&crypto_Revoked_Type) < 0) { + return 0; + } + + if (PyModule_AddObject(module, "Revoked", (PyObject *)&crypto_Revoked_Type) != 0) { + return 0; + } + return 1; +} |