[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [tor/master] Implement RSA for NSS.
commit aa45511250ed9509ca06b76497f66835796a7998
Author: Nick Mathewson <nickm@xxxxxxxxxxxxxx>
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
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits