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