tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

crypto_dh_nss.c (5251B)


      1 /* Copyright (c) 2001, Matej Pfajfar.
      2 * Copyright (c) 2001-2004, Roger Dingledine.
      3 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
      4 * Copyright (c) 2007-2021, The Tor Project, Inc. */
      5 /* See LICENSE for licensing information */
      6 
      7 /**
      8 * \file crypto_dh_nss.c
      9 *
     10 * \brief NSS implementation of Diffie-Hellman over Z_p.
     11 **/
     12 
     13 #include "lib/crypt_ops/crypto_dh.h"
     14 #include "lib/crypt_ops/crypto_nss_mgt.h"
     15 
     16 #include "lib/encoding/binascii.h"
     17 #include "lib/log/util_bug.h"
     18 #include "lib/malloc/malloc.h"
     19 
     20 DISABLE_GCC_WARNING("-Wstrict-prototypes")
     21 #include <cryptohi.h>
     22 #include <keyhi.h>
     23 #include <pk11pub.h>
     24 ENABLE_GCC_WARNING("-Wstrict-prototypes")
     25 
     26 static int dh_initialized = 0;
     27 static SECKEYDHParams tls_dh_param, circuit_dh_param;
     28 static unsigned char tls_dh_prime_data[DH2048_KEY_LEN];
     29 static unsigned char circuit_dh_prime_data[DH1024_KEY_LEN];
     30 static unsigned char dh_generator_data[1];
     31 
     32 void
     33 crypto_dh_init_nss(void)
     34 {
     35  if (dh_initialized)
     36    return;
     37 
     38  int r;
     39  r = base16_decode((char*)tls_dh_prime_data,
     40                    sizeof(tls_dh_prime_data),
     41                    TLS_DH_PRIME, strlen(TLS_DH_PRIME));
     42  tor_assert(r == DH2048_KEY_LEN);
     43  r = base16_decode((char*)circuit_dh_prime_data,
     44                    sizeof(circuit_dh_prime_data),
     45                    OAKLEY_PRIME_2, strlen(OAKLEY_PRIME_2));
     46  tor_assert(r == DH1024_KEY_LEN);
     47  dh_generator_data[0] = DH_GENERATOR;
     48 
     49  tls_dh_param.prime.data = tls_dh_prime_data;
     50  tls_dh_param.prime.len = DH2048_KEY_LEN;
     51  tls_dh_param.base.data = dh_generator_data;
     52  tls_dh_param.base.len = 1;
     53 
     54  circuit_dh_param.prime.data = circuit_dh_prime_data;
     55  circuit_dh_param.prime.len = DH1024_KEY_LEN;
     56  circuit_dh_param.base.data = dh_generator_data;
     57  circuit_dh_param.base.len = 1;
     58 
     59  dh_initialized = 1;
     60 }
     61 
     62 void
     63 crypto_dh_free_all_nss(void)
     64 {
     65  dh_initialized = 0;
     66 }
     67 
     68 struct crypto_dh_t {
     69  int dh_type; // XXXX let's remove this later on.
     70  SECKEYPrivateKey *seckey;
     71  SECKEYPublicKey *pubkey;
     72 };
     73 
     74 crypto_dh_t *
     75 crypto_dh_new(int dh_type)
     76 {
     77  crypto_dh_t *r = tor_malloc_zero(sizeof(crypto_dh_t));
     78  r->dh_type = dh_type;
     79  return r;
     80 }
     81 
     82 crypto_dh_t *
     83 crypto_dh_dup(const crypto_dh_t *dh)
     84 {
     85  tor_assert(dh);
     86  crypto_dh_t *r = crypto_dh_new(dh->dh_type);
     87  if (dh->seckey)
     88    r->seckey = SECKEY_CopyPrivateKey(dh->seckey);
     89  if (dh->pubkey)
     90    r->pubkey = SECKEY_CopyPublicKey(dh->pubkey);
     91  return r;
     92 }
     93 
     94 int
     95 crypto_dh_get_bytes(crypto_dh_t *dh)
     96 {
     97  (void)dh;
     98  return DH1024_KEY_LEN;
     99 }
    100 
    101 int
    102 crypto_dh_generate_public(crypto_dh_t *dh)
    103 {
    104  tor_assert(dh);
    105  SECKEYDHParams *p;
    106  if (dh->dh_type == DH_TYPE_TLS)
    107    p = &tls_dh_param;
    108  else
    109    p = &circuit_dh_param;
    110 
    111  dh->seckey = SECKEY_CreateDHPrivateKey(p, &dh->pubkey, NULL);
    112  if (!dh->seckey || !dh->pubkey)
    113    return -1;
    114  else
    115    return 0;
    116 }
    117 int
    118 crypto_dh_get_public(crypto_dh_t *dh, char *pubkey_out,
    119                     size_t pubkey_out_len)
    120 {
    121  tor_assert(dh);
    122  tor_assert(pubkey_out);
    123  if (!dh->pubkey) {
    124    if (crypto_dh_generate_public(dh) < 0)
    125      return -1;
    126  }
    127 
    128  const SECItem *item = &dh->pubkey->u.dh.publicValue;
    129 
    130  if (item->len > pubkey_out_len)
    131    return -1;
    132 
    133  /* Left-pad the result with 0s. */
    134  memset(pubkey_out, 0, pubkey_out_len);
    135  memcpy(pubkey_out + pubkey_out_len - item->len,
    136         item->data,
    137         item->len);
    138 
    139  return 0;
    140 }
    141 
    142 void
    143 crypto_dh_free_(crypto_dh_t *dh)
    144 {
    145  if (!dh)
    146    return;
    147  if (dh->seckey)
    148    SECKEY_DestroyPrivateKey(dh->seckey);
    149  if (dh->pubkey)
    150    SECKEY_DestroyPublicKey(dh->pubkey);
    151  tor_free(dh);
    152 }
    153 
    154 ssize_t
    155 crypto_dh_handshake(int severity, crypto_dh_t *dh,
    156                    const char *pubkey, size_t pubkey_len,
    157                    unsigned char *secret_out,
    158                    size_t secret_bytes_out)
    159 {
    160  tor_assert(dh);
    161  if (pubkey_len > DH1024_KEY_LEN)
    162    return -1;
    163  if (!dh->pubkey || !dh->seckey)
    164    return -1;
    165  if (secret_bytes_out < DH1024_KEY_LEN)
    166    return -1;
    167 
    168  SECKEYPublicKey peer_key;
    169  memset(&peer_key, 0, sizeof(peer_key));
    170  peer_key.keyType = dhKey;
    171  peer_key.pkcs11ID = CK_INVALID_HANDLE;
    172 
    173  if (dh->dh_type == DH_TYPE_TLS)
    174    peer_key.u.dh.prime.data = tls_dh_prime_data; // should never use this code
    175  else
    176    peer_key.u.dh.prime.data = circuit_dh_prime_data;
    177  peer_key.u.dh.prime.len = DH1024_KEY_LEN;
    178  peer_key.u.dh.base.data = dh_generator_data;
    179  peer_key.u.dh.base.len = 1;
    180  peer_key.u.dh.publicValue.data = (unsigned char *)pubkey;
    181  peer_key.u.dh.publicValue.len = (int) pubkey_len;
    182 
    183  PK11SymKey *sym = PK11_PubDerive(dh->seckey, &peer_key,
    184                       PR_FALSE, NULL, NULL, CKM_DH_PKCS_DERIVE,
    185                       CKM_GENERIC_SECRET_KEY_GEN /* ??? */,
    186                       CKA_DERIVE, 0, NULL);
    187  if (! sym) {
    188    crypto_nss_log_errors(severity, "deriving a DH shared secret");
    189    return -1;
    190  }
    191 
    192  SECStatus s = PK11_ExtractKeyValue(sym);
    193  if (s != SECSuccess) {
    194    crypto_nss_log_errors(severity, "extracting a DH shared secret");
    195    PK11_FreeSymKey(sym);
    196    return -1;
    197  }
    198 
    199  SECItem *result = PK11_GetKeyData(sym);
    200  tor_assert(result); // This cannot fail.
    201  if (BUG(result->len > secret_bytes_out)) {
    202    PK11_FreeSymKey(sym);
    203    return -1;
    204  }
    205 
    206  ssize_t len = result->len;
    207  memcpy(secret_out, result->data, len);
    208  PK11_FreeSymKey(sym);
    209 
    210  return len;
    211 }