1 /* $OpenBSD: ssl.c,v 1.52 2013/01/26 09:37:24 gilles Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> 5 * Copyright (c) 2008 Reyk Floeter <reyk@openbsd.org> 6 * Copyright (c) 2012 Gilles Chehade <gilles@poolp.org> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 #include <sys/types.h> 22 #include <sys/queue.h> 23 #include <sys/tree.h> 24 #include <sys/param.h> 25 #include <sys/socket.h> 26 #include <sys/stat.h> 27 28 #include <ctype.h> 29 #include <event.h> 30 #include <fcntl.h> 31 #include <imsg.h> 32 #include <pwd.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <unistd.h> 37 38 #include <openssl/ssl.h> 39 #include <openssl/engine.h> 40 #include <openssl/err.h> 41 42 #include "log.h" 43 #include "ssl.h" 44 45 void 46 ssl_init(void) 47 { 48 static int inited = 0; 49 50 if (inited) 51 return; 52 53 SSL_library_init(); 54 SSL_load_error_strings(); 55 56 OpenSSL_add_all_algorithms(); 57 58 /* Init hardware crypto engines. */ 59 ENGINE_load_builtin_engines(); 60 ENGINE_register_all_complete(); 61 inited = 1; 62 } 63 64 int 65 ssl_setup(SSL_CTX **ctxp, struct ssl *ssl) 66 { 67 DH *dh; 68 SSL_CTX *ctx; 69 70 ctx = ssl_ctx_create(); 71 72 if (!ssl_ctx_use_certificate_chain(ctx, 73 ssl->ssl_cert, ssl->ssl_cert_len)) 74 goto err; 75 if (!ssl_ctx_use_private_key(ctx, 76 ssl->ssl_key, ssl->ssl_key_len)) 77 goto err; 78 79 if (!SSL_CTX_check_private_key(ctx)) 80 goto err; 81 if (!SSL_CTX_set_session_id_context(ctx, 82 (const unsigned char *)ssl->ssl_name, 83 strlen(ssl->ssl_name) + 1)) 84 goto err; 85 86 if (ssl->ssl_dhparams_len == 0) 87 dh = get_dh1024(); 88 else 89 dh = get_dh_from_memory(ssl->ssl_dhparams, 90 ssl->ssl_dhparams_len); 91 ssl_set_ephemeral_key_exchange(ctx, dh); 92 DH_free(dh); 93 94 *ctxp = ctx; 95 return 1; 96 97 err: 98 SSL_CTX_free(ctx); 99 ssl_error("ssl_setup"); 100 return 0; 101 } 102 103 char * 104 ssl_load_file(const char *name, off_t *len, mode_t perm) 105 { 106 struct stat st; 107 off_t size; 108 char *buf = NULL; 109 int fd, saved_errno; 110 char mode[12]; 111 112 if ((fd = open(name, O_RDONLY)) == -1) 113 return (NULL); 114 if (fstat(fd, &st) != 0) 115 goto fail; 116 if (st.st_uid != 0) { 117 log_warnx("warn: %s: not owned by uid 0", name); 118 errno = EACCES; 119 goto fail; 120 } 121 if (st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO) & ~perm) { 122 strmode(perm, mode); 123 log_warnx("warn: %s: insecure permissions: must be at most %s", 124 name, &mode[1]); 125 errno = EACCES; 126 goto fail; 127 } 128 size = st.st_size; 129 if ((buf = calloc(1, size + 1)) == NULL) 130 goto fail; 131 if (read(fd, buf, size) != size) 132 goto fail; 133 close(fd); 134 135 *len = size + 1; 136 return (buf); 137 138 fail: 139 if (buf != NULL) 140 free(buf); 141 saved_errno = errno; 142 close(fd); 143 errno = saved_errno; 144 return (NULL); 145 } 146 147 static int 148 ssl_password_cb(char *buf, int size, int rwflag, void *u) 149 { 150 size_t len; 151 if (u == NULL) { 152 bzero(buf, size); 153 return (0); 154 } 155 if ((len = strlcpy(buf, u, size)) >= (size_t)size) 156 return (0); 157 return (len); 158 } 159 160 char * 161 ssl_load_key(const char *name, off_t *len, char *pass) 162 { 163 FILE *fp; 164 EVP_PKEY *key = NULL; 165 BIO *bio = NULL; 166 long size; 167 char *data, *buf = NULL; 168 169 /* Initialize SSL library once */ 170 ssl_init(); 171 172 /* 173 * Read (possibly) encrypted key from file 174 */ 175 if ((fp = fopen(name, "r")) == NULL) 176 return (NULL); 177 178 key = PEM_read_PrivateKey(fp, NULL, ssl_password_cb, pass); 179 fclose(fp); 180 if (key == NULL) 181 goto fail; 182 183 /* 184 * Write unencrypted key to memory buffer 185 */ 186 if ((bio = BIO_new(BIO_s_mem())) == NULL) 187 goto fail; 188 if (!PEM_write_bio_PrivateKey(bio, key, NULL, NULL, 0, NULL, NULL)) 189 goto fail; 190 if ((size = BIO_get_mem_data(bio, &data)) <= 0) 191 goto fail; 192 if ((buf = calloc(1, size)) == NULL) 193 goto fail; 194 memcpy(buf, data, size); 195 196 BIO_free_all(bio); 197 *len = (off_t)size; 198 return (buf); 199 200 fail: 201 ssl_error("ssl_load_key"); 202 203 free(buf); 204 if (bio != NULL) 205 BIO_free_all(bio); 206 return (NULL); 207 } 208 209 SSL_CTX * 210 ssl_ctx_create(void) 211 { 212 SSL_CTX *ctx; 213 214 ctx = SSL_CTX_new(SSLv23_method()); 215 if (ctx == NULL) { 216 ssl_error("ssl_ctx_create"); 217 fatal("ssl_ctx_create: could not create SSL context"); 218 } 219 220 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); 221 SSL_CTX_set_timeout(ctx, SSL_SESSION_TIMEOUT); 222 SSL_CTX_set_options(ctx, 223 SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_TICKET); 224 SSL_CTX_set_options(ctx, 225 SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); 226 227 if (!SSL_CTX_set_cipher_list(ctx, SSL_CIPHERS)) { 228 ssl_error("ssl_ctx_create"); 229 fatal("ssl_ctx_create: could not set cipher list"); 230 } 231 232 return (ctx); 233 } 234 235 int 236 ssl_load_certfile(struct ssl **sp, const char *path, const char *name, uint8_t flags) 237 { 238 struct ssl *s; 239 char pathname[PATH_MAX]; 240 int ret; 241 242 if ((s = calloc(1, sizeof(*s))) == NULL) 243 fatal(NULL); 244 245 s->flags = flags; 246 (void)strlcpy(s->ssl_name, name, sizeof(s->ssl_name)); 247 248 ret = snprintf(pathname, sizeof(pathname), "%s/%s.crt", 249 path ? path : "/etc/ssl", name); 250 if (ret == -1 || (size_t)ret >= sizeof pathname) 251 goto err; 252 s->ssl_cert = ssl_load_file(pathname, &s->ssl_cert_len, 0755); 253 if (s->ssl_cert == NULL) 254 goto err; 255 256 ret = snprintf(pathname, sizeof(pathname), "%s/%s.key", 257 path ? path : "/etc/ssl/private", name); 258 if (ret == -1 || (size_t)ret >= sizeof pathname) 259 goto err; 260 s->ssl_key = ssl_load_file(pathname, &s->ssl_key_len, 0700); 261 if (s->ssl_key == NULL) 262 goto err; 263 264 ret = snprintf(pathname, sizeof(pathname), "%s/%s.ca", 265 path ? path : "/etc/ssl", name); 266 if (ret == -1 || (size_t)ret >= sizeof pathname) 267 goto err; 268 s->ssl_ca = ssl_load_file(pathname, &s->ssl_ca_len, 0755); 269 if (s->ssl_ca == NULL) { 270 if (errno == EACCES) 271 goto err; 272 log_info("info: No CA found in %s", pathname); 273 } 274 275 ret = snprintf(pathname, sizeof(pathname), "%s/%s.dh", 276 path ? path : "/etc/ssl", name); 277 if (ret == -1 || (size_t)ret >= sizeof pathname) 278 goto err; 279 s->ssl_dhparams = ssl_load_file(pathname, &s->ssl_dhparams_len, 0755); 280 if (s->ssl_dhparams == NULL) { 281 if (errno == EACCES) 282 goto err; 283 log_info("info: No DH parameters found in %s: " 284 "using built-in parameters", pathname); 285 } 286 287 *sp = s; 288 return (1); 289 290 err: 291 if (s->ssl_cert != NULL) 292 free(s->ssl_cert); 293 if (s->ssl_key != NULL) 294 free(s->ssl_key); 295 if (s->ssl_ca != NULL) 296 free(s->ssl_ca); 297 if (s->ssl_dhparams != NULL) 298 free(s->ssl_dhparams); 299 if (s != NULL) 300 free(s); 301 return (0); 302 } 303 304 305 const char * 306 ssl_to_text(const SSL *ssl) 307 { 308 static char buf[256]; 309 310 snprintf(buf, sizeof buf, "version=%s, cipher=%s, bits=%i", 311 SSL_get_cipher_version(ssl), 312 SSL_get_cipher_name(ssl), 313 SSL_get_cipher_bits(ssl, NULL)); 314 315 return (buf); 316 } 317 318 void 319 ssl_error(const char *where) 320 { 321 unsigned long code; 322 char errbuf[128]; 323 extern int debug; 324 325 for (; (code = ERR_get_error()) != 0 ;) { 326 if (!debug) 327 continue; 328 ERR_error_string_n(code, errbuf, sizeof(errbuf)); 329 log_debug("debug: SSL library error: %s: %s", where, errbuf); 330 } 331 } 332 333 /* From OpenSSL's documentation: 334 * 335 * If "strong" primes were used to generate the DH parameters, it is 336 * not strictly necessary to generate a new key for each handshake 337 * but it does improve forward secrecy. 338 * 339 * -- gilles@ 340 */ 341 DH * 342 get_dh1024(void) 343 { 344 DH *dh; 345 unsigned char dh1024_p[] = { 346 0xAD,0x37,0xBB,0x26,0x75,0x01,0x27,0x75, 347 0x06,0xB5,0xE7,0x1E,0x1F,0x2B,0xBC,0x51, 348 0xC0,0xF4,0xEB,0x42,0x7A,0x2A,0x83,0x1E, 349 0xE8,0xD1,0xD8,0xCC,0x9E,0xE6,0x15,0x1D, 350 0x06,0x46,0x50,0x94,0xB9,0xEE,0xB6,0x89, 351 0xB7,0x3C,0xAC,0x07,0x5E,0x29,0x37,0xCC, 352 0x8F,0xDF,0x48,0x56,0x85,0x83,0x26,0x02, 353 0xB8,0xB6,0x63,0xAF,0x2D,0x4A,0x57,0x93, 354 0x6B,0x54,0xE1,0x8F,0x28,0x76,0x9C,0x5D, 355 0x90,0x65,0xD1,0x07,0xFE,0x5B,0x05,0x65, 356 0xDA,0xD2,0xE2,0xAF,0x23,0xCA,0x2F,0xD6, 357 0x4B,0xD2,0x04,0xFE,0xDF,0x21,0x2A,0xE1, 358 0xCD,0x1B,0x70,0x76,0xB3,0x51,0xA4,0xC9, 359 0x2B,0x68,0xE3,0xDD,0xCB,0x97,0xDA,0x59, 360 0x50,0x93,0xEE,0xDB,0xBF,0xC7,0xFA,0xA7, 361 0x47,0xC4,0x4D,0xF0,0xC6,0x09,0x4A,0x4B 362 }; 363 unsigned char dh1024_g[] = { 364 0x02 365 }; 366 367 if ((dh = DH_new()) == NULL) 368 return NULL; 369 370 dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL); 371 dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL); 372 if (dh->p == NULL || dh->g == NULL) { 373 DH_free(dh); 374 return NULL; 375 } 376 377 return dh; 378 } 379 380 DH * 381 get_dh_from_memory(char *params, size_t len) 382 { 383 BIO *mem; 384 DH *dh; 385 386 mem = BIO_new_mem_buf(params, len); 387 if (mem == NULL) 388 return NULL; 389 dh = PEM_read_bio_DHparams(mem, NULL, NULL, NULL); 390 if (dh == NULL) 391 goto err; 392 if (dh->p == NULL || dh->g == NULL) 393 goto err; 394 return dh; 395 396 err: 397 if (mem != NULL) 398 BIO_free(mem); 399 if (dh != NULL) 400 DH_free(dh); 401 return NULL; 402 } 403 404 405 void 406 ssl_set_ephemeral_key_exchange(SSL_CTX *ctx, DH *dh) 407 { 408 if (dh == NULL || !SSL_CTX_set_tmp_dh(ctx, dh)) { 409 ssl_error("ssl_set_ephemeral_key_exchange"); 410 fatal("ssl_set_ephemeral_key_exchange: cannot set tmp dh"); 411 } 412 } 413