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 */
8 * \file crypto_dh_nss.c
10 * \brief NSS implementation of Diffie-Hellman over Z_p.
13 #include "lib/crypt_ops/crypto_dh.h"
14 #include "lib/crypt_ops/crypto_nss_mgt.h"
16 #include "lib/encoding/binascii.h"
17 #include "lib/log/util_bug.h"
18 #include "lib/malloc/malloc.h"
20 DISABLE_GCC_WARNING("-Wstrict-prototypes")
24 ENABLE_GCC_WARNING("-Wstrict-prototypes")
26 static int dh_initialized
= 0;
27 static SECKEYDHParams tls_dh_param
, circuit_dh_param
;
28 static unsigned char tls_dh_prime_data
[DH1024_KEY_LEN
];
29 static unsigned char circuit_dh_prime_data
[DH1024_KEY_LEN
];
30 static unsigned char dh_generator_data
[1];
33 crypto_dh_init_nss(void)
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
== DH1024_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
;
49 tls_dh_param
.prime
.data
= tls_dh_prime_data
;
50 tls_dh_param
.prime
.len
= DH1024_KEY_LEN
;
51 tls_dh_param
.base
.data
= dh_generator_data
;
52 tls_dh_param
.base
.len
= 1;
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;
63 crypto_dh_free_all_nss(void)
69 int dh_type
; // XXXX let's remove this later on.
70 SECKEYPrivateKey
*seckey
;
71 SECKEYPublicKey
*pubkey
;
75 crypto_dh_new(int dh_type
)
77 crypto_dh_t
*r
= tor_malloc_zero(sizeof(crypto_dh_t
));
83 crypto_dh_dup(const crypto_dh_t
*dh
)
86 crypto_dh_t
*r
= crypto_dh_new(dh
->dh_type
);
88 r
->seckey
= SECKEY_CopyPrivateKey(dh
->seckey
);
90 r
->pubkey
= SECKEY_CopyPublicKey(dh
->pubkey
);
95 crypto_dh_get_bytes(crypto_dh_t
*dh
)
98 return DH1024_KEY_LEN
;
102 crypto_dh_generate_public(crypto_dh_t
*dh
)
106 if (dh
->dh_type
== DH_TYPE_TLS
)
109 p
= &circuit_dh_param
;
111 dh
->seckey
= SECKEY_CreateDHPrivateKey(p
, &dh
->pubkey
, NULL
);
112 if (!dh
->seckey
|| !dh
->pubkey
)
118 crypto_dh_get_public(crypto_dh_t
*dh
, char *pubkey_out
,
119 size_t pubkey_out_len
)
122 tor_assert(pubkey_out
);
124 if (crypto_dh_generate_public(dh
) < 0)
128 const SECItem
*item
= &dh
->pubkey
->u
.dh
.publicValue
;
130 if (item
->len
> pubkey_out_len
)
133 /* Left-pad the result with 0s. */
134 memset(pubkey_out
, 0, pubkey_out_len
);
135 memcpy(pubkey_out
+ pubkey_out_len
- item
->len
,
143 crypto_dh_free_(crypto_dh_t
*dh
)
148 SECKEY_DestroyPrivateKey(dh
->seckey
);
150 SECKEY_DestroyPublicKey(dh
->pubkey
);
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
)
161 if (pubkey_len
> DH1024_KEY_LEN
)
163 if (!dh
->pubkey
|| !dh
->seckey
)
165 if (secret_bytes_out
< DH1024_KEY_LEN
)
168 SECKEYPublicKey peer_key
;
169 memset(&peer_key
, 0, sizeof(peer_key
));
170 peer_key
.keyType
= dhKey
;
171 peer_key
.pkcs11ID
= CK_INVALID_HANDLE
;
173 if (dh
->dh_type
== DH_TYPE_TLS
)
174 peer_key
.u
.dh
.prime
.data
= tls_dh_prime_data
; // should never use this code
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
;
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
);
188 crypto_nss_log_errors(severity
, "deriving a DH shared secret");
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
);
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
);
206 ssize_t len
= result
->len
;
207 memcpy(secret_out
, result
->data
, len
);
208 PK11_FreeSymKey(sym
);