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