NSS support for x509 certs

7 unit tests are failing at this point, but they're all TLS-related.
This commit is contained in:
Nick Mathewson 2018-08-13 14:54:35 -04:00
parent 7c5339677f
commit c567b8fcb4
12 changed files with 620 additions and 217 deletions

View File

@ -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

View File

@ -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);

View File

@ -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. */

View File

@ -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>.
*/

View File

@ -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 *);

View File

@ -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)
{

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -15,10 +15,144 @@
#include "lib/tls/tortls.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
#include "lib/crypt_ops/crypto_nss_mgt.h"
#include "lib/log/util_bug.h"
#include "lib/encoding/time_fmt.h"
#include "lib/string/printf.h"
#include <pk11pub.h>
#include <cryptohi.h>
#include <cert.h>
#include <keyhi.h>
#include <time.h>
/* Units of PRTime per second.
*
* (PRTime is based in microseconds since the Unix
* epoch.) */
#define PRTIME_PER_SEC (1000*1000)
static tor_x509_cert_impl_t *tor_x509_cert_decode_internal(
const uint8_t *certificate, int certificate_len);
static tor_x509_cert_impl_t *
tor_tls_create_certificate_internal(crypto_pk_t *rsa,
crypto_pk_t *rsa_sign,
CERTName *subject_dn,
CERTName *issuer_dn,
time_t start_time,
time_t end_time)
{
if (! crypto_pk_key_is_private(rsa_sign)) {
return NULL;
}
const SECKEYPublicKey *subject_key = crypto_pk_get_nss_pubkey(rsa);
const SECKEYPrivateKey *signing_key = crypto_pk_get_nss_privkey(rsa_sign);
SECStatus s;
CERTSubjectPublicKeyInfo *subject_spki = NULL;
CERTCertificateRequest *request = NULL;
CERTValidity *validity = NULL;
CERTCertificate *cert = NULL;
SECItem der = { .data = NULL, .len = 0 };
SECItem signed_der = { .data = NULL, .len = 0 };
CERTCertificate *result_cert = NULL;
validity = CERT_CreateValidity(((PRTime)start_time) * PRTIME_PER_SEC,
((PRTime)end_time) * PRTIME_PER_SEC);
if (! validity) {
crypto_nss_log_errors(LOG_WARN, "creating a validity object");
goto err;
}
unsigned long serial_number;
crypto_rand((char*)&serial_number, sizeof(serial_number));
subject_spki = SECKEY_CreateSubjectPublicKeyInfo(subject_key);
if (!subject_spki)
goto err;
/* Make a CSR ... */
// XXX do we need to set any attributes?
request = CERT_CreateCertificateRequest(subject_dn,
subject_spki,
NULL /* attributes */);
if (!request)
goto err;
/* Put it into a certificate ... */
cert = CERT_CreateCertificate(serial_number,
issuer_dn,
validity,
request);
if (!cert)
goto err;
/* version 3 cert */
*cert->version.data = 2; /* 2 means version 3. */
cert->version.len = 1;
// XXX do we need to set anything else on the cert?
/* Sign it. */
KeyType privkey_type = SECKEY_GetPrivateKeyType(signing_key);
SECOidTag oid_tag = SEC_GetSignatureAlgorithmOidTag(privkey_type,
SEC_OID_SHA256);
if (oid_tag == SEC_OID_UNKNOWN)
goto err;
s = SECOID_SetAlgorithmID(cert->arena, &cert->signature, oid_tag, NULL);
if (s != SECSuccess)
goto err;
void *tmp;
tmp = SEC_ASN1EncodeItem(cert->arena, &der, cert,
SEC_ASN1_GET(CERT_CertificateTemplate));
if (!tmp)
goto err;
s = SEC_DerSignDataWithAlgorithmID(cert->arena,
&signed_der,
der.data, der.len,
(SECKEYPrivateKey *)signing_key,//const
&cert->signature);
if (s != SECSuccess)
goto err;
/* Re-parse it, to make sure all the certificates we actually use
* appear via being decoded. */
result_cert = tor_x509_cert_decode_internal(signed_der.data, signed_der.len);
#if 1
{
// Can we check the cert we just signed?
tor_assert(result_cert);
SECKEYPublicKey *issuer_pk = (SECKEYPublicKey *)
crypto_pk_get_nss_pubkey(rsa_sign);
SECStatus cert_ok = CERT_VerifySignedDataWithPublicKey(
&result_cert->signatureWrap, issuer_pk, NULL);
tor_assert(cert_ok == SECSuccess);
}
#endif
err:
if (subject_spki)
SECKEY_DestroySubjectPublicKeyInfo(subject_spki);
if (request)
CERT_DestroyCertificateRequest(request);
if (validity)
CERT_DestroyValidity(validity);
// unnecessary, since these are allocated in the cert's arena.
//SECITEM_FreeItem(&der, PR_FALSE);
//SECITEM_FreeItem(&signed_der, PR_FALSE);
if (cert)
CERT_DestroyCertificate(cert);
return result_cert;
}
MOCK_IMPL(tor_x509_cert_impl_t *,
tor_tls_create_certificate,(crypto_pk_t *rsa,
@ -31,9 +165,39 @@ tor_tls_create_certificate,(crypto_pk_t *rsa,
tor_assert(rsa_sign);
tor_assert(cname);
tor_assert(cname_sign);
(void) cert_lifetime;
// XXXX
return NULL;
char *cname_rfc_1485 = NULL, *cname_sign_rfc_1485 = NULL;
CERTName *subject_dn = NULL, *issuer_dn = NULL;
time_t start_time;
time_t end_time;
CERTCertificate *result = NULL;
tor_asprintf(&cname_rfc_1485, "CN=%s", cname);
tor_asprintf(&cname_sign_rfc_1485, "CN=%s", cname_sign);
subject_dn = CERT_AsciiToName(cname_rfc_1485);
issuer_dn = CERT_AsciiToName(cname_sign_rfc_1485);
if (!subject_dn || !issuer_dn)
goto err;
tor_tls_pick_certificate_lifetime(time(NULL), cert_lifetime,
&start_time, &end_time);
result = tor_tls_create_certificate_internal(rsa,
rsa_sign,
subject_dn,
issuer_dn,
start_time,
end_time);
err:
tor_free(cname_rfc_1485);
tor_free(cname_sign_rfc_1485);
if (subject_dn)
CERT_DestroyName(subject_dn);
if (issuer_dn)
CERT_DestroyName(issuer_dn);
return result;
}
/** Set *<b>encoded_out</b> and *<b>size_out</b> to <b>cert</b>'s encoded DER
@ -63,26 +227,63 @@ tor_x509_cert_t *
tor_x509_cert_dup(const tor_x509_cert_t *cert)
{
tor_assert(cert);
// XXXX
return tor_x509_cert_new(CERT_DupCertificate(cert->cert));
}
/**
* As tor_x509_cert_decode, but return the NSS certificate type
*/
static tor_x509_cert_impl_t *
tor_x509_cert_decode_internal(const uint8_t *certificate,
int certificate_len)
{
tor_assert(certificate);
if (certificate_len > INT_MAX)
return NULL;
SECItem der = { .type = siBuffer,
.data = (unsigned char *)certificate,
.len = certificate_len };
CERTCertDBHandle *certdb = CERT_GetDefaultCertDB();
tor_assert(certdb);
return CERT_NewTempCertificate(certdb,
&der,
NULL /* nickname */,
PR_FALSE, /* isPerm */
PR_TRUE /* CopyDER */);
}
tor_x509_cert_t *
tor_x509_cert_decode(const uint8_t *certificate,
size_t certificate_len)
{
tor_assert(certificate);
(void) certificate_len;
// XXXX
CERTCertificate *cert = tor_x509_cert_decode_internal(certificate,
(int)certificate_len);
if (! cert) {
crypto_nss_log_errors(LOG_INFO, "decoding certificate");
return NULL;
}
tor_x509_cert_t *newcert = tor_x509_cert_new(cert);
return newcert;
}
crypto_pk_t *
tor_tls_cert_get_key(tor_x509_cert_t *cert)
{
tor_assert(cert);
// XXXXX
CERTSubjectPublicKeyInfo *spki = &cert->cert->subjectPublicKeyInfo;
SECKEYPublicKey *pub = SECKEY_ExtractPublicKey(spki); // we own this pointer
if (pub == NULL)
return NULL;
if (SECKEY_GetPublicKeyType(pub) != rsaKey) {
SECKEY_DestroyPublicKey(pub);
return NULL;
}
return crypto_pk_new_from_nss_pubkey(pub);
}
int
@ -92,14 +293,80 @@ tor_tls_cert_is_valid(int severity,
time_t now,
int check_rsa_1024)
{
int result = 0;
tor_assert(cert);
tor_assert(signing_cert);
(void)severity;
(void)now;
(void)check_rsa_1024;
// XXXXX
return 0;
SECKEYPublicKey *pk = CERT_ExtractPublicKey(signing_cert->cert);
if (pk == NULL) {
log_fn(severity, LD_CRYPTO,
"Invalid certificate: could not extract issuer key");
goto fail;
}
SECStatus s = CERT_VerifySignedDataWithPublicKey(&cert->cert->signatureWrap,
pk, NULL);
if (s != SECSuccess) {
log_fn(severity, LD_CRYPTO,
"Invalid certificate: could not validate signature.");
goto fail;
}
if (tor_x509_check_cert_lifetime_internal(severity,
cert->cert,
now,
TOR_X509_PAST_SLOP,
TOR_X509_FUTURE_SLOP) < 0)
goto fail;
if (check_rsa_1024) {
/* We require that this is a 1024-bit RSA key, for legacy reasons .:p */
if (SECKEY_GetPublicKeyType(pk) != rsaKey ||
SECKEY_PublicKeyStrengthInBits(pk) != 1024) {
log_fn(severity, LD_CRYPTO, "Invalid certificate: Key is not RSA1024.");
goto fail;
}
} else {
/* We require that this key is at least minimally strong. */
unsigned min_bits = (SECKEY_GetPublicKeyType(pk) == ecKey) ? 128: 1024;
if (SECKEY_PublicKeyStrengthInBits(pk) < min_bits) {
log_fn(severity, LD_CRYPTO, "Invalid certificate: Key is too weak.");
goto fail;
}
}
/* The certificate is valid. */
result = 1;
fail:
if (pk)
SECKEY_DestroyPublicKey(pk);
return result;
}
static void
log_cert_lifetime(int severity,
const char *status,
time_t now,
PRTime notBefore,
PRTime notAfter)
{
log_fn(severity, LD_GENERAL,
"Certificate %s. Either their clock is set wrong, or your clock "
"is incorrect.", status);
char nowbuf[ISO_TIME_LEN+1];
char nbbuf[ISO_TIME_LEN+1];
char nabuf[ISO_TIME_LEN+1];
format_iso_time(nowbuf, now);
format_iso_time(nbbuf, notBefore / PRTIME_PER_SEC);
format_iso_time(nabuf, notAfter / PRTIME_PER_SEC);
log_fn(severity, LD_GENERAL,
"(The certificate is valid from %s until %s. Your time is %s.)",
nbbuf, nabuf, nowbuf);
}
int
@ -110,12 +377,33 @@ tor_x509_check_cert_lifetime_internal(int severity,
int future_tolerance)
{
tor_assert(cert);
(void)severity;
(void)now;
(void)past_tolerance;
(void)future_tolerance;
// XXXX
PRTime notBefore=0, notAfter=0;
int64_t t;
SECStatus r = CERT_GetCertTimes(cert, &notBefore, &notAfter);
if (r != SECSuccess) {
log_fn(severity, LD_CRYPTO,
"Couldn't get validity times from certificate");
return -1;
}
t = ((int64_t)now) + future_tolerance;
t *= PRTIME_PER_SEC;
if (notBefore > t) {
log_cert_lifetime(severity, "not yet valid", now,
notBefore, notAfter);
return -1;
}
t = ((int64_t)now) - past_tolerance;
t *= PRTIME_PER_SEC;
if (notAfter < t) {
log_cert_lifetime(severity, "already expired", now,
notBefore, notAfter);
return -1;
}
return 0;
}
#ifdef TOR_UNIT_TESTS
@ -126,9 +414,33 @@ tor_x509_cert_replace_expiration(const tor_x509_cert_t *inp,
{
tor_assert(inp);
tor_assert(signing_key);
(void)new_expiration_time;
// XXXX
PRTime notBefore=0, notAfter=0;
SECStatus r = CERT_GetCertTimes(inp->cert, &notBefore, &notAfter);
if (r != SECSuccess)
return NULL;
time_t start_time = notBefore / PRTIME_PER_SEC;
if (new_expiration_time < start_time) {
/* This prevents an NSS error. */
start_time = new_expiration_time - 10;
}
crypto_pk_t *subject_key = tor_tls_cert_get_key((tor_x509_cert_t *)inp);
if (!subject_key)
return NULL;
CERTCertificate *newcert;
newcert = tor_tls_create_certificate_internal(subject_key,
signing_key,
&inp->cert->subject,
&inp->cert->issuer,
start_time,
new_expiration_time);
crypto_pk_free(subject_key);
return newcert ? tor_x509_cert_new(newcert) : NULL;
}
#endif

View File

@ -319,7 +319,8 @@ tor_tls_cert_is_valid(int severity,
/* okay, the signature checked out right. Now let's check the check the
* lifetime. */
if (tor_x509_check_cert_lifetime_internal(severity, cert->cert, now,
48*60*60, 30*24*60*60) < 0)
TOR_X509_PAST_SLOP,
TOR_X509_FUTURE_SLOP) < 0)
goto bad;
cert_key = X509_get_pubkey(cert->cert);

View File

@ -795,11 +795,26 @@ CERTS_FAIL(bad_rsa_id_cert, /*ed25519*/
{
require_failure_message = "legacy RSA ID certificate was not valid";
certs_cell_cert_t *cert = certs_cell_get_certs(d->ccell, 1);
uint8_t *body = certs_cell_cert_getarray_body(cert);
ssize_t body_len = certs_cell_cert_getlen_body(cert);
/* Frob a byte in the signature */
body[body_len - 13] ^= 7;
uint8_t *body;
/* Frob a byte in the signature, after making a new cert. (NSS won't let
* us just frob the old cert, since it will see that the issuer & serial
* number are the same, which will make it fail at an earlier stage than
* signature verification.) */
const tor_x509_cert_t *idc;
tor_x509_cert_t *newc;
tor_tls_get_my_certs(1, NULL, &idc);
time_t new_end = time(NULL) + 86400 * 10;
newc = tor_x509_cert_replace_expiration(idc, new_end, d->key2);
const uint8_t *encoded;
size_t encoded_len;
tor_x509_cert_get_der(newc, &encoded, &encoded_len);
certs_cell_cert_setlen_body(cert, encoded_len);
certs_cell_cert_set_cert_len(cert, encoded_len);
body = certs_cell_cert_getarray_body(cert);
memcpy(body, encoded, encoded_len);
body[encoded_len - 13] ^= 7;
REENCODE();
tor_x509_cert_free(newc);
})
CERTS_FAIL(expired_rsa_id, /* both */
{
@ -815,6 +830,7 @@ CERTS_FAIL(expired_rsa_id, /* both */
size_t encoded_len;
tor_x509_cert_get_der(newc, &encoded, &encoded_len);
certs_cell_cert_setlen_body(cert, encoded_len);
certs_cell_cert_set_cert_len(cert, encoded_len);
memcpy(certs_cell_cert_getarray_body(cert), encoded, encoded_len);
REENCODE();
tor_x509_cert_free(newc);