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
130
131
132
133
134
use sha2::{Digest, Sha256, Sha384};
use yubikey_piv::{MgmKey, YubiKey};
use yubikey_piv::policy::{PinPolicy, TouchPolicy};
use yubikey_piv::key::{AlgorithmId, sign_data as yk_sign_data, SlotId};
use yubikey_piv::certificate::{Certificate, PublicKeyInfo};
#[derive(Debug)]
pub enum Error {
Unprovisioned,
WrongKeyType,
Unsupported,
InternalYubiKeyError(yubikey_piv::error::Error),
}
pub fn configured(yk: &mut YubiKey, slot: SlotId) -> Result<PublicKeyInfo, Error> {
match yubikey_piv::certificate::Certificate::read(yk, slot) {
Ok(cert) => Ok(cert.subject_pki().clone()),
Err(e) => Err(Error::InternalYubiKeyError(e)),
}
}
pub fn fetch_pubkey(slot: SlotId) -> Result<PublicKeyInfo, Error> {
let mut yubikey = match YubiKey::open() {
Ok(yk) => yk,
Err(e) => return Err(Error::InternalYubiKeyError(e)),
};
configured(&mut yubikey, slot)
}
pub fn provision(pin: &[u8], slot: SlotId, alg: AlgorithmId) -> Result<PublicKeyInfo, Error> {
let mut yk = match YubiKey::open() {
Ok(yk) => yk,
Err(e) => return Err(Error::InternalYubiKeyError(e)),
};
match yk.verify_pin(pin) {
Ok(_) => (),
Err(e) => {
println!("Error in verify pin: {}", e);
return Err(Error::InternalYubiKeyError(e))
},
}
match yk.authenticate(MgmKey::default()) {
Ok(_) => (),
Err(e) => {
println!("Error in MGM Key Authentication: {}", e);
return Err(Error::InternalYubiKeyError(e));
},
}
let key_info = match yubikey_piv::key::generate(&mut yk, slot, alg, PinPolicy::Never, TouchPolicy::Never) {
Ok(ki) => ki,
Err(e) => {
println!("Error in provisioning new key: {}", e);
return Err(Error::InternalYubiKeyError(e));
},
};
if let Err(e) = Certificate::generate_self_signed(
&mut yk,
slot,
[0u8; 20],
None,
"/CN=RusticaProvisioned/".to_owned(),
key_info,
) {
return Err(Error::InternalYubiKeyError(e));
}
configured(&mut yk, slot)
}
pub fn sign_data(data: &[u8], alg: AlgorithmId, slot: SlotId) -> Result<Vec<u8>, Error> {
let mut yk = match YubiKey::open() {
Ok(yk) => yk,
Err(e) => return Err(Error::InternalYubiKeyError(e)),
};
let slot_alg = match configured(&mut yk, slot) {
Ok(PublicKeyInfo::EcP256(_)) => AlgorithmId::EccP256,
Ok(PublicKeyInfo::EcP384(_)) => AlgorithmId::EccP384,
Ok(_) => AlgorithmId::Rsa2048,
Err(_) => return Err(Error::Unprovisioned),
};
if slot_alg != alg {
return Err(Error::WrongKeyType);
}
let hash = match slot_alg {
AlgorithmId::EccP256 => {
let mut hasher = Sha256::new();
hasher.update(data);
hasher.finalize().to_vec()
},
AlgorithmId::EccP384 => {
let mut hasher = Sha384::new();
hasher.update(data);
hasher.finalize().to_vec()
}
_ => return Err(Error::Unsupported),
};
match yk_sign_data(&mut yk, &hash[..], alg, slot) {
Ok(sig) => Ok(sig.to_vec()),
Err(e) => Err(Error::InternalYubiKeyError(e)),
}
}