blob: a81847d1a84306a03fbe39690b8f3762ff52864e [file] [log] [blame]
Rick Dean536ba022009-07-24 23:57:27 -05001#include <Python.h>
2#define crypto_MODULE
3#include "crypto.h"
4
Jean-Paul Calderone83461592010-01-30 14:19:01 -05005#ifdef _WIN32
6#define strcasecmp(string1, string2) _stricmp(string1, string2)
7#endif
Rick Dean536ba022009-07-24 23:57:27 -05008
Rick Dean6385faf2009-07-26 00:07:47 -05009/* http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_ */
10/* which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches */
11/* OCSP_crl_reason_str. We use the latter, just like the command line program. */
12static const char *crl_reasons[] = {
13 "unspecified",
14 "keyCompromise",
15 "CACompromise",
16 "affiliationChanged",
17 "superseded",
18 "cessationOfOperation",
19 "certificateHold",
20 NULL,
21 "removeFromCRL",
22};
23
24#define NUM_REASONS (sizeof(crl_reasons) / sizeof(char *))
25
26static char crypto_Revoked_all_reasons_doc[] = "\n\
27Return a list of all the supported reason strings.\n\
28\n\
29@return: A list of reason strings.\n\
30";
31static PyObject *
32crypto_Revoked_all_reasons(crypto_RevokedObj *self, PyObject *args)
33{
34 PyObject *list, *str;
35 int j;
36
37 list = PyList_New(0);
38 for (j = 0; j < NUM_REASONS; j++)
39 {
40 if( crl_reasons[j] )
41 {
42 str = PyString_FromString(crl_reasons[j]);
43 PyList_Append(list, str);
44 Py_DECREF(str);
45 }
46 }
47 return list;
48}
49
50static PyObject *
51X509_EXTENSION_value_to_PyString(X509_EXTENSION *ex)
52{
53 BIO *bio = NULL;
54 PyObject *str = NULL;
55 int str_len;
56 char *tmp_str;
57
58 /* Create a openssl BIO buffer */
59 bio = BIO_new(BIO_s_mem());
60 if (bio == NULL)
61 goto err;
62
63 /* These are not the droids you are looking for. */
64 if(!X509V3_EXT_print(bio, ex, 0, 0))
65 if(M_ASN1_OCTET_STRING_print(bio, ex->value) == 0)
66 goto err;
67
68 /* Convert to a Python string. */
69 str_len = BIO_get_mem_data(bio, &tmp_str);
70 str = PyString_FromStringAndSize(tmp_str, str_len);
71
72 /* Cleanup */
73 BIO_free(bio);
74 return str;
75
76 err:
77 if(bio) {
78 BIO_free(bio);
79 }
80 if(str) {
81 Py_DECREF(str);
82 }
83 return NULL;
84}
85
86static void
87delete_reason(STACK_OF(X509_EXTENSION) *sk)
88{
89 X509_EXTENSION * ext;
90 int j;
91
92 for(j = 0; j < sk_X509_EXTENSION_num(sk); j++) {
93 ext = sk_X509_EXTENSION_value(sk, j);
94 if ( OBJ_obj2nid(ext->object) == NID_crl_reason) {
95 X509_EXTENSION_free(ext);
96 (void) sk_X509_EXTENSION_delete(sk, j);
97 break;
98 }
99 }
100}
101
102static int
103reason_str_to_code(const char * reason_str)
104{
105 int reason_code = -1, j;
106 char *spaceless_reason, * sp;
107
108 /* Remove spaces so that the responses of
109 * get_reason() work in set_reason() */
110 if((spaceless_reason = strdup(reason_str)) == NULL)
111 return -1;
112 while((sp = strchr(spaceless_reason, ' ') ))
113 {
114 memmove(sp, sp+1, strlen(sp));
115 }
116
117 for (j = 0; j < NUM_REASONS; j++)
118 {
119 if(crl_reasons[j] && !strcasecmp(spaceless_reason, crl_reasons[j]))
120 {
121 reason_code = j;
122 break;
123 }
124 }
125 free(spaceless_reason);
126 return reason_code;
127}
128
129static char crypto_Revoked_set_reason_doc[] = "\n\
130Set the reason of a Revoked object.\n\
131\n\
132@param reason: The reason string.\n\
133@type reason: L{str}\n\
134@return: None\n\
135";
136static PyObject *
137crypto_Revoked_set_reason(crypto_RevokedObj *self, PyObject *args, PyObject *keywds)
138{
139 static char *kwlist[] = {"reason", NULL};
140 const char *reason_str = NULL;
141 int reason_code;
142 ASN1_ENUMERATED *rtmp = NULL;
143
144 if (!PyArg_ParseTupleAndKeywords(args, keywds, "z:set_reason",
145 kwlist, &reason_str))
146 return NULL;
147
148 if(reason_str == NULL)
149 {
150 delete_reason(self->revoked->extensions);
151 goto done;
152 }
153
154 reason_code = reason_str_to_code(reason_str);
155 if(reason_code == -1)
156 {
157 PyErr_SetString(PyExc_ValueError, "bad reason string");
158 return NULL;
159 }
160
161 rtmp = ASN1_ENUMERATED_new();
162 if (!rtmp || !ASN1_ENUMERATED_set(rtmp, reason_code))
163 goto err;
164 delete_reason(self->revoked->extensions);
165 if (!X509_REVOKED_add1_ext_i2d(self->revoked, NID_crl_reason, rtmp, 0, 0))
166 goto err;
167
168 done:
169 Py_INCREF(Py_None);
170 return Py_None;
171
172 err:
173 exception_from_error_queue(crypto_Error);
174 return NULL;
175}
176
177
178static char crypto_Revoked_get_reason_doc[] = "\n\
179Return the reason of a Revoked object.\n\
180\n\
181@return: The reason as a string\n\
182";
183static PyObject *
184crypto_Revoked_get_reason(crypto_RevokedObj *self, PyObject *args)
185{
186 X509_EXTENSION * ext;
187 int j;
188 STACK_OF(X509_EXTENSION) *sk = NULL;
189
190 if (!PyArg_ParseTuple(args, ":get_reason"))
191 return NULL;
192
193 sk = self->revoked->extensions;
194 for(j = 0; j < sk_X509_EXTENSION_num(sk); j++) {
195 ext = sk_X509_EXTENSION_value(sk, j);
196 if ( OBJ_obj2nid(ext->object) == NID_crl_reason) {
197 return X509_EXTENSION_value_to_PyString(ext);
198 }
199 }
200
201 Py_INCREF(Py_None);
202 return Py_None;
203}
204
205
Rick Dean536ba022009-07-24 23:57:27 -0500206static char crypto_Revoked_get_rev_date_doc[] = "\n\
207Retrieve the revocation date\n\
208\n\
209@return: A string giving the timestamp, in the format:\n\
210\n\
211 YYYYMMDDhhmmssZ\n\
212 YYYYMMDDhhmmss+hhmm\n\
213 YYYYMMDDhhmmss-hhmm\n\
214";
215
216static PyObject*
217crypto_Revoked_get_rev_date(crypto_RevokedObj *self, PyObject *args)
218{
Rick Dean6385faf2009-07-26 00:07:47 -0500219 /* returns a borrowed reference. */
220 return _get_asn1_time(
221 ":get_rev_date", self->revoked->revocationDate, args);
Rick Dean536ba022009-07-24 23:57:27 -0500222}
223
224static char crypto_Revoked_set_rev_date_doc[] = "\n\
225Set the revocation timestamp\n\
226\n\
227@param when: A string giving the timestamp, in the format:\n\
228\n\
229 YYYYMMDDhhmmssZ\n\
230 YYYYMMDDhhmmss+hhmm\n\
231 YYYYMMDDhhmmss-hhmm\n\
232\n\
233@return: None\n\
234";
235
236static PyObject*
237crypto_Revoked_set_rev_date(crypto_RevokedObj *self, PyObject *args)
238{
Rick Dean6385faf2009-07-26 00:07:47 -0500239 return _set_asn1_time(
240 "s:set_rev_date", self->revoked->revocationDate, args);
Rick Dean536ba022009-07-24 23:57:27 -0500241}
242
Rick Dean6385faf2009-07-26 00:07:47 -0500243/* The integer is converted to an upper-case hex string
244 * without a '0x' prefix. */
Rick Dean536ba022009-07-24 23:57:27 -0500245static PyObject *
246ASN1_INTEGER_to_PyString(ASN1_INTEGER *asn1_int)
247{
248 BIO *bio = NULL;
Rick Dean6385faf2009-07-26 00:07:47 -0500249 PyObject *str = NULL;
250 int str_len;
251 char *tmp_str;
Rick Dean536ba022009-07-24 23:57:27 -0500252
253 /* Create a openssl BIO buffer */
254 bio = BIO_new(BIO_s_mem());
255 if (bio == NULL)
256 goto err;
257
258 /* Write the integer to the BIO as a hex string. */
Rick Dean6385faf2009-07-26 00:07:47 -0500259 if(i2a_ASN1_INTEGER(bio, asn1_int) < 0)
Rick Dean536ba022009-07-24 23:57:27 -0500260 goto err;
Rick Dean536ba022009-07-24 23:57:27 -0500261
Rick Dean6385faf2009-07-26 00:07:47 -0500262 /* Convert to a Python string. */
263 str_len = BIO_get_mem_data(bio, &tmp_str);
264 str = PyString_FromStringAndSize(tmp_str, str_len);
Rick Dean536ba022009-07-24 23:57:27 -0500265
266 /* Cleanup */
267 BIO_free(bio);
Rick Dean6385faf2009-07-26 00:07:47 -0500268 return str;
Rick Dean536ba022009-07-24 23:57:27 -0500269
270 err:
271 if(bio) {
272 BIO_free(bio);
273 }
Rick Dean6385faf2009-07-26 00:07:47 -0500274 if(str) {
275 Py_DECREF(str);
Rick Dean536ba022009-07-24 23:57:27 -0500276 }
277 return NULL;
278}
279
280
281static char crypto_Revoked_get_serial_doc[] = "\n\
282Return the serial number of a Revoked structure\n\
283\n\
284@return: The serial number as a string\n\
285";
286static PyObject *
287crypto_Revoked_get_serial(crypto_RevokedObj *self, PyObject *args)
288{
289 if (!PyArg_ParseTuple(args, ":get_serial"))
290 return NULL;
291
292 if(self->revoked->serialNumber == NULL) {
293 /* never happens */
294 Py_INCREF(Py_None);
295 return Py_None;
296 } else {
297 return ASN1_INTEGER_to_PyString(self->revoked->serialNumber);
298 }
299}
300
301static char crypto_Revoked_set_serial_doc[] = "\n\
302Set the serial number of a revoked Revoked structure\n\
303\n\
304@param hex_str: The new serial number.\n\
305@type hex_str: L{str}\n\
306@return: None\n\
307";
308static PyObject *
309crypto_Revoked_set_serial(crypto_RevokedObj *self, PyObject *args, PyObject *keywds)
310{
311 static char *kwlist[] = {"hex_str", NULL};
312 const char *hex_str = NULL;
313 BIGNUM *serial = NULL;
314 ASN1_INTEGER *tmpser = NULL;
315
316 if (!PyArg_ParseTupleAndKeywords(args, keywds, "s:set_serial",
317 kwlist, &hex_str))
318 return NULL;
319
320 if( ! BN_hex2bn(&serial, hex_str) ) {
Rick Dean6385faf2009-07-26 00:07:47 -0500321 PyErr_SetString(PyExc_ValueError, "bad hex string");
Rick Dean536ba022009-07-24 23:57:27 -0500322 return NULL;
323 }
324
325 tmpser = BN_to_ASN1_INTEGER(serial, NULL);
326 BN_free(serial);
327 serial = NULL;
328 X509_REVOKED_set_serialNumber(self->revoked, tmpser);
329 ASN1_INTEGER_free(tmpser);
330
331 Py_INCREF(Py_None);
332 return Py_None;
333}
334
335
336crypto_RevokedObj *
337crypto_Revoked_New(X509_REVOKED *revoked)
338{
339 crypto_RevokedObj *self;
340
341 self = PyObject_New(crypto_RevokedObj, &crypto_Revoked_Type);
342 if (self==NULL)
Rick Dean6385faf2009-07-26 00:07:47 -0500343 return NULL;
Rick Dean536ba022009-07-24 23:57:27 -0500344 self->revoked = revoked;
345 return self;
346}
347
348/*
349 * ADD_METHOD(name) expands to a correct PyMethodDef declaration
350 * { 'name', (PyCFunction)crypto_Revoked_name, METH_VARARGS, crypto_Revoked_name_doc }
351 * for convenience
352 */
353#define ADD_METHOD(name) \
354 { #name, (PyCFunction)crypto_Revoked_##name, METH_VARARGS, crypto_Revoked_##name##_doc }
355#define ADD_KW_METHOD(name) \
356 { #name, (PyCFunction)crypto_Revoked_##name, METH_VARARGS | METH_KEYWORDS, crypto_Revoked_##name##_doc }
357static PyMethodDef crypto_Revoked_methods[] =
358{
Rick Dean6385faf2009-07-26 00:07:47 -0500359 ADD_METHOD(all_reasons),
360 ADD_METHOD(get_reason),
361 ADD_KW_METHOD(set_reason),
Rick Dean536ba022009-07-24 23:57:27 -0500362 ADD_METHOD(get_rev_date),
363 ADD_METHOD(set_rev_date),
364 ADD_METHOD(get_serial),
365 ADD_KW_METHOD(set_serial),
366 { NULL, NULL }
367};
368#undef ADD_METHOD
369
370
371static PyObject *
372crypto_Revoked_getattr(crypto_RevokedObj *self, char *name)
373{
374 return Py_FindMethod(crypto_Revoked_methods, (PyObject *)self, name);
375}
376
377static void
378crypto_Revoked_dealloc(crypto_RevokedObj *self)
379{
380 X509_REVOKED_free(self->revoked);
381 self->revoked = NULL;
382
383 PyObject_Del(self);
384}
385
386static char crypto_Revoked_doc[] = "\n\
387Revoked() -> Revoked instance\n\
388\n\
389Create a new empty Revoked object.\n\
390\n\
391@returns: The Revoked object\n\
392";
393
394static PyObject* crypto_Revoked_new(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) {
395 if (!PyArg_ParseTuple(args, ":Revoked")) {
396 return NULL;
397 }
398
399 return (PyObject *)crypto_Revoked_New(X509_REVOKED_new());
400}
401
402PyTypeObject crypto_Revoked_Type = {
403 PyObject_HEAD_INIT(NULL)
404 0,
405 "Revoked",
406 sizeof(crypto_RevokedObj),
407 0,
408 (destructor)crypto_Revoked_dealloc,
409 NULL, /* print */
410 (getattrfunc)crypto_Revoked_getattr,
411 NULL, /* setattr */
412 NULL, /* compare */
413 NULL, /* repr */
414 NULL, /* as_number */
415 NULL, /* as_sequence */
416 NULL, /* as_mapping */
417 NULL, /* hash */
418 NULL, /* call */
419 NULL, /* str */
420 NULL, /* getattro */
421 NULL, /* setattro */
422 NULL, /* as_buffer */
423 Py_TPFLAGS_DEFAULT,
424 crypto_Revoked_doc, /* doc */
425 NULL, /* traverse */
426 NULL, /* clear */
427 NULL, /* tp_richcompare */
428 0, /* tp_weaklistoffset */
429 NULL, /* tp_iter */
430 NULL, /* tp_iternext */
431 crypto_Revoked_methods, /* tp_methods */
432 NULL, /* tp_members */
433 NULL, /* tp_getset */
434 NULL, /* tp_base */
435 NULL, /* tp_dict */
436 NULL, /* tp_descr_get */
437 NULL, /* tp_descr_set */
438 0, /* tp_dictoffset */
439 NULL, /* tp_init */
440 NULL, /* tp_alloc */
441 crypto_Revoked_new, /* tp_new */
442};
443
444int init_crypto_revoked(PyObject *module) {
445 if(PyType_Ready(&crypto_Revoked_Type) < 0) {
446 return 0;
447 }
448
449 if (PyModule_AddObject(module, "Revoked", (PyObject *)&crypto_Revoked_Type) != 0) {
450 return 0;
451 }
452 return 1;
453}
454