char/avril

(wip) why'd you have to go and make things so complicaaaaated?

git clone https://git.t4t.associates/char/avril

Charlotte Somrearrange libs into lib and extensions into extsf4a0f5b

main
54.4 KiB1474 linesraw
1use std::io;
2
3use ed25519_dalek::Signer as _;
4use p256::elliptic_curve::sec1::ToEncodedPoint;
5use pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey, EncodePublicKey};
6use rand::RngCore;
7use rand::rngs::OsRng;
8use rsa::{
9    RsaPrivateKey, RsaPublicKey,
10    hazmat::{rsa_decrypt_and_check as rsa_decrypt_raw, rsa_encrypt as rsa_encrypt_raw},
11    traits::{PrivateKeyParts, PublicKeyParts},
12};
13use sha2::Digest as _;
14use signature::Verifier;
15use subtle::ConstantTimeEq as _;
16use zeroize::{Zeroize, Zeroizing};
17
18pub(crate) struct KeyPairDer {
19    pub private: Zeroizing<Vec<u8>>,
20    pub public: Vec<u8>,
21    pub length: usize,
22    pub exponent: Vec<u8>,
23}
24
25fn unsupported() -> io::Error {
26    io::Error::other("Unsupported asymmetric crypto operation")
27}
28
29fn hash_bytes(name: &str, data: &[u8]) -> io::Result<Vec<u8>> {
30    match name {
31        "SHA-1" => Ok(sha1::Sha1::digest(data).to_vec()),
32        "SHA-256" => Ok(sha2::Sha256::digest(data).to_vec()),
33        "SHA-384" => Ok(sha2::Sha384::digest(data).to_vec()),
34        "SHA-512" => Ok(sha2::Sha512::digest(data).to_vec()),
35        _ => Err(unsupported()),
36    }
37}
38
39pub(crate) fn generate(
40    name: &str,
41    length: usize,
42    exponent: &[u8],
43    curve: &str,
44) -> io::Result<KeyPairDer> {
45    let mut rng = OsRng;
46    match name {
47        "RSA-OAEP" | "RSA-PSS" | "RSASSA-PKCS1-V1_5" => {
48            if !(512..=8192).contains(&length) || !length.is_multiple_of(8) || exponent.is_empty() {
49                return Err(io::Error::other("Invalid RSA key parameters"));
50            }
51            let exp = rsa::BigUint::from_bytes_be(exponent);
52            let exponent_bytes = exp.to_bytes_be();
53            if exp < rsa::BigUint::from(3u8)
54                || exponent_bytes.last().is_none_or(|byte| byte % 2 == 0)
55            {
56                return Err(io::Error::other("Invalid RSA public exponent"));
57            }
58            let private =
59                RsaPrivateKey::new_with_exp(&mut rng, length, &exp).map_err(io::Error::other)?;
60            let public = RsaPublicKey::from(&private);
61            let private_der = private.to_pkcs8_der().map_err(io::Error::other)?;
62            let public_der = public.to_public_key_der().map_err(io::Error::other)?;
63            Ok(KeyPairDer {
64                private: Zeroizing::new(private_der.as_bytes().to_vec()),
65                public: public_der.as_bytes().to_vec(),
66                length,
67                exponent: exp.to_bytes_be(),
68            })
69        }
70        "ECDSA" | "ECDH" => match curve {
71            "P-256" => {
72                let private = p256::SecretKey::random(&mut rng);
73                let public = private.public_key();
74                Ok(KeyPairDer {
75                    private: Zeroizing::new(
76                        private
77                            .to_pkcs8_der()
78                            .map_err(io::Error::other)?
79                            .as_bytes()
80                            .to_vec(),
81                    ),
82                    public: public
83                        .to_public_key_der()
84                        .map_err(io::Error::other)?
85                        .as_bytes()
86                        .to_vec(),
87                    length: 256,
88                    exponent: Vec::new(),
89                })
90            }
91            "P-384" => {
92                let private = p384::SecretKey::random(&mut rng);
93                let public = private.public_key();
94                Ok(KeyPairDer {
95                    private: Zeroizing::new(
96                        private
97                            .to_pkcs8_der()
98                            .map_err(io::Error::other)?
99                            .as_bytes()
100                            .to_vec(),
101                    ),
102                    public: public
103                        .to_public_key_der()
104                        .map_err(io::Error::other)?
105                        .as_bytes()
106                        .to_vec(),
107                    length: 384,
108                    exponent: Vec::new(),
109                })
110            }
111            "P-521" => {
112                let private = p521::SecretKey::random(&mut rng);
113                let public = private.public_key();
114                Ok(KeyPairDer {
115                    private: Zeroizing::new(
116                        private
117                            .to_pkcs8_der()
118                            .map_err(io::Error::other)?
119                            .as_bytes()
120                            .to_vec(),
121                    ),
122                    public: public
123                        .to_public_key_der()
124                        .map_err(io::Error::other)?
125                        .as_bytes()
126                        .to_vec(),
127                    length: 521,
128                    exponent: Vec::new(),
129                })
130            }
131            _ => Err(unsupported()),
132        },
133        "ED25519" => {
134            let private = ed25519_dalek::SigningKey::generate(&mut rng);
135            let public = private.verifying_key();
136            Ok(KeyPairDer {
137                private: Zeroizing::new(
138                    private
139                        .to_pkcs8_der()
140                        .map_err(io::Error::other)?
141                        .as_bytes()
142                        .to_vec(),
143                ),
144                public: public
145                    .to_public_key_der()
146                    .map_err(io::Error::other)?
147                    .as_bytes()
148                    .to_vec(),
149                length: 256,
150                exponent: Vec::new(),
151            })
152        }
153        "X25519" => {
154            let mut secret = [0u8; 32];
155            rng.fill_bytes(&mut secret);
156            let private = x25519_dalek::StaticSecret::from(secret);
157            secret.zeroize();
158            let public = x25519_dalek::PublicKey::from(&private);
159            let private_der = Zeroizing::new(private.to_bytes().to_vec());
160            Ok(KeyPairDer {
161                private: private_der,
162                public: public.to_bytes().to_vec(),
163                length: 256,
164                exponent: Vec::new(),
165            })
166        }
167        _ => Err(unsupported()),
168    }
169}
170
171pub(crate) struct ImportedKey {
172    pub bytes: Vec<u8>,
173    pub length: usize,
174    pub exponent: Vec<u8>,
175    pub curve: String,
176}
177
178fn x25519_der(private: bool, key: &[u8]) -> io::Result<Vec<u8>> {
179    let prefix: &[u8] = if private {
180        &[
181            0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x04, 0x22,
182            0x04, 0x20,
183        ]
184    } else {
185        &[
186            0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x03, 0x21, 0x00,
187        ]
188    };
189    if key.len() != 32 {
190        return Err(unsupported());
191    }
192    let mut der = prefix.to_vec();
193    der.extend_from_slice(key);
194    Ok(der)
195}
196
197fn x25519_from_der(private: bool, der: &[u8]) -> io::Result<Vec<u8>> {
198    let prefix: &[u8] = if private {
199        &[
200            0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x04, 0x22,
201            0x04, 0x20,
202        ]
203    } else {
204        &[
205            0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x03, 0x21, 0x00,
206        ]
207    };
208    if der.len() != prefix.len() + 32 || !der.starts_with(prefix) {
209        return Err(unsupported());
210    }
211    Ok(der[prefix.len()..].to_vec())
212}
213
214fn ec_public_sec1(der: &[u8]) -> io::Result<Vec<u8>> {
215    let info = pkcs8::spki::SubjectPublicKeyInfoRef::try_from(der).map_err(io::Error::other)?;
216    info.subject_public_key
217        .as_bytes()
218        .map(ToOwned::to_owned)
219        .ok_or_else(unsupported)
220}
221
222pub(crate) fn import_key(
223    format: &str,
224    data: &[u8],
225    name: &str,
226    curve: &str,
227) -> io::Result<ImportedKey> {
228    let private = format == "pkcs8";
229    if format == "raw" && private {
230        return Err(unsupported());
231    }
232    if !matches!(format, "raw" | "spki" | "pkcs8") {
233        return Err(unsupported());
234    }
235    match name {
236        "RSA-OAEP" | "RSA-PSS" | "RSASSA-PKCS1-V1_5" => {
237            let (bytes, length, exponent) = if private {
238                let key = RsaPrivateKey::from_pkcs8_der(data).map_err(io::Error::other)?;
239                if !(512..=8192).contains(&key.n().bits()) {
240                    return Err(io::Error::other("Invalid RSA modulus size"));
241                }
242                let bytes = key
243                    .to_pkcs8_der()
244                    .map_err(io::Error::other)?
245                    .as_bytes()
246                    .to_vec();
247                (bytes, key.n().bits(), key.e().to_bytes_be())
248            } else {
249                let key = RsaPublicKey::from_public_key_der(data).map_err(io::Error::other)?;
250                if !(512..=8192).contains(&key.n().bits()) {
251                    return Err(io::Error::other("Invalid RSA modulus size"));
252                }
253                let bytes = key
254                    .to_public_key_der()
255                    .map_err(io::Error::other)?
256                    .as_bytes()
257                    .to_vec();
258                (bytes, key.n().bits(), key.e().to_bytes_be())
259            };
260            Ok(ImportedKey {
261                bytes,
262                length,
263                exponent,
264                curve: String::new(),
265            })
266        }
267        "ECDSA" | "ECDH" => match (curve, format) {
268            ("P-256", "raw") => {
269                let key = p256::PublicKey::from_sec1_bytes(data).map_err(io::Error::other)?;
270                Ok(ImportedKey {
271                    bytes: key
272                        .to_public_key_der()
273                        .map_err(io::Error::other)?
274                        .as_bytes()
275                        .to_vec(),
276                    length: 256,
277                    exponent: Vec::new(),
278                    curve: curve.into(),
279                })
280            }
281            ("P-256", "pkcs8") => {
282                let key = p256::SecretKey::from_pkcs8_der(data).map_err(io::Error::other)?;
283                Ok(ImportedKey {
284                    bytes: key
285                        .to_pkcs8_der()
286                        .map_err(io::Error::other)?
287                        .as_bytes()
288                        .to_vec(),
289                    length: 256,
290                    exponent: Vec::new(),
291                    curve: curve.into(),
292                })
293            }
294            ("P-256", "spki") => {
295                let key = p256::PublicKey::from_public_key_der(data).map_err(io::Error::other)?;
296                Ok(ImportedKey {
297                    bytes: key
298                        .to_public_key_der()
299                        .map_err(io::Error::other)?
300                        .as_bytes()
301                        .to_vec(),
302                    length: 256,
303                    exponent: Vec::new(),
304                    curve: curve.into(),
305                })
306            }
307            ("P-384", "raw") => {
308                let key = p384::PublicKey::from_sec1_bytes(data).map_err(io::Error::other)?;
309                Ok(ImportedKey {
310                    bytes: key
311                        .to_public_key_der()
312                        .map_err(io::Error::other)?
313                        .as_bytes()
314                        .to_vec(),
315                    length: 384,
316                    exponent: Vec::new(),
317                    curve: curve.into(),
318                })
319            }
320            ("P-384", "pkcs8") => {
321                let key = p384::SecretKey::from_pkcs8_der(data).map_err(io::Error::other)?;
322                Ok(ImportedKey {
323                    bytes: key
324                        .to_pkcs8_der()
325                        .map_err(io::Error::other)?
326                        .as_bytes()
327                        .to_vec(),
328                    length: 384,
329                    exponent: Vec::new(),
330                    curve: curve.into(),
331                })
332            }
333            ("P-384", "spki") => {
334                let key = p384::PublicKey::from_public_key_der(data).map_err(io::Error::other)?;
335                Ok(ImportedKey {
336                    bytes: key
337                        .to_public_key_der()
338                        .map_err(io::Error::other)?
339                        .as_bytes()
340                        .to_vec(),
341                    length: 384,
342                    exponent: Vec::new(),
343                    curve: curve.into(),
344                })
345            }
346            ("P-521", "raw") => {
347                let key = p521::PublicKey::from_sec1_bytes(data).map_err(io::Error::other)?;
348                Ok(ImportedKey {
349                    bytes: key
350                        .to_public_key_der()
351                        .map_err(io::Error::other)?
352                        .as_bytes()
353                        .to_vec(),
354                    length: 521,
355                    exponent: Vec::new(),
356                    curve: curve.into(),
357                })
358            }
359            ("P-521", "pkcs8") => {
360                let key = p521::SecretKey::from_pkcs8_der(data).map_err(io::Error::other)?;
361                Ok(ImportedKey {
362                    bytes: key
363                        .to_pkcs8_der()
364                        .map_err(io::Error::other)?
365                        .as_bytes()
366                        .to_vec(),
367                    length: 521,
368                    exponent: Vec::new(),
369                    curve: curve.into(),
370                })
371            }
372            ("P-521", "spki") => {
373                let sec1 = ec_public_sec1(data)?;
374                let key = p521::PublicKey::from_sec1_bytes(&sec1).map_err(io::Error::other)?;
375                Ok(ImportedKey {
376                    bytes: key
377                        .to_public_key_der()
378                        .map_err(io::Error::other)?
379                        .as_bytes()
380                        .to_vec(),
381                    length: 521,
382                    exponent: Vec::new(),
383                    curve: curve.into(),
384                })
385            }
386            _ => Err(unsupported()),
387        },
388        "ED25519" => match format {
389            "raw" => {
390                let public: [u8; 32] = data
391                    .try_into()
392                    .map_err(|_| io::Error::other("Invalid key length"))?;
393                let key =
394                    ed25519_dalek::VerifyingKey::from_bytes(&public).map_err(io::Error::other)?;
395                Ok(ImportedKey {
396                    bytes: key
397                        .to_public_key_der()
398                        .map_err(io::Error::other)?
399                        .as_bytes()
400                        .to_vec(),
401                    length: 256,
402                    exponent: Vec::new(),
403                    curve: String::new(),
404                })
405            }
406            "spki" => {
407                let key = ed25519_dalek::VerifyingKey::from_public_key_der(data)
408                    .map_err(io::Error::other)?;
409                Ok(ImportedKey {
410                    bytes: key
411                        .to_public_key_der()
412                        .map_err(io::Error::other)?
413                        .as_bytes()
414                        .to_vec(),
415                    length: 256,
416                    exponent: Vec::new(),
417                    curve: String::new(),
418                })
419            }
420            "pkcs8" => {
421                let key =
422                    ed25519_dalek::SigningKey::from_pkcs8_der(data).map_err(io::Error::other)?;
423                Ok(ImportedKey {
424                    bytes: key
425                        .to_pkcs8_der()
426                        .map_err(io::Error::other)?
427                        .as_bytes()
428                        .to_vec(),
429                    length: 256,
430                    exponent: Vec::new(),
431                    curve: String::new(),
432                })
433            }
434            _ => Err(unsupported()),
435        },
436        "X25519" => {
437            let bytes = match format {
438                "raw" | "spki" if !private => {
439                    if format == "raw" {
440                        data.to_vec()
441                    } else {
442                        x25519_from_der(false, data)?
443                    }
444                }
445                "pkcs8" if private => x25519_from_der(true, data)?,
446                _ => return Err(unsupported()),
447            };
448            if bytes.len() != 32 {
449                return Err(unsupported());
450            }
451            Ok(ImportedKey {
452                bytes,
453                length: 256,
454                exponent: Vec::new(),
455                curve: String::new(),
456            })
457        }
458        _ => Err(unsupported()),
459    }
460}
461
462pub(crate) fn export_key(
463    format: &str,
464    data: &[u8],
465    name: &str,
466    key_type: &str,
467    curve: &str,
468) -> io::Result<Vec<u8>> {
469    if (format == "raw" && key_type == "private")
470        || (format == "pkcs8" && key_type != "private")
471        || (format == "spki" && key_type != "public")
472    {
473        return Err(io::Error::other(
474            "InvalidAccessError: key type is incompatible with key format",
475        ));
476    }
477    match (format, name, key_type) {
478        (
479            "pkcs8",
480            "RSA-OAEP" | "RSA-PSS" | "RSASSA-PKCS1-V1_5" | "ECDSA" | "ECDH" | "ED25519",
481            "private",
482        ) => Ok(data.to_vec()),
483        (
484            "spki",
485            "RSA-OAEP" | "RSA-PSS" | "RSASSA-PKCS1-V1_5" | "ECDSA" | "ECDH" | "ED25519",
486            "public",
487        ) => Ok(data.to_vec()),
488        ("raw", "ECDSA" | "ECDH", "public") => match curve {
489            "P-256" => Ok(p256::PublicKey::from_public_key_der(data)
490                .map_err(io::Error::other)?
491                .to_encoded_point(false)
492                .as_bytes()
493                .to_vec()),
494            "P-384" => Ok(p384::PublicKey::from_public_key_der(data)
495                .map_err(io::Error::other)?
496                .to_encoded_point(false)
497                .as_bytes()
498                .to_vec()),
499            "P-521" => Ok(ec_public_sec1(data)?),
500            _ => Err(unsupported()),
501        },
502        ("raw", "ED25519", "public") => Ok(ed25519_dalek::VerifyingKey::from_public_key_der(data)
503            .map_err(io::Error::other)?
504            .to_bytes()
505            .to_vec()),
506        ("raw", "X25519", "public") => Ok(data.to_vec()),
507        ("spki", "X25519", "public") => x25519_der(false, data),
508        ("pkcs8", "X25519", "private") => x25519_der(true, data),
509        _ => Err(unsupported()),
510    }
511}
512
513fn jwk_bytes(value: &serde_json::Value, field: &str) -> io::Result<Vec<u8>> {
514    use base64::Engine;
515    use base64::engine::general_purpose::URL_SAFE_NO_PAD;
516    let encoded = value
517        .get(field)
518        .and_then(serde_json::Value::as_str)
519        .ok_or_else(|| io::Error::other("JWK field is missing"))?;
520    URL_SAFE_NO_PAD.decode(encoded).map_err(io::Error::other)
521}
522
523fn b64(bytes: &[u8]) -> String {
524    use base64::Engine;
525    use base64::engine::general_purpose::URL_SAFE_NO_PAD;
526    URL_SAFE_NO_PAD.encode(bytes)
527}
528
529pub(crate) fn import_jwk(
530    jwk: &serde_json::Value,
531    name: &str,
532    hash: &str,
533    curve: &str,
534) -> io::Result<(ImportedKey, String)> {
535    match name {
536        "RSA-OAEP" | "RSA-PSS" | "RSASSA-PKCS1-V1_5" => {
537            if jwk.get("kty").and_then(serde_json::Value::as_str) != Some("RSA") {
538                return Err(io::Error::other("JWK kty does not match RSA"));
539            }
540            if jwk.get("oth").is_some() {
541                return Err(io::Error::other("Multiprime RSA JWKs are unsupported"));
542            }
543            let n_bytes = jwk_bytes(jwk, "n")?;
544            let e_bytes = jwk_bytes(jwk, "e")?;
545            if n_bytes.is_empty() || e_bytes.is_empty() || n_bytes[0] == 0 || e_bytes[0] == 0 {
546                return Err(io::Error::other("Invalid RSA JWK integer encoding"));
547            }
548            let n = rsa::BigUint::from_bytes_be(&n_bytes);
549            if n.bits() < 512 || n.bits() > 8192 {
550                return Err(io::Error::other("Invalid RSA modulus size"));
551            }
552            let e = rsa::BigUint::from_bytes_be(&e_bytes);
553            let private = jwk.get("d").is_some();
554            let (bytes, length) = if private {
555                let d = rsa::BigUint::from_bytes_be(&jwk_bytes(jwk, "d")?);
556                let p = rsa::BigUint::from_bytes_be(&jwk_bytes(jwk, "p")?);
557                let q = rsa::BigUint::from_bytes_be(&jwk_bytes(jwk, "q")?);
558                let dp = rsa::BigUint::from_bytes_be(&jwk_bytes(jwk, "dp")?);
559                let dq = rsa::BigUint::from_bytes_be(&jwk_bytes(jwk, "dq")?);
560                let qi = rsa::BigUint::from_bytes_be(&jwk_bytes(jwk, "qi")?);
561                let mut key = RsaPrivateKey::from_components(n, e, d, vec![p, q])
562                    .map_err(io::Error::other)?;
563                key.precompute().map_err(io::Error::other)?;
564                key.validate().map_err(io::Error::other)?;
565                if key.dp() != Some(&dp)
566                    || key.dq() != Some(&dq)
567                    || key.qinv().and_then(|v| v.to_biguint()).as_ref() != Some(&qi)
568                {
569                    return Err(io::Error::other("JWK RSA CRT parameters do not match"));
570                }
571                let length = key.n().bits();
572                (
573                    key.to_pkcs8_der()
574                        .map_err(io::Error::other)?
575                        .as_bytes()
576                        .to_vec(),
577                    length,
578                )
579            } else {
580                let key = RsaPublicKey::new(n, e).map_err(io::Error::other)?;
581                let length = key.n().bits();
582                (
583                    key.to_public_key_der()
584                        .map_err(io::Error::other)?
585                        .as_bytes()
586                        .to_vec(),
587                    length,
588                )
589            };
590            let expected_alg = match name {
591                "RSA-OAEP" => {
592                    if hash == "SHA-1" {
593                        "RSA-OAEP".to_owned()
594                    } else {
595                        format!("RSA-OAEP-{}", &hash[4..])
596                    }
597                }
598                "RSA-PSS" => format!("PS{}", &hash[4..]),
599                _ => format!("RS{}", &hash[4..]),
600            };
601            if let Some(alg) = jwk.get("alg")
602                && alg.as_str() != Some(expected_alg.as_str())
603            {
604                return Err(io::Error::other("JWK alg does not match RSA hash"));
605            }
606            Ok((
607                ImportedKey {
608                    bytes,
609                    length,
610                    exponent: e_bytes,
611                    curve: String::new(),
612                },
613                if private { "private" } else { "public" }.into(),
614            ))
615        }
616        "ECDSA" | "ECDH" => {
617            if jwk.get("kty").and_then(serde_json::Value::as_str) != Some("EC") {
618                return Err(io::Error::other("JWK kty does not match EC"));
619            }
620            let expected_curve = match curve {
621                "P-256" => "P-256",
622                "P-384" => "P-384",
623                "P-521" => "P-521",
624                _ => return Err(unsupported()),
625            };
626            if jwk.get("crv").and_then(serde_json::Value::as_str) != Some(expected_curve) {
627                return Err(io::Error::other("JWK curve does not match"));
628            }
629            let x = jwk_bytes(jwk, "x")?;
630            let y = jwk_bytes(jwk, "y")?;
631            let width = match curve {
632                "P-256" => 32,
633                "P-384" => 48,
634                "P-521" => 66,
635                _ => return Err(unsupported()),
636            };
637            if x.len() != width || y.len() != width {
638                return Err(io::Error::other("Invalid EC JWK coordinate length"));
639            }
640            let private = jwk.get("d").is_some();
641            if private && jwk_bytes(jwk, "d")?.len() != width {
642                return Err(io::Error::other("Invalid EC JWK private key length"));
643            }
644            let mut point = Vec::with_capacity(1 + x.len() + y.len());
645            point.push(4);
646            point.extend_from_slice(&x);
647            point.extend_from_slice(&y);
648            let (bytes, length) = match (curve, private) {
649                ("P-256", true) => {
650                    let key = p256::SecretKey::from_slice(&jwk_bytes(jwk, "d")?)
651                        .map_err(io::Error::other)?;
652                    if key.public_key().to_encoded_point(false).as_bytes() != point {
653                        return Err(io::Error::other(
654                            "JWK EC public and private values disagree",
655                        ));
656                    }
657                    (
658                        key.to_pkcs8_der()
659                            .map_err(io::Error::other)?
660                            .as_bytes()
661                            .to_vec(),
662                        256,
663                    )
664                }
665                ("P-256", false) => (
666                    p256::PublicKey::from_sec1_bytes(&point)
667                        .map_err(io::Error::other)?
668                        .to_public_key_der()
669                        .map_err(io::Error::other)?
670                        .as_bytes()
671                        .to_vec(),
672                    256,
673                ),
674                ("P-384", true) => {
675                    let key = p384::SecretKey::from_slice(&jwk_bytes(jwk, "d")?)
676                        .map_err(io::Error::other)?;
677                    if key.public_key().to_encoded_point(false).as_bytes() != point {
678                        return Err(io::Error::other(
679                            "JWK EC public and private values disagree",
680                        ));
681                    }
682                    (
683                        key.to_pkcs8_der()
684                            .map_err(io::Error::other)?
685                            .as_bytes()
686                            .to_vec(),
687                        384,
688                    )
689                }
690                ("P-384", false) => (
691                    p384::PublicKey::from_sec1_bytes(&point)
692                        .map_err(io::Error::other)?
693                        .to_public_key_der()
694                        .map_err(io::Error::other)?
695                        .as_bytes()
696                        .to_vec(),
697                    384,
698                ),
699                ("P-521", true) => {
700                    let key = p521::SecretKey::from_slice(&jwk_bytes(jwk, "d")?)
701                        .map_err(io::Error::other)?;
702                    if key.public_key().to_encoded_point(false).as_bytes() != point {
703                        return Err(io::Error::other(
704                            "JWK EC public and private values disagree",
705                        ));
706                    }
707                    (
708                        key.to_pkcs8_der()
709                            .map_err(io::Error::other)?
710                            .as_bytes()
711                            .to_vec(),
712                        521,
713                    )
714                }
715                ("P-521", false) => (
716                    p521::PublicKey::from_sec1_bytes(&point)
717                        .map_err(io::Error::other)?
718                        .to_public_key_der()
719                        .map_err(io::Error::other)?
720                        .as_bytes()
721                        .to_vec(),
722                    521,
723                ),
724                _ => return Err(unsupported()),
725            };
726            Ok((
727                ImportedKey {
728                    bytes,
729                    length,
730                    exponent: Vec::new(),
731                    curve: curve.into(),
732                },
733                if private { "private" } else { "public" }.into(),
734            ))
735        }
736        "ED25519" => {
737            if jwk.get("kty").and_then(serde_json::Value::as_str) != Some("OKP")
738                || jwk.get("crv").and_then(serde_json::Value::as_str) != Some("Ed25519")
739            {
740                return Err(io::Error::other("JWK is not Ed25519"));
741            }
742            let x: [u8; 32] = jwk_bytes(jwk, "x")?
743                .try_into()
744                .map_err(|_| io::Error::other("Invalid key length"))?;
745            let private = jwk.get("d").is_some();
746            let bytes = if private {
747                let d: [u8; 32] = jwk_bytes(jwk, "d")?
748                    .try_into()
749                    .map_err(|_| io::Error::other("Invalid key length"))?;
750                let key = ed25519_dalek::SigningKey::from_bytes(&d);
751                if key.verifying_key().to_bytes() != x {
752                    return Err(io::Error::other("JWK public and private values disagree"));
753                }
754                key.to_pkcs8_der()
755                    .map_err(io::Error::other)?
756                    .as_bytes()
757                    .to_vec()
758            } else {
759                ed25519_dalek::VerifyingKey::from_bytes(&x)
760                    .map_err(io::Error::other)?
761                    .to_public_key_der()
762                    .map_err(io::Error::other)?
763                    .as_bytes()
764                    .to_vec()
765            };
766            Ok((
767                ImportedKey {
768                    bytes,
769                    length: 256,
770                    exponent: Vec::new(),
771                    curve: String::new(),
772                },
773                if private { "private" } else { "public" }.into(),
774            ))
775        }
776        "X25519" => {
777            if jwk.get("kty").and_then(serde_json::Value::as_str) != Some("OKP")
778                || jwk.get("crv").and_then(serde_json::Value::as_str) != Some("X25519")
779            {
780                return Err(io::Error::other("JWK is not X25519"));
781            }
782            let x: [u8; 32] = jwk_bytes(jwk, "x")?
783                .try_into()
784                .map_err(|_| io::Error::other("Invalid key length"))?;
785            let private = jwk.get("d").is_some();
786            let bytes = if private {
787                let d: [u8; 32] = jwk_bytes(jwk, "d")?
788                    .try_into()
789                    .map_err(|_| io::Error::other("Invalid key length"))?;
790                let secret = x25519_dalek::StaticSecret::from(d);
791                if x25519_dalek::PublicKey::from(&secret).to_bytes() != x {
792                    return Err(io::Error::other("JWK public and private values disagree"));
793                }
794                d.to_vec()
795            } else {
796                x.to_vec()
797            };
798            Ok((
799                ImportedKey {
800                    bytes,
801                    length: 256,
802                    exponent: Vec::new(),
803                    curve: String::new(),
804                },
805                if private { "private" } else { "public" }.into(),
806            ))
807        }
808        _ => Err(unsupported()),
809    }
810}
811
812pub(crate) fn export_jwk(
813    data: &[u8],
814    name: &str,
815    hash: &str,
816    key_type: &str,
817    curve: &str,
818    usages: &[String],
819    extractable: bool,
820) -> io::Result<serde_json::Value> {
821    let mut value = serde_json::Map::new();
822    match name {
823        "RSA-OAEP" | "RSA-PSS" | "RSASSA-PKCS1-V1_5" => {
824            let (n, e) = if key_type == "private" {
825                let key = RsaPrivateKey::from_pkcs8_der(data).map_err(io::Error::other)?;
826                (key.n().to_bytes_be(), key.e().to_bytes_be())
827            } else {
828                let key = RsaPublicKey::from_public_key_der(data).map_err(io::Error::other)?;
829                (key.n().to_bytes_be(), key.e().to_bytes_be())
830            };
831            value.insert("kty".into(), "RSA".into());
832            value.insert("n".into(), b64(&n).into());
833            value.insert("e".into(), b64(&e).into());
834            if key_type == "private" {
835                let key = RsaPrivateKey::from_pkcs8_der(data).map_err(io::Error::other)?;
836                let primes = key.primes();
837                if primes.len() != 2 {
838                    return Err(unsupported());
839                }
840                value.insert("d".into(), b64(&key.d().to_bytes_be()).into());
841                value.insert("p".into(), b64(&primes[0].to_bytes_be()).into());
842                value.insert("q".into(), b64(&primes[1].to_bytes_be()).into());
843                value.insert(
844                    "dp".into(),
845                    b64(&key.dp().ok_or_else(unsupported)?.to_bytes_be()).into(),
846                );
847                value.insert(
848                    "dq".into(),
849                    b64(&key.dq().ok_or_else(unsupported)?.to_bytes_be()).into(),
850                );
851                value.insert(
852                    "qi".into(),
853                    b64(&key.crt_coefficient().ok_or_else(unsupported)?.to_bytes_be()).into(),
854                );
855            }
856            let prefix = match name {
857                "RSA-OAEP" => "RSA-OAEP",
858                "RSA-PSS" => "PS",
859                _ => "RS",
860            };
861            let alg = if name == "RSA-OAEP" {
862                if hash == "SHA-1" {
863                    prefix.into()
864                } else {
865                    format!("{prefix}-{}", &hash[4..])
866                }
867            } else {
868                format!("{prefix}{}", &hash[4..])
869            };
870            value.insert("alg".into(), alg.into());
871        }
872        "ECDSA" | "ECDH" => {
873            let (x, y, d) = match (curve, key_type) {
874                ("P-256", "private") => {
875                    let k = p256::SecretKey::from_pkcs8_der(data).map_err(io::Error::other)?;
876                    let p = k.public_key().to_encoded_point(false);
877                    (
878                        p.x().ok_or_else(unsupported)?.to_vec(),
879                        p.y().ok_or_else(unsupported)?.to_vec(),
880                        Some(k.to_bytes().to_vec()),
881                    )
882                }
883                ("P-256", _) => {
884                    let k = p256::PublicKey::from_public_key_der(data).map_err(io::Error::other)?;
885                    let p = k.to_encoded_point(false);
886                    (
887                        p.x().ok_or_else(unsupported)?.to_vec(),
888                        p.y().ok_or_else(unsupported)?.to_vec(),
889                        None,
890                    )
891                }
892                ("P-384", "private") => {
893                    let k = p384::SecretKey::from_pkcs8_der(data).map_err(io::Error::other)?;
894                    let p = k.public_key().to_encoded_point(false);
895                    (
896                        p.x().ok_or_else(unsupported)?.to_vec(),
897                        p.y().ok_or_else(unsupported)?.to_vec(),
898                        Some(k.to_bytes().to_vec()),
899                    )
900                }
901                ("P-384", _) => {
902                    let k = p384::PublicKey::from_public_key_der(data).map_err(io::Error::other)?;
903                    let p = k.to_encoded_point(false);
904                    (
905                        p.x().ok_or_else(unsupported)?.to_vec(),
906                        p.y().ok_or_else(unsupported)?.to_vec(),
907                        None,
908                    )
909                }
910                ("P-521", "private") => {
911                    let k = p521::SecretKey::from_pkcs8_der(data).map_err(io::Error::other)?;
912                    let p = k.public_key().to_encoded_point(false);
913                    (
914                        p.x().ok_or_else(unsupported)?.to_vec(),
915                        p.y().ok_or_else(unsupported)?.to_vec(),
916                        Some(k.to_bytes().to_vec()),
917                    )
918                }
919                ("P-521", _) => {
920                    let p = p521::PublicKey::from_sec1_bytes(&ec_public_sec1(data)?)
921                        .map_err(io::Error::other)?
922                        .to_encoded_point(false);
923                    (
924                        p.x().ok_or_else(unsupported)?.to_vec(),
925                        p.y().ok_or_else(unsupported)?.to_vec(),
926                        None,
927                    )
928                }
929                _ => return Err(unsupported()),
930            };
931            value.insert("kty".into(), "EC".into());
932            value.insert("crv".into(), curve.into());
933            value.insert("x".into(), b64(&x).into());
934            value.insert("y".into(), b64(&y).into());
935            if let Some(d) = d {
936                value.insert("d".into(), b64(&d).into());
937            }
938            if name == "ECDSA" {
939                let alg = match curve {
940                    "P-256" => "ES256",
941                    "P-384" => "ES384",
942                    "P-521" => "ES512",
943                    _ => return Err(unsupported()),
944                };
945                value.insert("alg".into(), alg.into());
946            }
947        }
948        "ED25519" => {
949            let (x, d) = if key_type == "private" {
950                let k =
951                    ed25519_dalek::SigningKey::from_pkcs8_der(data).map_err(io::Error::other)?;
952                (
953                    k.verifying_key().to_bytes().to_vec(),
954                    Some(k.to_bytes().to_vec()),
955                )
956            } else {
957                (
958                    ed25519_dalek::VerifyingKey::from_public_key_der(data)
959                        .map_err(io::Error::other)?
960                        .to_bytes()
961                        .to_vec(),
962                    None,
963                )
964            };
965            value.insert("kty".into(), "OKP".into());
966            value.insert("crv".into(), "Ed25519".into());
967            value.insert("x".into(), b64(&x).into());
968            if let Some(d) = d {
969                value.insert("d".into(), b64(&d).into());
970            }
971            value.insert("alg".into(), "EdDSA".into());
972        }
973        "X25519" => {
974            let (x, d) = if key_type == "private" {
975                let d: [u8; 32] = data
976                    .try_into()
977                    .map_err(|_| io::Error::other("Invalid key length"))?;
978                let s = x25519_dalek::StaticSecret::from(d);
979                (
980                    x25519_dalek::PublicKey::from(&s).to_bytes().to_vec(),
981                    Some(d.to_vec()),
982                )
983            } else {
984                (data.to_vec(), None)
985            };
986            value.insert("kty".into(), "OKP".into());
987            value.insert("crv".into(), "X25519".into());
988            value.insert("x".into(), b64(&x).into());
989            if let Some(d) = d {
990                value.insert("d".into(), b64(&d).into());
991            }
992        }
993        _ => return Err(unsupported()),
994    }
995    value.insert(
996        "key_ops".into(),
997        serde_json::to_value(usages).map_err(io::Error::other)?,
998    );
999    value.insert("ext".into(), extractable.into());
1000    Ok(value.into())
1001}
1002
1003fn mgf1<D>(seed: &[u8], output: &mut [u8])
1004where
1005    D: sha2::Digest,
1006{
1007    let mut counter = 0u32;
1008    let mut offset = 0;
1009    while offset < output.len() {
1010        let mut hasher = D::new();
1011        hasher.update(seed);
1012        hasher.update(counter.to_be_bytes());
1013        let digest = hasher.finalize();
1014        let digest = digest.as_slice();
1015        let take = (output.len() - offset).min(digest.len());
1016        output[offset..offset + take].copy_from_slice(&digest[..take]);
1017        offset += take;
1018        counter = counter.wrapping_add(1);
1019    }
1020}
1021
1022fn oaep_encrypt<D>(public: &RsaPublicKey, label: &[u8], input: &[u8]) -> io::Result<Vec<u8>>
1023where
1024    D: sha2::Digest,
1025{
1026    let key_size = public.size();
1027    let hash_size = <D as sha2::Digest>::output_size();
1028    if input.len() + 2 * hash_size + 2 > key_size {
1029        return Err(io::Error::other("Invalid RSA-OAEP plaintext length"));
1030    }
1031    let db_size = key_size - hash_size - 1;
1032    let mut db = vec![0; db_size];
1033    db[..hash_size].copy_from_slice(D::digest(label).as_slice());
1034    db[db_size - input.len() - 1] = 1;
1035    db[db_size - input.len()..].copy_from_slice(input);
1036    let mut seed = Zeroizing::new(vec![0; hash_size]);
1037    OsRng.fill_bytes(seed.as_mut_slice());
1038    let mut db_mask = vec![0; db_size];
1039    mgf1::<D>(&seed, &mut db_mask);
1040    for (byte, mask) in db.iter_mut().zip(&db_mask) {
1041        *byte ^= *mask;
1042    }
1043    let mut seed_mask = Zeroizing::new(vec![0; hash_size]);
1044    mgf1::<D>(&db, &mut seed_mask);
1045    for (byte, mask) in seed.iter_mut().zip(seed_mask.iter()) {
1046        *byte ^= *mask;
1047    }
1048    let mut encoded = Vec::with_capacity(key_size);
1049    encoded.push(0);
1050    encoded.extend_from_slice(&seed);
1051    encoded.extend_from_slice(&db);
1052    let encoded = rsa::BigUint::from_bytes_be(&encoded);
1053    let encrypted = rsa_encrypt_raw(public, &encoded).map_err(io::Error::other)?;
1054    let bytes = encrypted.to_bytes_be();
1055    if bytes.len() > key_size {
1056        return Err(io::Error::other("Invalid RSA-OAEP ciphertext"));
1057    }
1058    let mut output = vec![0; key_size];
1059    output[key_size - bytes.len()..].copy_from_slice(&bytes);
1060    Ok(output)
1061}
1062
1063fn oaep_decrypt<D>(private: &RsaPrivateKey, label: &[u8], input: &[u8]) -> io::Result<Vec<u8>>
1064where
1065    D: sha2::Digest,
1066{
1067    let key_size = private.size();
1068    let hash_size = <D as sha2::Digest>::output_size();
1069    if key_size < 2 * hash_size + 2 || input.len() != key_size {
1070        return Err(io::Error::other("Invalid RSA-OAEP ciphertext"));
1071    }
1072    let ciphertext = rsa::BigUint::from_bytes_be(input);
1073    let mut rng = OsRng;
1074    let encoded =
1075        rsa_decrypt_raw(private, Some(&mut rng), &ciphertext).map_err(io::Error::other)?;
1076    let bytes = encoded.to_bytes_be();
1077    if bytes.len() > key_size {
1078        return Err(io::Error::other("Invalid RSA-OAEP ciphertext"));
1079    }
1080    let mut padded = Zeroizing::new(vec![0; key_size]);
1081    padded[key_size - bytes.len()..].copy_from_slice(&bytes);
1082    let mut failure = (padded[0] != 0) as u8;
1083    let (masked_seed, masked_db) = padded[1..].split_at(hash_size);
1084    let mut seed = Zeroizing::new(vec![0; hash_size]);
1085    let mut seed_mask = vec![0; hash_size];
1086    mgf1::<D>(masked_db, &mut seed_mask);
1087    for ((byte, masked), mask) in seed
1088        .iter_mut()
1089        .zip(masked_seed.iter())
1090        .zip(seed_mask.iter())
1091    {
1092        *byte = *masked ^ *mask;
1093    }
1094    let mut db = Zeroizing::new(vec![0; key_size - hash_size - 1]);
1095    let mut db_mask = vec![0; db.len()];
1096    mgf1::<D>(&seed, &mut db_mask);
1097    for ((byte, masked), mask) in db.iter_mut().zip(masked_db.iter()).zip(db_mask.iter()) {
1098        *byte = *masked ^ *mask;
1099    }
1100    failure |= (!bool::from(db[..hash_size].ct_eq(D::digest(label).as_slice()))) as u8;
1101    let mut message_start = 0usize;
1102    let mut looking = 1u8;
1103    for (index, &byte) in db.iter().enumerate().skip(hash_size) {
1104        let is_zero = (byte == 0) as u8;
1105        let is_one = (byte == 1) as u8;
1106        failure |= looking & (1 - (is_zero | is_one));
1107        message_start |= (looking & is_one) as usize * (index + 1);
1108        looking &= 1 - is_one;
1109    }
1110    failure |= looking;
1111    if failure != 0 {
1112        return Err(io::Error::other("Invalid RSA-OAEP ciphertext"));
1113    }
1114    Ok(db[message_start..].to_vec())
1115}
1116
1117pub(crate) fn rsa_encrypt(
1118    name: &str,
1119    public_der: &[u8],
1120    hash: &str,
1121    label: &[u8],
1122    input: &[u8],
1123) -> io::Result<Vec<u8>> {
1124    if name != "RSA-OAEP" {
1125        return Err(unsupported());
1126    }
1127    let key = RsaPublicKey::from_public_key_der(public_der).map_err(io::Error::other)?;
1128    macro_rules! encrypt {
1129        ($digest:ty) => {
1130            oaep_encrypt::<$digest>(&key, label, input)
1131        };
1132    }
1133    match hash {
1134        "SHA-1" => encrypt!(sha1::Sha1),
1135        "SHA-256" => encrypt!(sha2::Sha256),
1136        "SHA-384" => encrypt!(sha2::Sha384),
1137        "SHA-512" => encrypt!(sha2::Sha512),
1138        _ => Err(unsupported()),
1139    }
1140}
1141
1142pub(crate) fn rsa_decrypt(
1143    name: &str,
1144    private_der: &[u8],
1145    hash: &str,
1146    label: &[u8],
1147    input: &[u8],
1148) -> io::Result<Vec<u8>> {
1149    if name != "RSA-OAEP" {
1150        return Err(unsupported());
1151    }
1152    let key = RsaPrivateKey::from_pkcs8_der(private_der).map_err(io::Error::other)?;
1153    macro_rules! decrypt {
1154        ($digest:ty) => {
1155            oaep_decrypt::<$digest>(&key, label, input)
1156        };
1157    }
1158    match hash {
1159        "SHA-1" => decrypt!(sha1::Sha1),
1160        "SHA-256" => decrypt!(sha2::Sha256),
1161        "SHA-384" => decrypt!(sha2::Sha384),
1162        "SHA-512" => decrypt!(sha2::Sha512),
1163        _ => Err(unsupported()),
1164    }
1165}
1166
1167pub(crate) fn rsa_sign(
1168    name: &str,
1169    private_der: &[u8],
1170    hash: &str,
1171    salt_length: usize,
1172    input: &[u8],
1173) -> io::Result<Vec<u8>> {
1174    let hashed = hash_bytes(hash, input)?;
1175    if name == "RSA-PSS" {
1176        let mut rng = OsRng;
1177        macro_rules! sign {
1178            ($digest:ty) => {{
1179                let key = RsaPrivateKey::from_pkcs8_der(private_der).map_err(io::Error::other)?;
1180                let signing_key =
1181                    rsa::pss::SigningKey::<$digest>::new_with_salt_len(key, salt_length);
1182                signature::hazmat::RandomizedPrehashSigner::sign_prehash_with_rng(
1183                    &signing_key,
1184                    &mut rng,
1185                    &hashed,
1186                )
1187                .map_err(io::Error::other)
1188                .map(|signature| Box::<[u8]>::from(signature).into_vec())
1189            }};
1190        }
1191        match hash {
1192            "SHA-1" => sign!(sha1::Sha1),
1193            "SHA-256" => sign!(sha2::Sha256),
1194            "SHA-384" => sign!(sha2::Sha384),
1195            "SHA-512" => sign!(sha2::Sha512),
1196            _ => Err(unsupported()),
1197        }
1198    } else if name == "RSASSA-PKCS1-V1_5" {
1199        macro_rules! sign {
1200            ($digest:ty) => {{
1201                let key = RsaPrivateKey::from_pkcs8_der(private_der).map_err(io::Error::other)?;
1202                let signing_key = rsa::pkcs1v15::SigningKey::<$digest>::new(key);
1203                signature::hazmat::PrehashSigner::sign_prehash(&signing_key, &hashed)
1204                    .map_err(io::Error::other)
1205                    .map(|signature| Box::<[u8]>::from(signature).into_vec())
1206            }};
1207        }
1208        match hash {
1209            "SHA-1" => sign!(sha1::Sha1),
1210            "SHA-256" => sign!(sha2::Sha256),
1211            "SHA-384" => sign!(sha2::Sha384),
1212            "SHA-512" => sign!(sha2::Sha512),
1213            _ => Err(unsupported()),
1214        }
1215    } else {
1216        Err(unsupported())
1217    }
1218}
1219
1220pub(crate) fn rsa_verify(
1221    name: &str,
1222    public_der: &[u8],
1223    hash: &str,
1224    salt_length: usize,
1225    input: &[u8],
1226    signature: &[u8],
1227) -> io::Result<bool> {
1228    let hashed = hash_bytes(hash, input)?;
1229    if name == "RSA-PSS" {
1230        macro_rules! verify {
1231            ($digest:ty) => {{
1232                let key =
1233                    RsaPublicKey::from_public_key_der(public_der).map_err(io::Error::other)?;
1234                let verifying_key =
1235                    rsa::pss::VerifyingKey::<$digest>::new_with_salt_len(key, salt_length);
1236                let signature = rsa::pss::Signature::try_from(signature)
1237                    .map_err(|_| io::Error::other("Invalid RSA-PSS signature"))?;
1238                Ok(signature::hazmat::PrehashVerifier::verify_prehash(
1239                    &verifying_key,
1240                    &hashed,
1241                    &signature,
1242                )
1243                .is_ok())
1244            }};
1245        }
1246        match hash {
1247            "SHA-1" => verify!(sha1::Sha1),
1248            "SHA-256" => verify!(sha2::Sha256),
1249            "SHA-384" => verify!(sha2::Sha384),
1250            "SHA-512" => verify!(sha2::Sha512),
1251            _ => Err(unsupported()),
1252        }
1253    } else if name == "RSASSA-PKCS1-V1_5" {
1254        macro_rules! verify {
1255            ($digest:ty) => {{
1256                let key =
1257                    RsaPublicKey::from_public_key_der(public_der).map_err(io::Error::other)?;
1258                let verifying_key = rsa::pkcs1v15::VerifyingKey::<$digest>::new(key);
1259                let signature = rsa::pkcs1v15::Signature::try_from(signature)
1260                    .map_err(|_| io::Error::other("Invalid RSASSA-PKCS1-V1_5 signature"))?;
1261                Ok(signature::hazmat::PrehashVerifier::verify_prehash(
1262                    &verifying_key,
1263                    &hashed,
1264                    &signature,
1265                )
1266                .is_ok())
1267            }};
1268        }
1269        match hash {
1270            "SHA-1" => verify!(sha1::Sha1),
1271            "SHA-256" => verify!(sha2::Sha256),
1272            "SHA-384" => verify!(sha2::Sha384),
1273            "SHA-512" => verify!(sha2::Sha512),
1274            _ => Err(unsupported()),
1275        }
1276    } else {
1277        Err(unsupported())
1278    }
1279}
1280
1281pub(crate) fn sign(
1282    name: &str,
1283    private_der: &[u8],
1284    hash: &str,
1285    curve: &str,
1286    input: &[u8],
1287) -> io::Result<Vec<u8>> {
1288    if name == "ED25519" {
1289        let key =
1290            ed25519_dalek::SigningKey::from_pkcs8_der(private_der).map_err(io::Error::other)?;
1291        return Ok(key.sign(input).to_bytes().to_vec());
1292    }
1293    macro_rules! sign_curve {
1294        ($module:ident) => {{
1295            let key = $module::ecdsa::SigningKey::from_pkcs8_der(private_der)
1296                .map_err(io::Error::other)?;
1297            let digest = hash_bytes(hash, input)?;
1298            let signature: $module::ecdsa::Signature =
1299                signature::hazmat::PrehashSigner::sign_prehash(&key, &digest)
1300                    .map_err(io::Error::other)?;
1301            Ok(signature.to_bytes().to_vec())
1302        }};
1303    }
1304    match (name, curve) {
1305        ("ECDSA", "P-256") => match hash {
1306            "SHA-1" => sign_curve!(p256),
1307            "SHA-256" => sign_curve!(p256),
1308            "SHA-384" => sign_curve!(p256),
1309            "SHA-512" => sign_curve!(p256),
1310            _ => Err(unsupported()),
1311        },
1312        ("ECDSA", "P-384") => match hash {
1313            "SHA-1" => sign_curve!(p384),
1314            "SHA-256" => sign_curve!(p384),
1315            "SHA-384" => sign_curve!(p384),
1316            "SHA-512" => sign_curve!(p384),
1317            _ => Err(unsupported()),
1318        },
1319        ("ECDSA", "P-521") => {
1320            let private = p521::SecretKey::from_pkcs8_der(private_der).map_err(io::Error::other)?;
1321            let key = p521::ecdsa::SigningKey::from_slice(private.to_bytes().as_slice())
1322                .map_err(io::Error::other)?;
1323            let digest = hash_bytes(hash, input)?;
1324            let signature: p521::ecdsa::Signature =
1325                signature::hazmat::PrehashSigner::sign_prehash(&key, &digest)
1326                    .map_err(io::Error::other)?;
1327            Ok(signature.to_bytes().to_vec())
1328        }
1329        _ => Err(unsupported()),
1330    }
1331}
1332
1333pub(crate) fn verify(
1334    name: &str,
1335    public_der: &[u8],
1336    hash: &str,
1337    curve: &str,
1338    input: &[u8],
1339    signature_bytes: &[u8],
1340) -> io::Result<bool> {
1341    if name == "ED25519" {
1342        let key = ed25519_dalek::VerifyingKey::from_public_key_der(public_der)
1343            .map_err(io::Error::other)?;
1344        let Ok(sig) = ed25519_dalek::Signature::from_slice(signature_bytes) else {
1345            return Ok(false);
1346        };
1347        return Ok(key.verify(input, &sig).is_ok());
1348    }
1349    macro_rules! verify_curve {
1350        ($module:ident) => {{
1351            let key = $module::ecdsa::VerifyingKey::from_public_key_der(public_der)
1352                .map_err(io::Error::other)?;
1353            let Ok(sig) = $module::ecdsa::Signature::from_slice(signature_bytes) else {
1354                return Ok(false);
1355            };
1356            let digest = hash_bytes(hash, input)?;
1357            Ok(signature::hazmat::PrehashVerifier::verify_prehash(&key, &digest, &sig).is_ok())
1358        }};
1359    }
1360    match (name, curve) {
1361        ("ECDSA", "P-256") => verify_curve!(p256),
1362        ("ECDSA", "P-384") => verify_curve!(p384),
1363        ("ECDSA", "P-521") => {
1364            let info = pkcs8::spki::SubjectPublicKeyInfoRef::try_from(public_der)
1365                .map_err(io::Error::other)?;
1366            let encoded = info.subject_public_key.as_bytes().ok_or_else(unsupported)?;
1367            let key =
1368                p521::ecdsa::VerifyingKey::from_sec1_bytes(encoded).map_err(io::Error::other)?;
1369            let Ok(sig) = p521::ecdsa::Signature::from_slice(signature_bytes) else {
1370                return Ok(false);
1371            };
1372            let digest = hash_bytes(hash, input)?;
1373            Ok(signature::hazmat::PrehashVerifier::verify_prehash(&key, &digest, &sig).is_ok())
1374        }
1375        _ => Err(unsupported()),
1376    }
1377}
1378
1379pub(crate) fn ecdh(
1380    name: &str,
1381    curve: &str,
1382    private_der: &[u8],
1383    public_der: &[u8],
1384) -> io::Result<Vec<u8>> {
1385    macro_rules! derive {
1386        ($module:ident) => {{
1387            let private =
1388                $module::SecretKey::from_pkcs8_der(private_der).map_err(io::Error::other)?;
1389            let public =
1390                $module::PublicKey::from_public_key_der(public_der).map_err(io::Error::other)?;
1391            Ok(
1392                $module::ecdh::diffie_hellman(private.to_nonzero_scalar(), public.as_affine())
1393                    .raw_secret_bytes()
1394                    .to_vec(),
1395            )
1396        }};
1397    }
1398    match (name, curve) {
1399        ("ECDH", "P-256") => derive!(p256),
1400        ("ECDH", "P-384") => derive!(p384),
1401        ("ECDH", "P-521") => {
1402            let private = p521::SecretKey::from_pkcs8_der(private_der).map_err(io::Error::other)?;
1403            let info = pkcs8::spki::SubjectPublicKeyInfoRef::try_from(public_der)
1404                .map_err(io::Error::other)?;
1405            let encoded = info.subject_public_key.as_bytes().ok_or_else(unsupported)?;
1406            let public = p521::PublicKey::from_sec1_bytes(encoded).map_err(io::Error::other)?;
1407            Ok(
1408                p521::ecdh::diffie_hellman(private.to_nonzero_scalar(), public.as_affine())
1409                    .raw_secret_bytes()
1410                    .to_vec(),
1411            )
1412        }
1413        _ => Err(unsupported()),
1414    }
1415}
1416
1417pub(crate) fn x25519(private: &[u8], public: &[u8]) -> io::Result<Vec<u8>> {
1418    let private: [u8; 32] = private
1419        .try_into()
1420        .map_err(|_| io::Error::other("Invalid key length"))?;
1421    let public: [u8; 32] = public
1422        .try_into()
1423        .map_err(|_| io::Error::other("Invalid key length"))?;
1424    let shared = x25519_dalek::StaticSecret::from(private)
1425        .diffie_hellman(&x25519_dalek::PublicKey::from(public));
1426    if !shared.was_contributory() {
1427        return Err(io::Error::other(
1428            "X25519 produced an all-zero shared secret",
1429        ));
1430    }
1431    Ok(shared.to_bytes().to_vec())
1432}
1433
1434#[cfg(test)]
1435mod tests {
1436    use super::*;
1437
1438    #[test]
1439    fn rsa_generation_rejects_invalid_public_exponents_before_keygen() {
1440        for exponent in [&[0][..], &[1][..], &[2][..], &[1, 0, 2][..]] {
1441            assert!(generate("RSA-PSS", 1024, exponent, "").is_err());
1442        }
1443    }
1444
1445    #[test]
1446    fn asymmetric_export_rejects_incompatible_key_types() {
1447        for (format, key_type) in [("raw", "private"), ("pkcs8", "public"), ("spki", "private")] {
1448            let error = export_key(format, &[], "ECDSA", key_type, "P-256").unwrap_err();
1449            assert!(error.to_string().starts_with("InvalidAccessError:"));
1450        }
1451    }
1452
1453    #[test]
1454    fn rsa_signing_uses_requested_pss_salt_and_pkcs1() {
1455        let pair = generate("RSA-PSS", 1024, &[1, 0, 1], "").unwrap();
1456        let message = b"private RSA signatures use OpenSSL";
1457        let signature = rsa_sign("RSA-PSS", &pair.private, "SHA-256", 32, message).unwrap();
1458        assert!(rsa_verify("RSA-PSS", &pair.public, "SHA-256", 32, message, &signature).unwrap());
1459        assert!(!rsa_verify("RSA-PSS", &pair.public, "SHA-256", 20, message, &signature).unwrap());
1460        let signature =
1461            rsa_sign("RSASSA-PKCS1-V1_5", &pair.private, "SHA-256", 0, message).unwrap();
1462        assert!(
1463            rsa_verify(
1464                "RSASSA-PKCS1-V1_5",
1465                &pair.public,
1466                "SHA-256",
1467                0,
1468                message,
1469                &signature
1470            )
1471            .unwrap()
1472        );
1473    }
1474}