Use ecdsa crate for EC point representations
This commit is contained in:
@@ -21,6 +21,7 @@ maintenance = { status = "experimental" }
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
der-parser = "3"
|
der-parser = "3"
|
||||||
des = "0.3"
|
des = "0.3"
|
||||||
|
ecdsa = "0.1"
|
||||||
getrandom = "0.1"
|
getrandom = "0.1"
|
||||||
hmac = "0.7"
|
hmac = "0.7"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
|||||||
+65
-82
@@ -39,35 +39,38 @@ use crate::{
|
|||||||
yubikey::YubiKey,
|
yubikey::YubiKey,
|
||||||
Buffer,
|
Buffer,
|
||||||
};
|
};
|
||||||
|
use ecdsa::{
|
||||||
|
curve::{CompressedCurvePoint, NistP256, NistP384, UncompressedCurvePoint},
|
||||||
|
generic_array::GenericArray,
|
||||||
|
};
|
||||||
use log::error;
|
use log::error;
|
||||||
use rsa::{PublicKey, RSAPublicKey};
|
use rsa::{PublicKey, RSAPublicKey};
|
||||||
|
use std::fmt;
|
||||||
use x509_parser::{parse_x509_der, x509::SubjectPublicKeyInfo};
|
use x509_parser::{parse_x509_der, x509::SubjectPublicKeyInfo};
|
||||||
use zeroize::Zeroizing;
|
use zeroize::Zeroizing;
|
||||||
|
|
||||||
/// An encoded point for some elliptic curve.
|
/// An encoded point on the Nist P-256 curve.
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Eq, PartialEq)]
|
||||||
pub enum EcPoint {
|
pub enum EcP256Point {
|
||||||
/// A point in compressed form.
|
/// Compressed encoding of a point on the curve.
|
||||||
Compressed {
|
Compressed(CompressedCurvePoint<NistP256>),
|
||||||
/// EC algorithm
|
|
||||||
algorithm: AlgorithmId,
|
|
||||||
|
|
||||||
/// Encoded point
|
/// Uncompressed encoding of a point on the curve.
|
||||||
bytes: Buffer,
|
Uncompressed(UncompressedCurvePoint<NistP256>),
|
||||||
},
|
}
|
||||||
|
|
||||||
/// A point in uncompressed form.
|
/// An encoded point on the Nist P-384 curve.
|
||||||
Uncompressed {
|
#[derive(Clone, Eq, PartialEq)]
|
||||||
/// EC algorithm
|
pub enum EcP384Point {
|
||||||
algorithm: AlgorithmId,
|
/// Compressed encoding of a point on the curve.
|
||||||
|
Compressed(CompressedCurvePoint<NistP384>),
|
||||||
|
|
||||||
/// Encoded point
|
/// Uncompressed encoding of a point on the curve.
|
||||||
bytes: Buffer,
|
Uncompressed(UncompressedCurvePoint<NistP384>),
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Information about a public key within a [`Certificate`].
|
/// Information about a public key within a [`Certificate`].
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Eq, PartialEq)]
|
||||||
pub enum PublicKeyInfo {
|
pub enum PublicKeyInfo {
|
||||||
/// RSA keys
|
/// RSA keys
|
||||||
Rsa {
|
Rsa {
|
||||||
@@ -78,8 +81,17 @@ pub enum PublicKeyInfo {
|
|||||||
pubkey: RSAPublicKey,
|
pubkey: RSAPublicKey,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// EC keys
|
/// EC P-256 keys
|
||||||
Ec(EcPoint),
|
EcP256(EcP256Point),
|
||||||
|
|
||||||
|
/// EC P-384 keys
|
||||||
|
EcP384(EcP384Point),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for PublicKeyInfo {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "PublicKeyInfo({:?})", self.algorithm())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PublicKeyInfo {
|
impl PublicKeyInfo {
|
||||||
@@ -100,9 +112,36 @@ impl PublicKeyInfo {
|
|||||||
}
|
}
|
||||||
// EC Public Key
|
// EC Public Key
|
||||||
"1.2.840.10045.2.1" => {
|
"1.2.840.10045.2.1" => {
|
||||||
let algorithm = read_pki::ec_parameters(&subject_pki.algorithm.parameters)?;
|
let key_bytes = &subject_pki.subject_public_key.data;
|
||||||
read_pki::ec_point(algorithm, subject_pki.subject_public_key.data)
|
match read_pki::ec_parameters(&subject_pki.algorithm.parameters)? {
|
||||||
.map(PublicKeyInfo::Ec)
|
AlgorithmId::EccP256 => match key_bytes.len() {
|
||||||
|
33 => CompressedCurvePoint::<NistP256>::from_bytes(
|
||||||
|
GenericArray::clone_from_slice(key_bytes),
|
||||||
|
)
|
||||||
|
.map(EcP256Point::Compressed),
|
||||||
|
65 => UncompressedCurvePoint::<NistP256>::from_bytes(
|
||||||
|
GenericArray::clone_from_slice(key_bytes),
|
||||||
|
)
|
||||||
|
.map(EcP256Point::Uncompressed),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
.map(PublicKeyInfo::EcP256)
|
||||||
|
.ok_or(Error::InvalidObject),
|
||||||
|
AlgorithmId::EccP384 => match key_bytes.len() {
|
||||||
|
49 => CompressedCurvePoint::<NistP384>::from_bytes(
|
||||||
|
GenericArray::clone_from_slice(key_bytes),
|
||||||
|
)
|
||||||
|
.map(EcP384Point::Compressed),
|
||||||
|
97 => UncompressedCurvePoint::<NistP384>::from_bytes(
|
||||||
|
GenericArray::clone_from_slice(key_bytes),
|
||||||
|
)
|
||||||
|
.map(EcP384Point::Uncompressed),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
.map(PublicKeyInfo::EcP384)
|
||||||
|
.ok_or(Error::InvalidObject),
|
||||||
|
_ => Err(Error::AlgorithmError),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => Err(Error::InvalidObject),
|
_ => Err(Error::InvalidObject),
|
||||||
}
|
}
|
||||||
@@ -112,10 +151,8 @@ impl PublicKeyInfo {
|
|||||||
pub fn algorithm(&self) -> AlgorithmId {
|
pub fn algorithm(&self) -> AlgorithmId {
|
||||||
match self {
|
match self {
|
||||||
PublicKeyInfo::Rsa { algorithm, .. } => *algorithm,
|
PublicKeyInfo::Rsa { algorithm, .. } => *algorithm,
|
||||||
PublicKeyInfo::Ec(point) => match point {
|
PublicKeyInfo::EcP256(_) => AlgorithmId::EccP256,
|
||||||
EcPoint::Compressed { algorithm, .. } => *algorithm,
|
PublicKeyInfo::EcP384(_) => AlgorithmId::EccP384,
|
||||||
EcPoint::Uncompressed { algorithm, .. } => *algorithm,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -294,9 +331,7 @@ mod read_pki {
|
|||||||
};
|
};
|
||||||
use nom::{combinator, IResult};
|
use nom::{combinator, IResult};
|
||||||
use rsa::{BigUint, RSAPublicKey};
|
use rsa::{BigUint, RSAPublicKey};
|
||||||
use zeroize::Zeroizing;
|
|
||||||
|
|
||||||
use super::EcPoint;
|
|
||||||
use crate::{error::Error, key::AlgorithmId};
|
use crate::{error::Error, key::AlgorithmId};
|
||||||
|
|
||||||
/// From [RFC 8017](https://tools.ietf.org/html/rfc8017#appendix-A.1.1):
|
/// From [RFC 8017](https://tools.ietf.org/html/rfc8017#appendix-A.1.1):
|
||||||
@@ -356,59 +391,7 @@ mod read_pki {
|
|||||||
match curve_oid.to_string().as_str() {
|
match curve_oid.to_string().as_str() {
|
||||||
"1.2.840.10045.3.1.7" => Ok(AlgorithmId::EccP256),
|
"1.2.840.10045.3.1.7" => Ok(AlgorithmId::EccP256),
|
||||||
"1.3.132.0.34" => Ok(AlgorithmId::EccP384),
|
"1.3.132.0.34" => Ok(AlgorithmId::EccP384),
|
||||||
_ => Err(Error::InvalidObject),
|
_ => Err(Error::AlgorithmError),
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// From [RFC 5480](https://tools.ietf.org/html/rfc5480#section-2.2):
|
|
||||||
/// ```text
|
|
||||||
/// ECPoint ::= OCTET STRING
|
|
||||||
///
|
|
||||||
/// o The first octet of the OCTET STRING indicates whether the key is
|
|
||||||
/// compressed or uncompressed. The uncompressed form is indicated
|
|
||||||
/// by 0x04 and the compressed form is indicated by either 0x02 or
|
|
||||||
/// 0x03 (see 2.3.3 in [SEC1]). The public key MUST be rejected if
|
|
||||||
/// any other value is included in the first octet.
|
|
||||||
/// ```
|
|
||||||
pub(super) fn ec_point(algorithm: AlgorithmId, encoded: &[u8]) -> Result<EcPoint, Error> {
|
|
||||||
if encoded.is_empty() {
|
|
||||||
return Err(Error::InvalidObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
match encoded[0] {
|
|
||||||
0x02 | 0x03 => {
|
|
||||||
if encoded.len()
|
|
||||||
== match algorithm {
|
|
||||||
AlgorithmId::EccP256 => 33,
|
|
||||||
AlgorithmId::EccP384 => 49,
|
|
||||||
_ => return Err(Error::AlgorithmError),
|
|
||||||
}
|
|
||||||
{
|
|
||||||
Ok(EcPoint::Compressed {
|
|
||||||
algorithm,
|
|
||||||
bytes: Zeroizing::new(encoded[1..].to_vec()),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Err(Error::InvalidObject)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
0x04 => {
|
|
||||||
if encoded.len()
|
|
||||||
== match algorithm {
|
|
||||||
AlgorithmId::EccP256 => 65,
|
|
||||||
AlgorithmId::EccP384 => 97,
|
|
||||||
_ => return Err(Error::AlgorithmError),
|
|
||||||
}
|
|
||||||
{
|
|
||||||
Ok(EcPoint::Uncompressed {
|
|
||||||
algorithm,
|
|
||||||
bytes: Zeroizing::new(encoded[1..].to_vec()),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Err(Error::InvalidObject)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => Err(Error::InvalidObject),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user