Skip to main content

httpsig/crypto/
asymmetric.rs

1use super::AlgorithmName;
2use crate::{
3  error::{HttpSigError, HttpSigResult},
4  trace::*,
5};
6use ecdsa::{
7  elliptic_curve::{sec1::ToEncodedPoint, PublicKey as EcPublicKey, SecretKey as EcSecretKey},
8  signature::{DigestSigner, DigestVerifier},
9};
10use ed25519_compact::{PublicKey as Ed25519PublicKey, SecretKey as Ed25519SecretKey};
11use p256::NistP256;
12use p384::NistP384;
13use pkcs8::{der::Decode, Document, PrivateKeyInfo};
14use sha2::{Digest, Sha256, Sha384};
15use spki::SubjectPublicKeyInfoRef;
16
17#[cfg(feature = "rsa-signature")]
18use rsa::{
19  pkcs1::{DecodeRsaPrivateKey, DecodeRsaPublicKey, EncodeRsaPublicKey},
20  pkcs1v15, pss,
21  signature::{Keypair, RandomizedSigner, SignatureEncoding, Verifier},
22  RsaPrivateKey, RsaPublicKey,
23};
24
25#[allow(non_upper_case_globals, dead_code)]
26/// Algorithm OIDs
27mod algorithm_oids {
28  /// OID for `id-ecPublicKey`, if you're curious
29  pub const EC: &str = "1.2.840.10045.2.1";
30  /// OID for `id-Ed25519`, if you're curious
31  pub const Ed25519: &str = "1.3.101.112";
32  #[cfg(feature = "rsa-signature")]
33  /// OID for `id-rsaEncryption`, if you're curious
34  pub const rsaEncryption: &str = "1.2.840.113549.1.1.1";
35}
36#[allow(non_upper_case_globals, dead_code)]
37/// Params OIDs
38mod params_oids {
39  // OID for the NIST P-256 elliptic curve.
40  pub const Secp256r1: &str = "1.2.840.10045.3.1.7";
41  // OID for the NIST P-384 elliptic curve.
42  pub const Secp384r1: &str = "1.3.132.0.34";
43}
44
45/* -------------------------------- */
46#[derive(Debug, Clone)]
47/// Secret key for http signature
48/// Name conventions follow [Section-6.2.2, RFC9421](https://datatracker.ietf.org/doc/html/rfc9421#section-6.2.2)
49pub enum SecretKey {
50  /// ecdsa-p384-sha384
51  EcdsaP384Sha384(EcSecretKey<NistP384>),
52  /// ecdsa-p256-sha256
53  EcdsaP256Sha256(EcSecretKey<NistP256>),
54  /// ed25519
55  Ed25519(Ed25519SecretKey),
56  #[cfg(feature = "rsa-signature")]
57  /// rsa-v1_5-sha256
58  RsaV1_5Sha256(pkcs1v15::SigningKey<rsa::sha2::Sha256>),
59  #[cfg(feature = "rsa-signature")]
60  RsaPssSha512(pss::SigningKey<rsa::sha2::Sha512>),
61}
62
63impl SecretKey {
64  /// from plain bytes
65  pub fn from_bytes(alg: &AlgorithmName, bytes: &[u8]) -> HttpSigResult<Self> {
66    match alg {
67      AlgorithmName::EcdsaP256Sha256 => {
68        debug!("Read P256 private key");
69        let sk = EcSecretKey::from_bytes(bytes.into()).map_err(|e| HttpSigError::ParsePrivateKeyError(e.to_string()))?;
70        Ok(Self::EcdsaP256Sha256(sk))
71      }
72      AlgorithmName::EcdsaP384Sha384 => {
73        debug!("Read P384 private key");
74        let sk = EcSecretKey::from_bytes(bytes.into()).map_err(|e| HttpSigError::ParsePrivateKeyError(e.to_string()))?;
75        Ok(Self::EcdsaP384Sha384(sk))
76      }
77      AlgorithmName::Ed25519 => {
78        debug!("Read Ed25519 private key");
79        let mut seed = [0u8; 32];
80        seed.copy_from_slice(bytes);
81        let sk = ed25519_compact::KeyPair::from_seed(ed25519_compact::Seed::new(seed)).sk;
82        Ok(Self::Ed25519(sk))
83      }
84      #[cfg(feature = "rsa-signature")]
85      AlgorithmName::RsaV1_5Sha256 => {
86        debug!("Read RSA private key");
87        // read PrivateKeyInfo.private_key as RsaPrivateKey (RFC 3447), which is DER encoded RSAPrivateKey in PKCS#1
88        let sk = RsaPrivateKey::from_pkcs1_der(bytes).map_err(|e| HttpSigError::ParsePrivateKeyError(e.to_string()))?;
89        Ok(Self::RsaV1_5Sha256(pkcs1v15::SigningKey::<rsa::sha2::Sha256>::new(sk)))
90      }
91      #[cfg(feature = "rsa-signature")]
92      AlgorithmName::RsaPssSha512 => {
93        debug!("Read RSA-PSS private key");
94        // read PrivateKeyInfo.private_key as RsaPrivateKey (RFC 3447), which is DER encoded RSAPrivateKey in PKCS#1
95        let sk = RsaPrivateKey::from_pkcs1_der(bytes).map_err(|e| HttpSigError::ParsePrivateKeyError(e.to_string()))?;
96        Ok(Self::RsaPssSha512(pss::SigningKey::<rsa::sha2::Sha512>::new(sk)))
97      }
98      _ => Err(HttpSigError::ParsePrivateKeyError("Unsupported algorithm".to_string())),
99    }
100  }
101  /// parse der
102  /// Derive secret key from der bytes
103  pub fn from_der(alg: &AlgorithmName, der: &[u8]) -> HttpSigResult<Self> {
104    let pki = PrivateKeyInfo::from_der(der).map_err(|e| HttpSigError::ParsePrivateKeyError(e.to_string()))?;
105
106    let sk_bytes = match pki.algorithm.oid.to_string().as_ref() {
107      // ec
108      algorithm_oids::EC => {
109        let param = pki
110          .algorithm
111          .parameters_oid()
112          .map_err(|e| HttpSigError::ParsePrivateKeyError(e.to_string()))?;
113        let algorithm_name = match param.to_string().as_ref() {
114          params_oids::Secp256r1 => AlgorithmName::EcdsaP256Sha256,
115          params_oids::Secp384r1 => AlgorithmName::EcdsaP384Sha384,
116          _ => return Err(HttpSigError::ParsePrivateKeyError("Unsupported curve".to_string())),
117        };
118        // assert algorithm
119        if algorithm_name != *alg {
120          return Err(HttpSigError::ParsePrivateKeyError("Algorithm mismatch".to_string()));
121        }
122        let sk_bytes = sec1::EcPrivateKey::try_from(pki.private_key)
123          .map_err(|e| HttpSigError::ParsePrivateKeyError(format!("Error decoding EcPrivateKey: {e}")))?
124          .private_key;
125        sk_bytes
126      }
127      // ed25519
128      algorithm_oids::Ed25519 => {
129        // assert algorithm
130        if AlgorithmName::Ed25519 != *alg {
131          return Err(HttpSigError::ParsePrivateKeyError("Algorithm mismatch".to_string()));
132        }
133        &pki.private_key[2..]
134      }
135      // rsa
136      #[cfg(feature = "rsa-signature")]
137      algorithm_oids::rsaEncryption => {
138        // assert algorithm
139        match alg {
140          AlgorithmName::RsaV1_5Sha256 | AlgorithmName::RsaPssSha512 => {}
141          _ => return Err(HttpSigError::ParsePrivateKeyError("Algorithm mismatch".to_string())),
142        }
143        pki.private_key
144      }
145      _ => return Err(HttpSigError::ParsePrivateKeyError("Unsupported algorithm".to_string())),
146    };
147    let sk = Self::from_bytes(alg, sk_bytes)?;
148    Ok(sk)
149  }
150
151  /// Derive secret key from pem string
152  pub fn from_pem(alg: &AlgorithmName, pem: &str) -> HttpSigResult<Self> {
153    let (tag, doc) = Document::from_pem(pem).map_err(|e| HttpSigError::ParsePrivateKeyError(e.to_string()))?;
154    if tag != "PRIVATE KEY" {
155      return Err(HttpSigError::ParsePrivateKeyError("Invalid tag".to_string()));
156    };
157    Self::from_der(alg, doc.as_bytes())
158  }
159
160  /// Get public key from secret key
161  pub fn public_key(&self) -> PublicKey {
162    match &self {
163      Self::EcdsaP256Sha256(key) => PublicKey::EcdsaP256Sha256(key.public_key()),
164      Self::EcdsaP384Sha384(key) => PublicKey::EcdsaP384Sha384(key.public_key()),
165      Self::Ed25519(key) => PublicKey::Ed25519(key.public_key()),
166      #[cfg(feature = "rsa-signature")]
167      Self::RsaV1_5Sha256(key) => PublicKey::RsaV1_5Sha256(key.verifying_key()),
168      #[cfg(feature = "rsa-signature")]
169      Self::RsaPssSha512(key) => PublicKey::RsaPssSha512(key.verifying_key()),
170    }
171  }
172}
173
174impl super::SigningKey for SecretKey {
175  /// Sign data
176  fn sign(&self, data: &[u8]) -> HttpSigResult<Vec<u8>> {
177    match &self {
178      Self::EcdsaP256Sha256(sk) => {
179        debug!("Sign EcdsaP256Sha256");
180        let sk = ecdsa::SigningKey::from(sk);
181        let mut digest = <Sha256 as Digest>::new();
182        digest.update(data);
183        let sig: ecdsa::Signature<NistP256> = sk.sign_digest(digest);
184        Ok(sig.to_bytes().to_vec())
185      }
186      Self::EcdsaP384Sha384(sk) => {
187        debug!("Sign EcdsaP384Sha384");
188        let sk = ecdsa::SigningKey::from(sk);
189        let mut digest = <Sha384 as Digest>::new();
190        digest.update(data);
191        let sig: ecdsa::Signature<NistP384> = sk.sign_digest(digest);
192        Ok(sig.to_bytes().to_vec())
193      }
194      Self::Ed25519(sk) => {
195        debug!("Sign Ed25519");
196        let sig = sk.sign(data, Some(ed25519_compact::Noise::default()));
197        Ok(sig.as_ref().to_vec())
198      }
199      #[cfg(feature = "rsa-signature")]
200      Self::RsaV1_5Sha256(sk) => {
201        debug!("Sign RsaV1_5Sha256");
202        let sig = sk.sign_with_rng(&mut rand::rng(), data);
203        Ok(sig.to_vec())
204      }
205      #[cfg(feature = "rsa-signature")]
206      Self::RsaPssSha512(sk) => {
207        debug!("Sign RsaPssSha512");
208        let sig = sk.sign_with_rng(&mut rand::rng(), data);
209        Ok(sig.to_vec())
210      }
211    }
212  }
213
214  fn key_id(&self) -> String {
215    use super::VerifyingKey;
216    self.public_key().key_id()
217  }
218
219  fn alg(&self) -> AlgorithmName {
220    use super::VerifyingKey;
221    self.public_key().alg()
222  }
223}
224
225impl super::VerifyingKey for SecretKey {
226  fn verify(&self, data: &[u8], signature: &[u8]) -> HttpSigResult<()> {
227    self.public_key().verify(data, signature)
228  }
229
230  fn key_id(&self) -> String {
231    self.public_key().key_id()
232  }
233
234  fn alg(&self) -> AlgorithmName {
235    self.public_key().alg()
236  }
237}
238
239/* -------------------------------- */
240#[derive(Debug, Clone)]
241/// Public key for http signature, only for asymmetric algorithm
242/// Name conventions follow [Section 6.2.2, RFC9421](https://datatracker.ietf.org/doc/html/rfc9421#section-6.2.2)
243pub enum PublicKey {
244  /// ecdsa-p256-sha256
245  EcdsaP256Sha256(EcPublicKey<NistP256>),
246  /// ecdsa-p384-sha384
247  EcdsaP384Sha384(EcPublicKey<NistP384>),
248  /// ed25519
249  Ed25519(Ed25519PublicKey),
250  #[cfg(feature = "rsa-signature")]
251  /// rsa-v1_5-sha256
252  RsaV1_5Sha256(pkcs1v15::VerifyingKey<rsa::sha2::Sha256>),
253  #[cfg(feature = "rsa-signature")]
254  /// rsa-pss-sha512
255  RsaPssSha512(pss::VerifyingKey<rsa::sha2::Sha512>),
256}
257
258impl PublicKey {
259  /// from plain bytes
260  pub fn from_bytes(alg: &AlgorithmName, bytes: &[u8]) -> HttpSigResult<Self> {
261    match alg {
262      AlgorithmName::EcdsaP256Sha256 => {
263        debug!("Read P256 public key");
264        let pk = EcPublicKey::from_sec1_bytes(bytes).map_err(|e| HttpSigError::ParsePublicKeyError(e.to_string()))?;
265        Ok(Self::EcdsaP256Sha256(pk))
266      }
267      AlgorithmName::EcdsaP384Sha384 => {
268        debug!("Read P384 public key");
269        let pk = EcPublicKey::from_sec1_bytes(bytes).map_err(|e| HttpSigError::ParsePublicKeyError(e.to_string()))?;
270        Ok(Self::EcdsaP384Sha384(pk))
271      }
272      AlgorithmName::Ed25519 => {
273        debug!("Read Ed25519 public key");
274        let pk = ed25519_compact::PublicKey::from_slice(bytes).map_err(|e| HttpSigError::ParsePublicKeyError(e.to_string()))?;
275        Ok(Self::Ed25519(pk))
276      }
277      #[cfg(feature = "rsa-signature")]
278      AlgorithmName::RsaV1_5Sha256 => {
279        debug!("Read RSA public key");
280        // read RsaPublicKey in PKCS#1 DER format
281        let pk = RsaPublicKey::from_pkcs1_der(bytes).map_err(|e| HttpSigError::ParsePublicKeyError(e.to_string()))?;
282        Ok(Self::RsaV1_5Sha256(pkcs1v15::VerifyingKey::new(pk)))
283      }
284      #[cfg(feature = "rsa-signature")]
285      AlgorithmName::RsaPssSha512 => {
286        debug!("Read RSA-PSS public key");
287        // read RsaPublicKey in PKCS#1 DER format
288        let pk = RsaPublicKey::from_pkcs1_der(bytes).map_err(|e| HttpSigError::ParsePublicKeyError(e.to_string()))?;
289        Ok(Self::RsaPssSha512(pss::VerifyingKey::new(pk)))
290      }
291      _ => Err(HttpSigError::ParsePublicKeyError("Unsupported algorithm".to_string())),
292    }
293  }
294
295  #[allow(dead_code)]
296  /// Convert from pem string
297  pub fn from_pem(alg: &AlgorithmName, pem: &str) -> HttpSigResult<Self> {
298    let (tag, doc) = Document::from_pem(pem).map_err(|e| HttpSigError::ParsePublicKeyError(e.to_string()))?;
299    if tag != "PUBLIC KEY" {
300      return Err(HttpSigError::ParsePublicKeyError("Invalid tag".to_string()));
301    };
302
303    let spki_ref = SubjectPublicKeyInfoRef::from_der(doc.as_bytes())
304      .map_err(|e| HttpSigError::ParsePublicKeyError(format!("Error decoding SubjectPublicKeyInfo: {e}").to_string()))?;
305
306    let pk_bytes = match spki_ref.algorithm.oid.to_string().as_ref() {
307      // ec
308      algorithm_oids::EC => {
309        let param = spki_ref
310          .algorithm
311          .parameters_oid()
312          .map_err(|e| HttpSigError::ParsePublicKeyError(e.to_string()))?;
313        let algorithm_name = match param.to_string().as_ref() {
314          params_oids::Secp256r1 => AlgorithmName::EcdsaP256Sha256,
315          params_oids::Secp384r1 => AlgorithmName::EcdsaP384Sha384,
316          _ => return Err(HttpSigError::ParsePublicKeyError("Unsupported curve".to_string())),
317        };
318        // assert algorithm
319        if algorithm_name != *alg {
320          return Err(HttpSigError::ParsePublicKeyError("Algorithm mismatch".to_string()));
321        }
322        spki_ref
323          .subject_public_key
324          .as_bytes()
325          .ok_or(HttpSigError::ParsePublicKeyError("Invalid public key".to_string()))?
326      }
327      // ed25519
328      algorithm_oids::Ed25519 => {
329        // assert algorithm
330        if AlgorithmName::Ed25519 != *alg {
331          return Err(HttpSigError::ParsePublicKeyError("Algorithm mismatch".to_string()));
332        }
333        spki_ref
334          .subject_public_key
335          .as_bytes()
336          .ok_or(HttpSigError::ParsePublicKeyError("Invalid public key".to_string()))?
337      }
338      // rsa
339      #[cfg(feature = "rsa-signature")]
340      algorithm_oids::rsaEncryption => {
341        match alg {
342          AlgorithmName::RsaV1_5Sha256 | AlgorithmName::RsaPssSha512 => {}
343          _ => return Err(HttpSigError::ParsePublicKeyError("Algorithm mismatch".to_string())),
344        }
345        spki_ref
346          .subject_public_key
347          .as_bytes()
348          .ok_or(HttpSigError::ParsePublicKeyError("Invalid public key".to_string()))?
349      }
350      _ => return Err(HttpSigError::ParsePublicKeyError("Unsupported algorithm".to_string())),
351    };
352    Self::from_bytes(alg, pk_bytes)
353  }
354}
355
356impl super::VerifyingKey for PublicKey {
357  /// Verify signature
358  fn verify(&self, data: &[u8], signature: &[u8]) -> HttpSigResult<()> {
359    match self {
360      Self::EcdsaP256Sha256(pk) => {
361        debug!("Verify EcdsaP256Sha256");
362        let signature = ecdsa::Signature::<NistP256>::from_bytes(signature.into())
363          .map_err(|e| HttpSigError::ParseSignatureError(e.to_string()))?;
364        let vk = ecdsa::VerifyingKey::from(pk);
365        let mut digest = <Sha256 as Digest>::new();
366        digest.update(data);
367        vk.verify_digest(digest, &signature)
368          .map_err(|e| HttpSigError::InvalidSignature(e.to_string()))
369      }
370      Self::EcdsaP384Sha384(pk) => {
371        debug!("Verify EcdsaP384Sha384");
372        let signature = ecdsa::Signature::<NistP384>::from_bytes(signature.into())
373          .map_err(|e| HttpSigError::ParseSignatureError(e.to_string()))?;
374        let vk = ecdsa::VerifyingKey::from(pk);
375        let mut digest = <Sha384 as Digest>::new();
376        digest.update(data);
377        vk.verify_digest(digest, &signature)
378          .map_err(|e| HttpSigError::InvalidSignature(e.to_string()))
379      }
380      Self::Ed25519(pk) => {
381        debug!("Verify Ed25519");
382        let sig =
383          ed25519_compact::Signature::from_slice(signature).map_err(|e| HttpSigError::ParseSignatureError(e.to_string()))?;
384        pk.verify(data, &sig)
385          .map_err(|e| HttpSigError::InvalidSignature(e.to_string()))
386      }
387      #[cfg(feature = "rsa-signature")]
388      Self::RsaV1_5Sha256(pk) => {
389        debug!("Verify RsaV1_5Sha256");
390        let sig = pkcs1v15::Signature::try_from(signature).map_err(|e| HttpSigError::ParseSignatureError(e.to_string()))?;
391        pk.verify(data, &sig)
392          .map_err(|e| HttpSigError::InvalidSignature(e.to_string()))
393      }
394      #[cfg(feature = "rsa-signature")]
395      Self::RsaPssSha512(pk) => {
396        debug!("Verify RsaPssSha512");
397        let sig = pss::Signature::try_from(signature).map_err(|e| HttpSigError::ParseSignatureError(e.to_string()))?;
398        pk.verify(data, &sig)
399          .map_err(|e| HttpSigError::InvalidSignature(e.to_string()))
400      }
401    }
402  }
403
404  /// Create key id, created by SHA-256 hash of the public key bytes, then encoded in base64
405  /// - For ECDSA keys, use the uncompressed SEC1 encoding of the public key point as the byte representation.
406  /// - For Ed25519 keys, use the raw 32-byte public key.
407  /// - For RSA keys, use the DER encoding of the RSAPublicKey structure in PKCS#1 format.
408  fn key_id(&self) -> String {
409    use base64::{engine::general_purpose, Engine as _};
410
411    let bytes = match self {
412      Self::EcdsaP256Sha256(vk) => vk.to_encoded_point(true).as_bytes().to_vec(),
413      Self::EcdsaP384Sha384(vk) => vk.to_encoded_point(true).as_bytes().to_vec(),
414      Self::Ed25519(vk) => vk.as_ref().to_vec(),
415      #[cfg(feature = "rsa-signature")]
416      Self::RsaV1_5Sha256(vk) => vk
417        .as_ref()
418        .to_pkcs1_der()
419        .map(|der| der.as_bytes().to_vec())
420        .unwrap_or(b"rsa-der-serialization-failed".to_vec()),
421      #[cfg(feature = "rsa-signature")]
422      Self::RsaPssSha512(vk) => vk
423        .as_ref()
424        .to_pkcs1_der()
425        .map(|der| der.as_bytes().to_vec())
426        .unwrap_or(b"rsa-der-serialization-failed".to_vec()),
427    };
428    let mut hasher = <Sha256 as Digest>::new();
429    hasher.update(&bytes);
430    let hash = hasher.finalize();
431    general_purpose::STANDARD.encode(hash)
432  }
433
434  /// Get the algorithm name
435  fn alg(&self) -> AlgorithmName {
436    match self {
437      Self::EcdsaP256Sha256(_) => AlgorithmName::EcdsaP256Sha256,
438      Self::EcdsaP384Sha384(_) => AlgorithmName::EcdsaP384Sha384,
439      Self::Ed25519(_) => AlgorithmName::Ed25519,
440      #[cfg(feature = "rsa-signature")]
441      Self::RsaV1_5Sha256(_) => AlgorithmName::RsaV1_5Sha256,
442      #[cfg(feature = "rsa-signature")]
443      Self::RsaPssSha512(_) => AlgorithmName::RsaPssSha512,
444    }
445  }
446}
447
448#[cfg(test)]
449mod tests {
450  use p256::elliptic_curve::group::GroupEncoding;
451
452  use super::*;
453  use std::matches;
454
455  const P256_SECRET_KEY: &str = r##"-----BEGIN PRIVATE KEY-----
456MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgv7zxW56ojrWwmSo1
4574uOdbVhUfj9Jd+5aZIB9u8gtWnihRANCAARGYsMe0CT6pIypwRvoJlLNs4+cTh2K
458L7fUNb5i6WbKxkpAoO+6T3pMBG5Yw7+8NuGTvvtrZAXduA2giPxQ8zCf
459-----END PRIVATE KEY-----
460"##;
461  const P256_PUBLIC_KEY: &str = r##"-----BEGIN PUBLIC KEY-----
462MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERmLDHtAk+qSMqcEb6CZSzbOPnE4d
463ii+31DW+YulmysZKQKDvuk96TARuWMO/vDbhk777a2QF3bgNoIj8UPMwnw==
464-----END PUBLIC KEY-----
465"##;
466  const P384_SECRET_KEY: &str = r##"-----BEGIN PRIVATE KEY-----
467MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDCPYbeLLlIQKUzVyVGH
468MeuFp/9o2Lr+4GrI3bsbHuViMMceiuM+8xqzFCSm4Ltl5UyhZANiAARKg3yM+Ltx
469n4ZptF3hI6Q167crEtPRklCEsRTyWUqy+VrrnM5LU/+fqxVbyniBZHd4vmQVYtjF
470xsv8P3DpjvpKJZqFfVdIr2ZR+kYDKHwIruIF9fCPawAH2tnbuc3xEzQ=
471-----END PRIVATE KEY-----
472"##;
473  const P384_PUBLIC_KEY: &str = r##"-----BEGIN PUBLIC KEY-----
474MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAESoN8jPi7cZ+GabRd4SOkNeu3KxLT0ZJQ
475hLEU8llKsvla65zOS1P/n6sVW8p4gWR3eL5kFWLYxcbL/D9w6Y76SiWahX1XSK9m
476UfpGAyh8CK7iBfXwj2sAB9rZ27nN8RM0
477-----END PUBLIC KEY-----
478"##;
479
480  const EDDSA_SECRET_KEY: &str = r##"-----BEGIN PRIVATE KEY-----
481MC4CAQAwBQYDK2VwBCIEIDSHAE++q1BP7T8tk+mJtS+hLf81B0o6CFyWgucDFN/C
482-----END PRIVATE KEY-----
483"##;
484  const EDDSA_PUBLIC_KEY: &str = r##"-----BEGIN PUBLIC KEY-----
485MCowBQYDK2VwAyEA1ixMQcxO46PLlgQfYS46ivFd+n0CcDHSKUnuhm3i1O0=
486-----END PUBLIC KEY-----
487"##;
488
489  #[cfg(feature = "rsa-signature")]
490  const RSA2048_SECRET_KEY: &str = r##"-----BEGIN PRIVATE KEY-----
491MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCrjtdIxemmmL9V
492wfp7qqwytfRDZqQM6XNWcAi3x+j5dHFFIKKWQktJ7eCTRYQrBwjQs5sb0ieNUYwQ
493vTIH53z9PqKl1bCIk/6Pago2JNBQAUP9DSs+zcYYC1TYwPM12mxIqz6tHVBabBuG
49449OoqWGgU4J5YkXvjyNFPVK1+dePLalm4/jUJb4VpbppN5NQ9qaqRTB3vQPW9i3D
495uy2hefxh7FGfKx9BwrtKcV4JmjN9IjPpdjZTex/8GF3eIiePkHIJS88w8lkC4F03
49606EuaMRs6KyWpj1aof+LvMG6iIRAigc0K//4tTwfKALRky4tW9JAYe3cFACDulu2
497VXKGatq1AgMBAAECggEAH/cOb9XIci0VwXHSLQag7RXv/Dr8qBc7UUiwpyWNaCVl
498EX9CLAMQKiczZ91VAftejhxY8zcV/YPLODc4QjbEmB76iTGmodwJW0lju7DiS3Xg
4996B5zB1Gp7kL2PSi+aDNZZ7TYicLjfOWVv21lu5BLy2aj8d/4rekapkUFyzhRDLEk
500E9/mvztCrLjLXMS6SFXY/rjfwckBT/tACbmgHInzRcoyX75FYyGtOc3w1S1tXEM8
5017j/7EHZf+mNcHlpV5OMw+StVfl1Qwx8eJ9ZW1TmZEoysRe4zj/ej7+wTBSAC7AoA
502UVB6G8hVU1NP+KD7Z9/6SvfJGvj8yR1HdBE5BZ54JQKBgQDfkpDEH4EH0pRSd867
503nrijAwnqd4xdP11aOwgrrppxavUWAmd3vmki8k4O3ghkz8MtNd+bTcZNKcl4ioS3
504boFA++wZQuzPBu6dbwlM9QX0VyzKAmGITrcnFrxCk3k8d6r9DzTVrzY8oK7nvo+1
505n9QYtlBs/SyJZl4McEOCV0fsowKBgQDEcO6KkwQPt//Qm6Qb1ImrQQ1kgvOu77iG
506R5Gn/FkURJvy+I4g9ANRXmHFTcdMSIS3dzY5Zr4kwa0UYJ/ivQ5QYwzYISiW3kgj
507jmoLhxfWOXaO+vGNBXoZb5JkKrT2pnLlbbeiHaur6jfg20T2w2whts4vJ8aI6V3k
508HagrXuz4xwKBgQDWhMhZFq109w4QTxrTFYmuCAVkr07ETj9hi5DccQ2J1AnUE3x5
509/f7dZEeXpl3BdUSeRboHR0oF0hmZirerVeG5m7+/wWJ9hvY/o0H2UIhlGZxFPKGe
51064B7hiofa2eBqIUtiYC1pAfTho4smMFFkVUuXQiwewBX2hxVrQZpsxu1JwKBgEwH
511fXuqvPase1ks9A5Fa2cZzWoqeNArPdrS1mAS/hMnHsiiRLgiWSpkAilQGiO/KYas
512oBMFXfBx+WAaqacjDugz/eOkqcYCkB8a3pZJmgMyyF08aMLw7LntgdY85T9VWsDL
513fzhCjZADHc9sbjunlTFTRGfh2ChjUhCZHd5zZfo/AoGBANk7kXrHZlAsmEEoeA8R
514yVpIaTIu64SzCsn4lWzh02zuSB20uNzYdNYBkHT/JHMvV4ctxjAXjDWI8aYzHaHY
515KDYy4jUp2TeTPBpqwS24KzFaFx0y2U99TWrzt6sQJr7Y9NlR7S0znc/L7wwFobjr
516XVdlU40OaPP7xs0er/tWVAPY
517-----END PRIVATE KEY-----"##;
518
519  #[cfg(feature = "rsa-signature")]
520  const RSA2048_PUBLIC_KEY: &str = r##"-----BEGIN PUBLIC KEY-----
521MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq47XSMXpppi/VcH6e6qs
522MrX0Q2akDOlzVnAIt8fo+XRxRSCilkJLSe3gk0WEKwcI0LObG9InjVGMEL0yB+d8
523/T6ipdWwiJP+j2oKNiTQUAFD/Q0rPs3GGAtU2MDzNdpsSKs+rR1QWmwbhuPTqKlh
524oFOCeWJF748jRT1StfnXjy2pZuP41CW+FaW6aTeTUPamqkUwd70D1vYtw7stoXn8
525YexRnysfQcK7SnFeCZozfSIz6XY2U3sf/Bhd3iInj5ByCUvPMPJZAuBdN9OhLmjE
526bOislqY9WqH/i7zBuoiEQIoHNCv/+LU8HygC0ZMuLVvSQGHt3BQAg7pbtlVyhmra
527tQIDAQAB
528-----END PUBLIC KEY-----"##;
529
530  #[test]
531  fn test_from_bytes() {
532    let ed25519_kp = ed25519_compact::KeyPair::from_seed(ed25519_compact::Seed::default());
533    let ed25519_sk = ed25519_kp.sk.seed().to_vec();
534    let ed25519_pk = ed25519_kp.pk.as_ref();
535    let sk = SecretKey::from_bytes(&AlgorithmName::Ed25519, &ed25519_sk).unwrap();
536    assert!(matches!(sk, SecretKey::Ed25519(_)));
537    let pk = PublicKey::from_bytes(&AlgorithmName::Ed25519, ed25519_pk).unwrap();
538    assert!(matches!(pk, PublicKey::Ed25519(_)));
539
540    let mut rng = rand_085::thread_rng();
541    let es256_sk = p256::ecdsa::SigningKey::random(&mut rng);
542    let es256_pk = es256_sk.verifying_key();
543    let sk = SecretKey::from_bytes(&AlgorithmName::EcdsaP256Sha256, es256_sk.to_bytes().as_ref()).unwrap();
544    assert!(matches!(sk, SecretKey::EcdsaP256Sha256(_)));
545    let pk_bytes = es256_pk.as_affine().to_bytes();
546    let pk = PublicKey::from_bytes(&AlgorithmName::EcdsaP256Sha256, pk_bytes.as_ref()).unwrap();
547    assert!(matches!(pk, PublicKey::EcdsaP256Sha256(_)));
548  }
549
550  #[test]
551  fn test_from_pem() {
552    let sk = SecretKey::from_pem(&AlgorithmName::EcdsaP256Sha256, P256_SECRET_KEY).unwrap();
553    assert!(matches!(sk, SecretKey::EcdsaP256Sha256(_)));
554    let pk = PublicKey::from_pem(&AlgorithmName::EcdsaP256Sha256, P256_PUBLIC_KEY).unwrap();
555    assert!(matches!(pk, PublicKey::EcdsaP256Sha256(_)));
556
557    let sk = SecretKey::from_pem(&AlgorithmName::EcdsaP384Sha384, P384_SECRET_KEY).unwrap();
558    assert!(matches!(sk, SecretKey::EcdsaP384Sha384(_)));
559    let pk = PublicKey::from_pem(&AlgorithmName::EcdsaP384Sha384, P384_PUBLIC_KEY).unwrap();
560    assert!(matches!(pk, PublicKey::EcdsaP384Sha384(_)));
561
562    let sk = SecretKey::from_pem(&AlgorithmName::Ed25519, EDDSA_SECRET_KEY).unwrap();
563    assert!(matches!(sk, SecretKey::Ed25519(_)));
564    let pk = PublicKey::from_pem(&AlgorithmName::Ed25519, EDDSA_PUBLIC_KEY).unwrap();
565    assert!(matches!(pk, PublicKey::Ed25519(_)));
566  }
567
568  #[cfg(feature = "rsa-signature")]
569  #[test]
570  fn test_from_pem_rsa() {
571    let sk = SecretKey::from_pem(&AlgorithmName::RsaV1_5Sha256, RSA2048_SECRET_KEY).unwrap();
572    assert!(matches!(sk, SecretKey::RsaV1_5Sha256(_)));
573    let pk = PublicKey::from_pem(&AlgorithmName::RsaV1_5Sha256, RSA2048_PUBLIC_KEY).unwrap();
574    assert!(matches!(pk, PublicKey::RsaV1_5Sha256(_)));
575
576    let sk = SecretKey::from_pem(&AlgorithmName::RsaPssSha512, RSA2048_SECRET_KEY).unwrap();
577    assert!(matches!(sk, SecretKey::RsaPssSha512(_)));
578    let pk = PublicKey::from_pem(&AlgorithmName::RsaPssSha512, RSA2048_PUBLIC_KEY).unwrap();
579    assert!(matches!(pk, PublicKey::RsaPssSha512(_)));
580  }
581
582  #[test]
583  fn test_sign_verify() {
584    use super::super::{SigningKey, VerifyingKey};
585    let sk = SecretKey::from_pem(&AlgorithmName::EcdsaP256Sha256, P256_SECRET_KEY).unwrap();
586    let pk = PublicKey::from_pem(&AlgorithmName::EcdsaP256Sha256, P256_PUBLIC_KEY).unwrap();
587    let data = b"hello world";
588    let signature = sk.sign(data).unwrap();
589    pk.verify(data, &signature).unwrap();
590    assert!(pk.verify(b"hello", &signature).is_err());
591
592    let sk = SecretKey::from_pem(&AlgorithmName::EcdsaP384Sha384, P384_SECRET_KEY).unwrap();
593    let pk = PublicKey::from_pem(&AlgorithmName::EcdsaP384Sha384, P384_PUBLIC_KEY).unwrap();
594    let data = b"hello world";
595    let signature = sk.sign(data).unwrap();
596    pk.verify(data, &signature).unwrap();
597    assert!(pk.verify(b"hello", &signature).is_err());
598
599    let sk = SecretKey::from_pem(&AlgorithmName::Ed25519, EDDSA_SECRET_KEY).unwrap();
600    let pk = PublicKey::from_pem(&AlgorithmName::Ed25519, EDDSA_PUBLIC_KEY).unwrap();
601    let data = b"hello world";
602    let signature = sk.sign(data).unwrap();
603    pk.verify(data, &signature).unwrap();
604    assert!(pk.verify(b"hello", &signature).is_err());
605  }
606
607  #[cfg(feature = "rsa-signature")]
608  #[test]
609  fn test_sign_verify_rsa() {
610    use super::super::{SigningKey, VerifyingKey};
611    let sk = SecretKey::from_pem(&AlgorithmName::RsaV1_5Sha256, RSA2048_SECRET_KEY).unwrap();
612    let pk = PublicKey::from_pem(&AlgorithmName::RsaV1_5Sha256, RSA2048_PUBLIC_KEY).unwrap();
613    let data = b"hello world";
614    let signature = sk.sign(data).unwrap();
615    pk.verify(data, &signature).unwrap();
616    assert!(pk.verify(b"hello", &signature).is_err());
617
618    let sk = SecretKey::from_pem(&AlgorithmName::RsaPssSha512, RSA2048_SECRET_KEY).unwrap();
619    let pk = PublicKey::from_pem(&AlgorithmName::RsaPssSha512, RSA2048_PUBLIC_KEY).unwrap();
620    let data = b"hello world";
621    let signature = sk.sign(data).unwrap();
622    pk.verify(data, &signature).unwrap();
623    assert!(pk.verify(b"hello", &signature).is_err());
624  }
625
626  #[test]
627  fn test_kid() -> HttpSigResult<()> {
628    use super::super::VerifyingKey;
629    let sk = SecretKey::from_pem(&AlgorithmName::EcdsaP256Sha256, P256_SECRET_KEY)?;
630    let pk = PublicKey::from_pem(&AlgorithmName::EcdsaP256Sha256, P256_PUBLIC_KEY)?;
631    assert_eq!(sk.public_key().key_id(), pk.key_id());
632    assert_eq!(pk.key_id(), "k34r3Nqfak67bhJSXTjTRo5tCIr1Bsre1cPoJ3LJ9xE=");
633
634    let sk = SecretKey::from_pem(&AlgorithmName::EcdsaP384Sha384, P384_SECRET_KEY)?;
635    let pk = PublicKey::from_pem(&AlgorithmName::EcdsaP384Sha384, P384_PUBLIC_KEY)?;
636    assert_eq!(sk.public_key().key_id(), pk.key_id());
637    assert_eq!(pk.key_id(), "JluSJKLaQsbGcgg1Ves4FfP/Kf7qS11RT88TvU0eNSo=");
638
639    let sk = SecretKey::from_pem(&AlgorithmName::Ed25519, EDDSA_SECRET_KEY)?;
640    let pk = PublicKey::from_pem(&AlgorithmName::Ed25519, EDDSA_PUBLIC_KEY)?;
641    assert_eq!(sk.public_key().key_id(), pk.key_id());
642    assert_eq!(pk.key_id(), "gjrE7ACMxgzYfFHgabgf4kLTg1eKIdsJ94AiFTFj1is=");
643    Ok(())
644  }
645
646  #[cfg(feature = "rsa-signature")]
647  #[test]
648  fn test_kid_rsa() -> HttpSigResult<()> {
649    use super::super::VerifyingKey;
650    let sk = SecretKey::from_pem(&AlgorithmName::RsaV1_5Sha256, RSA2048_SECRET_KEY)?;
651    let pk = PublicKey::from_pem(&AlgorithmName::RsaV1_5Sha256, RSA2048_PUBLIC_KEY)?;
652    assert_eq!(sk.public_key().key_id(), pk.key_id());
653    assert_eq!(pk.key_id(), "NoJFUyf2XUdhrTK66RlrGEemIlr1tOScYVeNVCv+5Ns=");
654
655    let sk = SecretKey::from_pem(&AlgorithmName::RsaPssSha512, RSA2048_SECRET_KEY)?;
656    let pk = PublicKey::from_pem(&AlgorithmName::RsaPssSha512, RSA2048_PUBLIC_KEY)?;
657    assert_eq!(sk.public_key().key_id(), pk.key_id());
658    assert_eq!(pk.key_id(), "NoJFUyf2XUdhrTK66RlrGEemIlr1tOScYVeNVCv+5Ns="); // same as above nothing changes for RSA
659    Ok(())
660  }
661}