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
122
use generic_array::typenum::Unsigned;
use p256::{
ecdsa::{signature::Verifier, Signature},
elliptic_curve,
elliptic_curve::sec1::EncodedPoint,
};
use signature::Signature as _;
use tink_core::{utils::wrap_err, TinkError};
use tink_proto::{EcdsaSignatureEncoding, EllipticCurveType, HashType};
#[derive(Clone)]
pub enum EcdsaPublicKey {
NistP256(p256::ecdsa::VerifyingKey),
}
#[derive(Clone)]
pub struct EcdsaVerifier {
public_key: EcdsaPublicKey,
encoding: super::SignatureEncoding,
}
impl EcdsaVerifier {
pub fn new(
hash_alg: HashType,
curve: EllipticCurveType,
encoding: EcdsaSignatureEncoding,
x: &[u8],
y: &[u8],
) -> Result<Self, TinkError> {
let public_key = match curve {
EllipticCurveType::NistP256 => {
let x = element_from_padded_slice::<p256::NistP256>(x)?;
let y = element_from_padded_slice::<p256::NistP256>(y)?;
let pt = EncodedPoint::from_affine_coordinates(&x, &y, false);
let verify_key = p256::ecdsa::VerifyingKey::from_encoded_point(&pt)
.map_err(|e| wrap_err("EcdsaVerifier: invalid point", e))?;
EcdsaPublicKey::NistP256(verify_key)
}
_ => return Err(format!("EcdsaVerifier: unsupported curve {:?}", curve,).into()),
};
Self::new_from_public_key(hash_alg, curve, encoding, public_key)
}
pub fn new_from_public_key(
hash_alg: HashType,
curve: EllipticCurveType,
encoding: EcdsaSignatureEncoding,
public_key: EcdsaPublicKey,
) -> Result<Self, TinkError> {
let encoding = super::validate_ecdsa_params(hash_alg, curve, encoding)
.map_err(|e| wrap_err("EcdsaVerifier", e))?;
Ok(EcdsaVerifier {
public_key,
encoding,
})
}
}
pub fn element_from_padded_slice<C: elliptic_curve::Curve>(
data: &[u8],
) -> Result<elliptic_curve::FieldBytes<C>, TinkError> {
let point_len = C::FieldSize::to_usize();
if data.len() >= point_len {
let offset = data.len() - point_len;
for v in data.iter().take(offset) {
if *v != 0 {
return Err("EcdsaVerifier: point too large".into());
}
}
Ok(elliptic_curve::FieldBytes::<C>::clone_from_slice(
&data[offset..],
))
} else {
let mut data_copy = vec![0; point_len];
data_copy[(point_len - data.len())..].copy_from_slice(data);
Ok(elliptic_curve::FieldBytes::<C>::clone_from_slice(
&data_copy,
))
}
}
impl tink_core::Verifier for EcdsaVerifier {
fn verify(&self, signature: &[u8], data: &[u8]) -> Result<(), tink_core::TinkError> {
let signature = match self.encoding {
super::SignatureEncoding::Der => Signature::from_asn1(signature)
.map_err(|e| wrap_err("EcdsaVerifier: invalid ASN.1 signature", e))?,
super::SignatureEncoding::IeeeP1363 => Signature::from_bytes(signature)
.map_err(|e| wrap_err("EcdsaVerifier: invalid IEEE-P1363 signature", e))?,
};
match &self.public_key {
EcdsaPublicKey::NistP256(verify_key) => verify_key
.verify(&data, &signature)
.map_err(|e| wrap_err("EcdsaVerifier: invalid signature", e)),
}
}
}