1use crate::{internal_error, Signer, SigningError};
2use core::convert::TryFrom;
3use core::str::FromStr;
4use m10_protos::sdk::signature::Algorithm;
5use ring::{
6    rand::{self, SystemRandom}, signature::{EcdsaKeyPair, KeyPair, ECDSA_P256_SHA256_ASN1_SIGNING},
8};
9use std::fs::File;
10use std::io::{Read, Write};
11
12#[derive(serde::Deserialize)]
14#[serde(try_from = "String", into = "String")]
15pub struct P256 {
16    #[serde(flatten)]
17    key_pair: EcdsaKeyPair,
18    #[serde(skip)]
19    rng: rand::SystemRandom,
20}
21
22impl P256 {
23    pub fn new_key_pair(path: Option<&str>) -> Result<Self, SigningError> {
25        let rng = SystemRandom::new();
26        let pkcs8_bytes = EcdsaKeyPair::generate_pkcs8(&ECDSA_P256_SHA256_ASN1_SIGNING, &rng)
27            .map_err(|e| internal_error(e, "P256::new_key_pair: generate_pkcs8"))?;
28        if let Some(p) = path {
29            let mut key_file = File::create(p)?;
30            key_file.write_all(pkcs8_bytes.as_ref())?;
31        }
32        Ok(Self {
33            key_pair: EcdsaKeyPair::from_pkcs8(
34                &ECDSA_P256_SHA256_ASN1_SIGNING,
35                pkcs8_bytes.as_ref(),
36                &rng, )?,
38            rng,
39        })
40    }
41
42    pub fn load_key_pair(path: &str) -> Result<Self, SigningError> {
44        let mut key_file = File::open(path)?;
45        let mut pkcs8_bytes: Vec<u8> = Vec::new();
46        key_file.read_to_end(&mut pkcs8_bytes)?;
47        let rng = SystemRandom::new();
48        Ok(Self {
49            key_pair: EcdsaKeyPair::from_pkcs8(
50                &ECDSA_P256_SHA256_ASN1_SIGNING,
51                pkcs8_bytes.as_ref(),
52                &rng, )?,
54            rng,
55        })
56    }
57
58    pub fn new_key_pair_exportable() -> Result<(Vec<u8>, Self), SigningError> {
60        let rng = SystemRandom::new();
61        let pkcs8_bytes = EcdsaKeyPair::generate_pkcs8(&ECDSA_P256_SHA256_ASN1_SIGNING, &rng)
62            .map_err(|e| internal_error(e, "P256::new_key_pair_exportable: generate_pkcs8"))?;
63        let key_pair =
64            EcdsaKeyPair::from_pkcs8(&ECDSA_P256_SHA256_ASN1_SIGNING, pkcs8_bytes.as_ref(), &rng)?; Ok((pkcs8_bytes.as_ref().to_vec(), Self { key_pair, rng }))
66    }
67
68    pub fn from_pkcs8(bytes: &[u8]) -> Result<Self, SigningError> {
70        let rng = SystemRandom::new();
71        let key_pair = EcdsaKeyPair::from_pkcs8(&ECDSA_P256_SHA256_ASN1_SIGNING, bytes, &rng)?; Ok(Self { key_pair, rng })
73    }
74}
75
76#[async_trait::async_trait]
77impl Signer for P256 {
78    async fn sign(&self, msg: &[u8]) -> Result<Vec<u8>, super::SigningError> {
79        self.key_pair
80            .sign(&self.rng, msg)
81            .map(|x| x.as_ref().to_vec())
82            .map_err(|e| internal_error(e, "P256::sign: signing failed"))
83    }
84
85    fn public_key(&self) -> &[u8] {
86        self.key_pair.public_key().as_ref()
87    }
88
89    fn algorithm(&self) -> Algorithm {
90        Algorithm::P256Sha256Asn1
91    }
92}
93
94impl FromStr for P256 {
95    type Err = SigningError;
96    fn from_str(key_pair_enc: &str) -> Result<Self, Self::Err> {
97        let pkcs8_bytes = base64::decode(key_pair_enc).unwrap_or_default();
98        P256::from_pkcs8(&pkcs8_bytes)
99    }
100}
101
102impl TryFrom<String> for P256 {
103    type Error = SigningError;
104    fn try_from(key_pair: String) -> Result<Self, Self::Error> {
105        key_pair.parse()
106    }
107}