use ecdsa::{SigningKey, elliptic_curve::pkcs8::DecodePrivateKey, signature::Signer};
use p256::NistP256;
use prost::Message;
use crate::{
error::BuilderError, fabric::msp::SerializedIdentity, implement::crypto::generate_sha256_hash,
};
pub struct IdentityBuilder {
msp: Option<String>,
cert: Vec<u8>,
pkey: String,
}
#[derive(Clone)]
pub struct Identity {
msp: String,
cert: Vec<u8>,
pkey: SigningKey<NistP256>,
}
impl Identity {
#[allow(dead_code)]
pub(crate) fn get_certificate_bytes(&self) -> Vec<u8> {
self.cert.clone()
}
pub(crate) fn generate_tls_cert_hash(&self) -> Vec<u8> {
generate_sha256_hash(
self.get_serialized_identity()
.id_bytes
.encode_to_vec()
.as_slice(),
)
}
pub(crate) fn get_serialized_identity(&self) -> SerializedIdentity {
SerializedIdentity {
mspid: self.msp.clone(),
id_bytes: self.get_certificate_bytes(),
}
}
#[cfg(any(feature = "client", feature = "client-wasm"))]
pub fn generate_fabric_ca_token(&self, method: &str, path: &str, body: &[u8]) -> String {
use base64::Engine;
let b64 = base64::engine::general_purpose::STANDARD;
let cert_b64 = b64.encode(&self.cert);
let msg = format!(
"{}.{}.{}.{}",
method,
b64.encode(path.as_bytes()),
b64.encode(body),
cert_b64
);
let sig = self.sign_message(msg.as_bytes());
format!("{}.{}", cert_b64, b64.encode(&sig))
}
pub fn sign_message(&self, message: &[u8]) -> Vec<u8> {
use p256::pkcs8::der::Encode;
let signature: ecdsa::Signature<p256::NistP256> = self.pkey.sign(message);
let mut v = vec![];
signature
.normalize_s()
.to_der()
.encode_to_vec(&mut v)
.expect("Couldn't encode der to vec");
v
}
}
impl IdentityBuilder {
pub fn from_pem(pem_bytes: impl AsRef<[u8]>) -> Result<Self, BuilderError> {
Ok(IdentityBuilder {
msp: None,
cert: pem_bytes.as_ref().into(),
pkey: String::default(),
})
}
pub fn with_msp(mut self, msp: impl Into<String>) -> Result<Self, BuilderError> {
let msp = msp.into().trim().to_string();
if msp.is_empty() {
return Err(BuilderError::InvalidParameter("msp cannot be empty".into()));
}
self.msp = Some(msp);
Ok(self)
}
pub fn with_private_key(mut self, pkey: String) -> Result<Self, BuilderError> {
self.pkey = pkey;
Ok(self)
}
pub fn build(self) -> Result<Identity, BuilderError> {
if self.msp.is_none() {
return Err(BuilderError::MissingParameter("msp".into()));
}
if self.pkey.is_empty() {
return Err(BuilderError::MissingParameter("pkey".into()));
}
let signing_key = ecdsa::SigningKey::from_pkcs8_pem(&self.pkey.replace("EC ", ""))
.expect("Invalid signing key");
Ok(Identity {
msp: self.msp.unwrap(),
cert: self.cert,
pkey: signing_key,
})
}
}