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