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 pub mod dice;
22
23 use crate::authgraph_dev::AgDevice;
24 use crate::dice::OwnedDiceArtifactsWithExplicitKey;
25
26 use authgraph_boringssl as boring;
27 use authgraph_core::keyexchange as ke;
28 use authgraph_core::key;
29 use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper
30 ::ISecretkeeper::ISecretkeeper;
31 use android_hardware_security_authgraph::aidl::android::hardware::security::authgraph::{
32 IAuthGraphKeyExchange::IAuthGraphKeyExchange, PlainPubKey::PlainPubKey, PubKey::PubKey,
33 SessionIdSignature::SessionIdSignature, Identity::Identity,
34 };
35 use coset::{CoseKey, CborSerializable, CoseEncrypt0};
36 use secretkeeper_core::cipher;
37 use secretkeeper_comm::data_types::SeqNum;
38 use secretkeeper_comm::wire::ApiError;
39 use std::cell::RefCell;
40 use std::fmt;
41 use std::rc::Rc;
42
43 /// A Secretkeeper session that can be used by client, this encapsulates the Authgraph Key exchange
44 /// session as well as the encryption/decryption of request/response to/from Secretkeeper.
45 pub struct SkSession {
46 sk: binder::Strong<dyn ISecretkeeper>,
47 encryption_key: key::AesKey,
48 decryption_key: key::AesKey,
49 session_id: Vec<u8>,
50 // We allow seq numbers to be 0 to u64::MAX-1, increment beyond that fails
51 // Sequence number for next outgoing message encryption.
52 seq_num_outgoing: SeqNum,
53 // Sequence number for decrypting the next incoming message.
54 seq_num_incoming: SeqNum,
55 }
56
57 impl SkSession {
58 /// Create a new Secretkeeper session. This triggers an AuthgraphKeyExchange protocol with a
59 /// local `source` and remote `sink`.
60 ///
61 /// # Arguments
62 /// `sk`: Secretkeeper instance
63 ///
64 /// `dice`: DiceArtifacts of the caller (i.e, Sk client)
65 ///
66 /// `expected_sk_key`: Expected Identity of Secretkeeper. If set, the claimed peer identity is
67 /// 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>68 pub fn new(
69 sk: binder::Strong<dyn ISecretkeeper>,
70 dice: &OwnedDiceArtifactsWithExplicitKey,
71 expected_sk_key: Option<CoseKey>,
72 ) -> Result<Self, Error> {
73 let ag_dev = Rc::new(RefCell::new(AgDevice::new(dice, expected_sk_key)?));
74 let ([encryption_key, decryption_key], session_id) =
75 authgraph_key_exchange(sk.clone(), ag_dev.clone())?;
76 Ok(Self {
77 sk,
78 encryption_key,
79 decryption_key,
80 session_id,
81 seq_num_outgoing: SeqNum::new(),
82 seq_num_incoming: SeqNum::new(),
83 })
84 }
85
86 /// Wrapper around `ISecretkeeper::processSecretManagementRequest`. This additionally handles
87 /// encryption and decryption.
secret_management_request(&mut self, req_data: &[u8]) -> Result<Vec<u8>, Error>88 pub fn secret_management_request(&mut self, req_data: &[u8]) -> Result<Vec<u8>, Error> {
89 let aes_gcm = boring::BoringAes;
90 let rng = boring::BoringRng;
91 let req_aad = self.seq_num_outgoing.get_then_increment()?;
92 let request_bytes = cipher::encrypt_message(
93 &aes_gcm,
94 &rng,
95 &self.encryption_key,
96 &self.session_id,
97 req_data,
98 &req_aad,
99 )
100 .map_err(Error::CipherError)?;
101
102 let response_bytes = self.sk.processSecretManagementRequest(&request_bytes)?;
103
104 let response_encrypt0 = CoseEncrypt0::from_slice(&response_bytes)?;
105 let expected_res_aad = self.seq_num_incoming.get_then_increment()?;
106 cipher::decrypt_message(
107 &aes_gcm,
108 &self.decryption_key,
109 &response_encrypt0,
110 &expected_res_aad,
111 )
112 .map_err(Error::CipherError)
113 }
114
115 /// Get the encryption key corresponding to the session. Note on usage: This (along with other
116 /// getters [`decryption_key()`] & [`session_id()`]) can be used for custom encrypting requests
117 /// (for ex, with different aad, instead of using [`secret_management_request`] method.
118 /// In that case, seq_num_outgoing & seq_num_incoming will be out of sync. Recommended use for
119 /// testing only.
encryption_key(&self) -> &key::AesKey120 pub fn encryption_key(&self) -> &key::AesKey {
121 &self.encryption_key
122 }
123
124 /// Get the decryption key corresponding to the session.
decryption_key(&self) -> &key::AesKey125 pub fn decryption_key(&self) -> &key::AesKey {
126 &self.decryption_key
127 }
128
129 /// Get the session_id.
session_id(&self) -> &[u8]130 pub fn session_id(&self) -> &[u8] {
131 &self.session_id
132 }
133 }
134
135 impl fmt::Debug for SkSession {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result136 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
137 f.debug_struct("SkSession").field("session_id", &hex::encode(&self.session_id)).finish()
138 }
139 }
140
141 /// Errors thrown by this SkSession.
142 #[derive(Debug)]
143 pub enum Error {
144 /// These are server errors : thrown from remote instance (of Authgraph or Secretkeeper)
145 BinderStatus(binder::Status),
146 /// These are errors thrown from (local) source Authgraph instance.
147 AuthgraphError(authgraph_core::error::Error),
148 /// Error originating while encryption/decryption of packets (at source).
149 CipherError(ApiError),
150 /// Errors originating in the coset library.
151 CoseError(coset::CoseError),
152 /// Unexpected item encountered (got, want).
153 UnexpectedItem(&'static str, &'static str),
154 /// The set of errors from secretkeeper_comm library.
155 SkCommError(secretkeeper_comm::data_types::error::Error),
156 }
157
158 impl std::error::Error for Error {}
159
160 impl std::fmt::Display for Error {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result161 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
162 match self {
163 Self::BinderStatus(e) => write!(f, "Binder error {e:?}"),
164 Self::AuthgraphError(e) => write!(f, "Local Authgraph instance error {e:?}"),
165 Self::CipherError(e) => write!(f, "Error in encryption/decryption of packets {e:?}"),
166 Self::CoseError(e) => write!(f, "Errors originating in the coset library {e:?}"),
167 Self::UnexpectedItem(got, want) => {
168 write!(f, "Unexpected item - Got:{got}, Expected:{want}")
169 }
170 Self::SkCommError(e) => write!(f, "secretkeeper_comm error: {e:?}"),
171 }
172 }
173 }
174
175 impl From<authgraph_core::error::Error> for Error {
from(e: authgraph_core::error::Error) -> Self176 fn from(e: authgraph_core::error::Error) -> Self {
177 Self::AuthgraphError(e)
178 }
179 }
180
181 impl From<binder::Status> for Error {
from(s: binder::Status) -> Self182 fn from(s: binder::Status) -> Self {
183 Self::BinderStatus(s)
184 }
185 }
186
187 impl From<coset::CoseError> for Error {
from(e: coset::CoseError) -> Self188 fn from(e: coset::CoseError) -> Self {
189 Self::CoseError(e)
190 }
191 }
192
193 impl From<secretkeeper_comm::data_types::error::Error> for Error {
from(e: secretkeeper_comm::data_types::error::Error) -> Self194 fn from(e: secretkeeper_comm::data_types::error::Error) -> Self {
195 Self::SkCommError(e)
196 }
197 }
198
199 /// 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>200 fn authgraph_key_exchange(
201 sk: binder::Strong<dyn ISecretkeeper>,
202 ag_dev: Rc<RefCell<AgDevice>>,
203 ) -> Result<([key::AesKey; 2], Vec<u8>), Error> {
204 let sink = sk.getAuthGraphKe()?;
205 let mut source = ke::AuthGraphParticipant::new(
206 boring::crypto_trait_impls(),
207 ag_dev,
208 1, // Each SkSession supports only 1 open Authgraph session.
209 )?;
210 key_exchange(&mut source, sink)
211 }
212
213 /// Perform AuthGraph key exchange with the provided sink and local source implementation.
214 /// 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>215 fn key_exchange(
216 local_source: &mut ke::AuthGraphParticipant,
217 sink: binder::Strong<dyn IAuthGraphKeyExchange>,
218 ) -> Result<([key::AesKey; 2], Vec<u8>), Error> {
219 // Step 1: create an ephemeral ECDH key at the (local) source.
220 let source_init_info = local_source.create()?;
221
222 // Step 2: pass the source's ECDH public key and other session info to the (remote) sink.
223 let init_result = sink.init(
224 &build_plain_pub_key(&source_init_info.ke_key.pub_key)?,
225 &vec_to_identity(&source_init_info.identity),
226 &source_init_info.nonce,
227 source_init_info.version,
228 )?;
229 let sink_init_info = init_result.sessionInitiationInfo;
230 let sink_pub_key = extract_plain_pub_key(&sink_init_info.key.pubKey)?;
231 let sink_info = init_result.sessionInfo;
232
233 // Step 3: pass the sink's ECDH public key and other session info to the (local) source, so it
234 // can calculate the same pair of symmetric keys.
235 let source_info = local_source.finish(
236 &sink_pub_key.plainPubKey,
237 &sink_init_info.identity.identity,
238 &sink_info.signature.signature,
239 &sink_init_info.nonce,
240 sink_init_info.version,
241 source_init_info.ke_key,
242 )?;
243
244 // Step 4: pass the (local) source's session ID signature back to the sink, so it can check it
245 // and update the symmetric keys so they're marked as authentication complete.
246 let _sink_arcs = sink.authenticationComplete(
247 &vec_to_signature(&source_info.session_id_signature),
248 &sink_info.sharedKeys,
249 )?;
250
251 // Decrypt and return the session keys.
252 let decrypted_shared_keys_array = local_source
253 .decipher_shared_keys_from_arcs(&source_info.shared_keys)?
254 .try_into()
255 .map_err(|_| Error::UnexpectedItem("Array", "Array of size 2"))?;
256
257 Ok((decrypted_shared_keys_array, source_info.session_id))
258 }
259
build_plain_pub_key(pub_key: &Option<Vec<u8>>) -> Result<PubKey, Error>260 fn build_plain_pub_key(pub_key: &Option<Vec<u8>>) -> Result<PubKey, Error> {
261 Ok(PubKey::PlainKey(PlainPubKey {
262 plainPubKey: pub_key.clone().ok_or(Error::UnexpectedItem("None", "Some bytes"))?,
263 }))
264 }
265
extract_plain_pub_key(pub_key: &Option<PubKey>) -> Result<&PlainPubKey, Error>266 fn extract_plain_pub_key(pub_key: &Option<PubKey>) -> Result<&PlainPubKey, Error> {
267 match pub_key {
268 Some(PubKey::PlainKey(pub_key)) => Ok(pub_key),
269 Some(PubKey::SignedKey(_)) => Err(Error::UnexpectedItem("Signed Key", "Public Key")),
270 None => Err(Error::UnexpectedItem("No key", "Public key")),
271 }
272 }
273
vec_to_identity(data: &[u8]) -> Identity274 fn vec_to_identity(data: &[u8]) -> Identity {
275 Identity { identity: data.to_vec() }
276 }
277
vec_to_signature(data: &[u8]) -> SessionIdSignature278 fn vec_to_signature(data: &[u8]) -> SessionIdSignature {
279 SessionIdSignature { signature: data.to_vec() }
280 }
281
282 #[cfg(test)]
283 rdroidtest::test_main!();
284