-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Migrate parsing of unencrypted PKCS#8 private keys to Rust
- Loading branch information
Showing
7 changed files
with
305 additions
and
58 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// This file is dual licensed under the terms of the Apache License, Version | ||
// 2.0, and the BSD License. See the LICENSE file in the root of this repository | ||
// for complete details. | ||
|
||
use crate::KeyParsingResult; | ||
|
||
#[derive(asn1::Asn1Read)] | ||
struct DsaPrivateKey<'a> { | ||
version: u8, | ||
p: asn1::BigUint<'a>, | ||
q: asn1::BigUint<'a>, | ||
g: asn1::BigUint<'a>, | ||
pub_key: asn1::BigUint<'a>, | ||
priv_key: asn1::BigUint<'a>, | ||
} | ||
|
||
pub fn parse_pkcs1_private_key( | ||
data: &[u8], | ||
) -> KeyParsingResult<openssl::pkey::PKey<openssl::pkey::Private>> { | ||
let dsa_private_key = asn1::parse_single::<DsaPrivateKey<'_>>(data)?; | ||
if dsa_private_key.version != 0 { | ||
return Err(crate::KeyParsingError::InvalidKey); | ||
} | ||
let dsa = openssl::dsa::Dsa::from_private_components( | ||
openssl::bn::BigNum::from_slice(dsa_private_key.p.as_bytes())?, | ||
openssl::bn::BigNum::from_slice(dsa_private_key.q.as_bytes())?, | ||
openssl::bn::BigNum::from_slice(dsa_private_key.g.as_bytes())?, | ||
openssl::bn::BigNum::from_slice(dsa_private_key.priv_key.as_bytes())?, | ||
openssl::bn::BigNum::from_slice(dsa_private_key.pub_key.as_bytes())?, | ||
)?; | ||
Ok(openssl::pkey::PKey::from_dsa(dsa)?) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
// This file is dual licensed under the terms of the Apache License, Version | ||
// 2.0, and the BSD License. See the LICENSE file in the root of this repository | ||
// for complete details. | ||
|
||
use crate::{KeyParsingError, KeyParsingResult}; | ||
|
||
use cryptography_x509::common::EcParameters; | ||
|
||
// From RFC 5915 Section 3 | ||
#[derive(asn1::Asn1Read)] | ||
pub(crate) struct EcPrivateKey<'a> { | ||
pub(crate) version: u8, | ||
pub(crate) private_key: &'a [u8], | ||
#[explicit(0)] | ||
pub(crate) parameters: Option<EcParameters<'a>>, | ||
#[explicit(1)] | ||
pub(crate) public_key: Option<asn1::BitString<'a>>, | ||
} | ||
|
||
pub(crate) fn ec_params_to_group( | ||
params: &EcParameters<'_>, | ||
) -> KeyParsingResult<openssl::ec::EcGroup> { | ||
match params { | ||
EcParameters::NamedCurve(curve_oid) => { | ||
let curve_nid = match curve_oid { | ||
&cryptography_x509::oid::EC_SECP192R1 => openssl::nid::Nid::X9_62_PRIME192V1, | ||
&cryptography_x509::oid::EC_SECP224R1 => openssl::nid::Nid::SECP224R1, | ||
&cryptography_x509::oid::EC_SECP256R1 => openssl::nid::Nid::X9_62_PRIME256V1, | ||
&cryptography_x509::oid::EC_SECP384R1 => openssl::nid::Nid::SECP384R1, | ||
&cryptography_x509::oid::EC_SECP521R1 => openssl::nid::Nid::SECP521R1, | ||
|
||
&cryptography_x509::oid::EC_SECP256K1 => openssl::nid::Nid::SECP256K1, | ||
|
||
&cryptography_x509::oid::EC_SECT233R1 => openssl::nid::Nid::SECT233R1, | ||
&cryptography_x509::oid::EC_SECT283R1 => openssl::nid::Nid::SECT283R1, | ||
&cryptography_x509::oid::EC_SECT409R1 => openssl::nid::Nid::SECT409R1, | ||
&cryptography_x509::oid::EC_SECT571R1 => openssl::nid::Nid::SECT571R1, | ||
|
||
&cryptography_x509::oid::EC_SECT163R2 => openssl::nid::Nid::SECT163R2, | ||
|
||
&cryptography_x509::oid::EC_SECT163K1 => openssl::nid::Nid::SECT163K1, | ||
&cryptography_x509::oid::EC_SECT233K1 => openssl::nid::Nid::SECT233K1, | ||
&cryptography_x509::oid::EC_SECT283K1 => openssl::nid::Nid::SECT283K1, | ||
&cryptography_x509::oid::EC_SECT409K1 => openssl::nid::Nid::SECT409K1, | ||
&cryptography_x509::oid::EC_SECT571K1 => openssl::nid::Nid::SECT571K1, | ||
|
||
#[cfg(not(CRYPTOGRAPHY_IS_BORINGSSL))] | ||
&cryptography_x509::oid::EC_BRAINPOOLP256R1 => openssl::nid::Nid::BRAINPOOL_P256R1, | ||
#[cfg(not(CRYPTOGRAPHY_IS_BORINGSSL))] | ||
&cryptography_x509::oid::EC_BRAINPOOLP384R1 => openssl::nid::Nid::BRAINPOOL_P384R1, | ||
#[cfg(not(CRYPTOGRAPHY_IS_BORINGSSL))] | ||
&cryptography_x509::oid::EC_BRAINPOOLP512R1 => openssl::nid::Nid::BRAINPOOL_P512R1, | ||
|
||
_ => return Err(KeyParsingError::UnsupportedEllipticCurve(curve_oid.clone())), | ||
}; | ||
|
||
Ok(openssl::ec::EcGroup::from_curve_name(curve_nid) | ||
.map_err(|_| KeyParsingError::UnsupportedEllipticCurve(curve_oid.clone()))?) | ||
} | ||
EcParameters::ImplicitCurve(_) | EcParameters::SpecifiedCurve(_) => { | ||
Err(KeyParsingError::ExplicitCurveUnsupported) | ||
} | ||
} | ||
} | ||
|
||
pub fn parse_pkcs1_private_key( | ||
data: &[u8], | ||
ec_params: Option<EcParameters<'_>>, | ||
) -> KeyParsingResult<openssl::pkey::PKey<openssl::pkey::Private>> { | ||
let ec_private_key = asn1::parse_single::<EcPrivateKey<'_>>(data)?; | ||
if ec_private_key.version != 1 { | ||
return Err(crate::KeyParsingError::InvalidKey); | ||
} | ||
|
||
let group = match (ec_params, ec_private_key.parameters) { | ||
(Some(outer_params), Some(inner_params)) => { | ||
if outer_params != inner_params { | ||
return Err(crate::KeyParsingError::InvalidKey); | ||
} | ||
ec_params_to_group(&outer_params)? | ||
} | ||
(Some(outer_params), None) => ec_params_to_group(&outer_params)?, | ||
(None, Some(inner_params)) => ec_params_to_group(&inner_params)?, | ||
(None, None) => return Err(crate::KeyParsingError::InvalidKey), | ||
}; | ||
|
||
let private_number = openssl::bn::BigNum::from_slice(ec_private_key.private_key)?; | ||
let mut bn_ctx = openssl::bn::BigNumContext::new()?; | ||
let public_point = if let Some(point_bytes) = ec_private_key.public_key { | ||
openssl::ec::EcPoint::from_bytes(&group, point_bytes.as_bytes(), &mut bn_ctx) | ||
.map_err(|_| crate::KeyParsingError::InvalidKey)? | ||
} else { | ||
let mut public_point = openssl::ec::EcPoint::new(&group)?; | ||
public_point | ||
.mul(&group, group.generator(), &private_number, &bn_ctx) | ||
.map_err(|_| crate::KeyParsingError::InvalidKey)?; | ||
public_point | ||
}; | ||
|
||
let ec_key = | ||
openssl::ec::EcKey::from_private_components(&group, &private_number, &public_point)?; | ||
Ok(openssl::pkey::PKey::from_ec_key(ec_key)?) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
// This file is dual licensed under the terms of the Apache License, Version | ||
// 2.0, and the BSD License. See the LICENSE file in the root of this repository | ||
// for complete details. | ||
|
||
use cryptography_x509::common::{AlgorithmIdentifier, AlgorithmParameters}; | ||
use cryptography_x509::csr::Attributes; | ||
|
||
use crate::{ec, rsa, KeyParsingError, KeyParsingResult}; | ||
|
||
// RFC 5208 Section 5 | ||
#[derive(asn1::Asn1Read)] | ||
struct PrivateKeyInfo<'a> { | ||
version: u8, | ||
algorithm: AlgorithmIdentifier<'a>, | ||
private_key: &'a [u8], | ||
#[implicit(0)] | ||
_attributes: Option<Attributes<'a>>, | ||
} | ||
|
||
pub fn parse_private_key( | ||
data: &[u8], | ||
) -> KeyParsingResult<openssl::pkey::PKey<openssl::pkey::Private>> { | ||
let k = asn1::parse_single::<PrivateKeyInfo<'_>>(data)?; | ||
if k.version != 0 { | ||
return Err(crate::KeyParsingError::InvalidKey); | ||
} | ||
match k.algorithm.params { | ||
AlgorithmParameters::Rsa(_) => rsa::parse_pkcs1_private_key(k.private_key), | ||
AlgorithmParameters::Ec(ec_params) => { | ||
ec::parse_pkcs1_private_key(k.private_key, Some(ec_params)) | ||
} | ||
|
||
AlgorithmParameters::Dsa(dsa_params) => { | ||
let dsa_private_key = openssl::bn::BigNum::from_slice( | ||
asn1::parse_single::<asn1::BigUint<'_>>(k.private_key)?.as_bytes(), | ||
)?; | ||
let p = openssl::bn::BigNum::from_slice(dsa_params.p.as_bytes())?; | ||
let q = openssl::bn::BigNum::from_slice(dsa_params.q.as_bytes())?; | ||
let g = openssl::bn::BigNum::from_slice(dsa_params.g.as_bytes())?; | ||
|
||
let mut bn_ctx = openssl::bn::BigNumContext::new()?; | ||
let mut pub_key = openssl::bn::BigNum::new()?; | ||
pub_key.mod_exp(&g, &dsa_private_key, &p, &mut bn_ctx)?; | ||
|
||
let dsa = | ||
openssl::dsa::Dsa::from_private_components(p, q, g, dsa_private_key, pub_key)?; | ||
Ok(openssl::pkey::PKey::from_dsa(dsa)?) | ||
} | ||
|
||
#[cfg(not(CRYPTOGRAPHY_IS_BORINGSSL))] | ||
AlgorithmParameters::Dh(dh_params) => { | ||
let dh_private_key = openssl::bn::BigNum::from_slice( | ||
asn1::parse_single::<asn1::BigUint<'_>>(k.private_key)?.as_bytes(), | ||
)?; | ||
let p = openssl::bn::BigNum::from_slice(dh_params.p.as_bytes())?; | ||
let g = openssl::bn::BigNum::from_slice(dh_params.g.as_bytes())?; | ||
let q = openssl::bn::BigNum::from_slice(dh_params.q.as_bytes())?; | ||
|
||
let dh = openssl::dh::Dh::from_params(p, g, q)?; | ||
let dh = dh.set_private_key(dh_private_key)?; | ||
Ok(openssl::pkey::PKey::from_dh(dh)?) | ||
} | ||
|
||
#[cfg(not(CRYPTOGRAPHY_IS_BORINGSSL))] | ||
AlgorithmParameters::DhKeyAgreement(dh_params) => { | ||
let dh_private_key = openssl::bn::BigNum::from_slice( | ||
asn1::parse_single::<asn1::BigUint<'_>>(k.private_key)?.as_bytes(), | ||
)?; | ||
let p = openssl::bn::BigNum::from_slice(dh_params.p.as_bytes())?; | ||
let g = openssl::bn::BigNum::from_slice(dh_params.g.as_bytes())?; | ||
|
||
let dh = openssl::dh::Dh::from_pqg(p, None, g)?; | ||
let dh = dh.set_private_key(dh_private_key)?; | ||
Ok(openssl::pkey::PKey::from_dh(dh)?) | ||
} | ||
|
||
AlgorithmParameters::X25519 => Ok(openssl::pkey::PKey::private_key_from_raw_bytes( | ||
asn1::parse_single(k.private_key)?, | ||
openssl::pkey::Id::X25519, | ||
)?), | ||
#[cfg(all(not(CRYPTOGRAPHY_IS_LIBRESSL), not(CRYPTOGRAPHY_IS_BORINGSSL)))] | ||
AlgorithmParameters::X448 => Ok(openssl::pkey::PKey::private_key_from_raw_bytes( | ||
asn1::parse_single(k.private_key)?, | ||
openssl::pkey::Id::X448, | ||
)?), | ||
AlgorithmParameters::Ed25519 => Ok(openssl::pkey::PKey::private_key_from_raw_bytes( | ||
asn1::parse_single(k.private_key)?, | ||
openssl::pkey::Id::ED25519, | ||
)?), | ||
#[cfg(all(not(CRYPTOGRAPHY_IS_LIBRESSL), not(CRYPTOGRAPHY_IS_BORINGSSL)))] | ||
AlgorithmParameters::Ed448 => Ok(openssl::pkey::PKey::private_key_from_raw_bytes( | ||
asn1::parse_single(k.private_key)?, | ||
openssl::pkey::Id::ED448, | ||
)?), | ||
|
||
_ => Err(KeyParsingError::UnsupportedKeyType( | ||
k.algorithm.oid().clone(), | ||
)), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.