/** Run unit tests for our random number generation function and its wrappers. */ static void test_crypto_rng(void *arg) { int i, j, allok; char data1[100], data2[100]; double d; char *h=NULL; /* Try out RNG. */ (void)arg; tt_assert(! crypto_seed_rng()); crypto_rand(data1, 100); crypto_rand(data2, 100); tt_mem_op(data1,OP_NE, data2,100); allok = 1; for (i = 0; i < 100; ++i) { uint64_t big; char *host; j = crypto_rand_int(100); if (j < 0 || j >= 100) allok = 0; big = crypto_rand_uint64(UINT64_C(1)<<40); if (big >= (UINT64_C(1)<<40)) allok = 0; big = crypto_rand_uint64(UINT64_C(5)); if (big >= 5) allok = 0; d = crypto_rand_double(); tt_assert(d >= 0); tt_assert(d < 1.0); host = crypto_random_hostname(3,8,"www.",".onion"); if (strcmpstart(host,"www.") || strcmpend(host,".onion") || strlen(host) < 13 || strlen(host) > 18) allok = 0; tor_free(host); } /* Make sure crypto_random_hostname clips its inputs properly. */ h = crypto_random_hostname(20000, 9000, "www.", ".onion"); tt_assert(! strcmpstart(h,"www.")); tt_assert(! strcmpend(h,".onion")); tt_int_op(63+4+6, OP_EQ, strlen(h)); tt_assert(allok); done: tor_free(h); }
/** Run unit tests for our random number generation function and its wrappers. */ static void test_crypto_rng(void) { int i, j, allok; char data1[100], data2[100]; double d; /* Try out RNG. */ test_assert(! crypto_seed_rng(0)); crypto_rand(data1, 100); crypto_rand(data2, 100); test_memneq(data1,data2,100); allok = 1; for (i = 0; i < 100; ++i) { uint64_t big; char *host; j = crypto_rand_int(100); if (j < 0 || j >= 100) allok = 0; big = crypto_rand_uint64(U64_LITERAL(1)<<40); if (big >= (U64_LITERAL(1)<<40)) allok = 0; big = crypto_rand_uint64(U64_LITERAL(5)); if (big >= 5) allok = 0; d = crypto_rand_double(); test_assert(d >= 0); test_assert(d < 1.0); host = crypto_random_hostname(3,8,"www.",".onion"); if (strcmpstart(host,"www.") || strcmpend(host,".onion") || strlen(host) < 13 || strlen(host) > 18) allok = 0; tor_free(host); } test_assert(allok); done: ; }
/** Create a new TLS context for use with Tor TLS handshakes. * <b>identity</b> should be set to the identity key used to sign the * certificate, and <b>nickname</b> set to the nickname to use. * * You can call this function multiple times. Each time you call it, * it generates new certificates; all new connections will use * the new SSL context. */ int tor_tls_context_new(crypto_pk_env_t *identity, unsigned int key_lifetime) { crypto_pk_env_t *rsa = NULL; EVP_PKEY *pkey = NULL; tor_tls_context_t *result = NULL; X509 *cert = NULL, *idcert = NULL; char *nickname = NULL, *nn2 = NULL; tor_tls_init(); nickname = crypto_random_hostname(8, 20, "www.", ".net"); nn2 = crypto_random_hostname(8, 20, "www.", ".net"); /* Generate short-term RSA key. */ if (!(rsa = crypto_new_pk_env())) goto error; if (crypto_pk_generate_key(rsa)<0) goto error; /* Create certificate signed by identity key. */ cert = tor_tls_create_certificate(rsa, identity, nickname, nn2, key_lifetime); /* Create self-signed certificate for identity key. */ idcert = tor_tls_create_certificate(identity, identity, nn2, nn2, IDENTITY_CERT_LIFETIME); if (!cert || !idcert) { log(LOG_WARN, LD_CRYPTO, "Error creating certificate"); goto error; } result = tor_malloc_zero(sizeof(tor_tls_context_t)); result->refcnt = 1; result->my_cert = X509_dup(cert); result->my_id_cert = X509_dup(idcert); result->key = crypto_pk_dup_key(rsa); #ifdef EVERYONE_HAS_AES /* Tell OpenSSL to only use TLS1 */ if (!(result->ctx = SSL_CTX_new(TLSv1_method()))) goto error; #else /* Tell OpenSSL to use SSL3 or TLS1 but not SSL2. */ if (!(result->ctx = SSL_CTX_new(SSLv23_method()))) goto error; SSL_CTX_set_options(result->ctx, SSL_OP_NO_SSLv2); #endif SSL_CTX_set_options(result->ctx, SSL_OP_SINGLE_DH_USE); #ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION SSL_CTX_set_options(result->ctx, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); #endif /* Yes, we know what we are doing here. No, we do not treat a renegotiation * as authenticating any earlier-received data. */ if (use_unsafe_renegotiation_op) { SSL_CTX_set_options(result->ctx, SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION); } /* Don't actually allow compression; it uses ram and time, but the data * we transmit is all encrypted anyway. */ if (result->ctx->comp_methods) result->ctx->comp_methods = NULL; #ifdef SSL_MODE_RELEASE_BUFFERS SSL_CTX_set_mode(result->ctx, SSL_MODE_RELEASE_BUFFERS); #endif if (cert && !SSL_CTX_use_certificate(result->ctx,cert)) goto error; X509_free(cert); /* We just added a reference to cert. */ cert=NULL; if (idcert) { X509_STORE *s = SSL_CTX_get_cert_store(result->ctx); tor_assert(s); X509_STORE_add_cert(s, idcert); X509_free(idcert); /* The context now owns the reference to idcert */ idcert = NULL; } SSL_CTX_set_session_cache_mode(result->ctx, SSL_SESS_CACHE_OFF); tor_assert(rsa); if (!(pkey = _crypto_pk_env_get_evp_pkey(rsa,1))) goto error; if (!SSL_CTX_use_PrivateKey(result->ctx, pkey)) goto error; EVP_PKEY_free(pkey); pkey = NULL; if (!SSL_CTX_check_private_key(result->ctx)) goto error; { crypto_dh_env_t *dh = crypto_dh_new(); SSL_CTX_set_tmp_dh(result->ctx, _crypto_dh_env_get_dh(dh)); crypto_dh_free(dh); } SSL_CTX_set_verify(result->ctx, SSL_VERIFY_PEER, always_accept_verify_cb); /* let us realloc bufs that we're writing from */ SSL_CTX_set_mode(result->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); /* Free the old context if one exists. */ if (global_tls_context) { /* This is safe even if there are open connections: OpenSSL does * reference counting with SSL and SSL_CTX objects. */ tor_tls_context_decref(global_tls_context); } global_tls_context = result; if (rsa) crypto_free_pk_env(rsa); tor_free(nickname); tor_free(nn2); return 0; error: tls_log_errors(NULL, LOG_WARN, "creating TLS context"); tor_free(nickname); tor_free(nn2); if (pkey) EVP_PKEY_free(pkey); if (rsa) crypto_free_pk_env(rsa); if (result) tor_tls_context_decref(result); if (cert) X509_free(cert); if (idcert) X509_free(idcert); return -1; }