1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use crate::export::Principal;
use crate::{Identity, Signature};
#[cfg(feature = "pem")]
use crate::identity::error::PemError;
use num_bigint::BigUint;
use openssl::bn::BigNumContext;
use openssl::ec::{EcKey, PointConversionForm};
use openssl::ecdsa::EcdsaSig;
use openssl::error::ErrorStack;
use openssl::pkey::{Private, Public};
use simple_asn1::ASN1Block;
use simple_asn1::ASN1Block::{BitString, ObjectIdentifier, Sequence};
use simple_asn1::{oid, to_der, OID};
#[derive(Clone, Debug)]
pub struct Secp256k1Identity {
private_key: EcKey<Private>,
public_key: EcKey<Public>,
der_encoded_public_key: Vec<u8>,
}
impl Secp256k1Identity {
#[cfg(feature = "pem")]
pub fn from_pem_file<P: AsRef<std::path::Path>>(file_path: P) -> Result<Self, PemError> {
Self::from_pem(std::fs::File::open(file_path)?)
}
#[cfg(feature = "pem")]
pub fn from_pem<R: std::io::Read>(pem_reader: R) -> Result<Self, PemError> {
let contents = pem_reader
.bytes()
.collect::<Result<Vec<u8>, std::io::Error>>()?;
let private_key = EcKey::private_key_from_pem(&contents)?;
Ok(Self::from_private_key(private_key))
}
pub fn from_private_key(private_key: EcKey<Private>) -> Self {
let group = private_key.group();
let public_key = EcKey::from_public_key(group, private_key.public_key())
.expect("Cannot derive secp256k1 public key.");
let asn1_block = public_key_to_asn1_block(public_key.clone())
.expect("Cannot ASN1 encode secp256k1 public key.");
let der_encoded_public_key =
to_der(&asn1_block).expect("Cannot DER encode secp256k1 public key.");
Self {
private_key,
public_key,
der_encoded_public_key,
}
}
}
impl Identity for Secp256k1Identity {
fn sender(&self) -> Result<Principal, String> {
Ok(Principal::self_authenticating(&self.der_encoded_public_key))
}
fn sign(&self, msg: &[u8]) -> Result<Signature, String> {
let ecdsa_sig = EcdsaSig::sign(msg, &self.private_key.clone())
.map_err(|err| format!("Cannot create secp256k1 signature: {}", err.to_string(),))?;
let signature = ecdsa_sig.to_der().map(Some).map_err(|err| {
format!("Cannot DER ecnode secp256k1 signature: {}", err.to_string(),)
})?;
let public_key = Some(self.der_encoded_public_key.clone());
Ok(Signature {
signature,
public_key,
})
}
}
fn public_key_to_asn1_block(public_key: EcKey<Public>) -> Result<ASN1Block, ErrorStack> {
let mut context = BigNumContext::new()?;
let bytes = public_key.public_key().to_bytes(
public_key.group(),
PointConversionForm::UNCOMPRESSED,
&mut context,
)?;
let ec_public_key_id = ObjectIdentifier(0, oid!(1, 2, 840, 10045, 2, 1));
let secp256k1_id = ObjectIdentifier(0, oid!(1, 3, 132, 0, 10));
let metadata = Sequence(0, vec![ec_public_key_id, secp256k1_id]);
let data = BitString(0, bytes.len() * 8, bytes);
Ok(Sequence(0, vec![metadata, data]))
}
#[cfg(feature = "pem")]
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_from_pem() {
const IDENTITY_FILE: &str = "-----BEGIN EC PARAMETERS-----
BgUrgQQACg==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIAgy7nZEcVHkQ4Z1Kdqby8SwyAiyKDQmtbEHTIM+WNeBoAcGBSuBBAAK
oUQDQgAEgO87rJ1ozzdMvJyZQ+GABDqUxGLvgnAnTlcInV3NuhuPv4O3VGzMGzeB
N3d26cRxD99TPtm8uo2OuzKhSiq6EQ==
-----END EC PRIVATE KEY-----
";
const DER_ENCODED_PUBLIC_KEY: &str = "3056301006072a8648ce3d020106052b8104000a0342000480ef3bac9d68cf374cbc9c9943e180043a94c462ef8270274e57089d5dcdba1b8fbf83b7546ccc1b3781377776e9c4710fdf533ed9bcba8d8ebb32a14a2aba11";
let identity = Secp256k1Identity::from_pem(IDENTITY_FILE.as_bytes())
.expect("Cannot create secp256k1 identity from PEM file.");
assert!(DER_ENCODED_PUBLIC_KEY == hex::encode(identity.der_encoded_public_key));
}
}