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}