xref: /netbsd-src/external/ibm-public/postfix/dist/src/tls/tls_mgr.c (revision 82d56013d7b633d116a93943de88e08335357a7c)
1 /*	$NetBSD: tls_mgr.c,v 1.3 2020/03/18 19:05:21 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 
114 /* System library. */
115 
116 #include <sys_defs.h>
117 
118 #ifdef USE_TLS
119 
120 #ifdef STRCASECMP_IN_STRINGS_H
121 #include <strings.h>
122 #endif
123 
124 /* Utility library. */
125 
126 #include <msg.h>
127 #include <vstream.h>
128 #include <vstring.h>
129 #include <attr.h>
130 #include <attr_clnt.h>
131 #include <mymalloc.h>
132 #include <stringops.h>
133 
134 /* Global library. */
135 
136 #include <mail_params.h>
137 #include <mail_proto.h>
138 
139 /* TLS library. */
140 #include <tls_mgr.h>
141 
142 /* Application-specific. */
143 
144 #define STR(x) vstring_str(x)
145 #define LEN(x) VSTRING_LEN(x)
146 
147 static ATTR_CLNT *tls_mgr;
148 
149 /* tls_mgr_open - create client handle */
150 
151 static void tls_mgr_open(void)
152 {
153     char   *service;
154 
155     /*
156      * Sanity check.
157      */
158     if (tls_mgr != 0)
159 	msg_panic("tls_mgr_open: multiple initialization");
160 
161     /*
162      * Use whatever IPC is preferred for internal use: UNIX-domain sockets or
163      * Solaris streams.
164      */
165     service = concatenate("local:" TLS_MGR_CLASS "/", var_tls_mgr_service,
166 			  (char *) 0);
167     tls_mgr = attr_clnt_create(service, var_ipc_timeout,
168 			       var_ipc_idle_limit, var_ipc_ttl_limit);
169     myfree(service);
170 
171     attr_clnt_control(tls_mgr,
172 		      ATTR_CLNT_CTL_PROTO, attr_vprint, attr_vscan,
173 		      ATTR_CLNT_CTL_END);
174 }
175 
176 /* tls_mgr_seed - request PRNG seed */
177 
178 int     tls_mgr_seed(VSTRING *buf, int len)
179 {
180     int     status;
181 
182     /*
183      * Create the tlsmgr client handle.
184      */
185     if (tls_mgr == 0)
186 	tls_mgr_open();
187 
188     /*
189      * Request seed.
190      */
191     if (attr_clnt_request(tls_mgr,
192 			  ATTR_FLAG_NONE,	/* Request attributes */
193 			  SEND_ATTR_STR(TLS_MGR_ATTR_REQ, TLS_MGR_REQ_SEED),
194 			  SEND_ATTR_INT(TLS_MGR_ATTR_SIZE, len),
195 			  ATTR_TYPE_END,
196 			  ATTR_FLAG_MISSING,	/* Reply attributes */
197 			  RECV_ATTR_INT(TLS_MGR_ATTR_STATUS, &status),
198 			  RECV_ATTR_DATA(TLS_MGR_ATTR_SEED, buf),
199 			  ATTR_TYPE_END) != 2)
200 	status = TLS_MGR_STAT_FAIL;
201     return (status);
202 }
203 
204 /* tls_mgr_policy - request caching policy */
205 
206 int     tls_mgr_policy(const char *cache_type, int *cachable, int *timeout)
207 {
208     int     status;
209 
210     /*
211      * Create the tlsmgr client handle.
212      */
213     if (tls_mgr == 0)
214 	tls_mgr_open();
215 
216     /*
217      * Request policy.
218      */
219     if (attr_clnt_request(tls_mgr,
220 			  ATTR_FLAG_NONE,	/* Request attributes */
221 			SEND_ATTR_STR(TLS_MGR_ATTR_REQ, TLS_MGR_REQ_POLICY),
222 			  SEND_ATTR_STR(TLS_MGR_ATTR_CACHE_TYPE, cache_type),
223 			  ATTR_TYPE_END,
224 			  ATTR_FLAG_MISSING,	/* Reply attributes */
225 			  RECV_ATTR_INT(TLS_MGR_ATTR_STATUS, &status),
226 			  RECV_ATTR_INT(TLS_MGR_ATTR_CACHABLE, cachable),
227 			  RECV_ATTR_INT(TLS_MGR_ATTR_SESSTOUT, timeout),
228 			  ATTR_TYPE_END) != 3)
229 	status = TLS_MGR_STAT_FAIL;
230     return (status);
231 }
232 
233 /* tls_mgr_lookup - request cached session */
234 
235 int     tls_mgr_lookup(const char *cache_type, const char *cache_id,
236 		               VSTRING *buf)
237 {
238     int     status;
239 
240     /*
241      * Create the tlsmgr client handle.
242      */
243     if (tls_mgr == 0)
244 	tls_mgr_open();
245 
246     /*
247      * Send the request and receive the reply.
248      */
249     if (attr_clnt_request(tls_mgr,
250 			  ATTR_FLAG_NONE,	/* Request */
251 			SEND_ATTR_STR(TLS_MGR_ATTR_REQ, TLS_MGR_REQ_LOOKUP),
252 			  SEND_ATTR_STR(TLS_MGR_ATTR_CACHE_TYPE, cache_type),
253 			  SEND_ATTR_STR(TLS_MGR_ATTR_CACHE_ID, cache_id),
254 			  ATTR_TYPE_END,
255 			  ATTR_FLAG_MISSING,	/* Reply */
256 			  RECV_ATTR_INT(TLS_MGR_ATTR_STATUS, &status),
257 			  RECV_ATTR_DATA(TLS_MGR_ATTR_SESSION, buf),
258 			  ATTR_TYPE_END) != 2)
259 	status = TLS_MGR_STAT_FAIL;
260     return (status);
261 }
262 
263 /* tls_mgr_update - save session to cache */
264 
265 int     tls_mgr_update(const char *cache_type, const char *cache_id,
266 		               const char *buf, ssize_t len)
267 {
268     int     status;
269 
270     /*
271      * Create the tlsmgr client handle.
272      */
273     if (tls_mgr == 0)
274 	tls_mgr_open();
275 
276     /*
277      * Send the request and receive the reply.
278      */
279     if (attr_clnt_request(tls_mgr,
280 			  ATTR_FLAG_NONE,	/* Request */
281 			SEND_ATTR_STR(TLS_MGR_ATTR_REQ, TLS_MGR_REQ_UPDATE),
282 			  SEND_ATTR_STR(TLS_MGR_ATTR_CACHE_TYPE, cache_type),
283 			  SEND_ATTR_STR(TLS_MGR_ATTR_CACHE_ID, cache_id),
284 			  SEND_ATTR_DATA(TLS_MGR_ATTR_SESSION, len, buf),
285 			  ATTR_TYPE_END,
286 			  ATTR_FLAG_MISSING,	/* Reply */
287 			  RECV_ATTR_INT(TLS_MGR_ATTR_STATUS, &status),
288 			  ATTR_TYPE_END) != 1)
289 	status = TLS_MGR_STAT_FAIL;
290     return (status);
291 }
292 
293 /* tls_mgr_delete - remove cached session */
294 
295 int     tls_mgr_delete(const char *cache_type, const char *cache_id)
296 {
297     int     status;
298 
299     /*
300      * Create the tlsmgr client handle.
301      */
302     if (tls_mgr == 0)
303 	tls_mgr_open();
304 
305     /*
306      * Send the request and receive the reply.
307      */
308     if (attr_clnt_request(tls_mgr,
309 			  ATTR_FLAG_NONE,	/* Request */
310 			SEND_ATTR_STR(TLS_MGR_ATTR_REQ, TLS_MGR_REQ_DELETE),
311 			  SEND_ATTR_STR(TLS_MGR_ATTR_CACHE_TYPE, cache_type),
312 			  SEND_ATTR_STR(TLS_MGR_ATTR_CACHE_ID, cache_id),
313 			  ATTR_TYPE_END,
314 			  ATTR_FLAG_MISSING,	/* Reply */
315 			  RECV_ATTR_INT(TLS_MGR_ATTR_STATUS, &status),
316 			  ATTR_TYPE_END) != 1)
317 	status = TLS_MGR_STAT_FAIL;
318     return (status);
319 }
320 
321 /* request_scache_key - ask tlsmgr(8) for matching key */
322 
323 static TLS_TICKET_KEY *request_scache_key(unsigned char *keyname)
324 {
325     TLS_TICKET_KEY tmp;
326     static VSTRING *keybuf;
327     char   *name;
328     size_t  len;
329     int     status;
330 
331     /*
332      * Create the tlsmgr client handle.
333      */
334     if (tls_mgr == 0)
335 	tls_mgr_open();
336 
337     if (keybuf == 0)
338 	keybuf = vstring_alloc(sizeof(tmp));
339 
340     /* In tlsmgr requests we encode null key names as empty strings. */
341     name = keyname ? (char *) keyname : "";
342     len = keyname ? TLS_TICKET_NAMELEN : 0;
343 
344     /*
345      * Send the request and receive the reply.
346      */
347     if (attr_clnt_request(tls_mgr,
348 			  ATTR_FLAG_NONE,	/* Request */
349 			SEND_ATTR_STR(TLS_MGR_ATTR_REQ, TLS_MGR_REQ_TKTKEY),
350 			  SEND_ATTR_DATA(TLS_MGR_ATTR_KEYNAME, len, name),
351 			  ATTR_TYPE_END,
352 			  ATTR_FLAG_MISSING,	/* Reply */
353 			  RECV_ATTR_INT(TLS_MGR_ATTR_STATUS, &status),
354 			  RECV_ATTR_DATA(TLS_MGR_ATTR_KEYBUF, keybuf),
355 			  ATTR_TYPE_END) != 2
356 	|| status != TLS_MGR_STAT_OK
357 	|| LEN(keybuf) != sizeof(tmp))
358 	return (0);
359 
360     memcpy((void *) &tmp, STR(keybuf), sizeof(tmp));
361     return (tls_scache_key_rotate(&tmp));
362 }
363 
364 /* tls_mgr_key - session ticket key lookup, local cache, then tlsmgr(8) */
365 
366 TLS_TICKET_KEY *tls_mgr_key(unsigned char *keyname, int timeout)
367 {
368     TLS_TICKET_KEY *key = 0;
369     time_t  now = time((time_t *) 0);
370 
371     /* A zero timeout disables session tickets. */
372     if (timeout <= 0)
373 	return (0);
374 
375     if ((key = tls_scache_key(keyname, now, timeout)) == 0)
376 	key = request_scache_key(keyname);
377     return (key);
378 }
379 
380 #ifdef TEST
381 
382 /* System library. */
383 
384 #include <stdlib.h>
385 
386 /* Utility library. */
387 
388 #include <argv.h>
389 #include <msg_vstream.h>
390 #include <vstring_vstream.h>
391 #include <hex_code.h>
392 
393 /* Global library. */
394 
395 #include <config.h>
396 
397 /* Application-specific. */
398 
399 int     main(int unused_ac, char **av)
400 {
401     VSTRING *inbuf = vstring_alloc(10);
402     int     status;
403     ARGV   *argv = 0;
404 
405     msg_vstream_init(av[0], VSTREAM_ERR);
406 
407     msg_verbose = 3;
408 
409     mail_conf_read();
410     msg_info("using config files in %s", var_config_dir);
411 
412     if (chdir(var_queue_dir) < 0)
413 	msg_fatal("chdir %s: %m", var_queue_dir);
414 
415     while (vstring_fgets_nonl(inbuf, VSTREAM_IN)) {
416 	argv = argv_split(STR(inbuf), CHARS_SPACE);
417 	if (argv->argc == 0) {
418 	    argv_free(argv);
419 	    continue;
420 	}
421 #define COMMAND(argv, str, len) \
422     (strcasecmp(argv->argv[0], str) == 0 && argv->argc == len)
423 
424 	if (COMMAND(argv, "policy", 2)) {
425 	    int     cachable;
426 	    int     timeout;
427 
428 	    status = tls_mgr_policy(argv->argv[1], &cachable, &timeout);
429 	    vstream_printf("status=%d cachable=%d timeout=%d\n",
430 			   status, cachable, timeout);
431 	} else if (COMMAND(argv, "seed", 2)) {
432 	    VSTRING *buf = vstring_alloc(10);
433 	    VSTRING *hex = vstring_alloc(10);
434 	    int     len = atoi(argv->argv[1]);
435 
436 	    status = tls_mgr_seed(buf, len);
437 	    hex_encode(hex, STR(buf), LEN(buf));
438 	    vstream_printf("status=%d seed=%s\n", status, STR(hex));
439 	    vstring_free(hex);
440 	    vstring_free(buf);
441 	} else if (COMMAND(argv, "lookup", 3)) {
442 	    VSTRING *buf = vstring_alloc(10);
443 
444 	    status = tls_mgr_lookup(argv->argv[1], argv->argv[2], buf);
445 	    vstream_printf("status=%d session=%.*s\n",
446 			   status, (int) LEN(buf), STR(buf));
447 	    vstring_free(buf);
448 	} else if (COMMAND(argv, "update", 4)) {
449 	    status = tls_mgr_update(argv->argv[1], argv->argv[2],
450 				    argv->argv[3], strlen(argv->argv[3]));
451 	    vstream_printf("status=%d\n", status);
452 	} else if (COMMAND(argv, "delete", 3)) {
453 	    status = tls_mgr_delete(argv->argv[1], argv->argv[2]);
454 	    vstream_printf("status=%d\n", status);
455 	} else {
456 	    vstream_printf("usage:\n"
457 			   "seed byte_count\n"
458 			   "policy smtpd|smtp|lmtp\n"
459 			   "lookup smtpd|smtp|lmtp cache_id\n"
460 			   "update smtpd|smtp|lmtp cache_id session\n"
461 			   "delete smtpd|smtp|lmtp cache_id\n");
462 	}
463 	vstream_fflush(VSTREAM_OUT);
464 	argv_free(argv);
465     }
466 
467     vstring_free(inbuf);
468     return (0);
469 }
470 
471 #endif					/* TEST */
472 
473 #endif					/* USE_TLS */
474