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 
tls_mgr_handshake(VSTREAM * stream)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 
tls_mgr_open(void)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 
tls_mgr_seed(VSTRING * buf,int len)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 
tls_mgr_policy(const char * cache_type,int * cachable,int * timeout)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 
tls_mgr_lookup(const char * cache_type,const char * cache_id,VSTRING * buf)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 
tls_mgr_update(const char * cache_type,const char * cache_id,const char * buf,ssize_t len)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 
tls_mgr_delete(const char * cache_type,const char * cache_id)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 
request_scache_key(unsigned char * keyname)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 
tls_mgr_key(unsigned char * keyname,int timeout)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 
main(int unused_ac,char ** av)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