Load certificate chain and private key from files This function loads a certificate chain from `cert_path` and a private key from `key_path`. If `password` is provided, it will be used to decrypt an encrypted private key. Returns (certificate_chain, private_key) on success. # Arguments `cert_path` - Path to certificate file (PEM or DER format) `key_path` - Path to private key file (PEM or DER f
(
cert_path: &str,
key_path: &str,
password: Option<&str>,
)
| 1124 | /// - Certificate or key cannot be parsed |
| 1125 | /// - Password is incorrect for encrypted key |
| 1126 | pub(super) fn load_cert_chain_from_file( |
| 1127 | cert_path: &str, |
| 1128 | key_path: &str, |
| 1129 | password: Option<&str>, |
| 1130 | ) -> Result<(Vec<CertificateDer<'static>>, PrivateKeyDer<'static>), Box<dyn core::error::Error>> { |
| 1131 | // Load certificate file - preserve io::Error for errno |
| 1132 | let cert_contents = std::fs::read(cert_path)?; |
| 1133 | |
| 1134 | // Parse certificates (PEM format) |
| 1135 | let mut cert_cursor = std::io::Cursor::new(&cert_contents); |
| 1136 | let certs: Vec<CertificateDer<'static>> = rustls_pemfile::certs(&mut cert_cursor) |
| 1137 | .collect::<Result<Vec<_>, _>>() |
| 1138 | .map_err(cert_error::pem::parse_failed)?; |
| 1139 | |
| 1140 | if certs.is_empty() { |
| 1141 | return Err(Box::new(cert_error::pem::invalid_cert())); |
| 1142 | } |
| 1143 | |
| 1144 | // Load private key file - preserve io::Error for errno |
| 1145 | let key_contents = std::fs::read(key_path)?; |
| 1146 | |
| 1147 | // Parse private key (supports PKCS8, RSA, EC formats) |
| 1148 | let private_key = if let Some(pwd) = password { |
| 1149 | // Try to parse as encrypted PKCS#8 |
| 1150 | use der::SecretDocument; |
| 1151 | use pkcs8::EncryptedPrivateKeyInfo; |
| 1152 | use rustls::pki_types::{PrivateKeyDer, PrivatePkcs8KeyDer}; |
| 1153 | |
| 1154 | let pem_str = String::from_utf8_lossy(&key_contents); |
| 1155 | |
| 1156 | // Extract just the ENCRYPTED PRIVATE KEY block if present |
| 1157 | // (file may contain multiple PEM blocks like key + certificate) |
| 1158 | let encrypted_key_pem = if let Some(start) = |
| 1159 | pem_str.find("-----BEGIN ENCRYPTED PRIVATE KEY-----") |
| 1160 | { |
| 1161 | if let Some(end_marker) = pem_str[start..].find("-----END ENCRYPTED PRIVATE KEY-----") { |
| 1162 | let end = start + end_marker + "-----END ENCRYPTED PRIVATE KEY-----".len(); |
| 1163 | Some(&pem_str[start..end]) |
| 1164 | } else { |
| 1165 | None |
| 1166 | } |
| 1167 | } else { |
| 1168 | None |
| 1169 | }; |
| 1170 | |
| 1171 | // Try to decode and decrypt PEM-encoded encrypted private key using pkcs8's PEM support |
| 1172 | let decrypted_key_result = if let Some(key_pem) = encrypted_key_pem { |
| 1173 | match SecretDocument::from_pem(key_pem) { |
| 1174 | Ok((label, doc)) => { |
| 1175 | if label == "ENCRYPTED PRIVATE KEY" { |
| 1176 | // Parse encrypted key info from DER |
| 1177 | match EncryptedPrivateKeyInfo::try_from(doc.as_bytes()) { |
| 1178 | Ok(encrypted_key) => { |
| 1179 | // Decrypt with password |
| 1180 | match encrypted_key.decrypt(pwd.as_bytes()) { |
| 1181 | Ok(decrypted) => { |
| 1182 | // Convert decrypted SecretDocument to PrivateKeyDer |
| 1183 | let key_vec: Vec<u8> = decrypted.as_bytes().to_vec(); |
no test coverage detected