forked from awslabs/aws-nitro-enclaves-cose
/
openssl_pkey.rs
121 lines (98 loc) · 4.16 KB
/
openssl_pkey.rs
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
121
//! OpenSSL PKey(Ref) implementation for cryptography
use openssl::{
bn::BigNum,
ecdsa::EcdsaSig,
hash::MessageDigest,
pkey::{HasPrivate, HasPublic, PKey, PKeyRef},
};
use crate::{
crypto::{ec_curve_to_parameters, SigningPrivateKey, SigningPublicKey},
error::CoseError,
sign::SignatureAlgorithm,
};
impl<T> SigningPublicKey for PKey<T>
where
T: HasPublic,
{
fn get_parameters(&self) -> Result<(SignatureAlgorithm, MessageDigest), CoseError> {
self.as_ref().get_parameters()
}
fn verify(&self, data: &[u8], signature: &[u8]) -> Result<bool, CoseError> {
self.as_ref().verify(data, signature)
}
}
impl<T> SigningPublicKey for PKeyRef<T>
where
T: HasPublic,
{
fn get_parameters(&self) -> Result<(SignatureAlgorithm, MessageDigest), CoseError> {
let curve_name = self
.ec_key()
.map_err(|_| CoseError::UnsupportedError("Non-EC keys are not supported".to_string()))?
.group()
.curve_name()
.ok_or_else(|| {
CoseError::UnsupportedError("Anonymous EC keys are not supported".to_string())
})?;
let curve_parameters = ec_curve_to_parameters(curve_name)?;
Ok((curve_parameters.0, curve_parameters.1))
}
fn verify(&self, data: &[u8], signature: &[u8]) -> Result<bool, CoseError> {
let key = self.ec_key().map_err(|_| {
CoseError::UnsupportedError("Non-EC keys are not yet supported".to_string())
})?;
let curve_name = key.group().curve_name().ok_or_else(|| {
CoseError::UnsupportedError("Anonymous EC keys are not supported".to_string())
})?;
let (_, _, key_length) = ec_curve_to_parameters(curve_name)?;
// Recover the R and S factors from the signature contained in the object
let (bytes_r, bytes_s) = signature.split_at(key_length);
let r = BigNum::from_slice(&bytes_r).map_err(CoseError::SignatureError)?;
let s = BigNum::from_slice(&bytes_s).map_err(CoseError::SignatureError)?;
let sig = EcdsaSig::from_private_components(r, s).map_err(CoseError::SignatureError)?;
sig.verify(data, &key).map_err(CoseError::SignatureError)
}
}
impl<T> SigningPrivateKey for PKey<T>
where
T: HasPrivate,
{
fn sign(&self, data: &[u8]) -> Result<Vec<u8>, CoseError> {
self.as_ref().sign(data)
}
}
impl<T> SigningPrivateKey for PKeyRef<T>
where
T: HasPrivate,
{
fn sign(&self, data: &[u8]) -> Result<Vec<u8>, CoseError> {
let key = self.ec_key().map_err(|_| {
CoseError::UnsupportedError("Non-EC keys are not yet supported".to_string())
})?;
let curve_name = key.group().curve_name().ok_or_else(|| {
CoseError::UnsupportedError("Anonymous EC keys are not supported".to_string())
})?;
let (_, _, key_length) = ec_curve_to_parameters(curve_name)?;
// The spec defines the signature as:
// Signature = I2OSP(R, n) | I2OSP(S, n), where n = ceiling(key_length / 8)
// The Signer interface doesn't provide this, so this will use EcdsaSig interface instead
// and concatenate R and S.
// See https://tools.ietf.org/html/rfc8017#section-4.1 for details.
let signature = EcdsaSig::sign(data, &key).map_err(CoseError::SignatureError)?;
let bytes_r = signature.r().to_vec();
let bytes_s = signature.s().to_vec();
// These should *never* exceed ceiling(key_length / 8)
assert!(bytes_r.len() <= key_length);
assert!(bytes_s.len() <= key_length);
let mut signature_bytes = vec![0u8; key_length * 2];
// This is big-endian encoding so padding might be added at the start if the factor is
// too short.
let offset_copy = key_length - bytes_r.len();
signature_bytes[offset_copy..offset_copy + bytes_r.len()].copy_from_slice(&bytes_r);
// This is big-endian encoding so padding might be added at the start if the factor is
// too short.
let offset_copy = key_length - bytes_s.len() + key_length;
signature_bytes[offset_copy..offset_copy + bytes_s.len()].copy_from_slice(&bytes_s);
Ok(signature_bytes)
}
}