blob: 08c1542524c4f267a0ca9790cc100a1ff3c3a14b [file] [log] [blame]
#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 = PyBytes_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 = PyBytes_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 = PyBytes_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 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 = {
PyOpenSSL_HEAD_INIT(&PyType_Type, 0)
"Revoked",
sizeof(crypto_RevokedObj),
0,
(destructor)crypto_Revoked_dealloc,
NULL, /* print */
NULL, /* 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;
}