Home | History | Annotate | Line # | Download | only in tls
      1 /*	$NetBSD: tls_mgr.c,v 1.4 2022/10/08 16:12:50 christos Exp $	*/
      2 
      3 /*++
      4 /* NAME
      5 /*	tls_mgr 3
      6 /* SUMMARY
      7 /*	tlsmgr client interface
      8 /* SYNOPSIS
      9 /*	#include <tls_mgr.h>
     10 /*
     11 /*	int	tls_mgr_seed(buf, len)
     12 /*	VSTRING	*buf;
     13 /*	int	len;
     14 /*
     15 /*	int	tls_mgr_policy(cache_type, cachable, timeout)
     16 /*	const char *cache_type;
     17 /*	int	*cachable;
     18 /*	int	*timeout;
     19 /*
     20 /*	int	tls_mgr_update(cache_type, cache_id, buf, len)
     21 /*	const char *cache_type;
     22 /*	const char *cache_id;
     23 /*	const char *buf;
     24 /*	ssize_t	len;
     25 /*
     26 /*	int	tls_mgr_lookup(cache_type, cache_id, buf)
     27 /*	const char *cache_type;
     28 /*	const char *cache_id;
     29 /*	VSTRING	*buf;
     30 /*
     31 /*	int	tls_mgr_delete(cache_type, cache_id)
     32 /*	const char *cache_type;
     33 /*	const char *cache_id;
     34 /*
     35 /*	TLS_TICKET_KEY *tls_mgr_key(keyname, timeout)
     36 /*	unsigned char *keyname;
     37 /*	int	timeout;
     38 /* DESCRIPTION
     39 /*	These routines communicate with the tlsmgr(8) server for
     40 /*	entropy and session cache management. Since these are
     41 /*	non-critical services, requests are allowed to fail without
     42 /*	disrupting Postfix.
     43 /*
     44 /*	tls_mgr_seed() requests entropy from the tlsmgr(8)
     45 /*	Pseudo Random Number Generator (PRNG) pool.
     46 /*
     47 /*	tls_mgr_policy() requests the session caching policy.
     48 /*
     49 /*	tls_mgr_lookup() loads the specified session from
     50 /*	the specified session cache.
     51 /*
     52 /*	tls_mgr_update() saves the specified session to
     53 /*	the specified session cache.
     54 /*
     55 /*	tls_mgr_delete() removes specified session from
     56 /*	the specified session cache.
     57 /*
     58 /*	tls_mgr_key() is used to retrieve the current TLS session ticket
     59 /*	encryption or decryption keys.
     60 /*
     61 /*	Arguments:
     62 /* .IP cache_type
     63 /*	One of TLS_MGR_SCACHE_SMTPD, TLS_MGR_SCACHE_SMTP or
     64 /*	TLS_MGR_SCACHE_LMTP.
     65 /* .IP cachable
     66 /*	Pointer to int, set non-zero if the requested cache_type
     67 /*	is enabled.
     68 /* .IP timeout
     69 /*	Pointer to int, returns the cache entry timeout.
     70 /* .IP cache_id
     71 /*	The session cache lookup key.
     72 /* .IP buf
     73 /*	The result or input buffer.
     74 /* .IP len
     75 /*	The length of the input buffer, or the amount of data requested.
     76 /* .IP keyname
     77 /*	Is null when requesting the current encryption keys.  Otherwise,
     78 /*	keyname is a pointer to an array of TLS_TICKET_NAMELEN unsigned
     79 /*	chars (not NUL terminated) that is an identifier for a key
     80 /*	previously used to encrypt a session ticket.  When encrypting
     81 /*	a null result indicates that session tickets are not supported, when
     82 /*	decrypting it indicates that no matching keys were found.
     83 /* .IP timeout
     84 /*	The encryption key timeout.  Once a key has been active for this many
     85 /*	seconds it is retired and used only for decrypting previously issued
     86 /*	session tickets for another timeout seconds, and is then destroyed.
     87 /*	The timeout must not be longer than half the SSL session lifetime.
     88 /* DIAGNOSTICS
     89 /*	All client functions return one of the following status codes:
     90 /* .IP TLS_MGR_STAT_OK
     91 /*	The request completed, and the requested operation was
     92 /*	successful (for example, the requested session was found,
     93 /*	or the specified session was saved or removed).
     94 /* .IP TLS_MGR_STAT_ERR
     95 /*	The request completed, but the requested operation failed
     96 /*	(for example, the requested object was not found or the
     97 /*	specified session was not saved or removed).
     98 /* .IP TLS_MGR_STAT_FAIL
     99 /*	The request could not complete (the client could not
    100 /*	communicate with the tlsmgr(8) server).
    101 /* SEE ALSO
    102 /*	tlsmgr(8) TLS session and PRNG management
    103 /* LICENSE
    104 /* .ad
    105 /* .fi
    106 /*	The Secure Mailer license must be distributed with this software.
    107 /* AUTHOR(S)
    108 /*	Wietse Venema
    109 /*	IBM T.J. Watson Research
    110 /*	P.O. Box 704
    111 /*	Yorktown Heights, NY 10598, USA
    112 /*
    113 /*	Wietse Venema
    114 /*	Google, Inc.
    115 /*	111 8th Avenue
    116 /*	New York, NY 10011, USA
    117 /*--*/
    118 
    119 /* System library. */
    120 
    121 #include <sys_defs.h>
    122 
    123 #ifdef USE_TLS
    124 
    125 #ifdef STRCASECMP_IN_STRINGS_H
    126 #include <strings.h>
    127 #endif
    128 
    129 /* Utility library. */
    130 
    131 #include <msg.h>
    132 #include <vstream.h>
    133 #include <vstring.h>
    134 #include <attr.h>
    135 #include <attr_clnt.h>
    136 #include <mymalloc.h>
    137 #include <stringops.h>
    138 
    139 /* Global library. */
    140 
    141 #include <mail_params.h>
    142 #include <mail_proto.h>
    143 
    144 /* TLS library. */
    145 #include <tls_mgr.h>
    146 
    147 /* Application-specific. */
    148 
    149 #define STR(x) vstring_str(x)
    150 #define LEN(x) VSTRING_LEN(x)
    151 
    152 static ATTR_CLNT *tls_mgr;
    153 
    154 /* tls_mgr_handshake - receive server protocol announcement */
    155 
    156 static int tls_mgr_handshake(VSTREAM *stream)
    157 {
    158     return (attr_scan(stream, ATTR_FLAG_STRICT,
    159 		   RECV_ATTR_STREQ(MAIL_ATTR_PROTO, MAIL_ATTR_PROTO_TLSMGR),
    160 		      ATTR_TYPE_END));
    161 }
    162 
    163 /* tls_mgr_open - create client handle */
    164 
    165 static void tls_mgr_open(void)
    166 {
    167     char   *service;
    168 
    169     /*
    170      * Sanity check.
    171      */
    172     if (tls_mgr != 0)
    173 	msg_panic("tls_mgr_open: multiple initialization");
    174 
    175     /*
    176      * Use whatever IPC is preferred for internal use: UNIX-domain sockets or
    177      * Solaris streams.
    178      */
    179     service = concatenate("local:" TLS_MGR_CLASS "/", var_tls_mgr_service,
    180 			  (char *) 0);
    181     tls_mgr = attr_clnt_create(service, var_ipc_timeout,
    182 			       var_ipc_idle_limit, var_ipc_ttl_limit);
    183     myfree(service);
    184 
    185     attr_clnt_control(tls_mgr,
    186 		      ATTR_CLNT_CTL_PROTO, attr_vprint, attr_vscan,
    187 		      ATTR_CLNT_CTL_HANDSHAKE, tls_mgr_handshake,
    188 		      ATTR_CLNT_CTL_END);
    189 }
    190 
    191 /* tls_mgr_seed - request PRNG seed */
    192 
    193 int     tls_mgr_seed(VSTRING *buf, int len)
    194 {
    195     int     status;
    196 
    197     /*
    198      * Create the tlsmgr client handle.
    199      */
    200     if (tls_mgr == 0)
    201 	tls_mgr_open();
    202 
    203     /*
    204      * Request seed.
    205      */
    206     if (attr_clnt_request(tls_mgr,
    207 			  ATTR_FLAG_NONE,	/* Request attributes */
    208 			  SEND_ATTR_STR(TLS_MGR_ATTR_REQ, TLS_MGR_REQ_SEED),
    209 			  SEND_ATTR_INT(TLS_MGR_ATTR_SIZE, len),
    210 			  ATTR_TYPE_END,
    211 			  ATTR_FLAG_MISSING,	/* Reply attributes */
    212 			  RECV_ATTR_INT(TLS_MGR_ATTR_STATUS, &status),
    213 			  RECV_ATTR_DATA(TLS_MGR_ATTR_SEED, buf),
    214 			  ATTR_TYPE_END) != 2)
    215 	status = TLS_MGR_STAT_FAIL;
    216     return (status);
    217 }
    218 
    219 /* tls_mgr_policy - request caching policy */
    220 
    221 int     tls_mgr_policy(const char *cache_type, int *cachable, int *timeout)
    222 {
    223     int     status;
    224 
    225     /*
    226      * Create the tlsmgr client handle.
    227      */
    228     if (tls_mgr == 0)
    229 	tls_mgr_open();
    230 
    231     /*
    232      * Request policy.
    233      */
    234     if (attr_clnt_request(tls_mgr,
    235 			  ATTR_FLAG_NONE,	/* Request attributes */
    236 			SEND_ATTR_STR(TLS_MGR_ATTR_REQ, TLS_MGR_REQ_POLICY),
    237 			  SEND_ATTR_STR(TLS_MGR_ATTR_CACHE_TYPE, cache_type),
    238 			  ATTR_TYPE_END,
    239 			  ATTR_FLAG_MISSING,	/* Reply attributes */
    240 			  RECV_ATTR_INT(TLS_MGR_ATTR_STATUS, &status),
    241 			  RECV_ATTR_INT(TLS_MGR_ATTR_CACHABLE, cachable),
    242 			  RECV_ATTR_INT(TLS_MGR_ATTR_SESSTOUT, timeout),
    243 			  ATTR_TYPE_END) != 3)
    244 	status = TLS_MGR_STAT_FAIL;
    245     return (status);
    246 }
    247 
    248 /* tls_mgr_lookup - request cached session */
    249 
    250 int     tls_mgr_lookup(const char *cache_type, const char *cache_id,
    251 		               VSTRING *buf)
    252 {
    253     int     status;
    254 
    255     /*
    256      * Create the tlsmgr client handle.
    257      */
    258     if (tls_mgr == 0)
    259 	tls_mgr_open();
    260 
    261     /*
    262      * Send the request and receive the reply.
    263      */
    264     if (attr_clnt_request(tls_mgr,
    265 			  ATTR_FLAG_NONE,	/* Request */
    266 			SEND_ATTR_STR(TLS_MGR_ATTR_REQ, TLS_MGR_REQ_LOOKUP),
    267 			  SEND_ATTR_STR(TLS_MGR_ATTR_CACHE_TYPE, cache_type),
    268 			  SEND_ATTR_STR(TLS_MGR_ATTR_CACHE_ID, cache_id),
    269 			  ATTR_TYPE_END,
    270 			  ATTR_FLAG_MISSING,	/* Reply */
    271 			  RECV_ATTR_INT(TLS_MGR_ATTR_STATUS, &status),
    272 			  RECV_ATTR_DATA(TLS_MGR_ATTR_SESSION, buf),
    273 			  ATTR_TYPE_END) != 2)
    274 	status = TLS_MGR_STAT_FAIL;
    275     return (status);
    276 }
    277 
    278 /* tls_mgr_update - save session to cache */
    279 
    280 int     tls_mgr_update(const char *cache_type, const char *cache_id,
    281 		               const char *buf, ssize_t len)
    282 {
    283     int     status;
    284 
    285     /*
    286      * Create the tlsmgr client handle.
    287      */
    288     if (tls_mgr == 0)
    289 	tls_mgr_open();
    290 
    291     /*
    292      * Send the request and receive the reply.
    293      */
    294     if (attr_clnt_request(tls_mgr,
    295 			  ATTR_FLAG_NONE,	/* Request */
    296 			SEND_ATTR_STR(TLS_MGR_ATTR_REQ, TLS_MGR_REQ_UPDATE),
    297 			  SEND_ATTR_STR(TLS_MGR_ATTR_CACHE_TYPE, cache_type),
    298 			  SEND_ATTR_STR(TLS_MGR_ATTR_CACHE_ID, cache_id),
    299 			  SEND_ATTR_DATA(TLS_MGR_ATTR_SESSION, len, buf),
    300 			  ATTR_TYPE_END,
    301 			  ATTR_FLAG_MISSING,	/* Reply */
    302 			  RECV_ATTR_INT(TLS_MGR_ATTR_STATUS, &status),
    303 			  ATTR_TYPE_END) != 1)
    304 	status = TLS_MGR_STAT_FAIL;
    305     return (status);
    306 }
    307 
    308 /* tls_mgr_delete - remove cached session */
    309 
    310 int     tls_mgr_delete(const char *cache_type, const char *cache_id)
    311 {
    312     int     status;
    313 
    314     /*
    315      * Create the tlsmgr client handle.
    316      */
    317     if (tls_mgr == 0)
    318 	tls_mgr_open();
    319 
    320     /*
    321      * Send the request and receive the reply.
    322      */
    323     if (attr_clnt_request(tls_mgr,
    324 			  ATTR_FLAG_NONE,	/* Request */
    325 			SEND_ATTR_STR(TLS_MGR_ATTR_REQ, TLS_MGR_REQ_DELETE),
    326 			  SEND_ATTR_STR(TLS_MGR_ATTR_CACHE_TYPE, cache_type),
    327 			  SEND_ATTR_STR(TLS_MGR_ATTR_CACHE_ID, cache_id),
    328 			  ATTR_TYPE_END,
    329 			  ATTR_FLAG_MISSING,	/* Reply */
    330 			  RECV_ATTR_INT(TLS_MGR_ATTR_STATUS, &status),
    331 			  ATTR_TYPE_END) != 1)
    332 	status = TLS_MGR_STAT_FAIL;
    333     return (status);
    334 }
    335 
    336 /* request_scache_key - ask tlsmgr(8) for matching key */
    337 
    338 static TLS_TICKET_KEY *request_scache_key(unsigned char *keyname)
    339 {
    340     TLS_TICKET_KEY tmp;
    341     static VSTRING *keybuf;
    342     char   *name;
    343     size_t  len;
    344     int     status;
    345 
    346     /*
    347      * Create the tlsmgr client handle.
    348      */
    349     if (tls_mgr == 0)
    350 	tls_mgr_open();
    351 
    352     if (keybuf == 0)
    353 	keybuf = vstring_alloc(sizeof(tmp));
    354 
    355     /* In tlsmgr requests we encode null key names as empty strings. */
    356     name = keyname ? (char *) keyname : "";
    357     len = keyname ? TLS_TICKET_NAMELEN : 0;
    358 
    359     /*
    360      * Send the request and receive the reply.
    361      */
    362     if (attr_clnt_request(tls_mgr,
    363 			  ATTR_FLAG_NONE,	/* Request */
    364 			SEND_ATTR_STR(TLS_MGR_ATTR_REQ, TLS_MGR_REQ_TKTKEY),
    365 			  SEND_ATTR_DATA(TLS_MGR_ATTR_KEYNAME, len, name),
    366 			  ATTR_TYPE_END,
    367 			  ATTR_FLAG_MISSING,	/* Reply */
    368 			  RECV_ATTR_INT(TLS_MGR_ATTR_STATUS, &status),
    369 			  RECV_ATTR_DATA(TLS_MGR_ATTR_KEYBUF, keybuf),
    370 			  ATTR_TYPE_END) != 2
    371 	|| status != TLS_MGR_STAT_OK
    372 	|| LEN(keybuf) != sizeof(tmp))
    373 	return (0);
    374 
    375     memcpy((void *) &tmp, STR(keybuf), sizeof(tmp));
    376     return (tls_scache_key_rotate(&tmp));
    377 }
    378 
    379 /* tls_mgr_key - session ticket key lookup, local cache, then tlsmgr(8) */
    380 
    381 TLS_TICKET_KEY *tls_mgr_key(unsigned char *keyname, int timeout)
    382 {
    383     TLS_TICKET_KEY *key = 0;
    384     time_t  now = time((time_t *) 0);
    385 
    386     /* A zero timeout disables session tickets. */
    387     if (timeout <= 0)
    388 	return (0);
    389 
    390     if ((key = tls_scache_key(keyname, now, timeout)) == 0)
    391 	key = request_scache_key(keyname);
    392     return (key);
    393 }
    394 
    395 #ifdef TEST
    396 
    397 /* System library. */
    398 
    399 #include <stdlib.h>
    400 
    401 /* Utility library. */
    402 
    403 #include <argv.h>
    404 #include <msg_vstream.h>
    405 #include <vstring_vstream.h>
    406 #include <hex_code.h>
    407 
    408 /* Global library. */
    409 
    410 #include <config.h>
    411 
    412 /* Application-specific. */
    413 
    414 int     main(int unused_ac, char **av)
    415 {
    416     VSTRING *inbuf = vstring_alloc(10);
    417     int     status;
    418     ARGV   *argv = 0;
    419 
    420     msg_vstream_init(av[0], VSTREAM_ERR);
    421 
    422     msg_verbose = 3;
    423 
    424     mail_conf_read();
    425     msg_info("using config files in %s", var_config_dir);
    426 
    427     if (chdir(var_queue_dir) < 0)
    428 	msg_fatal("chdir %s: %m", var_queue_dir);
    429 
    430     while (vstring_fgets_nonl(inbuf, VSTREAM_IN)) {
    431 	argv = argv_split(STR(inbuf), CHARS_SPACE);
    432 	if (argv->argc == 0) {
    433 	    argv_free(argv);
    434 	    continue;
    435 	}
    436 #define COMMAND(argv, str, len) \
    437     (strcasecmp(argv->argv[0], str) == 0 && argv->argc == len)
    438 
    439 	if (COMMAND(argv, "policy", 2)) {
    440 	    int     cachable;
    441 	    int     timeout;
    442 
    443 	    status = tls_mgr_policy(argv->argv[1], &cachable, &timeout);
    444 	    vstream_printf("status=%d cachable=%d timeout=%d\n",
    445 			   status, cachable, timeout);
    446 	} else if (COMMAND(argv, "seed", 2)) {
    447 	    VSTRING *buf = vstring_alloc(10);
    448 	    VSTRING *hex = vstring_alloc(10);
    449 	    int     len = atoi(argv->argv[1]);
    450 
    451 	    status = tls_mgr_seed(buf, len);
    452 	    hex_encode(hex, STR(buf), LEN(buf));
    453 	    vstream_printf("status=%d seed=%s\n", status, STR(hex));
    454 	    vstring_free(hex);
    455 	    vstring_free(buf);
    456 	} else if (COMMAND(argv, "lookup", 3)) {
    457 	    VSTRING *buf = vstring_alloc(10);
    458 
    459 	    status = tls_mgr_lookup(argv->argv[1], argv->argv[2], buf);
    460 	    vstream_printf("status=%d session=%.*s\n",
    461 			   status, (int) LEN(buf), STR(buf));
    462 	    vstring_free(buf);
    463 	} else if (COMMAND(argv, "update", 4)) {
    464 	    status = tls_mgr_update(argv->argv[1], argv->argv[2],
    465 				    argv->argv[3], strlen(argv->argv[3]));
    466 	    vstream_printf("status=%d\n", status);
    467 	} else if (COMMAND(argv, "delete", 3)) {
    468 	    status = tls_mgr_delete(argv->argv[1], argv->argv[2]);
    469 	    vstream_printf("status=%d\n", status);
    470 	} else {
    471 	    vstream_printf("usage:\n"
    472 			   "seed byte_count\n"
    473 			   "policy smtpd|smtp|lmtp\n"
    474 			   "lookup smtpd|smtp|lmtp cache_id\n"
    475 			   "update smtpd|smtp|lmtp cache_id session\n"
    476 			   "delete smtpd|smtp|lmtp cache_id\n");
    477 	}
    478 	vstream_fflush(VSTREAM_OUT);
    479 	argv_free(argv);
    480     }
    481 
    482     vstring_free(inbuf);
    483     return (0);
    484 }
    485 
    486 #endif					/* TEST */
    487 
    488 #endif					/* USE_TLS */
    489