1 // Copyright 2023, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 //! This library is a stub for Secretkeeper, which can be used by clients. It exposes
16 //! Secretkeeper Session which can be used for using the SecretManagement API.
17 //! It encapsulates the Cryptography! AuthgraphKeyExchange is triggered on creation of a session
18 //! and the messages is encrypted/decrypted using the shared keys.
19
20 mod authgraph_dev;
21
22 use crate::authgraph_dev::AgDevice;
23
24 use authgraph_boringssl as boring;
25 use authgraph_core::keyexchange as ke;
26 use authgraph_core::key;
27 use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper
28 ::ISecretkeeper::ISecretkeeper;
29 use android_hardware_security_authgraph::aidl::android::hardware::security::authgraph::{
30 IAuthGraphKeyExchange::IAuthGraphKeyExchange, PlainPubKey::PlainPubKey, PubKey::PubKey,
31 SessionIdSignature::SessionIdSignature, Identity::Identity,
32 };
33 use coset::{CoseKey, CborSerializable, CoseEncrypt0};
34 use explicitkeydice::OwnedDiceArtifactsWithExplicitKey;
35 use secretkeeper_core::cipher;
36 use secretkeeper_comm::data_types::SeqNum;
37 use secretkeeper_comm::wire::ApiError;
38 use std::cell::RefCell;
39 use std::fmt;
40 use std::rc::Rc;
41
42 /// A Secretkeeper session that can be used by client, this encapsulates the AuthGraph Key exchange
43 /// session as well as the encryption/decryption of request/response to/from Secretkeeper.
44 pub struct SkSession {
45 sk: binder::Strong<dyn ISecretkeeper>,
46 encryption_key: key::AesKey,
47 decryption_key: key::AesKey,
48 session_id: Vec<u8>,
49 // We allow seq numbers to be 0 to u64::MAX-1, increment beyond that fails
50 // Sequence number for next outgoing message encryption.
51 seq_num_outgoing: SeqNum,
52 // Sequence number for decrypting the next incoming message.
53 seq_num_incoming: SeqNum,
54 // The local AuthGraph Device impl - encapsulates the local identity etc.
55 authgraph_participant: AgDevice,
56 }
57
58 impl SkSession {
59 /// Create a new Secretkeeper session. This triggers an AuthGraphKeyExchange protocol with a
60 /// local `source` and remote `sink`.
61 ///
62 /// # Arguments
63 /// `sk`: Secretkeeper instance
64 ///
65 /// `dice`: DiceArtifacts of the caller (i.e, Sk client)
66 ///
67 /// `expected_sk_key`: Expected Identity of Secretkeeper. If set, the claimed peer identity is
68 /// matched against this and in cases of mismatch, error is returned.
new( sk: binder::Strong<dyn ISecretkeeper>, dice: &OwnedDiceArtifactsWithExplicitKey, expected_sk_key: Option<CoseKey>, ) -> Result<Self, Error>69 pub fn new(
70 sk: binder::Strong<dyn ISecretkeeper>,
71 dice: &OwnedDiceArtifactsWithExplicitKey,
72 expected_sk_key: Option<CoseKey>,
73 ) -> Result<Self, Error> {
74 let authgraph_participant = AgDevice::new(dice, expected_sk_key)?;
75 let ([encryption_key, decryption_key], session_id) = authgraph_key_exchange(
76 sk.clone(),
77 Rc::new(RefCell::new(authgraph_participant.clone())),
78 )?;
79 Ok(Self {
80 sk,
81 encryption_key,
82 decryption_key,
83 session_id,
84 seq_num_outgoing: SeqNum::new(),
85 seq_num_incoming: SeqNum::new(),
86 authgraph_participant,
87 })
88 }
89
90 /// Refresh the existing Secretkeeper session. This reuses the client
91 /// identity & per_boot_key, does AuthGraphKeyExchange resetting the keys!
refresh(&mut self) -> Result<(), Error>92 pub fn refresh(&mut self) -> Result<(), Error> {
93 let ([encryption_key, decryption_key], session_id) = authgraph_key_exchange(
94 self.sk.clone(),
95 Rc::new(RefCell::new(self.authgraph_participant.clone())),
96 )?;
97 self.encryption_key = encryption_key;
98 self.decryption_key = decryption_key;
99 self.session_id = session_id;
100 self.seq_num_outgoing = SeqNum::new();
101 self.seq_num_incoming = SeqNum::new();
102 Ok(())
103 }
104
105 /// Wrapper around `ISecretkeeper::processSecretManagementRequest`. This additionally handles
106 /// encryption and decryption.
secret_management_request(&mut self, req_data: &[u8]) -> Result<Vec<u8>, Error>107 pub fn secret_management_request(&mut self, req_data: &[u8]) -> Result<Vec<u8>, Error> {
108 let aes_gcm = boring::BoringAes;
109 let rng = boring::BoringRng;
110 let req_aad = self.seq_num_outgoing.get_then_increment()?;
111 let request_bytes = cipher::encrypt_message(
112 &aes_gcm,
113 &rng,
114 &self.encryption_key,
115 &self.session_id,
116 req_data,
117 &req_aad,
118 )
119 .map_err(Error::CipherError)?;
120
121 let response_bytes = self.sk.processSecretManagementRequest(&request_bytes)?;
122
123 let response_encrypt0 = CoseEncrypt0::from_slice(&response_bytes)?;
124 let expected_res_aad = self.seq_num_incoming.get_then_increment()?;
125 cipher::decrypt_message(
126 &aes_gcm,
127 &self.decryption_key,
128 &response_encrypt0,
129 &expected_res_aad,
130 )
131 .map_err(Error::CipherError)
132 }
133
134 /// Get the encryption key corresponding to the session. Note on usage: This (along with other
135 /// getters [`decryption_key()`] & [`session_id()`]) can be used for custom encrypting requests
136 /// (for ex, with different aad, instead of using [`secret_management_request`] method.
137 /// In that case, seq_num_outgoing & seq_num_incoming will be out of sync. Recommended use for
138 /// testing only.
encryption_key(&self) -> &key::AesKey139 pub fn encryption_key(&self) -> &key::AesKey {
140 &self.encryption_key
141 }
142
143 /// Get the decryption key corresponding to the session.
decryption_key(&self) -> &key::AesKey144 pub fn decryption_key(&self) -> &key::AesKey {
145 &self.decryption_key
146 }
147
148 /// Get the session_id.
session_id(&self) -> &[u8]149 pub fn session_id(&self) -> &[u8] {
150 &self.session_id
151 }
152 }
153
154 impl fmt::Debug for SkSession {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result155 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
156 f.debug_struct("SkSession").field("session_id", &hex::encode(&self.session_id)).finish()
157 }
158 }
159
160 /// Errors thrown by this SkSession.
161 #[derive(Debug)]
162 pub enum Error {
163 /// These are server errors : thrown from remote instance (of Authgraph or Secretkeeper)
164 BinderStatus(binder::Status),
165 /// These are errors thrown from (local) source Authgraph instance.
166 AuthgraphError(authgraph_core::error::Error),
167 /// Error originating while encryption/decryption of packets (at source).
168 CipherError(ApiError),
169 /// Errors originating in the coset library.
170 CoseError(coset::CoseError),
171 /// Unexpected item encountered (got, want).
172 UnexpectedItem(&'static str, &'static str),
173 /// The set of errors from secretkeeper_comm library.
174 SkCommError(secretkeeper_comm::data_types::error::Error),
175 }
176
177 impl std::error::Error for Error {}
178
179 impl std::fmt::Display for Error {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result180 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
181 match self {
182 Self::BinderStatus(e) => write!(f, "Binder error {e:?}"),
183 Self::AuthgraphError(e) => write!(f, "Local Authgraph instance error {e:?}"),
184 Self::CipherError(e) => write!(f, "Error in encryption/decryption of packets {e:?}"),
185 Self::CoseError(e) => write!(f, "Errors originating in the coset library {e:?}"),
186 Self::UnexpectedItem(got, want) => {
187 write!(f, "Unexpected item - Got:{got}, Expected:{want}")
188 }
189 Self::SkCommError(e) => write!(f, "secretkeeper_comm error: {e:?}"),
190 }
191 }
192 }
193
194 impl From<authgraph_core::error::Error> for Error {
from(e: authgraph_core::error::Error) -> Self195 fn from(e: authgraph_core::error::Error) -> Self {
196 Self::AuthgraphError(e)
197 }
198 }
199
200 impl From<binder::Status> for Error {
from(s: binder::Status) -> Self201 fn from(s: binder::Status) -> Self {
202 Self::BinderStatus(s)
203 }
204 }
205
206 impl From<coset::CoseError> for Error {
from(e: coset::CoseError) -> Self207 fn from(e: coset::CoseError) -> Self {
208 Self::CoseError(e)
209 }
210 }
211
212 impl From<secretkeeper_comm::data_types::error::Error> for Error {
from(e: secretkeeper_comm::data_types::error::Error) -> Self213 fn from(e: secretkeeper_comm::data_types::error::Error) -> Self {
214 Self::SkCommError(e)
215 }
216 }
217
218 /// Perform AuthGraph key exchange, returning the session keys and session ID.
authgraph_key_exchange( sk: binder::Strong<dyn ISecretkeeper>, ag_dev: Rc<RefCell<AgDevice>>, ) -> Result<([key::AesKey; 2], Vec<u8>), Error>219 fn authgraph_key_exchange(
220 sk: binder::Strong<dyn ISecretkeeper>,
221 ag_dev: Rc<RefCell<AgDevice>>,
222 ) -> Result<([key::AesKey; 2], Vec<u8>), Error> {
223 let sink = sk.getAuthGraphKe()?;
224 let mut source = ke::AuthGraphParticipant::new(
225 boring::crypto_trait_impls(),
226 ag_dev,
227 1, // Each SkSession supports only 1 open Authgraph session.
228 )?;
229 key_exchange(&mut source, sink)
230 }
231
232 /// Perform AuthGraph key exchange with the provided sink and local source implementation.
233 /// Return the agreed AES keys in plaintext, together with the session ID.
key_exchange( local_source: &mut ke::AuthGraphParticipant, sink: binder::Strong<dyn IAuthGraphKeyExchange>, ) -> Result<([key::AesKey; 2], Vec<u8>), Error>234 fn key_exchange(
235 local_source: &mut ke::AuthGraphParticipant,
236 sink: binder::Strong<dyn IAuthGraphKeyExchange>,
237 ) -> Result<([key::AesKey; 2], Vec<u8>), Error> {
238 // Step 1: create an ephemeral ECDH key at the (local) source.
239 let source_init_info = local_source.create()?;
240
241 // Step 2: pass the source's ECDH public key and other session info to the (remote) sink.
242 let init_result = sink.init(
243 &build_plain_pub_key(&source_init_info.ke_key.pub_key)?,
244 &vec_to_identity(&source_init_info.identity),
245 &source_init_info.nonce,
246 source_init_info.version,
247 )?;
248 let sink_init_info = init_result.sessionInitiationInfo;
249 let sink_pub_key = extract_plain_pub_key(&sink_init_info.key.pubKey)?;
250 let sink_info = init_result.sessionInfo;
251
252 // Step 3: pass the sink's ECDH public key and other session info to the (local) source, so it
253 // can calculate the same pair of symmetric keys.
254 let source_info = local_source.finish(
255 &sink_pub_key.plainPubKey,
256 &sink_init_info.identity.identity,
257 &sink_info.signature.signature,
258 &sink_init_info.nonce,
259 sink_init_info.version,
260 source_init_info.ke_key,
261 )?;
262
263 // Step 4: pass the (local) source's session ID signature back to the sink, so it can check it
264 // and update the symmetric keys so they're marked as authentication complete.
265 let _sink_arcs = sink.authenticationComplete(
266 &vec_to_signature(&source_info.session_id_signature),
267 &sink_info.sharedKeys,
268 )?;
269
270 // Decrypt and return the session keys.
271 let decrypted_shared_keys_array = local_source
272 .decipher_shared_keys_from_arcs(&source_info.shared_keys)?
273 .try_into()
274 .map_err(|_| Error::UnexpectedItem("Array", "Array of size 2"))?;
275
276 Ok((decrypted_shared_keys_array, source_info.session_id))
277 }
278
build_plain_pub_key(pub_key: &Option<Vec<u8>>) -> Result<PubKey, Error>279 fn build_plain_pub_key(pub_key: &Option<Vec<u8>>) -> Result<PubKey, Error> {
280 Ok(PubKey::PlainKey(PlainPubKey {
281 plainPubKey: pub_key.clone().ok_or(Error::UnexpectedItem("None", "Some bytes"))?,
282 }))
283 }
284
extract_plain_pub_key(pub_key: &Option<PubKey>) -> Result<&PlainPubKey, Error>285 fn extract_plain_pub_key(pub_key: &Option<PubKey>) -> Result<&PlainPubKey, Error> {
286 match pub_key {
287 Some(PubKey::PlainKey(pub_key)) => Ok(pub_key),
288 Some(PubKey::SignedKey(_)) => Err(Error::UnexpectedItem("Signed Key", "Public Key")),
289 None => Err(Error::UnexpectedItem("No key", "Public key")),
290 }
291 }
292
vec_to_identity(data: &[u8]) -> Identity293 fn vec_to_identity(data: &[u8]) -> Identity {
294 Identity { identity: data.to_vec() }
295 }
296
vec_to_signature(data: &[u8]) -> SessionIdSignature297 fn vec_to_signature(data: &[u8]) -> SessionIdSignature {
298 SessionIdSignature { signature: data.to_vec() }
299 }
300