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 }