Commit c567b8fc authored by Nick Mathewson's avatar Nick Mathewson 🥄
Browse files

NSS support for x509 certs

7 unit tests are failing at this point, but they're all TLS-related.
parent 7c533967
......@@ -69,6 +69,15 @@ crypto_nss_early_init(void)
crypto_nss_log_errors(LOG_ERR, "setting cipher policy");
tor_assert_unreached();
}
/* We need to override the default here, or NSS will reject all the
* legacy Tor certificates. */
SECStatus rv = NSS_OptionSet(NSS_RSA_MIN_KEY_SIZE, 1024);
if (rv != SECSuccess) {
log_err(LD_CRYPTO, "Unable to set NSS min RSA key size");
crypto_nss_log_errors(LOG_ERR, "setting cipher option.");
tor_assert_unreached();
}
}
void
......
......@@ -121,6 +121,16 @@ MOCK_DECL(struct evp_pkey_st *, crypto_pk_get_openssl_evp_pkey_,(
crypto_pk_t *env,int private));
#endif
#ifdef ENABLE_NSS
struct SECKEYPublicKeyStr;
struct SECKEYPrivateKeyStr;
crypto_pk_t *crypto_pk_new_from_nss_pubkey(struct SECKEYPublicKeyStr *pub);
const struct SECKEYPublicKeyStr *crypto_pk_get_nss_pubkey(
const crypto_pk_t *key);
const struct SECKEYPrivateKeyStr *crypto_pk_get_nss_privkey(
const crypto_pk_t *key);
#endif
void crypto_pk_assign_public(crypto_pk_t *dest, const crypto_pk_t *src);
void crypto_pk_assign_private(crypto_pk_t *dest, const crypto_pk_t *src);
......
......@@ -47,6 +47,33 @@ crypto_pk_key_is_private(const crypto_pk_t *key)
return key && key->seckey;
}
/** used by tortls.c: wrap a SecKEYPublicKey in a crypto_pk_t. Take ownership
* of the RSA object. */
crypto_pk_t *
crypto_pk_new_from_nss_pubkey(struct SECKEYPublicKeyStr *pub)
{
crypto_pk_t *result = tor_malloc_zero(sizeof(crypto_pk_t));
result->pubkey = pub;
return result;
}
/** Return the SECKEYPublicKey for the provided crypto_pk_t. */
const SECKEYPublicKey *
crypto_pk_get_nss_pubkey(const crypto_pk_t *key)
{
tor_assert(key);
return key->pubkey;
}
/** Return the SECKEYPrivateKey for the provided crypto_pk_t, or NULL if it
* does not exist. */
const SECKEYPrivateKey *
crypto_pk_get_nss_privkey(const crypto_pk_t *key)
{
tor_assert(key);
return key->seckey;
}
#ifdef ENABLE_OPENSSL
/** used by tortls.c: wrap an RSA* in a crypto_pk_t. Take ownership of the
* RSA object. */
......
......@@ -5,11 +5,14 @@
#define TORTLS_PRIVATE
#include "lib/tls/x509.h"
#include "lib/tls/x509_internal.h"
#include "lib/tls/tortls.h"
#include "lib/tls/tortls_st.h"
#include "lib/tls/tortls_internal.h"
#include "lib/log/util_bug.h"
#include "lib/intmath/cmp.h"
#include "lib/crypt_ops/crypto_rsa.h"
#include "lib/crypt_ops/crypto_rand.h"
/** Global TLS contexts. We keep them here because nobody else needs
* to touch them.
......@@ -28,6 +31,39 @@ tor_tls_context_get(int is_server)
return is_server ? server_tls_context : client_tls_context;
}
/** Set *<b>link_cert_out</b> and *<b>id_cert_out</b> to the link certificate
* and ID certificate that we're currently using for our V3 in-protocol
* handshake's certificate chain. If <b>server</b> is true, provide the certs
* that we use in server mode (auth, ID); otherwise, provide the certs that we
* use in client mode. (link, ID) */
int
tor_tls_get_my_certs(int server,
const tor_x509_cert_t **link_cert_out,
const tor_x509_cert_t **id_cert_out)
{
tor_tls_context_t *ctx = tor_tls_context_get(server);
if (! ctx)
return -1;
if (link_cert_out)
*link_cert_out = server ? ctx->my_link_cert : ctx->my_auth_cert;
if (id_cert_out)
*id_cert_out = ctx->my_id_cert;
return 0;
}
/**
* Return the authentication key that we use to authenticate ourselves as a
* client in the V3 in-protocol handshake.
*/
crypto_pk_t *
tor_tls_get_my_client_auth_key(void)
{
tor_tls_context_t *context = tor_tls_context_get(0);
if (! context)
return NULL;
return context->auth_key;
}
/** Increase the reference count of <b>ctx</b>. */
void
tor_tls_context_incref(tor_tls_context_t *ctx)
......@@ -158,6 +194,127 @@ tor_tls_context_init(unsigned flags,
return MIN(rv1, rv2);
}
/** Create a new global TLS context.
*
* 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_init_one(tor_tls_context_t **ppcontext,
crypto_pk_t *identity,
unsigned int key_lifetime,
unsigned int flags,
int is_client)
{
tor_tls_context_t *new_ctx = tor_tls_context_new(identity,
key_lifetime,
flags,
is_client);
tor_tls_context_t *old_ctx = *ppcontext;
if (new_ctx != NULL) {
*ppcontext = new_ctx;
/* Free the old context if one existed. */
if (old_ctx != NULL) {
/* This is safe even if there are open connections: we reference-
* count tor_tls_context_t objects. */
tor_tls_context_decref(old_ctx);
}
}
return ((new_ctx != NULL) ? 0 : -1);
}
/** Size of the RSA key to use for our TLS link keys */
#define RSA_LINK_KEY_BITS 2048
/** How long do identity certificates live? (sec) */
#define IDENTITY_CERT_LIFETIME (365*24*60*60)
/**
* Initialize the certificates and keys for a TLS context <b>result</b>
*
* Other arguments as for tor_tls_context_new().
*/
int
tor_tls_context_init_certificates(tor_tls_context_t *result,
crypto_pk_t *identity,
unsigned key_lifetime,
unsigned flags)
{
(void)flags;
int rv = -1;
char *nickname = NULL, *nn2 = NULL;
crypto_pk_t *rsa = NULL, *rsa_auth = NULL;
tor_x509_cert_impl_t *cert = NULL, *idcert = NULL, *authcert = NULL;
nickname = crypto_random_hostname(8, 20, "www.", ".net");
#ifdef DISABLE_V3_LINKPROTO_SERVERSIDE
nn2 = crypto_random_hostname(8, 20, "www.", ".net");
#else
nn2 = crypto_random_hostname(8, 20, "www.", ".com");
#endif
/* Generate short-term RSA key for use with TLS. */
if (!(rsa = crypto_pk_new()))
goto error;
if (crypto_pk_generate_key_with_bits(rsa, RSA_LINK_KEY_BITS)<0)
goto error;
/* Generate short-term RSA key for use in the in-protocol ("v3")
* authentication handshake. */
if (!(rsa_auth = crypto_pk_new()))
goto error;
if (crypto_pk_generate_key(rsa_auth)<0)
goto error;
/* Create a link 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);
/* Create an authentication certificate signed by identity key. */
authcert = tor_tls_create_certificate(rsa_auth, identity, nickname, nn2,
key_lifetime);
if (!cert || !idcert || !authcert) {
log_warn(LD_CRYPTO, "Error creating certificate");
goto error;
}
result->my_link_cert = tor_x509_cert_new(cert);
cert = NULL;
result->my_id_cert = tor_x509_cert_new(idcert);
idcert = NULL;
result->my_auth_cert = tor_x509_cert_new(authcert);
authcert = NULL;
if (!result->my_link_cert || !result->my_id_cert || !result->my_auth_cert)
goto error;
result->link_key = rsa;
rsa = NULL;
result->auth_key = rsa_auth;
rsa_auth = NULL;
rv = 0;
error:
tor_free(nickname);
tor_free(nn2);
if (cert)
tor_x509_cert_impl_free_(cert);
if (idcert)
tor_x509_cert_impl_free_(idcert);
if (authcert)
tor_x509_cert_impl_free_(authcert);
crypto_pk_free(rsa);
crypto_pk_free(rsa_auth);
return rv;
}
/** Make future log messages about <b>tls</b> display the address
* <b>address</b>.
*/
......
......@@ -27,6 +27,10 @@ int tor_tls_context_init_one(tor_tls_context_t **ppcontext,
unsigned int key_lifetime,
unsigned int flags,
int is_client);
int tor_tls_context_init_certificates(tor_tls_context_t *result,
crypto_pk_t *identity,
unsigned key_lifetime,
unsigned flags);
#ifdef ENABLE_OPENSSL
void tor_tls_context_impl_free(struct ssl_ctx_st *);
......
......@@ -23,7 +23,9 @@
#include "lib/crypt_ops/crypto_dh.h"
#include "lib/crypt_ops/crypto_util.h"
#include "lib/tls/x509.h"
#include "lib/tls/x509_internal.h"
#include "lib/tls/tortls.h"
#include "lib/tls/tortls_st.h"
#include "lib/tls/tortls_internal.h"
#include "lib/log/util_bug.h"
......@@ -64,27 +66,27 @@ tor_tls_context_new(crypto_pk_t *identity,
unsigned int key_lifetime, unsigned flags, int is_client)
{
tor_assert(identity);
tor_assert(key_lifetime);
(void)flags;
(void)is_client;
// XXXX
return NULL;
}
int
tor_tls_context_init_one(tor_tls_context_t **ppcontext,
crypto_pk_t *identity,
unsigned int key_lifetime,
unsigned int flags,
int is_client)
{
tor_assert(ppcontext);
tor_assert(identity);
tor_assert(key_lifetime);
(void)flags;
(void)is_client;
// XXXX
return -1;
tor_tls_context_t *ctx = tor_malloc_zero(sizeof(tor_tls_context_t));
ctx->refcnt = 1;
if (! is_client) {
if (tor_tls_context_init_certificates(ctx, identity,
key_lifetime, flags) < 0) {
goto err;
}
}
// XXXX write the main body.
goto done;
err:
tor_tls_context_decref(ctx);
ctx = NULL;
done:
return ctx;
}
void
tor_tls_context_impl_free(struct ssl_ctx_st *ctx)
{
......@@ -361,25 +363,6 @@ tor_tls_log_one_error(tor_tls_t *tls, unsigned long err,
// XXXX
}
int
tor_tls_get_my_certs(int server,
const struct tor_x509_cert_t **link_cert_out,
const struct tor_x509_cert_t **id_cert_out)
{
tor_assert(link_cert_out);
tor_assert(id_cert_out);
(void)server;
// XXXX
return -1;
}
crypto_pk_t *
tor_tls_get_my_client_auth_key(void)
{
// XXXX
return NULL;
}
const char *
tor_tls_get_ciphersuite_name(tor_tls_t *tls)
{
......
......@@ -18,6 +18,7 @@
#define TORTLS_PRIVATE
#define TORTLS_OPENSSL_PRIVATE
#define TOR_X509_PRIVATE
#ifdef _WIN32 /*wrkard for dtls1.h >= 0.9.8m of "#include <winsock.h>"*/
#include <winsock2.h>
......@@ -75,9 +76,6 @@ ENABLE_GCC_WARNING(redundant-decls)
#define LEGAL_NICKNAME_CHARACTERS \
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
/** How long do identity certificates live? (sec) */
#define IDENTITY_CERT_LIFETIME (365*24*60*60)
#define ADDR(tls) (((tls) && (tls)->address) ? tls->address : "peer")
#if OPENSSL_VERSION_NUMBER < OPENSSL_V(1,0,0,'f')
......@@ -489,39 +487,6 @@ static const char CLIENT_CIPHER_LIST[] =
#undef CIPHER
#undef XCIPHER
/** Set *<b>link_cert_out</b> and *<b>id_cert_out</b> to the link certificate
* and ID certificate that we're currently using for our V3 in-protocol
* handshake's certificate chain. If <b>server</b> is true, provide the certs
* that we use in server mode (auth, ID); otherwise, provide the certs that we
* use in client mode. (link, ID) */
int
tor_tls_get_my_certs(int server,
const tor_x509_cert_t **link_cert_out,
const tor_x509_cert_t **id_cert_out)
{
tor_tls_context_t *ctx = tor_tls_context_get(server);
if (! ctx)
return -1;
if (link_cert_out)
*link_cert_out = server ? ctx->my_link_cert : ctx->my_auth_cert;
if (id_cert_out)
*id_cert_out = ctx->my_id_cert;
return 0;
}
/**
* Return the authentication key that we use to authenticate ourselves as a
* client in the V3 in-protocol handshake.
*/
crypto_pk_t *
tor_tls_get_my_client_auth_key(void)
{
tor_tls_context_t *context = tor_tls_context_get(0);
if (! context)
return NULL;
return context->auth_key;
}
/** Return true iff the other side of <b>tls</b> has authenticated to us, and
* the key certified in <b>cert</b> is the same as the key they used to do it.
*/
......@@ -548,39 +513,6 @@ tor_tls_cert_matches_key,(const tor_tls_t *tls, const tor_x509_cert_t *cert))
return result;
}
/** Create a new global TLS context.
*
* 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_init_one(tor_tls_context_t **ppcontext,
crypto_pk_t *identity,
unsigned int key_lifetime,
unsigned int flags,
int is_client)
{
tor_tls_context_t *new_ctx = tor_tls_context_new(identity,
key_lifetime,
flags,
is_client);
tor_tls_context_t *old_ctx = *ppcontext;
if (new_ctx != NULL) {
*ppcontext = new_ctx;
/* Free the old context if one existed. */
if (old_ctx != NULL) {
/* This is safe even if there are open connections: we reference-
* count tor_tls_context_t objects. */
tor_tls_context_decref(old_ctx);
}
}
return ((new_ctx != NULL) ? 0 : -1);
}
void
tor_tls_context_impl_free(struct ssl_ctx_st *ctx)
{
......@@ -592,8 +524,6 @@ tor_tls_context_impl_free(struct ssl_ctx_st *ctx)
/** The group we should use for ecdhe when none was selected. */
#define NID_tor_default_ecdhe_group NID_X9_62_prime256v1
#define RSA_LINK_KEY_BITS 2048
/** 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.
......@@ -602,57 +532,19 @@ tor_tls_context_t *
tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
unsigned flags, int is_client)
{
crypto_pk_t *rsa = NULL, *rsa_auth = NULL;
EVP_PKEY *pkey = NULL;
tor_tls_context_t *result = NULL;
X509 *cert = NULL, *idcert = NULL, *authcert = NULL;
char *nickname = NULL, *nn2 = NULL;
tor_tls_init();
nickname = crypto_random_hostname(8, 20, "www.", ".net");
#ifdef DISABLE_V3_LINKPROTO_SERVERSIDE
nn2 = crypto_random_hostname(8, 20, "www.", ".net");
#else
nn2 = crypto_random_hostname(8, 20, "www.", ".com");
#endif
/* Generate short-term RSA key for use with TLS. */
if (!(rsa = crypto_pk_new()))
goto error;
if (crypto_pk_generate_key_with_bits(rsa, RSA_LINK_KEY_BITS)<0)
goto error;
if (!is_client) {
/* Generate short-term RSA key for use in the in-protocol ("v3")
* authentication handshake. */
if (!(rsa_auth = crypto_pk_new()))
goto error;
if (crypto_pk_generate_key(rsa_auth)<0)
goto error;
/* Create a link 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);
/* Create an authentication certificate signed by identity key. */
authcert = tor_tls_create_certificate(rsa_auth, identity, nickname, nn2,
key_lifetime);
if (!cert || !idcert || !authcert) {
log_warn(LD_CRYPTO, "Error creating certificate");
goto error;
}
}
result = tor_malloc_zero(sizeof(tor_tls_context_t));
result->refcnt = 1;
if (!is_client) {
result->my_link_cert = tor_x509_cert_new(X509_dup(cert));
result->my_id_cert = tor_x509_cert_new(X509_dup(idcert));
result->my_auth_cert = tor_x509_cert_new(X509_dup(authcert));
if (!result->my_link_cert || !result->my_id_cert || !result->my_auth_cert)
if (! is_client) {
if (tor_tls_context_init_certificates(result, identity, key_lifetime,
flags) < 0) {
goto error;
result->link_key = crypto_pk_dup_key(rsa);
result->auth_key = crypto_pk_dup_key(rsa_auth);
}
}
#if 0
......@@ -727,22 +619,21 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
SSL_CTX_set_mode(result->ctx, SSL_MODE_RELEASE_BUFFERS);
#endif
if (! is_client) {
if (cert && !SSL_CTX_use_certificate(result->ctx,cert))
if (result->my_link_cert &&
!SSL_CTX_use_certificate(result->ctx,
result->my_link_cert->cert)) {
goto error;
X509_free(cert); /* We just added a reference to cert. */
cert=NULL;
if (idcert) {
}
if (result->my_id_cert) {
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;
X509_STORE_add_cert(s, X509_dup(result->my_id_cert->cert));
}
}
SSL_CTX_set_session_cache_mode(result->ctx, SSL_SESS_CACHE_OFF);
if (!is_client) {
tor_assert(rsa);
if (!(pkey = crypto_pk_get_openssl_evp_pkey_(rsa,1)))
tor_assert(result->link_key);
if (!(pkey = crypto_pk_get_openssl_evp_pkey_(result->link_key,1)))
goto error;
if (!SSL_CTX_use_PrivateKey(result->ctx, pkey))
goto error;
......@@ -751,6 +642,7 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
if (!SSL_CTX_check_private_key(result->ctx))
goto error;
}
{
DH *dh = crypto_dh_new_openssl_tls();
tor_assert(dh);
......@@ -777,33 +669,14 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
/* let us realloc bufs that we're writing from */
SSL_CTX_set_mode(result->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
if (rsa)
crypto_pk_free(rsa);
if (rsa_auth)
crypto_pk_free(rsa_auth);
X509_free(authcert);
tor_free(nickname);
tor_free(nn2);
return result;
error:
tls_log_errors(NULL, LOG_WARN, LD_NET, "creating TLS context");
tor_free(nickname);
tor_free(nn2);
if (pkey)
EVP_PKEY_free(pkey);
if (rsa)
crypto_pk_free(rsa);
if (rsa_auth)
crypto_pk_free(rsa_auth);
if (result)
tor_tls_context_decref(result);
if (cert)
X509_free(cert);
if (idcert)
X509_free(idcert);
if (authcert)
X509_free(authcert);
return NULL;
}
......
......@@ -72,10 +72,4 @@ int tor_tls_cert_is_valid(int severity,
time_t now,
int check_rsa_1024);
int tor_x509_check_cert_lifetime_internal(int severity,
const tor_x509_cert_impl_t *cert,
time_t now,
int past_tolerance,
int future_tolerance);
#endif
......@@ -14,6 +14,17 @@
#include "lib/crypt_ops/crypto_rsa.h"
#include "lib/testsupport/testsupport.h"
/**
* How skewed do we allow our clock to be with respect to certificates that
* seem to be expired? (seconds)
*/
#define TOR_X509_PAST_SLOP (2*24*60*60)
/**
* How skewed do we allow our clock to be with respect to certificates that
* seem to come from the future? (seconds)
*/
#define TOR_X509_FUTURE_SLOP (30*24*60*60)
MOCK_DECL(tor_x509_cert_impl_t *, tor_tls_create_certificate,
(crypto_pk_t *rsa,
crypto_pk_t *rsa_sign,
......@@ -25,6 +36,12 @@ MOCK_DECL(tor_x509_cert_t *, tor_x509_cert_new,
const tor_x509_cert_impl_t *tor_x509_cert_get_impl(
const tor_x509_cert_t *cert);
int tor_x509_check_cert_lifetime_internal(int severity,
const tor_x509_cert_impl_t *cert,
time_t now,
int past_tolerance,
int future_tolerance);
void tor_x509_cert_impl_free_(tor_x509_cert_impl_t *cert);
#ifdef ENABLE_OPENSSL
int tor_x509_cert_set_cached_der_encoding(tor_x509_cert_t *cert);
......