]> diplodocus.org Git - nmh/blob - sbr/netsec.c
mhlsbr.c: Don't strchr(3) non-string NUL-less buffer.
[nmh] / sbr / netsec.c
1 /* netsec.c -- Network security routines for handling protocols that
2 * require SASL and/or TLS.
3 *
4 * This code is Copyright (c) 2016, by the authors of nmh. See the
5 * COPYRIGHT file in the root directory of the nmh distribution for
6 * complete copyright information.
7 */
8
9 #include <h/mh.h>
10 #include <h/utils.h>
11 #include <h/netsec.h>
12 #include <h/oauth.h>
13 #include <stdarg.h>
14 #include <sys/select.h>
15 #include "base64.h"
16
17 #ifdef CYRUS_SASL
18 #include <sasl/sasl.h>
19 #include <sasl/saslutil.h>
20 # if SASL_VERSION_FULL < 0x020125
21 /* Cyrus SASL 2.1.25 introduced the sasl_callback_ft prototype,
22 which has an explicit void parameter list, according to best
23 practice. So we need to cast to avoid compile warnings.
24 Provide this prototype for earlier versions. */
25 typedef int (*sasl_callback_ft)();
26 # endif /* SASL_VERSION_FULL < 0x020125 */
27
28 static int netsec_get_user(void *context, int id, const char **result,
29 unsigned int *len);
30 static int netsec_get_password(sasl_conn_t *conn, void *context, int id,
31 sasl_secret_t **psecret);
32
33 static int sasl_initialized = 0;
34
35 #define SASL_MAXRECVBUF 65536
36 #endif /* CYRUS_SASL */
37
38 #ifdef TLS_SUPPORT
39 #include <openssl/ssl.h>
40 #include <openssl/err.h>
41
42 static int tls_initialized = 0;
43 static SSL_CTX *sslctx = NULL; /* SSL Context */
44
45 #endif /* TLS_SUPPORT */
46
47 /* I'm going to hardcode this for now; maybe make it adjustable later? */
48 #define NETSEC_BUFSIZE 65536
49
50 /*
51 * Our context structure, which holds all of the relevant information
52 * about a connection.
53 */
54
55 struct _netsec_context {
56 int ns_readfd; /* Read descriptor for network connection */
57 int ns_writefd; /* Write descriptor for network connection */
58 int ns_noclose; /* Do not close file descriptors if set */
59 int ns_snoop; /* If true, display network data */
60 int ns_snoop_noend; /* If true, didn't get a CR/LF on last line */
61 netsec_snoop_callback *ns_snoop_cb; /* Snoop output callback */
62 void *ns_snoop_context; /* Context data for snoop function */
63 int ns_timeout; /* Network read timeout, in seconds */
64 char *ns_userid; /* Userid for authentication */
65 char *ns_hostname; /* Hostname we've connected to */
66 unsigned char *ns_inbuffer; /* Our read input buffer */
67 unsigned char *ns_inptr; /* Our read buffer input pointer */
68 unsigned int ns_inbuflen; /* Length of data in input buffer */
69 unsigned int ns_inbufsize; /* Size of input buffer */
70 unsigned char *ns_outbuffer;/* Output buffer */
71 unsigned char *ns_outptr; /* Output buffer pointer */
72 unsigned int ns_outbuflen; /* Output buffer data length */
73 unsigned int ns_outbufsize; /* Output buffer size */
74 char *sasl_mech; /* User-requested mechanism */
75 char *sasl_chosen_mech; /* Mechanism chosen by SASL */
76 netsec_sasl_callback sasl_proto_cb; /* SASL callback we use */
77 #ifdef OAUTH_SUPPORT
78 char *oauth_service; /* OAuth2 service name */
79 #endif /* OAUTH_SUPPORT */
80 #ifdef CYRUS_SASL
81 sasl_conn_t *sasl_conn; /* SASL connection context */
82 sasl_ssf_t sasl_ssf; /* SASL Security Strength Factor */
83 sasl_callback_t *sasl_cbs; /* Callbacks used by SASL */
84 nmh_creds_t sasl_creds; /* Credentials (username/password) */
85 sasl_secret_t *sasl_secret; /* SASL password structure */
86 int sasl_seclayer; /* If true, SASL security layer is enabled */
87 char *sasl_tmpbuf; /* Temporary read buffer for decodes */
88 size_t sasl_maxbufsize; /* Maximum negotiated SASL buffer size */
89 #endif /* CYRUS_SASL */
90 #ifdef TLS_SUPPORT
91 BIO *ssl_io; /* BIO used for connection I/O */
92 int tls_active; /* If true, TLS is running */
93 #endif /* TLS_SUPPORT */
94 };
95
96 /*
97 * Function to read data from the actual network socket
98 */
99
100 static int netsec_fillread(netsec_context *ns_context, char **errstr);
101
102 /*
103 * Code to check the ASCII content of a byte array.
104 */
105
106 static int checkascii(const unsigned char *byte, size_t len);
107
108 /*
109 * How this code works, in general.
110 *
111 * _If_ we are using no encryption then we buffer the network data
112 * through ns_inbuffer and ns_outbuffer. That should be relatively
113 * self-explanatory.
114 *
115 * If we use encryption, then ns_inbuffer and ns_outbuffer contain the
116 * cleartext data. When it comes time to send the encrypted data on the
117 * (either from a flush or the buffer is full) we either use BIO_write()
118 * for TLS or sasl_encode() (followed by a write() for Cyrus-SASL. For
119 * reads we either use BIO_read() (TLS) or do a network read into a
120 * temporary buffer and use sasl_decode() (Cyrus-SASL). Note that if
121 * negotiate TLS then we disable SASL encryption.
122 *
123 * We used to use a buffering BIO for the reads/writes for TLS, but it
124 * ended up being complicated to special-case the buffering for everything
125 * except TLS, so the buffering is now unified, no matter which encryption
126 * method is being used (even none).
127 *
128 * For SASL authentication, we make use of (for now) the Cyrus-SASL
129 * library. For some mechanisms, we implement those mechanisms directly
130 * since the Cyrus SASL library doesn't support them (like OAuth).
131 */
132
133 /*
134 * Allocate and initialize our security context
135 */
136
137 netsec_context *
138 netsec_init(void)
139 {
140 netsec_context *nsc;
141
142 NEW(nsc);
143 nsc->ns_readfd = -1;
144 nsc->ns_writefd = -1;
145 nsc->ns_noclose = 0;
146 nsc->ns_snoop = 0;
147 nsc->ns_snoop_noend = 0;
148 nsc->ns_snoop_cb = NULL;
149 nsc->ns_snoop_context = NULL;
150 nsc->ns_userid = NULL;
151 nsc->ns_hostname = NULL;
152 nsc->ns_timeout = 60; /* Our default */
153 nsc->ns_inbufsize = NETSEC_BUFSIZE;
154 nsc->ns_inbuffer = mh_xmalloc(nsc->ns_inbufsize);
155 nsc->ns_inptr = nsc->ns_inbuffer;
156 nsc->ns_inbuflen = 0;
157 nsc->ns_outbufsize = NETSEC_BUFSIZE;
158 nsc->ns_outbuffer = mh_xmalloc(nsc->ns_outbufsize);
159 nsc->ns_outptr = nsc->ns_outbuffer;
160 nsc->ns_outbuflen = 0;
161 nsc->sasl_mech = NULL;
162 nsc->sasl_chosen_mech = NULL;
163 nsc->sasl_proto_cb = NULL;
164 #ifdef OAUTH_SUPPORT
165 nsc->oauth_service = NULL;
166 #endif /* OAUTH_SUPPORT */
167 #ifdef CYRUS_SASL
168 nsc->sasl_conn = NULL;
169 nsc->sasl_cbs = NULL;
170 nsc->sasl_creds = NULL;
171 nsc->sasl_secret = NULL;
172 nsc->sasl_ssf = 0;
173 nsc->sasl_seclayer = 0;
174 nsc->sasl_tmpbuf = NULL;
175 nsc->sasl_maxbufsize = 0;
176 #endif /* CYRUS_SASL */
177 #ifdef TLS_SUPPORT
178 nsc->ssl_io = NULL;
179 nsc->tls_active = 0;
180 #endif /* TLS_SUPPORT */
181 return nsc;
182 }
183
184 /*
185 * Shutdown the connection completely and free all resources.
186 */
187
188 void
189 netsec_shutdown(netsec_context *nsc)
190 {
191 free(nsc->ns_userid);
192 free(nsc->ns_hostname);
193 free(nsc->ns_inbuffer);
194 free(nsc->ns_outbuffer);
195 free(nsc->sasl_mech);
196 free(nsc->sasl_chosen_mech);
197 #ifdef OAUTH_SERVICE
198 free(nsc->oauth_service);
199 #endif /* OAUTH_SERVICE */
200 #ifdef CYRUS_SASL
201 if (nsc->sasl_conn)
202 sasl_dispose(&nsc->sasl_conn);
203 free(nsc->sasl_cbs);
204 if (nsc->sasl_creds)
205 nmh_credentials_free(nsc->sasl_creds);
206 if (nsc->sasl_secret) {
207 if (nsc->sasl_secret->len > 0) {
208 memset(nsc->sasl_secret->data, 0, nsc->sasl_secret->len);
209 }
210 free(nsc->sasl_secret);
211 }
212 free(nsc->sasl_tmpbuf);
213 #endif /* CYRUS_SASL */
214 #ifdef TLS_SUPPORT
215 if (nsc->ssl_io)
216 /*
217 * I checked; BIO_free_all() will cause SSL_shutdown to be called
218 * on the SSL object in the chain.
219 */
220 BIO_free_all(nsc->ssl_io);
221 #endif /* TLS_SUPPORT */
222
223 if (! nsc->ns_noclose) {
224 if (nsc->ns_readfd != -1)
225 close(nsc->ns_readfd);
226 if (nsc->ns_writefd != -1 && nsc->ns_writefd != nsc->ns_readfd)
227 close(nsc->ns_writefd);
228 }
229
230 free(nsc);
231 }
232
233 /*
234 * Set the file descriptor for our context
235 */
236
237 void
238 netsec_set_fd(netsec_context *nsc, int readfd, int writefd)
239 {
240 nsc->ns_readfd = readfd;
241 nsc->ns_writefd = writefd;
242 }
243
244 /*
245 * Set the userid used for authentication for this context
246 */
247
248 void
249 netsec_set_userid(netsec_context *nsc, const char *userid)
250 {
251 nsc->ns_userid = getcpy(userid);
252 }
253
254 /*
255 * Set the hostname of the remote host we're connecting to.
256 */
257
258 void
259 netsec_set_hostname(netsec_context *nsc, const char *hostname)
260 {
261 nsc->ns_hostname = mh_xstrdup(hostname);
262 }
263
264 /*
265 * Get the snoop flag for this connection
266 */
267
268 int
269 netsec_get_snoop(netsec_context *nsc)
270 {
271 return nsc->ns_snoop;
272 }
273
274 /*
275 * Set the snoop flag for this connection
276 */
277
278 void
279 netsec_set_snoop(netsec_context *nsc, int snoop)
280 {
281 nsc->ns_snoop = snoop;
282 }
283
284 /*
285 * Set the snoop callback for this connection.
286 */
287
288 void netsec_set_snoop_callback(netsec_context *nsc,
289 netsec_snoop_callback callback, void *context)
290 {
291 nsc->ns_snoop_cb = callback;
292 nsc->ns_snoop_context = context;
293 }
294
295 /*
296 * A base64-decoding snoop callback
297 */
298
299 void
300 netsec_b64_snoop_decoder(netsec_context *nsc, const char *string, size_t len,
301 void *context)
302 {
303 unsigned char *decoded;
304 size_t decodedlen;
305 int offset;
306 NMH_UNUSED(nsc);
307
308 offset = context ? *((int *) context) : 0;
309
310 if (offset > 0) {
311 /*
312 * Output non-base64 data first.
313 */
314 fprintf(stderr, "%.*s", offset, string);
315 string += offset;
316 len -= offset;
317 }
318
319 if (decodeBase64(string, &decoded, &decodedlen, 1, NULL) == OK) {
320 /*
321 * Some mechanisms produce large binary tokens, which aren't really
322 * readable. So let's do a simple heuristic. If the token is greater
323 * than 100 characters _and_ the first 100 bytes are more than 50%
324 * non-ASCII, then don't print the decoded buffer, just the
325 * base64 text.
326 */
327 if (decodedlen > 100 && !checkascii(decoded, 100)) {
328 fprintf(stderr, "%.*s\n", (int) len, string);
329 } else {
330 char *hexified;
331 hexify(decoded, decodedlen, &hexified);
332 fprintf(stderr, "b64<%s>\n", hexified);
333 free(hexified);
334 }
335 free(decoded);
336 } else {
337 fprintf(stderr, "%.*s\n", (int) len, string);
338 }
339 }
340
341 /*
342 * If the ASCII content is > 50%, return 1
343 */
344
345 static int
346 checkascii(const unsigned char *bytes, size_t len)
347 {
348 size_t count = 0, half = len / 2;
349
350 while (len-- > 0) {
351 if (isascii(*bytes) && isprint(*bytes) && ++count > half)
352 return 1;
353 bytes++;
354 /* No chance by this point */
355 if (count + len < half)
356 return 0;
357 }
358
359 return 0;
360 }
361
362 /*
363 * Set the read timeout for this connection
364 */
365
366 void
367 netsec_set_timeout(netsec_context *nsc, int timeout)
368 {
369 nsc->ns_timeout = timeout;
370 }
371
372 /*
373 * Read data from the network. Basically, return anything in our buffer,
374 * otherwise fill from the network.
375 */
376
377 ssize_t
378 netsec_read(netsec_context *nsc, void *buffer, size_t size, char **errstr)
379 {
380 int retlen;
381
382 /*
383 * If our buffer is empty, then we should fill it now
384 */
385
386 if (nsc->ns_inbuflen == 0) {
387 if (netsec_fillread(nsc, errstr) != OK)
388 return NOTOK;
389 }
390
391 /*
392 * netsec_fillread only returns if the buffer is full, so we can
393 * assume here that this has something in it.
394 */
395
396 retlen = min(size, nsc->ns_inbuflen);
397
398 memcpy(buffer, nsc->ns_inptr, retlen);
399
400 if (retlen == (int) nsc->ns_inbuflen) {
401 /*
402 * We've emptied our buffer, so reset everything.
403 */
404 nsc->ns_inptr = nsc->ns_inbuffer;
405 nsc->ns_inbuflen = 0;
406 } else {
407 nsc->ns_inptr += size;
408 nsc->ns_inbuflen -= size;
409 }
410
411 return OK;
412 }
413
414 /*
415 * Get a "line" (CR/LF) terminated from the network.
416 *
417 * Okay, we play some games here, so pay attention:
418 *
419 * - Unlike every other function, we return a pointer to the
420 * existing buffer. This pointer is valid until you call another
421 * read function again.
422 * - We NUL-terminate the buffer right at the end, before the CR-LF terminator.
423 * - Technically we look for a LF; if we find a CR right before it, then
424 * we back up one.
425 * - If your data may contain embedded NULs, this won't work. You should
426 * be using netsec_read() in that case.
427 */
428
429 char *
430 netsec_readline(netsec_context *nsc, size_t *len, char **errstr)
431 {
432 unsigned char *ptr = nsc->ns_inptr;
433 size_t count = 0, offset;
434
435 retry:
436 /*
437 * Search through our existing buffer for a LF
438 */
439
440 while (count < nsc->ns_inbuflen) {
441 count++;
442 if (*ptr++ == '\n') {
443 char *sptr = (char *) nsc->ns_inptr;
444 if (count > 1 && *(ptr - 2) == '\r')
445 ptr--;
446 *--ptr = '\0';
447 if (len)
448 *len = ptr - nsc->ns_inptr;
449 nsc->ns_inptr += count;
450 nsc->ns_inbuflen -= count;
451 if (nsc->ns_snoop) {
452 #ifdef CYRUS_SASL
453 if (nsc->sasl_seclayer)
454 fprintf(stderr, "(sasl-decrypted) ");
455 #endif /* CYRUS_SASL */
456 #ifdef TLS_SUPPORT
457 if (nsc->tls_active)
458 fprintf(stderr, "(tls-decrypted) ");
459 #endif /* TLS_SUPPORT */
460 fprintf(stderr, "<= ");
461 if (nsc->ns_snoop_cb)
462 nsc->ns_snoop_cb(nsc, sptr, strlen(sptr),
463 nsc->ns_snoop_context);
464 else {
465 fputs(sptr, stderr);
466 putc('\n', stderr);
467 }
468 }
469 return sptr;
470 }
471 }
472
473 /*
474 * Hm, we didn't find a \n. If we've already searched half of the input
475 * buffer, return an error.
476 */
477
478 if (count >= nsc->ns_inbufsize / 2) {
479 netsec_err(errstr, "Unable to find a line terminator after %zu bytes",
480 count);
481 return NULL;
482 }
483
484 /*
485 * Okay, get some more network data. This may move inptr, so regenerate
486 * our ptr value;
487 */
488
489 offset = ptr - nsc->ns_inptr;
490
491 if (netsec_fillread(nsc, errstr) != OK)
492 return NULL;
493
494 ptr = nsc->ns_inptr + offset;
495
496 goto retry;
497
498 return NULL; /* Should never reach this */
499 }
500
501 /*
502 * Fill our read buffer with some data from the network.
503 */
504
505 static int
506 netsec_fillread(netsec_context *nsc, char **errstr)
507 {
508 unsigned char *end;
509 char *readbuf;
510 size_t readbufsize, remaining, startoffset;
511 int rc;
512
513 /*
514 * If inbuflen is zero, that means the buffer has been emptied
515 * completely. In that case move inptr back to the start.
516 */
517
518 if (nsc->ns_inbuflen == 0) {
519 nsc->ns_inptr = nsc->ns_inbuffer;
520 }
521
522 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
523 retry:
524 #endif /* CYRUS_SASL || TLS_SUPPORT */
525 /*
526 * If we are using TLS and there's anything pending, then skip the
527 * select call
528 */
529 #ifdef TLS_SUPPORT
530 if (!nsc->tls_active || BIO_pending(nsc->ssl_io) == 0)
531 #endif /* TLS_SUPPORT */
532 {
533 struct timeval tv;
534 fd_set rfds;
535
536 FD_ZERO(&rfds);
537 FD_SET(nsc->ns_readfd, &rfds);
538
539 tv.tv_sec = nsc->ns_timeout;
540 tv.tv_usec = 0;
541
542 rc = select(nsc->ns_readfd + 1, &rfds, NULL, NULL, &tv);
543
544 if (rc == -1) {
545 netsec_err(errstr, "select() while reading failed: %s",
546 strerror(errno));
547 return NOTOK;
548 }
549
550 if (rc == 0) {
551 netsec_err(errstr, "read() timed out after %d seconds",
552 nsc->ns_timeout);
553 return NOTOK;
554 }
555
556 /*
557 * At this point, we know that rc is 1, so there's not even any
558 * point to check to see if our descriptor is set in rfds.
559 */
560 }
561
562 /*
563 * Some explanation:
564 *
565 * startoffset is the offset from the beginning of the input
566 * buffer to data that is in our input buffer, but has not yet
567 * been consumed. This can be non-zero if functions like
568 * netsec_readline() leave leftover data.
569 *
570 * remaining is the remaining amount of unconsumed data in the input
571 * buffer.
572 *
573 * end is a pointer to the end of the valid data + 1; it's where
574 * the next read should go.
575 */
576
577 startoffset = nsc->ns_inptr - nsc->ns_inbuffer;
578 remaining = nsc->ns_inbufsize - (startoffset + nsc->ns_inbuflen);
579 end = nsc->ns_inptr + nsc->ns_inbuflen;
580
581 /*
582 * If we're past the halfway point in our read buffers, shuffle everything
583 * back to the beginning.
584 */
585
586 if (startoffset > nsc->ns_inbufsize / 2) {
587 memmove(nsc->ns_inbuffer, nsc->ns_inptr, nsc->ns_inbuflen);
588 nsc->ns_inptr = nsc->ns_inbuffer;
589 startoffset = 0;
590 remaining = nsc->ns_inbufsize - nsc->ns_inbuflen;
591 end = nsc->ns_inptr + nsc->ns_inbuflen;
592 }
593
594 /*
595 * If we are using TLS, then just read via the BIO. But we still
596 * use our local buffer.
597 */
598 #ifdef TLS_SUPPORT
599 if (nsc->tls_active) {
600 rc = BIO_read(nsc->ssl_io, end, remaining);
601 if (rc == 0) {
602 SSL *ssl;
603 int errcode;
604
605 /*
606 * Check to see if we're supposed to retry; if so,
607 * then go back and read again.
608 */
609
610 if (BIO_should_retry(nsc->ssl_io))
611 goto retry;
612
613 /*
614 * Okay, fine. Get the real error out of the SSL context.
615 */
616
617 if (BIO_get_ssl(nsc->ssl_io, &ssl) < 1) {
618 netsec_err(errstr, "SSL_read() returned 0, but cannot "
619 "retrieve SSL context");
620 return NOTOK;
621 }
622
623 errcode = SSL_get_error(ssl, rc);
624 if (errcode == SSL_ERROR_ZERO_RETURN) {
625 netsec_err(errstr, "TLS peer closed remote connection");
626 } else {
627 netsec_err(errstr, "TLS network read failed: %s",
628 ERR_error_string(ERR_peek_last_error(), NULL));
629 }
630 if (nsc->ns_snoop)
631 ERR_print_errors_fp(stderr);
632 return NOTOK;
633 }
634 if (rc < 0) {
635 /* Definitely an error */
636 netsec_err(errstr, "Read on TLS connection failed: %s",
637 ERR_error_string(ERR_get_error(), NULL));
638 return NOTOK;
639 }
640
641 nsc->ns_inbuflen += rc;
642
643 return OK;
644 }
645 #endif /* TLS_SUPPORT */
646
647 /*
648 * Okay, time to read some data. Either we're just doing it straight
649 * or we're passing it through sasl_decode() first.
650 */
651
652 #ifdef CYRUS_SASL
653 if (nsc->sasl_seclayer) {
654 readbuf = nsc->sasl_tmpbuf;
655 readbufsize = nsc->sasl_maxbufsize;
656 } else
657 #endif /* CYRUS_SASL */
658 {
659 readbuf = (char *) end;
660 readbufsize = remaining;
661 }
662
663 /*
664 * At this point, we should have active data on the connection (see
665 * select() above) so this read SHOULDN'T block. Hopefully.
666 */
667
668 rc = read(nsc->ns_readfd, readbuf, readbufsize);
669
670 if (rc == 0) {
671 netsec_err(errstr, "Received EOF on network read");
672 return NOTOK;
673 }
674
675 if (rc < 0) {
676 netsec_err(errstr, "Network read failed: %s", strerror(errno));
677 return NOTOK;
678 }
679
680 /*
681 * Okay, so we've had a successful read. If we are doing SASL security
682 * layers, pass this through sasl_decode(). sasl_decode() can return
683 * 0 bytes decoded; if that happens, jump back to the beginning. Otherwise
684 * we can just update our length pointer.
685 */
686
687 #ifdef CYRUS_SASL
688 if (nsc->sasl_seclayer) {
689 const char *tmpout;
690 unsigned int tmpoutlen;
691
692 rc = sasl_decode(nsc->sasl_conn, nsc->sasl_tmpbuf, rc,
693 &tmpout, &tmpoutlen);
694
695 if (rc != SASL_OK) {
696 netsec_err(errstr, "Unable to decode SASL network data: %s",
697 sasl_errdetail(nsc->sasl_conn));
698 return NOTOK;
699 }
700
701 if (tmpoutlen == 0)
702 goto retry;
703
704 /*
705 * Just in case ...
706 */
707
708 if (tmpoutlen > remaining) {
709 netsec_err(errstr, "Internal error: SASL decode buffer overflow!");
710 return NOTOK;
711 }
712
713 memcpy(end, tmpout, tmpoutlen);
714
715 nsc->ns_inbuflen += tmpoutlen;
716 } else
717 #endif /* CYRUS_SASL */
718 nsc->ns_inbuflen += rc;
719
720 return OK;
721 }
722
723 /*
724 * Write data to our network connection. Really, fill up the buffer as
725 * much as we can, and flush it out if necessary. netsec_flush() does
726 * the real work.
727 */
728
729 int
730 netsec_write(netsec_context *nsc, const void *buffer, size_t size,
731 char **errstr)
732 {
733 const unsigned char *bufptr = buffer;
734 int rc, remaining;
735
736 /* Just in case */
737
738 if (size == 0)
739 return OK;
740
741 /*
742 * Run a loop copying in data to our local buffer; when we're done with
743 * any buffer overflows then just copy any remaining data in.
744 */
745
746 while ((int) size >= (remaining = nsc->ns_outbufsize - nsc->ns_outbuflen)) {
747 memcpy(nsc->ns_outptr, bufptr, remaining);
748
749 /*
750 * In theory I should increment outptr, but netsec_flush just resets
751 * it anyway.
752 */
753 nsc->ns_outbuflen = nsc->ns_outbufsize;
754
755 rc = netsec_flush(nsc, errstr);
756
757 if (rc != OK)
758 return NOTOK;
759
760 bufptr += remaining;
761 size -= remaining;
762 }
763
764 /*
765 * Copy any leftover data into the buffer.
766 */
767
768 if (size > 0) {
769 memcpy(nsc->ns_outptr, bufptr, size);
770 nsc->ns_outptr += size;
771 nsc->ns_outbuflen += size;
772 }
773
774 return OK;
775 }
776
777 /*
778 * Our network printf() routine, which really just calls netsec_vprintf().
779 */
780
781 int
782 netsec_printf(netsec_context *nsc, char **errstr, const char *format, ...)
783 {
784 va_list ap;
785 int rc;
786
787 va_start(ap, format);
788 rc = netsec_vprintf(nsc, errstr, format, ap);
789 va_end(ap);
790
791 return rc;
792 }
793
794 /*
795 * Write bytes to the network using printf()-style formatting.
796 *
797 * Again, for the most part copy stuff into our buffer to be flushed
798 * out later.
799 */
800
801 int
802 netsec_vprintf(netsec_context *nsc, char **errstr, const char *format,
803 va_list ap)
804 {
805 int rc;
806
807 /*
808 * Cheat a little. If we can fit the data into our outgoing buffer,
809 * great! If not, generate a flush and retry once.
810 */
811
812 retry:
813 rc = vsnprintf((char *) nsc->ns_outptr,
814 nsc->ns_outbufsize - nsc->ns_outbuflen, format, ap);
815
816 if (rc >= (int) (nsc->ns_outbufsize - nsc->ns_outbuflen)) {
817 /*
818 * This means we have an overflow. Note that we don't actually
819 * make use of the terminating NUL, but according to the spec
820 * vsnprintf() won't write to the last byte in the string; that's
821 * why we have to use >= in the comparison above.
822 */
823 if (nsc->ns_outbuffer == nsc->ns_outptr) {
824 /*
825 * Whoops, if the buffer pointer was the same as the start of the
826 * buffer, that means we overflowed the internal buffer.
827 * At that point, just give up.
828 */
829 netsec_err(errstr, "Internal error: wanted to printf() a total of "
830 "%d bytes, but our buffer size was only %d bytes",
831 rc, nsc->ns_outbufsize);
832 return NOTOK;
833 }
834 /*
835 * Generate a flush (which may be inefficient, but hopefully
836 * it isn't) and then try again.
837 */
838 if (netsec_flush(nsc, errstr) != OK)
839 return NOTOK;
840 /*
841 * After this, outbuffer should == outptr, so we shouldn't
842 * hit this next time around.
843 */
844 goto retry;
845 }
846
847 if (nsc->ns_snoop) {
848 int outlen = rc;
849 if (outlen > 0 && nsc->ns_outptr[outlen - 1] == '\n') {
850 outlen--;
851 if (outlen > 0 && nsc->ns_outptr[outlen - 1] == '\r')
852 outlen--;
853 } else {
854 nsc->ns_snoop_noend = 1;
855 }
856 if (outlen > 0 || nsc->ns_snoop_noend == 0) {
857 #ifdef CYRUS_SASL
858 if (nsc->sasl_seclayer)
859 fprintf(stderr, "(sasl-encrypted) ");
860 #endif /* CYRUS_SASL */
861 #ifdef TLS_SUPPORT
862 if (nsc->tls_active)
863 fprintf(stderr, "(tls-encrypted) ");
864 #endif /* TLS_SUPPORT */
865 fprintf(stderr, "=> ");
866 if (nsc->ns_snoop_cb)
867 nsc->ns_snoop_cb(nsc, (char *) nsc->ns_outptr, outlen,
868 nsc->ns_snoop_context);
869 else
870 fprintf(stderr, "%.*s\n", outlen, nsc->ns_outptr);
871 } else {
872 nsc->ns_snoop_noend = 0;
873 }
874 }
875
876 nsc->ns_outptr += rc;
877 nsc->ns_outbuflen += rc;
878
879 return OK;
880 }
881
882 /*
883 * Flush out any buffered data in our output buffers. This routine is
884 * actually where the real network writes take place.
885 */
886
887 int
888 netsec_flush(netsec_context *nsc, char **errstr)
889 {
890 const char *netoutbuf = (const char *) nsc->ns_outbuffer;
891 unsigned int netoutlen = nsc->ns_outbuflen;
892 int rc;
893
894 /*
895 * Small optimization
896 */
897
898 if (netoutlen == 0)
899 return OK;
900
901 /*
902 * If SASL security layers are in effect, run the data through
903 * sasl_encode() first.
904 */
905 #ifdef CYRUS_SASL
906 if (nsc->sasl_seclayer) {
907 rc = sasl_encode(nsc->sasl_conn, (const char *) nsc->ns_outbuffer,
908 nsc->ns_outbuflen, &netoutbuf, &netoutlen);
909
910 if (rc != SASL_OK) {
911 netsec_err(errstr, "SASL data encoding failed: %s",
912 sasl_errdetail(nsc->sasl_conn));
913 return NOTOK;
914 }
915
916 }
917 #endif /* CYRUS_SASL */
918
919 /*
920 * If TLS is active, then use those functions to write out the
921 * data.
922 */
923 #ifdef TLS_SUPPORT
924 if (nsc->tls_active) {
925 if (BIO_write(nsc->ssl_io, netoutbuf, netoutlen) <= 0) {
926 netsec_err(errstr, "Error writing to TLS connection: %s",
927 ERR_error_string(ERR_get_error(), NULL));
928 return NOTOK;
929 }
930 } else
931 #endif /* TLS_SUPPORT */
932 {
933 rc = write(nsc->ns_writefd, netoutbuf, netoutlen);
934
935 if (rc < 0) {
936 netsec_err(errstr, "write() failed: %s", strerror(errno));
937 return NOTOK;
938 }
939 }
940
941 nsc->ns_outptr = nsc->ns_outbuffer;
942 nsc->ns_outbuflen = 0;
943
944 return OK;
945 }
946
947 /*
948 * Set various SASL protocol parameters
949 */
950
951 int
952 netsec_set_sasl_params(netsec_context *nsc, const char *service,
953 const char *mechanism, netsec_sasl_callback callback,
954 char **errstr)
955 {
956 #ifdef CYRUS_SASL
957 sasl_callback_t *sasl_cbs;
958 int retval;
959
960 if (!nsc->ns_hostname) {
961 netsec_err(errstr, "Internal error: ns_hostname is NULL");
962 return NOTOK;
963 }
964
965 if (! sasl_initialized) {
966 retval = sasl_client_init(NULL);
967 if (retval != SASL_OK) {
968 netsec_err(errstr, "SASL client initialization failed: %s",
969 sasl_errstring(retval, NULL, NULL));
970 return NOTOK;
971 }
972 sasl_initialized++;
973 }
974
975 /*
976 * Allocate an array of SASL callbacks for this connection.
977 * Right now we just allocate an array of four callbacks.
978 */
979
980 sasl_cbs = mh_xmalloc(sizeof(*sasl_cbs) * 4);
981
982 sasl_cbs[0].id = SASL_CB_USER;
983 sasl_cbs[0].proc = (sasl_callback_ft) netsec_get_user;
984 sasl_cbs[0].context = nsc;
985
986 sasl_cbs[1].id = SASL_CB_AUTHNAME;
987 sasl_cbs[1].proc = (sasl_callback_ft) netsec_get_user;
988 sasl_cbs[1].context = nsc;
989
990 sasl_cbs[2].id = SASL_CB_PASS;
991 sasl_cbs[2].proc = (sasl_callback_ft) netsec_get_password;
992 sasl_cbs[2].context = nsc;
993
994 sasl_cbs[3].id = SASL_CB_LIST_END;
995 sasl_cbs[3].proc = NULL;
996 sasl_cbs[3].context = NULL;
997
998 nsc->sasl_cbs = sasl_cbs;
999
1000 retval = sasl_client_new(service, nsc->ns_hostname, NULL, NULL,
1001 nsc->sasl_cbs, 0, &nsc->sasl_conn);
1002
1003 if (retval) {
1004 netsec_err(errstr, "SASL new client allocation failed: %s",
1005 sasl_errstring(retval, NULL, NULL));
1006 return NOTOK;
1007 }
1008
1009 /*
1010 * Set up our credentials
1011 */
1012
1013 nsc->sasl_creds = nmh_get_credentials(nsc->ns_hostname, nsc->ns_userid);
1014
1015 #else /* CYRUS_SASL */
1016 NMH_UNUSED(service);
1017 NMH_UNUSED(errstr);
1018 #endif /* CYRUS_SASL */
1019
1020 /*
1021 * According to the RFC, mechanisms can only be uppercase letter, numbers,
1022 * and a hyphen or underscore. So make sure we uppercase any letters
1023 * in case the user passed in lowercase.
1024 */
1025
1026 if (mechanism) {
1027 char *p;
1028 nsc->sasl_mech = mh_xstrdup(mechanism);
1029
1030 for (p = nsc->sasl_mech; *p; p++)
1031 if (isascii((unsigned char) *p)) /* Leave non-ASCII lower alone. */
1032 *p = toupper((unsigned char) *p);
1033 }
1034
1035 nsc->sasl_proto_cb = callback;
1036
1037 return OK;
1038 }
1039
1040 #ifdef CYRUS_SASL
1041 /*
1042 * Our userid callback; return the specified username to the SASL
1043 * library when asked.
1044 */
1045
1046 int netsec_get_user(void *context, int id, const char **result,
1047 unsigned int *len)
1048 {
1049 netsec_context *nsc = (netsec_context *) context;
1050
1051 if (! result || (id != SASL_CB_USER && id != SASL_CB_AUTHNAME))
1052 return SASL_BADPARAM;
1053
1054 *result = nmh_cred_get_user(nsc->sasl_creds);
1055
1056 if (len)
1057 *len = strlen(*result);
1058
1059 return SASL_OK;
1060 }
1061
1062 /*
1063 * Retrieve a password and return it to SASL
1064 */
1065
1066 static int
1067 netsec_get_password(sasl_conn_t *conn, void *context, int id,
1068 sasl_secret_t **psecret)
1069 {
1070 netsec_context *nsc = (netsec_context *) context;
1071 const char *password;
1072 int len;
1073
1074 NMH_UNUSED(conn);
1075
1076 if (! psecret || id != SASL_CB_PASS)
1077 return SASL_BADPARAM;
1078
1079 password = nmh_cred_get_password(nsc->sasl_creds);
1080
1081 len = strlen(password);
1082
1083 /*
1084 * sasl_secret_t includes 1 bytes for "data" already, so that leaves
1085 * us room for a terminating NUL
1086 */
1087
1088 *psecret = (sasl_secret_t *) malloc(sizeof(sasl_secret_t) + len);
1089
1090 if (! *psecret)
1091 return SASL_NOMEM;
1092
1093 (*psecret)->len = len;
1094 strcpy((char *) (*psecret)->data, password);
1095
1096 nsc->sasl_secret = *psecret;
1097
1098 return SASL_OK;
1099 }
1100 #endif /* CYRUS_SASL */
1101
1102 /*
1103 * Negotiate SASL on this connection
1104 */
1105
1106 int
1107 netsec_negotiate_sasl(netsec_context *nsc, const char *mechlist, char **errstr)
1108 {
1109 #ifdef CYRUS_SASL
1110 sasl_security_properties_t secprops;
1111 const char *chosen_mech;
1112 const unsigned char *saslbuf;
1113 unsigned char *outbuf;
1114 unsigned int saslbuflen, outbuflen;
1115 sasl_ssf_t *ssf;
1116 int *outbufmax;
1117 #endif
1118 #ifdef OAUTH_SUPPORT
1119 unsigned char *xoauth_client_res;
1120 size_t xoauth_client_res_len;
1121 #endif /* OAUTH_SUPPORT */
1122 #if defined CYRUS_SASL || defined OAUTH_SUPPORT
1123 int rc;
1124 #endif /* CYRUS_SASL || OAUTH_SUPPORT */
1125
1126 /*
1127 * If we've been passed a requested mechanism, check our mechanism
1128 * list from the protocol. If it's not supported, return an error.
1129 */
1130
1131 if (nsc->sasl_mech) {
1132 char **str, *mlist = getcpy(mechlist);
1133 int i;
1134
1135 str = brkstring(mlist, " ", NULL);
1136
1137 for (i = 0; str[i] != NULL; i++) {
1138 if (strcasecmp(nsc->sasl_mech, str[i]) == 0) {
1139 break;
1140 }
1141 }
1142
1143 i = (str[i] == NULL);
1144
1145 free(mlist);
1146
1147 if (i) {
1148 netsec_err(errstr, "Chosen mechanism %s not supported by server",
1149 nsc->sasl_mech);
1150 return NOTOK;
1151 }
1152 }
1153
1154 #ifdef OAUTH_SUPPORT
1155 if (nsc->sasl_mech && strcasecmp(nsc->sasl_mech, "XOAUTH2") == 0) {
1156 /*
1157 * This should be relatively straightforward, but requires some
1158 * help from the plugin. Basically, if XOAUTH2 is a success,
1159 * the callback has to return success, but no output data. If
1160 * there is output data, it will be assumed that it is the JSON
1161 * error message.
1162 */
1163
1164 if (! nsc->oauth_service) {
1165 netsec_err(errstr, "Internal error: OAuth2 service name not given");
1166 return NOTOK;
1167 }
1168
1169 nsc->sasl_chosen_mech = mh_xstrdup(nsc->sasl_mech);
1170
1171 if (mh_oauth_do_xoauth(nsc->ns_userid, nsc->oauth_service,
1172 &xoauth_client_res, &xoauth_client_res_len,
1173 nsc->ns_snoop ? stderr : NULL) != OK) {
1174 netsec_err(errstr, "Internal error: Unable to get OAuth2 "
1175 "bearer token");
1176 return NOTOK;
1177 }
1178
1179 rc = nsc->sasl_proto_cb(NETSEC_SASL_START, xoauth_client_res,
1180 xoauth_client_res_len, NULL, 0, errstr);
1181 free(xoauth_client_res);
1182
1183 if (rc != OK)
1184 return NOTOK;
1185
1186 /*
1187 * Okay, we need to do a NETSEC_SASL_FINISH now. If we return
1188 * success, we indicate that with no output data. But if we
1189 * fail, then send a blank message and get the resulting
1190 * error.
1191 */
1192
1193 rc = nsc->sasl_proto_cb(NETSEC_SASL_FINISH, NULL, 0, NULL, 0, errstr);
1194
1195 if (rc != OK) {
1196 /*
1197 * We're going to assume the error here is a JSON response;
1198 * we ignore it and send a blank message in response. We should
1199 * then get a failure messages with a useful error. We should
1200 * NOT get a success message at this point.
1201 */
1202 free(*errstr);
1203 nsc->sasl_proto_cb(NETSEC_SASL_WRITE, NULL, 0, NULL, 0, NULL);
1204 rc = nsc->sasl_proto_cb(NETSEC_SASL_FINISH, NULL, 0, NULL, 0,
1205 errstr);
1206 if (rc == 0) {
1207 netsec_err(errstr, "Unexpected success after OAuth failure!");
1208 }
1209 return NOTOK;
1210 }
1211 return OK;
1212 }
1213 #endif /* OAUTH_SUPPORT */
1214
1215 #ifdef CYRUS_SASL
1216 /*
1217 * In netsec_set_sasl_params, we've already done all of our setup with
1218 * sasl_client_init() and sasl_client_new(). So time to set security
1219 * properties, call sasl_client_start(), and generate the protocol
1220 * messages.
1221 */
1222
1223 ZERO(&secprops);
1224 secprops.maxbufsize = SASL_MAXRECVBUF;
1225
1226 /*
1227 * If we're using TLS, do not negotiate a security layer
1228 */
1229
1230 secprops.max_ssf =
1231 #ifdef TLS_SUPPORT
1232 nsc->tls_active ? 0 :
1233 #endif /* TLS_SUPPORT */
1234 UINT_MAX;
1235
1236 rc = sasl_setprop(nsc->sasl_conn, SASL_SEC_PROPS, &secprops);
1237
1238 if (rc != SASL_OK) {
1239 netsec_err(errstr, "SASL security property initialization failed: %s",
1240 sasl_errstring(rc, NULL, NULL));
1241 return NOTOK;
1242 }
1243
1244 /*
1245 * Start the actual protocol negotiation, and go through the
1246 * sasl_client_step() loop (after sasl_client_start, of course).
1247 */
1248
1249 rc = sasl_client_start(nsc->sasl_conn,
1250 nsc->sasl_mech ? nsc->sasl_mech : mechlist, NULL,
1251 (const char **) &saslbuf, &saslbuflen,
1252 &chosen_mech);
1253
1254 if (rc != SASL_OK && rc != SASL_CONTINUE) {
1255 netsec_err(errstr, "SASL client start failed: %s",
1256 sasl_errdetail(nsc->sasl_conn));
1257 return NOTOK;
1258 }
1259
1260 nsc->sasl_chosen_mech = getcpy(chosen_mech);
1261
1262 if (nsc->sasl_proto_cb(NETSEC_SASL_START, saslbuf, saslbuflen, NULL, 0,
1263 errstr) != OK)
1264 return NOTOK;
1265
1266 /*
1267 * We've written out our first message; enter in the step loop
1268 */
1269
1270 while (rc == SASL_CONTINUE) {
1271 /*
1272 * Call our SASL callback, which will handle the details of
1273 * reading data from the network.
1274 */
1275
1276 if (nsc->sasl_proto_cb(NETSEC_SASL_READ, NULL, 0, &outbuf, &outbuflen,
1277 errstr) != OK) {
1278 nsc->sasl_proto_cb(NETSEC_SASL_CANCEL, NULL, 0, NULL, 0, NULL);
1279 return NOTOK;
1280 }
1281
1282 rc = sasl_client_step(nsc->sasl_conn, (char *) outbuf, outbuflen, NULL,
1283 (const char **) &saslbuf, &saslbuflen);
1284
1285 free(outbuf);
1286
1287 if (rc != SASL_OK && rc != SASL_CONTINUE) {
1288 netsec_err(errstr, "SASL client negotiation failed: %s",
1289 sasl_errdetail(nsc->sasl_conn));
1290 nsc->sasl_proto_cb(NETSEC_SASL_CANCEL, NULL, 0, NULL, 0, NULL);
1291 return NOTOK;
1292 }
1293
1294 if (nsc->sasl_proto_cb(NETSEC_SASL_WRITE, saslbuf, saslbuflen,
1295 NULL, 0, errstr) != OK) {
1296 nsc->sasl_proto_cb(NETSEC_SASL_CANCEL, NULL, 0, NULL, 0, NULL);
1297 return NOTOK;
1298 }
1299 }
1300
1301 /*
1302 * SASL exchanges should be complete, process the final response message
1303 * from the server.
1304 */
1305
1306 if (nsc->sasl_proto_cb(NETSEC_SASL_FINISH, NULL, 0, NULL, 0,
1307 errstr) != OK) {
1308 /*
1309 * At this point we can't really send an abort since the SASL dialog
1310 * has completed, so just bubble back up the error message.
1311 */
1312
1313 return NOTOK;
1314 }
1315
1316 /*
1317 * At this point, SASL should be complete. Get a few properties
1318 * from the authentication exchange.
1319 */
1320
1321 rc = sasl_getprop(nsc->sasl_conn, SASL_SSF, (const void **) &ssf);
1322
1323 if (rc != SASL_OK) {
1324 netsec_err(errstr, "Cannot retrieve SASL negotiated security "
1325 "strength factor: %s", sasl_errstring(rc, NULL, NULL));
1326 return NOTOK;
1327 }
1328
1329 nsc->sasl_ssf = *ssf;
1330
1331 if (nsc->sasl_ssf > 0) {
1332 rc = sasl_getprop(nsc->sasl_conn, SASL_MAXOUTBUF,
1333 (const void **) &outbufmax);
1334
1335 if (rc != SASL_OK) {
1336 netsec_err(errstr, "Cannot retrieve SASL negotiated output "
1337 "buffer size: %s", sasl_errstring(rc, NULL, NULL));
1338 return NOTOK;
1339 }
1340
1341 /*
1342 * If our output buffer isn't the same size as the input buffer,
1343 * reallocate it and set the new size (since we won't encode any
1344 * data larger than that).
1345 */
1346
1347 nsc->sasl_maxbufsize = *outbufmax;
1348
1349 if (nsc->ns_outbufsize != nsc->sasl_maxbufsize) {
1350 nsc->ns_outbufsize = nsc->sasl_maxbufsize;
1351 nsc->ns_outbuffer = mh_xrealloc(nsc->ns_outbuffer,
1352 nsc->ns_outbufsize);
1353 /*
1354 * There shouldn't be any data in the buffer, but for
1355 * consistency's sake discard it.
1356 */
1357 nsc->ns_outptr = nsc->ns_outbuffer;
1358 nsc->ns_outbuflen = 0;
1359 }
1360
1361 /*
1362 * Allocate a buffer to do temporary reads into, before we
1363 * call sasl_decode()
1364 */
1365
1366 nsc->sasl_tmpbuf = mh_xmalloc(nsc->sasl_maxbufsize);
1367
1368 /*
1369 * Okay, this is a bit weird. Make sure that the input buffer
1370 * is at least TWICE the size of the max buffer size. That's
1371 * because if we're consuming data but want to extend the current
1372 * buffer, we want to be sure there's room for another full buffer's
1373 * worth of data.
1374 */
1375
1376 if (nsc->ns_inbufsize < nsc->sasl_maxbufsize * 2) {
1377 size_t offset = nsc->ns_inptr - nsc->ns_inbuffer;
1378 nsc->ns_inbufsize = nsc->sasl_maxbufsize * 2;
1379 nsc->ns_inbuffer = mh_xrealloc(nsc->ns_inbuffer, nsc->ns_inbufsize);
1380 nsc->ns_inptr = nsc->ns_inbuffer + offset;
1381 }
1382
1383 nsc->sasl_seclayer = 1;
1384 }
1385
1386 return OK;
1387 #else
1388 /*
1389 * If we're at this point, then either we have NEITHER OAuth2 or
1390 * Cyrus-SASL compiled in, or have OAuth2 but didn't give the XOAUTH2
1391 * mechanism on the command line.
1392 */
1393
1394 if (! nsc->sasl_mech)
1395 netsec_err(errstr, "SASL library support not available; please "
1396 "specify a SASL mechanism to use");
1397 else
1398 netsec_err(errstr, "No support for the %s SASL mechanism",
1399 nsc->sasl_mech);
1400
1401 return NOTOK;
1402 #endif /* CYRUS_SASL */
1403 }
1404
1405 /*
1406 * Retrieve our chosen SASL mechanism
1407 */
1408
1409 char *
1410 netsec_get_sasl_mechanism(netsec_context *nsc)
1411 {
1412 return nsc->sasl_chosen_mech;
1413 }
1414
1415 /*
1416 * Set an OAuth2 service name, if we support it.
1417 */
1418
1419 int
1420 netsec_set_oauth_service(netsec_context *nsc, const char *service)
1421 {
1422 #ifdef OAUTH_SUPPORT
1423 nsc->oauth_service = getcpy(service);
1424 return OK;
1425 #else /* OAUTH_SUPPORT */
1426 NMH_UNUSED(nsc);
1427 NMH_UNUSED(service);
1428 return NOTOK;
1429 #endif /* OAUTH_SUPPORT */
1430 }
1431
1432 /*
1433 * Initialize (and enable) TLS for this connection
1434 */
1435
1436 int
1437 netsec_set_tls(netsec_context *nsc, int tls, int noverify, char **errstr)
1438 {
1439 #ifdef TLS_SUPPORT
1440 if (tls) {
1441 SSL *ssl;
1442 BIO *rbio, *wbio, *ssl_bio;
1443
1444 if (! tls_initialized) {
1445 SSL_library_init();
1446 SSL_load_error_strings();
1447
1448 /*
1449 * Create the SSL context; this has the properties for all
1450 * SSL connections (we are only doing one), though. Make sure
1451 * we only support secure (known as of now) TLS protocols.
1452 */
1453
1454 sslctx = SSL_CTX_new(SSLv23_client_method());
1455
1456 if (! sslctx) {
1457 netsec_err(errstr, "Unable to initialize OpenSSL context: %s",
1458 ERR_error_string(ERR_get_error(), NULL));
1459 return NOTOK;
1460 }
1461
1462 SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
1463 SSL_OP_NO_TLSv1);
1464
1465 if (!SSL_CTX_set_default_verify_paths(sslctx)) {
1466 netsec_err(errstr, "Unable to set default certificate "
1467 "verification paths: %s",
1468 ERR_error_string(ERR_get_error(), NULL));
1469 return NOTOK;
1470 }
1471
1472 tls_initialized++;
1473 }
1474
1475 if (nsc->ns_readfd == -1 || nsc->ns_writefd == -1) {
1476 netsec_err(errstr, "Invalid file descriptor in netsec context");
1477 return NOTOK;
1478 }
1479
1480 /*
1481 * Create the SSL structure which holds the data for a single
1482 * TLS connection.
1483 */
1484
1485 ssl = SSL_new(sslctx);
1486
1487 if (! ssl) {
1488 netsec_err(errstr, "Unable to create SSL connection: %s",
1489 ERR_error_string(ERR_get_error(), NULL));
1490 return NOTOK;
1491 }
1492
1493 /*
1494 * Never bother us, since we are using blocking sockets.
1495 */
1496
1497 SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
1498
1499 /*
1500 * This is a bit weird, so pay attention.
1501 *
1502 * We create a socket BIO, and bind it to our SSL connection.
1503 * That means reads and writes to the SSL connection will use our
1504 * supplied socket.
1505 *
1506 * Then we create an SSL BIO, and assign our current SSL connection
1507 * to it. This is done so our code stays simple if we want to use
1508 * any buffering BIOs (right now we do our own buffering).
1509 * So the chain looks like:
1510 *
1511 * SSL BIO -> socket BIO.
1512 */
1513
1514 rbio = BIO_new_socket(nsc->ns_readfd, BIO_CLOSE);
1515
1516 if (! rbio) {
1517 netsec_err(errstr, "Unable to create a read socket BIO: %s",
1518 ERR_error_string(ERR_get_error(), NULL));
1519 SSL_free(ssl);
1520 return NOTOK;
1521 }
1522
1523 wbio = BIO_new_socket(nsc->ns_writefd, BIO_CLOSE);
1524
1525 if (! wbio) {
1526 netsec_err(errstr, "Unable to create a write socket BIO: %s",
1527 ERR_error_string(ERR_get_error(), NULL));
1528 SSL_free(ssl);
1529 BIO_free(rbio);
1530 return NOTOK;
1531 }
1532
1533 SSL_set_bio(ssl, rbio, wbio);
1534 SSL_set_connect_state(ssl);
1535
1536 /*
1537 * If noverify is NOT set, then do certificate validation.
1538 * Turning on SSL_VERIFY_PEER will verify the certificate chain
1539 * against locally stored root certificates (the locations are
1540 * set using SSL_CTX_set_default_verify_paths()), and we put
1541 * the hostname in the X509 verification parameters so the OpenSSL
1542 * code will verify that the hostname appears in the server
1543 * certificate.
1544 */
1545
1546 if (! noverify) {
1547 #ifdef HAVE_X509_VERIFY_PARAM_SET1_HOST
1548 X509_VERIFY_PARAM *param;
1549 #endif /* HAVE_X509_VERIFY_PARAM_SET1_HOST */
1550
1551 SSL_set_verify(ssl, SSL_VERIFY_PEER, NULL);
1552 if (! nsc->ns_hostname) {
1553 netsec_err(errstr, "Internal error: hostname not set and "
1554 "certification verification enabled");
1555 SSL_free(ssl);
1556 return NOTOK;
1557 }
1558
1559 #ifdef HAVE_X509_VERIFY_PARAM_SET1_HOST
1560 param = SSL_get0_param(ssl);
1561
1562 if (! X509_VERIFY_PARAM_set1_host(param, nsc->ns_hostname, 0)) {
1563 netsec_err(errstr, "Unable to add hostname %s to cert "
1564 "verification parameters: %s", nsc->ns_hostname,
1565 ERR_error_string(ERR_get_error(), NULL));
1566 SSL_free(ssl);
1567 return NOTOK;
1568 }
1569 #endif /* HAVE_X509_VERIFY_PARAM_SET1_HOST */
1570 }
1571
1572 ssl_bio = BIO_new(BIO_f_ssl());
1573
1574 if (! ssl_bio) {
1575 netsec_err(errstr, "Unable to create a SSL BIO: %s",
1576 ERR_error_string(ERR_get_error(), NULL));
1577 SSL_free(ssl);
1578 return NOTOK;
1579 }
1580
1581 BIO_set_ssl(ssl_bio, ssl, BIO_CLOSE);
1582 nsc->ssl_io = ssl_bio;
1583
1584 /*
1585 * Since SSL now owns these file descriptors, have it handle the
1586 * closing of them instead of netsec_shutdown().
1587 */
1588
1589 nsc->ns_noclose = 1;
1590
1591 return OK;
1592 }
1593 BIO_free_all(nsc->ssl_io);
1594 nsc->ssl_io = NULL;
1595
1596 #else /* TLS_SUPPORT */
1597 NMH_UNUSED(nsc);
1598 NMH_UNUSED(noverify);
1599
1600 if (tls) {
1601 netsec_err(errstr, "TLS is not supported");
1602 return NOTOK;
1603 }
1604 #endif /* TLS_SUPPORT */
1605
1606 return OK;
1607 }
1608
1609 /*
1610 * Start TLS negotiation on this connection
1611 */
1612
1613 int
1614 netsec_negotiate_tls(netsec_context *nsc, char **errstr)
1615 {
1616 #ifdef TLS_SUPPORT
1617 if (! nsc->ssl_io) {
1618 netsec_err(errstr, "TLS has not been configured for this connection");
1619 return NOTOK;
1620 }
1621
1622 if (BIO_do_handshake(nsc->ssl_io) < 1) {
1623 unsigned long errcode = ERR_get_error();
1624
1625 /*
1626 * Print a more detailed message if it was certificate verification
1627 * failure.
1628 */
1629
1630 if (ERR_GET_LIB(errcode) == ERR_LIB_SSL &&
1631 ERR_GET_REASON(errcode) == SSL_R_CERTIFICATE_VERIFY_FAILED) {
1632 SSL *ssl;
1633
1634 if (BIO_get_ssl(nsc->ssl_io, &ssl) < 1) {
1635 netsec_err(errstr, "Certificate verification failed, but "
1636 "cannot retrieve SSL handle: %s",
1637 ERR_error_string(ERR_get_error(), NULL));
1638 } else {
1639 netsec_err(errstr, "Server certificate verification failed: %s",
1640 X509_verify_cert_error_string(
1641 SSL_get_verify_result(ssl)));
1642 }
1643 } else {
1644 netsec_err(errstr, "TLS negotiation failed: %s",
1645 ERR_error_string(errcode, NULL));
1646 }
1647
1648 /*
1649 * Because negotiation failed, shut down TLS so we don't get any
1650 * garbage on the connection. Because of weirdness with SSL_shutdown,
1651 * we end up calling it twice: once explicitly, once as part of
1652 * BIO_free_all().
1653 */
1654
1655 BIO_ssl_shutdown(nsc->ssl_io);
1656 BIO_free_all(nsc->ssl_io);
1657 nsc->ssl_io = NULL;
1658
1659 return NOTOK;
1660 }
1661
1662 if (nsc->ns_snoop) {
1663 SSL *ssl;
1664
1665 if (BIO_get_ssl(nsc->ssl_io, &ssl) < 1) {
1666 fprintf(stderr, "WARNING: cannot determine SSL ciphers\n");
1667 } else {
1668 const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl);
1669 fprintf(stderr, "TLS negotiation successful: %s(%d) %s\n",
1670 SSL_CIPHER_get_name(cipher),
1671 SSL_CIPHER_get_bits(cipher, NULL),
1672 SSL_CIPHER_get_version(cipher));
1673 SSL_SESSION_print_fp(stderr, SSL_get_session(ssl));
1674 }
1675 }
1676
1677 nsc->tls_active = 1;
1678
1679 return OK;
1680 #else /* TLS_SUPPORT */
1681 NMH_UNUSED(nsc);
1682 netsec_err(errstr, "TLS not supported");
1683
1684 return NOTOK;
1685 #endif /* TLS_SUPPORT */
1686 }
1687
1688 /*
1689 * Generate an (allocated) error string
1690 */
1691
1692 void
1693 netsec_err(char **errstr, const char *fmt, ...)
1694 {
1695 va_list ap;
1696 size_t errbufsize;
1697 char *errbuf = NULL;
1698 int rc = 127;
1699
1700 if (! errstr)
1701 return;
1702
1703 do {
1704 errbufsize = rc + 1;
1705 errbuf = mh_xrealloc(errbuf, errbufsize);
1706 va_start(ap, fmt);
1707 rc = vsnprintf(errbuf, errbufsize, fmt, ap);
1708 va_end(ap);
1709 } while (rc >= (int) errbufsize);
1710
1711 *errstr = errbuf;
1712 }