1use super::{arg_str, to_base64, to_hex};
13use crate::host::{is_callable, with_host, JsObj};
14use cipher::block_padding::Pkcs7;
15use cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit, StreamCipher};
16use fusevm::Value;
17use hkdf::Hkdf;
18use hmac::{Hmac, Mac};
19use indexmap::IndexMap;
20use md5::{Digest as _, Md5};
21use num_bigint::BigUint;
22use p256::elliptic_curve::sec1::ToEncodedPoint;
23use pkcs8::{DecodePrivateKey, EncodePrivateKey, LineEnding};
24use rsa::pkcs1::{DecodeRsaPrivateKey, DecodeRsaPublicKey};
25use sha1::Sha1;
26use sha2::{Sha256, Sha384, Sha512};
27use signature::{SignatureEncoding, Signer, Verifier};
28use spki::{DecodePublicKey, EncodePublicKey};
29use subtle::ConstantTimeEq;
30
31const CIPHERS: &[&str] = &[
33 "aes-128-cbc",
34 "aes-192-cbc",
35 "aes-256-cbc",
36 "aes-128-ctr",
37 "aes-192-ctr",
38 "aes-256-ctr",
39];
40
41const HASHES: &[&str] = &["md5", "sha1", "sha256", "sha512"];
43
44const CURVES: &[&str] = &[
48 "prime256v1",
49 "secp256k1",
50 "secp384r1",
51 "secp521r1",
52 "secp224r1",
53 "secp192k1",
54 "secp256r1",
55];
56
57pub const METHODS: &[&str] = &[
58 "createHash",
59 "createHmac",
60 "randomBytes",
61 "randomUUID",
62 "randomInt",
63 "pbkdf2Sync",
64 "pbkdf2",
65 "scryptSync",
66 "scrypt",
67 "hkdfSync",
68 "hkdf",
69 "createCipheriv",
70 "createDecipheriv",
71 "randomFillSync",
72 "randomFill",
73 "timingSafeEqual",
74 "getHashes",
75 "getCiphers",
76 "getCurves",
77 "getFips",
78 "pseudoRandomBytes",
79 "prng",
80 "rng",
81 "hash",
82 "randomUUIDv7",
83 "getCipherInfo",
84 "generateKeyPairSync",
86 "generateKeyPair",
87 "createPrivateKey",
88 "createPublicKey",
89 "createSecretKey",
90 "createSign",
91 "createVerify",
92 "sign",
93 "verify",
94 "publicEncrypt",
95 "privateDecrypt",
96 "privateEncrypt",
97 "publicDecrypt",
98 "createDiffieHellman",
100 "createDiffieHellmanGroup",
101 "getDiffieHellman",
102 "createECDH",
103 "diffieHellman",
104 "checkPrime",
106 "checkPrimeSync",
107 "generatePrime",
108 "generatePrimeSync",
109 "argon2",
111 "argon2Sync",
112 "getRandomValues",
113];
114
115pub const WEBCRYPTO_METHODS: &[&str] = &["getRandomValues", "randomUUID"];
123
124pub const SUBTLE_METHODS: &[&str] = &["digest"];
126
127pub fn subtle_call(method: &str, args: &[Value]) -> Option<Result<Value, String>> {
129 match method {
130 "digest" => {
135 let spec = args.first().cloned().unwrap_or(Value::Undef);
136 let named = crate::builtins::get_property(&spec, "name").unwrap_or(Value::Undef);
137 let raw = match named {
138 Value::Undef => with_host(|h| h.str_of(&spec)),
139 n => with_host(|h| h.str_of(&n)),
140 };
141 let algo = raw.replace('-', "").to_ascii_lowercase();
142 if !supported(&algo) {
143 return Some(Err(crate::host::dom_error(
144 "NotSupportedError",
145 "Unrecognized algorithm name",
146 )));
147 }
148 let data = val_bytes_at(args, 1);
149 let out = digest(&algo, &data);
150 let buf = crate::stdlib::typedarray::new_array_buffer(out.len());
151 crate::stdlib::typedarray::write_buffer_bytes(&buf, &out);
152 Some(crate::builtins::promise_resolve_pub(buf))
153 }
154 _ => None,
155 }
156}
157
158pub fn call(method: &str, args: &[Value]) -> Option<Result<Value, String>> {
159 Some(match method {
160 "createHash" => {
161 let algo = arg_str(args, 0).to_ascii_lowercase();
162 if !supported(&algo) {
163 return Some(Err("Error: Digest method not supported".into()));
166 }
167 Ok(with_host(|h| {
168 let data = h.new_array(Vec::new());
169 let mut m = IndexMap::new();
170 m.insert("@@native".into(), h.new_str("Hash"));
171 m.insert("@@algo".into(), h.new_str(algo));
172 m.insert("@@data".into(), data);
173 h.new_object(m)
174 }))
175 }
176 "createHmac" => {
177 let algo = arg_str(args, 0).to_ascii_lowercase();
178 if !supported(&algo) {
179 return Some(Err("Error: Digest method not supported".into()));
182 }
183 let key = key_bytes(args.get(1));
185 Ok(with_host(|h| {
186 let data = h.new_array(Vec::new());
187 let keyv = h.new_array(key.iter().map(|b| Value::Float(*b as f64)).collect());
188 let mut m = IndexMap::new();
189 m.insert("@@native".into(), h.new_str("Hmac"));
190 m.insert("@@algo".into(), h.new_str(algo));
191 m.insert("@@key".into(), keyv);
192 m.insert("@@data".into(), data);
193 h.new_object(m)
194 }))
195 }
196 "randomBytes" => {
197 let n = super::arg_num(args, 0).max(0.0) as usize;
198 let mut buf = vec![0u8; n];
199 if let Err(e) = getrandom::getrandom(&mut buf) {
200 return Some(Err(format!("Error: failed to generate random bytes: {e}")));
201 }
202 let cb = args
205 .get(1)
206 .cloned()
207 .filter(|v| with_host(|h| is_callable(h, v)));
208 if let Some(cb) = cb {
209 let bufv = super::buffer::from_bytes(&buf);
210 with_host(|h| {
211 let nullv = h.null();
212 h.queue_micro(cb, vec![nullv, bufv]);
213 });
214 Ok(Value::Undef)
215 } else {
216 Ok(super::buffer::from_bytes(&buf))
217 }
218 }
219 "randomUUID" => {
220 let mut b = [0u8; 16];
221 if let Err(e) = getrandom::getrandom(&mut b) {
222 return Some(Err(format!("Error: failed to generate random bytes: {e}")));
223 }
224 b[6] = (b[6] & 0x0f) | 0x40;
226 b[8] = (b[8] & 0x3f) | 0x80;
227 let h = to_hex(&b);
228 let uuid = format!(
229 "{}-{}-{}-{}-{}",
230 &h[0..8],
231 &h[8..12],
232 &h[12..16],
233 &h[16..20],
234 &h[20..32],
235 );
236 Ok(with_host(|host| host.new_str(uuid)))
237 }
238 "randomInt" => {
239 let (min, max) = if args.len() >= 2 {
241 (super::arg_num(args, 0), super::arg_num(args, 1))
242 } else {
243 (0.0, super::arg_num(args, 0))
244 };
245 let (min, max) = (min as i64, max as i64);
246 if max <= min {
247 return Some(Err(crate::host::coded_error(
248 "RangeError",
249 "ERR_OUT_OF_RANGE",
250 &format!(
251 "The value of \"max\" is out of range. It must be greater than \
252 the value of \"min\" ({min}). Received {max}"
253 ),
254 )));
255 }
256 let range = (max - min) as u64;
257 match random_below(range) {
258 Ok(r) => Ok(Value::Float((min + r as i64) as f64)),
259 Err(e) => Err(format!("Error: failed to generate random bytes: {e}")),
260 }
261 }
262 "pbkdf2Sync" => pbkdf2(args, None),
264 "pbkdf2" => pbkdf2(args, args.get(5).cloned()),
265 "scryptSync" => scrypt(args, None),
266 "scrypt" => scrypt(args, trailing_cb(args)),
267 "hkdfSync" => hkdf(args, None),
268 "hkdf" => hkdf(args, args.get(5).cloned()),
269 "createCipheriv" => make_cipher("Cipheriv", args),
271 "createDecipheriv" => make_cipher("Decipheriv", args),
272 "randomFillSync" => random_fill(args),
274 "randomFill" => {
275 let cb = trailing_cb(args);
276 let res = random_fill(args);
277 match (cb, res) {
278 (Some(cb), Ok(buf)) => {
279 with_host(|h| {
280 let nullv = h.null();
281 h.queue_micro(cb, vec![nullv, buf]);
282 });
283 Ok(Value::Undef)
284 }
285 (Some(cb), Err(e)) => {
286 let errv = with_host(|h| h.new_str(e));
287 with_host(|h| h.queue_micro(cb, vec![errv]));
288 Ok(Value::Undef)
289 }
290 (None, r) => r,
291 }
292 }
293 "timingSafeEqual" => {
295 let a = val_bytes_at(args, 0);
296 let b = val_bytes_at(args, 1);
297 if a.len() != b.len() {
298 return Some(Err(crate::host::plain_coded_error(
299 "RangeError",
300 "ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH",
301 "Input buffers must have the same byte length",
302 )));
303 }
304 Ok(Value::Bool(a.ct_eq(&b).into()))
305 }
306 "getHashes" => Ok(with_host(|h| {
308 let items: Vec<Value> = HASHES.iter().map(|s| h.new_str(*s)).collect();
309 h.new_array(items)
310 })),
311 "getCiphers" => Ok(with_host(|h| {
312 let items: Vec<Value> = CIPHERS.iter().map(|s| h.new_str(*s)).collect();
313 h.new_array(items)
314 })),
315 "getCurves" => Ok(with_host(|h| {
316 let items: Vec<Value> = CURVES.iter().map(|s| h.new_str(*s)).collect();
317 h.new_array(items)
318 })),
319 "getFips" => Ok(Value::Float(0.0)),
321 "getCipherInfo" => cipher_info(&arg_str(args, 0).to_ascii_lowercase()),
322 "pseudoRandomBytes" | "prng" | "rng" => {
324 let n = super::arg_num(args, 0).max(0.0) as usize;
325 let mut buf = vec![0u8; n];
326 if let Err(e) = getrandom::getrandom(&mut buf) {
327 return Some(Err(format!("Error: failed to generate random bytes: {e}")));
328 }
329 let cb = args
330 .get(1)
331 .cloned()
332 .filter(|v| with_host(|h| is_callable(h, v)));
333 if let Some(cb) = cb {
334 let bufv = super::buffer::from_bytes(&buf);
335 with_host(|h| {
336 let nullv = h.null();
337 h.queue_micro(cb, vec![nullv, bufv]);
338 });
339 Ok(Value::Undef)
340 } else {
341 Ok(super::buffer::from_bytes(&buf))
342 }
343 }
344 "hash" => {
346 let algo = arg_str(args, 0).to_ascii_lowercase();
347 if !supported(&algo) {
348 return Some(Err("Error: Digest method not supported".into()));
351 }
352 let data = val_bytes_at(args, 1);
354 let out = digest(&algo, &data);
356 let out_enc = if args.len() > 2 {
357 arg_str(args, 2)
358 } else {
359 "hex".into()
360 };
361 Ok(if out_enc == "buffer" {
362 super::buffer::from_bytes(&out)
363 } else {
364 encode_out(&out, Some(&out_enc))
365 })
366 }
367 "randomUUIDv7" => uuid_v7(),
369 "generateKeyPairSync" => {
371 generate_key_pair(&arg_str(args, 0).to_ascii_lowercase(), args.get(1))
372 }
373 "generateKeyPair" => {
374 let cb = trailing_cb(args);
375 let res = generate_key_pair(&arg_str(args, 0).to_ascii_lowercase(), args.get(1));
376 match cb {
377 Some(cb) => {
378 match res {
379 Ok(pair) => with_host(|h| {
380 let nullv = h.null();
382 let (pubk, prvk) = match h.get(&pair) {
383 Some(JsObj::Object(p)) => (
384 p.get("publicKey").cloned().unwrap_or(Value::Undef),
385 p.get("privateKey").cloned().unwrap_or(Value::Undef),
386 ),
387 _ => (Value::Undef, Value::Undef),
388 };
389 h.queue_micro(cb, vec![nullv, pubk, prvk]);
390 }),
391 Err(e) => {
392 let errv = with_host(|h| h.new_str(e));
393 with_host(|h| h.queue_micro(cb, vec![errv]));
394 }
395 }
396 Ok(Value::Undef)
397 }
398 None => res,
399 }
400 }
401 "createPrivateKey" => create_private_key(args.first()),
402 "createPublicKey" => create_public_key(args.first()),
403 "createSecretKey" => Ok(secret_key_object(&val_bytes_at(args, 0))),
404 "createSign" => Ok(new_sign_verify("Sign", &arg_str(args, 0))),
406 "createVerify" => Ok(new_sign_verify("Verify", &arg_str(args, 0))),
407 "sign" => {
409 let algo = arg_str(args, 0);
410 let data = val_bytes_at(args, 1);
411 let key = key_material(args.get(2).unwrap_or(&Value::Undef));
412 match sign_data(&key, &algo, &data) {
413 Ok(sig) => Ok(super::buffer::from_bytes(&sig)),
414 Err(e) => Err(e),
415 }
416 }
417 "verify" => {
418 let algo = arg_str(args, 0);
419 let data = val_bytes_at(args, 1);
420 let key = key_material(args.get(2).unwrap_or(&Value::Undef));
421 let sig = val_bytes_at(args, 3);
422 match verify_data(&key, &algo, &data, &sig) {
423 Ok(ok) => Ok(Value::Bool(ok)),
424 Err(e) => Err(e),
425 }
426 }
427 "publicEncrypt" => rsa_public_op(args, true, true),
429 "privateDecrypt" => rsa_public_op(args, false, false),
430 "privateEncrypt" => rsa_private_encrypt(args),
431 "publicDecrypt" => rsa_public_decrypt(args),
432 "createDiffieHellman" => create_diffie_hellman(args),
434 "createDiffieHellmanGroup" | "getDiffieHellman" => diffie_hellman_group(&arg_str(args, 0)),
435 "createECDH" => create_ecdh(&arg_str(args, 0)),
436 "diffieHellman" => diffie_hellman_oneshot(args.first()),
437 "checkPrimeSync" => Ok(Value::Bool(check_prime(args.first()))),
439 "checkPrime" => {
440 let ok = check_prime(args.first());
441 let cb = trailing_cb(args);
442 match cb {
443 Some(cb) => {
444 with_host(|h| {
445 let nullv = h.null();
446 h.queue_micro(cb, vec![nullv, Value::Bool(ok)]);
447 });
448 Ok(Value::Undef)
449 }
450 None => Ok(Value::Bool(ok)),
451 }
452 }
453 "generatePrimeSync" => {
454 generate_prime(super::arg_num(args, 0) as usize, opts_object(args, 1))
455 }
456 "generatePrime" => {
457 let res = generate_prime(super::arg_num(args, 0) as usize, opts_object(args, 1));
458 let cb = trailing_cb(args);
459 match (cb, res) {
460 (Some(cb), Ok(v)) => {
461 with_host(|h| {
462 let nullv = h.null();
463 h.queue_micro(cb, vec![nullv, v]);
464 });
465 Ok(Value::Undef)
466 }
467 (Some(cb), Err(e)) => {
468 let errv = with_host(|h| h.new_str(e));
469 with_host(|h| h.queue_micro(cb, vec![errv]));
470 Ok(Value::Undef)
471 }
472 (None, r) => r,
473 }
474 }
475 "argon2Sync" => match argon2_hash(&arg_str(args, 0), args.get(1)) {
477 Ok(out) => Ok(super::buffer::from_bytes(&out)),
478 Err(e) => Err(e),
479 },
480 "argon2" => deliver_async(
481 trailing_cb(args),
482 argon2_hash(&arg_str(args, 0), args.get(1)),
483 ),
484 "getRandomValues" => get_random_values(args.first()),
486 _ => return None,
487 })
488}
489
490pub fn instance_call(recv: &Value, method: &str, args: &[Value]) -> Result<Value, String> {
492 hashlike_call("Hash", recv, method, args)
493}
494
495pub fn hmac_instance_call(recv: &Value, method: &str, args: &[Value]) -> Result<Value, String> {
497 hashlike_call("Hmac", recv, method, args)
498}
499
500pub fn cipher_instance_call(
506 tag: &str,
507 recv: &Value,
508 method: &str,
509 args: &[Value],
510) -> Result<Value, String> {
511 match method {
512 "update" => {
513 if finalized(recv) {
516 return Err("Error: Trying to add data in unsupported state".into());
517 }
518 let enc = if args.len() > 1 {
522 arg_str(args, 1)
523 } else {
524 "utf8".into()
525 };
526 let bytes = update_bytes(args, &enc)?;
527 with_host(|h| {
528 if let Some(JsObj::Object(p)) = h.get(recv).cloned() {
529 if let Some(arr) = p.get("@@data").cloned() {
530 if let Some(JsObj::Array(items)) = h.get_mut(&arr) {
531 items.extend(bytes.iter().map(|b| Value::Float(*b as f64)));
532 }
533 }
534 }
535 });
536 let out_enc = if args.len() > 2 {
537 Some(arg_str(args, 2))
538 } else {
539 None
540 };
541 Ok(encode_out(&[], out_enc.as_deref()))
542 }
543 "final" => {
544 if finalized(recv) {
548 return Err(crate::host::coded_error(
549 "Error",
550 "ERR_CRYPTO_INVALID_STATE",
551 "Invalid state",
552 ));
553 }
554 mark_finalized(recv);
555 let (algo, key, iv, data) = with_host(|h| {
556 let (mut algo, mut key, mut iv, mut data) =
557 (String::new(), Vec::new(), Vec::new(), Vec::new());
558 if let Some(JsObj::Object(p)) = h.get(recv) {
559 algo = p.get("@@algo").map(|v| h.str_of(v)).unwrap_or_default();
560 if let Some(JsObj::Array(it)) = p.get("@@key").and_then(|v| h.get(v)) {
561 key = it.iter().map(|v| h.to_number(v) as u8).collect();
562 }
563 if let Some(JsObj::Array(it)) = p.get("@@iv").and_then(|v| h.get(v)) {
564 iv = it.iter().map(|v| h.to_number(v) as u8).collect();
565 }
566 if let Some(JsObj::Array(it)) = p.get("@@data").and_then(|v| h.get(v)) {
567 data = it.iter().map(|v| h.to_number(v) as u8).collect();
568 }
569 }
570 (algo, key, iv, data)
571 });
572 let out = cipher_crypt(&algo, &key, &iv, &data, tag == "Cipheriv")?;
573 let out_enc = if args.is_empty() {
574 None
575 } else {
576 Some(arg_str(args, 0))
577 };
578 Ok(encode_out(&out, out_enc.as_deref()))
579 }
580 "setAutoPadding" => Ok(recv.clone()),
581 _ => Err(crate::host::type_error(&format!(
582 "{}.{method} is not a function",
583 tag.to_ascii_lowercase()
584 ))),
585 }
586}
587
588fn hashlike_call(kind: &str, recv: &Value, method: &str, args: &[Value]) -> Result<Value, String> {
591 match method {
592 "update" => {
593 if finalized(recv) {
597 return Err(hash_finalized());
598 }
599 let enc = if args.len() > 1 {
600 arg_str(args, 1)
601 } else {
602 "utf8".into()
603 };
604 let bytes = update_bytes(args, &enc)?;
611 with_host(|h| {
612 if let Some(JsObj::Object(p)) = h.get(recv).cloned() {
613 if let Some(arr) = p.get("@@data").cloned() {
614 if let Some(JsObj::Array(items)) = h.get_mut(&arr) {
615 items.extend(bytes.iter().map(|b| Value::Float(*b as f64)));
616 }
617 }
618 }
619 });
620 Ok(recv.clone())
621 }
622 "copy" if kind == "Hash" => {
626 if finalized(recv) {
627 return Err(hash_finalized());
628 }
629 let (algo, data) = with_host(|h| {
630 let (mut algo, mut data) = (String::new(), Vec::new());
631 if let Some(JsObj::Object(p)) = h.get(recv) {
632 algo = p.get("@@algo").map(|v| h.str_of(v)).unwrap_or_default();
633 if let Some(JsObj::Array(items)) = p.get("@@data").and_then(|v| h.get(v)) {
634 data = items.clone();
635 }
636 }
637 (algo, data)
638 });
639 Ok(with_host(|h| {
640 let data = h.new_array(data);
641 let mut m = IndexMap::new();
642 m.insert("@@native".into(), h.new_str("Hash"));
643 m.insert("@@algo".into(), h.new_str(algo));
644 m.insert("@@data".into(), data);
645 h.new_object(m)
646 }))
647 }
648 "digest" => {
649 if finalized(recv) {
653 if kind == "Hash" {
654 return Err(hash_finalized());
655 }
656 let enc = args.first().map(|_| arg_str(args, 0));
657 return Ok(encode_digest(&[], enc.as_deref()));
658 }
659 mark_finalized(recv);
660 let (algo, key, data) = with_host(|h| {
661 let (mut algo, mut key, mut data) = (String::new(), Vec::new(), Vec::new());
662 if let Some(JsObj::Object(p)) = h.get(recv) {
663 algo = p.get("@@algo").map(|v| h.str_of(v)).unwrap_or_default();
664 if let Some(JsObj::Array(items)) = p.get("@@data").and_then(|v| h.get(v)) {
665 data = items.iter().map(|v| h.to_number(v) as u8).collect();
666 }
667 if let Some(JsObj::Array(items)) = p.get("@@key").and_then(|v| h.get(v)) {
668 key = items.iter().map(|v| h.to_number(v) as u8).collect();
669 }
670 }
671 (algo, key, data)
672 });
673 let out = if kind == "Hmac" {
674 hmac_digest(&algo, &key, &data)
675 } else {
676 digest(&algo, &data)
677 };
678 let enc = if args.is_empty() {
679 None
680 } else {
681 Some(arg_str(args, 0))
682 };
683 Ok(encode_digest(&out, enc.as_deref()))
684 }
685 _ => Err(crate::host::type_error(&format!(
686 "{}.{method} is not a function",
687 kind.to_ascii_lowercase()
688 ))),
689 }
690}
691
692fn update_bytes(args: &[Value], enc: &str) -> Result<Vec<u8>, String> {
699 let first = args.first().cloned().unwrap_or(Value::Undef);
700 if let Some(b) = super::buffer::view_bytes(&first) {
701 return Ok(b);
702 }
703 if with_host(|h| h.as_str(&first)).is_none() {
704 return Err(crate::host::invalid_arg_type(
705 "data",
706 "argument",
707 "string or an instance of Buffer, TypedArray, or DataView",
708 &first,
709 ));
710 }
711 Ok(decode(&arg_str(args, 0), enc))
712}
713
714fn encode_digest(out: &[u8], enc: Option<&str>) -> Value {
716 match enc {
717 Some("hex") => with_host(|h| h.new_str(to_hex(out))),
718 Some("base64") | Some("base64url") => with_host(|h| h.new_str(to_base64(out))),
719 Some("latin1") | Some("binary") => {
720 with_host(|h| h.new_str(out.iter().map(|b| *b as char).collect::<String>()))
721 }
722 _ => super::buffer::from_bytes(out),
723 }
724}
725
726fn finalized(recv: &Value) -> bool {
728 with_host(|h| matches!(h.get(recv), Some(JsObj::Object(p)) if p.contains_key("@@done")))
729}
730
731fn mark_finalized(recv: &Value) {
732 with_host(|h| {
733 if let Some(JsObj::Object(p)) = h.get_mut(recv) {
734 p.insert("@@done".into(), Value::Bool(true));
735 }
736 });
737}
738
739fn hash_finalized() -> String {
740 crate::host::coded_error(
741 "Error",
742 "ERR_CRYPTO_HASH_FINALIZED",
743 "Digest already called",
744 )
745}
746
747fn supported(algo: &str) -> bool {
748 matches!(algo, "md5" | "sha1" | "sha256" | "sha512")
749}
750
751fn digest(algo: &str, data: &[u8]) -> Vec<u8> {
752 match algo {
753 "md5" => {
754 let mut h = Md5::new();
755 h.update(data);
756 h.finalize().to_vec()
757 }
758 "sha1" => {
759 let mut h = Sha1::new();
760 h.update(data);
761 h.finalize().to_vec()
762 }
763 "sha512" => {
764 let mut h = Sha512::new();
765 h.update(data);
766 h.finalize().to_vec()
767 }
768 _ => {
769 let mut h = Sha256::new();
770 h.update(data);
771 h.finalize().to_vec()
772 }
773 }
774}
775
776fn hmac_digest(algo: &str, key: &[u8], data: &[u8]) -> Vec<u8> {
777 match algo {
779 "md5" => {
780 let mut m = Hmac::<Md5>::new_from_slice(key).expect("HMAC accepts any key length");
781 m.update(data);
782 m.finalize().into_bytes().to_vec()
783 }
784 "sha1" => {
785 let mut m = Hmac::<Sha1>::new_from_slice(key).expect("HMAC accepts any key length");
786 m.update(data);
787 m.finalize().into_bytes().to_vec()
788 }
789 "sha512" => {
790 let mut m = Hmac::<Sha512>::new_from_slice(key).expect("HMAC accepts any key length");
791 m.update(data);
792 m.finalize().into_bytes().to_vec()
793 }
794 _ => {
795 let mut m = Hmac::<Sha256>::new_from_slice(key).expect("HMAC accepts any key length");
796 m.update(data);
797 m.finalize().into_bytes().to_vec()
798 }
799 }
800}
801
802fn key_bytes(v: Option<&Value>) -> Vec<u8> {
805 v.map(val_bytes).unwrap_or_default()
806}
807
808fn val_bytes(v: &Value) -> Vec<u8> {
811 if let Some(bytes) = super::buffer::view_bytes(v) {
816 return bytes;
817 }
818 if is_key_object(v) {
822 return with_host(|h| {
823 match h.get(v) {
824 Some(JsObj::Object(p)) => p.get("@@secret").cloned(),
825 _ => None,
826 }
827 .and_then(|arr| match h.get(&arr) {
828 Some(JsObj::Array(items)) => {
829 Some(items.iter().map(|b| h.to_number(b) as u8).collect())
830 }
831 _ => None,
832 })
833 .unwrap_or_default()
834 });
835 }
836 with_host(|h| h.str_of(v)).into_bytes()
837}
838
839const KDF_BYTES: &str = "string or an instance of ArrayBuffer, Buffer, TypedArray, or DataView";
844const HKDF_IKM: &str =
845 "string or an instance of SecretKeyObject, ArrayBuffer, TypedArray, DataView, or Buffer";
846const HKDF_BYTES: &str = "string or an instance of ArrayBuffer, TypedArray, DataView, or Buffer";
847
848fn bytes_arg(args: &[Value], i: usize, name: &str, expected: &str) -> Result<Vec<u8>, String> {
853 let v = args.get(i).cloned().unwrap_or(Value::Undef);
854 if super::buffer::view_bytes(&v).is_none()
855 && with_host(|h| h.as_str(&v)).is_none()
856 && !(expected == HKDF_IKM && is_key_object(&v))
857 {
858 return Err(crate::host::invalid_arg_type(
859 name, "argument", expected, &v,
860 ));
861 }
862 Ok(val_bytes_at(args, i))
863}
864
865fn val_bytes_at(args: &[Value], i: usize) -> Vec<u8> {
867 args.get(i).map(val_bytes).unwrap_or_default()
868}
869
870fn trailing_cb(args: &[Value]) -> Option<Value> {
872 args.last()
873 .cloned()
874 .filter(|v| with_host(|h| is_callable(h, v)))
875}
876
877fn opts_object(args: &[Value], i: usize) -> Option<Value> {
879 let v = args.get(i)?.clone();
880 let is_obj = with_host(|h| matches!(h.get(&v), Some(JsObj::Object(_))) && !is_callable(h, &v));
881 is_obj.then_some(v)
882}
883
884fn deliver_async(cb: Option<Value>, res: Result<Vec<u8>, String>) -> Result<Value, String> {
887 let out = res?;
892 match cb.filter(|v| with_host(|h| is_callable(h, v))) {
893 Some(cb) => {
894 let bufv = super::buffer::from_bytes(&out);
895 with_host(|h| {
896 let nullv = h.null();
897 h.queue_micro(cb, vec![nullv, bufv]);
898 });
899 Ok(Value::Undef)
900 }
901 None => Ok(super::buffer::from_bytes(&out)),
902 }
903}
904
905fn pbkdf2(args: &[Value], cb: Option<Value>) -> Result<Value, String> {
908 let digest = arg_str(args, 4).to_ascii_lowercase();
909 let res = pbkdf2_derive(
910 &digest,
911 &bytes_arg(args, 0, "password", KDF_BYTES)?,
912 &bytes_arg(args, 1, "salt", KDF_BYTES)?,
913 super::arg_num(args, 2) as u32,
914 super::arg_num(args, 3).max(0.0) as usize,
915 );
916 deliver_async(cb, res)
917}
918
919fn scrypt(args: &[Value], cb: Option<Value>) -> Result<Value, String> {
921 let keylen = super::arg_num(args, 2).max(0.0) as usize;
922 let res = scrypt_derive(
923 &bytes_arg(args, 0, "password", KDF_BYTES)?,
924 &bytes_arg(args, 1, "salt", KDF_BYTES)?,
925 keylen,
926 opts_object(args, 3),
927 );
928 deliver_async(cb, res)
929}
930
931fn hkdf(args: &[Value], cb: Option<Value>) -> Result<Value, String> {
933 let digest = arg_str(args, 0).to_ascii_lowercase();
934 let res = hkdf_derive(
935 &digest,
936 &bytes_arg(args, 1, "ikm", HKDF_IKM)?,
937 &bytes_arg(args, 2, "salt", HKDF_BYTES)?,
938 &bytes_arg(args, 3, "info", HKDF_BYTES)?,
939 super::arg_num(args, 4).max(0.0) as usize,
940 );
941 deliver_async(cb, res)
942}
943
944fn pbkdf2_derive(
946 digest: &str,
947 pass: &[u8],
948 salt: &[u8],
949 iters: u32,
950 keylen: usize,
951) -> Result<Vec<u8>, String> {
952 let mut out = vec![0u8; keylen];
953 match digest {
954 "sha1" => pbkdf2::pbkdf2_hmac::<Sha1>(pass, salt, iters, &mut out),
955 "sha256" => pbkdf2::pbkdf2_hmac::<Sha256>(pass, salt, iters, &mut out),
956 "sha512" => pbkdf2::pbkdf2_hmac::<Sha512>(pass, salt, iters, &mut out),
957 "md5" => pbkdf2::pbkdf2_hmac::<Md5>(pass, salt, iters, &mut out),
958 _ => {
959 return Err(crate::host::coded_error(
960 "TypeError",
961 "ERR_CRYPTO_INVALID_DIGEST",
962 &format!("Invalid digest: {digest}"),
963 ))
964 }
965 }
966 Ok(out)
967}
968
969fn scrypt_derive(
972 pass: &[u8],
973 salt: &[u8],
974 keylen: usize,
975 opts: Option<Value>,
976) -> Result<Vec<u8>, String> {
977 let (mut n, mut r, mut p) = (16384.0f64, 8.0f64, 1.0f64);
978 if let Some(o) = opts {
979 n = opt_num(&o, &["N", "cost"], n);
980 r = opt_num(&o, &["r", "blockSize"], r);
981 p = opt_num(&o, &["p", "parallelization"], p);
982 }
983 let n = n as u64;
984 if n < 2 || (n & (n - 1)) != 0 {
985 return Err(crate::host::coded_error(
987 "RangeError",
988 "ERR_CRYPTO_INVALID_SCRYPT_PARAMS",
989 "Invalid scrypt params",
990 ));
991 }
992 let params = scrypt::Params::new(n.trailing_zeros() as u8, r as u32, p as u32, keylen)
993 .map_err(|e| format!("Error: {e}"))?;
994 let mut out = vec![0u8; keylen];
995 scrypt::scrypt(pass, salt, ¶ms, &mut out).map_err(|e| format!("Error: {e}"))?;
996 Ok(out)
997}
998
999fn hkdf_derive(
1001 digest: &str,
1002 ikm: &[u8],
1003 salt: &[u8],
1004 info: &[u8],
1005 keylen: usize,
1006) -> Result<Vec<u8>, String> {
1007 let mut out = vec![0u8; keylen];
1008 let ok = match digest {
1009 "sha1" => Hkdf::<Sha1>::new(Some(salt), ikm).expand(info, &mut out),
1010 "sha256" => Hkdf::<Sha256>::new(Some(salt), ikm).expand(info, &mut out),
1011 "sha512" => Hkdf::<Sha512>::new(Some(salt), ikm).expand(info, &mut out),
1012 "md5" => Hkdf::<Md5>::new(Some(salt), ikm).expand(info, &mut out),
1013 _ => {
1014 return Err(crate::host::coded_error(
1015 "TypeError",
1016 "ERR_CRYPTO_INVALID_DIGEST",
1017 &format!("Invalid digest: {digest}"),
1018 ))
1019 }
1020 };
1021 ok.map_err(|_| "Error: Invalid key length".to_string())?;
1022 Ok(out)
1023}
1024
1025fn opt_num(obj: &Value, keys: &[&str], default: f64) -> f64 {
1028 with_host(|h| {
1029 if let Some(JsObj::Object(p)) = h.get(obj) {
1030 for k in keys {
1031 if let Some(v) = p.get(*k) {
1032 let n = h.to_number(v);
1033 if !n.is_nan() {
1034 return n;
1035 }
1036 }
1037 }
1038 }
1039 default
1040 })
1041}
1042
1043fn make_cipher(tag: &str, args: &[Value]) -> Result<Value, String> {
1045 let algo = arg_str(args, 0).to_ascii_lowercase();
1046 if !CIPHERS.contains(&algo.as_str()) {
1047 return Err(crate::host::coded_error(
1050 "Error",
1051 "ERR_CRYPTO_UNKNOWN_CIPHER",
1052 "Unknown cipher",
1053 ));
1054 }
1055 let key = val_bytes_at(args, 1);
1056 let iv = val_bytes_at(args, 2);
1057 let want_key = key_len(&algo);
1058 if key.len() != want_key {
1061 return Err(crate::host::coded_error(
1062 "RangeError",
1063 "ERR_CRYPTO_INVALID_KEYLEN",
1064 "Invalid key length",
1065 ));
1066 }
1067 if iv.len() != 16 {
1068 return Err(crate::host::coded_error(
1069 "TypeError",
1070 "ERR_CRYPTO_INVALID_IV",
1071 "Invalid initialization vector",
1072 ));
1073 }
1074 Ok(with_host(|h| {
1075 let keyv = h.new_array(key.iter().map(|b| Value::Float(*b as f64)).collect());
1076 let ivv = h.new_array(iv.iter().map(|b| Value::Float(*b as f64)).collect());
1077 let data = h.new_array(Vec::new());
1078 let mut m = IndexMap::new();
1079 m.insert("@@native".into(), h.new_str(tag));
1080 m.insert("@@algo".into(), h.new_str(algo));
1081 m.insert("@@key".into(), keyv);
1082 m.insert("@@iv".into(), ivv);
1083 m.insert("@@data".into(), data);
1084 h.new_object(m)
1085 }))
1086}
1087
1088fn cipher_crypt(
1093 algo: &str,
1094 key: &[u8],
1095 iv: &[u8],
1096 data: &[u8],
1097 encrypt: bool,
1098) -> Result<Vec<u8>, String> {
1099 let keyerr = || {
1100 crate::host::coded_error(
1101 "RangeError",
1102 "ERR_CRYPTO_INVALID_KEYLEN",
1103 "Invalid key length",
1104 )
1105 };
1106 let decerr = || {
1108 crate::host::coded_error(
1109 "Error",
1110 "ERR_OSSL_BAD_DECRYPT",
1111 "error:1C800064:Provider routines::bad decrypt",
1112 )
1113 };
1114 match (algo, encrypt) {
1115 ("aes-128-cbc", true) => Ok(cbc::Encryptor::<aes::Aes128>::new_from_slices(key, iv)
1116 .map_err(|_| keyerr())?
1117 .encrypt_padded_vec_mut::<Pkcs7>(data)),
1118 ("aes-192-cbc", true) => Ok(cbc::Encryptor::<aes::Aes192>::new_from_slices(key, iv)
1119 .map_err(|_| keyerr())?
1120 .encrypt_padded_vec_mut::<Pkcs7>(data)),
1121 ("aes-256-cbc", true) => Ok(cbc::Encryptor::<aes::Aes256>::new_from_slices(key, iv)
1122 .map_err(|_| keyerr())?
1123 .encrypt_padded_vec_mut::<Pkcs7>(data)),
1124 ("aes-128-cbc", false) => cbc::Decryptor::<aes::Aes128>::new_from_slices(key, iv)
1125 .map_err(|_| keyerr())?
1126 .decrypt_padded_vec_mut::<Pkcs7>(data)
1127 .map_err(|_| decerr()),
1128 ("aes-192-cbc", false) => cbc::Decryptor::<aes::Aes192>::new_from_slices(key, iv)
1129 .map_err(|_| keyerr())?
1130 .decrypt_padded_vec_mut::<Pkcs7>(data)
1131 .map_err(|_| decerr()),
1132 ("aes-256-cbc", false) => cbc::Decryptor::<aes::Aes256>::new_from_slices(key, iv)
1133 .map_err(|_| keyerr())?
1134 .decrypt_padded_vec_mut::<Pkcs7>(data)
1135 .map_err(|_| decerr()),
1136 ("aes-128-ctr", _) => {
1137 let mut buf = data.to_vec();
1138 ctr::Ctr128BE::<aes::Aes128>::new_from_slices(key, iv)
1139 .map_err(|_| keyerr())?
1140 .apply_keystream(&mut buf);
1141 Ok(buf)
1142 }
1143 ("aes-192-ctr", _) => {
1144 let mut buf = data.to_vec();
1145 ctr::Ctr128BE::<aes::Aes192>::new_from_slices(key, iv)
1146 .map_err(|_| keyerr())?
1147 .apply_keystream(&mut buf);
1148 Ok(buf)
1149 }
1150 ("aes-256-ctr", _) => {
1151 let mut buf = data.to_vec();
1152 ctr::Ctr128BE::<aes::Aes256>::new_from_slices(key, iv)
1153 .map_err(|_| keyerr())?
1154 .apply_keystream(&mut buf);
1155 Ok(buf)
1156 }
1157 _ => Err(format!("Error: Unsupported cipher: {algo}")),
1158 }
1159}
1160
1161fn key_len(algo: &str) -> usize {
1163 if algo.starts_with("aes-128") {
1164 16
1165 } else if algo.starts_with("aes-192") {
1166 24
1167 } else {
1168 32
1169 }
1170}
1171
1172fn encode_out(bytes: &[u8], enc: Option<&str>) -> Value {
1174 match enc {
1175 Some("hex") => with_host(|h| h.new_str(to_hex(bytes))),
1176 Some("base64") | Some("base64url") => with_host(|h| h.new_str(to_base64(bytes))),
1177 Some("latin1") | Some("binary") => {
1178 with_host(|h| h.new_str(bytes.iter().map(|b| *b as char).collect::<String>()))
1179 }
1180 Some("utf8") | Some("utf-8") => {
1181 with_host(|h| h.new_str(String::from_utf8_lossy(bytes).into_owned()))
1182 }
1183 _ => super::buffer::from_bytes(bytes),
1184 }
1185}
1186
1187fn cipher_info(algo: &str) -> Result<Value, String> {
1189 if !CIPHERS.contains(&algo) {
1190 return Ok(Value::Undef);
1191 }
1192 let nid = match algo {
1193 "aes-128-cbc" => 419,
1194 "aes-192-cbc" => 423,
1195 "aes-256-cbc" => 427,
1196 "aes-128-ctr" => 904,
1197 "aes-192-ctr" => 905,
1198 _ => 906,
1199 };
1200 let (mode, block) = if algo.ends_with("ctr") {
1201 ("ctr", 1)
1202 } else {
1203 ("cbc", 16)
1204 };
1205 Ok(with_host(|h| {
1206 let mut m = IndexMap::new();
1207 m.insert("mode".into(), h.new_str(mode));
1208 m.insert("name".into(), h.new_str(algo));
1209 m.insert("nid".into(), Value::Float(nid as f64));
1210 m.insert("keyLength".into(), Value::Float(key_len(algo) as f64));
1211 m.insert("blockSize".into(), Value::Float(block as f64));
1212 m.insert("ivLength".into(), Value::Float(16.0));
1213 h.new_object(m)
1214 }))
1215}
1216
1217fn random_fill(args: &[Value]) -> Result<Value, String> {
1220 let buf = args.first().cloned().unwrap_or(Value::Undef);
1221 if super::native_tag(&buf).as_deref() != Some("Buffer") {
1222 return Err("Error: The \"buf\" argument must be a Buffer".into());
1223 }
1224 let cur = val_bytes(&buf);
1225 let len = cur.len();
1226 let offset = if args.len() > 1 {
1227 super::arg_num(args, 1).max(0.0) as usize
1228 } else {
1229 0
1230 };
1231 let offset = offset.min(len);
1232 let size = if args.len() > 2 {
1233 super::arg_num(args, 2).max(0.0) as usize
1234 } else {
1235 len - offset
1236 };
1237 let end = (offset + size).min(len);
1238 let mut rnd = vec![0u8; end.saturating_sub(offset)];
1239 if let Err(e) = getrandom::getrandom(&mut rnd) {
1240 return Err(format!("Error: failed to generate random bytes: {e}"));
1241 }
1242 let mut out = cur;
1243 out[offset..end].copy_from_slice(&rnd);
1244 with_host(|h| {
1245 let arr = match h.get(&buf) {
1246 Some(JsObj::Object(p)) => p.get("@@bytes").cloned(),
1247 _ => None,
1248 };
1249 if let Some(a) = arr {
1250 if let Some(JsObj::Array(items)) = h.get_mut(&a) {
1251 *items = out.iter().map(|b| Value::Float(*b as f64)).collect();
1252 }
1253 }
1254 });
1255 Ok(buf)
1256}
1257
1258fn uuid_v7() -> Result<Value, String> {
1261 let ms = std::time::SystemTime::now()
1262 .duration_since(std::time::UNIX_EPOCH)
1263 .map(|d| d.as_millis() as u64)
1264 .unwrap_or(0);
1265 let mut b = [0u8; 16];
1266 if let Err(e) = getrandom::getrandom(&mut b) {
1267 return Err(format!("Error: failed to generate random bytes: {e}"));
1268 }
1269 b[0..6].copy_from_slice(&ms.to_be_bytes()[2..8]);
1270 b[6] = (b[6] & 0x0f) | 0x70;
1271 b[8] = (b[8] & 0x3f) | 0x80;
1272 let h = to_hex(&b);
1273 let uuid = format!(
1274 "{}-{}-{}-{}-{}",
1275 &h[0..8],
1276 &h[8..12],
1277 &h[12..16],
1278 &h[16..20],
1279 &h[20..32]
1280 );
1281 Ok(with_host(|host| host.new_str(uuid)))
1282}
1283
1284fn random_below(range: u64) -> Result<u64, getrandom::Error> {
1287 let limit = u64::MAX - (u64::MAX % range);
1289 loop {
1290 let mut b = [0u8; 8];
1291 getrandom::getrandom(&mut b)?;
1292 let n = u64::from_le_bytes(b);
1293 if n < limit {
1294 return Ok(n % range);
1295 }
1296 }
1297}
1298
1299fn decode(s: &str, enc: &str) -> Vec<u8> {
1300 match enc.to_ascii_lowercase().as_str() {
1301 "hex" => super::from_hex(s),
1302 "base64" | "base64url" => super::from_base64(s),
1303 "ascii" | "latin1" | "binary" => s.chars().map(|c| c as u8).collect(),
1304 _ => s.as_bytes().to_vec(),
1305 }
1306}
1307
1308fn key_object(kind: &str, asym: &str, pem: &str) -> Value {
1321 let class = if kind == "private" {
1322 "PrivateKeyObject"
1323 } else {
1324 "PublicKeyObject"
1325 };
1326 with_host(|h| {
1327 let mut m = IndexMap::new();
1328 m.insert("@@native".into(), h.new_str(class));
1329 m.insert("@@type".into(), h.new_str(kind));
1330 m.insert("@@asymmetricKeyType".into(), h.new_str(asym));
1331 m.insert("@@pem".into(), h.new_str(pem));
1332 h.new_object(m)
1333 })
1334}
1335
1336fn is_key_object(v: &Value) -> bool {
1338 matches!(
1339 super::native_tag(v).as_deref(),
1340 Some("KeyObject" | "SecretKeyObject" | "PublicKeyObject" | "PrivateKeyObject")
1341 )
1342}
1343
1344fn secret_key_object(bytes: &[u8]) -> Value {
1346 with_host(|h| {
1347 let arr = h.new_array(bytes.iter().map(|b| Value::Float(*b as f64)).collect());
1348 let mut m = IndexMap::new();
1349 m.insert("@@native".into(), h.new_str("SecretKeyObject"));
1350 m.insert("@@type".into(), h.new_str("secret"));
1351 m.insert("@@secret".into(), arr);
1352 h.new_object(m)
1353 })
1354}
1355
1356fn pem_wrap(label: &str, der: &[u8]) -> String {
1358 let b64 = to_base64(der);
1359 let mut s = format!("-----BEGIN {label}-----\n");
1360 for chunk in b64.as_bytes().chunks(64) {
1361 s.push_str(std::str::from_utf8(chunk).unwrap_or_default());
1362 s.push('\n');
1363 }
1364 s.push_str(&format!("-----END {label}-----\n"));
1365 s
1366}
1367
1368fn pem_body(pem: &str) -> Vec<u8> {
1370 let body: String = pem.lines().filter(|l| !l.starts_with("-----")).collect();
1371 super::from_base64(&body)
1372}
1373
1374fn x25519_private_pem(raw: &[u8]) -> String {
1376 let mut der = vec![
1377 0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x04, 0x22, 0x04,
1378 0x20,
1379 ];
1380 der.extend_from_slice(raw);
1381 pem_wrap("PRIVATE KEY", &der)
1382}
1383
1384fn x25519_public_pem(raw: &[u8]) -> String {
1386 let mut der = vec![
1387 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x03, 0x21, 0x00,
1388 ];
1389 der.extend_from_slice(raw);
1390 pem_wrap("PUBLIC KEY", &der)
1391}
1392
1393fn x25519_raw(pem: &str) -> Option<[u8; 32]> {
1395 let der = pem_body(pem);
1396 if der.len() < 32 {
1397 return None;
1398 }
1399 let mut out = [0u8; 32];
1400 out.copy_from_slice(&der[der.len() - 32..]);
1401 Some(out)
1402}
1403
1404fn keygen_encoding(opts: Option<&Value>, priv_side: bool) -> Option<String> {
1406 let o = opts?;
1407 let field = if priv_side {
1408 "privateKeyEncoding"
1409 } else {
1410 "publicKeyEncoding"
1411 };
1412 with_host(|h| {
1413 let JsObj::Object(p) = h.get(o)? else {
1414 return None;
1415 };
1416 let enc = p.get(field)?;
1417 let JsObj::Object(e) = h.get(enc)? else {
1418 return None;
1419 };
1420 e.get("format").map(|v| h.str_of(v))
1421 })
1422}
1423
1424fn generate_key_pair(kind: &str, opts: Option<&Value>) -> Result<Value, String> {
1428 let mut rng = rand_core::OsRng;
1429 let (asym, priv_pem, pub_pem) = match kind {
1430 "rsa" => {
1431 let bits = opt_num(opts.unwrap_or(&Value::Undef), &["modulusLength"], 2048.0) as usize;
1432 let sk = rsa::RsaPrivateKey::new(&mut rng, bits).map_err(|e| format!("Error: {e}"))?;
1433 let pk = rsa::RsaPublicKey::from(&sk);
1434 let priv_pem = sk
1435 .to_pkcs8_pem(LineEnding::LF)
1436 .map_err(|e| format!("Error: {e}"))?
1437 .to_string();
1438 let pub_pem = pk
1439 .to_public_key_pem(LineEnding::LF)
1440 .map_err(|e| format!("Error: {e}"))?;
1441 ("rsa", priv_pem, pub_pem)
1442 }
1443 "ec" => {
1444 let curve = opt_str(opts.unwrap_or(&Value::Undef), "namedCurve");
1445 match ec_curve_id(&curve) {
1446 Some("p256") => {
1447 let sk = p256::SecretKey::random(&mut rng);
1448 let priv_pem = sk
1449 .to_pkcs8_pem(LineEnding::LF)
1450 .map_err(|e| format!("Error: {e}"))?
1451 .to_string();
1452 let pub_pem = sk
1453 .public_key()
1454 .to_public_key_pem(LineEnding::LF)
1455 .map_err(|e| format!("Error: {e}"))?;
1456 ("ec", priv_pem, pub_pem)
1457 }
1458 Some("p384") => {
1459 let sk = p384::SecretKey::random(&mut rng);
1460 let priv_pem = sk
1461 .to_pkcs8_pem(LineEnding::LF)
1462 .map_err(|e| format!("Error: {e}"))?
1463 .to_string();
1464 let pub_pem = sk
1465 .public_key()
1466 .to_public_key_pem(LineEnding::LF)
1467 .map_err(|e| format!("Error: {e}"))?;
1468 ("ec", priv_pem, pub_pem)
1469 }
1470 _ => return Err(format!("Error: Unsupported EC curve: {curve}")),
1471 }
1472 }
1473 "ed25519" => {
1474 let sk = ed25519_dalek::SigningKey::generate(&mut rng);
1475 let priv_pem = sk
1476 .to_pkcs8_pem(LineEnding::LF)
1477 .map_err(|e| format!("Error: {e}"))?
1478 .to_string();
1479 let pub_pem = sk
1480 .verifying_key()
1481 .to_public_key_pem(LineEnding::LF)
1482 .map_err(|e| format!("Error: {e}"))?;
1483 ("ed25519", priv_pem, pub_pem)
1484 }
1485 "x25519" => {
1486 let sk = x25519_dalek::StaticSecret::random_from_rng(rng);
1487 let pk = x25519_dalek::PublicKey::from(&sk);
1488 (
1489 "x25519",
1490 x25519_private_pem(&sk.to_bytes()),
1491 x25519_public_pem(pk.as_bytes()),
1492 )
1493 }
1494 _ => return Err(format!("Error: Unsupported key type: {kind}")),
1495 };
1496 let pub_is_pem = keygen_encoding(opts, false).as_deref() == Some("pem");
1497 let priv_is_pem = keygen_encoding(opts, true).as_deref() == Some("pem");
1498 let publik = if pub_is_pem {
1499 with_host(|h| h.new_str(pub_pem.clone()))
1500 } else {
1501 key_object("public", asym, &pub_pem)
1502 };
1503 let privat = if priv_is_pem {
1504 with_host(|h| h.new_str(priv_pem.clone()))
1505 } else {
1506 key_object("private", asym, &priv_pem)
1507 };
1508 Ok(with_host(|h| {
1509 let mut m = IndexMap::new();
1510 m.insert("publicKey".into(), publik);
1511 m.insert("privateKey".into(), privat);
1512 h.new_object(m)
1513 }))
1514}
1515
1516fn ec_curve_id(name: &str) -> Option<&'static str> {
1518 match name {
1519 "P-256" | "prime256v1" | "secp256r1" => Some("p256"),
1520 "P-384" | "secp384r1" => Some("p384"),
1521 _ => None,
1522 }
1523}
1524
1525fn opt_str(obj: &Value, key: &str) -> String {
1527 with_host(|h| match h.get(obj) {
1528 Some(JsObj::Object(p)) => p.get(key).map(|v| h.str_of(v)).unwrap_or_default(),
1529 _ => String::new(),
1530 })
1531}
1532
1533fn detect_private(bytes: &[u8]) -> Option<&'static str> {
1535 let pem = std::str::from_utf8(bytes).ok();
1536 if pem
1537 .map(|p| {
1538 rsa::RsaPrivateKey::from_pkcs8_pem(p).is_ok()
1539 || rsa::RsaPrivateKey::from_pkcs1_pem(p).is_ok()
1540 })
1541 .unwrap_or(false)
1542 || rsa::RsaPrivateKey::from_pkcs8_der(bytes).is_ok()
1543 {
1544 return Some("rsa");
1545 }
1546 if pem
1547 .map(|p| p256::SecretKey::from_pkcs8_pem(p).is_ok())
1548 .unwrap_or(false)
1549 {
1550 return Some("ec");
1551 }
1552 if pem
1553 .map(|p| p384::SecretKey::from_pkcs8_pem(p).is_ok())
1554 .unwrap_or(false)
1555 {
1556 return Some("ec");
1557 }
1558 if pem
1559 .map(|p| ed25519_dalek::SigningKey::from_pkcs8_pem(p).is_ok())
1560 .unwrap_or(false)
1561 {
1562 return Some("ed25519");
1563 }
1564 if pem.map(|p| p.contains("PRIVATE KEY")).unwrap_or(false)
1565 && x25519_raw(pem.unwrap_or("")).is_some()
1566 {
1567 let der = pem_body(pem.unwrap_or(""));
1569 if der.len() == 48 && der[9..12] == [0x2b, 0x65, 0x6e] {
1570 return Some("x25519");
1571 }
1572 }
1573 None
1574}
1575
1576fn detect_public(bytes: &[u8]) -> Option<&'static str> {
1578 let pem = std::str::from_utf8(bytes).ok();
1579 if pem
1580 .map(|p| rsa::RsaPublicKey::from_public_key_pem(p).is_ok())
1581 .unwrap_or(false)
1582 {
1583 return Some("rsa");
1584 }
1585 if pem
1586 .map(|p| p256::PublicKey::from_public_key_pem(p).is_ok())
1587 .unwrap_or(false)
1588 {
1589 return Some("ec");
1590 }
1591 if pem
1592 .map(|p| p384::PublicKey::from_public_key_pem(p).is_ok())
1593 .unwrap_or(false)
1594 {
1595 return Some("ec");
1596 }
1597 if pem
1598 .map(|p| ed25519_dalek::VerifyingKey::from_public_key_pem(p).is_ok())
1599 .unwrap_or(false)
1600 {
1601 return Some("ed25519");
1602 }
1603 if let Some(p) = pem {
1604 let der = pem_body(p);
1605 if der.len() == 44 && der[6..9] == [0x2b, 0x65, 0x6e] {
1606 return Some("x25519");
1607 }
1608 }
1609 None
1610}
1611
1612fn create_private_key(input: Option<&Value>) -> Result<Value, String> {
1614 let bytes = input.map(key_material).unwrap_or_default();
1615 let asym = detect_private(&bytes).ok_or("Error: Failed to read private key")?;
1616 let pem = String::from_utf8_lossy(&bytes).into_owned();
1617 Ok(key_object("private", asym, &pem))
1618}
1619
1620fn create_public_key(input: Option<&Value>) -> Result<Value, String> {
1623 let bytes = input.map(key_material).unwrap_or_default();
1624 if let Some(asym) = detect_public(&bytes) {
1625 let pem = String::from_utf8_lossy(&bytes).into_owned();
1626 return Ok(key_object("public", asym, &pem));
1627 }
1628 if let Some(asym) = detect_private(&bytes) {
1630 let pem = public_pem_from_private(&bytes, asym)?;
1631 return Ok(key_object("public", asym, &pem));
1632 }
1633 Err("Error: Failed to read public key".into())
1634}
1635
1636fn public_pem_from_private(bytes: &[u8], asym: &str) -> Result<String, String> {
1638 let pem = std::str::from_utf8(bytes).ok();
1639 let err = || "Error: Failed to derive public key".to_string();
1640 match asym {
1641 "rsa" => {
1642 let sk = pem
1643 .and_then(|p| rsa::RsaPrivateKey::from_pkcs8_pem(p).ok())
1644 .or_else(|| rsa::RsaPrivateKey::from_pkcs8_der(bytes).ok())
1645 .ok_or_else(err)?;
1646 rsa::RsaPublicKey::from(&sk)
1647 .to_public_key_pem(LineEnding::LF)
1648 .map_err(|e| format!("Error: {e}"))
1649 }
1650 "ec" => {
1651 if let Some(sk) = pem.and_then(|p| p256::SecretKey::from_pkcs8_pem(p).ok()) {
1652 return sk
1653 .public_key()
1654 .to_public_key_pem(LineEnding::LF)
1655 .map_err(|e| format!("Error: {e}"));
1656 }
1657 let sk = pem
1658 .and_then(|p| p384::SecretKey::from_pkcs8_pem(p).ok())
1659 .ok_or_else(err)?;
1660 sk.public_key()
1661 .to_public_key_pem(LineEnding::LF)
1662 .map_err(|e| format!("Error: {e}"))
1663 }
1664 "ed25519" => {
1665 let sk = pem
1666 .and_then(|p| ed25519_dalek::SigningKey::from_pkcs8_pem(p).ok())
1667 .ok_or_else(err)?;
1668 sk.verifying_key()
1669 .to_public_key_pem(LineEnding::LF)
1670 .map_err(|e| format!("Error: {e}"))
1671 }
1672 "x25519" => {
1673 let raw = pem.and_then(x25519_raw).ok_or_else(err)?;
1674 let sk = x25519_dalek::StaticSecret::from(raw);
1675 Ok(x25519_public_pem(
1676 x25519_dalek::PublicKey::from(&sk).as_bytes(),
1677 ))
1678 }
1679 _ => Err(err()),
1680 }
1681}
1682
1683fn key_material(v: &Value) -> Vec<u8> {
1686 if is_key_object(v) {
1687 return with_host(|h| match h.get(v) {
1688 Some(JsObj::Object(p)) => p.get("@@pem").map(|s| h.str_of(s)).unwrap_or_default(),
1689 _ => String::new(),
1690 })
1691 .into_bytes();
1692 }
1693 if super::native_tag(v).as_deref() != Some("Buffer") {
1694 let inner = with_host(|h| match h.get(v) {
1695 Some(JsObj::Object(p)) => p.get("key").cloned(),
1696 _ => None,
1697 });
1698 if let Some(k) = inner {
1699 return key_material(&k);
1700 }
1701 }
1702 val_bytes(v)
1703}
1704
1705fn new_sign_verify(tag: &str, algo: &str) -> Value {
1708 with_host(|h| {
1709 let data = h.new_array(Vec::new());
1710 let mut m = IndexMap::new();
1711 m.insert("@@native".into(), h.new_str(tag));
1712 m.insert("@@algo".into(), h.new_str(algo.to_ascii_lowercase()));
1713 m.insert("@@data".into(), data);
1714 h.new_object(m)
1715 })
1716}
1717
1718fn digest_of(algo: &str) -> String {
1720 let a = algo.to_ascii_lowercase();
1721 let a = a.strip_prefix("rsa-").unwrap_or(&a);
1722 a.replace('-', "")
1723}
1724
1725fn sign_data(key: &[u8], algo: &str, data: &[u8]) -> Result<Vec<u8>, String> {
1727 let pem = std::str::from_utf8(key).ok();
1728 let d = digest_of(algo);
1729 if let Some(sk) = pem
1730 .and_then(|p| rsa::RsaPrivateKey::from_pkcs8_pem(p).ok())
1731 .or_else(|| pem.and_then(|p| rsa::RsaPrivateKey::from_pkcs1_pem(p).ok()))
1732 .or_else(|| rsa::RsaPrivateKey::from_pkcs8_der(key).ok())
1733 {
1734 return rsa_sign(&sk, &d, data);
1735 }
1736 if let Some(sk) = pem.and_then(|p| p256::ecdsa::SigningKey::from_pkcs8_pem(p).ok()) {
1737 let sig: p256::ecdsa::Signature = sk.try_sign(data).map_err(|e| format!("Error: {e}"))?;
1738 return Ok(sig.to_der().as_bytes().to_vec());
1739 }
1740 if let Some(sk) = pem.and_then(|p| p384::ecdsa::SigningKey::from_pkcs8_pem(p).ok()) {
1741 let sig: p384::ecdsa::Signature = sk.try_sign(data).map_err(|e| format!("Error: {e}"))?;
1742 return Ok(sig.to_der().as_bytes().to_vec());
1743 }
1744 if let Some(sk) = pem.and_then(|p| ed25519_dalek::SigningKey::from_pkcs8_pem(p).ok()) {
1745 return Ok(sk.sign(data).to_bytes().to_vec());
1746 }
1747 Err("Error: Invalid or unsupported private key for signing".into())
1748}
1749
1750fn rsa_sign(sk: &rsa::RsaPrivateKey, digest: &str, data: &[u8]) -> Result<Vec<u8>, String> {
1752 let sig = match digest {
1753 "sha256" => rsa::pkcs1v15::SigningKey::<Sha256>::new(sk.clone())
1754 .sign(data)
1755 .to_vec(),
1756 "sha384" => rsa::pkcs1v15::SigningKey::<Sha384>::new(sk.clone())
1757 .sign(data)
1758 .to_vec(),
1759 "sha512" => rsa::pkcs1v15::SigningKey::<Sha512>::new(sk.clone())
1760 .sign(data)
1761 .to_vec(),
1762 _ => {
1763 return Err(format!(
1764 "Error: Unsupported digest for RSA signing: {digest}"
1765 ))
1766 }
1767 };
1768 Ok(sig)
1769}
1770
1771fn verify_data(key: &[u8], algo: &str, data: &[u8], sig: &[u8]) -> Result<bool, String> {
1773 let pem = std::str::from_utf8(key).ok();
1774 let d = digest_of(algo);
1775 if let Some(pk) = pem
1776 .and_then(|p| rsa::RsaPublicKey::from_public_key_pem(p).ok())
1777 .or_else(|| pem.and_then(|p| rsa::RsaPublicKey::from_pkcs1_pem(p).ok()))
1778 .or_else(|| {
1779 pem.and_then(|p| rsa::RsaPrivateKey::from_pkcs8_pem(p).ok())
1780 .map(|s| rsa::RsaPublicKey::from(&s))
1781 })
1782 {
1783 return rsa_verify(&pk, &d, data, sig);
1784 }
1785 if let Some(vk) = pem
1786 .and_then(|p| p256::ecdsa::VerifyingKey::from_public_key_pem(p).ok())
1787 .or_else(|| {
1788 pem.and_then(|p| p256::ecdsa::SigningKey::from_pkcs8_pem(p).ok())
1789 .map(|s| *s.verifying_key())
1790 })
1791 {
1792 let s = p256::ecdsa::Signature::from_der(sig).map_err(|e| format!("Error: {e}"))?;
1793 return Ok(vk.verify(data, &s).is_ok());
1794 }
1795 if let Some(vk) = pem
1796 .and_then(|p| p384::ecdsa::VerifyingKey::from_public_key_pem(p).ok())
1797 .or_else(|| {
1798 pem.and_then(|p| p384::ecdsa::SigningKey::from_pkcs8_pem(p).ok())
1799 .map(|s| *s.verifying_key())
1800 })
1801 {
1802 let s = p384::ecdsa::Signature::from_der(sig).map_err(|e| format!("Error: {e}"))?;
1803 return Ok(vk.verify(data, &s).is_ok());
1804 }
1805 if let Some(vk) = pem
1806 .and_then(|p| ed25519_dalek::VerifyingKey::from_public_key_pem(p).ok())
1807 .or_else(|| {
1808 pem.and_then(|p| ed25519_dalek::SigningKey::from_pkcs8_pem(p).ok())
1809 .map(|s| s.verifying_key())
1810 })
1811 {
1812 let s = ed25519_dalek::Signature::from_slice(sig).map_err(|e| format!("Error: {e}"))?;
1813 return Ok(vk.verify(data, &s).is_ok());
1814 }
1815 Err("Error: Invalid or unsupported public key for verifying".into())
1816}
1817
1818fn rsa_verify(
1820 pk: &rsa::RsaPublicKey,
1821 digest: &str,
1822 data: &[u8],
1823 sig: &[u8],
1824) -> Result<bool, String> {
1825 let signature = match rsa::pkcs1v15::Signature::try_from(sig) {
1826 Ok(s) => s,
1827 Err(_) => return Ok(false),
1828 };
1829 let ok = match digest {
1830 "sha256" => rsa::pkcs1v15::VerifyingKey::<Sha256>::new(pk.clone())
1831 .verify(data, &signature)
1832 .is_ok(),
1833 "sha384" => rsa::pkcs1v15::VerifyingKey::<Sha384>::new(pk.clone())
1834 .verify(data, &signature)
1835 .is_ok(),
1836 "sha512" => rsa::pkcs1v15::VerifyingKey::<Sha512>::new(pk.clone())
1837 .verify(data, &signature)
1838 .is_ok(),
1839 _ => {
1840 return Err(format!(
1841 "Error: Unsupported digest for RSA verifying: {digest}"
1842 ))
1843 }
1844 };
1845 Ok(ok)
1846}
1847
1848pub fn sign_verify_instance_call(
1850 tag: &str,
1851 recv: &Value,
1852 method: &str,
1853 args: &[Value],
1854) -> Result<Value, String> {
1855 match method {
1856 "update" => {
1857 let enc = if args.len() > 1 {
1858 arg_str(args, 1)
1859 } else {
1860 "utf8".into()
1861 };
1862 let bytes = update_bytes(args, &enc)?;
1868 with_host(|h| {
1869 if let Some(JsObj::Object(p)) = h.get(recv).cloned() {
1870 if let Some(arr) = p.get("@@data").cloned() {
1871 if let Some(JsObj::Array(items)) = h.get_mut(&arr) {
1872 items.extend(bytes.iter().map(|b| Value::Float(*b as f64)));
1873 }
1874 }
1875 }
1876 });
1877 Ok(recv.clone())
1878 }
1879 "sign" => {
1880 let (algo, data) = sign_verify_state(recv);
1881 let key = key_material(args.first().unwrap_or(&Value::Undef));
1882 let sig = sign_data(&key, &algo, &data)?;
1883 let out_enc = if args.len() > 1 {
1884 Some(arg_str(args, 1))
1885 } else {
1886 None
1887 };
1888 Ok(encode_out(&sig, out_enc.as_deref()))
1889 }
1890 "verify" => {
1891 let (algo, data) = sign_verify_state(recv);
1892 let key = key_material(args.first().unwrap_or(&Value::Undef));
1893 let sig = if args.len() > 2 {
1894 decode(&arg_str(args, 1), &arg_str(args, 2))
1895 } else {
1896 val_bytes_at(args, 1)
1897 };
1898 Ok(Value::Bool(verify_data(&key, &algo, &data, &sig)?))
1899 }
1900 _ => Err(crate::host::type_error(&format!(
1901 "{}.{method} is not a function",
1902 tag.to_ascii_lowercase()
1903 ))),
1904 }
1905}
1906
1907fn sign_verify_state(recv: &Value) -> (String, Vec<u8>) {
1909 with_host(|h| {
1910 let (mut algo, mut data) = (String::new(), Vec::new());
1911 if let Some(JsObj::Object(p)) = h.get(recv) {
1912 algo = p.get("@@algo").map(|v| h.str_of(v)).unwrap_or_default();
1913 if let Some(JsObj::Array(items)) = p.get("@@data").and_then(|v| h.get(v)) {
1914 data = items.iter().map(|v| h.to_number(v) as u8).collect();
1915 }
1916 }
1917 (algo, data)
1918 })
1919}
1920
1921fn rsa_padding(v: &Value) -> (i64, String) {
1923 let padding = opt_num(v, &["padding"], 4.0) as i64; let oaep = {
1925 let h = opt_str(v, "oaepHash");
1926 if h.is_empty() {
1927 "sha1".to_string()
1928 } else {
1929 h.to_ascii_lowercase()
1930 }
1931 };
1932 (padding, oaep)
1933}
1934
1935fn parse_rsa_public(key: &[u8]) -> Result<rsa::RsaPublicKey, String> {
1937 let pem = std::str::from_utf8(key).ok();
1938 pem.and_then(|p| rsa::RsaPublicKey::from_public_key_pem(p).ok())
1939 .or_else(|| pem.and_then(|p| rsa::RsaPublicKey::from_pkcs1_pem(p).ok()))
1940 .or_else(|| rsa::RsaPublicKey::from_public_key_der(key).ok())
1941 .or_else(|| {
1942 pem.and_then(|p| rsa::RsaPrivateKey::from_pkcs8_pem(p).ok())
1943 .map(|s| rsa::RsaPublicKey::from(&s))
1944 })
1945 .ok_or_else(|| "Error: Failed to parse RSA public key".into())
1946}
1947
1948fn parse_rsa_private(key: &[u8]) -> Result<rsa::RsaPrivateKey, String> {
1950 let pem = std::str::from_utf8(key).ok();
1951 pem.and_then(|p| rsa::RsaPrivateKey::from_pkcs8_pem(p).ok())
1952 .or_else(|| pem.and_then(|p| rsa::RsaPrivateKey::from_pkcs1_pem(p).ok()))
1953 .or_else(|| rsa::RsaPrivateKey::from_pkcs8_der(key).ok())
1954 .ok_or_else(|| "Error: Failed to parse RSA private key".into())
1955}
1956
1957fn rsa_public_op(args: &[Value], _public: bool, encrypt: bool) -> Result<Value, String> {
1960 let key_arg = args.first().cloned().unwrap_or(Value::Undef);
1961 let key = key_material(&key_arg);
1962 let (padding, oaep) = rsa_padding(&key_arg);
1963 let data = val_bytes_at(args, 1);
1964 let out = if encrypt {
1965 let pk = parse_rsa_public(&key)?;
1966 let mut rng = rand_core::OsRng;
1967 if padding == 1 {
1968 pk.encrypt(&mut rng, rsa::Pkcs1v15Encrypt, &data)
1969 } else if oaep == "sha256" {
1970 pk.encrypt(&mut rng, rsa::Oaep::new::<Sha256>(), &data)
1971 } else {
1972 pk.encrypt(&mut rng, rsa::Oaep::new::<Sha1>(), &data)
1973 }
1974 .map_err(|e| format!("Error: {e}"))?
1975 } else {
1976 let sk = parse_rsa_private(&key)?;
1977 if padding == 1 {
1978 sk.decrypt(rsa::Pkcs1v15Encrypt, &data)
1979 } else if oaep == "sha256" {
1980 sk.decrypt(rsa::Oaep::new::<Sha256>(), &data)
1981 } else {
1982 sk.decrypt(rsa::Oaep::new::<Sha1>(), &data)
1983 }
1984 .map_err(|e| format!("Error: {e}"))?
1985 };
1986 Ok(super::buffer::from_bytes(&out))
1987}
1988
1989fn rsa_private_encrypt(args: &[Value]) -> Result<Value, String> {
1992 let key = key_material(args.first().unwrap_or(&Value::Undef));
1993 let data = val_bytes_at(args, 1);
1994 let sk = parse_rsa_private(&key)?;
1995 let out = sk
1996 .sign(rsa::Pkcs1v15Sign::new_unprefixed(), &data)
1997 .map_err(|e| format!("Error: {e}"))?;
1998 Ok(super::buffer::from_bytes(&out))
1999}
2000
2001fn rsa_public_decrypt(args: &[Value]) -> Result<Value, String> {
2004 use rsa::traits::PublicKeyParts;
2005 let key = key_material(args.first().unwrap_or(&Value::Undef));
2006 let ct = val_bytes_at(args, 1);
2007 let pk = parse_rsa_public(&key)?;
2008 let n = BigUint::from_bytes_be(&pk.n().to_bytes_be());
2009 let e = BigUint::from_bytes_be(&pk.e().to_bytes_be());
2010 let k = pk.n().to_bytes_be().len();
2011 let s = BigUint::from_bytes_be(&ct);
2012 let m = s.modpow(&e, &n);
2013 let mut em = m.to_bytes_be();
2014 while em.len() < k {
2015 em.insert(0, 0);
2016 }
2017 if em.len() < 11 || em[0] != 0x00 || em[1] != 0x01 {
2019 return Err("Error: error:0200006E:rsa routines::padding check failed".into());
2020 }
2021 let sep = em[2..].iter().position(|&b| b == 0x00).map(|i| i + 2);
2022 match sep {
2023 Some(i) => Ok(super::buffer::from_bytes(&em[i + 1..])),
2024 None => Err("Error: error:0200006E:rsa routines::padding check failed".into()),
2025 }
2026}
2027
2028const MODP_GROUPS: &[(&str, &str)] = &[
2032 ("modp1", MODP1),
2033 ("modp2", MODP2),
2034 ("modp5", MODP5),
2035 ("modp14", MODP14),
2036 ("modp15", MODP15),
2037 ("modp16", MODP16),
2038 ("modp17", MODP17),
2039 ("modp18", MODP18),
2040];
2041
2042fn obj_bytes(recv: &Value, key: &str) -> Vec<u8> {
2044 with_host(|h| {
2045 if let Some(JsObj::Object(p)) = h.get(recv) {
2046 if let Some(JsObj::Array(it)) = p.get(key).and_then(|v| h.get(v)) {
2047 return it.iter().map(|v| h.to_number(v) as u8).collect();
2048 }
2049 }
2050 Vec::new()
2051 })
2052}
2053
2054fn set_obj_bytes(recv: &Value, key: &str, bytes: &[u8]) {
2056 with_host(|h| {
2057 let arr = h.new_array(bytes.iter().map(|b| Value::Float(*b as f64)).collect());
2058 if let Some(JsObj::Object(p)) = h.get_mut(recv) {
2059 p.insert(key.to_string(), arr);
2060 }
2061 });
2062}
2063
2064fn dh_object(prime: &[u8], gen: &[u8]) -> Value {
2066 with_host(|h| {
2067 let pv = h.new_array(prime.iter().map(|b| Value::Float(*b as f64)).collect());
2068 let gv = h.new_array(gen.iter().map(|b| Value::Float(*b as f64)).collect());
2069 let mut m = IndexMap::new();
2070 m.insert("@@native".into(), h.new_str("DiffieHellman"));
2071 m.insert("@@prime".into(), pv);
2072 m.insert("@@gen".into(), gv);
2073 h.new_object(m)
2074 })
2075}
2076
2077fn create_diffie_hellman(args: &[Value]) -> Result<Value, String> {
2079 let first = args.first().cloned().unwrap_or(Value::Undef);
2081 if matches!(first, Value::Int(_) | Value::Float(_)) {
2082 let bits = super::arg_num(args, 0) as usize;
2083 let prime = gen_prime(bits)?;
2084 return Ok(dh_object(&prime.to_bytes_be(), &[2]));
2085 }
2086 let prime = val_bytes_at(args, 0);
2087 let gen = if args.len() > 1 {
2088 match args.get(1) {
2089 Some(Value::Int(_)) | Some(Value::Float(_)) => {
2090 let g = super::arg_num(args, 1) as u64;
2091 BigUint::from(g).to_bytes_be()
2092 }
2093 _ => val_bytes_at(args, 1),
2094 }
2095 } else {
2096 vec![2]
2097 };
2098 Ok(dh_object(&prime, &gen))
2099}
2100
2101fn diffie_hellman_group(name: &str) -> Result<Value, String> {
2103 let hex = MODP_GROUPS
2104 .iter()
2105 .find(|(n, _)| *n == name)
2106 .map(|(_, h)| *h)
2107 .ok_or_else(|| format!("Error: Unknown group: {name}"))?;
2108 Ok(dh_object(&super::from_hex(hex), &[2]))
2109}
2110
2111pub fn dh_instance_call(recv: &Value, method: &str, args: &[Value]) -> Result<Value, String> {
2113 let enc = |args: &[Value], i: usize| -> Option<String> {
2114 if args.len() > i {
2115 let s = arg_str(args, i);
2116 if s.is_empty() {
2117 None
2118 } else {
2119 Some(s)
2120 }
2121 } else {
2122 None
2123 }
2124 };
2125 match method {
2126 "generateKeys" => {
2127 let p = BigUint::from_bytes_be(&obj_bytes(recv, "@@prime"));
2128 let g = BigUint::from_bytes_be(&obj_bytes(recv, "@@gen"));
2129 let priv_key = dh_random_priv(&p)?;
2130 let pub_key = g.modpow(&priv_key, &p);
2131 set_obj_bytes(recv, "@@priv", &priv_key.to_bytes_be());
2132 set_obj_bytes(recv, "@@pub", &pub_key.to_bytes_be());
2133 Ok(encode_out(&pub_key.to_bytes_be(), enc(args, 0).as_deref()))
2134 }
2135 "computeSecret" => {
2136 let other = if args.len() > 1
2137 && !arg_str(args, 1).is_empty()
2138 && !matches!(args.first(), Some(v) if super::native_tag(v).as_deref() == Some("Buffer"))
2139 {
2140 decode(&arg_str(args, 0), &arg_str(args, 1))
2141 } else {
2142 val_bytes_at(args, 0)
2143 };
2144 let p = BigUint::from_bytes_be(&obj_bytes(recv, "@@prime"));
2145 let priv_key = BigUint::from_bytes_be(&obj_bytes(recv, "@@priv"));
2146 let their_pub = BigUint::from_bytes_be(&other);
2147 let secret = their_pub.modpow(&priv_key, &p);
2148 let out_enc = if args.len() > 2 { enc(args, 2) } else { None };
2149 Ok(encode_out(&secret.to_bytes_be(), out_enc.as_deref()))
2150 }
2151 "getPrime" => Ok(encode_out(
2152 &obj_bytes(recv, "@@prime"),
2153 enc(args, 0).as_deref(),
2154 )),
2155 "getGenerator" => Ok(encode_out(
2156 &obj_bytes(recv, "@@gen"),
2157 enc(args, 0).as_deref(),
2158 )),
2159 "getPublicKey" => Ok(encode_out(
2160 &obj_bytes(recv, "@@pub"),
2161 enc(args, 0).as_deref(),
2162 )),
2163 "getPrivateKey" => Ok(encode_out(
2164 &obj_bytes(recv, "@@priv"),
2165 enc(args, 0).as_deref(),
2166 )),
2167 "setPublicKey" => {
2168 set_obj_bytes(recv, "@@pub", &val_bytes_at(args, 0));
2169 Ok(recv.clone())
2170 }
2171 "setPrivateKey" => {
2172 set_obj_bytes(recv, "@@priv", &val_bytes_at(args, 0));
2173 Ok(recv.clone())
2174 }
2175 _ => Err(crate::host::type_error(&format!(
2176 "dh.{method} is not a function"
2177 ))),
2178 }
2179}
2180
2181fn dh_random_priv(p: &BigUint) -> Result<BigUint, String> {
2183 let nbytes = p.to_bytes_be().len();
2184 let mut buf = vec![0u8; nbytes];
2185 getrandom::getrandom(&mut buf).map_err(|e| format!("Error: {e}"))?;
2186 let two = BigUint::from(2u32);
2187 let modulus = p - &two; let x = BigUint::from_bytes_be(&buf) % &modulus;
2189 Ok(x + &two)
2190}
2191
2192fn create_ecdh(curve: &str) -> Result<Value, String> {
2196 let id = ec_curve_id(curve).ok_or_else(|| format!("Error: Unsupported curve: {curve}"))?;
2197 Ok(with_host(|h| {
2198 let mut m = IndexMap::new();
2199 m.insert("@@native".into(), h.new_str("ECDH"));
2200 m.insert("@@curve".into(), h.new_str(id));
2201 h.new_object(m)
2202 }))
2203}
2204
2205pub fn ecdh_instance_call(recv: &Value, method: &str, args: &[Value]) -> Result<Value, String> {
2207 let curve = obj_str(recv, "@@curve");
2208 match method {
2209 "generateKeys" => {
2210 let (priv_b, pub_b) = ecdh_generate(&curve)?;
2211 set_obj_bytes(recv, "@@priv", &priv_b);
2212 set_obj_bytes(recv, "@@pub", &pub_b);
2213 let out_enc = if args.len() > 1 {
2214 Some(arg_str(args, 1))
2215 } else {
2216 None
2217 };
2218 Ok(encode_out(&pub_b, out_enc.as_deref()))
2219 }
2220 "computeSecret" => {
2221 let other = if args.len() > 1
2222 && !arg_str(args, 1).is_empty()
2223 && super::native_tag(args.first().unwrap_or(&Value::Undef)).as_deref()
2224 != Some("Buffer")
2225 {
2226 decode(&arg_str(args, 0), &arg_str(args, 1))
2227 } else {
2228 val_bytes_at(args, 0)
2229 };
2230 let secret = ecdh_compute(&curve, &obj_bytes(recv, "@@priv"), &other)?;
2231 let out_enc = if args.len() > 2 {
2232 Some(arg_str(args, 2))
2233 } else {
2234 None
2235 };
2236 Ok(encode_out(&secret, out_enc.as_deref()))
2237 }
2238 "getPublicKey" => {
2239 let out_enc = if args.len() > 1 {
2240 Some(arg_str(args, 1))
2241 } else {
2242 None
2243 };
2244 Ok(encode_out(&obj_bytes(recv, "@@pub"), out_enc.as_deref()))
2245 }
2246 "getPrivateKey" => {
2247 let out_enc = if !args.is_empty() {
2248 Some(arg_str(args, 0))
2249 } else {
2250 None
2251 };
2252 Ok(encode_out(&obj_bytes(recv, "@@priv"), out_enc.as_deref()))
2253 }
2254 "setPrivateKey" => {
2255 let priv_b = val_bytes_at(args, 0);
2256 let pub_b = ecdh_public_from_private(&curve, &priv_b)?;
2257 set_obj_bytes(recv, "@@priv", &priv_b);
2258 set_obj_bytes(recv, "@@pub", &pub_b);
2259 Ok(recv.clone())
2260 }
2261 _ => Err(crate::host::type_error(&format!(
2262 "ecdh.{method} is not a function"
2263 ))),
2264 }
2265}
2266
2267fn ecdh_generate(curve: &str) -> Result<(Vec<u8>, Vec<u8>), String> {
2269 let mut rng = rand_core::OsRng;
2270 match curve {
2271 "p256" => {
2272 let sk = p256::SecretKey::random(&mut rng);
2273 let pubk = sk.public_key().to_encoded_point(false).as_bytes().to_vec();
2274 Ok((sk.to_bytes().to_vec(), pubk))
2275 }
2276 "p384" => {
2277 let sk = p384::SecretKey::random(&mut rng);
2278 let pubk = sk.public_key().to_encoded_point(false).as_bytes().to_vec();
2279 Ok((sk.to_bytes().to_vec(), pubk))
2280 }
2281 _ => Err(format!("Error: Unsupported curve: {curve}")),
2282 }
2283}
2284
2285fn ecdh_public_from_private(curve: &str, priv_b: &[u8]) -> Result<Vec<u8>, String> {
2287 match curve {
2288 "p256" => {
2289 let sk = p256::SecretKey::from_slice(priv_b).map_err(|e| format!("Error: {e}"))?;
2290 Ok(sk.public_key().to_encoded_point(false).as_bytes().to_vec())
2291 }
2292 "p384" => {
2293 let sk = p384::SecretKey::from_slice(priv_b).map_err(|e| format!("Error: {e}"))?;
2294 Ok(sk.public_key().to_encoded_point(false).as_bytes().to_vec())
2295 }
2296 _ => Err(format!("Error: Unsupported curve: {curve}")),
2297 }
2298}
2299
2300fn ecdh_compute(curve: &str, priv_b: &[u8], pub_b: &[u8]) -> Result<Vec<u8>, String> {
2302 match curve {
2303 "p256" => {
2304 let sk = p256::SecretKey::from_slice(priv_b).map_err(|e| format!("Error: {e}"))?;
2305 let pk = p256::PublicKey::from_sec1_bytes(pub_b).map_err(|e| format!("Error: {e}"))?;
2306 let shared = p256::ecdh::diffie_hellman(sk.to_nonzero_scalar(), pk.as_affine());
2307 Ok(shared.raw_secret_bytes().to_vec())
2308 }
2309 "p384" => {
2310 let sk = p384::SecretKey::from_slice(priv_b).map_err(|e| format!("Error: {e}"))?;
2311 let pk = p384::PublicKey::from_sec1_bytes(pub_b).map_err(|e| format!("Error: {e}"))?;
2312 let shared = p384::ecdh::diffie_hellman(sk.to_nonzero_scalar(), pk.as_affine());
2313 Ok(shared.raw_secret_bytes().to_vec())
2314 }
2315 _ => Err(format!("Error: Unsupported curve: {curve}")),
2316 }
2317}
2318
2319fn obj_str(recv: &Value, key: &str) -> String {
2321 with_host(|h| match h.get(recv) {
2322 Some(JsObj::Object(p)) => p.get(key).map(|v| h.str_of(v)).unwrap_or_default(),
2323 _ => String::new(),
2324 })
2325}
2326
2327fn diffie_hellman_oneshot(opts: Option<&Value>) -> Result<Value, String> {
2329 let o = opts.ok_or("Error: options object required")?;
2330 let priv_v = with_host(|h| match h.get(o) {
2331 Some(JsObj::Object(p)) => p.get("privateKey").cloned(),
2332 _ => None,
2333 })
2334 .ok_or("Error: privateKey required")?;
2335 let pub_v = with_host(|h| match h.get(o) {
2336 Some(JsObj::Object(p)) => p.get("publicKey").cloned(),
2337 _ => None,
2338 })
2339 .ok_or("Error: publicKey required")?;
2340 let priv_bytes = key_material(&priv_v);
2341 let pub_bytes = key_material(&pub_v);
2342 let asym = detect_private(&priv_bytes).ok_or("Error: unsupported private key")?;
2343 let priv_pem = std::str::from_utf8(&priv_bytes).ok();
2344 let pub_pem = std::str::from_utf8(&pub_bytes).ok();
2345 let secret = match asym {
2346 "ec" => {
2347 if let Some(sk) = priv_pem.and_then(|p| p256::SecretKey::from_pkcs8_pem(p).ok()) {
2348 let pk = pub_pem
2349 .and_then(|p| p256::PublicKey::from_public_key_pem(p).ok())
2350 .ok_or("Error: bad public key")?;
2351 p256::ecdh::diffie_hellman(sk.to_nonzero_scalar(), pk.as_affine())
2352 .raw_secret_bytes()
2353 .to_vec()
2354 } else {
2355 let sk = priv_pem
2356 .and_then(|p| p384::SecretKey::from_pkcs8_pem(p).ok())
2357 .ok_or("Error: bad private key")?;
2358 let pk = pub_pem
2359 .and_then(|p| p384::PublicKey::from_public_key_pem(p).ok())
2360 .ok_or("Error: bad public key")?;
2361 p384::ecdh::diffie_hellman(sk.to_nonzero_scalar(), pk.as_affine())
2362 .raw_secret_bytes()
2363 .to_vec()
2364 }
2365 }
2366 "x25519" => {
2367 let sraw = priv_pem
2368 .and_then(x25519_raw)
2369 .ok_or("Error: bad private key")?;
2370 let praw = pub_pem
2371 .and_then(x25519_raw)
2372 .ok_or("Error: bad public key")?;
2373 let sk = x25519_dalek::StaticSecret::from(sraw);
2374 let pk = x25519_dalek::PublicKey::from(praw);
2375 sk.diffie_hellman(&pk).as_bytes().to_vec()
2376 }
2377 _ => return Err("Error: diffieHellman requires EC or X25519 keys".into()),
2378 };
2379 Ok(super::buffer::from_bytes(&secret))
2380}
2381
2382fn arg_biguint(v: Option<&Value>) -> BigUint {
2386 let Some(v) = v else {
2387 return BigUint::from(0u32);
2388 };
2389 if let Some(b) = with_host(|h| match h.get(v) {
2390 Some(JsObj::BigInt(b)) => b.to_biguint(),
2391 _ => None,
2392 }) {
2393 return b;
2394 }
2395 if super::native_tag(v).as_deref() == Some("Buffer") {
2396 return BigUint::from_bytes_be(&val_bytes(v));
2397 }
2398 let n = with_host(|h| h.to_number(v));
2399 BigUint::from(n.max(0.0) as u64)
2400}
2401
2402fn check_prime(v: Option<&Value>) -> bool {
2404 let n = arg_biguint(v);
2405 num_prime::nt_funcs::is_prime(&n, None).probably()
2406}
2407
2408fn generate_prime(bits: usize, opts: Option<Value>) -> Result<Value, String> {
2410 let p = gen_prime(bits)?;
2411 let want_bigint = opts
2412 .map(|o| with_host(|h| matches!(h.get(&o), Some(JsObj::Object(m)) if m.get("bigint").map(|v| h.truthy(v)).unwrap_or(false))))
2413 .unwrap_or(false);
2414 if want_bigint {
2415 Ok(with_host(|h| {
2416 h.alloc(JsObj::BigInt(num_bigint::BigInt::from(p)))
2417 }))
2418 } else {
2419 Ok(super::buffer::from_bytes(&p.to_bytes_be()))
2422 }
2423}
2424
2425fn gen_prime(bits: usize) -> Result<BigUint, String> {
2427 if bits < 2 {
2428 return Err("Error: size must be >= 2".into());
2429 }
2430 let nbytes = bits.div_ceil(8);
2431 let mut buf = vec![0u8; nbytes];
2432 getrandom::getrandom(&mut buf).map_err(|e| format!("Error: {e}"))?;
2433 let excess = nbytes * 8 - bits;
2434 buf[0] &= 0xffu8 >> excess;
2435 buf[0] |= 0x80u8 >> excess;
2436 let last = nbytes - 1;
2437 buf[last] |= 1;
2438 let start = BigUint::from_bytes_be(&buf);
2439 num_prime::nt_funcs::next_prime(&start, None)
2440 .ok_or_else(|| "Error: prime generation failed".into())
2441}
2442
2443fn argon2_hash(algo: &str, opts: Option<&Value>) -> Result<Vec<u8>, String> {
2447 let o = opts.cloned().ok_or("Error: argon2 options required")?;
2448 let msg = prop_bytes(&o, "message");
2449 let salt = prop_bytes(&o, "nonce");
2450 let secret = prop_bytes(&o, "secret");
2451 let taglen = opt_num(&o, &["tagLength"], 32.0).max(4.0) as usize;
2452 let mem = opt_num(&o, &["memory"], 65536.0) as u32;
2453 let passes = opt_num(&o, &["passes"], 3.0) as u32;
2454 let par = opt_num(&o, &["parallelism"], 4.0) as u32;
2455 let algorithm = match algo.to_ascii_lowercase().as_str() {
2456 "argon2d" => argon2::Algorithm::Argon2d,
2457 "argon2i" => argon2::Algorithm::Argon2i,
2458 _ => argon2::Algorithm::Argon2id,
2459 };
2460 let params =
2461 argon2::Params::new(mem, passes, par, Some(taglen)).map_err(|e| format!("Error: {e}"))?;
2462 let ctx = if secret.is_empty() {
2463 argon2::Argon2::new(algorithm, argon2::Version::V0x13, params)
2464 } else {
2465 argon2::Argon2::new_with_secret(&secret, algorithm, argon2::Version::V0x13, params)
2466 .map_err(|e| format!("Error: {e}"))?
2467 };
2468 let mut out = vec![0u8; taglen];
2469 ctx.hash_password_into(&msg, &salt, &mut out)
2470 .map_err(|e| format!("Error: {e}"))?;
2471 Ok(out)
2472}
2473
2474fn prop_bytes(obj: &Value, key: &str) -> Vec<u8> {
2476 let v = with_host(|h| match h.get(obj) {
2477 Some(JsObj::Object(p)) => p.get(key).cloned(),
2478 _ => None,
2479 });
2480 v.map(|x| val_bytes(&x)).unwrap_or_default()
2481}
2482
2483fn get_random_values(v: Option<&Value>) -> Result<Value, String> {
2487 let ta = v
2488 .cloned()
2489 .ok_or("Error: argument must be an integer-type TypedArray")?;
2490 let tag = super::native_tag(&ta);
2491 if tag.as_deref() == Some("Buffer") {
2492 let len = val_bytes(&ta).len();
2493 let mut rnd = vec![0u8; len];
2494 getrandom::getrandom(&mut rnd).map_err(|e| format!("Error: {e}"))?;
2495 set_obj_bytes_named(&ta, "@@bytes", &rnd);
2496 return Ok(ta);
2497 }
2498 if tag.as_deref() != Some("TypedArray") {
2499 return Err("Error: argument must be an integer-type TypedArray".into());
2500 }
2501 let kind = obj_str(&ta, "@@kind");
2502 if kind.starts_with("Float") {
2503 return Err("Error: The provided ArrayBufferView is of type 'Float', which is not an integer array type".into());
2504 }
2505 let len = crate::stdlib::typedarray::index_len(&ta).unwrap_or(0);
2506 let bpe = match kind.as_str() {
2507 "Int16Array" | "Uint16Array" => 2,
2508 "Int32Array" | "Uint32Array" => 4,
2509 _ => 1,
2510 };
2511 let mut raw = vec![0u8; len * bpe];
2512 getrandom::getrandom(&mut raw).map_err(|e| format!("Error: {e}"))?;
2513 let elems: Vec<Value> = (0..len)
2514 .map(|i| {
2515 let mut acc: u64 = 0;
2516 for j in 0..bpe {
2517 acc |= (raw[i * bpe + j] as u64) << (8 * j);
2518 }
2519 Value::Float(ta_coerce(&kind, acc))
2520 })
2521 .collect();
2522 for (i, e) in elems.iter().enumerate() {
2525 crate::stdlib::typedarray::elem_set(&ta, &i.to_string(), e)?;
2526 }
2527 Ok(ta)
2528}
2529
2530fn ta_coerce(kind: &str, raw: u64) -> f64 {
2532 match kind {
2533 "Int8Array" => (raw as i8) as f64,
2534 "Int16Array" => (raw as i16) as f64,
2535 "Int32Array" => (raw as i32) as f64,
2536 "Uint16Array" => (raw as u16) as f64,
2537 "Uint32Array" => (raw as u32) as f64,
2538 _ => (raw as u8) as f64, }
2540}
2541
2542fn set_obj_bytes_named(recv: &Value, key: &str, bytes: &[u8]) {
2544 with_host(|h| {
2545 let arr = match h.get(recv) {
2546 Some(JsObj::Object(p)) => p.get(key).cloned(),
2547 _ => None,
2548 };
2549 if let Some(a) = arr {
2550 if let Some(JsObj::Array(items)) = h.get_mut(&a) {
2551 *items = bytes.iter().map(|b| Value::Float(*b as f64)).collect();
2552 }
2553 }
2554 });
2555}
2556
2557pub fn key_object_instance_call(
2561 recv: &Value,
2562 method: &str,
2563 args: &[Value],
2564) -> Result<Value, String> {
2565 match method {
2566 "export" => {
2567 let secret = obj_bytes(recv, "@@secret");
2569 if !secret.is_empty() {
2570 return Ok(super::buffer::from_bytes(&secret));
2571 }
2572 let pem = obj_str(recv, "@@pem");
2573 let format = args
2574 .first()
2575 .map(|o| opt_str(o, "format"))
2576 .filter(|s| !s.is_empty())
2577 .unwrap_or_else(|| "pem".into());
2578 if format == "der" {
2579 Ok(super::buffer::from_bytes(&pem_body(&pem)))
2580 } else {
2581 Ok(with_host(|h| h.new_str(pem)))
2582 }
2583 }
2584 "equals" => {
2585 let Some(other) = args.first() else {
2586 return Ok(Value::Bool(false));
2587 };
2588 let kind = |v: &Value| obj_str(v, "@@type");
2594 if kind(recv) != kind(other) {
2595 return Ok(Value::Bool(false));
2596 }
2597 let mine = obj_bytes(recv, "@@secret");
2598 if !mine.is_empty() {
2599 return Ok(Value::Bool(mine == obj_bytes(other, "@@secret")));
2600 }
2601 Ok(Value::Bool(
2602 obj_str(recv, "@@pem") == obj_str(other, "@@pem"),
2603 ))
2604 }
2605 "@get@symmetricKeySize" => {
2608 let secret = obj_bytes(recv, "@@secret");
2609 Ok(if obj_str(recv, "@@type") == "secret" {
2610 Value::Float(secret.len() as f64)
2611 } else {
2612 Value::Undef
2613 })
2614 }
2615 _ => Err(crate::host::type_error(&format!(
2616 "keyObject.{method} is not a function"
2617 ))),
2618 }
2619}
2620
2621pub fn construct_x509(args: &[Value]) -> Result<Value, String> {
2625 use x509_cert::der::{Decode, DecodePem, Encode};
2626 let bytes = val_bytes_at(args, 0);
2627 let is_pem = bytes.starts_with(b"-----BEGIN");
2628 let cert = if is_pem {
2629 x509_cert::Certificate::from_pem(&bytes).map_err(|e| format!("Error: {e}"))?
2630 } else {
2631 x509_cert::Certificate::from_der(&bytes).map_err(|e| format!("Error: {e}"))?
2632 };
2633 let der = cert.to_der().map_err(|e| format!("Error: {e}"))?;
2635 let fp = {
2636 let d = digest("sha1", &der);
2637 d.iter()
2638 .map(|b| format!("{b:02X}"))
2639 .collect::<Vec<_>>()
2640 .join(":")
2641 };
2642 let subject = x509_name_node(&cert.tbs_certificate.subject.to_string());
2643 let issuer = x509_name_node(&cert.tbs_certificate.issuer.to_string());
2644 let not_before = x509_time(&cert.tbs_certificate.validity.not_before);
2645 let not_after = x509_time(&cert.tbs_certificate.validity.not_after);
2646 let serial = cert
2647 .tbs_certificate
2648 .serial_number
2649 .as_bytes()
2650 .iter()
2651 .map(|b| format!("{b:02X}"))
2652 .collect::<String>();
2653 let spki_der = cert
2654 .tbs_certificate
2655 .subject_public_key_info
2656 .to_der()
2657 .map_err(|e| format!("Error: {e}"))?;
2658 let pub_pem = pem_wrap("PUBLIC KEY", &spki_der);
2659 let pub_key =
2660 create_public_key(Some(&with_host(|h| h.new_str(pub_pem)))).unwrap_or(Value::Undef);
2661 let cert_pem = pem_wrap("CERTIFICATE", &der);
2662 let raw = super::buffer::from_bytes(&der);
2663 Ok(with_host(|h| {
2664 let mut m = IndexMap::new();
2665 m.insert("@@native".into(), h.new_str("X509Certificate"));
2666 m.insert("subject".into(), h.new_str(subject));
2667 m.insert("issuer".into(), h.new_str(issuer));
2668 m.insert("validFrom".into(), h.new_str(not_before));
2669 m.insert("validTo".into(), h.new_str(not_after));
2670 m.insert("serialNumber".into(), h.new_str(serial));
2671 m.insert("fingerprint".into(), h.new_str(fp));
2672 m.insert("publicKey".into(), pub_key);
2673 m.insert("raw".into(), raw);
2674 m.insert("@@pem".into(), h.new_str(cert_pem));
2675 h.new_object(m)
2676 }))
2677}
2678
2679pub fn x509_instance_call(recv: &Value, method: &str, _args: &[Value]) -> Result<Value, String> {
2681 match method {
2682 "toString" => {
2685 let pem = obj_str(recv, "@@pem");
2686 Ok(with_host(|h| h.new_str(pem)))
2687 }
2688 _ => Err(crate::host::type_error(&format!(
2689 "x509Certificate.{method} is not a function"
2690 ))),
2691 }
2692}
2693
2694fn x509_name_node(rfc4514: &str) -> String {
2697 rfc4514
2698 .split(',')
2699 .map(|s| s.trim())
2700 .rev()
2701 .collect::<Vec<_>>()
2702 .join("\n")
2703}
2704
2705fn x509_time(t: &x509_cert::time::Time) -> String {
2707 const MON: [&str; 12] = [
2708 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
2709 ];
2710 let dt = t.to_date_time();
2711 let mon = MON
2712 .get(dt.month().saturating_sub(1) as usize)
2713 .copied()
2714 .unwrap_or("Jan");
2715 format!(
2716 "{} {:2} {:02}:{:02}:{:02} {} GMT",
2717 mon,
2718 dt.day(),
2719 dt.hour(),
2720 dt.minutes(),
2721 dt.seconds(),
2722 dt.year()
2723 )
2724}
2725
2726const MODP1: &str = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF";
2728const MODP2: &str = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF";
2729const MODP5: &str = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF";
2730const MODP14: &str = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF";
2731const MODP15: &str = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF";
2732const MODP16: &str = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF";
2733const MODP17: &str = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AACC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF";
2734const MODP18: &str = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AACC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD922222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC50846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E7160C980DD98EDD3DFFFFFFFFFFFFFFFFF";