Initial import to Tizen
[profile/ivi/python-pyOpenSSL.git] / OpenSSL / crypto / revoked.c
1 #include <Python.h>
2 #define crypto_MODULE
3 #include "crypto.h"
4
5 #ifdef _WIN32
6 #define strcasecmp(string1, string2) _stricmp(string1, string2)
7 #endif
8
9 /* 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.  */
12 static 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
26 static char crypto_Revoked_all_reasons_doc[] = "\n\
27 Return a list of all the supported reason strings.\n\
28 \n\
29 @return: A list of reason strings.\n\
30 ";
31 static PyObject *
32 crypto_Revoked_all_reasons(crypto_RevokedObj *self, PyObject *args) {
33     PyObject *list, *str;
34     int j;
35
36     list = PyList_New(0);
37     for (j = 0; j < NUM_REASONS; j++) {
38         if(crl_reasons[j]) {
39             str = PyBytes_FromString(crl_reasons[j]);
40             PyList_Append(list, str);
41             Py_DECREF(str);
42         }
43     }
44     return list;
45 }
46
47 static PyObject *
48 X509_EXTENSION_value_to_PyString(X509_EXTENSION *ex) {
49     BIO *bio = NULL;
50     PyObject *str = NULL;
51     int str_len;
52     char *tmp_str;
53
54     /* Create a openssl BIO buffer */
55     bio = BIO_new(BIO_s_mem());
56     if (bio == NULL) {
57         goto err;
58     }
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     }
66
67     /* Convert to a Python string. */
68     str_len = BIO_get_mem_data(bio, &tmp_str);
69     str = PyBytes_FromStringAndSize(tmp_str, str_len);
70
71     /* Cleanup */
72     BIO_free(bio);
73     return str;
74
75  err:
76     if (bio) {
77         BIO_free(bio);
78     }
79     if (str) {
80         Py_DECREF(str);
81     }
82     return NULL;
83 }
84
85 static void
86 delete_reason(STACK_OF(X509_EXTENSION) *sk) {
87     X509_EXTENSION * ext;
88     int j;
89
90     for (j = 0; j < sk_X509_EXTENSION_num(sk); j++) {
91          ext = sk_X509_EXTENSION_value(sk, j);
92          if (OBJ_obj2nid(ext->object) == NID_crl_reason) {
93              X509_EXTENSION_free(ext);
94              (void) sk_X509_EXTENSION_delete(sk, j);
95              break;
96          }
97     }
98 }
99
100 static int
101 reason_str_to_code(const char * reason_str) {
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     }
110
111     while ((sp = strchr(spaceless_reason, ' '))) {
112        memmove(sp, sp+1, strlen(sp));
113     }
114
115     for (j = 0; j < NUM_REASONS; j++) {
116         if(crl_reasons[j] && !strcasecmp(spaceless_reason, crl_reasons[j])) {
117             reason_code = j;
118             break;
119         }
120     }
121     free(spaceless_reason);
122     return reason_code;
123 }
124
125
126 static char crypto_Revoked_set_reason_doc[] = "\n\
127 Set 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 ";
133 static PyObject *
134 crypto_Revoked_set_reason(crypto_RevokedObj *self, PyObject *args, PyObject *keywds) {
135     static char *kwlist[] = {"reason", NULL};
136     const char *reason_str = NULL;
137     int reason_code;
138     ASN1_ENUMERATED *rtmp = NULL;
139
140     if (!PyArg_ParseTupleAndKeywords(
141             args, keywds, "O&:set_reason", kwlist,
142             crypto_byte_converter, &reason_str)) {
143         return NULL;
144     }
145
146     if(reason_str == NULL) {
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         PyErr_SetString(PyExc_ValueError, "bad reason string");
154         return NULL;
155     }
156
157     rtmp = ASN1_ENUMERATED_new();
158     if (!rtmp || !ASN1_ENUMERATED_set(rtmp, reason_code)) {
159         goto err;
160     }
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
166  done:
167     Py_INCREF(Py_None);
168     return Py_None;
169
170  err:
171     exception_from_error_queue(crypto_Error);
172     return NULL;
173 }
174
175
176 static char crypto_Revoked_get_reason_doc[] = "\n\
177 Return the reason of a Revoked object.\n\
178 \n\
179 @return: The reason as a string\n\
180 ";
181 static PyObject *
182 crypto_Revoked_get_reason(crypto_RevokedObj *self, PyObject *args) {
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
191     sk = self->revoked->extensions;
192     for (j = 0; j < sk_X509_EXTENSION_num(sk); j++) {
193          ext = sk_X509_EXTENSION_value(sk, j);
194          if (OBJ_obj2nid(ext->object) == NID_crl_reason) {
195              return X509_EXTENSION_value_to_PyString(ext);
196          }
197     }
198
199     Py_INCREF(Py_None);
200     return Py_None;
201 }
202
203
204 static char crypto_Revoked_get_rev_date_doc[] = "\n\
205 Retrieve the revocation date\n\
206 \n\
207 @return: A string giving the timestamp, in the format:\n\
208 \n\
209                  YYYYMMDDhhmmssZ\n\
210                  YYYYMMDDhhmmss+hhmm\n\
211                  YYYYMMDDhhmmss-hhmm\n\
212 ";
213
214 static PyObject*
215 crypto_Revoked_get_rev_date(crypto_RevokedObj *self, PyObject *args) {
216     /* returns a borrowed reference.  */
217     return _get_asn1_time(
218         ":get_rev_date", self->revoked->revocationDate, args);
219 }
220
221 static char crypto_Revoked_set_rev_date_doc[] = "\n\
222 Set 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
233 static PyObject*
234 crypto_Revoked_set_rev_date(crypto_RevokedObj *self, PyObject *args) {
235     return _set_asn1_time(
236         BYTESTRING_FMT ":set_rev_date", self->revoked->revocationDate, args);
237 }
238
239 /* The integer is converted to an upper-case hex string
240  * without a '0x' prefix. */
241 static PyObject *
242 ASN1_INTEGER_to_PyString(ASN1_INTEGER *asn1_int) {
243     BIO *bio = NULL;
244     PyObject *str = NULL;
245     int str_len;
246     char *tmp_str;
247
248     /* Create a openssl BIO buffer */
249     bio = BIO_new(BIO_s_mem());
250     if (bio == NULL) {
251         goto err;
252     }
253
254     /* Write the integer to the BIO as a hex string. */
255     if (i2a_ASN1_INTEGER(bio, asn1_int) < 0) {
256         goto err;
257     }
258
259     /* Convert to a Python string. */
260     str_len = BIO_get_mem_data(bio, &tmp_str);
261     str = PyBytes_FromStringAndSize(tmp_str, str_len);
262
263     /* Cleanup */
264     BIO_free(bio);
265     return str;
266
267  err:
268     if (bio) {
269         BIO_free(bio);
270     }
271     if (str) {
272         Py_DECREF(str);
273     }
274     return NULL;
275 }
276
277
278 static char crypto_Revoked_get_serial_doc[] = "\n\
279 Return the serial number of a Revoked structure\n\
280 \n\
281 @return: The serial number as a string\n\
282 ";
283 static PyObject *
284 crypto_Revoked_get_serial(crypto_RevokedObj *self, PyObject *args) {
285     if (!PyArg_ParseTuple(args, ":get_serial")) {
286         return NULL;
287     }
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
298 static char crypto_Revoked_set_serial_doc[] = "\n\
299 Set 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 ";
305 static PyObject *
306 crypto_Revoked_set_serial(crypto_RevokedObj *self, PyObject *args, PyObject *keywds) {
307     static char *kwlist[] = {"hex_str", NULL};
308     const char *hex_str = NULL;
309     BIGNUM *serial = NULL;
310     ASN1_INTEGER *tmpser = NULL;
311
312     if (!PyArg_ParseTupleAndKeywords(args, keywds, BYTESTRING_FMT ":set_serial",
313                                      kwlist, &hex_str)) {
314         return NULL;
315     }
316
317     if (!BN_hex2bn(&serial, hex_str) ) {
318         PyErr_SetString(PyExc_ValueError, "bad hex string");
319         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
333 crypto_RevokedObj *
334 crypto_Revoked_New(X509_REVOKED *revoked) {
335     crypto_RevokedObj *self;
336
337     self = PyObject_New(crypto_RevokedObj, &crypto_Revoked_Type);
338     if (self == NULL) {
339         return NULL;
340     }
341     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 }
354 static PyMethodDef crypto_Revoked_methods[] = {
355     ADD_METHOD(all_reasons),
356     ADD_METHOD(get_reason),
357     ADD_KW_METHOD(set_reason),
358     ADD_METHOD(get_rev_date),
359     ADD_METHOD(set_rev_date),
360     ADD_METHOD(get_serial),
361     ADD_KW_METHOD(set_serial),
362     { NULL, NULL }
363 };
364 #undef ADD_METHOD
365
366
367 static void
368 crypto_Revoked_dealloc(crypto_RevokedObj *self) {
369     X509_REVOKED_free(self->revoked);
370     self->revoked = NULL;
371
372     PyObject_Del(self);
373 }
374
375 static char crypto_Revoked_doc[] = "\n\
376 Revoked() -> Revoked instance\n\
377 \n\
378 Create a new empty Revoked object.\n\
379 \n\
380 @returns: The Revoked object\n\
381 ";
382
383 static PyObject* crypto_Revoked_new(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) {
384     if (!PyArg_ParseTuple(args, ":Revoked")) {
385         return NULL;
386     }
387
388     return (PyObject *)crypto_Revoked_New(X509_REVOKED_new());
389 }
390
391 PyTypeObject crypto_Revoked_Type = {
392     PyOpenSSL_HEAD_INIT(&PyType_Type, 0)
393     "Revoked",
394     sizeof(crypto_RevokedObj),
395     0,
396     (destructor)crypto_Revoked_dealloc,
397     NULL, /* print */
398     NULL, /* getattr */
399     NULL, /* setattr */
400     NULL, /* compare */
401     NULL, /* repr */
402     NULL, /* as_number */
403     NULL, /* as_sequence */
404     NULL, /* as_mapping */
405     NULL, /* hash */
406     NULL, /* call */
407     NULL, /* str */
408     NULL, /* getattro */
409     NULL, /* setattro */
410     NULL, /* as_buffer */
411     Py_TPFLAGS_DEFAULT,
412     crypto_Revoked_doc, /* doc */
413     NULL, /* traverse */
414     NULL, /* clear */
415     NULL, /* tp_richcompare */
416     0, /* tp_weaklistoffset */
417     NULL, /* tp_iter */
418     NULL, /* tp_iternext */
419     crypto_Revoked_methods, /* tp_methods */
420     NULL, /* tp_members */
421     NULL, /* tp_getset */
422     NULL, /* tp_base */
423     NULL, /* tp_dict */
424     NULL, /* tp_descr_get */
425     NULL, /* tp_descr_set */
426     0, /* tp_dictoffset */
427     NULL, /* tp_init */
428     NULL, /* tp_alloc */
429     crypto_Revoked_new, /* tp_new */
430 };
431
432 int init_crypto_revoked(PyObject *module) {
433     if(PyType_Ready(&crypto_Revoked_Type) < 0) {
434         return 0;
435     }
436
437     if (PyModule_AddObject(module, "Revoked", (PyObject *)&crypto_Revoked_Type) != 0) {
438         return 0;
439     }
440     return 1;
441 }