mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-11 05:33:47 +01:00
Implement RSA for NSS.
This commit is contained in:
parent
cb5cfe3177
commit
aa45511250
@ -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
|
||||
|
699
src/lib/crypt_ops/crypto_rsa_nss.c
Normal file
699
src/lib/crypt_ops/crypto_rsa_nss.c
Normal file
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user