Skip to content

Commit 0ed9891

Browse files
committed
tss-esapi: move public keys to rustcrypto ecosystem
Signed-off-by: Arthur Gautier <arthur.gautier@arista.com>
1 parent 1eaad6b commit 0ed9891

File tree

4 files changed

+264
-146
lines changed

4 files changed

+264
-146
lines changed

tss-esapi/Cargo.toml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,6 @@ hostname-validator = "1.1.0"
3434
regex = "1.3.9"
3535
zeroize = { version = "1.5.7", features = ["zeroize_derive"] }
3636
tss-esapi-sys = { path = "../tss-esapi-sys", version = "0.5.0" }
37-
oid = { version = "0.2.1", optional = true }
38-
picky-asn1 = { version = "0.9.0", optional = true }
39-
picky-asn1-x509 = { version = "0.13.0", optional = true }
4037
x509-cert = { version = "0.2.0", optional = true }
4138
ecdsa = { version = "0.16.9", features = ["der", "hazmat", "arithmetic", "verifying"], optional = true }
4239
elliptic-curve = { version = "0.13.8", optional = true, features = ["alloc", "pkcs8"] }
@@ -45,6 +42,7 @@ p224 = { version = "0.13.2", optional = true }
4542
p256 = { version = "0.13.2", optional = true }
4643
p384 = { version = "0.13.0", optional = true }
4744
p521 = { version = "0.13.3", optional = true }
45+
pkcs8 = { version = "0.10.2", optional = true }
4846
rsa = { version = "0.9", optional = true }
4947
sha1 = { version = "0.10.6", optional = true }
5048
sha2 = { version = "0.10.8", optional = true }
@@ -77,8 +75,8 @@ semver = "1.0.7"
7775
[features]
7876
default = ["abstraction"]
7977
generate-bindings = ["tss-esapi-sys/generate-bindings"]
80-
abstraction = ["oid", "picky-asn1", "picky-asn1-x509"]
78+
abstraction = ["rustcrypto"]
8179
integration-tests = ["strum", "strum_macros"]
8280

83-
rustcrypto = ["ecdsa", "elliptic-curve", "signature", "x509-cert"]
81+
rustcrypto = ["digest", "ecdsa", "elliptic-curve", "pkcs8", "signature", "x509-cert"]
8482
rustcrypto-full = ["rustcrypto", "p192", "p224", "p256", "p384", "p521", "rsa", "sha1", "sha2", "sha3", "sm2", "sm3"]

tss-esapi/src/abstraction/public.rs

Lines changed: 213 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -2,127 +2,250 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
use crate::interface_types::ecc::EccCurve;
5-
use crate::structures::{Public, RsaExponent};
5+
use crate::structures::Public;
6+
use crate::utils::PublicKey as TpmPublicKey;
67
use crate::{Error, WrapperErrorKind};
78

89
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,
10+
use elliptic_curve::{
11+
generic_array::typenum::Unsigned,
12+
sec1::{EncodedPoint, FromEncodedPoint, ModulusSize, ToEncodedPoint},
13+
AffinePoint, CurveArithmetic, FieldBytesSize, PublicKey,
1414
};
1515

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),
16+
use x509_cert::spki::SubjectPublicKeyInfoOwned;
17+
18+
#[cfg(feature = "rsa")]
19+
use {
20+
crate::structures::RsaExponent,
21+
rsa::{BigUint, RsaPublicKey},
22+
};
23+
24+
#[cfg(any(
25+
feature = "p192",
26+
feature = "p224",
27+
feature = "p256",
28+
feature = "p384",
29+
feature = "p521",
30+
feature = "rsa",
31+
feature = "sm2"
32+
))]
33+
use pkcs8::EncodePublicKey;
34+
35+
/// Default exponent for RSA keys.
36+
// Also known as 0x10001
37+
#[cfg(feature = "rsa")]
38+
const RSA_DEFAULT_EXP: u64 = 65537;
39+
40+
impl<C> TryFrom<&Public> for PublicKey<C>
41+
where
42+
C: CurveArithmetic + AssociatedTpmCurve,
43+
FieldBytesSize<C>: ModulusSize,
44+
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
45+
{
46+
type Error = Error;
47+
48+
fn try_from(value: &Public) -> Result<Self, Self::Error> {
49+
match value {
50+
Public::Ecc {
51+
parameters, unique, ..
52+
} => {
53+
if parameters.ecc_curve() != C::TPM_CURVE {
54+
return Err(Error::local_error(WrapperErrorKind::InvalidParam));
55+
}
56+
57+
let x = unique.x().as_bytes();
58+
let y = unique.y().as_bytes();
59+
60+
if x.len() != FieldBytesSize::<C>::USIZE {
61+
return Err(Error::local_error(WrapperErrorKind::InvalidParam));
62+
}
63+
if y.len() != FieldBytesSize::<C>::USIZE {
64+
return Err(Error::local_error(WrapperErrorKind::InvalidParam));
65+
}
66+
67+
let encoded_point =
68+
EncodedPoint::<C>::from_affine_coordinates(x.into(), y.into(), false);
69+
let public_key = PublicKey::<C>::try_from(&encoded_point)
70+
.map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?;
71+
72+
Ok(public_key)
73+
}
74+
_ => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)),
75+
}
76+
}
3077
}
3178

32-
impl TryFrom<Public> for DecodedKey {
79+
#[cfg(feature = "rsa")]
80+
impl TryFrom<&Public> for RsaPublicKey {
3381
type Error = Error;
3482

35-
fn try_from(value: Public) -> Result<Self, Self::Error> {
36-
public_to_decoded_key(&value)
83+
fn try_from(value: &Public) -> Result<Self, Self::Error> {
84+
match value {
85+
Public::Rsa {
86+
unique, parameters, ..
87+
} => {
88+
let exponent = match parameters.exponent() {
89+
RsaExponent::ZERO_EXPONENT => BigUint::from(RSA_DEFAULT_EXP),
90+
_ => BigUint::from(parameters.exponent().value()),
91+
};
92+
let modulus = BigUint::from_bytes_be(unique.as_bytes());
93+
94+
let public_key = RsaPublicKey::new(modulus, exponent)
95+
.map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?;
96+
97+
Ok(public_key)
98+
}
99+
_ => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)),
100+
}
37101
}
38102
}
39103

40-
impl TryFrom<Public> for SubjectPublicKeyInfo {
104+
impl TryFrom<&Public> for SubjectPublicKeyInfoOwned {
41105
type Error = Error;
42106

43-
/// Converts [`crate::structures::Public::Rsa`] and [`crate::structures::Public::Ecc`] to [`picky_asn1_x509::SubjectPublicKeyInfo`].
107+
/// Converts [`crate::structures::Public::Rsa`] and [`crate::structures::Public::Ecc`] to [`x509_cert::spki::SubjectPublicKeyInfoOwned`].
44108
///
45109
/// # Details
46-
/// The result can be used to convert TPM public keys to DER using `picky_asn1_der`.
110+
/// The result can be used to convert TPM public keys to DER using `x509-cert`.
47111
///
48112
/// # Errors
49113
/// * 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-
})
114+
fn try_from(value: &Public) -> Result<Self, Self::Error> {
115+
match value {
116+
#[cfg(feature = "rsa")]
117+
Public::Rsa { .. } => {
118+
let public_key = RsaPublicKey::try_from(value)?;
119+
120+
Ok(public_key
121+
.to_public_key_der()
122+
.map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?
123+
.decode_msg::<Self>()
124+
.map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?)
125+
}
126+
#[allow(unused)]
127+
Public::Ecc { parameters, .. } => {
128+
macro_rules! read_key {
129+
($key_type:ty) => {
130+
if parameters.ecc_curve() == <$key_type>::TPM_CURVE {
131+
let public_key = PublicKey::<$key_type>::try_from(value)?;
132+
133+
return public_key
134+
.to_public_key_der()
135+
.map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?
136+
.decode_msg::<Self>()
137+
.map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam));
138+
}
139+
};
140+
}
141+
142+
#[cfg(feature = "p192")]
143+
read_key!(p192::NistP192);
144+
#[cfg(feature = "p224")]
145+
read_key!(p224::NistP224);
146+
#[cfg(feature = "p256")]
147+
read_key!(p256::NistP256);
148+
#[cfg(feature = "p384")]
149+
read_key!(p384::NistP384);
150+
#[cfg(feature = "p521")]
151+
read_key!(p521::NistP521);
152+
#[cfg(feature = "sm2")]
153+
read_key!(sm2::Sm2);
154+
155+
Err(Error::local_error(WrapperErrorKind::UnsupportedParam))
65156
}
66157
_ => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)),
67158
}
68159
}
69160
}
70161

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(),
162+
impl<C> TryFrom<&TpmPublicKey> for PublicKey<C>
163+
where
164+
C: CurveArithmetic + AssociatedTpmCurve,
165+
FieldBytesSize<C>: ModulusSize,
166+
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
167+
{
168+
type Error = Error;
169+
170+
fn try_from(value: &TpmPublicKey) -> Result<Self, Self::Error> {
171+
match value {
172+
TpmPublicKey::Ecc { x, y } => {
173+
let x = x.as_slice();
174+
let y = y.as_slice();
175+
176+
// TODO: When elliptic_curve bumps to 0.14, we can use the TryFrom implementation instead
177+
// of checking lengths manually
178+
if x.len() != FieldBytesSize::<C>::USIZE {
179+
return Err(Error::local_error(WrapperErrorKind::InvalidParam));
180+
}
181+
if y.len() != FieldBytesSize::<C>::USIZE {
182+
return Err(Error::local_error(WrapperErrorKind::InvalidParam));
183+
}
184+
185+
let encoded_point =
186+
EncodedPoint::<C>::from_affine_coordinates(x.into(), y.into(), false);
187+
let public_key = PublicKey::<C>::try_from(&encoded_point)
188+
.map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?;
189+
190+
Ok(public_key)
86191
}
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-
)))
192+
_ => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)),
99193
}
194+
}
195+
}
196+
197+
#[cfg(feature = "rsa")]
198+
impl TryFrom<&TpmPublicKey> for RsaPublicKey {
199+
type Error = Error;
100200

101-
_ => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)),
201+
fn try_from(value: &TpmPublicKey) -> Result<Self, Self::Error> {
202+
match value {
203+
TpmPublicKey::Rsa(modulus) => {
204+
let exponent = BigUint::from(RSA_DEFAULT_EXP);
205+
let modulus = BigUint::from_bytes_be(modulus.as_slice());
206+
207+
let public_key = RsaPublicKey::new(modulus, exponent)
208+
.map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?;
209+
210+
Ok(public_key)
211+
}
212+
_ => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)),
213+
}
102214
}
103215
}
104216

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
217+
/// Provides the value of the curve used in this crate for the specific curve.
218+
pub trait AssociatedTpmCurve {
219+
/// Value of the curve when interacting with the TPM.
220+
const TPM_CURVE: EccCurve;
113221
}
114222

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-
}
223+
#[cfg(feature = "p192")]
224+
impl AssociatedTpmCurve for p192::NistP192 {
225+
const TPM_CURVE: EccCurve = EccCurve::NistP192;
226+
}
227+
228+
#[cfg(feature = "p224")]
229+
impl AssociatedTpmCurve for p224::NistP224 {
230+
const TPM_CURVE: EccCurve = EccCurve::NistP224;
231+
}
232+
233+
#[cfg(feature = "p256")]
234+
impl AssociatedTpmCurve for p256::NistP256 {
235+
const TPM_CURVE: EccCurve = EccCurve::NistP256;
236+
}
237+
238+
#[cfg(feature = "p384")]
239+
impl AssociatedTpmCurve for p384::NistP384 {
240+
const TPM_CURVE: EccCurve = EccCurve::NistP384;
241+
}
242+
243+
#[cfg(feature = "p521")]
244+
impl AssociatedTpmCurve for p521::NistP521 {
245+
const TPM_CURVE: EccCurve = EccCurve::NistP521;
246+
}
247+
248+
#[cfg(feature = "sm2")]
249+
impl AssociatedTpmCurve for sm2::Sm2 {
250+
const TPM_CURVE: EccCurve = EccCurve::Sm2P256;
128251
}

tss-esapi/src/structures/tagged/public.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ use crate::{
1313
Error, Result, ReturnCode, WrapperErrorKind,
1414
};
1515

16+
use self::rsa::PublicRsaParameters;
1617
use ecc::PublicEccParameters;
1718
use keyed_hash::PublicKeyedHashParameters;
18-
use rsa::PublicRsaParameters;
1919

2020
use log::error;
2121
use std::convert::{TryFrom, TryInto};

0 commit comments

Comments
 (0)