DH * dh_new_group_asc(const char *gen, const char *modulus) { DH *dh = NULL; BIGNUM *p=NULL, *g=NULL; if ((dh = DH_new()) == NULL || (p = BN_new()) == NULL || (g = BN_new()) == NULL) goto null; if (BN_hex2bn(&p, modulus) == 0 || BN_hex2bn(&g, gen) == 0) { goto null; } if (DH_set0_pqg(dh, p, NULL, g) == 0) { goto null; } p = g = NULL; return (dh); null: BN_free(p); BN_free(g); DH_free(dh); return NULL; }
tr_dh_ctx_t tr_dh_new (const uint8_t * prime_num, size_t prime_num_length, const uint8_t * generator_num, size_t generator_num_length) { DH * handle = DH_new (); BIGNUM * p, * g; assert (prime_num != NULL); assert (generator_num != NULL); p = BN_bin2bn (prime_num, prime_num_length, NULL); g = BN_bin2bn (generator_num, generator_num_length, NULL); if (!check_pointer (p) || !check_pointer (g) || !DH_set0_pqg (handle, p, NULL, g)) { BN_free (p); BN_free (g); DH_free (handle); handle = NULL; } return handle; }
bool diffie_hellman::compute_shared_key( const char* buf, uint32_t s ) { ssl_dh dh = DH_new(); #if OPENSSL_VERSION_NUMBER >= 0x10100000L auto bn_p = BN_bin2bn( (unsigned char*)&p.front(), p.size(), NULL ); auto bn_pub_key = BN_bin2bn( (unsigned char*)&pub_key.front(), pub_key.size(), NULL ); auto bn_priv_key = BN_bin2bn( (unsigned char*)&priv_key.front(), priv_key.size(), NULL ); auto bn_g = BN_bin2bn( (unsigned char*)&g, 1, NULL ); DH_set0_pqg(dh.obj, bn_p, NULL, bn_g); DH_set0_key(dh.obj, bn_pub_key, bn_priv_key); #else dh->p = BN_bin2bn( (unsigned char*)&p.front(), p.size(), NULL ); dh->pub_key = BN_bin2bn( (unsigned char*)&pub_key.front(), pub_key.size(), NULL ); dh->priv_key = BN_bin2bn( (unsigned char*)&priv_key.front(), priv_key.size(), NULL ); dh->g = BN_bin2bn( (unsigned char*)&g, 1, NULL ); #endif int check; DH_check(dh,&check); if( !fc::validate( dh, valid ) ) { return false; } ssl_bignum pk; BN_bin2bn( (unsigned char*)buf, s, pk ); shared_key.resize( DH_size(dh) ); DH_compute_key( (unsigned char*)&shared_key.front(), pk, dh ); return true; }
ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (OthersPublicKey, MyPrivateKey, DHParams=[P,G]) */ BIGNUM *other_pub_key = NULL, *dh_p = NULL, *dh_g = NULL; DH *dh_priv = DH_new(); /* Check the arguments and get my private key (dh_priv), the peer's public key (other_pub_key), the parameters p & q */ { BIGNUM *dummy_pub_key = NULL, *priv_key = NULL; ERL_NIF_TERM head, tail; if (!get_bn_from_bin(env, argv[0], &other_pub_key) || !get_bn_from_bin(env, argv[1], &priv_key) || !enif_get_list_cell(env, argv[2], &head, &tail) || !get_bn_from_bin(env, head, &dh_p) || !enif_get_list_cell(env, tail, &head, &tail) || !get_bn_from_bin(env, head, &dh_g) || !enif_is_empty_list(env, tail) /* Note: DH_set0_key() does not allow setting only the * private key, although DH_compute_key() does not use the * public key. Work around this limitation by setting * the public key to a copy of the private key. */ || !(dummy_pub_key = BN_dup(priv_key)) || !DH_set0_key(dh_priv, dummy_pub_key, priv_key) || !DH_set0_pqg(dh_priv, dh_p, NULL, dh_g) ) { if (dh_p) BN_free(dh_p); if (dh_g) BN_free(dh_g); if (other_pub_key) BN_free(other_pub_key); if (dummy_pub_key) BN_free(dummy_pub_key); if (priv_key) BN_free(priv_key); return enif_make_badarg(env); } } { ErlNifBinary ret_bin; int size; enif_alloc_binary(DH_size(dh_priv), &ret_bin); size = DH_compute_key(ret_bin.data, other_pub_key, dh_priv); BN_free(other_pub_key); DH_free(dh_priv); if (size<=0) { enif_release_binary(&ret_bin); return atom_error; } if (size != ret_bin.size) enif_realloc_binary(&ret_bin, size); return enif_make_binary(env, &ret_bin); } }
static int s2n_set_p_g_Ys_dh_params(struct s2n_dh_params *dh_params, struct s2n_blob *p, struct s2n_blob *g, struct s2n_blob *Ys) { BIGNUM *bn_p = BN_bin2bn((const unsigned char *)p->data, p->size, NULL); BIGNUM *bn_g = BN_bin2bn((const unsigned char *)g->data, g->size, NULL); BIGNUM *bn_Ys = BN_bin2bn((const unsigned char *)Ys->data, Ys->size, NULL); #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined LIBRESSL_VERSION_NUMBER dh_params->dh->p = bn_p; dh_params->dh->g = bn_g; dh_params->dh->pub_key = bn_Ys; #else if (DH_set0_pqg(dh_params->dh, bn_p, NULL, bn_g) == 0) { /* Per https://www.openssl.org/docs/man1.1.0/crypto/DH_get0_pqg.html: * values that have been passed in should not be freed directly after this function has been called */ S2N_ERROR(S2N_ERR_DH_PARAMS_CREATE); } if (DH_set0_key(dh_params->dh, bn_Ys, NULL) == 0) { /* Same as DH_set0_pqg */ S2N_ERROR(S2N_ERR_DH_PARAMS_CREATE); } #endif return 0; }
// Create the OpenSSL representation of the key void OSSLDHPublicKey::createOSSLKey() { if (dh != NULL) return; dh = DH_new(); if (dh == NULL) { ERROR_MSG("Could not create DH object"); return; } // Use the OpenSSL implementation and not any engine #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) #ifdef WITH_FIPS if (FIPS_mode()) DH_set_method(dh, FIPS_dh_openssl()); else DH_set_method(dh, DH_OpenSSL()); #else DH_set_method(dh, DH_OpenSSL()); #endif #else DH_set_method(dh, DH_OpenSSL()); #endif BIGNUM* bn_p = OSSL::byteString2bn(p); BIGNUM* bn_g = OSSL::byteString2bn(g); BIGNUM* bn_pub_key = OSSL::byteString2bn(y); DH_set0_pqg(dh, bn_p, NULL, bn_g); DH_set0_key(dh, bn_pub_key, NULL); }
static void setup_dh(SSL_CTX *ctx) { DH *dh; BIGNUM *p; BIGNUM *g; dh = DH_new(); if (dh == NULL) { return; } p = BN_bin2bn(dh3072_p, sizeof(dh3072_p), NULL); g = BN_bin2bn(dh3072_g, sizeof(dh3072_g), NULL); if (p == NULL || g == NULL) { DH_free(dh); return; } #if (OPENSSL_VERSION_NUMBER >= 0x1010000fL) /* libssl >= v1.1.0 */ DH_set0_pqg(dh, p, NULL, g); #else dh->p = p; dh->g = g; #endif SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE); SSL_CTX_set_tmp_dh(ctx, dh); DH_free(dh); }
static DH * get_rfc5114_modp(int num) { DH *ret = NULL; BIGNUM *p = NULL, *g = NULL, *q = NULL; int check = 0; ret = DH_new(); if (!ret) goto err; switch(num) { case 0: p = BN_bin2bn(rfc_5114_modp_1_p, sizeof(rfc_5114_modp_1_p), p); g = BN_bin2bn(rfc_5114_modp_1_g, sizeof(rfc_5114_modp_1_g), g); q = BN_bin2bn(rfc_5114_modp_1_q, sizeof(rfc_5114_modp_1_q), q); break; case 1: p = BN_bin2bn(rfc_5114_modp_2_p, sizeof(rfc_5114_modp_2_p), p); g = BN_bin2bn(rfc_5114_modp_2_g, sizeof(rfc_5114_modp_2_g), g); q = BN_bin2bn(rfc_5114_modp_2_q, sizeof(rfc_5114_modp_2_q), q); break; case 2: p = BN_bin2bn(rfc_5114_modp_3_p, sizeof(rfc_5114_modp_3_p), p); g = BN_bin2bn(rfc_5114_modp_3_g, sizeof(rfc_5114_modp_3_g), g); q = BN_bin2bn(rfc_5114_modp_3_q, sizeof(rfc_5114_modp_3_q), q); break; default: log_err("Invalid arguments"); goto err; } if (!p || !g || !q) goto err; if (!DH_set0_pqg(ret, p, q, g)) goto err; /* Perform some checks. OpenSSL only knows generators 2 and 5, so the * DH_UNABLE_TO_CHECK_GENERATOR will be set, but the prime should be safe * nevertheless */ if (!DH_check(ret, &check)) goto err; if (check & DH_CHECK_P_NOT_PRIME) goto err; return ret; err: if (ret) DH_free(ret); if (p) BN_free(p); if (g) BN_free(g); if (q) BN_free(q); return NULL; }
DH *DSA_dup_DH(const DSA *r) { /* * DSA has p, q, g, optional pub_key, optional priv_key. DH has p, * optional length, g, optional pub_key, optional priv_key, optional q. */ DH *ret = NULL; BIGNUM *p = NULL, *q = NULL, *g = NULL, *pub_key = NULL, *priv_key = NULL; if (r == NULL) goto err; ret = DH_new(); if (ret == NULL) goto err; if (r->p != NULL || r->g != NULL || r->q != NULL) { if (r->p == NULL || r->g == NULL || r->q == NULL) { /* Shouldn't happen */ goto err; } p = BN_dup(r->p); g = BN_dup(r->g); q = BN_dup(r->q); if (p == NULL || g == NULL || q == NULL || !DH_set0_pqg(ret, p, q, g)) goto err; p = g = q = NULL; } if (r->pub_key != NULL) { pub_key = BN_dup(r->pub_key); if (pub_key == NULL) goto err; if (r->priv_key != NULL) { priv_key = BN_dup(r->priv_key); if (priv_key == NULL) goto err; } if (!DH_set0_key(ret, pub_key, priv_key)) goto err; } else if (r->priv_key != NULL) { /* Shouldn't happen */ goto err; } return ret; err: BN_free(p); BN_free(g); BN_free(q); BN_free(pub_key); BN_free(priv_key); DH_free(ret); return NULL; }
DH * DHparams_dup_with_q(DH *dh) { const BIGNUM *p, *q, *g; DH *dup = DHparams_dup(dh); DH_get0_pqg(dh, &p, &q, &g); DH_set0_pqg(dup, BN_dup(p), BN_dup(q), BN_dup(g)); return dup; }
DH * dh_new_group(BIGNUM *gen, BIGNUM *modulus) { DH *dh; if ((dh = DH_new()) == NULL) return NULL; if (DH_set0_pqg(dh, modulus, NULL, gen) == 0) return NULL; return (dh); }
DH *get_dh2048() { static unsigned char dhp_2048[] = { 0x89, 0x9D, 0x84, 0xB8, 0x3A, 0x2D, 0xD4, 0xF7, 0x41, 0x5A, 0xBB, 0x27, 0x00, 0x69, 0xAE, 0xB4, 0xAC, 0x5E, 0xD8, 0xEB, 0xAE, 0x3D, 0x0E, 0x1A, 0x05, 0xD5, 0xE5, 0xEF, 0x2B, 0x8E, 0x4F, 0xF3, 0x65, 0x3C, 0xE3, 0x40, 0x6B, 0xFB, 0xA7, 0x24, 0x58, 0x85, 0xE4, 0xFA, 0x86, 0x0D, 0xED, 0x8D, 0xBF, 0xA0, 0x4D, 0x58, 0xC9, 0x30, 0x26, 0x3B, 0xF0, 0x1E, 0xAF, 0x15, 0x6F, 0x4E, 0x71, 0x2D, 0xF1, 0x67, 0xED, 0x44, 0x8C, 0x04, 0x04, 0x23, 0xE4, 0xA8, 0x5B, 0x7B, 0x28, 0x32, 0x0D, 0x67, 0xBB, 0x7E, 0xE5, 0x1B, 0x58, 0x6F, 0x0C, 0x3C, 0x0A, 0x8A, 0x3E, 0xC8, 0x8A, 0x10, 0xCA, 0x74, 0x94, 0x6E, 0xC8, 0xC0, 0x52, 0x9C, 0xE5, 0x45, 0xE7, 0x0A, 0x78, 0x9B, 0x30, 0x60, 0x70, 0xEA, 0xF2, 0xEF, 0xB6, 0xD5, 0x28, 0x2F, 0xA1, 0x92, 0xA6, 0x94, 0x45, 0x03, 0x5A, 0x8F, 0xF3, 0x17, 0x93, 0x99, 0x28, 0x1B, 0x9C, 0xE1, 0x3F, 0x96, 0x4E, 0x95, 0x62, 0x72, 0x79, 0x8E, 0xD9, 0xE6, 0x42, 0xEF, 0xF5, 0x46, 0xBF, 0xB3, 0x2B, 0x23, 0x5D, 0xEF, 0x11, 0x18, 0x81, 0x85, 0xBB, 0xD9, 0xD1, 0x32, 0x96, 0xEE, 0x98, 0x8C, 0x14, 0x6E, 0x57, 0x68, 0xAD, 0x5B, 0xE0, 0xF4, 0x7A, 0x75, 0x9E, 0x8D, 0xB0, 0x18, 0x9A, 0xFD, 0x1E, 0x0C, 0xD9, 0x23, 0x4B, 0xF1, 0xF3, 0x92, 0xD8, 0x23, 0x41, 0xE0, 0xEC, 0x94, 0xDE, 0xF3, 0x34, 0x87, 0xF6, 0x87, 0x35, 0xF4, 0x48, 0x9B, 0xB7, 0x3B, 0x4E, 0xCD, 0x1A, 0x8D, 0xFC, 0x5A, 0xD1, 0x39, 0x41, 0x33, 0x66, 0xE2, 0x06, 0xEE, 0x2C, 0x1B, 0x5F, 0x5C, 0xB2, 0xF2, 0xB3, 0xBA, 0xA3, 0x58, 0x8B, 0xF2, 0xD2, 0x9A, 0xAF, 0x03, 0xA2, 0x84, 0x7D, 0xA1, 0xAA, 0x23, 0x3A, 0x7B, 0xE2, 0xF8, 0xAF, 0xA6, 0xE3, 0x5B, 0xCE, 0x25, 0x68, 0x7B }; static unsigned char dhg_2048[] = { 0x02 }; DH *dh = DH_new(); BIGNUM *dhp_bn, *dhg_bn; if (dh == NULL) return NULL; dhp_bn = BN_bin2bn(dhp_2048, sizeof (dhp_2048), NULL); dhg_bn = BN_bin2bn(dhg_2048, sizeof (dhg_2048), NULL); if (dhp_bn == NULL || dhg_bn == NULL || !DH_set0_pqg(dh, dhp_bn, NULL, dhg_bn)) { DH_free(dh); BN_free(dhp_bn); BN_free(dhg_bn); return NULL; } return dh; }
bool diffie_hellman::validate() { if( !p.size() ) return valid = false; ssl_dh dh = DH_new(); #if OPENSSL_VERSION_NUMBER >= 0x10100000L const auto bn_p = BN_bin2bn( (unsigned char*)&p.front(), p.size(), NULL ); const auto bn_g = BN_bin2bn( (unsigned char*)&g, 1, NULL ); DH_set0_pqg(dh.obj, bn_p, NULL, bn_g); #else dh->p = BN_bin2bn( (unsigned char*)&p.front(), p.size(), NULL ); dh->g = BN_bin2bn( (unsigned char*)&g, 1, NULL ); #endif return fc::validate( dh, valid ); }
/** Sets generator and prime parameters for DH. Given generator g, and prime number p, this function and sets DH context accordingly. If DhContext is NULL, then return FALSE. If Prime is NULL, then return FALSE. @param[in, out] DhContext Pointer to the DH context. @param[in] Generator Value of generator. @param[in] PrimeLength Length in bits of prime to be generated. @param[in] Prime Pointer to the prime number. @retval TRUE DH parameter setting succeeded. @retval FALSE Value of Generator is not supported. @retval FALSE Value of Generator is not suitable for the Prime. @retval FALSE Value of Prime is not a prime number. @retval FALSE Value of Prime is not a safe prime number. **/ BOOLEAN EFIAPI DhSetParameter ( IN OUT VOID *DhContext, IN UINTN Generator, IN UINTN PrimeLength, IN CONST UINT8 *Prime ) { DH *Dh; BIGNUM *BnP; BIGNUM *BnG; // // Check input parameters. // if (DhContext == NULL || Prime == NULL || PrimeLength > INT_MAX) { return FALSE; } if (Generator != DH_GENERATOR_2 && Generator != DH_GENERATOR_5) { return FALSE; } // // Set the generator and prime parameters for DH object. // Dh = (DH *)DhContext; BnP = BN_bin2bn ((const unsigned char *)Prime, (int)(PrimeLength / 8), NULL); BnG = BN_bin2bn ((const unsigned char *)&Generator, 1, NULL); if ((BnP == NULL) || (BnG == NULL) || !DH_set0_pqg (Dh, BnP, NULL, BnG)) { goto Error; } return TRUE; Error: BN_free (BnP); BN_free (BnG); return FALSE; }
bool diffie_hellman::generate_pub_key() { if( !p.size() ) return valid = false; ssl_dh dh = DH_new(); #if OPENSSL_VERSION_NUMBER >= 0x10100000L const auto bn_p = BN_bin2bn( (unsigned char*)&p.front(), p.size(), NULL ); const auto bn_g = BN_bin2bn( (unsigned char*)&g, 1, NULL ); DH_set0_pqg(dh.obj, bn_p, NULL, bn_g); #else dh->p = BN_bin2bn( (unsigned char*)&p.front(), p.size(), NULL ); dh->g = BN_bin2bn( (unsigned char*)&g, 1, NULL ); #endif if( !fc::validate( dh, valid ) ) { return false; } DH_generate_key(dh); #if OPENSSL_VERSION_NUMBER >= 0x10100000L ssl_bignum bn_pub_key; ssl_bignum bn_priv_key; DH_get0_key(dh.obj, (const BIGNUM**)&bn_pub_key.obj, (const BIGNUM**)&bn_priv_key.obj); pub_key.resize( BN_num_bytes( bn_pub_key ) ); priv_key.resize( BN_num_bytes( bn_priv_key ) ); if( pub_key.size() ) BN_bn2bin( bn_pub_key.obj, (unsigned char*)&pub_key.front() ); if( priv_key.size() ) BN_bn2bin( bn_priv_key.obj, (unsigned char*)&priv_key.front() ); #else pub_key.resize( BN_num_bytes( dh->pub_key ) ); priv_key.resize( BN_num_bytes( dh->priv_key ) ); if( pub_key.size() ) BN_bn2bin( dh->pub_key, (unsigned char*)&pub_key.front() ); if( priv_key.size() ) BN_bn2bin( dh->priv_key, (unsigned char*)&priv_key.front() ); #endif return true; }
int network_init(server *srv) { buffer *b; size_t i, j; network_backend_t backend; #if OPENSSL_VERSION_NUMBER >= 0x0090800fL #ifndef OPENSSL_NO_ECDH EC_KEY *ecdh; int nid; #endif #endif #ifdef USE_OPENSSL # ifndef OPENSSL_NO_DH DH *dh; # endif BIO *bio; /* 1024-bit MODP Group with 160-bit prime order subgroup (RFC5114) * -----BEGIN DH PARAMETERS----- * MIIBDAKBgQCxC4+WoIDgHd6S3l6uXVTsUsmfvPsGo8aaap3KUtI7YWBz4oZ1oj0Y * mDjvHi7mUsAT7LSuqQYRIySXXDzUm4O/rMvdfZDEvXCYSI6cIZpzck7/1vrlZEc4 * +qMaT/VbzMChUa9fDci0vUW/N982XBpl5oz9p21NpwjfH7K8LkpDcQKBgQCk0cvV * w/00EmdlpELvuZkF+BBN0lisUH/WQGz/FCZtMSZv6h5cQVZLd35pD1UE8hMWAhe0 * sBuIal6RVH+eJ0n01/vX07mpLuGQnQ0iY/gKdqaiTAh6CR9THb8KAWm2oorWYqTR * jnOvoy13nVkY0IvIhY9Nzvl8KiSFXm7rIrOy5QICAKA= * -----END DH PARAMETERS----- */ static const unsigned char dh1024_p[]={ 0xB1,0x0B,0x8F,0x96,0xA0,0x80,0xE0,0x1D,0xDE,0x92,0xDE,0x5E, 0xAE,0x5D,0x54,0xEC,0x52,0xC9,0x9F,0xBC,0xFB,0x06,0xA3,0xC6, 0x9A,0x6A,0x9D,0xCA,0x52,0xD2,0x3B,0x61,0x60,0x73,0xE2,0x86, 0x75,0xA2,0x3D,0x18,0x98,0x38,0xEF,0x1E,0x2E,0xE6,0x52,0xC0, 0x13,0xEC,0xB4,0xAE,0xA9,0x06,0x11,0x23,0x24,0x97,0x5C,0x3C, 0xD4,0x9B,0x83,0xBF,0xAC,0xCB,0xDD,0x7D,0x90,0xC4,0xBD,0x70, 0x98,0x48,0x8E,0x9C,0x21,0x9A,0x73,0x72,0x4E,0xFF,0xD6,0xFA, 0xE5,0x64,0x47,0x38,0xFA,0xA3,0x1A,0x4F,0xF5,0x5B,0xCC,0xC0, 0xA1,0x51,0xAF,0x5F,0x0D,0xC8,0xB4,0xBD,0x45,0xBF,0x37,0xDF, 0x36,0x5C,0x1A,0x65,0xE6,0x8C,0xFD,0xA7,0x6D,0x4D,0xA7,0x08, 0xDF,0x1F,0xB2,0xBC,0x2E,0x4A,0x43,0x71, }; static const unsigned char dh1024_g[]={ 0xA4,0xD1,0xCB,0xD5,0xC3,0xFD,0x34,0x12,0x67,0x65,0xA4,0x42, 0xEF,0xB9,0x99,0x05,0xF8,0x10,0x4D,0xD2,0x58,0xAC,0x50,0x7F, 0xD6,0x40,0x6C,0xFF,0x14,0x26,0x6D,0x31,0x26,0x6F,0xEA,0x1E, 0x5C,0x41,0x56,0x4B,0x77,0x7E,0x69,0x0F,0x55,0x04,0xF2,0x13, 0x16,0x02,0x17,0xB4,0xB0,0x1B,0x88,0x6A,0x5E,0x91,0x54,0x7F, 0x9E,0x27,0x49,0xF4,0xD7,0xFB,0xD7,0xD3,0xB9,0xA9,0x2E,0xE1, 0x90,0x9D,0x0D,0x22,0x63,0xF8,0x0A,0x76,0xA6,0xA2,0x4C,0x08, 0x7A,0x09,0x1F,0x53,0x1D,0xBF,0x0A,0x01,0x69,0xB6,0xA2,0x8A, 0xD6,0x62,0xA4,0xD1,0x8E,0x73,0xAF,0xA3,0x2D,0x77,0x9D,0x59, 0x18,0xD0,0x8B,0xC8,0x85,0x8F,0x4D,0xCE,0xF9,0x7C,0x2A,0x24, 0x85,0x5E,0x6E,0xEB,0x22,0xB3,0xB2,0xE5, }; #endif struct nb_map { network_backend_t nb; const char *name; } network_backends[] = { /* lowest id wins */ #if defined USE_SENDFILE { NETWORK_BACKEND_SENDFILE, "sendfile" }, #endif #if defined USE_LINUX_SENDFILE { NETWORK_BACKEND_SENDFILE, "linux-sendfile" }, #endif #if defined USE_FREEBSD_SENDFILE { NETWORK_BACKEND_SENDFILE, "freebsd-sendfile" }, #endif #if defined USE_SOLARIS_SENDFILEV { NETWORK_BACKEND_SENDFILE, "solaris-sendfilev" }, #endif #if defined USE_WRITEV { NETWORK_BACKEND_WRITEV, "writev" }, #endif { NETWORK_BACKEND_WRITE, "write" }, { NETWORK_BACKEND_UNSET, NULL } }; #ifdef USE_OPENSSL /* load SSL certificates */ for (i = 0; i < srv->config_context->used; i++) { specific_config *s = srv->config_storage[i]; #ifndef SSL_OP_NO_COMPRESSION # define SSL_OP_NO_COMPRESSION 0 #endif long ssloptions = SSL_OP_ALL | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_NO_COMPRESSION; if (buffer_string_is_empty(s->ssl_pemfile) && buffer_string_is_empty(s->ssl_ca_file)) continue; if (srv->ssl_is_init == 0) { SSL_load_error_strings(); SSL_library_init(); OpenSSL_add_all_algorithms(); srv->ssl_is_init = 1; if (0 == RAND_status()) { log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", "not enough entropy in the pool"); return -1; } } if (!buffer_string_is_empty(s->ssl_pemfile)) { #ifdef OPENSSL_NO_TLSEXT data_config *dc = (data_config *)srv->config_context->data[i]; if (COMP_HTTP_HOST == dc->comp) { log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", "can't use ssl.pemfile with $HTTP[\"host\"], openssl version does not support TLS extensions"); return -1; } #endif if (network_openssl_load_pemfile(srv, i)) return -1; } if (!buffer_string_is_empty(s->ssl_ca_file)) { s->ssl_ca_file_cert_names = SSL_load_client_CA_file(s->ssl_ca_file->ptr); if (NULL == s->ssl_ca_file_cert_names) { log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_file); } } if (buffer_string_is_empty(s->ssl_pemfile) || !s->ssl_enabled) continue; if (NULL == (s->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) { log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", ERR_error_string(ERR_get_error(), NULL)); return -1; } /* completely useless identifier; required for client cert verification to work with sessions */ if (0 == SSL_CTX_set_session_id_context(s->ssl_ctx, (const unsigned char*) CONST_STR_LEN("lighttpd"))) { log_error_write(srv, __FILE__, __LINE__, "ss:s", "SSL:", "failed to set session context", ERR_error_string(ERR_get_error(), NULL)); return -1; } if (s->ssl_empty_fragments) { #ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS ssloptions &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; #else ssloptions &= ~0x00000800L; /* hardcode constant */ log_error_write(srv, __FILE__, __LINE__, "ss", "WARNING: SSL:", "'insert empty fragments' not supported by the openssl version used to compile lighttpd with"); #endif } SSL_CTX_set_options(s->ssl_ctx, ssloptions); SSL_CTX_set_info_callback(s->ssl_ctx, ssl_info_callback); if (!s->ssl_use_sslv2) { /* disable SSLv2 */ if ((SSL_OP_NO_SSLv2 & SSL_CTX_set_options(s->ssl_ctx, SSL_OP_NO_SSLv2)) != SSL_OP_NO_SSLv2) { log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", ERR_error_string(ERR_get_error(), NULL)); return -1; } } if (!s->ssl_use_sslv3) { /* disable SSLv3 */ if ((SSL_OP_NO_SSLv3 & SSL_CTX_set_options(s->ssl_ctx, SSL_OP_NO_SSLv3)) != SSL_OP_NO_SSLv3) { log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", ERR_error_string(ERR_get_error(), NULL)); return -1; } } if (!buffer_string_is_empty(s->ssl_cipher_list)) { /* Disable support for low encryption ciphers */ if (SSL_CTX_set_cipher_list(s->ssl_ctx, s->ssl_cipher_list->ptr) != 1) { log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", ERR_error_string(ERR_get_error(), NULL)); return -1; } if (s->ssl_honor_cipher_order) { SSL_CTX_set_options(s->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); } } #ifndef OPENSSL_NO_DH /* Support for Diffie-Hellman key exchange */ if (!buffer_string_is_empty(s->ssl_dh_file)) { /* DH parameters from file */ bio = BIO_new_file((char *) s->ssl_dh_file->ptr, "r"); if (bio == NULL) { log_error_write(srv, __FILE__, __LINE__, "ss", "SSL: Unable to open file", s->ssl_dh_file->ptr); return -1; } dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); BIO_free(bio); if (dh == NULL) { log_error_write(srv, __FILE__, __LINE__, "ss", "SSL: PEM_read_bio_DHparams failed", s->ssl_dh_file->ptr); return -1; } } else { BIGNUM *dh_p, *dh_g; /* Default DH parameters from RFC5114 */ dh = DH_new(); if (dh == NULL) { log_error_write(srv, __FILE__, __LINE__, "s", "SSL: DH_new () failed"); return -1; } dh_p = BN_bin2bn(dh1024_p,sizeof(dh1024_p), NULL); dh_g = BN_bin2bn(dh1024_g,sizeof(dh1024_g), NULL); if ((dh_p == NULL) || (dh_g == NULL)) { DH_free(dh); log_error_write(srv, __FILE__, __LINE__, "s", "SSL: BN_bin2bn () failed"); return -1; } #if OPENSSL_VERSION_NUMBER < 0x10100000L \ || defined(LIBRESSL_VERSION_NUMBER) dh->p = dh_p; dh->g = dh_g; dh->length = 160; #else DH_set0_pqg(dh, dh_p, NULL, dh_g); DH_set_length(dh, 160); #endif } SSL_CTX_set_tmp_dh(s->ssl_ctx,dh); SSL_CTX_set_options(s->ssl_ctx,SSL_OP_SINGLE_DH_USE); DH_free(dh); #else if (!buffer_string_is_empty(s->ssl_dh_file)) { log_error_write(srv, __FILE__, __LINE__, "ss", "SSL: openssl compiled without DH support, can't load parameters from", s->ssl_dh_file->ptr); } #endif #if OPENSSL_VERSION_NUMBER >= 0x0090800fL #ifndef OPENSSL_NO_ECDH /* Support for Elliptic-Curve Diffie-Hellman key exchange */ if (!buffer_string_is_empty(s->ssl_ec_curve)) { /* OpenSSL only supports the "named curves" from RFC 4492, section 5.1.1. */ nid = OBJ_sn2nid((char *) s->ssl_ec_curve->ptr); if (nid == 0) { log_error_write(srv, __FILE__, __LINE__, "ss", "SSL: Unknown curve name", s->ssl_ec_curve->ptr); return -1; } } else { /* Default curve */ nid = OBJ_sn2nid("prime256v1"); } ecdh = EC_KEY_new_by_curve_name(nid); if (ecdh == NULL) { log_error_write(srv, __FILE__, __LINE__, "ss", "SSL: Unable to create curve", s->ssl_ec_curve->ptr); return -1; } SSL_CTX_set_tmp_ecdh(s->ssl_ctx,ecdh); SSL_CTX_set_options(s->ssl_ctx,SSL_OP_SINGLE_ECDH_USE); EC_KEY_free(ecdh); #endif #endif /* load all ssl.ca-files specified in the config into each SSL_CTX to be prepared for SNI */ for (j = 0; j < srv->config_context->used; j++) { specific_config *s1 = srv->config_storage[j]; if (!buffer_string_is_empty(s1->ssl_ca_file)) { if (1 != SSL_CTX_load_verify_locations(s->ssl_ctx, s1->ssl_ca_file->ptr, NULL)) { log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", ERR_error_string(ERR_get_error(), NULL), s1->ssl_ca_file); return -1; } } } if (s->ssl_verifyclient) { if (NULL == s->ssl_ca_file_cert_names) { log_error_write(srv, __FILE__, __LINE__, "s", "SSL: You specified ssl.verifyclient.activate but no ca_file" ); return -1; } SSL_CTX_set_client_CA_list(s->ssl_ctx, SSL_dup_CA_list(s->ssl_ca_file_cert_names)); SSL_CTX_set_verify( s->ssl_ctx, SSL_VERIFY_PEER | (s->ssl_verifyclient_enforce ? SSL_VERIFY_FAIL_IF_NO_PEER_CERT : 0), NULL ); SSL_CTX_set_verify_depth(s->ssl_ctx, s->ssl_verifyclient_depth); } if (SSL_CTX_use_certificate(s->ssl_ctx, s->ssl_pemfile_x509) < 0) { log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile); return -1; } if (SSL_CTX_use_PrivateKey(s->ssl_ctx, s->ssl_pemfile_pkey) < 0) { log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile); return -1; } if (SSL_CTX_check_private_key(s->ssl_ctx) != 1) { log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:", "Private key does not match the certificate public key, reason:", ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile); return -1; } SSL_CTX_set_default_read_ahead(s->ssl_ctx, 1); SSL_CTX_set_mode(s->ssl_ctx, SSL_CTX_get_mode(s->ssl_ctx) | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); # ifndef OPENSSL_NO_TLSEXT if (!SSL_CTX_set_tlsext_servername_callback(s->ssl_ctx, network_ssl_servername_callback) || !SSL_CTX_set_tlsext_servername_arg(s->ssl_ctx, srv)) { log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", "failed to initialize TLS servername callback, openssl library does not support TLS servername extension"); return -1; } # endif } #endif b = buffer_init(); buffer_copy_buffer(b, srv->srvconf.bindhost); buffer_append_string_len(b, CONST_STR_LEN(":")); buffer_append_int(b, srv->srvconf.port); if (0 != network_server_init(srv, b, srv->config_storage[0])) { buffer_free(b); return -1; } buffer_free(b); #ifdef USE_OPENSSL srv->network_ssl_backend_write = network_write_chunkqueue_openssl; #endif /* get a usefull default */ backend = network_backends[0].nb; /* match name against known types */ if (!buffer_string_is_empty(srv->srvconf.network_backend)) { for (i = 0; network_backends[i].name; i++) { /**/ if (buffer_is_equal_string(srv->srvconf.network_backend, network_backends[i].name, strlen(network_backends[i].name))) { backend = network_backends[i].nb; break; } } if (NULL == network_backends[i].name) { /* we don't know it */ log_error_write(srv, __FILE__, __LINE__, "sb", "server.network-backend has a unknown value:", srv->srvconf.network_backend); return -1; } } switch(backend) { case NETWORK_BACKEND_WRITE: srv->network_backend_write = network_write_chunkqueue_write; break; #if defined(USE_WRITEV) case NETWORK_BACKEND_WRITEV: srv->network_backend_write = network_write_chunkqueue_writev; break; #endif #if defined(USE_SENDFILE) case NETWORK_BACKEND_SENDFILE: srv->network_backend_write = network_write_chunkqueue_sendfile; break; #endif default: return -1; } /* check for $SERVER["socket"] */ for (i = 1; i < srv->config_context->used; i++) { data_config *dc = (data_config *)srv->config_context->data[i]; specific_config *s = srv->config_storage[i]; /* not our stage */ if (COMP_SERVER_SOCKET != dc->comp) continue; if (dc->cond != CONFIG_COND_EQ) continue; /* check if we already know this socket, * if yes, don't init it */ for (j = 0; j < srv->srv_sockets.used; j++) { if (buffer_is_equal(srv->srv_sockets.ptr[j]->srv_token, dc->string)) { break; } } if (j == srv->srv_sockets.used) { if (0 != network_server_init(srv, dc->string, s)) return -1; } } return 0; }
SSL_CTX * tls_server_setup( int authlevel, const char *caFile, const char *caDir, const char *cert, const char *privatekey, const char *ciphers ) { SSL_CTX *ssl_ctx; int ssl_mode = 0; static unsigned char dh4096_p[ ] = { 0x91, 0x6B, 0xA1, 0x6D, 0xC7, 0xE7, 0x1C, 0x21, 0x69, 0xCE, 0x7C, 0x3D, 0x72, 0x28, 0x01, 0x56, 0xAE, 0x71, 0xFE, 0xEF, 0x29, 0x4B, 0xDC, 0xD1, 0x23, 0x37, 0x9E, 0xA5, 0x80, 0x45, 0xEF, 0x51, 0x7A, 0x65, 0x77, 0x41, 0x90, 0x5D, 0xEA, 0xAB, 0x52, 0x39, 0xF0, 0xE1, 0xA9, 0x77, 0xA1, 0xCD, 0x14, 0xB1, 0x8B, 0x07, 0x4F, 0xC5, 0x44, 0xD9, 0x2F, 0x7A, 0x74, 0xFD, 0xBB, 0xEA, 0x6C, 0x4A, 0x22, 0xD0, 0x78, 0xCA, 0xCF, 0x51, 0x04, 0x0E, 0x88, 0x44, 0x65, 0x41, 0xD9, 0x10, 0x6A, 0x11, 0x66, 0x21, 0x0E, 0xE7, 0x9B, 0x39, 0x36, 0xF6, 0x59, 0x15, 0x83, 0xFB, 0x57, 0x51, 0x02, 0xE2, 0x95, 0xBE, 0x85, 0xDA, 0x78, 0x40, 0xC1, 0x9A, 0x0A, 0xE6, 0x43, 0x95, 0xD8, 0x7A, 0x30, 0x50, 0x15, 0x9F, 0x37, 0x5E, 0xAA, 0x27, 0x50, 0xA4, 0x15, 0x1C, 0x6E, 0xFE, 0x3B, 0xA5, 0xD9, 0xF6, 0x0F, 0xE3, 0xA5, 0xFF, 0xE7, 0xDA, 0xD9, 0x68, 0x64, 0x40, 0xF3, 0x54, 0x32, 0x84, 0xF3, 0x12, 0xC4, 0xD3, 0x77, 0x25, 0x00, 0x60, 0x0D, 0x95, 0xEA, 0x16, 0xE0, 0x51, 0x91, 0x8F, 0xF4, 0x40, 0x1B, 0x8A, 0x2D, 0x84, 0x0E, 0xAC, 0x53, 0x58, 0x08, 0x4E, 0x52, 0xC8, 0xE4, 0x6E, 0xA1, 0xCB, 0xA6, 0xF8, 0x3B, 0xE0, 0x1F, 0x35, 0xA6, 0x37, 0x6A, 0x62, 0x61, 0xDE, 0x6D, 0x5A, 0x70, 0x70, 0x71, 0xC9, 0x24, 0x41, 0x70, 0x7C, 0xCD, 0x3F, 0xD9, 0x38, 0xDB, 0x7B, 0x26, 0xFA, 0xB5, 0x6B, 0xAC, 0xF0, 0x2D, 0x45, 0xD8, 0x55, 0x68, 0xCB, 0x89, 0x04, 0x1F, 0xA0, 0xAD, 0x6F, 0xCB, 0x05, 0x04, 0xB3, 0x26, 0xF4, 0x53, 0x02, 0x9E, 0xB8, 0x76, 0x8D, 0xC6, 0xE8, 0x12, 0x24, 0x38, 0x4E, 0x46, 0x27, 0x30, 0xAE, 0x55, 0x1A, 0xD0, 0xDB, 0xCE, 0x4C, 0x35, 0xFA, 0x7D, 0x9D, 0x40, 0x3E, 0x66, 0x7A, 0xBA, 0xEA, 0x78, 0x6C, 0x6E, 0x47, 0x81, 0xBD, 0xB0, 0x57, 0x5D, 0x1C, 0x94, 0xCC, 0x4F, 0x08, 0xF3, 0x5E, 0xB1, 0x6E, 0x0B, 0xD5, 0x55, 0x45, 0x3F, 0x8B, 0xFD, 0x01, 0x4E, 0x01, 0x21, 0x34, 0x20, 0xA8, 0x49, 0xB0, 0x75, 0x40, 0xB4, 0x55, 0x17, 0x3A, 0x55, 0x1E, 0xBA, 0xF2, 0x31, 0x1D, 0x89, 0x81, 0x7A, 0xB3, 0x87, 0xC9, 0xFB, 0xBB, 0x8A, 0x26, 0x66, 0x99, 0x19, 0x7E, 0x3C, 0xB1, 0x6A, 0x9A, 0x4A, 0xDC, 0xE9, 0x3C, 0xF0, 0x7C, 0x29, 0xC9, 0xA1, 0xE1, 0x78, 0x3A, 0x73, 0x8F, 0xEF, 0x2B, 0x33, 0xDF, 0x0C, 0x53, 0xCE, 0x98, 0x91, 0x7C, 0xE3, 0xC9, 0xE2, 0x26, 0xD8, 0x2F, 0x1A, 0x69, 0xCA, 0xB8, 0x64, 0x3B, 0x43, 0x38, 0xBB, 0xFA, 0x89, 0x59, 0xE0, 0x3C, 0xDA, 0xED, 0x93, 0x65, 0x8B, 0x12, 0xED, 0xDB, 0x6F, 0x8F, 0xC5, 0xFE, 0x9C, 0xEB, 0x88, 0xD2, 0xAB, 0x89, 0xAF, 0xAF, 0x60, 0xFF, 0xFC, 0x40, 0x69, 0x3C, 0xD0, 0x22, 0x02, 0xB8, 0x2C, 0x1D, 0x9A, 0x26, 0x19, 0x33, 0xCB, 0x5A, 0x9D, 0x91, 0xDD, 0x05, 0x39, 0x68, 0xBA, 0x15, 0x2B, 0x14, 0xFD, 0x5D, 0xB8, 0x87, 0x90, 0xAF, 0xAA, 0x5F, 0x54, 0xC7, 0x43, 0x04, 0xF4, 0xE1, 0x49, 0x91, 0x42, 0x27, 0x23, 0xCC, 0x5A, 0xFC, 0xF1, 0xA6, 0x2A, 0x39, 0x19, 0xC1, 0x31, 0xBF, 0xE5, 0x89, 0x8C, 0x48, 0xA7, 0xCE, 0x0E, 0x67, 0x18, 0xA1, 0x07, 0x8E, 0xBD, 0xFE, 0x2A, 0x9F, 0xF0, 0xA3, 0x19, 0xAA, 0xBC, 0xD7, 0x6D, 0x43, 0x1C, 0x3D, 0x31, 0xBA, 0x9B, 0xD4, 0xF7, 0xDF, 0x2C, 0x7F, 0x37, 0x7B, 0xD9, 0x7B, 0xDE, 0x62, 0x5C, 0xDE, 0x21, 0x38, 0x4D, 0xB7, 0x4A, 0x45, 0x04, 0x7D, 0x76, 0x4A, 0x93, 0xFE, 0x8E, 0x49, 0x04, 0xD0, 0xAD, 0x99, 0xCD, 0xF0, 0x86, 0x24, 0x5E, 0x73, }; static unsigned char dh4096_g[ ] = { 0x02, }; DH *dh = NULL; /* OpenSSL 1.1.0 added auto-init */ #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) SSL_load_error_strings(); SSL_library_init(); #endif /* OpenSSL < 1.1.0 */ if (( ssl_ctx = SSL_CTX_new( SSLv23_server_method())) == NULL ) { syslog( LOG_ERR, "Liberror: tls_server_setup SSL_CTX_new: %s", ERR_error_string( ERR_get_error(), NULL )); return( NULL ); } if (( dh = DH_new( )) == NULL ) { syslog( LOG_ERR, "Liberror: tls_server_setup DH_new: %s", ERR_error_string( ERR_get_error(), NULL )); goto error; } #if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) if ( DH_set0_pqg( dh, BN_bin2bn( dh4096_p, sizeof( dh4096_p ), NULL ), NULL, BN_bin2bn( dh4096_g, sizeof( dh4096_g ), NULL )) != 1 ) { syslog( LOG_ERR, "Liberror: tls_server_setup DH_set0_pqg: %s", ERR_error_string( ERR_get_error(), NULL )); } #else dh->p = BN_bin2bn( dh4096_p, sizeof( dh4096_p ), NULL ); dh->g = BN_bin2bn( dh4096_g, sizeof( dh4096_g ), NULL ); if (( dh->p == NULL ) || ( dh->g == NULL )) { syslog( LOG_ERR, "Liberror: tls_server_setup BN_bin2bn: %s", ERR_error_string( ERR_get_error(), NULL )); goto error; } #endif /* OpenSSL 1.1.0 */ if ( SSL_CTX_set_tmp_dh( ssl_ctx, dh ) != 1 ) { syslog( LOG_ERR, "Liberror: tls_server_setup SSL_CTX_set_tmp_dh: %s", ERR_error_string( ERR_get_error(), NULL )); goto error; } /* Disable SSLv2 and SSLv3, prefer server cipher ordering */ SSL_CTX_set_options( ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_CIPHER_SERVER_PREFERENCE ); if ( ciphers == NULL ) { SSL_CTX_set_cipher_list( ssl_ctx, "EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:" "RSA+AES256:DH+CHACHA20:DH+AES128:DH+AES256:!MD5" ); } else { SSL_CTX_set_cipher_list( ssl_ctx, ciphers ); } if ( SSL_CTX_use_PrivateKey_file( ssl_ctx, privatekey, SSL_FILETYPE_PEM ) != 1 ) { syslog( LOG_ERR, "Liberror: tls_server_setup " "SSL_CTX_use_PrivateKey_file: %s: %s", privatekey, ERR_error_string( ERR_get_error(), NULL )); goto error; } if ( SSL_CTX_use_certificate_chain_file( ssl_ctx, cert ) != 1 ) { syslog( LOG_ERR, "Liberror: tls_server_setup " "SSL_CTX_use_certificate_chain_file: %s: %s", cert, ERR_error_string( ERR_get_error(), NULL )); goto error; } /* Verify that private key matches cert */ if ( SSL_CTX_check_private_key( ssl_ctx ) != 1 ) { syslog( LOG_ERR, "Liberror: tls_server_setup " "SSL_CTX_check_private_key: %s", ERR_error_string( ERR_get_error(), NULL )); goto error; } /* Load CA */ if ( caFile != NULL ) { if ( SSL_CTX_load_verify_locations( ssl_ctx, caFile, NULL ) != 1 ) { syslog( LOG_ERR, "Liberror: tls_server_setup " "SSL_CTX_load_verify_locations: %s: %s", caFile, ERR_error_string( ERR_get_error(), NULL )); goto error; } } if ( caDir != NULL ) { if ( SSL_CTX_load_verify_locations( ssl_ctx, NULL, caDir ) != 1 ) { syslog( LOG_ERR, "Liberror: tls_server_setup " "SSL_CTX_load_verify_locations: %s: %s", caDir, ERR_error_string( ERR_get_error(), NULL )); goto error; } } /* Set level of security expecations */ if ( authlevel <= 1 ) { ssl_mode = SSL_VERIFY_NONE; } else { /* authlevel == 2 */ ssl_mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; } SSL_CTX_set_verify( ssl_ctx, ssl_mode, NULL ); #ifndef OPENSSL_NO_ECDH /* Do not reuse the same ECDH key pair */ SSL_CTX_set_options(ssl_ctx, SSL_OP_SINGLE_ECDH_USE); #if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)) /* OpenSSL >= 1.1.0 automatically enables automatic handling of parameter * selection and makes SSL_CTX_set_ecdh_auto a noop, so we don't want * to do anything. */ #elif OPENSSL_VERSION_NUMBER >= 0x10002000L /* OpenSSL >= 1.0.2 automatically handles parameter selection */ SSL_CTX_set_ecdh_auto(ssl_ctx, 1); #elif OPENSSL_VERSION_NUMBER >= 0x10000000L /* Manually select the curve. This selection is compliant with RFC 6460 * when AES-256 cipher suites are in use, but noncompliant when AES-128 * cipher suites are used. Oh, well. */ EC_KEY *ecdh; if (( ecdh = EC_KEY_new_by_curve_name( NID_secp384r1 )) != NULL ) { SSL_CTX_set_tmp_ecdh(ssl_ctx, ecdh); EC_KEY_free(ecdh); } else { syslog( LOG_ERR, "Liberror: tls_server_setup EC_KEY_new failed: %s", ERR_error_string( ERR_get_error(), NULL )); } #endif /* openssl 1.0 - 1.0.1 */ #endif /* OPENSSL_NO_ECDH */ return( ssl_ctx ); error: SSL_CTX_free( ssl_ctx ); if ( dh != NULL ) { DH_free( dh ); } return( NULL ); }
static DH * get_dh2048(void) { static const uint8_t dh2048_p[] = { 0x8C, 0x9A, 0x5A, 0x28, 0xBF, 0x13, 0x24, 0xC0, 0xD3, 0x7A, 0x73, 0xC3, 0x87, 0x5B, 0x80, 0x81, 0xE8, 0xF3, 0x7B, 0xF6, 0xF7, 0x18, 0x71, 0xF9, 0xBB, 0x5B, 0x88, 0x21, 0xAB, 0x63, 0xF6, 0x82, 0xA6, 0xEC, 0xD7, 0x04, 0x25, 0xDC, 0x64, 0x75, 0x00, 0x49, 0x2C, 0x13, 0x04, 0x4F, 0xCF, 0xF9, 0x06, 0xE0, 0x4D, 0x23, 0xB8, 0x7C, 0xD8, 0x29, 0x59, 0x6F, 0x69, 0xCC, 0x41, 0x1F, 0x45, 0xF8, 0x25, 0xC8, 0x72, 0xF4, 0xC8, 0x37, 0x3C, 0x30, 0xC2, 0x5A, 0xF3, 0x14, 0x43, 0x98, 0x4F, 0x99, 0x12, 0xBC, 0x68, 0x7E, 0x20, 0x24, 0xAA, 0x8B, 0xBA, 0x87, 0x32, 0xBC, 0x4B, 0xF3, 0x16, 0x25, 0xEE, 0xE5, 0xEB, 0x47, 0xED, 0xB2, 0x7D, 0x8F, 0x4F, 0xC8, 0xFB, 0x58, 0x3D, 0x2E, 0xF6, 0x54, 0xF4, 0xDA, 0xD1, 0x88, 0x6A, 0xD8, 0xBC, 0x32, 0xEC, 0xDA, 0xF1, 0xBC, 0xAF, 0x16, 0x90, 0xCD, 0xEE, 0x5F, 0x92, 0x0B, 0xCE, 0xB9, 0x26, 0xCF, 0x18, 0xAE, 0x8C, 0x9B, 0x06, 0x0B, 0x83, 0x4D, 0x99, 0x31, 0x98, 0x3B, 0x29, 0xE1, 0x16, 0x6A, 0xA4, 0x5E, 0xE8, 0x10, 0x5F, 0x5B, 0x72, 0x3A, 0xA1, 0xD9, 0x89, 0x70, 0x61, 0xD9, 0xC2, 0x25, 0x53, 0x5C, 0x44, 0x10, 0x27, 0xD7, 0xF2, 0x68, 0x75, 0x3F, 0xA3, 0xA7, 0xCF, 0x02, 0x03, 0x49, 0xB4, 0xE4, 0xAF, 0x08, 0xEA, 0xAE, 0x97, 0x07, 0x36, 0xC8, 0xD5, 0x24, 0xC6, 0x51, 0x8B, 0x91, 0x9A, 0x14, 0x91, 0x67, 0x6A, 0xC0, 0xC3, 0x0E, 0x7C, 0xD8, 0x1F, 0xD2, 0x31, 0x07, 0x59, 0x5D, 0x1D, 0xBD, 0x8E, 0xAE, 0xD7, 0x01, 0xBA, 0xDE, 0x0B, 0xDA, 0xA6, 0xBC, 0x9A, 0xD1, 0x39, 0x59, 0x8F, 0xE5, 0x72, 0x65, 0x0F, 0x2A, 0x2D, 0x90, 0x56, 0xE9, 0xDA, 0xF5, 0x4A, 0x26, 0xD3, 0xB3, 0x56, 0x19, 0x84, 0x00, 0x3A, 0x11, 0x78, 0x83, }; static const uint8_t dh2048_g[] = { 0x02, }; DH *dh; if ((dh = DH_new()) == NULL) return NULL; #ifdef HAVE_DH_SET0_PQG BIGNUM *p, *g; p = BN_bin2bn(dh2048_p, sizeof(dh2048_p), NULL); if (!p) { lock_file(stderr); fputs("Error in BN_bin2bn 1!\n", stderr); unlock_file(stderr); DH_free(dh); return NULL; } g = BN_bin2bn(dh2048_g, sizeof(dh2048_g), NULL); if (!g) { lock_file(stderr); fputs("Error in BN_bin2bn 2!\n", stderr); unlock_file(stderr); BN_free(p); DH_free(dh); return NULL; } DH_set0_pqg(dh, p, NULL, g); #else dh->p = BN_bin2bn(dh2048_p, sizeof(dh2048_p), NULL); if (!dh->p) { lock_file(stderr); fputs("Error in BN_bin2bn 1!\n", stderr); unlock_file(stderr); DH_free(dh); return NULL; } dh->g = BN_bin2bn(dh2048_g, sizeof(dh2048_g), NULL); if (!dh->g) { lock_file(stderr); fputs("Error in BN_bin2bn 2!\n", stderr); unlock_file(stderr); DH_free(dh); return NULL; } #endif return dh; }
ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (PrivKey|undefined, DHParams=[P,G], Mpint, Len|0) */ DH *dh_params = NULL; int mpint; /* 0 or 4 */ { ERL_NIF_TERM head, tail; BIGNUM *dh_p = NULL, *dh_g = NULL, *priv_key_in = NULL; unsigned long len = 0; if (!(get_bn_from_bin(env, argv[0], &priv_key_in) || argv[0] == atom_undefined) || !enif_get_list_cell(env, argv[1], &head, &tail) || !get_bn_from_bin(env, head, &dh_p) || !enif_get_list_cell(env, tail, &head, &tail) || !get_bn_from_bin(env, head, &dh_g) || !enif_is_empty_list(env, tail) || !enif_get_int(env, argv[2], &mpint) || (mpint & ~4) || !enif_get_ulong(env, argv[3], &len) /* Load dh_params with values to use by the generator. Mem mgmnt transfered from dh_p etc to dh_params */ || !(dh_params = DH_new()) || (priv_key_in && !DH_set0_key(dh_params, NULL, priv_key_in)) || !DH_set0_pqg(dh_params, dh_p, NULL, dh_g) ) { if (priv_key_in) BN_free(priv_key_in); if (dh_p) BN_free(dh_p); if (dh_g) BN_free(dh_g); if (dh_params) DH_free(dh_params); return enif_make_badarg(env); } if (len) { if (len < BN_num_bits(dh_p)) DH_set_length(dh_params, len); else { if (priv_key_in) BN_free(priv_key_in); if (dh_p) BN_free(dh_p); if (dh_g) BN_free(dh_g); if (dh_params) DH_free(dh_params); return enif_make_badarg(env); } } } #ifdef HAS_EVP_PKEY_CTX { EVP_PKEY_CTX *ctx; EVP_PKEY *dhkey, *params; int success; params = EVP_PKEY_new(); success = EVP_PKEY_set1_DH(params, dh_params); /* set the key referenced by params to dh_params... */ DH_free(dh_params); /* ...dh_params (and params) must be freed */ if (!success) return atom_error; ctx = EVP_PKEY_CTX_new(params, NULL); EVP_PKEY_free(params); if (!ctx) { return atom_error; } if (!EVP_PKEY_keygen_init(ctx)) { /* EVP_PKEY_CTX_free(ctx); */ return atom_error; } dhkey = EVP_PKEY_new(); if (!EVP_PKEY_keygen(ctx, &dhkey)) { /* "performs a key generation operation, the ... */ /*... generated key is written to ppkey." (=last arg) */ /* EVP_PKEY_CTX_free(ctx); */ /* EVP_PKEY_free(dhkey); */ return atom_error; } dh_params = EVP_PKEY_get1_DH(dhkey); /* return the referenced key. dh_params and dhkey must be freed */ EVP_PKEY_free(dhkey); if (!dh_params) { /* EVP_PKEY_CTX_free(ctx); */ return atom_error; } EVP_PKEY_CTX_free(ctx); } #else if (!DH_generate_key(dh_params)) return atom_error; #endif { unsigned char *pub_ptr, *prv_ptr; int pub_len, prv_len; ERL_NIF_TERM ret_pub, ret_prv; const BIGNUM *pub_key_gen, *priv_key_gen; DH_get0_key(dh_params, &pub_key_gen, &priv_key_gen); /* Get pub_key_gen and priv_key_gen. "The values point to the internal representation of the public key and private key values. This memory should not be freed directly." says man */ pub_len = BN_num_bytes(pub_key_gen); prv_len = BN_num_bytes(priv_key_gen); pub_ptr = enif_make_new_binary(env, pub_len+mpint, &ret_pub); prv_ptr = enif_make_new_binary(env, prv_len+mpint, &ret_prv); if (mpint) { put_int32(pub_ptr, pub_len); pub_ptr += 4; put_int32(prv_ptr, prv_len); prv_ptr += 4; } BN_bn2bin(pub_key_gen, pub_ptr); BN_bn2bin(priv_key_gen, prv_ptr); ERL_VALGRIND_MAKE_MEM_DEFINED(pub_ptr, pub_len); ERL_VALGRIND_MAKE_MEM_DEFINED(prv_ptr, prv_len); DH_free(dh_params); return enif_make_tuple2(env, ret_pub, ret_prv); } }
static int dh_test(void) { BN_GENCB *_cb = NULL; DH *a = NULL; DH *b = NULL; const BIGNUM *ap = NULL, *ag = NULL, *apub_key = NULL; const BIGNUM *bpub_key = NULL; BIGNUM *bp = NULL, *bg = NULL; unsigned char *abuf = NULL; unsigned char *bbuf = NULL; int i, alen, blen, aout, bout; int ret = 0; RAND_seed(rnd_seed, sizeof rnd_seed); if (!TEST_ptr(_cb = BN_GENCB_new())) goto err; BN_GENCB_set(_cb, &cb, NULL); if (!TEST_ptr(a = DH_new()) || !TEST_true(DH_generate_parameters_ex(a, 64, DH_GENERATOR_5, _cb))) goto err; if (!DH_check(a, &i)) goto err; if (!TEST_false(i & DH_CHECK_P_NOT_PRIME) || !TEST_false(i & DH_CHECK_P_NOT_SAFE_PRIME) || !TEST_false(i & DH_UNABLE_TO_CHECK_GENERATOR) || !TEST_false(i & DH_NOT_SUITABLE_GENERATOR)) goto err; DH_get0_pqg(a, &ap, NULL, &ag); if (!TEST_ptr(b = DH_new())) goto err; if (!TEST_ptr(bp = BN_dup(ap)) || !TEST_ptr(bg = BN_dup(ag)) || !TEST_true(DH_set0_pqg(b, bp, NULL, bg))) goto err; bp = bg = NULL; if (!DH_generate_key(a)) goto err; DH_get0_key(a, &apub_key, NULL); if (!DH_generate_key(b)) goto err; DH_get0_key(b, &bpub_key, NULL); alen = DH_size(a); if (!TEST_ptr(abuf = OPENSSL_malloc(alen)) || !TEST_true((aout = DH_compute_key(abuf, bpub_key, a)) != -1)) goto err; blen = DH_size(b); if (!TEST_ptr(bbuf = OPENSSL_malloc(blen)) || !TEST_true((bout = DH_compute_key(bbuf, apub_key, b)) != -1)) goto err; if (!TEST_true(aout >= 4) || !TEST_mem_eq(abuf, aout, bbuf, bout)) goto err; ret = 1; err: OPENSSL_free(abuf); OPENSSL_free(bbuf); DH_free(b); DH_free(a); BN_free(bp); BN_free(bg); BN_GENCB_free(_cb); return ret; }
int main(int argc, char *argv[]) { BN_GENCB *_cb = NULL; DH *a = NULL; DH *b = NULL; BIGNUM *ap = NULL, *ag = NULL, *bp = NULL, *bg = NULL, *apub_key = NULL; BIGNUM *bpub_key = NULL, *priv_key = NULL; char buf[12] = {0}; unsigned char *abuf = NULL; unsigned char *bbuf = NULL; int i, alen, blen, aout, bout; int ret = 1; BIO *out = NULL; CRYPTO_set_mem_debug(1); CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); RAND_seed(rnd_seed, sizeof rnd_seed); out = BIO_new(BIO_s_file()); if (out == NULL) EXIT(1); BIO_set_fp(out, stdout, BIO_NOCLOSE | BIO_FP_TEXT); _cb = BN_GENCB_new(); if (_cb == NULL) goto err; BN_GENCB_set(_cb, &cb, out); if (((a = DH_new()) == NULL) || (!DH_generate_parameters_ex(a, 64, DH_GENERATOR_5, _cb))) goto err; if (!DH_check(a, &i)) goto err; if (i & DH_CHECK_P_NOT_PRIME) BIO_puts(out, "p value is not prime\n"); if (i & DH_CHECK_P_NOT_SAFE_PRIME) BIO_puts(out, "p value is not a safe prime\n"); if (i & DH_UNABLE_TO_CHECK_GENERATOR) BIO_puts(out, "unable to check the generator value\n"); if (i & DH_NOT_SUITABLE_GENERATOR) BIO_puts(out, "the g value is not a generator\n"); DH_get0_pqg(a, &ap, NULL, &ag); BIO_puts(out, "\np ="); BN_print(out, ap); BIO_puts(out, "\ng ="); BN_print(out, ag); BIO_puts(out, "\n"); b = DH_new(); if (b == NULL) goto err; bp = BN_dup(ap); bg = BN_dup(ag); if ((bp == NULL) || (bg == NULL) || !DH_set0_pqg(b, bp, NULL, bg)) goto err; bp = bg = NULL; if (!DH_generate_key(a)) goto err; DH_get0_key(a, &apub_key, &priv_key); BIO_puts(out, "pri 1="); BN_print(out, priv_key); BIO_puts(out, "\npub 1="); BN_print(out, apub_key); BIO_puts(out, "\n"); if (!DH_generate_key(b)) goto err; DH_get0_key(b, &bpub_key, &priv_key); BIO_puts(out, "pri 2="); BN_print(out, priv_key); BIO_puts(out, "\npub 2="); BN_print(out, bpub_key); BIO_puts(out, "\n"); alen = DH_size(a); abuf = OPENSSL_malloc(alen); if (abuf == NULL) goto err; aout = DH_compute_key(abuf, bpub_key, a); BIO_puts(out, "key1 ="); for (i = 0; i < aout; i++) { sprintf(buf, "%02X", abuf[i]); BIO_puts(out, buf); } BIO_puts(out, "\n"); blen = DH_size(b); bbuf = OPENSSL_malloc(blen); if (bbuf == NULL) goto err; bout = DH_compute_key(bbuf, apub_key, b); BIO_puts(out, "key2 ="); for (i = 0; i < bout; i++) { sprintf(buf, "%02X", bbuf[i]); BIO_puts(out, buf); } BIO_puts(out, "\n"); if ((aout < 4) || (bout != aout) || (memcmp(abuf, bbuf, aout) != 0)) { fprintf(stderr, "Error in DH routines\n"); ret = 1; } else ret = 0; if (!run_rfc5114_tests()) ret = 1; err: (void)BIO_flush(out); ERR_print_errors_fp(stderr); OPENSSL_free(abuf); OPENSSL_free(bbuf); DH_free(b); DH_free(a); BN_free(bp); BN_free(bg); BN_GENCB_free(_cb); BIO_free(out); #ifndef OPENSSL_NO_CRYPTO_MDEBUG if (CRYPTO_mem_leaks_fp(stderr) <= 0) ret = 1; #endif EXIT(ret); }
void Context::initDH(const std::string& dhParamsFile) { #ifndef OPENSSL_NO_DH // 1024-bit MODP Group with 160-bit prime order subgroup (RFC5114) // -----BEGIN DH PARAMETERS----- // MIIBDAKBgQCxC4+WoIDgHd6S3l6uXVTsUsmfvPsGo8aaap3KUtI7YWBz4oZ1oj0Y // mDjvHi7mUsAT7LSuqQYRIySXXDzUm4O/rMvdfZDEvXCYSI6cIZpzck7/1vrlZEc4 // +qMaT/VbzMChUa9fDci0vUW/N982XBpl5oz9p21NpwjfH7K8LkpDcQKBgQCk0cvV // w/00EmdlpELvuZkF+BBN0lisUH/WQGz/FCZtMSZv6h5cQVZLd35pD1UE8hMWAhe0 // sBuIal6RVH+eJ0n01/vX07mpLuGQnQ0iY/gKdqaiTAh6CR9THb8KAWm2oorWYqTR // jnOvoy13nVkY0IvIhY9Nzvl8KiSFXm7rIrOy5QICAKA= // -----END DH PARAMETERS----- // static const unsigned char dh1024_p[] = { 0xB1,0x0B,0x8F,0x96,0xA0,0x80,0xE0,0x1D,0xDE,0x92,0xDE,0x5E, 0xAE,0x5D,0x54,0xEC,0x52,0xC9,0x9F,0xBC,0xFB,0x06,0xA3,0xC6, 0x9A,0x6A,0x9D,0xCA,0x52,0xD2,0x3B,0x61,0x60,0x73,0xE2,0x86, 0x75,0xA2,0x3D,0x18,0x98,0x38,0xEF,0x1E,0x2E,0xE6,0x52,0xC0, 0x13,0xEC,0xB4,0xAE,0xA9,0x06,0x11,0x23,0x24,0x97,0x5C,0x3C, 0xD4,0x9B,0x83,0xBF,0xAC,0xCB,0xDD,0x7D,0x90,0xC4,0xBD,0x70, 0x98,0x48,0x8E,0x9C,0x21,0x9A,0x73,0x72,0x4E,0xFF,0xD6,0xFA, 0xE5,0x64,0x47,0x38,0xFA,0xA3,0x1A,0x4F,0xF5,0x5B,0xCC,0xC0, 0xA1,0x51,0xAF,0x5F,0x0D,0xC8,0xB4,0xBD,0x45,0xBF,0x37,0xDF, 0x36,0x5C,0x1A,0x65,0xE6,0x8C,0xFD,0xA7,0x6D,0x4D,0xA7,0x08, 0xDF,0x1F,0xB2,0xBC,0x2E,0x4A,0x43,0x71, }; static const unsigned char dh1024_g[] = { 0xA4,0xD1,0xCB,0xD5,0xC3,0xFD,0x34,0x12,0x67,0x65,0xA4,0x42, 0xEF,0xB9,0x99,0x05,0xF8,0x10,0x4D,0xD2,0x58,0xAC,0x50,0x7F, 0xD6,0x40,0x6C,0xFF,0x14,0x26,0x6D,0x31,0x26,0x6F,0xEA,0x1E, 0x5C,0x41,0x56,0x4B,0x77,0x7E,0x69,0x0F,0x55,0x04,0xF2,0x13, 0x16,0x02,0x17,0xB4,0xB0,0x1B,0x88,0x6A,0x5E,0x91,0x54,0x7F, 0x9E,0x27,0x49,0xF4,0xD7,0xFB,0xD7,0xD3,0xB9,0xA9,0x2E,0xE1, 0x90,0x9D,0x0D,0x22,0x63,0xF8,0x0A,0x76,0xA6,0xA2,0x4C,0x08, 0x7A,0x09,0x1F,0x53,0x1D,0xBF,0x0A,0x01,0x69,0xB6,0xA2,0x8A, 0xD6,0x62,0xA4,0xD1,0x8E,0x73,0xAF,0xA3,0x2D,0x77,0x9D,0x59, 0x18,0xD0,0x8B,0xC8,0x85,0x8F,0x4D,0xCE,0xF9,0x7C,0x2A,0x24, 0x85,0x5E,0x6E,0xEB,0x22,0xB3,0xB2,0xE5, }; DH* dh = 0; if (!dhParamsFile.empty()) { BIO* bio = BIO_new_file(dhParamsFile.c_str(), "r"); if (!bio) { std::string msg = Utility::getLastError(); throw SSLContextException(std::string("Error opening Diffie-Hellman parameters file ") + dhParamsFile, msg); } dh = PEM_read_bio_DHparams(bio, 0, 0, 0); BIO_free(bio); if (!dh) { std::string msg = Utility::getLastError(); throw SSLContextException(std::string("Error reading Diffie-Hellman parameters from file ") + dhParamsFile, msg); } } else { dh = DH_new(); if (!dh) { std::string msg = Utility::getLastError(); throw SSLContextException("Error creating Diffie-Hellman parameters", msg); } #if OPENSSL_VERSION_NUMBER >= 0x10100000L BIGNUM* p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), 0); BIGNUM* g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), 0); DH_set0_pqg(dh, p, 0, g); DH_set_length(dh, 160); if (!p || !g) { DH_free(dh); throw SSLContextException("Error creating Diffie-Hellman parameters"); } #else dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), 0); dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), 0); dh->length = 160; if ((!dh->p) || (!dh->g)) { DH_free(dh); throw SSLContextException("Error creating Diffie-Hellman parameters"); } #endif } SSL_CTX_set_tmp_dh(_pSSLContext, dh); SSL_CTX_set_options(_pSSLContext, SSL_OP_SINGLE_DH_USE); DH_free(dh); #else if (!dhParamsFile.empty()) throw SSLContextException("OpenSSL does not support DH"); #endif }