mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-11 05:33:47 +01:00
NSS support for x509 certs
7 unit tests are failing at this point, but they're all TLS-related.
This commit is contained in:
parent
7c5339677f
commit
c567b8fcb4
@ -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);
|
||||
|
@ -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, ¬Before, ¬After);
|
||||
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, ¬Before, ¬After);
|
||||
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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user