1/* $NetBSD$ */ 2 3/*++ 4/* NAME 5/* tls_dh 6/* SUMMARY 7/* Diffie-Hellman parameter support 8/* SYNOPSIS 9/* #define TLS_INTERNAL 10/* #include <tls.h> 11/* 12/* void tls_set_dh_from_file(path, bits) 13/* const char *path; 14/* int bits; 15/* 16/* int tls_set_eecdh_curve(server_ctx, grade) 17/* SSL_CTX *server_ctx; 18/* const char *grade; 19/* 20/* DH *tls_tmp_dh_cb(ssl, export, keylength) 21/* SSL *ssl; /* unused */ 22/* int export; 23/* int keylength; 24/* DESCRIPTION 25/* This module maintains parameters for Diffie-Hellman key generation. 26/* 27/* tls_tmp_dh_cb() is a call-back routine for the 28/* SSL_CTX_set_tmp_dh_callback() function. 29/* 30/* tls_set_dh_from_file() overrides compiled-in DH parameters 31/* with those specified in the named files. The file format 32/* is as expected by the PEM_read_DHparams() routine. The 33/* "bits" argument must be 512 or 1024. 34/* 35/* tls_set_eecdh_curve() enables ephemeral Elliptic-Curve DH 36/* key exchange algorithms by instantiating in the server SSL 37/* context a suitable curve (corresponding to the specified 38/* EECDH security grade) from the set of named curves in RFC 39/* 4492 Section 5.1.1. Errors generate warnings, but do not 40/* disable TLS, rather we continue without EECDH. A zero 41/* result indicates that the grade is invalid or the corresponding 42/* curve could not be used. 43/* DIAGNOSTICS 44/* In case of error, tls_set_dh_from_file() logs a warning and 45/* ignores the request. 46/* LICENSE 47/* .ad 48/* .fi 49/* This software is free. You can do with it whatever you want. 50/* The original author kindly requests that you acknowledge 51/* the use of his software. 52/* AUTHOR(S) 53/* Originally written by: 54/* Lutz Jaenicke 55/* BTU Cottbus 56/* Allgemeine Elektrotechnik 57/* Universitaetsplatz 3-4 58/* D-03044 Cottbus, Germany 59/* 60/* Updated by: 61/* Wietse Venema 62/* IBM T.J. Watson Research 63/* P.O. Box 704 64/* Yorktown Heights, NY 10598, USA 65/*--*/ 66 67/* System library. */ 68 69#include <sys_defs.h> 70 71#ifdef USE_TLS 72#include <stdio.h> 73 74/* Utility library. */ 75 76#include <msg.h> 77 78 /* 79 * Global library 80 */ 81#include <mail_params.h> 82 83/* TLS library. */ 84 85#define TLS_INTERNAL 86#include <tls.h> 87 88/* Application-specific. */ 89 90 /* 91 * Compiled-in EDH primes (the compiled-in generator is always 2). These are 92 * used when no parameters are explicitly loaded from a site-specific file. 93 * 94 * 512-bit parameters are used for export ciphers, and 1024-bit parameters are 95 * used for non-export ciphers. An ~80-bit strong EDH key exchange is really 96 * too weak to protect 128+ bit keys, but larger DH primes are 97 * computationally expensive. When greater security is required, use EECDH. 98 */ 99 100 /* 101 * Generated via "openssl dhparam -2 -noout -C 512 2>/dev/null" TODO: 102 * generate at compile-time. 103 */ 104static unsigned char dh512_p[] = { 105 0x88, 0x3F, 0x00, 0xAF, 0xFC, 0x0C, 0x8A, 0xB8, 0x35, 0xCD, 0xE5, 0xC2, 106 0x0F, 0x55, 0xDF, 0x06, 0x3F, 0x16, 0x07, 0xBF, 0xCE, 0x13, 0x35, 0xE4, 107 0x1C, 0x1E, 0x03, 0xF3, 0xAB, 0x17, 0xF6, 0x63, 0x50, 0x63, 0x67, 0x3E, 108 0x10, 0xD7, 0x3E, 0xB4, 0xEB, 0x46, 0x8C, 0x40, 0x50, 0xE6, 0x91, 0xA5, 109 0x6E, 0x01, 0x45, 0xDE, 0xC9, 0xB1, 0x1F, 0x64, 0x54, 0xFA, 0xD9, 0xAB, 110 0x4F, 0x70, 0xBA, 0x5B, 111}; 112 113 /* 114 * Generated via "openssl dhparam -2 -noout -C 1024 2>/dev/null" TODO: 115 * generate at compile-time. 116 */ 117static unsigned char dh1024_p[] = { 118 0xB0, 0xFE, 0xB4, 0xCF, 0xD4, 0x55, 0x07, 0xE7, 0xCC, 0x88, 0x59, 0x0D, 119 0x17, 0x26, 0xC5, 0x0C, 0xA5, 0x4A, 0x92, 0x23, 0x81, 0x78, 0xDA, 0x88, 120 0xAA, 0x4C, 0x13, 0x06, 0xBF, 0x5D, 0x2F, 0x9E, 0xBC, 0x96, 0xB8, 0x51, 121 0x00, 0x9D, 0x0C, 0x0D, 0x75, 0xAD, 0xFD, 0x3B, 0xB1, 0x7E, 0x71, 0x4F, 122 0x3F, 0x91, 0x54, 0x14, 0x44, 0xB8, 0x30, 0x25, 0x1C, 0xEB, 0xDF, 0x72, 123 0x9C, 0x4C, 0xF1, 0x89, 0x0D, 0x68, 0x3F, 0x94, 0x8E, 0xA4, 0xFB, 0x76, 124 0x89, 0x18, 0xB2, 0x91, 0x16, 0x90, 0x01, 0x99, 0x66, 0x8C, 0x53, 0x81, 125 0x4E, 0x27, 0x3D, 0x99, 0xE7, 0x5A, 0x7A, 0xAF, 0xD5, 0xEC, 0xE2, 0x7E, 126 0xFA, 0xED, 0x01, 0x18, 0xC2, 0x78, 0x25, 0x59, 0x06, 0x5C, 0x39, 0xF6, 127 0xCD, 0x49, 0x54, 0xAF, 0xC1, 0xB1, 0xEA, 0x4A, 0xF9, 0x53, 0xD0, 0xDF, 128 0x6D, 0xAF, 0xD4, 0x93, 0xE7, 0xBA, 0xAE, 0x9B, 129}; 130 131 /* 132 * Cached results. 133 */ 134static DH *dh_1024 = 0; 135static DH *dh_512 = 0; 136 137/* tls_set_dh_from_file - set Diffie-Hellman parameters from file */ 138 139void tls_set_dh_from_file(const char *path, int bits) 140{ 141 FILE *paramfile; 142 DH **dhPtr; 143 144 switch (bits) { 145 case 512: 146 dhPtr = &dh_512; 147 break; 148 case 1024: 149 dhPtr = &dh_1024; 150 break; 151 default: 152 msg_panic("Invalid DH parameters size %d, file %s", bits, path); 153 } 154 155 if ((paramfile = fopen(path, "r")) != 0) { 156 if ((*dhPtr = PEM_read_DHparams(paramfile, 0, 0, 0)) == 0) { 157 msg_warn("cannot load %d-bit DH parameters from file %s" 158 " -- using compiled-in defaults", bits, path); 159 tls_print_errors(); 160 } 161 (void) fclose(paramfile); /* 200411 */ 162 } else { 163 msg_warn("cannot load %d-bit DH parameters from file %s: %m" 164 " -- using compiled-in defaults", bits, path); 165 } 166} 167 168/* tls_get_dh - get compiled-in DH parameters */ 169 170static DH *tls_get_dh(const unsigned char *p, int plen) 171{ 172 DH *dh; 173 static unsigned char g[] = {0x02,}; 174 175 /* Use the compiled-in parameters. */ 176 if ((dh = DH_new()) == 0) { 177 msg_warn("cannot create DH parameter set: %m"); /* 200411 */ 178 return (0); 179 } 180 dh->p = BN_bin2bn(p, plen, (BIGNUM *) 0); 181 dh->g = BN_bin2bn(g, 1, (BIGNUM *) 0); 182 if ((dh->p == 0) || (dh->g == 0)) { 183 msg_warn("cannot load compiled-in DH parameters"); /* 200411 */ 184 DH_free(dh); /* 200411 */ 185 return (0); 186 } 187 return (dh); 188} 189 190/* tls_tmp_dh_cb - call-back for Diffie-Hellman parameters */ 191 192DH *tls_tmp_dh_cb(SSL *unused_ssl, int export, int keylength) 193{ 194 DH *dh_tmp; 195 196 if (export && keylength == 512) { /* 40-bit export cipher */ 197 if (dh_512 == 0) 198 dh_512 = tls_get_dh(dh512_p, (int) sizeof(dh512_p)); 199 dh_tmp = dh_512; 200 } else { /* ADH, DHE-RSA or DSA */ 201 if (dh_1024 == 0) 202 dh_1024 = tls_get_dh(dh1024_p, (int) sizeof(dh1024_p)); 203 dh_tmp = dh_1024; 204 } 205 return (dh_tmp); 206} 207 208int tls_set_eecdh_curve(SSL_CTX *server_ctx, const char *grade) 209{ 210#if OPENSSL_VERSION_NUMBER >= 0x1000000fL && !defined(OPENSSL_NO_ECDH) 211 int nid; 212 EC_KEY *ecdh; 213 const char *curve; 214 int g; 215 216#define TLS_EECDH_INVALID 0 217#define TLS_EECDH_NONE 1 218#define TLS_EECDH_STRONG 2 219#define TLS_EECDH_ULTRA 3 220 static NAME_CODE eecdh_table[] = { 221 "none", TLS_EECDH_NONE, 222 "strong", TLS_EECDH_STRONG, 223 "ultra", TLS_EECDH_ULTRA, 224 0, TLS_EECDH_INVALID, 225 }; 226 227 switch (g = name_code(eecdh_table, NAME_CODE_FLAG_NONE, grade)) { 228 default: 229 msg_panic("Invalid eecdh grade code: %d", g); 230 case TLS_EECDH_INVALID: 231 msg_warn("Invalid TLS eecdh grade \"%s\": EECDH disabled", grade); 232 return (0); 233 case TLS_EECDH_NONE: 234 return (1); 235 case TLS_EECDH_STRONG: 236 curve = var_tls_eecdh_strong; 237 break; 238 case TLS_EECDH_ULTRA: 239 curve = var_tls_eecdh_ultra; 240 break; 241 } 242 243 /* 244 * Elliptic-Curve Diffie-Hellman parameters are either "named curves" 245 * from RFC 4492 section 5.1.1, or explicitly described curves over 246 * binary fields. OpenSSL only supports the "named curves", which provide 247 * maximum interoperability. The recommended curve for 128-bit 248 * work-factor key exchange is "prime256v1" a.k.a. "secp256r1" from 249 * Section 2.7 of http://www.secg.org/download/aid-386/sec2_final.pdf 250 */ 251 252 if ((nid = OBJ_sn2nid(curve)) == NID_undef) { 253 msg_warn("unknown curve \"%s\": disabling EECDH support", curve); 254 return (0); 255 } 256 ERR_clear_error(); 257 if ((ecdh = EC_KEY_new_by_curve_name(nid)) == 0 258 || SSL_CTX_set_tmp_ecdh(server_ctx, ecdh) == 0) { 259 msg_warn("unable to use curve \"%s\": disabling EECDH support", curve); 260 tls_print_errors(); 261 return (0); 262 } 263#endif 264 return (1); 265} 266 267#ifdef TEST 268 269int main(int unused_argc, char **unused_argv) 270{ 271 tls_tmp_dh_cb(0, 1, 512); 272 tls_tmp_dh_cb(0, 1, 1024); 273 tls_tmp_dh_cb(0, 1, 2048); 274 tls_tmp_dh_cb(0, 0, 512); 275 return (0); 276} 277 278#endif 279 280#endif 281