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