tor-commits
Threads by month
- ----- 2025 -----
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
September 2018
- 17 participants
- 3230 discussions
commit aa45511250ed9509ca06b76497f66835796a7998
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Thu Jul 19 12:03:01 2018 -0400
Implement RSA for NSS.
---
src/lib/crypt_ops/crypto_rsa.h | 16 +-
src/lib/crypt_ops/crypto_rsa_nss.c | 699 +++++++++++++++++++++++++++++++++
src/lib/crypt_ops/crypto_rsa_openssl.c | 2 +-
src/lib/crypt_ops/include.am | 7 +-
4 files changed, 712 insertions(+), 12 deletions(-)
diff --git a/src/lib/crypt_ops/crypto_rsa.h b/src/lib/crypt_ops/crypto_rsa.h
index bcb2b51dd..afc6c4201 100644
--- a/src/lib/crypt_ops/crypto_rsa.h
+++ b/src/lib/crypt_ops/crypto_rsa.h
@@ -110,14 +110,6 @@ int crypto_pk_get_common_digests(crypto_pk_t *pk,
int crypto_pk_base64_encode_private(const crypto_pk_t *pk, char **priv_out);
crypto_pk_t *crypto_pk_base64_decode_private(const char *str, size_t len);
-#ifdef TOR_UNIT_TESTS
-#ifdef ENABLE_NSS
-struct SECItemStr;
-STATIC int secitem_uint_cmp(const struct SECItemStr *a,
- const struct SECItemStr *b);
-#endif
-#endif
-
#ifdef ENABLE_OPENSSL
/* Prototypes for private functions only used by tortls.c, crypto.c, and the
* unit tests. */
@@ -132,4 +124,12 @@ MOCK_DECL(struct evp_pkey_st *, crypto_pk_get_openssl_evp_pkey_,(
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);
+#ifdef TOR_UNIT_TESTS
+#ifdef ENABLE_NSS
+struct SECItemStr;
+STATIC int secitem_uint_cmp(const struct SECItemStr *a,
+ const struct SECItemStr *b);
+#endif
+#endif
+
#endif
diff --git a/src/lib/crypt_ops/crypto_rsa_nss.c b/src/lib/crypt_ops/crypto_rsa_nss.c
new file mode 100644
index 000000000..0411687b9
--- /dev/null
+++ b/src/lib/crypt_ops/crypto_rsa_nss.c
@@ -0,0 +1,699 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file crypto_rsa.c
+ * \brief NSS implementations of our RSA code.
+ **/
+
+#include "lib/crypt_ops/crypto_rsa.h"
+
+#include "lib/crypt_ops/crypto_nss_mgt.h"
+#include "lib/crypt_ops/crypto_util.h"
+#include "lib/ctime/di_ops.h"
+#include "lib/encoding/binascii.h"
+#include "lib/fs/files.h"
+#include "lib/intmath/cmp.h"
+#include "lib/intmath/muldiv.h"
+#include "lib/log/log.h"
+#include "lib/log/util_bug.h"
+
+#include <string.h>
+
+#include <keyhi.h>
+#include <pk11pub.h>
+#include <secder.h>
+
+#ifdef ENABLE_OPENSSL
+#include <openssl/rsa.h>
+#include <openssl/evp.h>
+#endif
+
+/** Declaration for crypto_pk_t structure. */
+struct crypto_pk_t
+{
+ SECKEYPrivateKey *seckey;
+ SECKEYPublicKey *pubkey;
+};
+
+/** Return true iff <b>key</b> contains the private-key portion of the RSA
+ * key. */
+int
+crypto_pk_key_is_private(const crypto_pk_t *key)
+{
+ return key && key->seckey;
+}
+
+#ifdef ENABLE_OPENSSL
+/** used by tortls.c: wrap an RSA* in a crypto_pk_t. Take ownership of the
+ * RSA object. */
+crypto_pk_t *
+crypto_new_pk_from_openssl_rsa_(RSA *rsa)
+{
+ crypto_pk_t *pk = NULL;
+ unsigned char *buf = NULL;
+ int len = i2d_RSAPublicKey(rsa, &buf);
+ RSA_free(rsa);
+
+ if (len < 0 || buf == NULL)
+ goto end;
+
+ pk = crypto_pk_asn1_decode((const char *)buf, len);
+
+ end:
+ if (buf)
+ OPENSSL_free(buf);
+ return pk;
+}
+
+/** Helper, used by tor-gencert.c. Return the RSA from a
+ * crypto_pk_t. */
+struct rsa_st *
+crypto_pk_get_openssl_rsa_(crypto_pk_t *pk)
+{
+ size_t buflen = crypto_pk_keysize(pk)*16;
+ unsigned char *buf = tor_malloc_zero(buflen);
+ const unsigned char *cp = buf;
+ RSA *rsa = NULL;
+
+ int used = crypto_pk_asn1_encode_private(pk, (char*)buf, buflen);
+ if (used < 0)
+ goto end;
+ rsa = d2i_RSAPrivateKey(NULL, &cp, used);
+
+ end:
+ memwipe(buf, 0, buflen);
+ tor_free(buf);
+ return rsa;
+}
+
+/** used by tortls.c: get an equivalent EVP_PKEY* for a crypto_pk_t. Iff
+ * private is set, include the private-key portion of the key. Return a valid
+ * pointer on success, and NULL on failure. */
+MOCK_IMPL(struct evp_pkey_st *,
+crypto_pk_get_openssl_evp_pkey_,(crypto_pk_t *pk, int private))
+{
+ size_t buflen = crypto_pk_keysize(pk)*16;
+ unsigned char *buf = tor_malloc_zero(buflen);
+ const unsigned char *cp = buf;
+ RSA *rsa = NULL;
+ EVP_PKEY *result = NULL;
+
+ if (private) {
+ int len = crypto_pk_asn1_encode_private(pk, (char*)buf, buflen);
+ if (len < 0)
+ goto end;
+ rsa = d2i_RSAPrivateKey(NULL, &cp, len);
+ } else {
+ int len = crypto_pk_asn1_encode(pk, (char*)buf, buflen);
+ if (len < 0)
+ goto end;
+ rsa = d2i_RSAPublicKey(NULL, &cp, len);
+ }
+ if (!rsa)
+ goto end;
+
+ if (!(result = EVP_PKEY_new()))
+ goto end;
+ if (!(EVP_PKEY_assign_RSA(result, rsa))) {
+ EVP_PKEY_free(result);
+ RSA_free(rsa);
+ result = NULL;
+ }
+
+ end:
+ memwipe(buf, 0, buflen);
+ tor_free(buf);
+ return result;
+}
+#endif
+
+/** Allocate and return storage for a public key. The key itself will not yet
+ * be set.
+ */
+MOCK_IMPL(crypto_pk_t *,
+crypto_pk_new,(void))
+{
+ crypto_pk_t *result = tor_malloc_zero(sizeof(crypto_pk_t));
+ return result;
+}
+
+/** Release the NSS objects held in <b>key</b> */
+static void
+crypto_pk_clear(crypto_pk_t *key)
+{
+ if (key->pubkey)
+ SECKEY_DestroyPublicKey(key->pubkey);
+ if (key->seckey)
+ SECKEY_DestroyPrivateKey(key->seckey);
+ memset(key, 0, sizeof(crypto_pk_t));
+}
+
+/** Release a reference to an asymmetric key; when all the references
+ * are released, free the key.
+ */
+void
+crypto_pk_free_(crypto_pk_t *key)
+{
+ if (!key)
+ return;
+
+ crypto_pk_clear(key);
+
+ tor_free(key);
+}
+
+/** Generate a <b>bits</b>-bit new public/private keypair in <b>env</b>.
+ * Return 0 on success, -1 on failure.
+ */
+MOCK_IMPL(int,
+crypto_pk_generate_key_with_bits,(crypto_pk_t *key, int bits))
+{
+ tor_assert(key);
+
+ PK11RSAGenParams params = {
+ .keySizeInBits = bits,
+ .pe = TOR_RSA_EXPONENT
+ };
+
+ int result = -1;
+ PK11SlotInfo *slot = PK11_GetBestSlot(CKM_RSA_PKCS_KEY_PAIR_GEN, NULL);
+ SECKEYPrivateKey *seckey = NULL;
+ SECKEYPublicKey *pubkey = NULL;
+
+ if (!slot) {
+ crypto_nss_log_errors(LOG_WARN, "getting slot for RSA keygen");
+ goto done;
+ }
+
+ seckey = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, ¶ms,
+ &pubkey,
+ PR_FALSE /*isPerm */,
+ PR_FALSE /*isSensitive*/,
+ NULL);
+ if (seckey == NULL || pubkey == NULL) {
+ crypto_nss_log_errors(LOG_WARN, "generating an RSA key");
+ goto done;
+ }
+
+ crypto_pk_clear(key);
+ key->seckey = seckey;
+ key->pubkey = pubkey;
+ seckey = NULL;
+ pubkey = NULL;
+
+ result = 0;
+ done:
+ if (slot)
+ PK11_FreeSlot(slot);
+ if (pubkey)
+ SECKEY_DestroyPublicKey(pubkey);
+ if (seckey)
+ SECKEY_DestroyPrivateKey(seckey);
+
+ return result;
+}
+
+/** Return true iff <b>env</b> has a valid key.
+ */
+int
+crypto_pk_check_key(crypto_pk_t *key)
+{
+ return key && key->pubkey;
+}
+
+/** Return true iff <b>env</b> contains a public key whose public exponent
+ * equals 65537.
+ */
+int
+crypto_pk_public_exponent_ok(crypto_pk_t *key)
+{
+ return key &&
+ key->pubkey &&
+ key->pubkey->keyType == rsaKey &&
+ DER_GetUInteger(&key->pubkey->u.rsa.publicExponent) == TOR_RSA_EXPONENT;
+}
+
+/** Compare two big-endian integers stored in a and b; return a tristate.
+ */
+STATIC int
+secitem_uint_cmp(const SECItem *a, const SECItem *b)
+{
+ const unsigned abits = SECKEY_BigIntegerBitLength(a);
+ const unsigned bbits = SECKEY_BigIntegerBitLength(b);
+
+ if (abits < bbits)
+ return -1;
+ else if (abits > bbits)
+ return 1;
+
+ /* okay, they have the same number of bits set. Get a pair of aligned
+ * pointers to their bytes that are set... */
+ const unsigned nbytes = CEIL_DIV(abits, 8);
+ tor_assert(nbytes <= a->len);
+ tor_assert(nbytes <= b->len);
+
+ const unsigned char *aptr = a->data + (a->len - nbytes);
+ const unsigned char *bptr = b->data + (b->len - nbytes);
+
+ /* And compare them. */
+ return fast_memcmp(aptr, bptr, nbytes);
+}
+
+/** Compare the public-key components of a and b. Return less than 0
+ * if a\<b, 0 if a==b, and greater than 0 if a\>b. A NULL key is
+ * considered to be less than all non-NULL keys, and equal to itself.
+ *
+ * Note that this may leak information about the keys through timing.
+ */
+int
+crypto_pk_cmp_keys(const crypto_pk_t *a, const crypto_pk_t *b)
+{
+ int result;
+ char a_is_non_null = (a != NULL) && (a->pubkey != NULL);
+ char b_is_non_null = (b != NULL) && (b->pubkey != NULL);
+ char an_argument_is_null = !a_is_non_null | !b_is_non_null;
+
+ result = tor_memcmp(&a_is_non_null, &b_is_non_null, sizeof(a_is_non_null));
+ if (an_argument_is_null)
+ return result;
+
+ // This is all Tor uses with this structure.
+ tor_assert(a->pubkey->keyType == rsaKey);
+ tor_assert(b->pubkey->keyType == rsaKey);
+
+ const SECItem *a_n, *a_e, *b_n, *b_e;
+ a_n = &a->pubkey->u.rsa.modulus;
+ b_n = &b->pubkey->u.rsa.modulus;
+ a_e = &a->pubkey->u.rsa.publicExponent;
+ b_e = &b->pubkey->u.rsa.publicExponent;
+
+ result = secitem_uint_cmp(a_n, b_n);
+ if (result)
+ return result;
+ return secitem_uint_cmp(a_e, b_e);
+}
+
+/** Return the size of the public key modulus in <b>env</b>, in bytes. */
+size_t
+crypto_pk_keysize(const crypto_pk_t *key)
+{
+ tor_assert(key);
+ tor_assert(key->pubkey);
+ return SECKEY_PublicKeyStrength(key->pubkey);
+}
+
+/** Return the size of the public key modulus of <b>env</b>, in bits. */
+int
+crypto_pk_num_bits(crypto_pk_t *key)
+{
+ tor_assert(key);
+ tor_assert(key->pubkey);
+ return SECKEY_PublicKeyStrengthInBits(key->pubkey);
+}
+
+/**
+ * Make a copy of <b>key</b> and return it.
+ */
+crypto_pk_t *
+crypto_pk_dup_key(crypto_pk_t *key)
+{
+ crypto_pk_t *result = crypto_pk_new();
+ if (key->pubkey)
+ result->pubkey = SECKEY_CopyPublicKey(key->pubkey);
+ if (key->seckey)
+ result->seckey = SECKEY_CopyPrivateKey(key->seckey);
+ return result;
+}
+
+/** For testing: replace dest with src. (Dest must have a refcount
+ * of 1) */
+void
+crypto_pk_assign_public(crypto_pk_t *dest, const crypto_pk_t *src)
+{
+ crypto_pk_clear(dest);
+ if (src->pubkey)
+ dest->pubkey = SECKEY_CopyPublicKey(src->pubkey);
+}
+
+/** For testing: replace dest with src. (Dest must have a refcount
+ * of 1) */
+void
+crypto_pk_assign_private(crypto_pk_t *dest, const crypto_pk_t *src)
+{
+ crypto_pk_clear(dest);
+ if (src->pubkey)
+ dest->pubkey = SECKEY_CopyPublicKey(src->pubkey);
+ if (src->seckey)
+ dest->seckey = SECKEY_CopyPrivateKey(src->seckey);
+}
+
+/** Make a real honest-to-goodness copy of <b>env</b>, and return it.
+ * Returns NULL on failure. */
+crypto_pk_t *
+crypto_pk_copy_full(crypto_pk_t *key)
+{
+ // These aren't reference-counted is nss, so it's fine to just
+ // use the same function.
+ return crypto_pk_dup_key(key);
+}
+
+static const CK_RSA_PKCS_OAEP_PARAMS oaep_params = {
+ .hashAlg = CKM_SHA_1,
+ .mgf = CKG_MGF1_SHA1,
+ .source = CKZ_DATA_SPECIFIED,
+ .pSourceData = NULL,
+ .ulSourceDataLen = 0
+};
+static const SECItem oaep_item = {
+ .type = siBuffer,
+ .data = (unsigned char *) &oaep_params,
+ .len = sizeof(oaep_params)
+};
+
+/** Return the mechanism code and parameters for a given padding method when
+ * used with RSA */
+static CK_MECHANISM_TYPE
+padding_to_mechanism(int padding, SECItem **item_out)
+{
+ switch (padding) {
+ case PK_PKCS1_OAEP_PADDING:
+ *item_out = (SECItem *)&oaep_item;
+ return CKM_RSA_PKCS_OAEP;
+ default:
+ tor_assert_unreached();
+ *item_out = NULL;
+ return CKM_INVALID_MECHANISM;
+ }
+}
+
+/** Encrypt <b>fromlen</b> bytes from <b>from</b> with the public key
+ * in <b>env</b>, using the padding method <b>padding</b>. On success,
+ * write the result to <b>to</b>, and return the number of bytes
+ * written. On failure, return -1.
+ *
+ * <b>tolen</b> is the number of writable bytes in <b>to</b>, and must be
+ * at least the length of the modulus of <b>env</b>.
+ */
+int
+crypto_pk_public_encrypt(crypto_pk_t *env, char *to, size_t tolen,
+ const char *from, size_t fromlen, int padding)
+{
+ tor_assert(env);
+ tor_assert(to);
+ tor_assert(from);
+ tor_assert(tolen < INT_MAX);
+ tor_assert(fromlen < INT_MAX);
+
+ if (BUG(!crypto_pk_check_key(env)))
+ return -1;
+
+ unsigned int result_len = 0;
+ SECItem *item = NULL;
+ CK_MECHANISM_TYPE m = padding_to_mechanism(padding, &item);
+
+ SECStatus s = PK11_PubEncrypt(env->pubkey, m, item,
+ (unsigned char *)to, &result_len,
+ (unsigned int)tolen,
+ (const unsigned char *)from,
+ (unsigned int)fromlen,
+ NULL);
+ if (s != SECSuccess) {
+ crypto_nss_log_errors(LOG_WARN, "encrypting to an RSA key");
+ return -1;
+ }
+
+ return (int)result_len;
+}
+
+/** Decrypt <b>fromlen</b> bytes from <b>from</b> with the private key
+ * in <b>env</b>, using the padding method <b>padding</b>. On success,
+ * write the result to <b>to</b>, and return the number of bytes
+ * written. On failure, return -1.
+ *
+ * <b>tolen</b> is the number of writable bytes in <b>to</b>, and must be
+ * at least the length of the modulus of <b>key</b>.
+ */
+int
+crypto_pk_private_decrypt(crypto_pk_t *key, char *to,
+ size_t tolen,
+ const char *from, size_t fromlen,
+ int padding, int warnOnFailure)
+{
+ tor_assert(key);
+ tor_assert(to);
+ tor_assert(from);
+ tor_assert(tolen < INT_MAX);
+ tor_assert(fromlen < INT_MAX);
+
+ if (!crypto_pk_key_is_private(key))
+ return -1; /* Not a private key. */
+
+ unsigned int result_len = 0;
+ SECItem *item = NULL;
+ CK_MECHANISM_TYPE m = padding_to_mechanism(padding, &item);
+ SECStatus s = PK11_PrivDecrypt(key->seckey, m, item,
+ (unsigned char *)to, &result_len,
+ (unsigned int)tolen,
+ (const unsigned char *)from,
+ (unsigned int)fromlen);
+
+ if (s != SECSuccess) {
+ const int severity = warnOnFailure ? LOG_WARN : LOG_INFO;
+ crypto_nss_log_errors(severity, "decrypting with an RSA key");
+ return -1;
+ }
+
+ return (int)result_len;
+}
+
+/** Check the signature in <b>from</b> (<b>fromlen</b> bytes long) with the
+ * public key in <b>key</b>, using PKCS1 padding. On success, write the
+ * signed data to <b>to</b>, and return the number of bytes written.
+ * On failure, return -1.
+ *
+ * <b>tolen</b> is the number of writable bytes in <b>to</b>, and must be
+ * at least the length of the modulus of <b>key</b>.
+ */
+MOCK_IMPL(int,
+crypto_pk_public_checksig,(const crypto_pk_t *key, char *to,
+ size_t tolen,
+ const char *from, size_t fromlen))
+{
+ tor_assert(key);
+ tor_assert(to);
+ tor_assert(from);
+ tor_assert(tolen < INT_MAX);
+ tor_assert(fromlen < INT_MAX);
+ tor_assert(key->pubkey);
+
+ SECItem sig = {
+ .type = siBuffer,
+ .data = (unsigned char *) from,
+ .len = (unsigned int) fromlen,
+ };
+ SECItem dsig = {
+ .type = siBuffer,
+ .data = (unsigned char *) to,
+ .len = (unsigned int) tolen
+ };
+ SECStatus s;
+ s = PK11_VerifyRecover(key->pubkey, &sig, &dsig, NULL);
+ if (s != SECSuccess)
+ return -1;
+
+ return (int)dsig.len;
+}
+
+/** Sign <b>fromlen</b> bytes of data from <b>from</b> with the private key in
+ * <b>env</b>, using PKCS1 padding. On success, write the signature to
+ * <b>to</b>, and return the number of bytes written. On failure, return
+ * -1.
+ *
+ * <b>tolen</b> is the number of writable bytes in <b>to</b>, and must be
+ * at least the length of the modulus of <b>env</b>.
+ */
+int
+crypto_pk_private_sign(const crypto_pk_t *key, char *to, size_t tolen,
+ const char *from, size_t fromlen)
+{
+ tor_assert(key);
+ tor_assert(to);
+ tor_assert(from);
+ tor_assert(tolen < INT_MAX);
+ tor_assert(fromlen < INT_MAX);
+
+ if (BUG(!crypto_pk_key_is_private(key)))
+ return -1;
+
+ SECItem sig = {
+ .type = siBuffer,
+ .data = (unsigned char *)to,
+ .len = (unsigned int) tolen
+ };
+ SECItem hash = {
+ .type = siBuffer,
+ .data = (unsigned char *)from,
+ .len = (unsigned int) fromlen
+ };
+ CK_MECHANISM_TYPE m = CKM_RSA_PKCS;
+ SECStatus s = PK11_SignWithMechanism(key->seckey, m, NULL,
+ &sig, &hash);
+
+ if (s != SECSuccess) {
+ crypto_nss_log_errors(LOG_WARN, "signing with an RSA key");
+ return -1;
+ }
+
+ return (int)sig.len;
+}
+
+/* "This has lead to people trading hard-to-find object identifiers and ASN.1
+ * definitions like baseball cards" - Peter Gutmann, "X.509 Style Guide". */
+static const unsigned char RSA_OID[] = {
+ /* RSADSI */ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ /* PKCS1 */ 0x01, 0x01,
+ /* RSA */ 0x01
+};
+
+/** ASN.1-encode the public portion of <b>pk</b> into <b>dest</b>.
+ * Return -1 on error, or the number of characters used on success.
+ */
+int
+crypto_pk_asn1_encode(const crypto_pk_t *pk, char *dest, size_t dest_len)
+{
+ tor_assert(pk);
+ if (pk->pubkey == NULL)
+ return -1;
+
+ CERTSubjectPublicKeyInfo *info;
+ info = SECKEY_CreateSubjectPublicKeyInfo(pk->pubkey);
+ if (! info)
+ return -1;
+
+ const SECItem *item = &info->subjectPublicKey;
+ size_t actual_len = (item->len) >> 3; /* bits to bytes */
+ size_t n_used = MIN(actual_len, dest_len);
+ memcpy(dest, item->data, n_used);
+
+ SECKEY_DestroySubjectPublicKeyInfo(info);
+ return (int) n_used;
+}
+
+/** Decode an ASN.1-encoded public key from <b>str</b>; return the result on
+ * success and NULL on failure.
+ */
+crypto_pk_t *
+crypto_pk_asn1_decode(const char *str, size_t len)
+{
+ tor_assert(str);
+ if (len >= INT_MAX)
+ return NULL;
+ CERTSubjectPublicKeyInfo info = {
+ .algorithm = {
+ .algorithm = {
+ .type = siDEROID,
+ .data = (unsigned char *)RSA_OID,
+ .len = sizeof(RSA_OID)
+ }
+ },
+ .subjectPublicKey = {
+ .type = siBuffer,
+ .data = (unsigned char *)str,
+ .len = (unsigned int)(len << 3) /* bytes to bits */
+ }
+ };
+
+ SECKEYPublicKey *pub = SECKEY_ExtractPublicKey(&info);
+ if (pub == NULL)
+ return NULL;
+
+ crypto_pk_t *result = crypto_pk_new();
+ result->pubkey = pub;
+ return result;
+}
+
+DISABLE_GCC_WARNING(unused-parameter)
+
+/** Given a crypto_pk_t <b>pk</b>, allocate a new buffer containing the Base64
+ * encoding of the DER representation of the private key into the
+ * <b>dest_len</b>-byte buffer in <b>dest</b>.
+ * Return the number of bytes written on success, -1 on failure.
+ */
+int
+crypto_pk_asn1_encode_private(const crypto_pk_t *pk,
+ char *dest, size_t destlen)
+{
+ tor_assert(destlen <= INT_MAX);
+ if (!crypto_pk_key_is_private(pk))
+ return -1;
+
+ SECKEYPrivateKeyInfo *info = PK11_ExportPrivKeyInfo(pk->seckey, NULL);
+ if (!info)
+ return -1;
+ SECItem *item = &info->privateKey;
+
+ if (destlen < item->len) {
+ SECKEY_DestroyPrivateKeyInfo(info, PR_TRUE);
+ return -1;
+ }
+ int result = (int)item->len;
+ memcpy(dest, item->data, item->len);
+ SECKEY_DestroyPrivateKeyInfo(info, PR_TRUE);
+
+ return result;
+}
+
+/** Given a buffer containing the DER representation of the
+ * private key <b>str</b>, decode and return the result on success, or NULL
+ * on failure.
+ */
+crypto_pk_t *
+crypto_pk_asn1_decode_private(const char *str, size_t len)
+{
+ tor_assert(str);
+ tor_assert(len < INT_MAX);
+
+ SECKEYPrivateKeyInfo info = {
+ .algorithm = {
+ .algorithm = {
+ .type = siBuffer,
+ .data = (unsigned char *)RSA_OID,
+ .len = sizeof(RSA_OID)
+ }
+ },
+ .privateKey = {
+ .type = siBuffer,
+ .data = (unsigned char *)str,
+ .len = (int)len,
+ }
+ };
+
+ PK11SlotInfo *slot = PK11_GetBestSlot(CKM_RSA_PKCS, NULL);
+ SECStatus s;
+ SECKEYPrivateKey *seckey = NULL;
+
+ s = PK11_ImportPrivateKeyInfoAndReturnKey(slot, &info,
+ NULL /* nickname */,
+ NULL /* publicValue */,
+ PR_FALSE /* isPerm */,
+ PR_FALSE /* isPrivate */,
+ KU_ALL /* keyUsage */,
+ &seckey, NULL);
+
+ crypto_pk_t *output = NULL;
+
+ if (s == SECSuccess && seckey) {
+ output = crypto_pk_new();
+ output->seckey = seckey;
+ output->pubkey = SECKEY_ConvertToPublicKey(seckey);
+ tor_assert(output->pubkey);
+ } else {
+ crypto_nss_log_errors(LOG_WARN, "decoding an RSA private key");
+ }
+
+ return output;
+}
diff --git a/src/lib/crypt_ops/crypto_rsa_openssl.c b/src/lib/crypt_ops/crypto_rsa_openssl.c
index 9a3729a87..7ff71f6dd 100644
--- a/src/lib/crypt_ops/crypto_rsa_openssl.c
+++ b/src/lib/crypt_ops/crypto_rsa_openssl.c
@@ -76,7 +76,7 @@ crypto_new_pk_from_openssl_rsa_(RSA *rsa)
RSA *
crypto_pk_get_openssl_rsa_(crypto_pk_t *env)
{
- return RSA_PrivateKeyDup(env->key);
+ return RSAPrivateKey_dup(env->key);
}
/** used by tortls.c: get an equivalent EVP_PKEY* for a crypto_pk_t. Iff
diff --git a/src/lib/crypt_ops/include.am b/src/lib/crypt_ops/include.am
index 69bd7c2db..195dac6bd 100644
--- a/src/lib/crypt_ops/include.am
+++ b/src/lib/crypt_ops/include.am
@@ -19,7 +19,6 @@ src_lib_libtor_crypt_ops_a_SOURCES = \
src/lib/crypt_ops/crypto_pwbox.c \
src/lib/crypt_ops/crypto_rand.c \
src/lib/crypt_ops/crypto_rsa.c \
- src/lib/crypt_ops/crypto_rsa_openssl.c \
src/lib/crypt_ops/crypto_s2k.c \
src/lib/crypt_ops/crypto_util.c \
src/lib/crypt_ops/digestset.c
@@ -28,10 +27,12 @@ if USE_NSS
src_lib_libtor_crypt_ops_a_SOURCES += \
src/lib/crypt_ops/aes_nss.c \
src/lib/crypt_ops/crypto_dh_nss.c \
- src/lib/crypt_ops/crypto_nss_mgt.c
+ src/lib/crypt_ops/crypto_nss_mgt.c \
+ src/lib/crypt_ops/crypto_rsa_nss.c
else
src_lib_libtor_crypt_ops_a_SOURCES += \
- src/lib/crypt_ops/aes_openssl.c
+ src/lib/crypt_ops/aes_openssl.c \
+ src/lib/crypt_ops/crypto_rsa_openssl.c
endif
if USE_OPENSSL
1
0
commit 96f8e1980204e83bb943fbff31e308a03b41160c
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Sun Aug 12 17:46:53 2018 -0400
Implement PBKDF2 with NSS.
This was a gap that we left in the last commit.
---
src/lib/crypt_ops/crypto_s2k.c | 47 +++++++++++++++++++++++++++++++++++++++---
1 file changed, 44 insertions(+), 3 deletions(-)
diff --git a/src/lib/crypt_ops/crypto_s2k.c b/src/lib/crypt_ops/crypto_s2k.c
index 433fbb026..e0b2f40bb 100644
--- a/src/lib/crypt_ops/crypto_s2k.c
+++ b/src/lib/crypt_ops/crypto_s2k.c
@@ -20,10 +20,14 @@
#include "lib/crypt_ops/crypto_util.h"
#include "lib/ctime/di_ops.h"
#include "lib/log/util_bug.h"
+#include "lib/intmath/cmp.h"
#ifdef ENABLE_OPENSSL
#include <openssl/evp.h>
#endif
+#ifdef ENABLE_NSS
+#include <pk11pub.h>
+#endif
#if defined(HAVE_LIBSCRYPT_H) && defined(HAVE_LIBSCRYPT_SCRYPT)
#define HAVE_SCRYPT
@@ -267,13 +271,13 @@ secret_to_key_compute_key(uint8_t *key_out, size_t key_out_len,
return (int)key_out_len;
case S2K_TYPE_PBKDF2: {
-#ifdef ENABLE_OPENSSL
uint8_t log_iters;
if (spec_len < 1 || secret_len > INT_MAX || spec_len > INT_MAX)
return S2K_BAD_LEN;
log_iters = spec[spec_len-1];
if (log_iters > 31)
return S2K_BAD_PARAMS;
+#ifdef ENABLE_OPENSSL
rv = PKCS5_PBKDF2_HMAC_SHA1(secret, (int)secret_len,
spec, (int)spec_len-1,
(1<<log_iters),
@@ -282,8 +286,45 @@ secret_to_key_compute_key(uint8_t *key_out, size_t key_out_len,
return S2K_FAILED;
return (int)key_out_len;
#else
- // XXXXXXXXXXXXXXXXXXXXXXXX implement me.
- return S2K_NO_SCRYPT_SUPPORT;
+ SECItem passItem = { .type = siBuffer,
+ .data = (unsigned char *) secret,
+ .len = (int)secret_len };
+ SECItem saltItem = { .type = siBuffer,
+ .data = (unsigned char *) spec,
+ .len = (int)spec_len - 1 };
+ SECAlgorithmID *alg = NULL;
+ PK11SymKey *key = NULL;
+
+ rv = S2K_FAILED;
+ alg = PK11_CreatePBEV2AlgorithmID(
+ SEC_OID_PKCS5_PBKDF2, SEC_OID_HMAC_SHA1, SEC_OID_HMAC_SHA1,
+ (int)key_out_len, (1<<log_iters), &saltItem);
+ if (alg == NULL)
+ return S2K_FAILED;
+
+ key = PK11_PBEKeyGen(NULL /* slot */,
+ alg,
+ &passItem,
+ false,
+ NULL);
+
+ SECStatus st = PK11_ExtractKeyValue(key);
+ if (st != SECSuccess)
+ goto nss_pbkdf_err;
+
+ const SECItem *iptr = PK11_GetKeyData(key);
+ if (iptr == NULL)
+ goto nss_pbkdf_err;
+
+ rv = MIN((int)iptr->len, (int)key_out_len);
+ memcpy(key_out, iptr->data, rv);
+
+ nss_pbkdf_err:
+ if (key)
+ PK11_FreeSymKey(key);
+ if (alg)
+ SECOID_DestroyAlgorithmID(alg, PR_TRUE);
+ return rv;
#endif
}
1
0
commit 6a88d8f6b413efdac4b0176cfb78431be46ca9e0
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Sun Aug 12 17:18:41 2018 -0400
When enabling NSS, disable OpenSSL.
We used to link both libraries at once, but now that I'm working on
TLS, there's nothing left to keep OpenSSL around for when NSS is
enabled.
Note that this patch causes a couple of places that still assumed
OpenSSL to be disabled when NSS is enabled
- tor-gencert
- pbkdf2
---
configure.ac | 14 +++++++++---
src/app/config/config.c | 12 +++++++++++
src/core/mainloop/main.c | 5 +++--
src/lib/crypt_ops/compat_openssl.h | 6 ++++++
src/lib/crypt_ops/crypto_dh.h | 2 +-
src/lib/crypt_ops/crypto_ed25519.c | 1 +
src/lib/crypt_ops/crypto_format.c | 1 +
src/lib/crypt_ops/crypto_hkdf.c | 2 ++
src/lib/crypt_ops/crypto_init.c | 42 ++++++++++++++++++++++++++++++++++++
src/lib/crypt_ops/crypto_init.h | 4 ++++
src/lib/crypt_ops/crypto_rand.c | 14 ++++++++----
src/lib/crypt_ops/crypto_rsa.c | 6 ++++--
src/lib/crypt_ops/crypto_s2k.c | 7 ++++++
src/lib/crypt_ops/crypto_util.c | 6 ++++--
src/lib/crypt_ops/include.am | 2 +-
src/lib/tls/tortls_internal.h | 44 +++++++++++++++++++++-----------------
src/lib/tls/tortls_nss.c | 42 ------------------------------------
src/test/bench.c | 8 +++++++
src/test/include.am | 2 +-
src/test/test.c | 2 ++
src/test/test_crypto.c | 4 ++++
src/test/test_crypto_slow.c | 2 ++
src/tools/include.am | 14 ++++++++++--
src/tools/tor-gencert.c | 2 ++
24 files changed, 164 insertions(+), 80 deletions(-)
diff --git a/configure.ac b/configure.ac
index aa9b2ba6b..f99697a44 100644
--- a/configure.ac
+++ b/configure.ac
@@ -67,14 +67,15 @@ AM_CONDITIONAL(LIBFUZZER_ENABLED, test "x$enable_libfuzzer" = "xyes")
AM_CONDITIONAL(OSS_FUZZ_ENABLED, test "x$enable_oss_fuzz" = "xyes")
AM_CONDITIONAL(USE_RUST, test "x$enable_rust" = "xyes")
AM_CONDITIONAL(USE_NSS, test "x$enable_nss" = "xyes")
-AM_CONDITIONAL(USE_OPENSSL, true)
+AM_CONDITIONAL(USE_OPENSSL, test "x$enable_nss" != "xyes")
if test "x$enable_nss" = "xyes"; then
AC_DEFINE(ENABLE_NSS, 1,
[Defined if we're building with NSS in addition to OpenSSL.])
+else
+ AC_DEFINE(ENABLE_OPENSSL, 1,
+ [Defined if we're building with OpenSSL or LibreSSL])
fi
-AC_DEFINE(ENABLE_OPENSSL, 1,
- [Defined if we're building with OpenSSL or LibreSSL])
if test "$enable_static_tor" = "yes"; then
enable_static_libevent="yes";
@@ -872,6 +873,8 @@ fi
dnl ------------------------------------------------------
dnl Where do you live, openssl? And how do we call you?
+if test "x$enable_nss" != "xyes"; then
+
tor_openssl_pkg_redhat="openssl"
tor_openssl_pkg_debian="libssl-dev"
tor_openssl_devpkg_redhat="openssl-devel"
@@ -971,6 +974,11 @@ AC_CHECK_SIZEOF(SHA_CTX, , [AC_INCLUDES_DEFAULT()
#include <openssl/sha.h>
])
+fi # enable_nss
+
+dnl ======================================================================
+dnl Can we use KIST?
+
dnl Define the set of checks for KIST scheduler support.
AC_DEFUN([CHECK_KIST_SUPPORT],[
dnl KIST needs struct tcp_info and for certain members to exist.
diff --git a/src/app/config/config.c b/src/app/config/config.c
index d2ed29562..d7c9f6d61 100644
--- a/src/app/config/config.c
+++ b/src/app/config/config.c
@@ -82,6 +82,11 @@
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
#include "lib/crypt_ops/crypto_init.h"
+#ifdef ENABLE_NSS
+#include "lib/crypt_ops/crypto_nss_mgt.h"
+#else
+#include "lib/crypt_ops/crypto_openssl_mgt.h"
+#endif
#include "feature/dircache/dirserv.h"
#include "feature/relay/dns.h"
#include "core/or/dos.h"
@@ -5238,9 +5243,16 @@ options_init_from_torrc(int argc, char **argv)
printf("Libevent\t\t%-15s\t\t%s\n",
tor_libevent_get_header_version_str(),
tor_libevent_get_version_str());
+#ifdef ENABLE_OPENSSL
printf("OpenSSL \t\t%-15s\t\t%s\n",
crypto_openssl_get_header_version_str(),
crypto_openssl_get_version_str());
+#endif
+#ifdef ENABLE_NSS
+ printf("NSS \t\t%-15s\t\t%s\n",
+ crypto_nss_get_header_version_str(),
+ crypto_nss_get_version_str());
+#endif
if (tor_compress_supports_method(ZLIB_METHOD)) {
printf("Zlib \t\t%-15s\t\t%s\n",
tor_compress_version_str(ZLIB_METHOD),
diff --git a/src/core/mainloop/main.c b/src/core/mainloop/main.c
index ad8c1ead6..f40639d08 100644
--- a/src/core/mainloop/main.c
+++ b/src/core/mainloop/main.c
@@ -3504,10 +3504,11 @@ tor_init(int argc, char *argv[])
const char *version = get_version();
log_notice(LD_GENERAL, "Tor %s running on %s with Libevent %s, "
- "OpenSSL %s, Zlib %s, Liblzma %s, and Libzstd %s.", version,
+ "%s %s, Zlib %s, Liblzma %s, and Libzstd %s.", version,
get_uname(),
tor_libevent_get_version_str(),
- crypto_openssl_get_version_str(),
+ crypto_get_library_name(),
+ crypto_get_library_version_string(),
tor_compress_supports_method(ZLIB_METHOD) ?
tor_compress_version_str(ZLIB_METHOD) : "N/A",
tor_compress_supports_method(LZMA_METHOD) ?
diff --git a/src/lib/crypt_ops/compat_openssl.h b/src/lib/crypt_ops/compat_openssl.h
index 317c01134..f2f632ab4 100644
--- a/src/lib/crypt_ops/compat_openssl.h
+++ b/src/lib/crypt_ops/compat_openssl.h
@@ -7,6 +7,10 @@
#ifndef TOR_COMPAT_OPENSSL_H
#define TOR_COMPAT_OPENSSL_H
+#include "orconfig.h"
+
+#ifdef ENABLE_OPENSSL
+
#include <openssl/opensslv.h>
#include "lib/crypt_ops/crypto_openssl_mgt.h"
@@ -47,5 +51,7 @@
#define CONST_IF_OPENSSL_1_1_API const
#endif /* !defined(OPENSSL_1_1_API) */
+#endif /* defined(ENABLE_OPENSSL) */
+
#endif /* !defined(TOR_COMPAT_OPENSSL_H) */
diff --git a/src/lib/crypt_ops/crypto_dh.h b/src/lib/crypt_ops/crypto_dh.h
index 6e79a6404..3ee343a27 100644
--- a/src/lib/crypt_ops/crypto_dh.h
+++ b/src/lib/crypt_ops/crypto_dh.h
@@ -56,7 +56,7 @@ struct dh_st *crypto_dh_new_openssl_tls(void);
void crypto_dh_init_openssl(void);
void crypto_dh_free_all_openssl(void);
#endif
-#ifdef ENABLE_OPENSSL
+#ifdef ENABLE_NSS
void crypto_dh_init_nss(void);
void crypto_dh_free_all_nss(void);
#endif
diff --git a/src/lib/crypt_ops/crypto_ed25519.c b/src/lib/crypt_ops/crypto_ed25519.c
index 9d2c9e9fa..11c1f56ae 100644
--- a/src/lib/crypt_ops/crypto_ed25519.c
+++ b/src/lib/crypt_ops/crypto_ed25519.c
@@ -37,6 +37,7 @@
#include "ed25519/donna/ed25519_donna_tor.h"
#include <string.h>
+#include <errno.h>
static void pick_ed25519_impl(void);
diff --git a/src/lib/crypt_ops/crypto_format.c b/src/lib/crypt_ops/crypto_format.c
index 50916a8d6..09ec753a0 100644
--- a/src/lib/crypt_ops/crypto_format.c
+++ b/src/lib/crypt_ops/crypto_format.c
@@ -29,6 +29,7 @@
#include "lib/fs/files.h"
#include <string.h>
+#include <errno.h>
/** Write the <b>datalen</b> bytes from <b>data</b> to the file named
* <b>fname</b> in the tagged-data format. This format contains a
diff --git a/src/lib/crypt_ops/crypto_hkdf.c b/src/lib/crypt_ops/crypto_hkdf.c
index 1873632a9..a63d9131d 100644
--- a/src/lib/crypt_ops/crypto_hkdf.c
+++ b/src/lib/crypt_ops/crypto_hkdf.c
@@ -17,12 +17,14 @@
#include "lib/intmath/cmp.h"
#include "lib/log/util_bug.h"
+#ifdef ENABLE_OPENSSL
#include <openssl/opensslv.h>
#if defined(HAVE_ERR_LOAD_KDF_STRINGS)
#include <openssl/kdf.h>
#define HAVE_OPENSSL_HKDF 1
#endif
+#endif
#include <string.h>
diff --git a/src/lib/crypt_ops/crypto_init.c b/src/lib/crypt_ops/crypto_init.c
index 620fe8e1b..f9b077e9e 100644
--- a/src/lib/crypt_ops/crypto_init.c
+++ b/src/lib/crypt_ops/crypto_init.c
@@ -88,6 +88,10 @@ crypto_global_init(int useAccel, const char *accelName, const char *accelDir)
#ifdef ENABLE_OPENSSL
if (crypto_openssl_late_init(useAccel, accelName, accelDir) < 0)
return -1;
+#else
+ (void)useAccel;
+ (void)accelName;
+ (void)accelDir;
#endif
#ifdef ENABLE_NSS
if (crypto_nss_late_init() < 0)
@@ -139,3 +143,41 @@ crypto_postfork(void)
crypto_nss_postfork();
#endif
}
+
+/** Return the name of the crypto library we're using. */
+const char *
+crypto_get_library_name(void)
+{
+#ifdef ENABLE_OPENSSL
+ return "OpenSSL";
+#endif
+#ifdef ENABLE_NSS
+ return "NSS";
+#endif
+}
+
+/** Return the version of the crypto library we are using, as given in the
+ * library. */
+const char *
+crypto_get_library_version_string(void)
+{
+#ifdef ENABLE_OPENSSL
+ return crypto_openssl_get_version_str();
+#endif
+#ifdef ENABLE_NSS
+ return crypto_nss_get_version_str();
+#endif
+}
+
+/** Return the version of the crypto library we're using, as given in the
+ * headers. */
+const char *
+crypto_get_header_version_string(void)
+{
+#ifdef ENABLE_OPENSSL
+ return crypto_openssl_get_header_version_str();
+#endif
+#ifdef ENABLE_NSS
+ return crypto_nss_get_header_version_str();
+#endif
+}
diff --git a/src/lib/crypt_ops/crypto_init.h b/src/lib/crypt_ops/crypto_init.h
index 3e32456b5..05b281720 100644
--- a/src/lib/crypt_ops/crypto_init.h
+++ b/src/lib/crypt_ops/crypto_init.h
@@ -26,4 +26,8 @@ void crypto_thread_cleanup(void);
int crypto_global_cleanup(void);
void crypto_postfork(void);
+const char *crypto_get_library_name(void);
+const char *crypto_get_library_version_string(void);
+const char *crypto_get_header_version_string(void);
+
#endif /* !defined(TOR_CRYPTO_H) */
diff --git a/src/lib/crypt_ops/crypto_rand.c b/src/lib/crypt_ops/crypto_rand.c
index 980671474..78471bf39 100644
--- a/src/lib/crypt_ops/crypto_rand.c
+++ b/src/lib/crypt_ops/crypto_rand.c
@@ -35,9 +35,11 @@
#include "lib/testsupport/testsupport.h"
#include "lib/fs/files.h"
+#include "lib/defs/digest_sizes.h"
+#include "lib/crypt_ops/crypto_digest.h"
+
#ifdef ENABLE_NSS
#include "lib/crypt_ops/crypto_nss_mgt.h"
-#include "lib/crypt_ops/crypto_digest.h"
#endif
#ifdef ENABLE_OPENSSL
@@ -80,6 +82,7 @@ ENABLE_GCC_WARNING(redundant-decls)
#endif
#include <string.h>
+#include <errno.h>
/**
* How many bytes of entropy we add at once.
@@ -335,7 +338,8 @@ crypto_strongest_rand_raw(uint8_t *out, size_t out_len)
void
crypto_strongest_rand(uint8_t *out, size_t out_len)
{
-#define DLEN SHA512_DIGEST_LENGTH
+#define DLEN DIGEST512_LEN
+
/* We're going to hash DLEN bytes from the system RNG together with some
* bytes from the PRNGs from our crypto librar(y/ies), in order to yield
* DLEN bytes.
@@ -360,11 +364,11 @@ crypto_strongest_rand(uint8_t *out, size_t out_len)
// LCOV_EXCL_STOP
}
if (out_len >= DLEN) {
- SHA512(inp, sizeof(inp), out);
+ crypto_digest512((char*)out, (char*)inp, sizeof(inp), DIGEST_SHA512);
out += DLEN;
out_len -= DLEN;
} else {
- SHA512(inp, sizeof(inp), tmp);
+ crypto_digest512((char*)tmp, (char*)inp, sizeof(inp), DIGEST_SHA512);
memcpy(out, tmp, out_len);
break;
}
@@ -699,6 +703,7 @@ smartlist_shuffle(smartlist_t *sl)
int
crypto_force_rand_ssleay(void)
{
+#ifdef ENABLE_OPENSSL
RAND_METHOD *default_method;
default_method = RAND_OpenSSL();
if (RAND_get_rand_method() != default_method) {
@@ -708,6 +713,7 @@ crypto_force_rand_ssleay(void)
RAND_set_rand_method(default_method);
return 1;
}
+#endif
return 0;
}
diff --git a/src/lib/crypt_ops/crypto_rsa.c b/src/lib/crypt_ops/crypto_rsa.c
index 0f80bc967..31497e650 100644
--- a/src/lib/crypt_ops/crypto_rsa.c
+++ b/src/lib/crypt_ops/crypto_rsa.c
@@ -37,11 +37,12 @@ crypto_get_rsa_padding_overhead(int padding)
{
switch (padding)
{
- case RSA_PKCS1_OAEP_PADDING: return PKCS1_OAEP_PADDING_OVERHEAD;
+ case PK_PKCS1_OAEP_PADDING: return PKCS1_OAEP_PADDING_OVERHEAD;
default: tor_assert(0); return -1; // LCOV_EXCL_LINE
}
}
+#ifdef ENABLE_OPENSSL
/** Given a padding method <b>padding</b>, return the correct OpenSSL constant.
*/
int
@@ -53,6 +54,7 @@ crypto_get_rsa_padding(int padding)
default: tor_assert(0); return -1; // LCOV_EXCL_LINE
}
}
+#endif
/** Compare the public-key components of a and b. Return non-zero iff
* a==b. A NULL key is considered to be distinct from all non-NULL
@@ -100,7 +102,7 @@ crypto_pk_obsolete_public_hybrid_encrypt(crypto_pk_t *env,
tor_assert(to);
tor_assert(fromlen < SIZE_T_CEILING);
- overhead = crypto_get_rsa_padding_overhead(crypto_get_rsa_padding(padding));
+ overhead = crypto_get_rsa_padding_overhead(padding);
pkeylen = crypto_pk_keysize(env);
if (!force && fromlen+overhead <= pkeylen) {
diff --git a/src/lib/crypt_ops/crypto_s2k.c b/src/lib/crypt_ops/crypto_s2k.c
index 0e151f0a6..433fbb026 100644
--- a/src/lib/crypt_ops/crypto_s2k.c
+++ b/src/lib/crypt_ops/crypto_s2k.c
@@ -21,7 +21,9 @@
#include "lib/ctime/di_ops.h"
#include "lib/log/util_bug.h"
+#ifdef ENABLE_OPENSSL
#include <openssl/evp.h>
+#endif
#if defined(HAVE_LIBSCRYPT_H) && defined(HAVE_LIBSCRYPT_SCRYPT)
#define HAVE_SCRYPT
@@ -265,6 +267,7 @@ secret_to_key_compute_key(uint8_t *key_out, size_t key_out_len,
return (int)key_out_len;
case S2K_TYPE_PBKDF2: {
+#ifdef ENABLE_OPENSSL
uint8_t log_iters;
if (spec_len < 1 || secret_len > INT_MAX || spec_len > INT_MAX)
return S2K_BAD_LEN;
@@ -278,6 +281,10 @@ secret_to_key_compute_key(uint8_t *key_out, size_t key_out_len,
if (rv < 0)
return S2K_FAILED;
return (int)key_out_len;
+#else
+ // XXXXXXXXXXXXXXXXXXXXXXXX implement me.
+ return S2K_NO_SCRYPT_SUPPORT;
+#endif
}
case S2K_TYPE_SCRYPT: {
diff --git a/src/lib/crypt_ops/crypto_util.c b/src/lib/crypt_ops/crypto_util.c
index a645321bf..7af80291e 100644
--- a/src/lib/crypt_ops/crypto_util.c
+++ b/src/lib/crypt_ops/crypto_util.c
@@ -23,12 +23,14 @@
#include <wincrypt.h>
#endif /* defined(_WIN32) */
-DISABLE_GCC_WARNING(redundant-decls)
+#include <stdlib.h>
+#ifdef ENABLE_OPENSSL
+DISABLE_GCC_WARNING(redundant-decls)
#include <openssl/err.h>
#include <openssl/crypto.h>
-
ENABLE_GCC_WARNING(redundant-decls)
+#endif
#include "lib/log/log.h"
#include "lib/log/util_bug.h"
diff --git a/src/lib/crypt_ops/include.am b/src/lib/crypt_ops/include.am
index 195dac6bd..1022096fd 100644
--- a/src/lib/crypt_ops/include.am
+++ b/src/lib/crypt_ops/include.am
@@ -9,7 +9,6 @@ src_lib_libtor_crypt_ops_a_SOURCES = \
src/lib/crypt_ops/crypto_cipher.c \
src/lib/crypt_ops/crypto_curve25519.c \
src/lib/crypt_ops/crypto_dh.c \
- src/lib/crypt_ops/crypto_dh_openssl.c \
src/lib/crypt_ops/crypto_digest.c \
src/lib/crypt_ops/crypto_ed25519.c \
src/lib/crypt_ops/crypto_format.c \
@@ -37,6 +36,7 @@ endif
if USE_OPENSSL
src_lib_libtor_crypt_ops_a_SOURCES += \
+ src/lib/crypt_ops/crypto_dh_openssl.c \
src/lib/crypt_ops/crypto_openssl_mgt.c
endif
diff --git a/src/lib/tls/tortls_internal.h b/src/lib/tls/tortls_internal.h
index f6afb348c..c58379e19 100644
--- a/src/lib/tls/tortls_internal.h
+++ b/src/lib/tls/tortls_internal.h
@@ -15,28 +15,38 @@ struct ssl_session_st;
int tor_errno_to_tls_error(int e);
int tor_tls_get_error(tor_tls_t *tls, int r, int extra,
const char *doing, int severity, int domain);
-tor_tls_t *tor_tls_get_by_ssl(const struct ssl_st *ssl);
-void tor_tls_allocate_tor_tls_object_ex_data_index(void);
MOCK_DECL(void, try_to_extract_certs_from_tls,
(int severity, tor_tls_t *tls,
tor_x509_cert_impl_t **cert_out,
tor_x509_cert_impl_t **id_cert_out));
-#ifdef TORTLS_OPENSSL_PRIVATE
-int always_accept_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx);
-int tor_tls_classify_client_ciphers(const struct ssl_st *ssl,
- STACK_OF(SSL_CIPHER) *peer_ciphers);
-#endif
+
+tor_tls_context_t *tor_tls_context_new(crypto_pk_t *identity,
+ unsigned int key_lifetime, unsigned flags, int is_client);
+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);
+
+#ifdef ENABLE_OPENSSL
+tor_tls_t *tor_tls_get_by_ssl(const struct ssl_st *ssl);
int tor_tls_client_is_using_v2_ciphers(const struct ssl_st *ssl);
-#ifndef HAVE_SSL_SESSION_GET_MASTER_KEY
-size_t SSL_SESSION_get_master_key(struct ssl_session_st *s,
- uint8_t *out,
- size_t len);
-#endif
void tor_tls_debug_state_callback(const struct ssl_st *ssl,
int type, int val);
void tor_tls_server_info_callback(const struct ssl_st *ssl,
int type, int val);
+void tor_tls_allocate_tor_tls_object_ex_data_index(void);
+
+#if !defined(HAVE_SSL_SESSION_GET_MASTER_KEY)
+size_t SSL_SESSION_get_master_key(struct ssl_session_st *s,
+ uint8_t *out,
+ size_t len);
+#endif
+
#ifdef TORTLS_OPENSSL_PRIVATE
+int always_accept_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx);
+int tor_tls_classify_client_ciphers(const struct ssl_st *ssl,
+ STACK_OF(SSL_CIPHER) *peer_ciphers);
STATIC int tor_tls_session_secret_cb(struct ssl_st *ssl, void *secret,
int *secret_len,
STACK_OF(SSL_CIPHER) *peer_ciphers,
@@ -44,14 +54,8 @@ STATIC int tor_tls_session_secret_cb(struct ssl_st *ssl, void *secret,
void *arg);
STATIC int find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m,
uint16_t cipher);
-#endif /* defined(TORTLS_OPENSSL_PRIVATE) */
-tor_tls_context_t *tor_tls_context_new(crypto_pk_t *identity,
- unsigned int key_lifetime, unsigned flags, int is_client);
-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);
+#endif
+#endif
#ifdef TOR_UNIT_TESTS
extern int tor_tls_object_ex_data_index;
diff --git a/src/lib/tls/tortls_nss.c b/src/lib/tls/tortls_nss.c
index 078196ac5..98fecdaf1 100644
--- a/src/lib/tls/tortls_nss.c
+++ b/src/lib/tls/tortls_nss.c
@@ -47,19 +47,6 @@ tor_tls_get_error(tor_tls_t *tls, int r, int extra,
// XXXX
return -1;
}
-tor_tls_t *
-tor_tls_get_by_ssl(const struct ssl_st *ssl)
-{
- (void) ssl;
- // XXXX
- // XXXX refers to ssl_st.
- return NULL;
-}
-void
-tor_tls_allocate_tor_tls_object_ex_data_index(void)
-{
- // XXXX openssl only.
-}
MOCK_IMPL(void,
try_to_extract_certs_from_tls,(int severity, tor_tls_t *tls,
tor_x509_cert_impl_t **cert_out,
@@ -71,36 +58,7 @@ try_to_extract_certs_from_tls,(int severity, tor_tls_t *tls,
(void)severity;
// XXXX
}
-int
-tor_tls_client_is_using_v2_ciphers(const struct ssl_st *ssl)
-{
- (void) ssl;
- // XXXX
- // XXXX refers to ssl_st.
- return 0;
-}
-void
-tor_tls_debug_state_callback(const struct ssl_st *ssl,
- int type, int val)
-{
- (void) ssl;
- (void)type;
- (void)val;
- // XXXX
- // XXXX refers to ssl_st.
-}
-
-void
-tor_tls_server_info_callback(const struct ssl_st *ssl,
- int type, int val)
-{
- (void)ssl;
- (void)type;
- (void)val;
- // XXXX
- // XXXX refers to ssl_st.
-}
tor_tls_context_t *
tor_tls_context_new(crypto_pk_t *identity,
unsigned int key_lifetime, unsigned flags, int is_client)
diff --git a/src/test/bench.c b/src/test/bench.c
index 2b90ccf73..359405905 100644
--- a/src/test/bench.c
+++ b/src/test/bench.c
@@ -13,11 +13,14 @@
#include "core/or/or.h"
#include "core/crypto/onion_tap.h"
#include "core/crypto/relay_crypto.h"
+
+#ifdef ENABLE_OPENSSL
#include <openssl/opensslv.h>
#include <openssl/evp.h>
#include <openssl/ec.h>
#include <openssl/ecdh.h>
#include <openssl/obj_mac.h>
+#endif
#include "core/or/circuitlist.h"
#include "app/config/config.h"
@@ -580,6 +583,7 @@ bench_dh(void)
" %f millisec each.\n", NANOCOUNT(start, end, iters)/1e6);
}
+#ifdef ENABLE_OPENSSL
static void
bench_ecdh_impl(int nid, const char *name)
{
@@ -629,6 +633,7 @@ bench_ecdh_p224(void)
{
bench_ecdh_impl(NID_secp224r1, "P-224");
}
+#endif
typedef void (*bench_fn)(void);
@@ -652,8 +657,11 @@ static struct benchmark_t benchmarks[] = {
ENT(cell_aes),
ENT(cell_ops),
ENT(dh),
+
+#ifdef ENABLE_OPENSSL
ENT(ecdh_p256),
ENT(ecdh_p224),
+#endif
{NULL,NULL,0}
};
diff --git a/src/test/include.am b/src/test/include.am
index c2e08aa3d..05149b865 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -118,7 +118,6 @@ src_test_test_SOURCES += \
src/test/test_controller_events.c \
src/test/test_crypto.c \
src/test/test_crypto_ope.c \
- src/test/test_crypto_openssl.c \
src/test/test_data.c \
src/test/test_dir.c \
src/test/test_dir_common.c \
@@ -189,6 +188,7 @@ if USE_NSS
# ...
else
src_test_test_SOURCES += \
+ src/test/test_crypto_openssl.c \
src/test/test_tortls_openssl.c
endif
diff --git a/src/test/test.c b/src/test/test.c
index 3b63f1c07..962344305 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -866,7 +866,9 @@ struct testgroup_t testgroups[] = {
{ "control/event/", controller_event_tests },
{ "crypto/", crypto_tests },
{ "crypto/ope/", crypto_ope_tests },
+#ifdef ENABLE_OPENSSL
{ "crypto/openssl/", crypto_openssl_tests },
+#endif
{ "crypto/pem/", pem_tests },
{ "dir/", dir_tests },
{ "dir_handle_get/", dir_handle_get_tests },
diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c
index 90fb8d468..04077b42f 100644
--- a/src/test/test_crypto.c
+++ b/src/test/test_crypto.c
@@ -224,6 +224,9 @@ static void
test_crypto_openssl_version(void *arg)
{
(void)arg;
+#ifdef ENABLE_NSS
+ tt_skip();
+#else
const char *version = crypto_openssl_get_version_str();
const char *h_version = crypto_openssl_get_header_version_str();
tt_assert(version);
@@ -243,6 +246,7 @@ test_crypto_openssl_version(void *arg)
tt_int_op(a, OP_GE, 0);
tt_int_op(b, OP_GE, 0);
tt_int_op(c, OP_GE, 0);
+#endif
done:
;
diff --git a/src/test/test_crypto_slow.c b/src/test/test_crypto_slow.c
index 88b31ad9a..ca6b7b8d4 100644
--- a/src/test/test_crypto_slow.c
+++ b/src/test/test_crypto_slow.c
@@ -18,7 +18,9 @@
#include <libscrypt.h>
#endif
+#ifdef ENABLE_OPENSSL
#include <openssl/evp.h>
+#endif
/** Run unit tests for our secret-to-key passphrase hashing functionality. */
static void
diff --git a/src/tools/include.am b/src/tools/include.am
index cdd5616fb..73ec86935 100644
--- a/src/tools/include.am
+++ b/src/tools/include.am
@@ -1,7 +1,7 @@
-bin_PROGRAMS+= src/tools/tor-resolve src/tools/tor-gencert src/tools/tor-print-ed-signing-cert
+bin_PROGRAMS+= src/tools/tor-resolve src/tools/tor-print-ed-signing-cert
if COVERAGE_ENABLED
-noinst_PROGRAMS+= src/tools/tor-cov-resolve src/tools/tor-cov-gencert
+noinst_PROGRAMS+= src/tools/tor-cov-resolve
endif
src_tools_tor_resolve_SOURCES = src/tools/tor-resolve.c
@@ -20,6 +20,10 @@ src_tools_tor_cov_resolve_LDADD = \
@TOR_LIB_MATH@ @TOR_LIB_WS32@
endif
+if USE_NSS
+# ...
+else
+bin_PROGRAMS += src/tools/tor-gencert
src_tools_tor_gencert_SOURCES = src/tools/tor-gencert.c
src_tools_tor_gencert_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB)
src_tools_tor_gencert_LDADD = \
@@ -28,6 +32,7 @@ src_tools_tor_gencert_LDADD = \
$(rust_ldadd) \
@TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ $(TOR_LIBS_CRYPTLIB) \
@TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@
+endif
src_tools_tor_print_ed_signing_cert_SOURCES = src/tools/tor-print-ed-signing-cert.c
src_tools_tor_print_ed_signing_cert_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@
@@ -38,7 +43,11 @@ src_tools_tor_print_ed_signing_cert_LDADD = \
@TOR_LIB_MATH@ $(TOR_LIBS_CRYPTLIB) \
@TOR_LIB_WS32@ @TOR_LIB_USERENV@
+if USE_NSS
+# ...
+else
if COVERAGE_ENABLED
+noinst_PROGRAMS += src/tools/tor-cov-gencert
src_tools_tor_cov_gencert_SOURCES = src/tools/tor-gencert.c
src_tools_tor_cov_gencert_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_tools_tor_cov_gencert_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
@@ -49,6 +58,7 @@ src_tools_tor_cov_gencert_LDADD = \
@TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ $(TOR_LIBS_CRYPTLIB) \
@TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
endif
+endif
if BUILD_LIBTORRUNNER
noinst_LIBRARIES += src/tools/libtorrunner.a
diff --git a/src/tools/tor-gencert.c b/src/tools/tor-gencert.c
index e0ac3dec8..a498c205b 100644
--- a/src/tools/tor-gencert.c
+++ b/src/tools/tor-gencert.c
@@ -17,6 +17,7 @@
#include "lib/crypt_ops/crypto_init.h"
#include "lib/crypt_ops/crypto_openssl_mgt.h"
+#ifdef ENABLE_OPENSSL
/* Some versions of OpenSSL declare X509_STORE_CTX_set_verify_cb twice in
* x509.h and x509_vfy.h. Suppress the GCC warning so we can build with
* -Wredundant-decl. */
@@ -30,6 +31,7 @@ DISABLE_GCC_WARNING(redundant-decls)
#include <openssl/err.h>
ENABLE_GCC_WARNING(redundant-decls)
+#endif
#include <errno.h>
1
0

[tor/master] Extract the non-generic part of tor_tls_context_decref().
by nickm@torproject.org 05 Sep '18
by nickm@torproject.org 05 Sep '18
05 Sep '18
commit 108d9879eb814bc06095a1819d98b1c7c9a38e88
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Sun Aug 12 17:54:06 2018 -0400
Extract the non-generic part of tor_tls_context_decref().
---
src/lib/tls/tortls.c | 19 +++++++++++++++++++
src/lib/tls/tortls_internal.h | 7 +++++++
src/lib/tls/tortls_nss.c | 7 +++++++
src/lib/tls/tortls_openssl.c | 28 +++++++++-------------------
4 files changed, 42 insertions(+), 19 deletions(-)
diff --git a/src/lib/tls/tortls.c b/src/lib/tls/tortls.c
index 4b35177df..395f0148e 100644
--- a/src/lib/tls/tortls.c
+++ b/src/lib/tls/tortls.c
@@ -35,6 +35,25 @@ tor_tls_context_incref(tor_tls_context_t *ctx)
++ctx->refcnt;
}
+/** Remove a reference to <b>ctx</b>, and free it if it has no more
+ * references. */
+void
+tor_tls_context_decref(tor_tls_context_t *ctx)
+{
+ tor_assert(ctx);
+ if (--ctx->refcnt == 0) {
+ tor_tls_context_impl_free(ctx->ctx);
+ tor_x509_cert_free(ctx->my_link_cert);
+ tor_x509_cert_free(ctx->my_id_cert);
+ tor_x509_cert_free(ctx->my_auth_cert);
+ crypto_pk_free(ctx->link_key);
+ crypto_pk_free(ctx->auth_key);
+ /* LCOV_EXCL_BR_START since ctx will never be NULL here */
+ tor_free(ctx);
+ /* LCOV_EXCL_BR_STOP */
+ }
+}
+
/** Free all global TLS structures. */
void
tor_tls_free_all(void)
diff --git a/src/lib/tls/tortls_internal.h b/src/lib/tls/tortls_internal.h
index c58379e19..b997ee3e4 100644
--- a/src/lib/tls/tortls_internal.h
+++ b/src/lib/tls/tortls_internal.h
@@ -29,6 +29,13 @@ int tor_tls_context_init_one(tor_tls_context_t **ppcontext,
int is_client);
#ifdef ENABLE_OPENSSL
+void tor_tls_context_impl_free(struct ssl_ctx_st *);
+#else
+struct ssl_ctx_st; // XXXX replace
+void tor_tls_context_impl_free(struct ssl_ctx_st *);
+#endif
+
+#ifdef ENABLE_OPENSSL
tor_tls_t *tor_tls_get_by_ssl(const struct ssl_st *ssl);
int tor_tls_client_is_using_v2_ciphers(const struct ssl_st *ssl);
void tor_tls_debug_state_callback(const struct ssl_st *ssl,
diff --git a/src/lib/tls/tortls_nss.c b/src/lib/tls/tortls_nss.c
index 98fecdaf1..3ab5c753d 100644
--- a/src/lib/tls/tortls_nss.c
+++ b/src/lib/tls/tortls_nss.c
@@ -85,6 +85,13 @@ tor_tls_context_init_one(tor_tls_context_t **ppcontext,
// XXXX
return -1;
}
+void
+tor_tls_context_impl_free(struct ssl_ctx_st *ctx)
+{
+ (void)ctx;
+ // XXXX
+ // XXXX openssl type.
+}
void
tor_tls_get_state_description(tor_tls_t *tls, char *buf, size_t sz)
diff --git a/src/lib/tls/tortls_openssl.c b/src/lib/tls/tortls_openssl.c
index 333b86481..5f5431235 100644
--- a/src/lib/tls/tortls_openssl.c
+++ b/src/lib/tls/tortls_openssl.c
@@ -30,6 +30,7 @@
#include "lib/crypt_ops/crypto_util.h"
#include "lib/crypt_ops/compat_openssl.h"
#include "lib/tls/x509.h"
+#include "lib/tls/x509_internal.h"
/* Some versions of OpenSSL declare SSL_get_selected_srtp_profile twice in
* srtp.h. Suppress the GCC warning so we can build with -Wredundant-decl. */
@@ -488,25 +489,6 @@ static const char CLIENT_CIPHER_LIST[] =
#undef CIPHER
#undef XCIPHER
-/** Remove a reference to <b>ctx</b>, and free it if it has no more
- * references. */
-void
-tor_tls_context_decref(tor_tls_context_t *ctx)
-{
- tor_assert(ctx);
- if (--ctx->refcnt == 0) {
- SSL_CTX_free(ctx->ctx);
- tor_x509_cert_free(ctx->my_link_cert);
- tor_x509_cert_free(ctx->my_id_cert);
- tor_x509_cert_free(ctx->my_auth_cert);
- crypto_pk_free(ctx->link_key);
- crypto_pk_free(ctx->auth_key);
- /* LCOV_EXCL_BR_START since ctx will never be NULL here */
- tor_free(ctx);
- /* LCOV_EXCL_BR_STOP */
- }
-}
-
/** 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
@@ -599,6 +581,14 @@ tor_tls_context_init_one(tor_tls_context_t **ppcontext,
return ((new_ctx != NULL) ? 0 : -1);
}
+void
+tor_tls_context_impl_free(struct ssl_ctx_st *ctx)
+{
+ if (!ctx)
+ return;
+ SSL_CTX_free(ctx);
+}
+
/** The group we should use for ecdhe when none was selected. */
#define NID_tor_default_ecdhe_group NID_X9_62_prime256v1
1
0
commit b9ca8f2356a98630a262951486cd10436963e169
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Sun Aug 12 18:01:14 2018 -0400
Extract internal-only parts of x509.h
---
src/lib/tls/include.am | 3 ++-
src/lib/tls/x509.c | 1 +
src/lib/tls/x509.h | 11 -----------
src/lib/tls/x509_internal.h | 28 ++++++++++++++++++++++++++++
src/lib/tls/x509_nss.c | 1 +
src/lib/tls/x509_openssl.c | 1 +
src/test/test_tortls.c | 1 +
src/test/test_tortls_openssl.c | 1 +
8 files changed, 35 insertions(+), 12 deletions(-)
diff --git a/src/lib/tls/include.am b/src/lib/tls/include.am
index 173104903..b25e2e16b 100644
--- a/src/lib/tls/include.am
+++ b/src/lib/tls/include.am
@@ -34,4 +34,5 @@ noinst_HEADERS += \
src/lib/tls/tortls.h \
src/lib/tls/tortls_internal.h \
src/lib/tls/tortls_st.h \
- src/lib/tls/x509.h
+ src/lib/tls/x509.h \
+ src/lib/tls/x509_internal.h
diff --git a/src/lib/tls/x509.c b/src/lib/tls/x509.c
index dbf1dd927..fc6139ace 100644
--- a/src/lib/tls/x509.c
+++ b/src/lib/tls/x509.c
@@ -11,6 +11,7 @@
#define TOR_X509_PRIVATE
#include "lib/tls/x509.h"
+#include "lib/tls/x509_internal.h"
#include "lib/log/util_bug.h"
#include "lib/crypt_ops/crypto_rand.h"
diff --git a/src/lib/tls/x509.h b/src/lib/tls/x509.h
index f75d15d7e..ccaa92184 100644
--- a/src/lib/tls/x509.h
+++ b/src/lib/tls/x509.h
@@ -40,15 +40,6 @@ void tor_tls_pick_certificate_lifetime(time_t now,
time_t *start_time_out,
time_t *end_time_out);
-MOCK_DECL(tor_x509_cert_impl_t *, tor_tls_create_certificate,
- (crypto_pk_t *rsa,
- crypto_pk_t *rsa_sign,
- const char *cname,
- const char *cname_sign,
- unsigned int cert_lifetime));
-MOCK_DECL(tor_x509_cert_t *, tor_x509_cert_new,
- (tor_x509_cert_impl_t *x509_cert));
-
#ifdef TOR_UNIT_TESTS
tor_x509_cert_t *tor_x509_cert_replace_expiration(
const tor_x509_cert_t *inp,
@@ -63,8 +54,6 @@ void tor_x509_cert_free_(tor_x509_cert_t *cert);
FREE_AND_NULL(tor_x509_cert_t, tor_x509_cert_free_, (c))
tor_x509_cert_t *tor_x509_cert_decode(const uint8_t *certificate,
size_t certificate_len);
-const tor_x509_cert_impl_t *tor_x509_cert_get_impl(
- const tor_x509_cert_t *cert);
void tor_x509_cert_get_der(const tor_x509_cert_t *cert,
const uint8_t **encoded_out, size_t *size_out);
diff --git a/src/lib/tls/x509_internal.h b/src/lib/tls/x509_internal.h
new file mode 100644
index 000000000..2cca393d2
--- /dev/null
+++ b/src/lib/tls/x509_internal.h
@@ -0,0 +1,28 @@
+/* Copyright (c) 2003, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_X509_INTERNAL_H
+#define TOR_X509_INTERNAL_H
+
+/**
+ * \file x509.h
+ * \brief Internal headers for tortls.c
+ **/
+
+#include "lib/crypt_ops/crypto_rsa.h"
+#include "lib/testsupport/testsupport.h"
+
+MOCK_DECL(tor_x509_cert_impl_t *, tor_tls_create_certificate,
+ (crypto_pk_t *rsa,
+ crypto_pk_t *rsa_sign,
+ const char *cname,
+ const char *cname_sign,
+ unsigned int cert_lifetime));
+MOCK_DECL(tor_x509_cert_t *, tor_x509_cert_new,
+ (tor_x509_cert_impl_t *x509_cert));
+const tor_x509_cert_impl_t *tor_x509_cert_get_impl(
+ const tor_x509_cert_t *cert);
+
+#endif
diff --git a/src/lib/tls/x509_nss.c b/src/lib/tls/x509_nss.c
index e856c9518..e0087eae6 100644
--- a/src/lib/tls/x509_nss.c
+++ b/src/lib/tls/x509_nss.c
@@ -11,6 +11,7 @@
#define TOR_X509_PRIVATE
#include "lib/tls/x509.h"
+#include "lib/tls/x509_internal.h"
#include "lib/tls/tortls.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
diff --git a/src/lib/tls/x509_openssl.c b/src/lib/tls/x509_openssl.c
index c003d4704..43d33d781 100644
--- a/src/lib/tls/x509_openssl.c
+++ b/src/lib/tls/x509_openssl.c
@@ -11,6 +11,7 @@
#define TOR_X509_PRIVATE
#include "lib/tls/x509.h"
+#include "lib/tls/x509_internal.h"
#include "lib/tls/tortls.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
diff --git a/src/test/test_tortls.c b/src/test/test_tortls.c
index d20bc5fa6..eedf0dd3c 100644
--- a/src/test/test_tortls.c
+++ b/src/test/test_tortls.c
@@ -19,6 +19,7 @@
#include "app/config/config.h"
#include "lib/crypt_ops/compat_openssl.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"
diff --git a/src/test/test_tortls_openssl.c b/src/test/test_tortls_openssl.c
index a9336a6f1..12a05b303 100644
--- a/src/test/test_tortls_openssl.c
+++ b/src/test/test_tortls_openssl.c
@@ -36,6 +36,7 @@ ENABLE_GCC_WARNING(redundant-decls)
#include "app/config/config.h"
#include "lib/crypt_ops/compat_openssl.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"
1
0

05 Sep '18
commit 91c1e88b7a6d41f93f88cd8754746c836b25721f
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Sat Aug 11 19:54:11 2018 -0400
Refactor some of the certificate-manipulation logic
---
src/lib/tls/tortls.c | 5 ++--
src/lib/tls/x509.c | 68 ++++++++++++++++++++++++++++++++--------------------
src/lib/tls/x509.h | 14 +++++++----
3 files changed, 55 insertions(+), 32 deletions(-)
diff --git a/src/lib/tls/tortls.c b/src/lib/tls/tortls.c
index cb507057e..4c5dedb57 100644
--- a/src/lib/tls/tortls.c
+++ b/src/lib/tls/tortls.c
@@ -1856,8 +1856,9 @@ tor_tls_check_lifetime(int severity, tor_tls_t *tls,
if (!(cert = SSL_get_peer_certificate(tls->ssl)))
goto done;
- if (check_cert_lifetime_internal(severity, cert, now,
- past_tolerance, future_tolerance) < 0)
+ if (tor_x509_check_cert_lifetime_internal(severity, cert, now,
+ past_tolerance,
+ future_tolerance) < 0)
goto done;
r = 0;
diff --git a/src/lib/tls/x509.c b/src/lib/tls/x509.c
index 27cba1be6..8bed6f5a1 100644
--- a/src/lib/tls/x509.c
+++ b/src/lib/tls/x509.c
@@ -85,6 +85,42 @@ tor_x509_name_new(const char *cname)
/* LCOV_EXCL_STOP */
}
+/** Choose the start and end times for a certificate */
+void
+tor_tls_pick_certificate_lifetime(time_t now,
+ unsigned int cert_lifetime,
+ time_t *start_time_out,
+ time_t *end_time_out)
+{
+ time_t start_time, end_time;
+ /* Make sure we're part-way through the certificate lifetime, rather
+ * than having it start right now. Don't choose quite uniformly, since
+ * then we might pick a time where we're about to expire. Lastly, be
+ * sure to start on a day boundary. */
+ /* Our certificate lifetime will be cert_lifetime no matter what, but if we
+ * start cert_lifetime in the past, we'll have 0 real lifetime. instead we
+ * start up to (cert_lifetime - min_real_lifetime - start_granularity) in
+ * the past. */
+ const time_t min_real_lifetime = 24*3600;
+ const time_t start_granularity = 24*3600;
+ time_t earliest_start_time;
+ /* Don't actually start in the future! */
+ if (cert_lifetime <= min_real_lifetime + start_granularity) {
+ earliest_start_time = now - 1;
+ } else {
+ earliest_start_time = now + min_real_lifetime + start_granularity
+ - cert_lifetime;
+ }
+ start_time = crypto_rand_time_range(earliest_start_time, now);
+ /* Round the start time back to the start of a day. */
+ start_time -= start_time % start_granularity;
+
+ end_time = start_time + cert_lifetime;
+
+ *start_time_out = start_time;
+ *end_time_out = end_time;
+}
+
/** Generate and sign an X509 certificate with the public key <b>rsa</b>,
* signed by the private key <b>rsa_sign</b>. The commonName of the
* certificate will be <b>cname</b>; the commonName of the issuer will be
@@ -113,30 +149,10 @@ tor_tls_create_certificate,(crypto_pk_t *rsa,
tor_tls_init();
- /* Make sure we're part-way through the certificate lifetime, rather
- * than having it start right now. Don't choose quite uniformly, since
- * then we might pick a time where we're about to expire. Lastly, be
- * sure to start on a day boundary. */
time_t now = time(NULL);
- /* Our certificate lifetime will be cert_lifetime no matter what, but if we
- * start cert_lifetime in the past, we'll have 0 real lifetime. instead we
- * start up to (cert_lifetime - min_real_lifetime - start_granularity) in
- * the past. */
- const time_t min_real_lifetime = 24*3600;
- const time_t start_granularity = 24*3600;
- time_t earliest_start_time;
- /* Don't actually start in the future! */
- if (cert_lifetime <= min_real_lifetime + start_granularity) {
- earliest_start_time = now - 1;
- } else {
- earliest_start_time = now + min_real_lifetime + start_granularity
- - cert_lifetime;
- }
- start_time = crypto_rand_time_range(earliest_start_time, now);
- /* Round the start time back to the start of a day. */
- start_time -= start_time % start_granularity;
- end_time = start_time + cert_lifetime;
+ tor_tls_pick_certificate_lifetime(now, cert_lifetime,
+ &start_time, &end_time);
tor_assert(rsa);
tor_assert(cname);
@@ -410,7 +426,7 @@ tor_tls_cert_is_valid(int severity,
/* okay, the signature checked out right. Now let's check the check the
* lifetime. */
- if (check_cert_lifetime_internal(severity, cert->cert, now,
+ if (tor_x509_check_cert_lifetime_internal(severity, cert->cert, now,
48*60*60, 30*24*60*60) < 0)
goto bad;
@@ -509,9 +525,9 @@ log_cert_lifetime(int severity, const X509 *cert, const char *problem,
* <b>now</b>.) If it is live, return 0. If it is not live, log a message
* and return -1. */
int
-check_cert_lifetime_internal(int severity, const X509 *cert,
- time_t now,
- int past_tolerance, int future_tolerance)
+tor_x509_check_cert_lifetime_internal(int severity, const X509 *cert,
+ time_t now,
+ int past_tolerance, int future_tolerance)
{
time_t t;
diff --git a/src/lib/tls/x509.h b/src/lib/tls/x509.h
index 4dadba06d..e3dfcf393 100644
--- a/src/lib/tls/x509.h
+++ b/src/lib/tls/x509.h
@@ -33,6 +33,11 @@ struct tor_x509_cert_t {
};
#endif
+void tor_tls_pick_certificate_lifetime(time_t now,
+ unsigned cert_lifetime,
+ time_t *start_time_out,
+ time_t *end_time_out);
+
MOCK_DECL(tor_x509_cert_impl_t *, tor_tls_create_certificate,
(crypto_pk_t *rsa,
crypto_pk_t *rsa_sign,
@@ -74,9 +79,10 @@ int tor_tls_cert_is_valid(int severity,
time_t now,
int check_rsa_1024);
-int check_cert_lifetime_internal(int severity,
- const tor_x509_cert_impl_t *cert,
- time_t now,
- int past_tolerance, int future_tolerance);
+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
1
0

[tor/master] Make some x509 functions generic; remove some fields NSS doesn't need
by nickm@torproject.org 05 Sep '18
by nickm@torproject.org 05 Sep '18
05 Sep '18
commit 5245a296c58eb8aba712e94a78d5bcaa2a2f25fb
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Sun Aug 12 19:40:47 2018 -0400
Make some x509 functions generic; remove some fields NSS doesn't need
---
src/lib/tls/x509.c | 79 +++++++++++++++++++++++++++++++++-------
src/lib/tls/x509.h | 2 ++
src/lib/tls/x509_internal.h | 7 ++++
src/lib/tls/x509_nss.c | 35 +++++++++++-------
src/lib/tls/x509_openssl.c | 82 +++++++++++++-----------------------------
src/test/test_link_handshake.c | 8 +++--
6 files changed, 127 insertions(+), 86 deletions(-)
diff --git a/src/lib/tls/x509.c b/src/lib/tls/x509.c
index fc6139ace..d2270f910 100644
--- a/src/lib/tls/x509.c
+++ b/src/lib/tls/x509.c
@@ -14,6 +14,7 @@
#include "lib/tls/x509_internal.h"
#include "lib/log/util_bug.h"
#include "lib/crypt_ops/crypto_rand.h"
+#include "lib/crypt_ops/crypto_util.h"
/** Choose the start and end times for a certificate */
void
@@ -51,19 +52,6 @@ tor_tls_pick_certificate_lifetime(time_t now,
*end_time_out = end_time;
}
-/** Set *<b>encoded_out</b> and *<b>size_out</b> to <b>cert</b>'s encoded DER
- * representation and length, respectively. */
-void
-tor_x509_cert_get_der(const tor_x509_cert_t *cert,
- const uint8_t **encoded_out, size_t *size_out)
-{
- tor_assert(cert);
- tor_assert(encoded_out);
- tor_assert(size_out);
- *encoded_out = cert->encoded;
- *size_out = cert->encoded_len;
-}
-
/** Return the underlying implementation for <b>cert</b> */
const tor_x509_cert_impl_t *
tor_x509_cert_get_impl(const tor_x509_cert_t *cert)
@@ -90,3 +78,68 @@ tor_x509_cert_get_cert_digests(const tor_x509_cert_t *cert)
return &cert->cert_digests;
}
+/** Free all storage held in <b>cert</b> */
+void
+tor_x509_cert_free_(tor_x509_cert_t *cert)
+{
+ if (! cert)
+ return;
+ if (cert->cert)
+ tor_x509_cert_impl_free_(cert->cert);
+#ifdef ENABLE_OPENSSL
+ tor_free(cert->encoded);
+#endif
+ memwipe(cert, 0x03, sizeof(*cert));
+ /* LCOV_EXCL_BR_START since cert will never be NULL here */
+ tor_free(cert);
+ /* LCOV_EXCL_BR_STOP */
+}
+
+/**
+ * Allocate a new tor_x509_cert_t to hold the certificate "x509_cert".
+ *
+ * Steals a reference to x509_cert.
+ */
+MOCK_IMPL(tor_x509_cert_t *,
+tor_x509_cert_new,(tor_x509_cert_impl_t *x509_cert))
+{
+ tor_x509_cert_t *cert;
+
+ if (!x509_cert)
+ return NULL;
+
+ cert = tor_malloc_zero(sizeof(tor_x509_cert_t));
+ cert->cert = x509_cert;
+
+ if (tor_x509_cert_set_cached_der_encoding(cert) < 0)
+ goto err;
+
+ {
+ const uint8_t *encoded=NULL;
+ size_t encoded_len=0;
+ tor_x509_cert_get_der(cert, &encoded, &encoded_len);
+ tor_assert(encoded);
+ crypto_common_digests(&cert->cert_digests, (char *)encoded, encoded_len);
+ }
+
+ {
+ crypto_pk_t *pk = tor_tls_cert_get_key(cert);
+ if (pk) {
+ if (crypto_pk_get_common_digests(pk, &cert->pkey_digests) < 0) {
+ crypto_pk_free(pk);
+ goto err;
+ }
+ }
+ cert->pkey_digests_set = 1;
+ crypto_pk_free(pk);
+ }
+
+ return cert;
+ err:
+ /* LCOV_EXCL_START for the same reason as the exclusion above */
+ tor_free(cert);
+ log_err(LD_CRYPTO, "Couldn't wrap encoded X509 certificate.");
+ tor_x509_cert_impl_free_(x509_cert);
+ return NULL;
+ /* LCOV_EXCL_STOP */
+}
diff --git a/src/lib/tls/x509.h b/src/lib/tls/x509.h
index ccaa92184..8316df75a 100644
--- a/src/lib/tls/x509.h
+++ b/src/lib/tls/x509.h
@@ -27,8 +27,10 @@ typedef struct x509_st tor_x509_cert_impl_t;
/** Structure that we use for a single certificate. */
struct tor_x509_cert_t {
tor_x509_cert_impl_t *cert;
+#ifdef ENABLE_OPENSSL
uint8_t *encoded;
size_t encoded_len;
+#endif
unsigned pkey_digests_set : 1;
common_digests_t cert_digests;
common_digests_t pkey_digests;
diff --git a/src/lib/tls/x509_internal.h b/src/lib/tls/x509_internal.h
index 2cca393d2..86f5a0de5 100644
--- a/src/lib/tls/x509_internal.h
+++ b/src/lib/tls/x509_internal.h
@@ -25,4 +25,11 @@ 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);
+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);
+#else
+#define tor_x509_cert_set_cached_der_encoding(cert) (0)
+#endif
+
#endif
diff --git a/src/lib/tls/x509_nss.c b/src/lib/tls/x509_nss.c
index e0087eae6..ac9e6658d 100644
--- a/src/lib/tls/x509_nss.c
+++ b/src/lib/tls/x509_nss.c
@@ -17,6 +17,9 @@
#include "lib/crypt_ops/crypto_util.h"
#include "lib/log/util_bug.h"
+#include <pk11pub.h>
+#include <cert.h>
+
MOCK_IMPL(tor_x509_cert_impl_t *,
tor_tls_create_certificate,(crypto_pk_t *rsa,
crypto_pk_t *rsa_sign,
@@ -33,12 +36,27 @@ tor_tls_create_certificate,(crypto_pk_t *rsa,
return NULL;
}
-MOCK_IMPL(tor_x509_cert_t *,
-tor_x509_cert_new,(tor_x509_cert_impl_t *x509_cert))
+/** Set *<b>encoded_out</b> and *<b>size_out</b> to <b>cert</b>'s encoded DER
+ * representation and length, respectively. */
+void
+tor_x509_cert_get_der(const tor_x509_cert_t *cert,
+ const uint8_t **encoded_out, size_t *size_out)
{
- tor_assert(x509_cert);
- // XXXX
- return NULL;
+ tor_assert(cert);
+ tor_assert(cert->cert);
+ tor_assert(encoded_out);
+ tor_assert(size_out);
+
+ const SECItem *item = &cert->cert->derCert;
+ *encoded_out = item->data;
+ *size_out = (size_t)item->len;
+}
+
+void
+tor_x509_cert_impl_free_(tor_x509_cert_impl_t *cert)
+{
+ if (cert)
+ CERT_DestroyCertificate(cert);
}
tor_x509_cert_t *
@@ -49,13 +67,6 @@ tor_x509_cert_dup(const tor_x509_cert_t *cert)
return NULL;
}
-void
-tor_x509_cert_free_(tor_x509_cert_t *cert)
-{
- (void)cert;
- // XXXX
-}
-
tor_x509_cert_t *
tor_x509_cert_decode(const uint8_t *certificate,
size_t certificate_len)
diff --git a/src/lib/tls/x509_openssl.c b/src/lib/tls/x509_openssl.c
index 43d33d781..43bd6b4d4 100644
--- a/src/lib/tls/x509_openssl.c
+++ b/src/lib/tls/x509_openssl.c
@@ -182,75 +182,41 @@ tor_tls_create_certificate,(crypto_pk_t *rsa,
#undef SERIAL_NUMBER_SIZE
}
-/** Free all storage held in <b>cert</b> */
-void
-tor_x509_cert_free_(tor_x509_cert_t *cert)
-{
- if (! cert)
- return;
- if (cert->cert)
- X509_free(cert->cert);
- tor_free(cert->encoded);
- memwipe(cert, 0x03, sizeof(*cert));
- /* LCOV_EXCL_BR_START since cert will never be NULL here */
- tor_free(cert);
- /* LCOV_EXCL_BR_STOP */
-}
-
-/**
- * Allocate a new tor_x509_cert_t to hold the certificate "x509_cert".
- *
- * Steals a reference to x509_cert.
- */
-MOCK_IMPL(tor_x509_cert_t *,
-tor_x509_cert_new,(X509 *x509_cert))
+/** Set the 'encoded' and 'encoded_len' fields of "cert" from cert->cert. */
+int
+tor_x509_cert_set_cached_der_encoding(tor_x509_cert_t *cert)
{
- tor_x509_cert_t *cert;
- EVP_PKEY *pkey;
- RSA *rsa;
- int length;
unsigned char *buf = NULL;
+ int length = i2d_X509(cert->cert, &buf);
- if (!x509_cert)
- return NULL;
-
- length = i2d_X509(x509_cert, &buf);
- cert = tor_malloc_zero(sizeof(tor_x509_cert_t));
if (length <= 0 || buf == NULL) {
- goto err;
+ return -1;
}
cert->encoded_len = (size_t) length;
cert->encoded = tor_malloc(length);
memcpy(cert->encoded, buf, length);
OPENSSL_free(buf);
+ return 0;
+}
- cert->cert = x509_cert;
-
- crypto_common_digests(&cert->cert_digests,
- (char*)cert->encoded, cert->encoded_len);
-
- if ((pkey = X509_get_pubkey(x509_cert)) &&
- (rsa = EVP_PKEY_get1_RSA(pkey))) {
- crypto_pk_t *pk = crypto_new_pk_from_openssl_rsa_(rsa);
- if (crypto_pk_get_common_digests(pk, &cert->pkey_digests) < 0) {
- crypto_pk_free(pk);
- EVP_PKEY_free(pkey);
- goto err;
- }
-
- cert->pkey_digests_set = 1;
- crypto_pk_free(pk);
- EVP_PKEY_free(pkey);
- }
+void
+tor_x509_cert_impl_free_(tor_x509_cert_impl_t *cert)
+{
+ if (cert)
+ X509_free(cert);
+}
- return cert;
- err:
- /* LCOV_EXCL_START for the same reason as the exclusion above */
- tor_free(cert);
- log_err(LD_CRYPTO, "Couldn't wrap encoded X509 certificate.");
- X509_free(x509_cert);
- return NULL;
- /* LCOV_EXCL_STOP */
+/** Set *<b>encoded_out</b> and *<b>size_out</b> to <b>cert</b>'s encoded DER
+ * representation and length, respectively. */
+void
+tor_x509_cert_get_der(const tor_x509_cert_t *cert,
+ const uint8_t **encoded_out, size_t *size_out)
+{
+ tor_assert(cert);
+ tor_assert(encoded_out);
+ tor_assert(size_out);
+ *encoded_out = cert->encoded;
+ *size_out = cert->encoded_len;
}
/** Return a new copy of <b>cert</b>. */
diff --git a/src/test/test_link_handshake.c b/src/test/test_link_handshake.c
index e4722b4df..677276599 100644
--- a/src/test/test_link_handshake.c
+++ b/src/test/test_link_handshake.c
@@ -811,9 +811,11 @@ CERTS_FAIL(expired_rsa_id, /* both */
tor_x509_cert_t *newc;
time_t new_end = time(NULL) - 86400 * 10;
newc = tor_x509_cert_replace_expiration(idc, new_end, d->key2);
- certs_cell_cert_setlen_body(cert, newc->encoded_len);
- memcpy(certs_cell_cert_getarray_body(cert),
- newc->encoded, newc->encoded_len);
+ 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);
+ memcpy(certs_cell_cert_getarray_body(cert), encoded, encoded_len);
REENCODE();
tor_x509_cert_free(newc);
})
1
0
commit 5205c7fd903cb5bd751812bddb5497ac76e1f30b
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Fri Aug 17 11:24:50 2018 -0400
Initial NSS support for TLS.
This is enough to get a chutney network to bootstrap, though a bunch
of work remains.
---
src/lib/tls/tortls.c | 122 +++++++++
src/lib/tls/tortls.h | 23 +-
src/lib/tls/tortls_internal.h | 16 +-
src/lib/tls/tortls_nss.c | 621 +++++++++++++++++++++++++++++++++---------
src/lib/tls/tortls_openssl.c | 137 +---------
src/lib/tls/tortls_st.h | 17 +-
src/test/test_tortls.c | 26 +-
7 files changed, 656 insertions(+), 306 deletions(-)
diff --git a/src/lib/tls/tortls.c b/src/lib/tls/tortls.c
index 0b14b69f4..cc9738599 100644
--- a/src/lib/tls/tortls.c
+++ b/src/lib/tls/tortls.c
@@ -4,6 +4,7 @@
/* See LICENSE for licensing information */
#define TORTLS_PRIVATE
+#define TOR_X509_PRIVATE
#include "lib/tls/x509.h"
#include "lib/tls/x509_internal.h"
#include "lib/tls/tortls.h"
@@ -14,6 +15,8 @@
#include "lib/crypt_ops/crypto_rsa.h"
#include "lib/crypt_ops/crypto_rand.h"
+#include <time.h>
+
/** Global TLS contexts. We keep them here because nobody else needs
* to touch them.
*
@@ -31,6 +34,26 @@ tor_tls_context_get(int is_server)
return is_server ? server_tls_context : client_tls_context;
}
+/** Convert an errno (or a WSAerrno on windows) into a TOR_TLS_* error
+ * code. */
+int
+tor_errno_to_tls_error(int e)
+{
+ switch (e) {
+ case SOCK_ERRNO(ECONNRESET): // most common
+ return TOR_TLS_ERROR_CONNRESET;
+ case SOCK_ERRNO(ETIMEDOUT):
+ return TOR_TLS_ERROR_TIMEOUT;
+ case SOCK_ERRNO(EHOSTUNREACH):
+ case SOCK_ERRNO(ENETUNREACH):
+ return TOR_TLS_ERROR_NO_ROUTE;
+ case SOCK_ERRNO(ECONNREFUSED):
+ return TOR_TLS_ERROR_CONNREFUSED; // least common
+ default:
+ return TOR_TLS_ERROR_MISC;
+ }
+}
+
/** 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
@@ -334,3 +357,102 @@ tor_tls_is_server(tor_tls_t *tls)
tor_assert(tls);
return tls->isServer;
}
+
+/** Release resources associated with a TLS object. Does not close the
+ * underlying file descriptor.
+ */
+void
+tor_tls_free_(tor_tls_t *tls)
+{
+ if (!tls)
+ return;
+ tor_assert(tls->ssl);
+ {
+ size_t r,w;
+ tor_tls_get_n_raw_bytes(tls,&r,&w); /* ensure written_by_tls is updated */
+ }
+ tor_tls_impl_free_(tls->ssl);
+ tls->ssl = NULL;
+#ifdef ENABLE_OPENSSL
+ tls->negotiated_callback = NULL;
+#endif
+ if (tls->context)
+ tor_tls_context_decref(tls->context);
+ tor_free(tls->address);
+ tls->magic = 0x99999999;
+ tor_free(tls);
+}
+
+/** If the provided tls connection is authenticated and has a
+ * certificate chain that is currently valid and signed, then set
+ * *<b>identity_key</b> to the identity certificate's key and return
+ * 0. Else, return -1 and log complaints with log-level <b>severity</b>.
+ */
+int
+tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_t **identity)
+{
+ tor_x509_cert_impl_t *cert = NULL, *id_cert = NULL;
+ tor_x509_cert_t *peer_x509 = NULL, *id_x509 = NULL;
+ tor_assert(tls);
+ tor_assert(identity);
+ int rv = -1;
+
+ try_to_extract_certs_from_tls(severity, tls, &cert, &id_cert);
+ if (!cert)
+ goto done;
+ if (!id_cert) {
+ log_fn(severity,LD_PROTOCOL,"No distinct identity certificate found");
+ goto done;
+ }
+ peer_x509 = tor_x509_cert_new(cert);
+ id_x509 = tor_x509_cert_new(id_cert);
+ cert = id_cert = NULL; /* Prevent double-free */
+
+ if (! tor_tls_cert_is_valid(severity, peer_x509, id_x509, time(NULL), 0)) {
+ goto done;
+ }
+
+ *identity = tor_tls_cert_get_key(id_x509);
+ rv = 0;
+
+ done:
+ if (cert)
+ tor_x509_cert_impl_free_(cert);
+ if (id_cert)
+ tor_x509_cert_impl_free_(id_cert);
+ tor_x509_cert_free(peer_x509);
+ tor_x509_cert_free(id_x509);
+
+ return rv;
+}
+
+/** Check whether the certificate set on the connection <b>tls</b> is expired
+ * give or take <b>past_tolerance</b> seconds, or not-yet-valid give or take
+ * <b>future_tolerance</b> seconds. Return 0 for valid, -1 for failure.
+ *
+ * NOTE: you should call tor_tls_verify before tor_tls_check_lifetime.
+ */
+int
+tor_tls_check_lifetime(int severity, tor_tls_t *tls,
+ time_t now,
+ int past_tolerance, int future_tolerance)
+{
+ tor_x509_cert_t *cert;
+ int r = -1;
+
+ if (!(cert = tor_tls_get_peer_cert(tls)))
+ goto done;
+
+ if (tor_x509_check_cert_lifetime_internal(severity, cert->cert, now,
+ past_tolerance,
+ future_tolerance) < 0)
+ goto done;
+
+ r = 0;
+ done:
+ tor_x509_cert_free(cert);
+ /* Not expected to get invoked */
+ tls_log_errors(tls, LOG_WARN, LD_NET, "checking certificate lifetime");
+
+ return r;
+}
diff --git a/src/lib/tls/tortls.h b/src/lib/tls/tortls.h
index 306d321cd..7bbb42b2f 100644
--- a/src/lib/tls/tortls.h
+++ b/src/lib/tls/tortls.h
@@ -13,10 +13,25 @@
#include "lib/crypt_ops/crypto_rsa.h"
#include "lib/testsupport/testsupport.h"
+#include "lib/net/nettypes.h"
/* Opaque structure to hold a TLS connection. */
typedef struct tor_tls_t tor_tls_t;
+#ifdef TORTLS_PRIVATE
+#ifdef ENABLE_OPENSSL
+struct ssl_st;
+struct ssl_ctx_st;
+struct ssl_session_st;
+typedef struct ssl_ctx_st tor_tls_context_impl_t;
+typedef struct ssl_st tor_tls_impl_t;
+#else
+struct PRFileDesc;
+typedef struct PRFileDesc tor_tls_context_impl_t;
+typedef struct PRFileDesc tor_tls_impl_t;
+#endif
+#endif
+
struct tor_x509_cert_t;
/* Possible return values for most tor_tls_* functions. */
@@ -73,7 +88,7 @@ int tor_tls_context_init(unsigned flags,
void tor_tls_context_incref(tor_tls_context_t *ctx);
void tor_tls_context_decref(tor_tls_context_t *ctx);
tor_tls_context_t *tor_tls_context_get(int is_server);
-tor_tls_t *tor_tls_new(int sock, int is_server);
+tor_tls_t *tor_tls_new(tor_socket_t sock, int is_server);
void tor_tls_set_logged_address(tor_tls_t *tls, const char *address);
void tor_tls_set_renegotiate_callback(tor_tls_t *tls,
void (*cb)(tor_tls_t *, void *arg),
@@ -121,13 +136,17 @@ MOCK_DECL(int,tor_tls_export_key_material,(
size_t context_len,
const char *label));
+#ifdef ENABLE_OPENSSL
/* Log and abort if there are unhandled TLS errors in OpenSSL's error stack.
*/
#define check_no_tls_errors() check_no_tls_errors_(__FILE__,__LINE__)
-
void check_no_tls_errors_(const char *fname, int line);
+
void tor_tls_log_one_error(tor_tls_t *tls, unsigned long err,
int severity, int domain, const char *doing);
+#else
+#define check_no_tls_errors() STMT_NIL
+#endif
int tor_tls_get_my_certs(int server,
const struct tor_x509_cert_t **link_cert_out,
diff --git a/src/lib/tls/tortls_internal.h b/src/lib/tls/tortls_internal.h
index 2920e9658..b9e01e0c5 100644
--- a/src/lib/tls/tortls_internal.h
+++ b/src/lib/tls/tortls_internal.h
@@ -6,15 +6,11 @@
#ifndef TORTLS_INTERNAL_H
#define TORTLS_INTERNAL_H
-#ifdef ENABLE_OPENSSL
-struct ssl_st;
-struct ssl_ctx_st;
-struct ssl_session_st;
-#endif
-
int tor_errno_to_tls_error(int e);
+#ifdef ENABLE_OPENSSL
int tor_tls_get_error(tor_tls_t *tls, int r, int extra,
const char *doing, int severity, int domain);
+#endif
MOCK_DECL(void, try_to_extract_certs_from_tls,
(int severity, tor_tls_t *tls,
tor_x509_cert_impl_t **cert_out,
@@ -31,13 +27,9 @@ int tor_tls_context_init_certificates(tor_tls_context_t *result,
crypto_pk_t *identity,
unsigned key_lifetime,
unsigned flags);
+void tor_tls_impl_free_(tor_tls_impl_t *ssl);
-#ifdef ENABLE_OPENSSL
-void tor_tls_context_impl_free(struct ssl_ctx_st *);
-#else
-struct ssl_ctx_st; // XXXX replace
-void tor_tls_context_impl_free(struct ssl_ctx_st *);
-#endif
+void tor_tls_context_impl_free(tor_tls_context_impl_t *);
#ifdef ENABLE_OPENSSL
tor_tls_t *tor_tls_get_by_ssl(const struct ssl_st *ssl);
diff --git a/src/lib/tls/tortls_nss.c b/src/lib/tls/tortls_nss.c
index 35dbc27d9..d2b81ad08 100644
--- a/src/lib/tls/tortls_nss.c
+++ b/src/lib/tls/tortls_nss.c
@@ -12,6 +12,7 @@
#include "orconfig.h"
#define TORTLS_PRIVATE
+#define TOR_X509_PRIVATE
#ifdef _WIN32 /*wrkard for dtls1.h >= 0.9.8m of "#include <winsock.h>"*/
#include <winsock2.h>
@@ -22,6 +23,9 @@
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_dh.h"
#include "lib/crypt_ops/crypto_util.h"
+#include "lib/crypt_ops/crypto_nss_mgt.h"
+#include "lib/string/printf.h"
+
#include "lib/tls/x509.h"
#include "lib/tls/x509_internal.h"
#include "lib/tls/tortls.h"
@@ -29,26 +33,16 @@
#include "lib/tls/tortls_internal.h"
#include "lib/log/util_bug.h"
-int
-tor_errno_to_tls_error(int e)
-{
- (void)e;
- // XXXX
- return -1;
-}
-int
-tor_tls_get_error(tor_tls_t *tls, int r, int extra,
- const char *doing, int severity, int domain)
-{
- (void)tls;
- (void)r;
- (void)extra;
- (void)doing;
- (void)severity;
- (void)domain;
- // XXXX
- return -1;
-}
+#include <prio.h>
+// For access to raw sockets.
+#include <private/pprio.h>
+#include <ssl.h>
+#include <sslt.h>
+#include <sslproto.h>
+#include <certt.h>
+
+static SECStatus always_accept_cert_cb(void *, PRFileDesc *, PRBool, PRBool);
+
MOCK_IMPL(void,
try_to_extract_certs_from_tls,(int severity, tor_tls_t *tls,
tor_x509_cert_impl_t **cert_out,
@@ -57,14 +51,109 @@ try_to_extract_certs_from_tls,(int severity, tor_tls_t *tls,
tor_assert(tls);
tor_assert(cert_out);
tor_assert(id_cert_out);
- (void)severity;
- // XXXX
+ (void) severity;
+
+ *cert_out = *id_cert_out = NULL;
+
+ CERTCertificate *peer = SSL_PeerCertificate(tls->ssl);
+ if (!peer)
+ return;
+ *cert_out = peer; /* Now owns pointer. */
+
+ CERTCertList *chain = SSL_PeerCertificateChain(tls->ssl);
+ CERTCertListNode *c = CERT_LIST_HEAD(chain);
+ for (; !CERT_LIST_END(c, chain); c = CERT_LIST_NEXT(c)) {
+ if (CERT_CompareCerts(c->cert, peer) == PR_FALSE) {
+ *id_cert_out = CERT_DupCertificate(c->cert);
+ break;
+ }
+ }
+ CERT_DestroyCertList(chain);
+}
+
+static bool
+we_like_ssl_cipher(SSLCipherAlgorithm ca)
+{
+ switch (ca) {
+ case ssl_calg_null: return false;
+ case ssl_calg_rc4: return false;
+ case ssl_calg_rc2: return false;
+ case ssl_calg_des: return false;
+ case ssl_calg_3des: return false; /* ???? */
+ case ssl_calg_idea: return false;
+ case ssl_calg_fortezza: return false;
+ case ssl_calg_camellia: return false;
+ case ssl_calg_seed: return false;
+
+ case ssl_calg_aes: return true;
+ case ssl_calg_aes_gcm: return true;
+ case ssl_calg_chacha20: return true;
+ default: return true;
+ }
+}
+static bool
+we_like_ssl_kea(SSLKEAType kt)
+{
+ switch (kt) {
+ case ssl_kea_null: return false;
+ case ssl_kea_rsa: return false; /* ??? */
+ case ssl_kea_fortezza: return false;
+ case ssl_kea_ecdh_psk: return false;
+ case ssl_kea_dh_psk: return false;
+
+ case ssl_kea_dh: return true;
+ case ssl_kea_ecdh: return true;
+ case ssl_kea_tls13_any: return true;
+
+ case ssl_kea_size: return true; /* prevent a warning. */
+ default: return true;
+ }
+}
+
+static bool
+we_like_mac_algorithm(SSLMACAlgorithm ma)
+{
+ switch (ma) {
+ case ssl_mac_null: return false;
+ case ssl_mac_md5: return false;
+ case ssl_hmac_md5: return false;
+
+ case ssl_mac_sha: return true;
+ case ssl_hmac_sha: return true;
+ case ssl_hmac_sha256: return true;
+ case ssl_mac_aead: return true;
+ case ssl_hmac_sha384: return true;
+ default: return true;
+ }
+}
+
+static bool
+we_like_auth_type(SSLAuthType at)
+{
+ switch (at) {
+ case ssl_auth_null: return false;
+ case ssl_auth_rsa_decrypt: return false;
+ case ssl_auth_dsa: return false;
+ case ssl_auth_kea: return false;
+
+ case ssl_auth_ecdsa: return true;
+ case ssl_auth_ecdh_rsa: return true;
+ case ssl_auth_ecdh_ecdsa: return true;
+ case ssl_auth_rsa_sign: return true;
+ case ssl_auth_rsa_pss: return true;
+ case ssl_auth_psk: return true;
+ case ssl_auth_tls13_any: return true;
+
+ case ssl_auth_size: return true; /* prevent a warning. */
+ default: return true;
+ }
}
tor_tls_context_t *
tor_tls_context_new(crypto_pk_t *identity,
unsigned int key_lifetime, unsigned flags, int is_client)
{
+ SECStatus s;
tor_assert(identity);
tor_tls_context_t *ctx = tor_malloc_zero(sizeof(tor_tls_context_t));
@@ -77,7 +166,128 @@ tor_tls_context_new(crypto_pk_t *identity,
}
}
- // XXXX write the main body.
+ {
+ /* Create the "model" PRFileDesc that we will use to base others on. */
+ PRFileDesc *tcp = PR_NewTCPSocket();
+ if (!tcp)
+ goto err;
+
+ ctx->ctx = SSL_ImportFD(NULL, tcp);
+ if (!ctx->ctx) {
+ PR_Close(tcp);
+ goto err;
+ }
+ }
+
+ // Configure the certificate.
+ if (!is_client) {
+ s = SSL_ConfigServerCert(ctx->ctx,
+ ctx->my_link_cert->cert,
+ (SECKEYPrivateKey *)
+ crypto_pk_get_nss_privkey(ctx->link_key),
+ NULL, /* ExtraServerCertData */
+ 0 /* DataLen */);
+ if (s != SECSuccess)
+ goto err;
+ }
+
+ // We need a certificate from the other side.
+ if (is_client) {
+ // XXXX does this do anything?
+ s = SSL_OptionSet(ctx->ctx, SSL_REQUIRE_CERTIFICATE, PR_TRUE);
+ if (s != SECSuccess)
+ goto err;
+ }
+
+ // Always accept other side's cert; we'll check it ourselves in goofy
+ // tor ways.
+ s = SSL_AuthCertificateHook(ctx->ctx, always_accept_cert_cb, NULL);
+
+ // We allow simultaneous read and write.
+ s = SSL_OptionSet(ctx->ctx, SSL_ENABLE_FDX, PR_TRUE);
+ if (s != SECSuccess)
+ goto err;
+ // XXXX SSL_ROLLBACK_DETECTION??
+ // XXXX SSL_ENABLE_ALPN??
+
+ // Force client-mode or server_mode.
+ s = SSL_OptionSet(ctx->ctx,
+ is_client ? SSL_HANDSHAKE_AS_CLIENT : SSL_HANDSHAKE_AS_SERVER,
+ PR_TRUE);
+ if (s != SECSuccess)
+ goto err;
+
+ // Disable everything before TLS 1.0; support everything else.
+ {
+ SSLVersionRange vrange;
+ memset(&vrange, 0, sizeof(vrange));
+ s = SSL_VersionRangeGetSupported(ssl_variant_stream, &vrange);
+ if (s != SECSuccess)
+ goto err;
+ if (vrange.min < SSL_LIBRARY_VERSION_TLS_1_0)
+ vrange.min = SSL_LIBRARY_VERSION_TLS_1_0;
+ s = SSL_VersionRangeSet(ctx->ctx, &vrange);
+ if (s != SECSuccess)
+ goto err;
+ }
+
+ // Only support strong ciphers.
+ {
+ const PRUint16 *ciphers = SSL_GetImplementedCiphers();
+ const PRUint16 n_ciphers = SSL_GetNumImplementedCiphers();
+ PRUint16 i;
+ for (i = 0; i < n_ciphers; ++i) {
+ SSLCipherSuiteInfo info;
+ memset(&info, 0, sizeof(info));
+ s = SSL_GetCipherSuiteInfo(ciphers[i], &info, sizeof(info));
+ if (s != SECSuccess)
+ goto err;
+ if (BUG(info.cipherSuite != ciphers[i]))
+ goto err;
+ int disable = info.effectiveKeyBits < 128 ||
+ info.macBits < 128 ||
+ !we_like_ssl_cipher(info.symCipher) ||
+ !we_like_ssl_kea(info.keaType) ||
+ !we_like_mac_algorithm(info.macAlgorithm) ||
+ !we_like_auth_type(info.authType)/* Requires NSS 3.24 */;
+
+ s = SSL_CipherPrefSet(ctx->ctx, ciphers[i],
+ disable ? PR_FALSE : PR_TRUE);
+ if (s != SECSuccess)
+ goto err;
+ }
+ }
+
+ // Only use DH and ECDH keys once.
+ s = SSL_OptionSet(ctx->ctx, SSL_REUSE_SERVER_ECDHE_KEY, PR_FALSE);
+ if (s != SECSuccess)
+ goto err;
+
+ // don't cache sessions.
+ s = SSL_OptionSet(ctx->ctx, SSL_NO_CACHE, PR_TRUE);
+ if (s != SECSuccess)
+ goto err;
+
+ // Enable DH.
+ s = SSL_OptionSet(ctx->ctx, SSL_ENABLE_SERVER_DHE, PR_TRUE);
+ if (s != SECSuccess)
+ goto err;
+
+ // Set DH and ECDH groups.
+ SSLNamedGroup groups[] = {
+ ssl_grp_ec_curve25519,
+ ssl_grp_ec_secp256r1,
+ ssl_grp_ec_secp224r1,
+ ssl_grp_ffdhe_2048,
+ };
+ s = SSL_NamedGroupConfig(ctx->ctx, groups, ARRAY_LENGTH(groups));
+ if (s != SECSuccess)
+ goto err;
+
+ // These features are off by default, so we don't need to disable them:
+ // Session tickets
+ // Renegotiation
+ // Compression
goto done;
err:
@@ -88,11 +298,9 @@ tor_tls_context_new(crypto_pk_t *identity,
}
void
-tor_tls_context_impl_free(struct ssl_ctx_st *ctx)
+tor_tls_context_impl_free(tor_tls_context_impl_t *ctx)
{
- (void)ctx;
- // XXXX
- // XXXX openssl type.
+ PR_Close(ctx);
}
void
@@ -101,33 +309,82 @@ tor_tls_get_state_description(tor_tls_t *tls, char *buf, size_t sz)
(void)tls;
(void)buf;
(void)sz;
- // XXXX
+ // AFAICT, NSS doesn't expose its internal state.
+ buf[0]=0;
}
void
tor_tls_init(void)
{
- // XXXX
+ /* We don't have any global setup to do yet, but that will change */
}
+
void
tls_log_errors(tor_tls_t *tls, int severity, int domain,
const char *doing)
{
+ /* XXXX This implementation isn't right for NSS -- it logs the last error
+ whether anything actually failed or not. */
+
(void)tls;
- (void)severity;
- (void)domain;
- (void)doing;
- // XXXX
+ PRErrorCode code = PORT_GetError();
+
+ const char *string = PORT_ErrorToString(code);
+ const char *name = PORT_ErrorToName(code);
+ char buf[16];
+ if (!string)
+ string = "<unrecognized>";
+ if (!name) {
+ tor_snprintf(buf, sizeof(buf), "%d", code);
+ name = buf;
+ }
+
+ if (doing) {
+ log_fn(severity, domain, "TLS error %s while %s: %s", name, doing, string);
+ } else {
+ log_fn(severity, domain, "TLS error %s: %s", name, string);
+ }
}
tor_tls_t *
-tor_tls_new(int sock, int is_server)
+tor_tls_new(tor_socket_t sock, int is_server)
{
(void)sock;
- (void)is_server;
- // XXXX
- return NULL;
+ tor_tls_context_t *ctx = tor_tls_context_get(is_server);
+
+ PRFileDesc *tcp = PR_ImportTCPSocket(sock);
+ if (!tcp)
+ return NULL;
+
+ PRFileDesc *ssl = SSL_ImportFD(ctx->ctx, tcp);
+ if (!ssl) {
+ PR_Close(tcp);
+ return NULL;
+ }
+
+ tor_tls_t *tls = tor_malloc_zero(sizeof(tor_tls_t));
+ tls->magic = TOR_TLS_MAGIC;
+ tls->context = ctx;
+ tor_tls_context_incref(ctx);
+ tls->ssl = ssl;
+ tls->socket = sock;
+ tls->state = TOR_TLS_ST_HANDSHAKE;
+ tls->isServer = !!is_server;
+
+ if (!is_server) {
+ /* Set a random SNI */
+ char *fake_hostname = crypto_random_hostname(4,25, "www.",".com");
+ SSL_SetURL(tls->ssl, fake_hostname);
+ tor_free(fake_hostname);
+ }
+ SECStatus s = SSL_ResetHandshake(ssl, is_server ? PR_TRUE : PR_FALSE);
+ if (s != SECSuccess) {
+ crypto_nss_log_errors(LOG_WARN, "resetting handshake state");
+ }
+
+ return tls;
}
+
void
tor_tls_set_renegotiate_callback(tor_tls_t *tls,
void (*cb)(tor_tls_t *, void *arg),
@@ -136,131 +393,175 @@ tor_tls_set_renegotiate_callback(tor_tls_t *tls,
tor_assert(tls);
(void)cb;
(void)arg;
- // XXXX;
+
+ /* We don't support renegotiation-based TLS with NSS. */
}
void
-tor_tls_free_(tor_tls_t *tls)
+tor_tls_impl_free_(tor_tls_impl_t *tls)
{
- (void)tls;
- // XXXX
+ // XXXX This will close the underlying fd, which our OpenSSL version does
+ // not do!
+
+ PR_Close(tls);
}
int
tor_tls_peer_has_cert(tor_tls_t *tls)
{
- (void)tls;
- // XXXX
- return -1;
+ CERTCertificate *cert = SSL_PeerCertificate(tls->ssl);
+ int result = (cert != NULL);
+ CERT_DestroyCertificate(cert);
+ return result;
}
+
MOCK_IMPL(tor_x509_cert_t *,
tor_tls_get_peer_cert,(tor_tls_t *tls))
{
- tor_assert(tls);
- // XXXX
- return NULL;
+ CERTCertificate *cert = SSL_PeerCertificate(tls->ssl);
+ if (cert)
+ return tor_x509_cert_new(cert);
+ else
+ return NULL;
}
+
MOCK_IMPL(tor_x509_cert_t *,
tor_tls_get_own_cert,(tor_tls_t *tls))
{
tor_assert(tls);
- // XXXX
- return NULL;
-}
-int
-tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_t **identity)
-{
- tor_assert(tls);
- tor_assert(identity);
- (void)severity;
- // XXXX
- return -1;
-}
-int
-tor_tls_check_lifetime(int severity,
- tor_tls_t *tls, time_t now,
- int past_tolerance,
- int future_tolerance)
-{
- tor_assert(tls);
- (void)severity;
- (void)now;
- (void)past_tolerance;
- (void)future_tolerance;
- // XXXX
- return -1;
+ CERTCertificate *cert = SSL_LocalCertificate(tls->ssl);
+ if (cert)
+ return tor_x509_cert_new(cert);
+ else
+ return NULL;
}
+
MOCK_IMPL(int,
tor_tls_read, (tor_tls_t *tls, char *cp, size_t len))
{
tor_assert(tls);
tor_assert(cp);
- (void)len;
- // XXXX
- return -1;
+ tor_assert(len < INT_MAX);
+
+ PRInt32 rv = PR_Read(tls->ssl, cp, (int)len);
+ // log_debug(LD_NET, "PR_Read(%zu) returned %d", n, (int)rv);
+ if (rv > 0) {
+ tls->n_read_since_last_check += rv;
+ return rv;
+ }
+ if (rv == 0)
+ return TOR_TLS_CLOSE;
+ PRErrorCode err = PORT_GetError();
+ if (err == PR_WOULD_BLOCK_ERROR) {
+ return TOR_TLS_WANTREAD; // XXXX ????
+ } else {
+ crypto_nss_log_errors(LOG_NOTICE, "reading"); // XXXX
+ return TOR_TLS_ERROR_MISC; // ????
+ }
}
+
int
tor_tls_write(tor_tls_t *tls, const char *cp, size_t n)
{
tor_assert(tls);
- tor_assert(cp);
- (void)n;
- // XXXX
- return -1;
+ tor_assert(cp || n == 0);
+ tor_assert(n < INT_MAX);
+
+ PRInt32 rv = PR_Write(tls->ssl, cp, (int)n);
+ // log_debug(LD_NET, "PR_Write(%zu) returned %d", n, (int)rv);
+ if (rv > 0) {
+ tls->n_written_since_last_check += rv;
+ return rv;
+ }
+ if (rv == 0)
+ return TOR_TLS_ERROR_MISC;
+ PRErrorCode err = PORT_GetError();
+
+ if (err == PR_WOULD_BLOCK_ERROR) {
+ return TOR_TLS_WANTWRITE; // XXXX ????
+ } else {
+ crypto_nss_log_errors(LOG_NOTICE, "writing"); // XXXX
+ return TOR_TLS_ERROR_MISC; // ????
+ }
}
+
int
tor_tls_handshake(tor_tls_t *tls)
{
tor_assert(tls);
- // XXXX
- return -1;
+ tor_assert(tls->state == TOR_TLS_ST_HANDSHAKE);
+
+ SECStatus s = SSL_ForceHandshake(tls->ssl);
+ if (s == SECSuccess) {
+ tls->state = TOR_TLS_ST_OPEN;
+ log_debug(LD_NET, "SSL handshake is supposedly complete.");
+ return tor_tls_finish_handshake(tls);
+ }
+ if (PORT_GetError() == PR_WOULD_BLOCK_ERROR)
+ return TOR_TLS_WANTREAD; /* XXXX What about wantwrite? */
+
+ return TOR_TLS_ERROR_MISC; // XXXX
}
+
int
tor_tls_finish_handshake(tor_tls_t *tls)
{
tor_assert(tls);
- // XXXX
- return -1;
+ // We don't need to do any of the weird handshake nonsense stuff on NSS,
+ // since we only support recent handshakes.
+ return TOR_TLS_DONE;
}
+
void
tor_tls_unblock_renegotiation(tor_tls_t *tls)
{
tor_assert(tls);
- // XXXX
+ /* We don't support renegotiation with NSS. */
}
+
void
tor_tls_block_renegotiation(tor_tls_t *tls)
{
tor_assert(tls);
- // XXXX
+ /* We don't support renegotiation with NSS. */
}
+
void
tor_tls_assert_renegotiation_unblocked(tor_tls_t *tls)
{
tor_assert(tls);
- // XXXX
+ /* We don't support renegotiation with NSS. */
}
+
int
tor_tls_shutdown(tor_tls_t *tls)
{
tor_assert(tls);
- // XXXX
+ /* XXXX This is not actually used, so I'm not implementing it. We can
+ * XXXX remove this function entirely someday. */
return -1;
}
+
int
tor_tls_get_pending_bytes(tor_tls_t *tls)
{
tor_assert(tls);
- // XXXX
- return -1;
+ int n = SSL_DataPending(tls->ssl);
+ if (n < 0) {
+ crypto_nss_log_errors(LOG_WARN, "Looking up pending bytes");
+ return 0;
+ }
+ return (int)n;
}
+
size_t
tor_tls_get_forced_write_size(tor_tls_t *tls)
{
tor_assert(tls);
- // XXXX
+ /* NSS doesn't have the same "forced write" restriction as openssl. */
return 0;
}
+
void
tor_tls_get_n_raw_bytes(tor_tls_t *tls,
size_t *n_read, size_t *n_written)
@@ -268,7 +569,13 @@ tor_tls_get_n_raw_bytes(tor_tls_t *tls,
tor_assert(tls);
tor_assert(n_read);
tor_assert(n_written);
- // XXXX
+ /* XXXX We don't curently have a way to measure this information correctly
+ * in NSS; we could do that with a PRIO layer, but it'll take a little
+ * coding. For now, we just track the number of bytes sent _in_ the TLS
+ * stream. Doing this will make our rate-limiting slightly inaccurate. */
+ *n_read = tls->n_read_since_last_check;
+ *n_written = tls->n_written_since_last_check;
+ tls->n_read_since_last_check = tls->n_written_since_last_check = 0;
}
int
@@ -281,54 +588,70 @@ tor_tls_get_buffer_sizes(tor_tls_t *tls,
tor_assert(rbuf_bytes);
tor_assert(wbuf_capacity);
tor_assert(wbuf_bytes);
- // XXXX
+
+ /* This is an acceptable way to say "we can't measure this." */
return -1;
}
+
MOCK_IMPL(double,
tls_get_write_overhead_ratio, (void))
{
- // XXXX
- return 0.0;
+ /* XXX We don't currently have a way to measure this in NSS; we could do that
+ * XXX with a PRIO layer, but it'll take a little coding. */
+ return 0.95;
}
int
tor_tls_used_v1_handshake(tor_tls_t *tls)
{
tor_assert(tls);
- // XXXX
- return -1;
-}
-int
-tor_tls_get_num_server_handshakes(tor_tls_t *tls)
-{
- tor_assert(tls);
- // XXXX
- return -1;
+ /* We don't support or allow the V1 handshake with NSS.
+ */
+ return 0;
}
+
int
tor_tls_server_got_renegotiate(tor_tls_t *tls)
{
tor_assert(tls);
- // XXXX
- return -1;
+ return 0; /* We don't support renegotiation with NSS */
}
+
MOCK_IMPL(int,
tor_tls_cert_matches_key,(const tor_tls_t *tls,
const struct tor_x509_cert_t *cert))
{
tor_assert(tls);
tor_assert(cert);
- // XXXX
- return 0;
+ int rv = 0;
+
+ CERTCertificate *peercert = SSL_PeerCertificate(tls->ssl);
+ if (!peercert)
+ goto done;
+ CERTSubjectPublicKeyInfo *peer_info = &peercert->subjectPublicKeyInfo;
+ CERTSubjectPublicKeyInfo *cert_info = &cert->cert->subjectPublicKeyInfo;
+ rv = SECOID_CompareAlgorithmID(&peer_info->algorithm,
+ &cert_info->algorithm) == 0 &&
+ SECITEM_ItemsAreEqual(&peer_info->subjectPublicKey,
+ &cert_info->subjectPublicKey);
+
+ done:
+ if (peercert)
+ CERT_DestroyCertificate(peercert);
+ return rv;
}
+
MOCK_IMPL(int,
tor_tls_get_tlssecrets,(tor_tls_t *tls, uint8_t *secrets_out))
{
tor_assert(tls);
tor_assert(secrets_out);
- // XXXX
+
+ /* There's no way to get this information out of NSS. */
+
return -1;
}
+
MOCK_IMPL(int,
tor_tls_export_key_material,(tor_tls_t *tls, uint8_t *secrets_out,
const uint8_t *context,
@@ -339,42 +662,72 @@ tor_tls_export_key_material,(tor_tls_t *tls, uint8_t *secrets_out,
tor_assert(secrets_out);
tor_assert(context);
tor_assert(label);
- (void)context_len;
- // XXXX
- return -1;
-}
+ tor_assert(strlen(label) <= UINT_MAX);
+ tor_assert(context_len <= UINT_MAX);
-void
-check_no_tls_errors_(const char *fname, int line)
-{
- (void)fname;
- (void)line;
- // XXXX
-}
-void
-tor_tls_log_one_error(tor_tls_t *tls, unsigned long err,
- int severity, int domain, const char *doing)
-{
- tor_assert(tls);
- (void)err;
- (void)severity;
- (void)domain;
- (void)doing;
- // XXXX
+ SECStatus s;
+ s = SSL_ExportKeyingMaterial(tls->ssl,
+ label, (unsigned)strlen(label),
+ PR_TRUE, context, (unsigned)context_len,
+ secrets_out, DIGEST256_LEN);
+
+ return (s == SECSuccess) ? 0 : -1;
}
const char *
tor_tls_get_ciphersuite_name(tor_tls_t *tls)
{
tor_assert(tls);
- // XXXX
- return NULL;
+
+ SSLChannelInfo channel_info;
+ SSLCipherSuiteInfo cipher_info;
+
+ memset(&channel_info, 0, sizeof(channel_info));
+ memset(&cipher_info, 0, sizeof(cipher_info));
+
+ SECStatus s = SSL_GetChannelInfo(tls->ssl,
+ &channel_info, sizeof(channel_info));
+ if (s != SECSuccess)
+ return NULL;
+
+ s = SSL_GetCipherSuiteInfo(channel_info.cipherSuite,
+ &cipher_info, sizeof(cipher_info));
+ if (s != SECSuccess)
+ return NULL;
+
+ return cipher_info.cipherSuiteName;
}
+/** The group we should use for ecdhe when none was selected. */
+#define SEC_OID_TOR_DEFAULT_ECDHE_GROUP SEC_OID_ANSIX962_EC_PRIME256V1
+
int
evaluate_ecgroup_for_tls(const char *ecgroup)
{
- (void)ecgroup;
- // XXXX
- return -1;
+ SECOidTag tag;
+
+ if (!ecgroup)
+ tag = SEC_OID_TOR_DEFAULT_ECDHE_GROUP;
+ else if (!strcasecmp(ecgroup, "P256"))
+ tag = SEC_OID_ANSIX962_EC_PRIME256V1;
+ else if (!strcasecmp(ecgroup, "P224"))
+ tag = SEC_OID_SECG_EC_SECP224R1;
+ else
+ return 0;
+
+ /* I don't think we need any additional tests here for NSS */
+ (void) tag;
+
+ return 1;
+}
+
+static SECStatus
+always_accept_cert_cb(void *arg, PRFileDesc *ssl, PRBool checkSig,
+ PRBool isServer)
+{
+ (void)arg;
+ (void)ssl;
+ (void)checkSig;
+ (void)isServer;
+ return SECSuccess;
}
diff --git a/src/lib/tls/tortls_openssl.c b/src/lib/tls/tortls_openssl.c
index fb6328bcd..c4e9e7770 100644
--- a/src/lib/tls/tortls_openssl.c
+++ b/src/lib/tls/tortls_openssl.c
@@ -244,26 +244,6 @@ tls_log_errors(tor_tls_t *tls, int severity, int domain, const char *doing)
}
}
-/** Convert an errno (or a WSAerrno on windows) into a TOR_TLS_* error
- * code. */
-int
-tor_errno_to_tls_error(int e)
-{
- switch (e) {
- case SOCK_ERRNO(ECONNRESET): // most common
- return TOR_TLS_ERROR_CONNRESET;
- case SOCK_ERRNO(ETIMEDOUT):
- return TOR_TLS_ERROR_TIMEOUT;
- case SOCK_ERRNO(EHOSTUNREACH):
- case SOCK_ERRNO(ENETUNREACH):
- return TOR_TLS_ERROR_NO_ROUTE;
- case SOCK_ERRNO(ECONNREFUSED):
- return TOR_TLS_ERROR_CONNREFUSED; // least common
- default:
- return TOR_TLS_ERROR_MISC;
- }
-}
-
#define CATCH_SYSCALL 1
#define CATCH_ZERO 2
@@ -952,8 +932,6 @@ tor_tls_server_info_callback(const SSL *ssl, int type, int val)
/* Check whether we're watching for renegotiates. If so, this is one! */
if (tls->negotiated_callback)
tls->got_renegotiate = 1;
- if (tls->server_handshake_count < 127) /*avoid any overflow possibility*/
- ++tls->server_handshake_count;
} else {
log_warn(LD_BUG, "Couldn't look up the tls for an SSL*. How odd!");
return;
@@ -1167,30 +1145,13 @@ tor_tls_assert_renegotiation_unblocked(tor_tls_t *tls)
#endif /* defined(SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION) && ... */
}
-/** Release resources associated with a TLS object. Does not close the
- * underlying file descriptor.
- */
void
-tor_tls_free_(tor_tls_t *tls)
+tor_tls_impl_free_(tor_tls_impl_t *ssl)
{
- if (!tls)
- return;
- tor_assert(tls->ssl);
- {
- size_t r,w;
- tor_tls_get_n_raw_bytes(tls,&r,&w); /* ensure written_by_tls is updated */
- }
#ifdef SSL_set_tlsext_host_name
- SSL_set_tlsext_host_name(tls->ssl, NULL);
+ SSL_set_tlsext_host_name(ssl, NULL);
#endif
- SSL_free(tls->ssl);
- tls->ssl = NULL;
- tls->negotiated_callback = NULL;
- if (tls->context)
- tor_tls_context_decref(tls->context);
- tor_free(tls->address);
- tls->magic = 0x99999999;
- tor_free(tls);
+ SSL_free(ssl);
}
/** Underlying function for TLS reading. Reads up to <b>len</b>
@@ -1509,90 +1470,6 @@ try_to_extract_certs_from_tls,(int severity, tor_tls_t *tls,
*id_cert_out = id_cert;
}
-/** If the provided tls connection is authenticated and has a
- * certificate chain that is currently valid and signed, then set
- * *<b>identity_key</b> to the identity certificate's key and return
- * 0. Else, return -1 and log complaints with log-level <b>severity</b>.
- */
-int
-tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_t **identity_key)
-{
- X509 *cert = NULL, *id_cert = NULL;
- EVP_PKEY *id_pkey = NULL;
- RSA *rsa;
- int r = -1;
-
- check_no_tls_errors();
- *identity_key = NULL;
-
- try_to_extract_certs_from_tls(severity, tls, &cert, &id_cert);
- if (!cert)
- goto done;
- if (!id_cert) {
- log_fn(severity,LD_PROTOCOL,"No distinct identity certificate found");
- goto done;
- }
- tls_log_errors(tls, severity, LD_HANDSHAKE, "before verifying certificate");
-
- if (!(id_pkey = X509_get_pubkey(id_cert)) ||
- X509_verify(cert, id_pkey) <= 0) {
- log_fn(severity,LD_PROTOCOL,"X509_verify on cert and pkey returned <= 0");
- tls_log_errors(tls, severity, LD_HANDSHAKE, "verifying certificate");
- goto done;
- }
-
- rsa = EVP_PKEY_get1_RSA(id_pkey);
- if (!rsa)
- goto done;
- *identity_key = crypto_new_pk_from_openssl_rsa_(rsa);
-
- r = 0;
-
- done:
- if (cert)
- X509_free(cert);
- if (id_pkey)
- EVP_PKEY_free(id_pkey);
-
- /* This should never get invoked, but let's make sure in case OpenSSL
- * acts unexpectedly. */
- tls_log_errors(tls, LOG_WARN, LD_HANDSHAKE, "finishing tor_tls_verify");
-
- return r;
-}
-
-/** Check whether the certificate set on the connection <b>tls</b> is expired
- * give or take <b>past_tolerance</b> seconds, or not-yet-valid give or take
- * <b>future_tolerance</b> seconds. Return 0 for valid, -1 for failure.
- *
- * NOTE: you should call tor_tls_verify before tor_tls_check_lifetime.
- */
-int
-tor_tls_check_lifetime(int severity, tor_tls_t *tls,
- time_t now,
- int past_tolerance, int future_tolerance)
-{
- X509 *cert;
- int r = -1;
-
- if (!(cert = SSL_get_peer_certificate(tls->ssl)))
- goto done;
-
- if (tor_x509_check_cert_lifetime_internal(severity, cert, now,
- past_tolerance,
- future_tolerance) < 0)
- goto done;
-
- r = 0;
- done:
- if (cert)
- X509_free(cert);
- /* Not expected to get invoked */
- tls_log_errors(tls, LOG_WARN, LD_NET, "checking certificate lifetime");
-
- return r;
-}
-
/** Return the number of bytes available for reading from <b>tls</b>.
*/
int
@@ -1690,14 +1567,6 @@ tor_tls_used_v1_handshake(tor_tls_t *tls)
return ! tls->wasV2Handshake;
}
-/** Return the number of server handshakes that we've noticed doing on
- * <b>tls</b>. */
-int
-tor_tls_get_num_server_handshakes(tor_tls_t *tls)
-{
- return tls->server_handshake_count;
-}
-
/** Return true iff the server TLS connection <b>tls</b> got the renegotiation
* request it was waiting for. */
int
diff --git a/src/lib/tls/tortls_st.h b/src/lib/tls/tortls_st.h
index 897be497e..a1b59a37a 100644
--- a/src/lib/tls/tortls_st.h
+++ b/src/lib/tls/tortls_st.h
@@ -6,6 +6,8 @@
#ifndef TOR_TORTLS_ST_H
#define TOR_TORTLS_ST_H
+#include "lib/net/socket.h"
+
#define TOR_TLS_MAGIC 0x71571571
typedef enum {
@@ -17,7 +19,7 @@ typedef enum {
struct tor_tls_context_t {
int refcnt;
- struct ssl_ctx_st *ctx;
+ tor_tls_context_impl_t *ctx;
struct tor_x509_cert_t *my_link_cert;
struct tor_x509_cert_t *my_id_cert;
struct tor_x509_cert_t *my_auth_cert;
@@ -31,8 +33,9 @@ struct tor_tls_context_t {
struct tor_tls_t {
uint32_t magic;
tor_tls_context_t *context; /** A link to the context object for this tls. */
- struct ssl_st *ssl; /**< An OpenSSL SSL object. */
- int socket; /**< The underlying file descriptor for this TLS connection. */
+ tor_tls_impl_t *ssl; /**< An OpenSSL SSL object or NSS PRFileDesc. */
+ tor_socket_t socket; /**< The underlying file descriptor for this TLS
+ * connection. */
char *address; /**< An address to log when describing this connection. */
tor_tls_state_bitfield_t state : 3; /**< The current SSL state,
* depending on which operations
@@ -45,11 +48,10 @@ struct tor_tls_t {
* one certificate). */
/** True iff we should call negotiated_callback when we're done reading. */
unsigned int got_renegotiate:1;
+#ifdef ENABLE_OPENSSL
/** Return value from tor_tls_classify_client_ciphers, or 0 if we haven't
* called that function yet. */
int8_t client_cipher_list_type;
- /** Incremented every time we start the server side of a handshake. */
- uint8_t server_handshake_count;
size_t wantwrite_n; /**< 0 normally, >0 if we returned wantwrite last
* time. */
/** Last values retrieved from BIO_number_read()/write(); see
@@ -62,6 +64,11 @@ struct tor_tls_t {
void (*negotiated_callback)(tor_tls_t *tls, void *arg);
/** Argument to pass to negotiated_callback. */
void *callback_arg;
+#endif
+#ifdef ENABLE_NSS
+ size_t n_read_since_last_check;
+ size_t n_written_since_last_check;
+#endif
};
#endif
diff --git a/src/test/test_tortls.c b/src/test/test_tortls.c
index eedf0dd3c..0e4b5afaf 100644
--- a/src/test/test_tortls.c
+++ b/src/test/test_tortls.c
@@ -72,6 +72,7 @@ test_tortls_err_to_string(void *data)
(void)1;
}
+#ifdef ENABLE_OPENSSL
static int
mock_tls_cert_matches_key(const tor_tls_t *tls, const tor_x509_cert_t *cert)
{
@@ -105,6 +106,7 @@ test_tortls_tor_tls_get_error(void *data)
crypto_pk_free(key2);
tor_tls_free(tls);
}
+#endif
static void
test_tortls_x509_cert_get_id_digests(void *ignored)
@@ -165,6 +167,7 @@ test_tortls_get_my_certs(void *ignored)
(void)1;
}
+#ifdef ENABLE_OPENSSL
static void
test_tortls_get_forced_write_size(void *ignored)
{
@@ -204,23 +207,6 @@ test_tortls_used_v1_handshake(void *ignored)
}
static void
-test_tortls_get_num_server_handshakes(void *ignored)
-{
- (void)ignored;
- int ret;
- tor_tls_t *tls;
-
- tls = tor_malloc_zero(sizeof(tor_tls_t));
-
- tls->server_handshake_count = 3;
- ret = tor_tls_get_num_server_handshakes(tls);
- tt_int_op(ret, OP_EQ, 3);
-
- done:
- tor_free(tls);
-}
-
-static void
test_tortls_server_got_renegotiate(void *ignored)
{
(void)ignored;
@@ -236,6 +222,7 @@ test_tortls_server_got_renegotiate(void *ignored)
done:
tor_free(tls);
}
+#endif
static void
test_tortls_evaluate_ecgroup_for_tls(void *ignored)
@@ -266,13 +253,14 @@ test_tortls_evaluate_ecgroup_for_tls(void *ignored)
struct testcase_t tortls_tests[] = {
LOCAL_TEST_CASE(errno_to_tls_error, 0),
LOCAL_TEST_CASE(err_to_string, 0),
- LOCAL_TEST_CASE(tor_tls_get_error, 0),
LOCAL_TEST_CASE(x509_cert_get_id_digests, 0),
LOCAL_TEST_CASE(get_my_certs, TT_FORK),
+#ifdef ENABLE_OPENSSL
+ LOCAL_TEST_CASE(tor_tls_get_error, 0),
LOCAL_TEST_CASE(get_forced_write_size, 0),
LOCAL_TEST_CASE(used_v1_handshake, TT_FORK),
- LOCAL_TEST_CASE(get_num_server_handshakes, 0),
LOCAL_TEST_CASE(server_got_renegotiate, 0),
+#endif
LOCAL_TEST_CASE(evaluate_ecgroup_for_tls, 0),
END_OF_TESTCASES
};
1
0
commit c567b8fcb4e4851d6db19946cce8c4d5e75535f5
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Mon Aug 13 14:54:35 2018 -0400
NSS support for x509 certs
7 unit tests are failing at this point, but they're all TLS-related.
---
src/lib/crypt_ops/crypto_nss_mgt.c | 9 +
src/lib/crypt_ops/crypto_rsa.h | 10 +
src/lib/crypt_ops/crypto_rsa_nss.c | 27 +++
src/lib/tls/tortls.c | 157 ++++++++++++++++
src/lib/tls/tortls_internal.h | 4 +
src/lib/tls/tortls_nss.c | 61 +++----
src/lib/tls/tortls_openssl.c | 157 ++--------------
src/lib/tls/x509.h | 6 -
src/lib/tls/x509_internal.h | 17 ++
src/lib/tls/x509_nss.c | 362 ++++++++++++++++++++++++++++++++++---
src/lib/tls/x509_openssl.c | 3 +-
src/test/test_link_handshake.c | 24 ++-
12 files changed, 620 insertions(+), 217 deletions(-)
diff --git a/src/lib/crypt_ops/crypto_nss_mgt.c b/src/lib/crypt_ops/crypto_nss_mgt.c
index 85b18e00c..187f556bd 100644
--- a/src/lib/crypt_ops/crypto_nss_mgt.c
+++ b/src/lib/crypt_ops/crypto_nss_mgt.c
@@ -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
diff --git a/src/lib/crypt_ops/crypto_rsa.h b/src/lib/crypt_ops/crypto_rsa.h
index afc6c4201..aaf32ec1b 100644
--- a/src/lib/crypt_ops/crypto_rsa.h
+++ b/src/lib/crypt_ops/crypto_rsa.h
@@ -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);
diff --git a/src/lib/crypt_ops/crypto_rsa_nss.c b/src/lib/crypt_ops/crypto_rsa_nss.c
index 0411687b9..517faa5c7 100644
--- a/src/lib/crypt_ops/crypto_rsa_nss.c
+++ b/src/lib/crypt_ops/crypto_rsa_nss.c
@@ -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. */
diff --git a/src/lib/tls/tortls.c b/src/lib/tls/tortls.c
index 395f0148e..0b14b69f4 100644
--- a/src/lib/tls/tortls.c
+++ b/src/lib/tls/tortls.c
@@ -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>.
*/
diff --git a/src/lib/tls/tortls_internal.h b/src/lib/tls/tortls_internal.h
index b997ee3e4..2920e9658 100644
--- a/src/lib/tls/tortls_internal.h
+++ b/src/lib/tls/tortls_internal.h
@@ -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 *);
diff --git a/src/lib/tls/tortls_nss.c b/src/lib/tls/tortls_nss.c
index 3ab5c753d..35dbc27d9 100644
--- a/src/lib/tls/tortls_nss.c
+++ b/src/lib/tls/tortls_nss.c
@@ -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)
{
diff --git a/src/lib/tls/tortls_openssl.c b/src/lib/tls/tortls_openssl.c
index 5f5431235..fb6328bcd 100644
--- a/src/lib/tls/tortls_openssl.c
+++ b/src/lib/tls/tortls_openssl.c
@@ -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;
}
diff --git a/src/lib/tls/x509.h b/src/lib/tls/x509.h
index 8316df75a..e7440a192 100644
--- a/src/lib/tls/x509.h
+++ b/src/lib/tls/x509.h
@@ -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
diff --git a/src/lib/tls/x509_internal.h b/src/lib/tls/x509_internal.h
index 86f5a0de5..4b49f1dec 100644
--- a/src/lib/tls/x509_internal.h
+++ b/src/lib/tls/x509_internal.h
@@ -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);
diff --git a/src/lib/tls/x509_nss.c b/src/lib/tls/x509_nss.c
index ac9e6658d..35b3d2542 100644
--- a/src/lib/tls/x509_nss.c
+++ b/src/lib/tls/x509_nss.c
@@ -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 NULL;
+ 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
- return NULL;
+ 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
- return NULL;
+ 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
- return -1;
+
+ 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
- return NULL;
+ 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
diff --git a/src/lib/tls/x509_openssl.c b/src/lib/tls/x509_openssl.c
index 43bd6b4d4..28a30b66e 100644
--- a/src/lib/tls/x509_openssl.c
+++ b/src/lib/tls/x509_openssl.c
@@ -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);
diff --git a/src/test/test_link_handshake.c b/src/test/test_link_handshake.c
index 677276599..df3fa67eb 100644
--- a/src/test/test_link_handshake.c
+++ b/src/test/test_link_handshake.c
@@ -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);
1
0

05 Sep '18
commit 7c5339677fd4d524a95bc8c18af223f710ca94e2
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Wed Aug 22 11:03:33 2018 -0400
Log error strings in crypto_nss_log_errors().
I'll need this for debugging.
---
src/lib/crypt_ops/crypto_nss_mgt.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/src/lib/crypt_ops/crypto_nss_mgt.c b/src/lib/crypt_ops/crypto_nss_mgt.c
index 89ef01921..85b18e00c 100644
--- a/src/lib/crypt_ops/crypto_nss_mgt.c
+++ b/src/lib/crypt_ops/crypto_nss_mgt.c
@@ -14,6 +14,7 @@
#include "lib/log/log.h"
#include "lib/log/util_bug.h"
+#include "lib/string/printf.h"
DISABLE_GCC_WARNING(strict-prototypes)
#include <nss.h>
@@ -74,11 +75,20 @@ void
crypto_nss_log_errors(int severity, const char *doing)
{
PRErrorCode code = PR_GetError();
- /* XXXX how do I convert errors to strings? */
+ const char *string = PORT_ErrorToString(code);
+ const char *name = PORT_ErrorToName(code);
+ char buf[16];
+ if (!string)
+ string = "<unrecognized>";
+ if (!name) {
+ tor_snprintf(buf, sizeof(buf), "%d", code);
+ name = buf;
+ }
if (doing) {
- tor_log(severity, LD_CRYPTO, "NSS error %u while %s", code, doing);
+ tor_log(severity, LD_CRYPTO, "NSS error %s while %s: %s",
+ name, doing, string);
} else {
- tor_log(severity, LD_CRYPTO, "NSS error %u", code);
+ tor_log(severity, LD_CRYPTO, "NSS error %s: %s", name, string);
}
}
1
0