Skip to content

Commit 93d4792

Browse files
authored
fix(ext/node): add crypto.diffieHellman (#24938)
Co-authored-by: Divy Srivastava <[email protected]> Closes #21806
1 parent 507e5b7 commit 93d4792

File tree

9 files changed

+286
-65
lines changed

9 files changed

+286
-65
lines changed

Cargo.lock

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/node/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ deno_net.workspace = true
3636
deno_package_json.workspace = true
3737
deno_permissions.workspace = true
3838
deno_whoami = "0.1.0"
39+
der = { version = "0.7.9", features = ["derive"] }
3940
digest = { version = "0.10.5", features = ["core-api", "std"] }
4041
dsa = "0.6.1"
4142
ecb.workspace = true

ext/node/lib.rs

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -219,46 +219,47 @@ deno_core::extension!(deno_node,
219219

220220
ops::buffer::op_is_ascii,
221221
ops::buffer::op_is_utf8,
222-
ops::crypto::op_node_create_decipheriv,
222+
ops::crypto::op_node_check_prime_async,
223+
ops::crypto::op_node_check_prime_bytes_async,
224+
ops::crypto::op_node_check_prime_bytes,
225+
ops::crypto::op_node_check_prime,
223226
ops::crypto::op_node_cipheriv_encrypt,
224227
ops::crypto::op_node_cipheriv_final,
225228
ops::crypto::op_node_cipheriv_set_aad,
226-
ops::crypto::op_node_decipheriv_set_aad,
227229
ops::crypto::op_node_create_cipheriv,
230+
ops::crypto::op_node_create_decipheriv,
228231
ops::crypto::op_node_create_hash,
229-
ops::crypto::op_node_get_hashes,
230232
ops::crypto::op_node_decipheriv_decrypt,
231233
ops::crypto::op_node_decipheriv_final,
232-
ops::crypto::op_node_hash_update,
233-
ops::crypto::op_node_hash_update_str,
234-
ops::crypto::op_node_hash_digest,
235-
ops::crypto::op_node_hash_digest_hex,
234+
ops::crypto::op_node_decipheriv_set_aad,
235+
ops::crypto::op_node_dh_compute_secret,
236+
ops::crypto::op_node_diffie_hellman,
237+
ops::crypto::op_node_ecdh_compute_public_key,
238+
ops::crypto::op_node_ecdh_compute_secret,
239+
ops::crypto::op_node_ecdh_encode_pubkey,
240+
ops::crypto::op_node_ecdh_generate_keys,
241+
ops::crypto::op_node_fill_random_async,
242+
ops::crypto::op_node_fill_random,
243+
ops::crypto::op_node_gen_prime_async,
244+
ops::crypto::op_node_gen_prime,
245+
ops::crypto::op_node_get_hashes,
236246
ops::crypto::op_node_hash_clone,
237-
ops::crypto::op_node_private_encrypt,
247+
ops::crypto::op_node_hash_digest_hex,
248+
ops::crypto::op_node_hash_digest,
249+
ops::crypto::op_node_hash_update_str,
250+
ops::crypto::op_node_hash_update,
251+
ops::crypto::op_node_hkdf_async,
252+
ops::crypto::op_node_hkdf,
253+
ops::crypto::op_node_pbkdf2_async,
254+
ops::crypto::op_node_pbkdf2,
238255
ops::crypto::op_node_private_decrypt,
256+
ops::crypto::op_node_private_encrypt,
239257
ops::crypto::op_node_public_encrypt,
240-
ops::crypto::op_node_check_prime,
241-
ops::crypto::op_node_check_prime_async,
242-
ops::crypto::op_node_check_prime_bytes,
243-
ops::crypto::op_node_check_prime_bytes_async,
244-
ops::crypto::op_node_gen_prime,
245-
ops::crypto::op_node_gen_prime_async,
246-
ops::crypto::op_node_pbkdf2,
247-
ops::crypto::op_node_pbkdf2_async,
248-
ops::crypto::op_node_hkdf,
249-
ops::crypto::op_node_hkdf_async,
250-
ops::crypto::op_node_fill_random,
251-
ops::crypto::op_node_fill_random_async,
252-
ops::crypto::op_node_sign,
253-
ops::crypto::op_node_dh_compute_secret,
254-
ops::crypto::op_node_verify,
255258
ops::crypto::op_node_random_int,
256-
ops::crypto::op_node_scrypt_sync,
257259
ops::crypto::op_node_scrypt_async,
258-
ops::crypto::op_node_ecdh_generate_keys,
259-
ops::crypto::op_node_ecdh_compute_secret,
260-
ops::crypto::op_node_ecdh_compute_public_key,
261-
ops::crypto::op_node_ecdh_encode_pubkey,
260+
ops::crypto::op_node_scrypt_sync,
261+
ops::crypto::op_node_sign,
262+
ops::crypto::op_node_verify,
262263
ops::crypto::keys::op_node_create_private_key,
263264
ops::crypto::keys::op_node_create_public_key,
264265
ops::crypto::keys::op_node_create_secret_key,

ext/node/ops/crypto/keys.rs

Lines changed: 123 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use rsa::pkcs1::EncodeRsaPublicKey;
3030
use rsa::traits::PublicKeyParts;
3131
use rsa::RsaPrivateKey;
3232
use rsa::RsaPublicKey;
33+
use sec1::der::Tag;
3334
use sec1::der::Writer as _;
3435
use sec1::pem::PemLabel as _;
3536
use sec1::DecodeEcPrivateKey as _;
@@ -46,7 +47,10 @@ use spki::EncodePublicKey as _;
4647
use spki::SubjectPublicKeyInfoRef;
4748

4849
use super::dh;
50+
use super::dh::DiffieHellmanGroup;
4951
use super::digest::match_fixed_digest_with_oid;
52+
use super::pkcs3;
53+
use super::pkcs3::DhParameter;
5054
use super::primes::Prime;
5155

5256
#[derive(Clone)]
@@ -66,8 +70,7 @@ pub enum AsymmetricPrivateKey {
6670
Ec(EcPrivateKey),
6771
X25519(x25519_dalek::StaticSecret),
6872
Ed25519(ed25519_dalek::SigningKey),
69-
#[allow(unused)]
70-
Dh(dh::PrivateKey),
73+
Dh(DhPrivateKey),
7174
}
7275

7376
#[derive(Clone)]
@@ -125,17 +128,21 @@ pub enum EcPrivateKey {
125128
P384(p384::SecretKey),
126129
}
127130

131+
#[derive(Clone)]
132+
pub struct DhPrivateKey {
133+
pub key: dh::PrivateKey,
134+
pub params: DhParameter,
135+
}
136+
128137
#[derive(Clone)]
129138
pub enum AsymmetricPublicKey {
130139
Rsa(rsa::RsaPublicKey),
131140
RsaPss(RsaPssPublicKey),
132141
Dsa(dsa::VerifyingKey),
133142
Ec(EcPublicKey),
134-
#[allow(unused)]
135143
X25519(x25519_dalek::PublicKey),
136144
Ed25519(ed25519_dalek::VerifyingKey),
137-
#[allow(unused)]
138-
Dh(dh::PublicKey),
145+
Dh(DhPublicKey),
139146
}
140147

141148
#[derive(Clone)]
@@ -151,6 +158,12 @@ pub enum EcPublicKey {
151158
P384(p384::PublicKey),
152159
}
153160

161+
#[derive(Clone)]
162+
pub struct DhPublicKey {
163+
pub key: dh::PublicKey,
164+
pub params: DhParameter,
165+
}
166+
154167
impl KeyObjectHandle {
155168
/// Returns the private key if the handle is an asymmetric private key.
156169
pub fn as_private_key(&self) -> Option<&AsymmetricPrivateKey> {
@@ -492,9 +505,18 @@ impl KeyObjectHandle {
492505
bytes.copy_from_slice(string_ref.as_bytes());
493506
AsymmetricPrivateKey::Ed25519(ed25519_dalek::SigningKey::from(bytes))
494507
}
495-
DH_KEY_AGREEMENT_OID => AsymmetricPrivateKey::Dh(
496-
dh::PrivateKey::from_bytes(pk_info.private_key),
497-
),
508+
DH_KEY_AGREEMENT_OID => {
509+
let params = pk_info
510+
.algorithm
511+
.parameters
512+
.ok_or_else(|| type_error("missing dh parameters"))?;
513+
let params = pkcs3::DhParameter::from_der(&params.to_der().unwrap())
514+
.map_err(|_| type_error("malformed dh parameters"))?;
515+
AsymmetricPrivateKey::Dh(DhPrivateKey {
516+
key: dh::PrivateKey::from_bytes(pk_info.private_key),
517+
params,
518+
})
519+
}
498520
_ => return Err(type_error("unsupported private key oid")),
499521
};
500522

@@ -634,11 +656,20 @@ impl KeyObjectHandle {
634656
AsymmetricPublicKey::Ed25519(verifying_key)
635657
}
636658
DH_KEY_AGREEMENT_OID => {
659+
let params = spki
660+
.algorithm
661+
.parameters
662+
.ok_or_else(|| type_error("missing dh parameters"))?;
663+
let params = pkcs3::DhParameter::from_der(&params.to_der().unwrap())
664+
.map_err(|_| type_error("malformed dh parameters"))?;
637665
let Some(subject_public_key) = spki.subject_public_key.as_bytes()
638666
else {
639667
return Err(type_error("malformed or missing public key in dh spki"));
640668
};
641-
AsymmetricPublicKey::Dh(dh::PublicKey::from_bytes(subject_public_key))
669+
AsymmetricPublicKey::Dh(DhPublicKey {
670+
key: dh::PublicKey::from_bytes(subject_public_key),
671+
params,
672+
})
642673
}
643674
_ => return Err(type_error("unsupported public key oid")),
644675
};
@@ -788,16 +819,18 @@ impl AsymmetricPublicKey {
788819
.into_boxed_slice()
789820
}
790821
AsymmetricPublicKey::Dh(key) => {
791-
let public_key_bytes = key.clone().into_vec();
792-
let spki =
793-
SubjectPublicKeyInfoRef {
794-
algorithm: rsa::pkcs8::AlgorithmIdentifierRef {
795-
oid: DH_KEY_AGREEMENT_OID,
796-
parameters: None,
797-
},
798-
subject_public_key: BitStringRef::from_bytes(&public_key_bytes)
799-
.map_err(|_| type_error("invalid DH public key"))?,
800-
};
822+
let public_key_bytes = key.key.clone().into_vec();
823+
let params = key.params.to_der().unwrap();
824+
let spki = SubjectPublicKeyInfoRef {
825+
algorithm: rsa::pkcs8::AlgorithmIdentifierRef {
826+
oid: DH_KEY_AGREEMENT_OID,
827+
parameters: Some(AnyRef::new(Tag::Sequence, &params).unwrap()),
828+
},
829+
subject_public_key: BitStringRef::from_bytes(&public_key_bytes)
830+
.map_err(|_| {
831+
type_error("invalid DH public key")
832+
})?,
833+
};
801834
spki
802835
.to_der()
803836
.map_err(|_| type_error("invalid DH public key"))?
@@ -917,11 +950,12 @@ impl AsymmetricPrivateKey {
917950
.into_boxed_slice()
918951
}
919952
AsymmetricPrivateKey::Dh(key) => {
920-
let private_key = key.clone().into_vec();
953+
let private_key = key.key.clone().into_vec();
954+
let params = key.params.to_der().unwrap();
921955
let private_key = PrivateKeyInfo {
922956
algorithm: rsa::pkcs8::AlgorithmIdentifierRef {
923957
oid: DH_KEY_AGREEMENT_OID,
924-
parameters: None,
958+
parameters: Some(AnyRef::new(Tag::Sequence, &params).unwrap()),
925959
},
926960
private_key: &private_key,
927961
public_key: None,
@@ -1514,21 +1548,66 @@ pub async fn op_node_generate_ed25519_key_async() -> KeyObjectHandlePair {
15141548
spawn_blocking(ed25519_generate).await.unwrap()
15151549
}
15161550

1551+
fn u32_slice_to_u8_slice(slice: &[u32]) -> &[u8] {
1552+
// SAFETY: just reinterpreting the slice as u8
1553+
unsafe {
1554+
std::slice::from_raw_parts(
1555+
slice.as_ptr() as *const u8,
1556+
std::mem::size_of_val(slice),
1557+
)
1558+
}
1559+
}
1560+
15171561
fn dh_group_generate(
15181562
group_name: &str,
15191563
) -> Result<KeyObjectHandlePair, AnyError> {
1520-
let dh = match group_name {
1521-
"modp5" => dh::DiffieHellman::group::<dh::Modp1536>(),
1522-
"modp14" => dh::DiffieHellman::group::<dh::Modp2048>(),
1523-
"modp15" => dh::DiffieHellman::group::<dh::Modp3072>(),
1524-
"modp16" => dh::DiffieHellman::group::<dh::Modp4096>(),
1525-
"modp17" => dh::DiffieHellman::group::<dh::Modp6144>(),
1526-
"modp18" => dh::DiffieHellman::group::<dh::Modp8192>(),
1564+
let (dh, prime, generator) = match group_name {
1565+
"modp5" => (
1566+
dh::DiffieHellman::group::<dh::Modp1536>(),
1567+
dh::Modp1536::MODULUS,
1568+
dh::Modp1536::GENERATOR,
1569+
),
1570+
"modp14" => (
1571+
dh::DiffieHellman::group::<dh::Modp2048>(),
1572+
dh::Modp2048::MODULUS,
1573+
dh::Modp2048::GENERATOR,
1574+
),
1575+
"modp15" => (
1576+
dh::DiffieHellman::group::<dh::Modp3072>(),
1577+
dh::Modp3072::MODULUS,
1578+
dh::Modp3072::GENERATOR,
1579+
),
1580+
"modp16" => (
1581+
dh::DiffieHellman::group::<dh::Modp4096>(),
1582+
dh::Modp4096::MODULUS,
1583+
dh::Modp4096::GENERATOR,
1584+
),
1585+
"modp17" => (
1586+
dh::DiffieHellman::group::<dh::Modp6144>(),
1587+
dh::Modp6144::MODULUS,
1588+
dh::Modp6144::GENERATOR,
1589+
),
1590+
"modp18" => (
1591+
dh::DiffieHellman::group::<dh::Modp8192>(),
1592+
dh::Modp8192::MODULUS,
1593+
dh::Modp8192::GENERATOR,
1594+
),
15271595
_ => return Err(type_error("Unsupported group name")),
15281596
};
1597+
let params = DhParameter {
1598+
prime: asn1::Int::new(u32_slice_to_u8_slice(prime)).unwrap(),
1599+
base: asn1::Int::new(generator.to_be_bytes().as_slice()).unwrap(),
1600+
private_value_length: None,
1601+
};
15291602
Ok(KeyObjectHandlePair::new(
1530-
AsymmetricPrivateKey::Dh(dh.private_key),
1531-
AsymmetricPublicKey::Dh(dh.public_key),
1603+
AsymmetricPrivateKey::Dh(DhPrivateKey {
1604+
key: dh.private_key,
1605+
params: params.clone(),
1606+
}),
1607+
AsymmetricPublicKey::Dh(DhPublicKey {
1608+
key: dh.public_key,
1609+
params,
1610+
}),
15321611
))
15331612
}
15341613

@@ -1558,10 +1637,21 @@ fn dh_generate(
15581637
let prime = prime
15591638
.map(|p| p.into())
15601639
.unwrap_or_else(|| Prime::generate(prime_len));
1561-
let dh = dh::DiffieHellman::new(prime, generator);
1640+
let dh = dh::DiffieHellman::new(prime.clone(), generator);
1641+
let params = DhParameter {
1642+
prime: asn1::Int::new(&prime.0.to_bytes_be()).unwrap(),
1643+
base: asn1::Int::new(generator.to_be_bytes().as_slice()).unwrap(),
1644+
private_value_length: None,
1645+
};
15621646
Ok(KeyObjectHandlePair::new(
1563-
AsymmetricPrivateKey::Dh(dh.private_key),
1564-
AsymmetricPublicKey::Dh(dh.public_key),
1647+
AsymmetricPrivateKey::Dh(DhPrivateKey {
1648+
key: dh.private_key,
1649+
params: params.clone(),
1650+
}),
1651+
AsymmetricPublicKey::Dh(DhPublicKey {
1652+
key: dh.public_key,
1653+
params,
1654+
}),
15651655
))
15661656
}
15671657

0 commit comments

Comments
 (0)