tss_esapi/abstraction/
public.rs

1// Copyright 2022 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::interface_types::ecc::EccCurve;
5use crate::structures::{Public, RsaExponent};
6use crate::{Error, WrapperErrorKind};
7
8use core::convert::TryFrom;
9use oid::ObjectIdentifier;
10use picky_asn1::bit_string::BitString;
11use picky_asn1::wrapper::{IntegerAsn1, OctetStringAsn1};
12use picky_asn1_x509::{
13    AlgorithmIdentifier, EcParameters, EcPoint, PublicKey, RsaPublicKey, SubjectPublicKeyInfo,
14};
15use serde::{Deserialize, Serialize};
16
17/// Can be converted from [`crate::structures::Public`] when not a fully constructed
18/// [`picky_asn1_x509::SubjectPublicKeyInfo`] is required.
19///
20/// # Details
21///
22/// Holds either [`picky_asn1_x509::RsaPublicKey`] for [`crate::structures::Public::Rsa`] or
23/// [`picky_asn1_x509::EcPoint`] for [`crate::structures::Public::Ecc`].
24#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
25pub enum DecodedKey {
26    RsaPublicKey(RsaPublicKey),
27    EcPoint(EcPoint),
28}
29
30impl TryFrom<Public> for DecodedKey {
31    type Error = Error;
32
33    fn try_from(value: Public) -> Result<Self, Self::Error> {
34        public_to_decoded_key(&value)
35    }
36}
37
38impl TryFrom<Public> for SubjectPublicKeyInfo {
39    type Error = Error;
40
41    /// Converts [`crate::structures::Public::Rsa`] and [`crate::structures::Public::Ecc`] to [`picky_asn1_x509::SubjectPublicKeyInfo`].
42    ///
43    /// # Details
44    /// The result can be used to convert TPM public keys to DER using `picky_asn1_der`.
45    ///
46    /// # Errors
47    /// * if other instances of [`crate::structures::Public`] are used `UnsupportedParam` will be returned.
48    fn try_from(value: Public) -> Result<Self, Self::Error> {
49        let decoded_key = public_to_decoded_key(&value)?;
50
51        match (value, decoded_key) {
52            (Public::Rsa { .. }, DecodedKey::RsaPublicKey(key)) => Ok(SubjectPublicKeyInfo {
53                algorithm: AlgorithmIdentifier::new_rsa_encryption(),
54                subject_public_key: PublicKey::Rsa(key.into()),
55            }),
56            (Public::Ecc { parameters, .. }, DecodedKey::EcPoint(point)) => {
57                Ok(SubjectPublicKeyInfo {
58                    algorithm: AlgorithmIdentifier::new_elliptic_curve(EcParameters::NamedCurve(
59                        curve_oid(parameters.ecc_curve())?.into(),
60                    )),
61                    subject_public_key: PublicKey::Ec(BitString::with_bytes(point).into()),
62                })
63            }
64            _ => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)),
65        }
66    }
67}
68
69/// Converts [`crate::structures::Public::Rsa`] and [`crate::structures::Public::Ecc`] to [DecodedKey].
70///
71/// # Details
72/// Does basic key conversion to either RSA or ECC. In RSA conversion the TPM zero exponent is replaced with `65537`.
73///
74/// # Errors
75/// * if other instances of [`crate::structures::Public`] are used `UnsupportedParam` will be returned.
76fn public_to_decoded_key(public: &Public) -> Result<DecodedKey, Error> {
77    match public {
78        Public::Rsa {
79            unique, parameters, ..
80        } => {
81            let exponent = match parameters.exponent() {
82                RsaExponent::ZERO_EXPONENT => 65537,
83                _ => parameters.exponent().value(),
84            }
85            .to_be_bytes();
86            Ok(DecodedKey::RsaPublicKey(RsaPublicKey {
87                modulus: IntegerAsn1::from_bytes_be_unsigned(unique.value().to_vec()),
88                public_exponent: IntegerAsn1::from_bytes_be_signed(exponent.to_vec()),
89            }))
90        }
91        Public::Ecc { unique, .. } => {
92            let x = unique.x().value().to_vec();
93            let y = unique.y().value().to_vec();
94            Ok(DecodedKey::EcPoint(OctetStringAsn1(
95                elliptic_curve_point_to_octet_string(x, y),
96            )))
97        }
98
99        _ => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)),
100    }
101}
102
103// Taken from https://github.com/parallaxsecond/parsec/blob/561235f3cc37bcff3d9a6cb29c84eeae5d55100b/src/providers/tpm/utils.rs#L319
104// Points on elliptic curves are represented as defined in section 2.3.3 of https://www.secg.org/sec1-v2.pdf
105// The (uncompressed) representation is [ 0x04 || x || y ] where x and y are the coordinates of the point
106fn elliptic_curve_point_to_octet_string(mut x: Vec<u8>, mut y: Vec<u8>) -> Vec<u8> {
107    let mut octet_string = vec![0x04];
108    octet_string.append(&mut x);
109    octet_string.append(&mut y);
110    octet_string
111}
112
113// Map TPM supported ECC curves to their respective OIDs
114fn curve_oid(ecc_curve: EccCurve) -> Result<ObjectIdentifier, Error> {
115    match ecc_curve {
116        EccCurve::NistP192 => Ok(picky_asn1_x509::oids::secp192r1()),
117        EccCurve::NistP224 => Ok(picky_asn1_x509::oids::secp256r1()),
118        EccCurve::NistP256 => Ok(picky_asn1_x509::oids::secp256r1()),
119        EccCurve::NistP384 => Ok(picky_asn1_x509::oids::secp384r1()),
120        EccCurve::NistP521 => Ok(picky_asn1_x509::oids::secp521r1()),
121        //  Barreto-Naehrig curves seem to not have any OIDs
122        EccCurve::BnP256 => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)),
123        EccCurve::BnP638 => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)),
124        EccCurve::Sm2P256 => Ok(ObjectIdentifier::try_from("1.2.156.10197.1.301").unwrap()),
125    }
126}