u2f/
protocol.rs

1use crate::util::*;
2use crate::messages::*;
3use crate::register::*;
4use crate::authorization::*;
5
6use base64::{encode_config, decode_config, URL_SAFE_NO_PAD};
7use chrono::prelude::*;
8use time::Duration;
9use crate::u2ferror::U2fError;
10
11type Result<T> = ::std::result::Result<T, U2fError>;
12
13#[derive(Clone)]
14pub struct U2f {
15    app_id: String,
16}
17
18#[derive(Deserialize, Serialize, Clone)]
19#[serde(rename_all = "camelCase")]
20pub struct Challenge {
21    pub app_id: String,
22    pub challenge: String,
23    pub timestamp: String,
24}
25
26impl Challenge {
27    pub fn new() -> Self {
28        Challenge {
29            app_id: String::new(),
30            challenge: String::new(),
31            timestamp: String::new()
32        }
33    }
34}
35
36impl U2f {
37    // The app ID is a string used to uniquely identify an U2F app
38    pub fn new(app_id: String) -> Self {
39        U2f {
40            app_id: app_id,
41        }
42    }
43
44    pub fn generate_challenge(&self) -> Result<Challenge> {
45        let utc: DateTime<Utc> = Utc::now();
46
47        let challenge_bytes = generate_challenge(32)?; 
48        let challenge = Challenge {
49            challenge : encode_config(&challenge_bytes, URL_SAFE_NO_PAD),
50            timestamp : format!("{:?}", utc),
51            app_id : self.app_id.clone()
52        };
53        
54        Ok(challenge.clone())
55    }
56
57    pub fn request(&self, challenge: Challenge, registrations: Vec<Registration>) -> Result<U2fRegisterRequest> {
58        let u2f_request = U2fRegisterRequest {
59            app_id : self.app_id.clone(),
60            register_requests: self.register_request(challenge),
61            registered_keys: self.registered_keys(registrations)
62        };
63
64        Ok(u2f_request)
65    }
66
67    fn register_request(&self, challenge: Challenge) -> Vec<RegisterRequest> {
68        let mut requests: Vec<RegisterRequest> = vec![];
69
70        let request = RegisterRequest {
71            version : U2F_V2.into(),
72            challenge: challenge.challenge
73        };
74        requests.push(request);
75
76        requests
77    }
78
79    pub fn register_response(&self, challenge: Challenge, response: RegisterResponse) -> Result<Registration> {
80        if expiration(challenge.timestamp) > Duration::seconds(300) {
81            return Err(U2fError::ChallengeExpired);
82        }
83
84        let registration_data: Vec<u8> = decode_config(&response.registration_data[..], URL_SAFE_NO_PAD).unwrap();
85        let client_data: Vec<u8> = decode_config(&response.client_data[..], URL_SAFE_NO_PAD).unwrap();
86
87        parse_registration(challenge.app_id, client_data, registration_data)
88    }
89
90    fn registered_keys(&self, registrations: Vec<Registration>) -> Vec<RegisteredKey> {
91        let mut keys: Vec<RegisteredKey> = vec![];
92
93        for registration in registrations {
94            keys.push(get_registered_key(self.app_id.clone(), registration.key_handle));
95        }
96
97        keys
98    }
99    
100    pub fn sign_request(&self, challenge: Challenge, registrations: Vec<Registration>) -> U2fSignRequest {
101        let mut keys: Vec<RegisteredKey> = vec![];
102
103        for registration in registrations {
104            keys.push(get_registered_key(self.app_id.clone(), registration.key_handle));
105        }
106
107        let signed_request = U2fSignRequest {
108            app_id : self.app_id.clone(),
109            challenge: encode_config(challenge.challenge.as_bytes(), URL_SAFE_NO_PAD),
110            registered_keys: keys
111        };
112
113        signed_request
114    }  
115
116    pub fn sign_response(&self, challenge: Challenge, reg: Registration, sign_resp: SignResponse, counter: u32) -> Result<u32> {
117        if expiration(challenge.timestamp) > Duration::seconds(300) {
118            return Err(U2fError::ChallengeExpired);
119        }
120
121        if sign_resp.key_handle != get_encoded(&reg.key_handle[..]) {            
122            return Err(U2fError::WrongKeyHandler);
123        }
124
125        let client_data: Vec<u8> = decode_config(&sign_resp.client_data[..], URL_SAFE_NO_PAD).map_err(|_e| U2fError::InvalidClientData)?;
126        let sign_data: Vec<u8> = decode_config(&sign_resp.signature_data[..], URL_SAFE_NO_PAD).map_err(|_e| U2fError::InvalidSignatureData)?;
127
128        let public_key = reg.pub_key;
129
130        let auth = parse_sign_response(self.app_id.clone(), client_data.clone(), public_key, sign_data.clone());
131
132        match auth {
133            Ok(ref res) => {
134                // CounterTooLow is raised when the counter value received from the device is
135                // lower than last stored counter value.
136                if res.counter < counter {
137                    return Err(U2fError::CounterTooLow);
138                }
139                else {
140                    return Ok(res.counter);
141                }
142            },
143                Err(e) => return Err(e),
144            }
145        }       
146}