aws_sdk_cloudfront_url_signer/
key.rs1use crate::error::SigningError;
7use rsa::pkcs1::DecodeRsaPrivateKey;
8use rsa::RsaPrivateKey;
9use sha1::{Digest, Sha1};
10
11use p256::ecdsa::signature::SignatureEncoding;
12#[cfg(feature = "rt-tokio")]
13use std::path::Path;
14
15#[derive(Debug, Clone)]
17pub enum PrivateKey {
18 Rsa(Box<RsaPrivateKey>),
20 Ecdsa(p256::ecdsa::SigningKey),
22}
23
24impl PrivateKey {
25 pub fn from_pem(bytes: &[u8]) -> Result<Self, SigningError> {
29 let pem_str = std::str::from_utf8(bytes).map_err(SigningError::invalid_key)?;
30
31 if pem_str.contains("BEGIN RSA PRIVATE KEY") {
33 let key = RsaPrivateKey::from_pkcs1_pem(pem_str).map_err(SigningError::invalid_key)?;
35 return Ok(PrivateKey::Rsa(Box::new(key)));
36 }
37
38 if pem_str.contains("BEGIN PRIVATE KEY") {
39 if let Ok(key) = p256::ecdsa::SigningKey::from_pkcs8_pem(pem_str) {
42 return Ok(PrivateKey::Ecdsa(key));
43 }
44
45 use p256::pkcs8::DecodePrivateKey;
47 let key = RsaPrivateKey::from_pkcs8_pem(pem_str).map_err(SigningError::invalid_key)?;
48 return Ok(PrivateKey::Rsa(Box::new(key)));
49 }
50
51 Err(SigningError::invalid_key(
52 "Unsupported key format. Expected RSA (PKCS#1 or PKCS#8) or ECDSA P-256 (PKCS#8)",
53 ))
54 }
55
56 #[cfg(feature = "rt-tokio")]
60 #[cfg_attr(docsrs, doc(cfg(feature = "rt-tokio")))]
61 pub async fn from_pem_file(path: impl AsRef<Path>) -> Result<Self, SigningError> {
62 let bytes = tokio::fs::read(path.as_ref())
63 .await
64 .map_err(SigningError::invalid_key)?;
65
66 Self::from_pem(&bytes)
67 }
68
69 pub(crate) fn sign(&self, message: &[u8]) -> Result<Vec<u8>, SigningError> {
70 match self {
71 PrivateKey::Rsa(key) => {
72 let mut hasher = Sha1::new();
73 hasher.update(message);
74 let digest = hasher.finalize();
75
76 let signature = key
77 .sign(rsa::Pkcs1v15Sign::new::<Sha1>(), &digest)
78 .map_err(SigningError::signing_failure)?;
79
80 Ok(signature)
81 }
82 PrivateKey::Ecdsa(key) => {
83 use p256::ecdsa::signature::DigestSigner;
84
85 let mut hasher = Sha1::new();
87 hasher.update(message);
88
89 let (signature, _recovery_id): (p256::ecdsa::Signature, _) = key
90 .try_sign_digest(hasher)
91 .map_err(SigningError::signing_failure)?;
92
93 Ok(signature.to_der().to_vec())
95 }
96 }
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103
104 const TEST_RSA_KEY_PEM: &[u8] = b"-----BEGIN RSA PRIVATE KEY-----
105MIIBPAIBAAJBANW8WjQksUoX/7nwOfRDNt1XQpLCueHoXSt91MASMOSAqpbzZvXO
106g2hW2gCFUIFUPCByMXPoeRe6iUZ5JtjepssCAwEAAQJBALR7ybwQY/lKTLKJrZab
107D4BXCCt/7ZFbMxnftsC+W7UHef4S4qFW8oOOLeYfmyGZK1h44rXf2AIp4PndKUID
1081zECIQD1suunYw5U22Pa0+2dFThp1VMXdVbPuf/5k3HT2/hSeQIhAN6yX0aT/N6G
109gb1XlBKw6GQvhcM0fXmP+bVXV+RtzFJjAiAP+2Z2yeu5u1egeV6gdCvqPnUcNobC
110FmA/NMcXt9xMSQIhALEMMJEFAInNeAIXSYKeoPNdkMPDzGnD3CueuCLEZCevAiEA
111j+KnJ7pJkTvOzFwE8RfNLli9jf6/OhyYaLL4et7Ng5k=
112-----END RSA PRIVATE KEY-----";
113
114 const TEST_ECDSA_KEY_PEM: &[u8] = b"-----BEGIN PRIVATE KEY-----
115MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg4//aTM1/HqiVWagy
11601cAx3EaegJ0Y5KLRoTtub8T8EWhRANCAARV/wa477wYpyWB5LCrCdS5M9bEAvD+
117VORtjoydSpheKlsa+gE4PcFG88G2gE1Lilb8f6wEq/Lz+5kFa2S8gZmb
118-----END PRIVATE KEY-----";
119
120 #[test]
121 fn test_from_pem_invalid() {
122 let result = PrivateKey::from_pem(b"invalid pem data");
123 assert!(result.is_err());
124 }
125
126 #[test]
127 fn test_rsa_key_parsing() {
128 let key = PrivateKey::from_pem(TEST_RSA_KEY_PEM).expect("valid RSA key");
129 assert!(matches!(key, PrivateKey::Rsa(_)));
130 }
131
132 #[test]
133 fn test_ecdsa_key_parsing() {
134 let key = PrivateKey::from_pem(TEST_ECDSA_KEY_PEM).expect("valid ECDSA key");
135 assert!(matches!(key, PrivateKey::Ecdsa(_)));
136 }
137
138 #[test]
139 fn test_rsa_sign() {
140 let key = PrivateKey::from_pem(TEST_RSA_KEY_PEM).expect("valid test key");
141 let message = b"test message";
142 let signature = key.sign(message).expect("signing should succeed");
143 assert!(!signature.is_empty());
144 }
145
146 #[test]
147 fn test_ecdsa_sign() {
148 let key = PrivateKey::from_pem(TEST_ECDSA_KEY_PEM).expect("valid test key");
149 let message = b"test message";
150 let signature = key.sign(message).expect("signing should succeed");
151 assert!(!signature.is_empty());
152 }
153}