blob: 2112e58176ff4013919a37d864ef953f00be827d [file] [log] [blame]
David Drysdale7fd838c2023-10-05 13:07:28 +01001/*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//! Default implementation of the AuthGraph key exchange HAL.
18//!
19//! This implementation of the HAL is only intended to allow testing and policy compliance. A real
20//! implementation of the AuthGraph HAL would be implemented in a secure environment, and would not
21//! be independently registered with service manager (a secure component that uses AuthGraph would
22//! expose an entrypoint that allowed retrieval of the specific IAuthGraphKeyExchange instance that
23//! is correlated with the component).
24
25use android_hardware_security_authgraph::aidl::android::hardware::security::authgraph::{
26 Arc::Arc, IAuthGraphKeyExchange::BnAuthGraphKeyExchange,
27 IAuthGraphKeyExchange::IAuthGraphKeyExchange, Identity::Identity, KeInitResult::KeInitResult,
28 Key::Key, PubKey::PubKey, SessionIdSignature::SessionIdSignature, SessionInfo::SessionInfo,
29 SessionInitiationInfo::SessionInitiationInfo,
30};
31use authgraph_boringssl as boring;
32use authgraph_core::{key::MillisecondsSinceEpoch, keyexchange as ke, traits};
33use authgraph_hal::{err_to_binder, Innto, TryInnto};
34use log::{error, info};
35use std::ffi::CString;
36use std::sync::Mutex;
37
38static SERVICE_NAME: &str = "android.hardware.security.authgraph.IAuthGraphKeyExchange";
39static SERVICE_INSTANCE: &str = "nonsecure";
40
41/// Local error type for failures in the HAL service.
42#[derive(Debug, Clone)]
43struct HalServiceError(String);
44
45impl From<String> for HalServiceError {
46 fn from(s: String) -> Self {
47 Self(s)
48 }
49}
50
51fn main() {
52 if let Err(e) = inner_main() {
53 panic!("HAL service failed: {:?}", e);
54 }
55}
56
57fn inner_main() -> Result<(), HalServiceError> {
58 // Initialize Android logging.
59 android_logger::init_once(
60 android_logger::Config::default()
61 .with_tag("authgraph-hal-nonsecure")
62 .with_min_level(log::Level::Info)
63 .with_log_id(android_logger::LogId::System),
64 );
65 // Redirect panic messages to logcat.
66 std::panic::set_hook(Box::new(|panic_info| {
67 error!("{}", panic_info);
68 }));
69
70 info!("Insecure AuthGraph key exchange HAL service is starting.");
71
72 info!("Starting thread pool now.");
73 binder::ProcessState::start_thread_pool();
74
75 // Register the service
76 let service = AuthGraphService::new_as_binder();
77 let service_name = format!("{}/{}", SERVICE_NAME, SERVICE_INSTANCE);
78 binder::add_service(&service_name, service.as_binder()).map_err(|e| {
79 format!(
80 "Failed to register service {} because of {:?}.",
81 service_name, e
82 )
83 })?;
84
85 info!("Successfully registered AuthGraph HAL services.");
86 binder::ProcessState::join_thread_pool();
87 info!("AuthGraph HAL service is terminating."); // should not reach here
88 Ok(())
89}
90
91/// Non-secure implementation of the AuthGraph key exchange service.
92struct AuthGraphService {
93 imp: Mutex<traits::TraitImpl>,
94}
95
96impl AuthGraphService {
97 /// Create a new instance.
98 fn new() -> Self {
99 Self {
100 imp: Mutex::new(traits::TraitImpl {
101 aes_gcm: Box::new(boring::BoringAes),
102 ecdh: Box::new(boring::BoringEcDh),
103 ecdsa: Box::new(boring::BoringEcDsa),
104 hmac: Box::new(boring::BoringHmac),
105 hkdf: Box::new(boring::BoringHkdf),
106 sha256: Box::new(boring::BoringSha256),
107 rng: Box::new(boring::BoringRng),
108 device: Box::<boring::test_device::AgDevice>::default(),
109 clock: Some(Box::new(StdClock)),
110 }),
111 }
112 }
113
114 /// Create a new instance wrapped in a proxy object.
115 pub fn new_as_binder() -> binder::Strong<dyn IAuthGraphKeyExchange> {
116 BnAuthGraphKeyExchange::new_binder(Self::new(), binder::BinderFeatures::default())
117 }
118}
119
120impl binder::Interface for AuthGraphService {}
121
122/// Extract (and require) an unsigned public key as bytes from a [`PubKey`].
123fn unsigned_pub_key(pub_key: &PubKey) -> binder::Result<&[u8]> {
124 match pub_key {
125 PubKey::PlainKey(key) => Ok(&key.plainPubKey),
126 PubKey::SignedKey(_) => Err(binder::Status::new_exception(
127 binder::ExceptionCode::ILLEGAL_ARGUMENT,
128 Some(&CString::new("expected unsigned public key").unwrap()),
129 )),
130 }
131}
132
133/// This nonsecure implementation of the AuthGraph HAL interface directly calls the AuthGraph
134/// reference implementation library code; a real implementation requires the AuthGraph
135/// code to run in a secure environment, not within Android.
136impl IAuthGraphKeyExchange for AuthGraphService {
137 fn create(&self) -> binder::Result<SessionInitiationInfo> {
138 info!("create()");
139 let mut imp = self.imp.lock().unwrap();
140 let info = ke::create(&mut *imp).map_err(err_to_binder)?;
141 Ok(info.innto())
142 }
143 fn init(
144 &self,
145 peer_pub_key: &PubKey,
146 peer_id: &Identity,
147 peer_nonce: &[u8],
148 peer_version: i32,
149 ) -> binder::Result<KeInitResult> {
150 info!("init(v={peer_version})");
151 let mut imp = self.imp.lock().unwrap();
152 let peer_pub_key = unsigned_pub_key(peer_pub_key)?;
153 let result = ke::init(
154 &mut *imp,
155 peer_pub_key,
156 &peer_id.identity,
157 &peer_nonce,
158 peer_version,
159 )
160 .map_err(err_to_binder)?;
161 Ok(result.innto())
162 }
163
164 fn finish(
165 &self,
166 peer_pub_key: &PubKey,
167 peer_id: &Identity,
168 peer_signature: &SessionIdSignature,
169 peer_nonce: &[u8],
170 peer_version: i32,
171 own_key: &Key,
172 ) -> binder::Result<SessionInfo> {
173 info!("finish(v={peer_version})");
174 let mut imp = self.imp.lock().unwrap();
175 let peer_pub_key = unsigned_pub_key(peer_pub_key)?;
176 let own_key: Key = own_key.clone();
177 let own_key: authgraph_core::key::Key = own_key.try_innto()?;
178 let session_info = ke::finish(
179 &mut *imp,
180 peer_pub_key,
181 &peer_id.identity,
182 &peer_signature.signature,
183 &peer_nonce,
184 peer_version,
185 own_key,
186 )
187 .map_err(err_to_binder)?;
188 Ok(session_info.innto())
189 }
190
191 fn authenticationComplete(
192 &self,
193 peer_signature: &SessionIdSignature,
194 shared_keys: &[Arc; 2],
195 ) -> binder::Result<[Arc; 2]> {
196 info!("authComplete()");
197 let mut imp = self.imp.lock().unwrap();
198 let shared_keys = [shared_keys[0].arc.clone(), shared_keys[1].arc.clone()];
199 let arcs = ke::authentication_complete(&mut *imp, &peer_signature.signature, shared_keys)
200 .map_err(err_to_binder)?;
201 Ok(arcs.map(|arc| Arc { arc }))
202 }
203}
204
205/// Monotonic clock.
206#[derive(Default)]
207pub struct StdClock;
208
209impl traits::MonotonicClock for StdClock {
210 fn now(&self) -> authgraph_core::key::MillisecondsSinceEpoch {
211 let mut time = libc::timespec {
212 tv_sec: 0, // libc::time_t
213 tv_nsec: 0, // libc::c_long
214 };
215 let rc =
216 // Safety: `time` is a valid structure.
217 unsafe { libc::clock_gettime(libc::CLOCK_BOOTTIME, &mut time as *mut libc::timespec) };
218 if rc < 0 {
219 log::warn!("failed to get time!");
220 return MillisecondsSinceEpoch(0);
221 }
222 // The types in `libc::timespec` may be different on different architectures,
223 // so allow conversion to `i64`.
224 #[allow(clippy::unnecessary_cast)]
225 MillisecondsSinceEpoch((time.tv_sec as i64 * 1000) + (time.tv_nsec as i64 / 1000 / 1000))
226 }
227}