Generalize auto-conversion of SEC1 EC keys to PKCS#8. (#618)

Get the key curve from the params of the SEC1 certificate instead of
assuming that it is P256.
This commit is contained in:
Jeffrey Esquivel S. 2025-03-20 04:10:57 -06:00 committed by GitHub
parent 293cfe2664
commit f97af991be
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 54 additions and 22 deletions

3
Cargo.lock generated
View File

@ -834,7 +834,6 @@ dependencies = [
"diesel-async", "diesel-async",
"diesel_migrations", "diesel_migrations",
"dotenv", "dotenv",
"elliptic-curve",
"email_address", "email_address",
"futures", "futures",
"futures-util", "futures-util",
@ -854,7 +853,6 @@ dependencies = [
"mime_guess", "mime_guess",
"oauth2", "oauth2",
"openidconnect", "openidconnect",
"p256",
"pbjson-types", "pbjson-types",
"pbkdf2", "pbkdf2",
"pem", "pem",
@ -878,6 +876,7 @@ dependencies = [
"rustls-native-certs 0.8.1", "rustls-native-certs 0.8.1",
"rustls-pemfile", "rustls-pemfile",
"scoped-futures", "scoped-futures",
"sec1",
"serde", "serde",
"serde_json", "serde_json",
"serde_urlencoded", "serde_urlencoded",

View File

@ -118,8 +118,7 @@
pem = "3.0" pem = "3.0"
x509-parser = "0.16" x509-parser = "0.16"
rsa = "0.9" rsa = "0.9"
elliptic-curve = { version = "0.13", features = ["pem"] } sec1 = { version = "0.7.3", features = ["alloc", "pem", "pkcs8"] }
p256 = "0.13"
rcgen = { version = "0.13.1", features = ["x509-parser"] } rcgen = { version = "0.13.1", features = ["x509-parser"] }
oauth2 = "5.0.0-alpha.4" oauth2 = "5.0.0-alpha.4"
openidconnect = { version = "4.0.0-alpha.2", features = [ openidconnect = { version = "4.0.0-alpha.2", features = [

View File

@ -68,17 +68,34 @@ pub fn private_key_to_pkcs8(pem: &str) -> Result<String> {
let pkcs8_pem = pkey.to_pkcs8_pem(LineEnding::default())?; let pkcs8_pem = pkey.to_pkcs8_pem(LineEnding::default())?;
Ok(pkcs8_pem.as_str().to_owned()) Ok(pkcs8_pem.as_str().to_owned())
} else if pem.contains("EC PRIVATE KEY") { } else if pem.contains("EC PRIVATE KEY") {
use elliptic_curve::{ use sec1::{
pkcs8::{EncodePrivateKey, LineEnding}, der::{Decode, Encode, EncodePem},
SecretKey, pkcs8::{AlgorithmIdentifierRef, PrivateKeyInfo},
EcPrivateKey, LineEnding,
}; };
// We assume it is a P256 based secret-key, which is the most popular curve. // Get a SEC1 ECPrivateKey from the PEM string input
// Attempting to decode it as P256 is still better than just failing to read it. let pem = pem::parse(pem).context("Parse PEM string")?;
let pkey: SecretKey<p256::NistP256> = let pkey =
SecretKey::from_sec1_pem(pem).context("Read EC SEC1")?; EcPrivateKey::from_der(pem.contents()).context("Decode PEM into SEC1 ECPrivateKey")?;
let pkcs8_pem = pkey.to_pkcs8_pem(LineEnding::default())?;
Ok(pkcs8_pem.as_str().to_owned()) // Retrieve the curve name from the decoded private key's parameters
let params_oid = pkey.parameters.and_then(|params| params.named_curve());
// Get the proper types to construct a PKCS#8 PrivateKeyInfo
let private_key = &pkey.to_der()?;
let algorithm = AlgorithmIdentifierRef {
oid: sec1::ALGORITHM_OID,
parameters: params_oid.as_ref().map(Into::into),
};
let pkcs8 = PrivateKeyInfo {
algorithm,
private_key,
public_key: None,
};
Ok(pkcs8.to_pem(LineEnding::default())?)
} else { } else {
Ok(pem.to_string()) Ok(pem.to_string())
} }

View File

@ -71,17 +71,34 @@ pub fn private_key_to_pkcs8(pem: &str) -> Result<String> {
let pkcs8_pem = pkey.to_pkcs8_pem(LineEnding::default())?; let pkcs8_pem = pkey.to_pkcs8_pem(LineEnding::default())?;
Ok(pkcs8_pem.as_str().to_owned()) Ok(pkcs8_pem.as_str().to_owned())
} else if pem.contains("EC PRIVATE KEY") { } else if pem.contains("EC PRIVATE KEY") {
use elliptic_curve::{ use sec1::{
pkcs8::{EncodePrivateKey, LineEnding}, der::{Decode, Encode, EncodePem},
SecretKey, pkcs8::{AlgorithmIdentifierRef, PrivateKeyInfo},
EcPrivateKey, LineEnding,
}; };
// We assume it is a P256 based secret-key, which is the most popular curve. // Get a SEC1 ECPrivateKey from the PEM string input
// Attempting to decode it as P256 is still better than just failing to read it. let pem = pem::parse(pem).context("Parse PEM string")?;
let pkey: SecretKey<p256::NistP256> = let pkey =
SecretKey::from_sec1_pem(pem).context("Read EC SEC1")?; EcPrivateKey::from_der(pem.contents()).context("Decode PEM into SEC1 ECPrivateKey")?;
let pkcs8_pem = pkey.to_pkcs8_pem(LineEnding::default())?;
Ok(pkcs8_pem.as_str().to_owned()) // Retrieve the curve name from the decoded private key's parameters
let params_oid = pkey.parameters.and_then(|params| params.named_curve());
// Get the proper types to construct a PKCS#8 PrivateKeyInfo
let private_key = &pkey.to_der()?;
let algorithm = AlgorithmIdentifierRef {
oid: sec1::ALGORITHM_OID,
parameters: params_oid.as_ref().map(Into::into),
};
let pkcs8 = PrivateKeyInfo {
algorithm,
private_key,
public_key: None,
};
Ok(pkcs8.to_pem(LineEnding::default())?)
} else { } else {
Ok(pem.to_string()) Ok(pem.to_string())
} }