blob: d9ce52e848e9673170231ffc5059e8c02e745f5f [file] [log] [blame]
Jean-Paul Calderone897bc252008-02-18 20:50:23 -05001/*
2 * crypto.c
3 *
Jean-Paul Calderone8671c852011-03-02 19:26:20 -05004 * Copyright (C) AB Strakt
5 * Copyright (C) Keyphrene
6 * Copyright (C) Jean-Paul Calderone
7 * See LICENSE for details.
Jean-Paul Calderone897bc252008-02-18 20:50:23 -05008 *
9 * Main file of crypto sub module.
10 * See the file RATIONALE for a short explanation of why this module was written.
11 *
12 * Reviewed 2001-07-23
13 */
14#include <Python.h>
15#define crypto_MODULE
16#include "crypto.h"
Rick Dean623ee362009-07-17 12:22:16 -050017#include "pkcs12.h"
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050018
19static char crypto_doc[] = "\n\
20Main file of crypto sub module.\n\
21See the file RATIONALE for a short explanation of why this module was written.\n\
22";
23
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050024void **ssl_API;
25
26PyObject *crypto_Error;
27
Jean-Paul Calderone7b643a92010-08-28 14:40:58 -040028int crypto_byte_converter(PyObject *input, void* output) {
29 char **message = output;
30 if (input == Py_None) {
31 *message = NULL;
32 } else if (PyBytes_CheckExact(input)) {
33 *message = PyBytes_AsString(input);
34 } else {
35 return 0;
36 }
37 return 1;
38}
39
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050040static int
41global_passphrase_callback(char *buf, int len, int rwflag, void *cb_arg)
42{
43 PyObject *func, *argv, *ret;
44 int nchars;
45
46 func = (PyObject *)cb_arg;
47 argv = Py_BuildValue("(i)", rwflag);
48 ret = PyEval_CallObject(func, argv);
49 Py_DECREF(argv);
50 if (ret == NULL)
51 return 0;
Jean-Paul Calderoneef853eb2010-08-10 19:47:06 -040052 if (!PyBytes_Check(ret))
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050053 {
54 PyErr_SetString(PyExc_ValueError, "String expected");
55 return 0;
56 }
Jean-Paul Calderoneef853eb2010-08-10 19:47:06 -040057 nchars = PyBytes_Size(ret);
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050058 if (nchars > len)
59 nchars = len;
Jean-Paul Calderoneef853eb2010-08-10 19:47:06 -040060 strncpy(buf, PyBytes_AsString(ret), nchars);
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050061 return nchars;
62}
63
Ziga Seilnacht6b90a402009-12-22 14:33:47 +010064static PyObject *
65raise_current_error(void)
66{
67 if (PyErr_Occurred()) {
68 /*
69 * The python exception from callback is more informative than
70 * OpenSSL's error.
71 */
72 flush_error_queue();
73 return NULL;
74 }
75 exception_from_error_queue(crypto_Error);
76 return NULL;
77}
78
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050079static char crypto_load_privatekey_doc[] = "\n\
80Load a private key from a buffer\n\
81\n\
Jonathan Ballet78b92a22011-07-16 08:07:26 +090082:param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\
83:param buffer: The buffer the key is stored in\n\
84:param passphrase: (optional) if encrypted PEM format, this can be\n\
Jean-Paul Calderone54bcc832009-05-27 14:06:48 -040085 either the passphrase to use, or a callback for\n\
86 providing the passphrase.\n\
87\n\
Jonathan Ballet78b92a22011-07-16 08:07:26 +090088:return: The PKey object\n\
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050089";
90
91static PyObject *
92crypto_load_privatekey(PyObject *spam, PyObject *args)
93{
94 crypto_PKeyObj *crypto_PKey_New(EVP_PKEY *, int);
95 int type, len;
96 char *buffer;
97 PyObject *pw = NULL;
98 pem_password_cb *cb = NULL;
99 void *cb_arg = NULL;
100 BIO *bio;
101 EVP_PKEY *pkey;
102
103 if (!PyArg_ParseTuple(args, "is#|O:load_privatekey", &type, &buffer, &len, &pw))
104 return NULL;
105
106 if (pw != NULL)
107 {
Jean-Paul Calderoneef853eb2010-08-10 19:47:06 -0400108 if (PyBytes_Check(pw))
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500109 {
110 cb = NULL;
Jean-Paul Calderoneef853eb2010-08-10 19:47:06 -0400111 cb_arg = PyBytes_AsString(pw);
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500112 }
113 else if (PyCallable_Check(pw))
114 {
115 cb = global_passphrase_callback;
116 cb_arg = pw;
117 }
118 else
119 {
120 PyErr_SetString(PyExc_TypeError, "Last argument must be string or callable");
121 return NULL;
122 }
123 }
124
125 bio = BIO_new_mem_buf(buffer, len);
126 switch (type)
127 {
128 case X509_FILETYPE_PEM:
129 pkey = PEM_read_bio_PrivateKey(bio, NULL, cb, cb_arg);
130 break;
131
132 case X509_FILETYPE_ASN1:
133 pkey = d2i_PrivateKey_bio(bio, NULL);
134 break;
135
136 default:
137 PyErr_SetString(PyExc_ValueError, "type argument must be FILETYPE_PEM or FILETYPE_ASN1");
138 BIO_free(bio);
139 return NULL;
140 }
141 BIO_free(bio);
142
143 if (pkey == NULL)
144 {
Ziga Seilnacht6b90a402009-12-22 14:33:47 +0100145 return raise_current_error();
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500146 }
147
148 return (PyObject *)crypto_PKey_New(pkey, 1);
149}
150
151static char crypto_dump_privatekey_doc[] = "\n\
152Dump a private key to a buffer\n\
153\n\
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900154:param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\
155:param pkey: The PKey to dump\n\
156:param cipher: (optional) if encrypted PEM format, the cipher to\n\
Jean-Paul Calderone54bcc832009-05-27 14:06:48 -0400157 use\n\
Jonathan Ballet648875f2011-07-16 14:14:58 +0900158:param passphrase: (optional) if encrypted PEM format, this can be either\n\
159 the passphrase to use, or a callback for providing the\n\
160 passphrase.\n\
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900161:return: The buffer with the dumped key in\n\
Jonathan Ballet648875f2011-07-16 14:14:58 +0900162:rtype: :py:data:`str`\n\
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500163";
164
165static PyObject *
166crypto_dump_privatekey(PyObject *spam, PyObject *args)
167{
168 int type, ret, buf_len;
169 char *temp;
170 PyObject *buffer;
171 char *cipher_name = NULL;
172 const EVP_CIPHER *cipher = NULL;
173 PyObject *pw = NULL;
174 pem_password_cb *cb = NULL;
175 void *cb_arg = NULL;
176 BIO *bio;
Rick Dean5b7b6372009-04-01 11:34:06 -0500177 RSA *rsa;
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500178 crypto_PKeyObj *pkey;
179
180 if (!PyArg_ParseTuple(args, "iO!|sO:dump_privatekey", &type,
181 &crypto_PKey_Type, &pkey, &cipher_name, &pw))
182 return NULL;
183
184 if (cipher_name != NULL && pw == NULL)
185 {
186 PyErr_SetString(PyExc_ValueError, "Illegal number of arguments");
187 return NULL;
188 }
189 if (cipher_name != NULL)
190 {
191 cipher = EVP_get_cipherbyname(cipher_name);
192 if (cipher == NULL)
193 {
194 PyErr_SetString(PyExc_ValueError, "Invalid cipher name");
195 return NULL;
196 }
Jean-Paul Calderoneef853eb2010-08-10 19:47:06 -0400197 if (PyBytes_Check(pw))
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500198 {
199 cb = NULL;
Jean-Paul Calderoneef853eb2010-08-10 19:47:06 -0400200 cb_arg = PyBytes_AsString(pw);
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500201 }
202 else if (PyCallable_Check(pw))
203 {
204 cb = global_passphrase_callback;
205 cb_arg = pw;
206 }
207 else
208 {
209 PyErr_SetString(PyExc_TypeError, "Last argument must be string or callable");
210 return NULL;
211 }
212 }
213
214 bio = BIO_new(BIO_s_mem());
215 switch (type)
216 {
217 case X509_FILETYPE_PEM:
218 ret = PEM_write_bio_PrivateKey(bio, pkey->pkey, cipher, NULL, 0, cb, cb_arg);
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500219 break;
220
221 case X509_FILETYPE_ASN1:
222 ret = i2d_PrivateKey_bio(bio, pkey->pkey);
223 break;
224
Rick Dean5b7b6372009-04-01 11:34:06 -0500225 case X509_FILETYPE_TEXT:
226 rsa = EVP_PKEY_get1_RSA(pkey->pkey);
227 ret = RSA_print(bio, rsa, 0);
Ziga Seilnachtcccb6962009-12-22 14:06:31 +0100228 RSA_free(rsa);
Rick Dean5b7b6372009-04-01 11:34:06 -0500229 break;
230
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500231 default:
Rick Dean5b7b6372009-04-01 11:34:06 -0500232 PyErr_SetString(PyExc_ValueError, "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT");
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500233 BIO_free(bio);
234 return NULL;
235 }
236
237 if (ret == 0)
238 {
239 BIO_free(bio);
Ziga Seilnacht6b90a402009-12-22 14:33:47 +0100240 return raise_current_error();
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500241 }
242
243 buf_len = BIO_get_mem_data(bio, &temp);
Jean-Paul Calderoneef853eb2010-08-10 19:47:06 -0400244 buffer = PyBytes_FromStringAndSize(temp, buf_len);
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500245 BIO_free(bio);
246
247 return buffer;
248}
249
250static char crypto_load_certificate_doc[] = "\n\
251Load a certificate from a buffer\n\
252\n\
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900253:param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500254 buffer - The buffer the certificate is stored in\n\
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900255:return: The X509 object\n\
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500256";
257
258static PyObject *
259crypto_load_certificate(PyObject *spam, PyObject *args)
260{
261 crypto_X509Obj *crypto_X509_New(X509 *, int);
262 int type, len;
263 char *buffer;
264 BIO *bio;
265 X509 *cert;
266
267 if (!PyArg_ParseTuple(args, "is#:load_certificate", &type, &buffer, &len))
268 return NULL;
269
270 bio = BIO_new_mem_buf(buffer, len);
271 switch (type)
272 {
273 case X509_FILETYPE_PEM:
274 cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
275 break;
276
277 case X509_FILETYPE_ASN1:
278 cert = d2i_X509_bio(bio, NULL);
279 break;
280
281 default:
282 PyErr_SetString(PyExc_ValueError, "type argument must be FILETYPE_PEM or FILETYPE_ASN1");
283 BIO_free(bio);
284 return NULL;
285 }
286 BIO_free(bio);
287
288 if (cert == NULL)
289 {
Rick Deand369c932009-07-08 11:48:33 -0500290 exception_from_error_queue(crypto_Error);
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500291 return NULL;
292 }
293
294 return (PyObject *)crypto_X509_New(cert, 1);
295}
296
297static char crypto_dump_certificate_doc[] = "\n\
298Dump a certificate to a buffer\n\
299\n\
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900300:param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\
301:param cert: The certificate to dump\n\
302:return: The buffer with the dumped certificate in\n\
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500303";
304
305static PyObject *
306crypto_dump_certificate(PyObject *spam, PyObject *args)
307{
308 int type, ret, buf_len;
309 char *temp;
310 PyObject *buffer;
311 BIO *bio;
312 crypto_X509Obj *cert;
313
314 if (!PyArg_ParseTuple(args, "iO!:dump_certificate", &type,
315 &crypto_X509_Type, &cert))
316 return NULL;
317
318 bio = BIO_new(BIO_s_mem());
319 switch (type)
320 {
321 case X509_FILETYPE_PEM:
322 ret = PEM_write_bio_X509(bio, cert->x509);
323 break;
324
325 case X509_FILETYPE_ASN1:
326 ret = i2d_X509_bio(bio, cert->x509);
327 break;
328
Rick Dean5b7b6372009-04-01 11:34:06 -0500329 case X509_FILETYPE_TEXT:
330 ret = X509_print_ex(bio, cert->x509, 0, 0);
331 break;
332
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500333 default:
Rick Dean5b7b6372009-04-01 11:34:06 -0500334 PyErr_SetString(PyExc_ValueError, "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT");
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500335 BIO_free(bio);
336 return NULL;
337 }
338
339 if (ret == 0)
340 {
341 BIO_free(bio);
Rick Deand369c932009-07-08 11:48:33 -0500342 exception_from_error_queue(crypto_Error);
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500343 return NULL;
344 }
345
346 buf_len = BIO_get_mem_data(bio, &temp);
Jean-Paul Calderoneef853eb2010-08-10 19:47:06 -0400347 buffer = PyBytes_FromStringAndSize(temp, buf_len);
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500348 BIO_free(bio);
349
350 return buffer;
351}
352
353static char crypto_load_certificate_request_doc[] = "\n\
354Load a certificate request from a buffer\n\
355\n\
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900356:param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500357 buffer - The buffer the certificate request is stored in\n\
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900358:return: The X509Req object\n\
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500359";
360
361static PyObject *
362crypto_load_certificate_request(PyObject *spam, PyObject *args)
363{
364 crypto_X509ReqObj *crypto_X509Req_New(X509_REQ *, int);
365 int type, len;
366 char *buffer;
367 BIO *bio;
368 X509_REQ *req;
369
370 if (!PyArg_ParseTuple(args, "is#:load_certificate_request", &type, &buffer, &len))
371 return NULL;
372
373 bio = BIO_new_mem_buf(buffer, len);
374 switch (type)
375 {
376 case X509_FILETYPE_PEM:
377 req = PEM_read_bio_X509_REQ(bio, NULL, NULL, NULL);
378 break;
379
380 case X509_FILETYPE_ASN1:
381 req = d2i_X509_REQ_bio(bio, NULL);
382 break;
383
384 default:
385 PyErr_SetString(PyExc_ValueError, "type argument must be FILETYPE_PEM or FILETYPE_ASN1");
386 BIO_free(bio);
387 return NULL;
388 }
389 BIO_free(bio);
390
391 if (req == NULL)
392 {
Rick Deand369c932009-07-08 11:48:33 -0500393 exception_from_error_queue(crypto_Error);
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500394 return NULL;
395 }
396
397 return (PyObject *)crypto_X509Req_New(req, 1);
398}
399
400static char crypto_dump_certificate_request_doc[] = "\n\
401Dump a certificate request to a buffer\n\
402\n\
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900403:param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500404 req - The certificate request to dump\n\
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900405:return: The buffer with the dumped certificate request in\n\
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500406";
407
408static PyObject *
409crypto_dump_certificate_request(PyObject *spam, PyObject *args)
410{
411 int type, ret, buf_len;
412 char *temp;
413 PyObject *buffer;
414 BIO *bio;
415 crypto_X509ReqObj *req;
416
417 if (!PyArg_ParseTuple(args, "iO!:dump_certificate_request", &type,
418 &crypto_X509Req_Type, &req))
419 return NULL;
420
421 bio = BIO_new(BIO_s_mem());
422 switch (type)
423 {
424 case X509_FILETYPE_PEM:
425 ret = PEM_write_bio_X509_REQ(bio, req->x509_req);
426 break;
427
428 case X509_FILETYPE_ASN1:
429 ret = i2d_X509_REQ_bio(bio, req->x509_req);
430 break;
431
Rick Dean5b7b6372009-04-01 11:34:06 -0500432 case X509_FILETYPE_TEXT:
433 ret = X509_REQ_print_ex(bio, req->x509_req, 0, 0);
434 break;
435
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500436 default:
Rick Dean5b7b6372009-04-01 11:34:06 -0500437 PyErr_SetString(PyExc_ValueError, "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT");
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500438 BIO_free(bio);
439 return NULL;
440 }
441
442 if (ret == 0)
443 {
444 BIO_free(bio);
Rick Deand369c932009-07-08 11:48:33 -0500445 exception_from_error_queue(crypto_Error);
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500446 return NULL;
447 }
448
449 buf_len = BIO_get_mem_data(bio, &temp);
Jean-Paul Calderoneef853eb2010-08-10 19:47:06 -0400450 buffer = PyBytes_FromStringAndSize(temp, buf_len);
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500451 BIO_free(bio);
452
453 return buffer;
454}
455
Rick Dean536ba022009-07-24 23:57:27 -0500456static char crypto_load_crl_doc[] = "\n\
457Load a certificate revocation list from a buffer\n\
458\n\
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900459:param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\
460:param buffer: The buffer the CRL is stored in\n\
Rick Dean536ba022009-07-24 23:57:27 -0500461\n\
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900462:return: The PKey object\n\
Rick Dean536ba022009-07-24 23:57:27 -0500463";
464
465static PyObject *
Jean-Paul Calderone03ae4d32010-05-24 18:04:59 -0400466crypto_load_crl(PyObject *spam, PyObject *args) {
Rick Dean536ba022009-07-24 23:57:27 -0500467 int type, len;
468 char *buffer;
469 BIO *bio;
470 X509_CRL *crl;
471
Jean-Paul Calderone03ae4d32010-05-24 18:04:59 -0400472 if (!PyArg_ParseTuple(args, "is#:load_crl", &type, &buffer, &len)) {
Rick Dean536ba022009-07-24 23:57:27 -0500473 return NULL;
Jean-Paul Calderone03ae4d32010-05-24 18:04:59 -0400474 }
Rick Dean536ba022009-07-24 23:57:27 -0500475
476 bio = BIO_new_mem_buf(buffer, len);
Jean-Paul Calderone03ae4d32010-05-24 18:04:59 -0400477 switch (type) {
Rick Dean536ba022009-07-24 23:57:27 -0500478 case X509_FILETYPE_PEM:
479 crl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL);
480 break;
481
482 case X509_FILETYPE_ASN1:
483 crl = d2i_X509_CRL_bio(bio, NULL);
484 break;
485
486 default:
487 PyErr_SetString(PyExc_ValueError, "type argument must be FILETYPE_PEM or FILETYPE_ASN1");
488 BIO_free(bio);
489 return NULL;
490 }
491 BIO_free(bio);
492
Jean-Paul Calderone03ae4d32010-05-24 18:04:59 -0400493 if (crl == NULL) {
Rick Dean536ba022009-07-24 23:57:27 -0500494 exception_from_error_queue(crypto_Error);
495 return NULL;
496 }
497
498 return (PyObject *)crypto_CRL_New(crl);
499}
500
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500501static char crypto_load_pkcs7_data_doc[] = "\n\
502Load pkcs7 data from a buffer\n\
503\n\
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900504:param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)\n\
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500505 buffer - The buffer with the pkcs7 data.\n\
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900506:return: The PKCS7 object\n\
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500507";
508
509static PyObject *
510crypto_load_pkcs7_data(PyObject *spam, PyObject *args)
511{
512 int type, len;
513 char *buffer;
514 BIO *bio;
515 PKCS7 *pkcs7 = NULL;
516
517 if (!PyArg_ParseTuple(args, "is#:load_pkcs7_data", &type, &buffer, &len))
518 return NULL;
519
Ziga Seilnachtcccb6962009-12-22 14:06:31 +0100520 /*
521 * Try to read the pkcs7 data from the bio
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500522 */
523 bio = BIO_new_mem_buf(buffer, len);
524 switch (type)
525 {
526 case X509_FILETYPE_PEM:
527 pkcs7 = PEM_read_bio_PKCS7(bio, NULL, NULL, NULL);
528 break;
529
530 case X509_FILETYPE_ASN1:
531 pkcs7 = d2i_PKCS7_bio(bio, NULL);
532 break;
533
534 default:
535 PyErr_SetString(PyExc_ValueError,
536 "type argument must be FILETYPE_PEM or FILETYPE_ASN1");
537 return NULL;
538 }
539 BIO_free(bio);
540
541 /*
542 * Check if we got a PKCS7 structure
543 */
544 if (pkcs7 == NULL)
545 {
Rick Deand369c932009-07-08 11:48:33 -0500546 exception_from_error_queue(crypto_Error);
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500547 return NULL;
548 }
549
550 return (PyObject *)crypto_PKCS7_New(pkcs7, 1);
551}
552
553static char crypto_load_pkcs12_doc[] = "\n\
554Load a PKCS12 object from a buffer\n\
555\n\
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900556:param buffer: The buffer the certificate is stored in\n\
Jean-Paul Calderone54bcc832009-05-27 14:06:48 -0400557 passphrase (Optional) - The password to decrypt the PKCS12 lump\n\
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900558:returns: The PKCS12 object\n\
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500559";
560
561static PyObject *
562crypto_load_pkcs12(PyObject *spam, PyObject *args)
563{
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500564 int len;
565 char *buffer, *passphrase = NULL;
566 BIO *bio;
567 PKCS12 *p12;
568
569 if (!PyArg_ParseTuple(args, "s#|s:load_pkcs12", &buffer, &len, &passphrase))
570 return NULL;
571
572 bio = BIO_new_mem_buf(buffer, len);
573 if ((p12 = d2i_PKCS12_bio(bio, NULL)) == NULL)
574 {
575 BIO_free(bio);
Rick Deand369c932009-07-08 11:48:33 -0500576 exception_from_error_queue(crypto_Error);
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500577 return NULL;
578 }
579 BIO_free(bio);
580
581 return (PyObject *)crypto_PKCS12_New(p12, passphrase);
582}
583
584
Jean-Paul Calderone7df40db2008-03-03 15:12:42 -0500585static char crypto_X509_verify_cert_error_string_doc[] = "\n\
586Get X509 verify certificate error string.\n\
587\n\
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900588:param errnum: The error number.\n\
589:return: Error string as a Python string\n\
Jean-Paul Calderone7df40db2008-03-03 15:12:42 -0500590";
591
592static PyObject *
593crypto_X509_verify_cert_error_string(PyObject *spam, PyObject *args)
594{
595 int errnum;
596 const char *str;
597
598 if (!PyArg_ParseTuple(args, "i", &errnum))
599 return NULL;
600
601 str = X509_verify_cert_error_string(errnum);
Jean-Paul Calderoneef853eb2010-08-10 19:47:06 -0400602 return PyText_FromString(str);
Jean-Paul Calderone7df40db2008-03-03 15:12:42 -0500603}
604
Jean-Paul Calderone1206daf2009-07-16 16:07:42 -0400605static char crypto_exception_from_error_queue_doc[] = "\n\
606Raise an exception from the current OpenSSL error queue.\n\
607";
608
609static PyObject *
610crypto_exception_from_error_queue(PyObject *spam, PyObject *eggs) {
611 exception_from_error_queue(crypto_Error);
612 return NULL;
613}
614
James Yonan7c2e5d32010-02-27 05:45:50 -0700615static char crypto_sign_doc[] = "\n\
616Sign data with a digest\n\
617\n\
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900618:param pkey: Pkey to sign with\n\
619:param data: data to be signed\n\
620:param digest: message digest to use\n\
621:return: signature\n\
James Yonan7c2e5d32010-02-27 05:45:50 -0700622";
623
624static PyObject *
Jean-Paul Calderone8b37f0a2010-06-22 09:43:42 -0400625crypto_sign(PyObject *spam, PyObject *args) {
626 PyObject *buffer;
627 crypto_PKeyObj *pkey;
628 char *data = NULL;
David Brodsky5c019772010-12-07 20:08:50 +0100629 int data_len;
Jean-Paul Calderone8b37f0a2010-06-22 09:43:42 -0400630 char *digest_name;
631 int err;
632 unsigned int sig_len;
633 const EVP_MD *digest;
634 EVP_MD_CTX md_ctx;
635 unsigned char sig_buf[512];
James Yonan7c2e5d32010-02-27 05:45:50 -0700636
Jean-Paul Calderone7b643a92010-08-28 14:40:58 -0400637 if (!PyArg_ParseTuple(
David Brodsky5c019772010-12-07 20:08:50 +0100638 args, "O!" BYTESTRING_FMT "#s:sign", &crypto_PKey_Type,
639 &pkey, &data, &data_len, &digest_name)) {
Jean-Paul Calderone8b37f0a2010-06-22 09:43:42 -0400640 return NULL;
James Yonan7c2e5d32010-02-27 05:45:50 -0700641 }
642
Jean-Paul Calderone8b37f0a2010-06-22 09:43:42 -0400643 if ((digest = EVP_get_digestbyname(digest_name)) == NULL) {
644 PyErr_SetString(PyExc_ValueError, "No such digest method");
645 return NULL;
646 }
James Yonan7c2e5d32010-02-27 05:45:50 -0700647
Jean-Paul Calderoneb1fac9f2010-06-22 09:44:33 -0400648 EVP_SignInit(&md_ctx, digest);
David Brodsky5c019772010-12-07 20:08:50 +0100649 EVP_SignUpdate(&md_ctx, data, data_len);
Jean-Paul Calderone8b37f0a2010-06-22 09:43:42 -0400650 sig_len = sizeof(sig_buf);
Jean-Paul Calderoneb1fac9f2010-06-22 09:44:33 -0400651 err = EVP_SignFinal(&md_ctx, sig_buf, &sig_len, pkey->pkey);
James Yonan7c2e5d32010-02-27 05:45:50 -0700652
Jean-Paul Calderone8b37f0a2010-06-22 09:43:42 -0400653 if (err != 1) {
654 exception_from_error_queue(crypto_Error);
655 return NULL;
656 }
657
Jean-Paul Calderoneef853eb2010-08-10 19:47:06 -0400658 buffer = PyBytes_FromStringAndSize((char*)sig_buf, sig_len);
Jean-Paul Calderone8b37f0a2010-06-22 09:43:42 -0400659 return buffer;
James Yonan7c2e5d32010-02-27 05:45:50 -0700660}
661
662static char crypto_verify_doc[] = "\n\
663Verify a signature\n\
664\n\
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900665:param cert: signing certificate (X509 object)\n\
666:param signature: signature returned by sign function\n\
667:param data: data to be verified\n\
668:param digest: message digest to use\n\
669:return: None if the signature is correct, raise exception otherwise\n\
James Yonan7c2e5d32010-02-27 05:45:50 -0700670";
671
672static PyObject *
Jean-Paul Calderoneb1fac9f2010-06-22 09:44:33 -0400673crypto_verify(PyObject *spam, PyObject *args) {
674 crypto_X509Obj *cert;
675 unsigned char *signature;
676 int sig_len;
677 char *data, *digest_name;
David Brodsky5c019772010-12-07 20:08:50 +0100678 int data_len;
Jean-Paul Calderoneb1fac9f2010-06-22 09:44:33 -0400679 int err;
680 const EVP_MD *digest;
681 EVP_MD_CTX md_ctx;
682 EVP_PKEY *pkey;
James Yonan7c2e5d32010-02-27 05:45:50 -0700683
Jean-Paul Calderone7b643a92010-08-28 14:40:58 -0400684#ifdef PY3
David Brodsky5c019772010-12-07 20:08:50 +0100685 if (!PyArg_ParseTuple(args, "O!" BYTESTRING_FMT "#" BYTESTRING_FMT "#s:verify", &crypto_X509_Type, &cert, &signature, &sig_len, &data, &data_len, &digest_name)) {
Jean-Paul Calderone7b643a92010-08-28 14:40:58 -0400686#else
David Brodsky5c019772010-12-07 20:08:50 +0100687 if (!PyArg_ParseTuple(args, "O!t#s#s:verify", &crypto_X509_Type, &cert, &signature, &sig_len, &data, &data_len, &digest_name)) {
Jean-Paul Calderone7b643a92010-08-28 14:40:58 -0400688#endif
Jean-Paul Calderoneb1fac9f2010-06-22 09:44:33 -0400689 return NULL;
690 }
James Yonan7c2e5d32010-02-27 05:45:50 -0700691
Jean-Paul Calderoneb1fac9f2010-06-22 09:44:33 -0400692 if ((digest = EVP_get_digestbyname(digest_name)) == NULL){
693 PyErr_SetString(PyExc_ValueError, "No such digest method");
694 return NULL;
695 }
James Yonan7c2e5d32010-02-27 05:45:50 -0700696
Jean-Paul Calderoneb1fac9f2010-06-22 09:44:33 -0400697 pkey = X509_get_pubkey(cert->x509);
698 if (pkey == NULL) {
699 PyErr_SetString(PyExc_ValueError, "No public key");
700 return NULL;
701 }
James Yonan7c2e5d32010-02-27 05:45:50 -0700702
Jean-Paul Calderoneb1fac9f2010-06-22 09:44:33 -0400703 EVP_VerifyInit(&md_ctx, digest);
David Brodsky5c019772010-12-07 20:08:50 +0100704 EVP_VerifyUpdate(&md_ctx, data, data_len);
Jean-Paul Calderoneb1fac9f2010-06-22 09:44:33 -0400705 err = EVP_VerifyFinal(&md_ctx, signature, sig_len, pkey);
706 EVP_PKEY_free(pkey);
James Yonan7c2e5d32010-02-27 05:45:50 -0700707
Jean-Paul Calderoneb1fac9f2010-06-22 09:44:33 -0400708 if (err != 1) {
709 exception_from_error_queue(crypto_Error);
710 return NULL;
711 }
712
713 Py_INCREF(Py_None);
714 return Py_None;
James Yonan7c2e5d32010-02-27 05:45:50 -0700715}
Jean-Paul Calderone1206daf2009-07-16 16:07:42 -0400716
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500717/* Methods in the OpenSSL.crypto module (i.e. none) */
718static PyMethodDef crypto_methods[] = {
719 /* Module functions */
720 { "load_privatekey", (PyCFunction)crypto_load_privatekey, METH_VARARGS, crypto_load_privatekey_doc },
721 { "dump_privatekey", (PyCFunction)crypto_dump_privatekey, METH_VARARGS, crypto_dump_privatekey_doc },
722 { "load_certificate", (PyCFunction)crypto_load_certificate, METH_VARARGS, crypto_load_certificate_doc },
723 { "dump_certificate", (PyCFunction)crypto_dump_certificate, METH_VARARGS, crypto_dump_certificate_doc },
724 { "load_certificate_request", (PyCFunction)crypto_load_certificate_request, METH_VARARGS, crypto_load_certificate_request_doc },
725 { "dump_certificate_request", (PyCFunction)crypto_dump_certificate_request, METH_VARARGS, crypto_dump_certificate_request_doc },
Rick Dean536ba022009-07-24 23:57:27 -0500726 { "load_crl", (PyCFunction)crypto_load_crl, METH_VARARGS, crypto_load_crl_doc },
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500727 { "load_pkcs7_data", (PyCFunction)crypto_load_pkcs7_data, METH_VARARGS, crypto_load_pkcs7_data_doc },
728 { "load_pkcs12", (PyCFunction)crypto_load_pkcs12, METH_VARARGS, crypto_load_pkcs12_doc },
James Yonan7c2e5d32010-02-27 05:45:50 -0700729 { "sign", (PyCFunction)crypto_sign, METH_VARARGS, crypto_sign_doc },
730 { "verify", (PyCFunction)crypto_verify, METH_VARARGS, crypto_verify_doc },
Jean-Paul Calderone7df40db2008-03-03 15:12:42 -0500731 { "X509_verify_cert_error_string", (PyCFunction)crypto_X509_verify_cert_error_string, METH_VARARGS, crypto_X509_verify_cert_error_string_doc },
Jean-Paul Calderone1206daf2009-07-16 16:07:42 -0400732 { "_exception_from_error_queue", (PyCFunction)crypto_exception_from_error_queue, METH_NOARGS, crypto_exception_from_error_queue_doc },
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500733 { NULL, NULL }
734};
735
Jean-Paul Calderoneaea5d902008-04-26 19:53:39 -0400736
737#ifdef WITH_THREAD
738
739#include <pythread.h>
740
741/**
742 * This array will store all of the mutexes available to OpenSSL.
743 */
744static PyThread_type_lock *mutex_buf = NULL;
745
746
747/**
748 * Callback function supplied to OpenSSL to acquire or release a lock.
749 *
750 */
751static void locking_function(int mode, int n, const char * file, int line) {
752 if (mode & CRYPTO_LOCK) {
753 PyThread_acquire_lock(mutex_buf[n], WAIT_LOCK);
754 } else {
755 PyThread_release_lock(mutex_buf[n]);
756 }
757}
758
759
760/**
761 * Initialize OpenSSL for use from multiple threads.
762 *
763 * Returns: 0 if initialization fails, 1 otherwise.
764 */
765static int init_openssl_threads(void) {
766 int i;
767
768 mutex_buf = (PyThread_type_lock *)malloc(
769 CRYPTO_num_locks() * sizeof(PyThread_type_lock));
770 if (!mutex_buf) {
771 return 0;
772 }
773 for (i = 0; i < CRYPTO_num_locks(); ++i) {
774 mutex_buf[i] = PyThread_allocate_lock();
775 }
Jean-Paul Calderone28ebb302008-12-29 16:25:30 -0500776 CRYPTO_set_id_callback((unsigned long (*)(void))PyThread_get_thread_ident);
Jean-Paul Calderoneaea5d902008-04-26 19:53:39 -0400777 CRYPTO_set_locking_callback(locking_function);
778 return 1;
779}
780
781/* /\** */
782/* * Clean up after OpenSSL thread initialization. */
783/* *\/ */
784/* static int deinit_openssl_threads() { */
785/* int i; */
786
787/* if (!mutex_buf) { */
788/* return 0; */
789/* } */
790/* CRYPTO_set_id_callback(NULL); */
791/* CRYPTO_set_locking_callback(NULL); */
792/* for (i = 0; i < CRYPTO_num_locks(); i++) { */
793/* PyThread_free_lock(mutex_buf[i]); */
794/* } */
795/* free(mutex_buf); */
796/* mutex_buf = NULL; */
797/* return 1; */
798/* } */
799
800#endif
801
Jean-Paul Calderoneef853eb2010-08-10 19:47:06 -0400802#ifdef PY3
803static struct PyModuleDef cryptomodule = {
804 PyModuleDef_HEAD_INIT,
805 "crypto",
806 crypto_doc,
807 -1,
808 crypto_methods
809};
810#endif
Jean-Paul Calderoneaea5d902008-04-26 19:53:39 -0400811
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500812/*
813 * Initialize crypto sub module
814 *
815 * Arguments: None
816 * Returns: None
817 */
Jean-Paul Calderoneef853eb2010-08-10 19:47:06 -0400818PyOpenSSL_MODINIT(crypto) {
819#ifndef PY3
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500820 static void *crypto_API[crypto_API_pointers];
821 PyObject *c_api_object;
Jean-Paul Calderoneef853eb2010-08-10 19:47:06 -0400822#endif
Jean-Paul Calderone0cdb7bd2009-07-04 10:21:07 -0400823 PyObject *module;
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500824
825 ERR_load_crypto_strings();
826 OpenSSL_add_all_algorithms();
827
Jean-Paul Calderoneef853eb2010-08-10 19:47:06 -0400828#ifdef PY3
829 module = PyModule_Create(&cryptomodule);
830#else
831 module = Py_InitModule3("crypto", crypto_methods, crypto_doc);
832#endif
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500833
Jean-Paul Calderoneef853eb2010-08-10 19:47:06 -0400834 if (module == NULL) {
Jean-Paul Calderone3fe7f672010-08-11 23:55:10 -0400835 PyOpenSSL_MODRETURN(NULL);
Jean-Paul Calderoneef853eb2010-08-10 19:47:06 -0400836 }
837
838#ifndef PY3
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500839 /* Initialize the C API pointer array */
840 crypto_API[crypto_X509_New_NUM] = (void *)crypto_X509_New;
841 crypto_API[crypto_X509Name_New_NUM] = (void *)crypto_X509Name_New;
842 crypto_API[crypto_X509Req_New_NUM] = (void *)crypto_X509Req_New;
843 crypto_API[crypto_X509Store_New_NUM] = (void *)crypto_X509Store_New;
844 crypto_API[crypto_PKey_New_NUM] = (void *)crypto_PKey_New;
845 crypto_API[crypto_X509Extension_New_NUM] = (void *)crypto_X509Extension_New;
846 crypto_API[crypto_PKCS7_New_NUM] = (void *)crypto_PKCS7_New;
847 crypto_API[crypto_NetscapeSPKI_New_NUM] = (void *)crypto_NetscapeSPKI_New;
848 c_api_object = PyCObject_FromVoidPtr((void *)crypto_API, NULL);
Jean-Paul Calderoneaed23582011-03-12 22:45:02 -0500849 if (c_api_object != NULL) {
850 /* PyModule_AddObject steals a reference.
851 */
Jean-Paul Calderone026f6642011-04-20 18:59:33 -0400852 Py_INCREF(c_api_object);
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500853 PyModule_AddObject(module, "_C_API", c_api_object);
Jean-Paul Calderoneaed23582011-03-12 22:45:02 -0500854 }
Jean-Paul Calderoneef853eb2010-08-10 19:47:06 -0400855#endif
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500856
857 crypto_Error = PyErr_NewException("OpenSSL.crypto.Error", NULL, NULL);
858 if (crypto_Error == NULL)
859 goto error;
Jean-Paul Calderoneaed23582011-03-12 22:45:02 -0500860
861 /* PyModule_AddObject steals a reference.
862 */
Jean-Paul Calderone026f6642011-04-20 18:59:33 -0400863 Py_INCREF(crypto_Error);
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500864 if (PyModule_AddObject(module, "Error", crypto_Error) != 0)
865 goto error;
866
867 PyModule_AddIntConstant(module, "FILETYPE_PEM", X509_FILETYPE_PEM);
868 PyModule_AddIntConstant(module, "FILETYPE_ASN1", X509_FILETYPE_ASN1);
Rick Dean5b7b6372009-04-01 11:34:06 -0500869 PyModule_AddIntConstant(module, "FILETYPE_TEXT", X509_FILETYPE_TEXT);
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500870
871 PyModule_AddIntConstant(module, "TYPE_RSA", crypto_TYPE_RSA);
872 PyModule_AddIntConstant(module, "TYPE_DSA", crypto_TYPE_DSA);
873
Jean-Paul Calderoneaea5d902008-04-26 19:53:39 -0400874#ifdef WITH_THREAD
875 if (!init_openssl_threads())
876 goto error;
877#endif
Jean-Paul Calderone2e1da572009-06-27 10:44:00 -0400878 if (!init_crypto_x509(module))
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500879 goto error;
Jean-Paul Calderone2cd7a922009-06-27 11:02:46 -0400880 if (!init_crypto_x509name(module))
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500881 goto error;
Jean-Paul Calderone0cdb7bd2009-07-04 10:21:07 -0400882 if (!init_crypto_x509store(module))
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500883 goto error;
Jean-Paul Calderonef1592522009-06-27 11:10:43 -0400884 if (!init_crypto_x509req(module))
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500885 goto error;
Jean-Paul Calderone2e1da572009-06-27 10:44:00 -0400886 if (!init_crypto_pkey(module))
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500887 goto error;
Jean-Paul Calderone51e90662009-06-27 11:17:28 -0400888 if (!init_crypto_x509extension(module))
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500889 goto error;
Jean-Paul Calderonedc138fa2009-06-27 14:32:07 -0400890 if (!init_crypto_pkcs7(module))
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500891 goto error;
Jean-Paul Calderonedc138fa2009-06-27 14:32:07 -0400892 if (!init_crypto_pkcs12(module))
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500893 goto error;
Jean-Paul Calderonedc138fa2009-06-27 14:32:07 -0400894 if (!init_crypto_netscape_spki(module))
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500895 goto error;
Rick Dean536ba022009-07-24 23:57:27 -0500896 if (!init_crypto_crl(module))
897 goto error;
898 if (!init_crypto_revoked(module))
899 goto error;
Jean-Paul Calderoneef853eb2010-08-10 19:47:06 -0400900
Jean-Paul Calderone3fe7f672010-08-11 23:55:10 -0400901 PyOpenSSL_MODRETURN(module);
Jean-Paul Calderoneef853eb2010-08-10 19:47:06 -0400902
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500903error:
Jean-Paul Calderone3fe7f672010-08-11 23:55:10 -0400904 PyOpenSSL_MODRETURN(NULL);
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500905 ;
906}