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