1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* Copyright (c) 1999 Ng Pheng Siong. All rights reserved.
3 *
4 * Portions created by Open Source Applications Foundation (OSAF) are
5 * Copyright (C) 2004-2005 OSAF. All Rights Reserved.
6 * Author: Heikki Toivonen
7 *
8 * Copyright 2018 Daniel Wozniak. All Rights Reserved.*/
9 /* $Id$ */
10
11 %{
12 #include <openssl/bio.h>
13 %}
14
15 %apply Pointer NONNULL { BIO * };
16 %apply Pointer NONNULL { BIO_METHOD * };
17
18 %rename(bio_s_bio) BIO_s_bio;
19 extern BIO_METHOD *BIO_s_bio(void);
20 %rename(bio_s_mem) BIO_s_mem;
21 extern BIO_METHOD *BIO_s_mem(void);
22 %rename(bio_s_socket) BIO_s_socket;
23 extern BIO_METHOD *BIO_s_socket(void);
24 %rename(bio_f_ssl) BIO_f_ssl;
25 extern BIO_METHOD *BIO_f_ssl(void);
26 %rename(bio_f_buffer) BIO_f_buffer;
27 extern BIO_METHOD *BIO_f_buffer(void);
28 %rename(bio_f_cipher) BIO_f_cipher;
29 extern BIO_METHOD *BIO_f_cipher(void);
30
31 %rename(bio_new) BIO_new;
32 extern BIO *BIO_new(BIO_METHOD *);
33 %rename(bio_new_socket) BIO_new_socket;
34 extern BIO *BIO_new_socket(int, int);
35 %rename(bio_new_fd) BIO_new_pyfd;
36 %rename(bio_new_pyfd) BIO_new_pyfd;
37 %rename(bio_free_all) BIO_free_all;
38 %threadallow BIO_free_all;
39 extern void BIO_free_all(BIO *);
40 %rename(bio_dup_chain) BIO_dup_chain;
41 extern BIO *BIO_dup_chain(BIO *);
42
43 %rename(bio_push) BIO_push;
44 extern BIO *BIO_push(BIO *, BIO *);
45 %rename(bio_pop) BIO_pop;
46 extern BIO *BIO_pop(BIO *);
47
48 %rename(bio_eof) BIO_eof;
49 extern int BIO_eof(BIO *);
50
51 %constant int bio_noclose = BIO_NOCLOSE;
52 %constant int bio_close = BIO_CLOSE;
53 %constant int BIO_FLAGS_READ = 0x01;
54 %constant int BIO_FLAGS_WRITE = 0x02;
55 %constant int BIO_FLAGS_IO_SPECIAL = 0x04;
56 %constant int BIO_FLAGS_RWS = (BIO_FLAGS_READ|BIO_FLAGS_WRITE|BIO_FLAGS_IO_SPECIAL);
57 %constant int BIO_FLAGS_SHOULD_RETRY = 0x08;
58 %constant int BIO_FLAGS_MEM_RDONLY = 0x200;
59
60 %warnfilter(454) _bio_err;
61 %inline %{
62 static PyObject *_bio_err;
63
64
65 void pyfd_init(void);
66
bio_init(PyObject * bio_err)67 void bio_init(PyObject *bio_err) {
68 Py_INCREF(bio_err);
69 _bio_err = bio_err;
70 pyfd_init();
71 }
72
bio_free(BIO * bio)73 int bio_free(BIO *bio) {
74 int ret;
75
76 Py_BEGIN_ALLOW_THREADS
77 ret = BIO_free(bio);
78 Py_END_ALLOW_THREADS
79 if (ret == 0) {
80 m2_PyErr_Msg(_bio_err);
81 }
82 return ret;
83 }
84
bio_new_file(const char * filename,const char * mode)85 BIO * bio_new_file(const char *filename, const char *mode) {
86 BIO *ret;
87
88 Py_BEGIN_ALLOW_THREADS
89 ret = BIO_new_file(filename, mode);
90 Py_END_ALLOW_THREADS
91
92 if (ret == NULL) {
93 m2_PyErr_Msg(_bio_err);
94 }
95
96 return ret;
97 }
98
bio_new_pyfile(PyObject * pyfile,int bio_close)99 BIO *bio_new_pyfile(PyObject *pyfile, int bio_close) {
100 FILE *fp = NULL;
101 BIO *bio = NULL;
102
103 fp = PyFile_AsFile(pyfile);
104
105 bio = BIO_new_fp(fp, bio_close);
106
107 /* returns NULL if error occurred */
108 if (bio == NULL) {
109 /* Find out the name of the file so we can have good error
110 * message. */
111 PyObject *pyname = m2_PyFile_Name(pyfile);
112 char *name = PyBytes_AsString(pyname);
113
114 if (name == NULL) {
115 PyErr_Format(_bio_err,
116 "Opening of the new BIO on file failed!");
117 }
118 else {
119 PyErr_Format(_bio_err,
120 "Opening of the new BIO on file %s failed!", name);
121 }
122 Py_DECREF(pyname);
123 }
124 return bio;
125 }
126
bio_read(BIO * bio,int num)127 PyObject *bio_read(BIO *bio, int num) {
128 PyObject *blob;
129 void *buf;
130 int r;
131
132 if (!(buf = PyMem_Malloc(num))) {
133 PyErr_SetString(PyExc_MemoryError, "bio_read");
134 return NULL;
135 }
136 Py_BEGIN_ALLOW_THREADS
137 r = BIO_read(bio, buf, num);
138 Py_END_ALLOW_THREADS
139 if (r < 0) {
140 PyMem_Free(buf);
141 if (ERR_peek_error()) {
142 m2_PyErr_Msg(_bio_err);
143 return NULL;
144 }
145 Py_RETURN_NONE;
146 }
147
148 blob = PyBytes_FromStringAndSize(buf, r);
149
150 PyMem_Free(buf);
151 return blob;
152 }
153
bio_gets(BIO * bio,int num)154 PyObject *bio_gets(BIO *bio, int num) {
155 PyObject *blob;
156 void *buf;
157 int r;
158
159 if (!(buf = PyMem_Malloc(num))) {
160 PyErr_SetString(PyExc_MemoryError, "bio_gets");
161 return NULL;
162 }
163 Py_BEGIN_ALLOW_THREADS
164 r = BIO_gets(bio, buf, num);
165 Py_END_ALLOW_THREADS
166 if (r < 1) {
167 PyMem_Free(buf);
168 if (ERR_peek_error()) {
169 m2_PyErr_Msg(_bio_err);
170 return NULL;
171 }
172 Py_RETURN_NONE;
173 }
174
175 blob = PyBytes_FromStringAndSize(buf, r);
176
177 PyMem_Free(buf);
178 return blob;
179 }
180
bio_write(BIO * bio,PyObject * from)181 int bio_write(BIO *bio, PyObject *from) {
182 const void *fbuf;
183 int flen = 0, ret;
184
185 if (m2_PyObject_AsReadBufferInt(from, &fbuf, &flen) == -1)
186 return -1;
187
188 Py_BEGIN_ALLOW_THREADS
189 ret = BIO_write(bio, fbuf, flen);
190 Py_END_ALLOW_THREADS
191 if (ret < 0) {
192 if (ERR_peek_error()) {
193 m2_PyErr_Msg(_bio_err);
194 return -1;
195 }
196 }
197 return ret;
198 }
199
200 /* XXX Casting size_t to int. */
bio_ctrl_pending(BIO * bio)201 int bio_ctrl_pending(BIO *bio) {
202 return (int)BIO_ctrl_pending(bio);
203 }
204
bio_ctrl_wpending(BIO * bio)205 int bio_ctrl_wpending(BIO *bio) {
206 return (int)BIO_ctrl_wpending(bio);
207 }
208
bio_ctrl_get_write_guarantee(BIO * a)209 int bio_ctrl_get_write_guarantee(BIO *a) {
210 return BIO_ctrl_get_write_guarantee(a);
211 }
212
bio_reset(BIO * bio)213 int bio_reset(BIO *bio) {
214 return (int)BIO_reset(bio);
215 }
216 %}
217
218 %threadallow bio_flush;
219 %inline %{
bio_flush(BIO * bio)220 int bio_flush(BIO *bio) {
221 return (int)BIO_flush(bio);
222 }
223
bio_seek(BIO * bio,int offset)224 int bio_seek(BIO *bio, int offset) {
225 return (int)BIO_seek(bio, offset);
226 }
227
bio_tell(BIO * bio)228 int bio_tell(BIO* bio) {
229 return BIO_tell(bio);
230 }
231
bio_set_flags(BIO * bio,int flags)232 void bio_set_flags(BIO *bio, int flags) {
233 BIO_set_flags(bio, flags);
234 }
235
bio_get_flags(BIO * bio)236 int bio_get_flags(BIO *bio) {
237 return BIO_get_flags(bio);
238 }
239
240 /*
241 * sets the cipher of BIO @param b to c using key @param key and IV @iv.
242 * @param enc should be set to 1 for encryption and zero to decryption.
243 *
244 */
bio_set_cipher(BIO * b,EVP_CIPHER * c,PyObject * key,PyObject * iv,int op)245 PyObject *bio_set_cipher(BIO *b, EVP_CIPHER *c, PyObject *key, PyObject *iv, int op) {
246 const void *kbuf, *ibuf;
247 Py_ssize_t klen, ilen;
248
249 if ((m2_PyObject_AsReadBuffer(key, &kbuf, &klen) == -1)
250 || (m2_PyObject_AsReadBuffer(iv, &ibuf, &ilen) == -1))
251 return NULL;
252
253 BIO_set_cipher(b, (const EVP_CIPHER *)c,
254 (unsigned char *)kbuf, (unsigned char *)ibuf, op);
255 Py_RETURN_NONE;
256 }
257
bio_set_mem_eof_return(BIO * b,int v)258 int bio_set_mem_eof_return(BIO *b, int v) {
259 return (int)BIO_set_mem_eof_return(b, v);
260 }
261
bio_get_fd(BIO * bio)262 int bio_get_fd(BIO *bio) {
263 return BIO_get_fd(bio, NULL);
264 }
265 %}
266
267 %warnfilter(454) methods_fdp;
268 %threadallow bio_do_handshake;
269 %inline %{
bio_do_handshake(BIO * bio)270 int bio_do_handshake(BIO *bio) {
271 return BIO_do_handshake(bio);
272 }
273
274 /* macro */
bio_make_bio_pair(BIO * b1,BIO * b2)275 int bio_make_bio_pair(BIO* b1, BIO* b2) {
276 return BIO_make_bio_pair(b1, b2);
277 }
278
bio_set_write_buf_size(BIO * b,size_t size)279 int bio_set_write_buf_size(BIO* b, size_t size) {
280 return BIO_set_write_buf_size(b, size);
281 }
282
bio_should_retry(BIO * a)283 int bio_should_retry(BIO* a) {
284 return BIO_should_retry(a);
285 }
286
bio_should_read(BIO * a)287 int bio_should_read(BIO* a) {
288 return BIO_should_read(a);
289 }
290
bio_should_write(BIO * a)291 int bio_should_write(BIO* a) {
292 return BIO_should_write(a);
293 }
294
295 /* Macros for things not defined before 1.1.0 */
296 #if OPENSSL_VERSION_NUMBER < 0x10100000L
297 static BIO_METHOD *
BIO_meth_new(int type,const char * name)298 BIO_meth_new( int type, const char *name )
299 {
300 BIO_METHOD *method = malloc( sizeof(BIO_METHOD) );
301 memset( method, 0, sizeof(BIO_METHOD) );
302
303 method->type = type;
304 method->name = name;
305
306 return method;
307 }
308
309 static void
BIO_meth_free(BIO_METHOD * meth)310 BIO_meth_free( BIO_METHOD *meth )
311 {
312 if ( meth == NULL ) {
313 return;
314 }
315
316 free(meth);
317 }
318 #define BIO_meth_set_write(m, f) (m)->bwrite = (f)
319 #define BIO_meth_set_read(m, f) (m)->bread = (f)
320 #define BIO_meth_set_puts(m, f) (m)->bputs = (f)
321 #define BIO_meth_set_gets(m, f) (m)->bgets = (f)
322 #define BIO_meth_set_ctrl(m, f) (m)->ctrl = (f)
323 #define BIO_meth_set_create(m, f) (m)->create = (f)
324 #define BIO_meth_set_destroy(m, f) (m)->destroy = (f)
325 #define BIO_set_shutdown(b, x) (b)->shutdown = x
326 #define BIO_get_shutdown(b) (b)->shutdown
327 #define BIO_set_init(b, x) b->init = x
328 #define BIO_get_init(b) (b)->init
329 #define BIO_set_data(b, x) b->ptr = x
330 #define BIO_clear_flags(b, x) b->flags &= ~(x)
331 #define BIO_get_data(b) b->ptr
332 #endif
333
334 /* implment custom BIO_s_pyfd */
335
336 #ifdef _WIN32
337 # define clear_sys_error() SetLastError(0)
338 /* Linux doesn't use underscored calls yet */
339 # define open(p, f, m) _open(p, f, m)
340 # define read(f, b, n) _read(f, b, n)
341 # define write(f, b, n) _write(f, b, n)
342 # define close(f) _close(f)
343 # define lseek(fd, o, w) _lseek(fd, o, w)
344 #else
345 # define clear_sys_error() errno=0
346 #endif
347
348 typedef struct pyfd_struct {
349 int fd;
350 } BIO_PYFD_CTX;
351
352 /* Setting up methods_fdp */
353 static BIO_METHOD *methods_fdp;
354
pyfd_write(BIO * b,const char * in,int inl)355 static int pyfd_write(BIO *b, const char *in, int inl) {
356 int ret, fd;
357
358 if (BIO_get_fd(b, &fd) == -1) {
359 PyErr_SetString(_bio_err, "BIO has not been initialized.");
360 return -1;
361 }
362 clear_sys_error();
363 ret = write(fd, in, inl);
364 BIO_clear_retry_flags(b);
365 if (ret <= 0) {
366 if (BIO_fd_should_retry(ret))
367 BIO_set_retry_write(b);
368 }
369 return ret;
370 }
371
pyfd_read(BIO * b,char * out,int outl)372 static int pyfd_read(BIO *b, char *out, int outl) {
373 int ret = 0, fd;
374
375 if (BIO_get_fd(b, &fd) == -1) {
376 PyErr_SetString(_bio_err, "BIO has not been initialized.");
377 return -1;
378 }
379 if (out != NULL) {
380 clear_sys_error();
381 ret = read(fd, out, outl);
382 BIO_clear_retry_flags(b);
383 if (ret <= 0) {
384 if (BIO_fd_should_retry(ret))
385 BIO_set_retry_read(b);
386 }
387 }
388 return ret;
389 }
390
pyfd_puts(BIO * bp,const char * str)391 static int pyfd_puts(BIO *bp, const char *str) {
392 int n, ret;
393
394 n = strlen(str);
395 ret = pyfd_write(bp, str, n);
396 return ret;
397 }
398
pyfd_gets(BIO * bp,char * buf,int size)399 static int pyfd_gets(BIO *bp, char *buf, int size) {
400 int ret = 0;
401 char *ptr = buf;
402 char *end = buf + size - 1;
403
404 /* See
405 https://github.com/openssl/openssl/pull/3442
406 We were here just repeating a bug from OpenSSL
407 */
408 while (ptr < end && pyfd_read(bp, ptr, 1) > 0) {
409 if (*ptr++ == '\n')
410 break;
411 }
412
413 ptr[0] = '\0';
414
415 if (buf[0] != '\0')
416 ret = strlen(buf);
417 return ret;
418 }
419
pyfd_new(BIO * b)420 static int pyfd_new(BIO* b) {
421 BIO_PYFD_CTX* ctx;
422
423 ctx = OPENSSL_zalloc(sizeof(*ctx));
424 if (ctx == NULL)
425 return 0;
426
427 ctx->fd = -1;
428
429 BIO_set_data(b, ctx);
430 BIO_set_shutdown(b, 0);
431 BIO_set_init(b, 1);
432
433 return 1;
434 }
435
436 #ifdef LIBRESSL_VERSION_NUMBER
437 #define BIO_get_init(b) (b)->init
438 #endif
439
pyfd_free(BIO * b)440 static int pyfd_free(BIO* b) {
441 BIO_PYFD_CTX* ctx;
442
443 if (b == 0)
444 return 0;
445
446 ctx = BIO_get_data(b);
447 if (ctx == NULL)
448 return 0;
449
450 if (BIO_get_shutdown(b) && BIO_get_init(b))
451 close(ctx->fd);
452
453 BIO_set_data(b, NULL);
454 BIO_set_shutdown(b, 0);
455 BIO_set_init(b, 0);
456
457 OPENSSL_free(ctx);
458
459 return 1;
460 }
461
pyfd_ctrl(BIO * b,int cmd,long num,void * ptr)462 static long pyfd_ctrl(BIO *b, int cmd, long num, void *ptr) {
463 BIO_PYFD_CTX* ctx;
464 int *ip;
465 long ret = 1;
466
467 ctx = BIO_get_data(b);
468 if (ctx == NULL)
469 return 0;
470
471 switch (cmd) {
472 case BIO_CTRL_RESET:
473 num = 0;
474 case BIO_C_FILE_SEEK:
475 ret = (long)lseek(ctx->fd, num, 0);
476 break;
477 case BIO_C_FILE_TELL:
478 case BIO_CTRL_INFO:
479 ret = (long)lseek(ctx->fd, 0, 1);
480 break;
481 case BIO_C_SET_FD:
482 pyfd_free(b);
483 if (*((int *)ptr) > -1) {
484 if (!pyfd_new(b) || !(ctx = BIO_get_data(b)))
485 return 0;
486 ctx->fd = *((int *)ptr);
487 BIO_set_shutdown(b, (int)num);
488 BIO_set_init(b, 1);
489 }
490 break;
491 case BIO_C_GET_FD:
492 if (BIO_get_init(b)) {
493 ip = (int *)ptr;
494 if (ip != NULL)
495 *ip = ctx->fd;
496 ret = ctx->fd;
497 } else
498 ret = -1;
499 break;
500 case BIO_CTRL_GET_CLOSE:
501 ret = BIO_get_shutdown(b);
502 break;
503 case BIO_CTRL_SET_CLOSE:
504 BIO_set_shutdown(b, (int)num);
505 break;
506 case BIO_CTRL_PENDING:
507 case BIO_CTRL_WPENDING:
508 ret = 0;
509 break;
510 case BIO_CTRL_DUP:
511 case BIO_CTRL_FLUSH:
512 ret = 1;
513 break;
514 default:
515 ret = 0;
516 break;
517 }
518 return ret;
519 }
520
pyfd_init(void)521 void pyfd_init(void) {
522 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
523 methods_fdp = BIO_meth_new(
524 BIO_get_new_index()|BIO_TYPE_DESCRIPTOR|BIO_TYPE_SOURCE_SINK,
525 "python file descriptor");
526 #else
527 methods_fdp = BIO_meth_new(
528 100 |BIO_TYPE_DESCRIPTOR|BIO_TYPE_SOURCE_SINK,
529 "python file descriptor");
530 #endif
531
532 BIO_meth_set_write(methods_fdp, pyfd_write);
533 BIO_meth_set_read(methods_fdp, pyfd_read);
534 BIO_meth_set_puts(methods_fdp, pyfd_puts);
535 BIO_meth_set_gets(methods_fdp, pyfd_gets);
536 BIO_meth_set_ctrl(methods_fdp, pyfd_ctrl);
537 BIO_meth_set_create(methods_fdp, pyfd_new);
538 BIO_meth_set_destroy(methods_fdp, pyfd_free);
539 }
540
BIO_new_pyfd(int fd,int close_flag)541 BIO* BIO_new_pyfd(int fd, int close_flag) {
542 BIO *ret;
543
544 ret = BIO_new(methods_fdp);
545 BIO_set_fd(ret, fd, close_flag);
546 return ret;
547 }
548 %}
549
550