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