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