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
123
124
125
126
127
128
129
#![warn(missing_docs)]
use data_encoding::BASE64URL_NOPAD;
use openssl::nid::Nid;
use sha2::{Sha256, Digest};
use openssl::bn::BigNum;
use openssl::ec::EcGroup;
use openssl::ec::EcKey;
use openssl::ecdsa::EcdsaSig;
use std::collections::HashMap;
pub fn verify_ssv_callback(query_string: &str, public_keys: &HashMap<u64, String>) -> Result<bool, String> {
let signature_position = match query_string.find("&signature") {
None => { return Err(String::from("Could not find &signature= parameter in query_string")); }
Some(x) => { x }
};
let message = &query_string[..signature_position];
let sig_and_key_id_part = String::from(&query_string[signature_position..]);
let key_id_position = match sig_and_key_id_part.find("&key_id") {
None => { return Err(String::from("Could not find &key_id= parameter in query_string")); }
Some(x) => { x }
};
let signature = &sig_and_key_id_part[11..key_id_position];
let key_id_part = String::from(&sig_and_key_id_part[key_id_position..]);
let key_id = match key_id_part[8..].parse::<u64>() {
Ok(x) => { x }
Err(_) => { return Err(String::from("Could not parse key_id as u64!")); }
};
let key = match public_keys.get(&key_id) {
None => { return Err(String::from("Key not found!")); }
Some(x) => { x }
};
let mut octet_key = match base64::decode(key) {
Ok(x) => { x }
Err(_) => { return Err(String::from("Could not decode base64 encoded Public key!")); }
};
octet_key.reverse();
octet_key.truncate(64);
octet_key.reverse();
let points = octet_key.split_at(32);
let x = match BigNum::from_slice(&points.0) {
Ok(x) => { x }
Err(_) => { return Err(String::from("Could not convert the X coordinate of the public key to BigNum.")); }
};
let y = match BigNum::from_slice(&points.1) {
Ok(x) => { x }
Err(_) => { return Err(String::from("Could not convert the Y coordinate of the public key to BigNum.")); }
};
let signature_bytes = match BASE64URL_NOPAD.decode(signature.as_bytes()) {
Ok(x) => { x }
Err(_) => { return Err(String::from("Could not decode the Base64Url encoded signature from the query_string")); }
};
let ecdsa_signature = match EcdsaSig::from_der(&signature_bytes) {
Ok(x) => { x }
Err(_) => { return Err(String::from("Could not decode the DER-encoded ECDSA signature.")); }
};
let group = match EcGroup::from_curve_name(Nid::X9_62_PRIME256V1) {
Ok(x) => { x }
Err(_) => { return Err(String::from("Could not get the group of the X9_62_PRIME256V1 curve.")); }
};
let ec_key = match EcKey::from_public_key_affine_coordinates(&*group, &*x, &*y) {
Ok(x) => { x }
Err(_) => { return Err(String::from("Could not construct a public key from its affine coordinates.")); }
};
let unquoted = match urlparse::unquote(message) {
Ok(x) => { x }
Err(_) => { return Err(String::from("Could not replace %xx escapes by their single-character equivalent.")); }
};
let mut hasher = Sha256::new();
hasher.input(unquoted);
let hashed_data = hasher.result().as_slice().to_owned();
match ecdsa_signature.verify(&hashed_data, &*ec_key) {
Ok(x) => { Ok(x) }
Err(_) => { Err(String::from("Error verifying")) }
}
}