Skip to content

Commit 03f955e

Browse files
committed
tss-esapi: move public keys to rustcrypto ecosystem
Signed-off-by: Arthur Gautier <[email protected]>
1 parent 75e9879 commit 03f955e

File tree

3 files changed

+200
-146
lines changed

3 files changed

+200
-146
lines changed

tss-esapi/Cargo.toml

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,15 @@ hostname-validator = "1.1.0"
2727
regex = "1.3.9"
2828
zeroize = { version = "1.5.7", features = ["zeroize_derive"] }
2929
tss-esapi-sys = { path = "../tss-esapi-sys", version = "0.5.0" }
30-
oid = { version = "0.2.1", optional = true }
31-
picky-asn1 = { version = "0.8.0", optional = true }
32-
picky-asn1-x509 = { version = "0.12.0", optional = true }
30+
x509-cert = { version = "0.2.0", optional = true }
31+
elliptic-curve = { version = "0.13.8", optional = true, features = ["alloc", "pkcs8"] }
32+
p192 = { version = "0.13.0", optional = true }
33+
p224 = { version = "0.13.2", optional = true }
34+
p256 = { version = "0.13.2", optional = true }
35+
p384 = { version = "0.13.0", optional = true }
36+
p521 = { version = "0.13.3", optional = true }
37+
sm2 = { version = "0.13.3", optional = true }
38+
rsa = { version = "0.9", optional = true }
3339
cfg-if = "1.0.0"
3440
strum = { version = "0.25.0", optional = true }
3541
strum_macros = { version = "0.25.0", optional = true }
@@ -47,5 +53,5 @@ semver = "1.0.7"
4753
[features]
4854
default = ["abstraction"]
4955
generate-bindings = ["tss-esapi-sys/generate-bindings"]
50-
abstraction = ["oid", "picky-asn1", "picky-asn1-x509"]
56+
abstraction = ["elliptic-curve", "rsa", "x509-cert", "p192", "p224", "p256", "p384", "p521", "sm2"]
5157
integration-tests = ["strum", "strum_macros"]

tss-esapi/src/abstraction/public.rs

Lines changed: 145 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -6,123 +6,176 @@ use crate::structures::{Public, RsaExponent};
66
use crate::{Error, WrapperErrorKind};
77

88
use core::convert::TryFrom;
9-
use oid::ObjectIdentifier;
10-
use picky_asn1::bit_string::BitString;
11-
use picky_asn1::wrapper::{IntegerAsn1, OctetStringAsn1};
12-
use picky_asn1_x509::{
13-
AlgorithmIdentifier, EcParameters, EcPoint, PublicKey, RsaPublicKey, SubjectPublicKeyInfo,
9+
use elliptic_curve::{
10+
// See TODO below, you're upgrading from 0.13 to 0.14 and
11+
// that moved the implementation from generic-array to
12+
// hybrid-array, you can now use TryFrom
13+
generic_array::typenum::Unsigned,
14+
sec1::{EncodedPoint, FromEncodedPoint, ModulusSize, ToEncodedPoint},
15+
AffinePoint,
16+
CurveArithmetic,
17+
FieldBytesSize,
18+
PublicKey,
1419
};
20+
use rsa::{pkcs8::EncodePublicKey, BigUint, RsaPublicKey};
21+
use x509_cert::spki::SubjectPublicKeyInfoOwned;
1522

16-
/// Can be converted from [`crate::structures::Public`] when not a fully constructed
17-
/// [`picky_asn1_x509::SubjectPublicKeyInfo`] is required.
18-
///
19-
/// # Details
20-
/// Holds either [`picky_asn1_x509::RsaPublicKey`] for [`crate::structures::Public::Rsa`] or
21-
/// [`picky_asn1_x509::EcPoint`] for [`crate::structures::Public::Ecc`].
22-
///
23-
/// This object can be serialized and deserialized
24-
/// using serde if the `serde` feature is enabled.
25-
#[derive(Debug, PartialEq, Eq, Clone)]
26-
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
27-
pub enum DecodedKey {
28-
RsaPublicKey(RsaPublicKey),
29-
EcPoint(EcPoint),
23+
impl<C> TryFrom<&Public> for PublicKey<C>
24+
where
25+
C: CurveArithmetic + AssociatedTpmCurve,
26+
FieldBytesSize<C>: ModulusSize,
27+
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
28+
{
29+
type Error = Error;
30+
31+
fn try_from(value: &Public) -> Result<Self, Self::Error> {
32+
match value {
33+
Public::Ecc {
34+
parameters, unique, ..
35+
} => {
36+
if parameters.ecc_curve() != C::TPM_CURVE {
37+
return Err(Error::local_error(WrapperErrorKind::InvalidParam));
38+
}
39+
40+
let x = unique.x().as_bytes();
41+
let y = unique.y().as_bytes();
42+
43+
// TODO: When elliptic_curve bumps to 0.14, we can use the TryFrom implementation instead
44+
// of checking lengths manually
45+
if x.len() != FieldBytesSize::<C>::USIZE {
46+
return Err(Error::local_error(WrapperErrorKind::InvalidParam));
47+
}
48+
if y.len() != FieldBytesSize::<C>::USIZE {
49+
return Err(Error::local_error(WrapperErrorKind::InvalidParam));
50+
}
51+
52+
let encoded_point =
53+
EncodedPoint::<C>::from_affine_coordinates(x.into(), y.into(), false);
54+
let public_key = PublicKey::<C>::try_from(&encoded_point)
55+
.map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?;
56+
57+
Ok(public_key)
58+
}
59+
_ => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)),
60+
}
61+
}
3062
}
3163

32-
impl TryFrom<Public> for DecodedKey {
64+
impl TryFrom<&Public> for RsaPublicKey {
3365
type Error = Error;
3466

35-
fn try_from(value: Public) -> Result<Self, Self::Error> {
36-
public_to_decoded_key(&value)
67+
fn try_from(value: &Public) -> Result<Self, Self::Error> {
68+
match value {
69+
Public::Rsa {
70+
unique, parameters, ..
71+
} => {
72+
let exponent = match parameters.exponent() {
73+
RsaExponent::ZERO_EXPONENT => BigUint::from(65537u32),
74+
_ => BigUint::from(parameters.exponent().value()),
75+
};
76+
let modulus = BigUint::from_bytes_be(unique.as_bytes());
77+
78+
let public_key = RsaPublicKey::new(modulus, exponent)
79+
.map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?;
80+
81+
Ok(public_key)
82+
}
83+
_ => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)),
84+
}
3785
}
3886
}
3987

40-
impl TryFrom<Public> for SubjectPublicKeyInfo {
88+
impl TryFrom<&Public> for SubjectPublicKeyInfoOwned {
4189
type Error = Error;
4290

43-
/// Converts [`crate::structures::Public::Rsa`] and [`crate::structures::Public::Ecc`] to [`picky_asn1_x509::SubjectPublicKeyInfo`].
91+
/// Converts [`crate::structures::Public::Rsa`] and [`crate::structures::Public::Ecc`] to [`x509_cert::spki::SubjectPublicKeyInfoOwned`].
4492
///
4593
/// # Details
46-
/// The result can be used to convert TPM public keys to DER using `picky_asn1_der`.
94+
/// The result can be used to convert TPM public keys to DER using `x509-cert`.
4795
///
4896
/// # Errors
4997
/// * if other instances of [`crate::structures::Public`] are used `UnsupportedParam` will be returned.
50-
fn try_from(value: Public) -> Result<Self, Self::Error> {
51-
let decoded_key = public_to_decoded_key(&value)?;
52-
53-
match (value, decoded_key) {
54-
(Public::Rsa { .. }, DecodedKey::RsaPublicKey(key)) => Ok(SubjectPublicKeyInfo {
55-
algorithm: AlgorithmIdentifier::new_rsa_encryption(),
56-
subject_public_key: PublicKey::Rsa(key.into()),
57-
}),
58-
(Public::Ecc { parameters, .. }, DecodedKey::EcPoint(point)) => {
59-
Ok(SubjectPublicKeyInfo {
60-
algorithm: AlgorithmIdentifier::new_elliptic_curve(EcParameters::NamedCurve(
61-
curve_oid(parameters.ecc_curve())?.into(),
62-
)),
63-
subject_public_key: PublicKey::Ec(BitString::with_bytes(point).into()),
64-
})
98+
fn try_from(value: &Public) -> Result<Self, Self::Error> {
99+
match value {
100+
Public::Rsa { .. } => {
101+
let public_key = RsaPublicKey::try_from(value)?;
102+
103+
Ok(public_key
104+
.to_public_key_der()
105+
.map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?
106+
.decode_msg::<Self>()
107+
.map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?)
108+
}
109+
#[allow(unused)]
110+
Public::Ecc { parameters, .. } => {
111+
macro_rules! read_key {
112+
($curve:expr, $key_type:ty) => {
113+
if parameters.ecc_curve() == <$key_type>::TPM_CURVE {
114+
let public_key = PublicKey::<$key_type>::try_from(value)?;
115+
116+
return Ok(public_key
117+
.to_public_key_der()
118+
.map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?
119+
.decode_msg::<Self>()
120+
.map_err(|_| {
121+
Error::local_error(WrapperErrorKind::InvalidParam)
122+
})?);
123+
}
124+
};
125+
}
126+
127+
#[cfg(feature = "p192")]
128+
read_key!(EccCurve::NistP192, p192::NistP192);
129+
#[cfg(feature = "p224")]
130+
read_key!(EccCurve::NistP224, p224::NistP224);
131+
#[cfg(feature = "p256")]
132+
read_key!(EccCurve::NistP256, p256::NistP256);
133+
#[cfg(feature = "p384")]
134+
read_key!(EccCurve::NistP384, p384::NistP384);
135+
#[cfg(feature = "p521")]
136+
read_key!(EccCurve::NistP521, p521::NistP521);
137+
#[cfg(feature = "sm2")]
138+
read_key!(EccCurve::Sm2P256, sm2::Sm2);
139+
140+
Err(Error::local_error(WrapperErrorKind::UnsupportedParam))
65141
}
66142
_ => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)),
67143
}
68144
}
69145
}
70146

71-
/// Converts [`crate::structures::Public::Rsa`] and [`crate::structures::Public::Ecc`] to [DecodedKey].
72-
///
73-
/// # Details
74-
/// Does basic key conversion to either RSA or ECC. In RSA conversion the TPM zero exponent is replaced with `65537`.
75-
///
76-
/// # Errors
77-
/// * if other instances of [`crate::structures::Public`] are used `UnsupportedParam` will be returned.
78-
fn public_to_decoded_key(public: &Public) -> Result<DecodedKey, Error> {
79-
match public {
80-
Public::Rsa {
81-
unique, parameters, ..
82-
} => {
83-
let exponent = match parameters.exponent() {
84-
RsaExponent::ZERO_EXPONENT => 65537,
85-
_ => parameters.exponent().value(),
86-
}
87-
.to_be_bytes();
88-
Ok(DecodedKey::RsaPublicKey(RsaPublicKey {
89-
modulus: IntegerAsn1::from_bytes_be_unsigned(unique.as_bytes().to_vec()),
90-
public_exponent: IntegerAsn1::from_bytes_be_signed(exponent.to_vec()),
91-
}))
92-
}
93-
Public::Ecc { unique, .. } => {
94-
let x = unique.x().as_bytes().to_vec();
95-
let y = unique.y().as_bytes().to_vec();
96-
Ok(DecodedKey::EcPoint(OctetStringAsn1(
97-
elliptic_curve_point_to_octet_string(x, y),
98-
)))
99-
}
147+
/// Provides the value of the curve used in this crate for the specific curve.
148+
pub trait AssociatedTpmCurve {
149+
/// Value of the curve when interacting with the TPM.
150+
const TPM_CURVE: EccCurve;
151+
}
100152

101-
_ => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)),
102-
}
153+
#[cfg(feature = "p192")]
154+
impl AssociatedTpmCurve for p192::NistP192 {
155+
const TPM_CURVE: EccCurve = EccCurve::NistP192;
103156
}
104157

105-
// Taken from https://github.com/parallaxsecond/parsec/blob/561235f3cc37bcff3d9a6cb29c84eeae5d55100b/src/providers/tpm/utils.rs#L319
106-
// Points on elliptic curves are represented as defined in section 2.3.3 of https://www.secg.org/sec1-v2.pdf
107-
// The (uncompressed) representation is [ 0x04 || x || y ] where x and y are the coordinates of the point
108-
fn elliptic_curve_point_to_octet_string(mut x: Vec<u8>, mut y: Vec<u8>) -> Vec<u8> {
109-
let mut octet_string = vec![0x04];
110-
octet_string.append(&mut x);
111-
octet_string.append(&mut y);
112-
octet_string
158+
#[cfg(feature = "p224")]
159+
impl AssociatedTpmCurve for p224::NistP224 {
160+
const TPM_CURVE: EccCurve = EccCurve::NistP224;
113161
}
114162

115-
// Map TPM supported ECC curves to their respective OIDs
116-
fn curve_oid(ecc_curve: EccCurve) -> Result<ObjectIdentifier, Error> {
117-
match ecc_curve {
118-
EccCurve::NistP192 => Ok(picky_asn1_x509::oids::secp192r1()),
119-
EccCurve::NistP224 => Ok(picky_asn1_x509::oids::secp256r1()),
120-
EccCurve::NistP256 => Ok(picky_asn1_x509::oids::secp256r1()),
121-
EccCurve::NistP384 => Ok(picky_asn1_x509::oids::secp384r1()),
122-
EccCurve::NistP521 => Ok(picky_asn1_x509::oids::secp521r1()),
123-
// Barreto-Naehrig curves seem to not have any OIDs
124-
EccCurve::BnP256 => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)),
125-
EccCurve::BnP638 => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)),
126-
EccCurve::Sm2P256 => Ok(ObjectIdentifier::try_from("1.2.156.10197.1.301").unwrap()),
127-
}
163+
#[cfg(feature = "p256")]
164+
impl AssociatedTpmCurve for p256::NistP256 {
165+
const TPM_CURVE: EccCurve = EccCurve::NistP256;
166+
}
167+
168+
#[cfg(feature = "p384")]
169+
impl AssociatedTpmCurve for p384::NistP384 {
170+
const TPM_CURVE: EccCurve = EccCurve::NistP384;
171+
}
172+
173+
#[cfg(feature = "p521")]
174+
impl AssociatedTpmCurve for p521::NistP521 {
175+
const TPM_CURVE: EccCurve = EccCurve::NistP521;
176+
}
177+
178+
#[cfg(feature = "sm2")]
179+
impl AssociatedTpmCurve for sm2::Sm2 {
180+
const TPM_CURVE: EccCurve = EccCurve::Sm2P256;
128181
}

0 commit comments

Comments
 (0)