1 /*
2 * Copyright (c) 2008
3 * Matt Harris. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * "This product includes software developed by Matt Harris."
16 * 4. Neither the name of the Mr. Harris nor the names of his contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 * 5. Any modifications and/or variations in the end-product which you are
20 * distributing from the original source code are clearly noted in
21 * the standard end-user documentation distributed with any package
22 * containing this software in either source or binary form, as well
23 * as on any internet sites or media on which this software is included.
24 *
25 * THIS SOFTWARE IS PROVIDED BY Mr. Harris AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL Mr. Harris OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 */
38
39 #include <msocket-internal.h>
40
41
42 static SSL *_lms_ssl_list[LMS_HIGHSOCK];
43 static SSL_CTX *_lms_ssl_ctx;
44 static SSL_CTX *_lms_ssl_clientctx;
45 static lms_ssl_store *_lms_ssl_masterstore;
46 #ifndef LMS_SSLV2
47 static char _lms_ssl_sciphers[] = "-ALL:DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:AES256-SHA:DHE-RSA-CAMELLIA256-SHA:DHE-DSS-CAMELLIA256-SHA:CAMELLIA256-SHA:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA:AES128-SHA:DHE-RSA-CAMELLIA128-SHA:DHE-DSS-CAMELLIA128-SHA:CAMELLIA128-SHA";
48 static char _lms_ssl_cciphers[] = "-ALL:DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:AES256-SHA:DHE-RSA-CAMELLIA256-SHA:DHE-DSS-CAMELLIA256-SHA:CAMELLIA256-SHA:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA:AES128-SHA:DHE-RSA-CAMELLIA128-SHA:DHE-DSS-CAMELLIA128-SHA:CAMELLIA128-SHA:IDEA-CBC-SHA:RC4-SHA:EDH-RSA-DES-CBC3-SHA:EDH-DSS-DES-CBC3-SHA:DES-CBC3-SHA";
49 static char _lms_ssl_jciphers[] = "ALL:!ADH:@STRENGTH";
50 #else
51 static char _lms_ssl_sciphers[] = "ALL:!ADH:@STRENGTH";
52 static char _lms_ssl_cciphers[] = "ALL:!ADH:@STRENGTH";
53 #endif /* LMS_SSLV2 */
54
55 static lms_ssl_store *_lms_ssl_loadfiles(X509 *ca, const char *path);
56 static int _lms_ssl_freestore(lms_ssl_store *s);
57 static int _lms_ssl_getbiofd(BIO *b);
58
59
60 /*
61 * lms_ssl_init() initializes the SSL functionality of NGCast
62 *
63 */
lms_ssl_init()64 int lms_ssl_init()
65 {
66 unsigned int i;
67 unsigned char *buffer;
68 X509_STORE *serverstore;
69 X509_STORE *clientstore;
70
71 serverstore = 0;
72 clientstore = 0;
73
74 SSL_library_init();
75 ERR_load_crypto_strings();
76
77 buffer = (unsigned char *)malloc(LMS_SSL_SEEDLEN);
78 if (!buffer)
79 {
80 return(-1);
81 }
82 while (RAND_status() != 1)
83 {
84 memset(buffer, 0, LMS_SSL_SEEDLEN);
85
86 if (lms_rand_get(LMS_SSL_SEEDLEN, buffer) < 0)
87 {
88 return(-1);
89 }
90
91 RAND_seed(buffer, LMS_SSL_SEEDLEN);
92 }
93 free(buffer);
94
95 for (i = 0; i < LMS_HIGHSOCK; ++i)
96 {
97 _lms_ssl_list[i] = (SSL *)NULL;
98 }
99
100 SSL_load_error_strings();
101
102 // _lms_ssl_masterstore = _lms_ssl_loadfiles(Config->ssl_files);
103
104 /* Server CTX */
105 _lms_ssl_ctx = SSL_CTX_new(SSLv23_server_method());
106 if (!_lms_ssl_ctx)
107 {
108 char ssl_error_buf[128];
109
110 ERR_error_string_n(ERR_get_error(), ssl_error_buf, 128);
111 return(-1);
112 }
113 if (SSL_CTX_set_cipher_list(_lms_ssl_ctx, _lms_ssl_sciphers) == 0)
114 {
115 #ifndef LMS_SSLV2
116 /* If we can't use our best cipher set, try enabling some less awesome ciphers like 3DES and RC4. */
117 if (SSL_CTX_set_cipher_list(_lms_ssl_ctx, _lms_ssl_cciphers) == 0)
118 {
119 /* Try junk ciphers only as a last resort! */
120 if (SSL_CTX_set_cipher_list(_lms_ssl_ctx, _lms_ssl_jciphers) == 0)
121 {
122 return(-1);
123 }
124 else
125 {
126 }
127 }
128 #else
129 return(-1);
130 #endif /* LMS_SSLV2 */
131 }
132 #ifdef LMS_SSLV2
133 SSL_CTX_set_options(_lms_ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE|SSL_OP_SINGLE_DH_USE);
134 #else
135 SSL_CTX_set_options(_lms_ssl_ctx, SSL_OP_NO_SSLv2|SSL_OP_CIPHER_SERVER_PREFERENCE|SSL_OP_SINGLE_DH_USE);
136 #endif /* LMS_SSLV2 */
137 SSL_CTX_set_verify(_lms_ssl_ctx, SSL_VERIFY_NONE, NULL);
138 SSL_CTX_set_mode(_lms_ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
139
140 // SSL_CTX_set_cert_store(_lms_ssl_ctx, serverstore);
141 // SSL_CTX_set_ex_data(_lms_ssl_ctx, 0, );
142
143 /* Client CTX */
144 _lms_ssl_clientctx = SSL_CTX_new(SSLv23_client_method());
145 if (!_lms_ssl_clientctx)
146 {
147 char ssl_error_buf[128];
148
149 ERR_error_string_n(ERR_get_error(), ssl_error_buf, 128);
150 SSL_CTX_free(_lms_ssl_ctx);
151 return(-1);
152 }
153 if (SSL_CTX_set_cipher_list(_lms_ssl_clientctx, _lms_ssl_cciphers) == 0)
154 {
155 #ifndef LMS_SSLV2
156 /* Try junk ciphers only as a last resort! */
157 SSL_CTX_set_cipher_list(_lms_ssl_clientctx, _lms_ssl_jciphers);
158 #else
159 return(-1);
160 #endif /* LMS_SSLV2 */
161 }
162 #ifdef LMS_SSLV2
163 SSL_CTX_set_options(_lms_ssl_clientctx, SSL_OP_SINGLE_DH_USE);
164 #else
165 SSL_CTX_set_options(_lms_ssl_clientctx, SSL_OP_NO_SSLv2|SSL_OP_SINGLE_DH_USE);
166 #endif /* LMS_SSLV2 */
167 SSL_CTX_set_verify(_lms_ssl_clientctx, SSL_VERIFY_NONE, NULL);
168 SSL_CTX_set_mode(_lms_ssl_clientctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
169
170 // SSL_CTX_set_cert_store(_lms_ssl_ctx, clientstore);
171 // SSL_CTX_set_ex_data(_lms_ssl_clientctx, 0, );
172
173 return(0);
174 }
175
176 /*
177 * lms_ssl_startsock() initiates SSL on socket m
178 *
179 * m = the socket on which to begin SSL processing
180 *
181 */
lms_ssl_startsock(MSocket * m)182 int lms_ssl_startsock(MSocket *m)
183 {
184 SSL *s;
185
186 if (!m)
187 {
188 errno = EINVAL;
189 return(-1);
190 }
191 else if (m->fd < 0)
192 {
193 errno = EINVAL;
194 return(-1);
195 }
196 else if ((m->type != LMSTYPE_STREAM4) && (m->type != LMSTYPE_STREAM6) && (m->type != LMSTYPE_LOCALCLIENT))
197 {
198 errno = EINVAL;
199 return(-1);
200 }
201 else if (!(m->opts & LMSOPTION_SSL))
202 {
203 errno = ENODEV;
204 return(-1);
205 }
206
207 if (m->flags & LMSFLG_INBOUND)
208 {
209 s = SSL_new(_lms_ssl_ctx);
210 }
211 else if (m->flags & LMSFLG_OUTBOUND)
212 {
213 s = SSL_new(_lms_ssl_clientctx);
214 }
215 else
216 {
217 return(-1);
218 }
219
220 if (!s)
221 {
222 char *ssl_error_buf;
223
224 ssl_error_buf = (char *)malloc(128);
225 if (!ssl_error_buf)
226 {
227 return(-1);
228 }
229 memset(ssl_error_buf, 0, 128);
230 ERR_error_string_n(ERR_get_error(), ssl_error_buf, 128);
231 return(-1);
232 }
233
234 if (!SSL_set_fd(s, m->fd))
235 {
236 char *ssl_error_buf;
237
238 ssl_error_buf = (char *)malloc(128);
239 if (!ssl_error_buf)
240 {
241 return(-1);
242 }
243 memset(ssl_error_buf, 0, 128);
244 ERR_error_string_n(ERR_get_error(), ssl_error_buf, 128);
245 SSL_free(s);
246 return(-1);
247 }
248
249 _lms_ssl_list[m->fd] = s;
250
251 m->flags |= LMSFLG_SSL;
252
253 if (m->opts & LMSOPTION_UCREP)
254 {
255 lms_ssl_unclean(m);
256 }
257
258 m->func_w = lms_ssl_handshake;
259 m->func_r = lms_ssl_handshake;
260 m->flags |= LMSFLG_SSLHDSHK;
261 if (m->flags & LMSFLG_INBOUND)
262 {
263 SSL_set_accept_state(s);
264 }
265 else if (m->flags & LMSFLG_OUTBOUND)
266 {
267 SSL_set_connect_state(s);
268 }
269 else
270 {
271 }
272 lms_ssl_handshake(m);
273
274 return(0);
275 }
276
277 /*
278 * lms_ssl_closesock() sends the SSL shutdown string and such
279 *
280 * m = the socket
281 *
282 */
lms_ssl_closesock(MSocket * m)283 int lms_ssl_closesock(MSocket *m)
284 {
285 int sav;
286 int sdval;
287
288 if (!m)
289 {
290 errno = EINVAL;
291 return(-1);
292 }
293 else if (!(m->flags & LMSFLG_SSL))
294 {
295 return(0);
296 }
297 else if (!(m->flags & LMSFLG_SSLRDY) && !(m->flags & LMSFLG_SSLHDSHK))
298 {
299 return(0);
300 }
301 else if (!_lms_ssl_list[m->fd])
302 {
303 errno = EINVAL;
304 return(-1);
305 }
306 else if (!(m->flags & LMSFLG_CONNECTED))
307 {
308 errno = ENOTCONN;
309 return(-1);
310 }
311
312 sav = SSL_shutdown(_lms_ssl_list[m->fd]);
313 if (sav <= 0)
314 {
315 /* I don't care if this succeeded or failed, however the error queue on OpenSSL's end must be kept clear if it failed. */
316 SSL_get_error(_lms_ssl_list[m->fd], sav);
317 }
318 sdval = SSL_get_shutdown(_lms_ssl_list[m->fd]);
319 if (!(sdval & SSL_SENT_SHUTDOWN))
320 {
321 SSL_set_shutdown(_lms_ssl_list[m->fd], sdval|SSL_SENT_SHUTDOWN);
322 }
323
324 if (m->flags & LMSFLG_SSLRDY)
325 {
326 m->flags &= ~LMSFLG_SSLRDY;
327 }
328 if (m->flags & LMSFLG_SSLHDSHK)
329 {
330 m->flags &= ~LMSFLG_SSLHDSHK;
331 }
332
333 return(0);
334 }
335
336 /*
337 * lms_ssl_stopsock() ends SSL on a socket, freeing all structures and removing list entries
338 *
339 * m = the socket
340 *
341 */
lms_ssl_stopsock(MSocket * m)342 int lms_ssl_stopsock(MSocket *m)
343 {
344 if (!m)
345 {
346 errno = EINVAL;
347 return(-1);
348 }
349 else if (!(m->flags & LMSFLG_SSL))
350 {
351 return(0);
352 }
353 else if (!_lms_ssl_list[m->fd])
354 {
355 errno = EINVAL;
356 return(-1);
357 }
358
359 SSL_free(_lms_ssl_list[m->fd]);
360 _lms_ssl_list[m->fd] = (SSL *)NULL;
361 if (m->flags & LMSFLG_SSLRDY)
362 {
363 m->flags &= ~LMSFLG_SSLRDY;
364 }
365 if (m->flags & LMSFLG_SSLHDSHK)
366 {
367 m->flags &= ~LMSFLG_SSLHDSHK;
368 }
369 m->flags &= ~LMSFLG_SSL;
370
371 return(0);
372 }
373
374 /*
375 * lms_ssl_unclean() sets a socket as `unclean', meaning it will connect to an unknown (non-NGCast) remote application, and OpenSSL's
376 * broken-implementation-compatability bug options should be set.
377 *
378 * m = the socket on which to set the unclean flag
379 *
380 */
lms_ssl_unclean(MSocket * m)381 int lms_ssl_unclean(MSocket *m)
382 {
383 long curopts;
384
385 if (!m)
386 {
387 errno = EINVAL;
388 return(-1);
389 }
390
391 m->opts |= LMSOPTION_UCREP;
392
393 if (!(m->flags & LMSFLG_SSL))
394 {
395 /*
396 * This function can be called to set the flag before the socket is initialized,
397 * and lms_ssl_startsock() will call this function again to actually set the
398 * OpenSSL options on the (SSL *) pointer for the socket once it is initialized
399 * if that flag is set.
400 */
401 return(0);
402 }
403 else if (!_lms_ssl_list[m->fd])
404 {
405 errno = EINVAL;
406 return(-1);
407 }
408
409 SSL_set_ssl_method(_lms_ssl_list[m->fd], SSLv23_method());
410 curopts = SSL_get_options(_lms_ssl_list[m->fd]);
411 #ifndef LMS_SSLV2
412 if (!(curopts & SSL_OP_NO_SSLv2))
413 {
414 curopts |= SSL_OP_NO_SSLv2;
415 }
416 #endif
417 if ((m->flags & LMSFLG_OUTBOUND) && (curopts & SSL_OP_CIPHER_SERVER_PREFERENCE))
418 {
419 curopts &= ~SSL_OP_CIPHER_SERVER_PREFERENCE;
420 }
421 /* - SSL_OP_TLS_ROLLBACK_BUG ; Note that we don't set the MSIE/Microsoft related compatability bug-workarounds here. ;) */
422 SSL_set_options(_lms_ssl_list[m->fd], curopts|SSL_OP_NETSCAPE_CHALLENGE_BUG|SSL_OP_TLS_D5_BUG|SSL_OP_TLS_BLOCK_PADDING_BUG|SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
423
424 return(1);
425 }
426
427 /*
428 * lms_ssl_read() is the SSL connection input processor
429 *
430 * m = the socket on which to receive data
431 *
432 */
lms_ssl_read(MSocket * m)433 int lms_ssl_read(MSocket *m)
434 {
435 unsigned char *c;
436 int sav;
437 int sav_x;
438 size_t bufsz;
439 unsigned char callpfunc;
440
441 if (!m)
442 {
443 errno = EINVAL;
444 return(-1);
445 }
446 else if (!(m->flags & LMSFLG_CONNECTED))
447 {
448 errno = ENOTCONN;
449 return(-1);
450 }
451 else if (!(m->flags & LMSFLG_SSL))
452 {
453 errno = EINVAL;
454 return(-1);
455 }
456 else if ((m->type != LMSTYPE_STREAM4) && (m->type != LMSTYPE_STREAM6))
457 {
458 errno = EINVAL;
459 return(-1);
460 }
461 else if (!_lms_ssl_list[m->fd])
462 {
463 errno = EINVAL;
464 return(-1);
465 }
466
467 callpfunc = 0;
468 bufsz = 1024;
469
470 c = (unsigned char *)malloc(bufsz);
471 if (!c)
472 {
473 return(-1);
474 }
475 memset(c, 0, bufsz);
476
477 if ((m->recvQ_sz > 0) && m->recvQ)
478 {
479 if (m->recvQ_sz < (m->recvQ_len + bufsz))
480 {
481 #ifdef HAVE_REALLOCF
482 m->recvQ = (unsigned char *)reallocf(m->recvQ, (m->recvQ_sz + bufsz));
483 #else
484 m->recvQ = (unsigned char *)realloc(m->recvQ, (m->recvQ_sz + bufsz));
485 #endif /* HAVE_REALLOCF */
486 if (!m->recvQ)
487 {
488 free(c);
489 return(-1);
490 }
491 m->recvQ_sz += bufsz;
492 }
493 }
494 else
495 {
496 m->recvQ = (unsigned char *)malloc(bufsz);
497 if (!m->recvQ)
498 {
499 free(c);
500 return(-1);
501 }
502 m->recvQ_sz = bufsz;
503 }
504
505 while (1)
506 {
507 sav = SSL_read(_lms_ssl_list[m->fd], c, bufsz);
508
509 sav_x = SSL_get_shutdown(_lms_ssl_list[m->fd]);
510 if (sav_x & SSL_RECEIVED_SHUTDOWN)
511 {
512 lms_ssl_closesock(m);
513 m->func_e(m);
514 return(0);
515 }
516
517 if (sav <= 0)
518 {
519 sav_x = SSL_get_error(_lms_ssl_list[m->fd], sav);
520 if ((sav_x == SSL_ERROR_WANT_READ) || (sav_x == SSL_ERROR_WANT_WRITE))
521 {
522 break;
523 }
524 else if (sav_x == SSL_ERROR_ZERO_RETURN)
525 {
526 m->func_e(m);
527 return(0);
528 }
529 else
530 {
531 if (sav_x == SSL_ERROR_SSL)
532 {
533 char *ssl_error_buf;
534
535 ssl_error_buf = (char *)malloc(128);
536 if (!ssl_error_buf)
537 {
538 return(-1);
539 }
540 memset(ssl_error_buf, 0, 128);
541 ERR_error_string_n(ERR_get_error(), ssl_error_buf, 128);
542 free(ssl_error_buf);
543 }
544
545 m->func_e(m);
546 return(0);
547 }
548
549 break;
550 }
551 else
552 {
553 lms_str_ocopy(c, m->recvQ, sav, m->recvQ_len);
554 m->recvQ_len += sav;
555 memset(c, 0, bufsz);
556 callpfunc = 1;
557 m->bytes_r += sav;
558 }
559
560 if (m->recvQ_sz < (m->recvQ_len + bufsz))
561 {
562 #ifdef HAVE_REALLOCF
563 m->recvQ = (unsigned char *)reallocf(m->recvQ, (m->recvQ_sz + bufsz));
564 #else
565 m->recvQ = (unsigned char *)realloc(m->recvQ, (m->recvQ_sz + bufsz));
566 #endif /* HAVE_REALLOCF */
567 if (!m->recvQ)
568 {
569 free(c);
570 return(-1);
571 }
572 m->recvQ_sz += bufsz;
573 }
574 }
575
576 m->last_recv = time(NULL);
577 if (callpfunc)
578 {
579 m->func_p(m);
580 }
581
582 free(c);
583 return(0);
584 }
585
586 /*
587 * lms_ssl_handshake() is an input processor that deals with the handshake phase
588 *
589 * m = the socket on which to receive data
590 *
591 */
lms_ssl_handshake(MSocket * m)592 int lms_ssl_handshake(MSocket *m)
593 {
594 int sav;
595 int sav_x;
596
597 if (!m)
598 {
599 errno = EINVAL;
600 return(-1);
601 }
602 else if (!_lms_ssl_list[m->fd])
603 {
604 errno = EINVAL;
605 return(-1);
606 }
607
608 sav = SSL_do_handshake(_lms_ssl_list[m->fd]);
609
610 if (sav <= 0)
611 {
612 sav_x = SSL_get_error(_lms_ssl_list[m->fd], sav);
613 if ((sav_x == SSL_ERROR_WANT_READ) || (sav_x == SSL_ERROR_WANT_WRITE))
614 {
615 return(0);
616 }
617 else
618 {
619 if (sav_x == SSL_ERROR_SSL)
620 {
621 char *ssl_error_buf;
622
623 ssl_error_buf = (char *)malloc(128);
624 if (!ssl_error_buf)
625 {
626 return(-1);
627 }
628 memset(ssl_error_buf, 0, 128);
629 ERR_error_string_n(ERR_get_error(), ssl_error_buf, 128);
630 free(ssl_error_buf);
631 }
632
633 lms_socket_destroy(m);
634 return(0);
635 }
636 }
637 else
638 {
639 /* Handshake completed successfully and we can move on */
640 m->flags &= ~LMSFLG_SSLHDSHK;
641 m->flags |= LMSFLG_SSLRDY;
642 m->func_w = lms_ssl_flushq;
643 m->func_r = lms_ssl_read;
644 m->last_recv = time(NULL);
645 }
646
647 return(0);
648 }
649
650 /*
651 * lms_ssl_flushq() flushes the sendQ of an SSL socket
652 *
653 * m = the socket to flush the sendQ of
654 *
655 */
lms_ssl_flushq(MSocket * m)656 int lms_ssl_flushq(MSocket *m)
657 {
658 ssize_t rv;
659 ssize_t sl;
660 unsigned char *tmpptr;
661 size_t tmplen;
662 int sav_x;
663
664 if (!m)
665 {
666 errno = EINVAL;
667 return(-1);
668 }
669 else if (!(m->flags & LMSFLG_SSL))
670 {
671 errno = EINVAL;
672 return(-1);
673 }
674 else if (!_lms_ssl_list[m->fd])
675 {
676 errno = EINVAL;
677 return(-1);
678 }
679 else if ((m->type != LMSTYPE_STREAM4) && (m->type != LMSTYPE_STREAM6) && (m->type != LMSTYPE_LOCALCLIENT))
680 {
681 errno = EINVAL;
682 return(-1);
683 }
684 else if (!(m->flags & LMSFLG_CONNECTED))
685 {
686 errno = ENOTCONN;
687 return(-1);
688 }
689
690 if ((m->sendQ_len == 0) || (m->sendQ_sz == 0))
691 {
692 return(0);
693 }
694 if (!m->sendQ)
695 {
696 #ifdef EDOOFUS
697 errno = EDOOFUS;
698 #else
699 errno = EINVAL;
700 #endif
701 return(-1);
702 }
703
704 sl = 0;
705 tmpptr = m->sendQ;
706 tmplen = m->sendQ_len;
707 while (tmplen > 0)
708 {
709 rv = SSL_write(_lms_ssl_list[m->fd], tmpptr, tmplen);
710 if (rv <= 0)
711 {
712 sav_x = SSL_get_error(_lms_ssl_list[m->fd], rv);
713 if ((sav_x == SSL_ERROR_WANT_READ) || (sav_x == SSL_ERROR_WANT_WRITE))
714 {
715 if (sl > 0)
716 {
717 lms_socket_clearsq(m, sl);
718 m->sendQ_len -= sl;
719 m->last_send = time(NULL);
720 }
721 return((int)sl);
722 }
723 else
724 {
725 if (sav_x == SSL_ERROR_SSL)
726 {
727 char *ssl_error_buf;
728
729 ssl_error_buf = (char *)malloc(128);
730 if (!ssl_error_buf)
731 {
732 return(-1);
733 }
734 memset(ssl_error_buf, 0, 128);
735 ERR_error_string_n(ERR_get_error(), ssl_error_buf, 128);
736 free(ssl_error_buf);
737 }
738
739 if (sl > 0)
740 {
741 lms_socket_clearsq(m, sl);
742 m->sendQ_len -= sl;
743 m->last_send = time(NULL);
744 }
745 return((int)sl);
746 }
747 }
748 else
749 {
750 sl += rv;
751 tmplen -= rv;
752 if (tmplen > 0)
753 {
754 tmpptr += rv;
755 }
756 m->bytes_s += rv;
757 }
758 }
759
760 m->sendQ_len = 0;
761 free(m->sendQ);
762 m->sendQ = (unsigned char *)NULL;
763 m->sendQ_sz = 0;
764
765 m->last_send = time(NULL);
766
767 return((int)sl);
768 }
769
770 /*
771 * lms_ssl_getclientinfo() returns a pointer to a string containing a bunch of info about the client's SSL connectivity
772 * + Allocates memory which must be later free()'d by the caller
773 *
774 * m = the socket about which to get SSL statistics and information
775 *
776 */
lms_ssl_getclientinfo(MSocket * m)777 char *lms_ssl_getclientinfo(MSocket *m)
778 {
779 char *infobuf;
780 SSL_CIPHER *clientcipher;
781 int useless_bits;
782
783 if (!m)
784 {
785 errno = EINVAL;
786 return((char *)NULL);
787 }
788 else if (!(m->flags & LMSFLG_SSL))
789 {
790 errno = EINVAL;
791 return((char *)NULL);
792 }
793 else if (!_lms_ssl_list[m->fd])
794 {
795 errno = EINVAL;
796 return((char *)NULL);
797 }
798
799 /* 48 bytes for this is a wee bit arbitrary, but seems like a good choice, the string is unlikely to be truncated, unless someone comes up with a cipher and gives it a really long name..... */
800 infobuf = (char *)NULL;
801 #ifdef LMS_HARDCORE_ALLOC
802 while (!infobuf)
803 {
804 infobuf = (char *)malloc(48);
805 }
806 #else
807 infobuf = (char *)malloc(48);
808 if (!infobuf)
809 {
810 return((char *)NULL);
811 }
812 #endif
813 memset(infobuf, 0, 48);
814
815 clientcipher = SSL_get_current_cipher(_lms_ssl_list[m->fd]);
816 snprintf(infobuf, 48, "%s (%s/%i)", SSL_CIPHER_get_version(clientcipher), SSL_CIPHER_get_name(clientcipher), SSL_CIPHER_get_bits(clientcipher, &useless_bits));
817
818 return(infobuf);
819 }
820
821 /*
822 * _lms_ssl_loadfiles() loads a public/private keypair
823 *
824 * ca = the CA root cert
825 * path = the path (will be appended with '.pub' for the public key, '.priv' for the private key, and '.crt' for the X509 certificate)
826 *
827 */
_lms_ssl_loadfiles(X509 * ca,const char * path)828 lms_ssl_store *_lms_ssl_loadfiles(X509 *ca, const char *path)
829 {
830 char *pubpath;
831 char *privpath;
832 lms_ssl_store *ks;
833
834 pubpath = (char *)malloc(MAXPATHLEN + 1);
835 if (!pubpath)
836 {
837 return((lms_ssl_store *)NULL);
838 }
839 memset(pubpath, 0, (MAXPATHLEN + 1));
840 snprintf(pubpath, MAXPATHLEN, "%s.pub", path);
841 privpath = (char *)malloc(MAXPATHLEN + 1);
842 if (!privpath)
843 {
844 free(pubpath);
845 return((lms_ssl_store *)NULL);
846 }
847 memset(privpath, 0, (MAXPATHLEN + 1));
848 snprintf(privpath, MAXPATHLEN, "%s.priv", path);
849
850 ks = (lms_ssl_store *)NULL;
851 #ifdef LMS_HARDCORE_ALLOC
852 while (!ks)
853 {
854 ks = (lms_ssl_store *)malloc(sizeof(lms_ssl_store));
855 }
856 #else
857 ks = (lms_ssl_store *)malloc(sizeof(lms_ssl_store));
858 if (!ks)
859 {
860 free(pubpath);
861 free(privpath);
862 return((lms_ssl_store *)NULL);
863 }
864 #endif
865 memset(ks, 0, sizeof(lms_ssl_store));
866
867 /*
868 * ca = CA cert
869 * crt = my cert
870 * privkey = RSA private key
871 * pubkey = RSA public key
872 * dhp = DH params
873 */
874
875 #if OPENSSL_VERSION_NUMBER >= 0x10100000
876 ks->ca = X509_dup(ca);
877 #else
878 memcpy(ks->ca, ca, sizeof(X509));
879 #endif
880 ks->crt = X509_new();
881 ks->privkey = RSA_new();
882 ks->pubkey = RSA_new();
883 ks->dhp = DH_new();
884
885 return(ks);
886 }
887
888 /*
889 * _lms_ssl_freestore() frees a key/cert store
890 *
891 * s = the lms_ssl_store object to free
892 *
893 */
_lms_ssl_freestore(lms_ssl_store * s)894 int _lms_ssl_freestore(lms_ssl_store *s)
895 {
896 if (!s)
897 {
898 errno = EINVAL;
899 return(-1);
900 }
901
902 if (s->crt)
903 {
904 X509_free(s->crt);
905 }
906 if (s->ca)
907 {
908 X509_free(s->ca);
909 }
910
911 free(s);
912
913 return(0);
914 }
915
916 /*
917 * _lms_ssl_getbiofd() returns the fd of a BIO object
918 *
919 * b = the OpenSSL BIO object to return the fd of
920 *
921 */
_lms_ssl_getbiofd(BIO * b)922 int _lms_ssl_getbiofd(BIO *b)
923 {
924 int fd;
925
926 if (!b)
927 {
928 errno = EINVAL;
929 return(-1);
930 }
931
932 fd = (int)BIO_ctrl(b, BIO_C_GET_FD, (long)0, (void *)NULL);
933
934 return(fd);
935 }
936