blob: 0cbe8de4166efc5a50a0aa3ab5be783d1c86959a [file] [log] [blame]
Alan Stokes337874a2021-06-16 16:49:32 +01001// Copyright 2021, 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//! Provides a binder service for key generation & verification for CompOs. We assume we have
16//! access to Keystore in the VM, but not persistent storage; instead the host stores the key
17//! on our behalf via this service.
18
19use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
20 Algorithm::Algorithm, Digest::Digest, KeyParameter::KeyParameter,
21 KeyParameterValue::KeyParameterValue, KeyPurpose::KeyPurpose, PaddingMode::PaddingMode,
22 SecurityLevel::SecurityLevel, Tag::Tag,
23};
24use android_system_keystore2::aidl::android::system::keystore2::{
25 Domain::Domain, IKeystoreSecurityLevel::IKeystoreSecurityLevel,
26 IKeystoreService::IKeystoreService, KeyDescriptor::KeyDescriptor,
27};
28use anyhow::{anyhow, Context, Result};
29use compos_aidl_interface::aidl::com::android::compos::{
30 CompOsKeyData::CompOsKeyData,
31 ICompOsKeyService::{BnCompOsKeyService, ICompOsKeyService},
32};
33use compos_aidl_interface::binder::{
34 self, add_service, get_interface, BinderFeatures, ExceptionCode, Interface, ProcessState,
35 Status, Strong,
36};
37use log::{info, warn, Level};
38use ring::rand::{SecureRandom, SystemRandom};
39use ring::signature;
40use scopeguard::ScopeGuard;
41use std::ffi::CString;
Alan Stokes337874a2021-06-16 16:49:32 +010042
43const LOG_TAG: &str = "CompOsKeyService";
44const OUR_SERVICE_NAME: &str = "android.system.composkeyservice";
45
46const KEYSTORE_SERVICE_NAME: &str = "android.system.keystore2.IKeystoreService/default";
47const COMPOS_NAMESPACE: i64 = 101;
48const PURPOSE_SIGN: KeyParameter =
49 KeyParameter { tag: Tag::PURPOSE, value: KeyParameterValue::KeyPurpose(KeyPurpose::SIGN) };
50const ALGORITHM: KeyParameter =
51 KeyParameter { tag: Tag::ALGORITHM, value: KeyParameterValue::Algorithm(Algorithm::RSA) };
52const PADDING: KeyParameter = KeyParameter {
53 tag: Tag::PADDING,
54 value: KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
55};
56const DIGEST: KeyParameter =
57 KeyParameter { tag: Tag::DIGEST, value: KeyParameterValue::Digest(Digest::SHA_2_256) };
58const KEY_SIZE: KeyParameter =
59 KeyParameter { tag: Tag::KEY_SIZE, value: KeyParameterValue::Integer(2048) };
60const EXPONENT: KeyParameter =
61 KeyParameter { tag: Tag::RSA_PUBLIC_EXPONENT, value: KeyParameterValue::LongInteger(65537) };
62const NO_AUTH_REQUIRED: KeyParameter =
63 KeyParameter { tag: Tag::NO_AUTH_REQUIRED, value: KeyParameterValue::BoolValue(true) };
64
65const KEY_DESCRIPTOR: KeyDescriptor =
66 KeyDescriptor { domain: Domain::BLOB, nspace: COMPOS_NAMESPACE, alias: None, blob: None };
67
68struct CompOsKeyService {
69 random: SystemRandom,
Alan Stokes337874a2021-06-16 16:49:32 +010070 security_level: Strong<dyn IKeystoreSecurityLevel>,
71}
72
73impl Interface for CompOsKeyService {}
74
75impl ICompOsKeyService for CompOsKeyService {
76 fn generateSigningKey(&self) -> binder::Result<CompOsKeyData> {
77 self.do_generate()
78 .map_err(|e| new_binder_exception(ExceptionCode::ILLEGAL_STATE, e.to_string()))
79 }
80
81 fn verifySigningKey(&self, key_blob: &[u8], public_key: &[u8]) -> binder::Result<bool> {
82 Ok(if let Err(e) = self.do_verify(key_blob, public_key) {
83 warn!("Signing key verification failed: {}", e.to_string());
84 false
85 } else {
86 true
87 })
88 }
89}
90
91/// Constructs a new Binder error `Status` with the given `ExceptionCode` and message.
92fn new_binder_exception<T: AsRef<str>>(exception: ExceptionCode, message: T) -> Status {
93 Status::new_exception(exception, CString::new(message.as_ref()).ok().as_deref())
94}
95
96impl CompOsKeyService {
97 fn new(keystore_service: &Strong<dyn IKeystoreService>) -> Self {
98 Self {
99 random: SystemRandom::new(),
Alan Stokes4a489d42021-06-28 10:12:05 +0100100 security_level: keystore_service
101 .getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT)
102 .unwrap(),
Alan Stokes337874a2021-06-16 16:49:32 +0100103 }
104 }
105
Alan Stokes337874a2021-06-16 16:49:32 +0100106 fn do_generate(&self) -> Result<CompOsKeyData> {
107 let key_parameters =
108 [PURPOSE_SIGN, ALGORITHM, PADDING, DIGEST, KEY_SIZE, EXPONENT, NO_AUTH_REQUIRED];
109 let attestation_key = None;
110 let flags = 0;
111 let entropy = [];
112
113 let key_metadata = self
Alan Stokes4a489d42021-06-28 10:12:05 +0100114 .security_level
Alan Stokes337874a2021-06-16 16:49:32 +0100115 .generateKey(&KEY_DESCRIPTOR, attestation_key, &key_parameters, flags, &entropy)
116 .context("Generating key failed")?;
117
118 if let (Some(certificate), Some(blob)) = (key_metadata.certificate, key_metadata.key.blob) {
119 Ok(CompOsKeyData { certificate, keyBlob: blob })
120 } else {
121 Err(anyhow!("Missing cert or blob"))
122 }
123 }
124
125 fn do_verify(&self, key_blob: &[u8], public_key: &[u8]) -> Result<()> {
126 let mut data = [0u8; 32];
127 self.random.fill(&mut data).context("No random data")?;
128
129 let signature = self.sign(key_blob, &data)?;
130
131 let public_key =
132 signature::UnparsedPublicKey::new(&signature::RSA_PKCS1_2048_8192_SHA256, public_key);
133 public_key.verify(&data, &signature).context("Signature verification failed")?;
134
135 Ok(())
136 }
137
138 fn sign(&self, key_blob: &[u8], data: &[u8]) -> Result<Vec<u8>> {
139 let key_descriptor = KeyDescriptor { blob: Some(key_blob.to_vec()), ..KEY_DESCRIPTOR };
140 let operation_parameters = [PURPOSE_SIGN, ALGORITHM, PADDING, DIGEST];
141 let forced = false;
142
143 let response = self
Alan Stokes4a489d42021-06-28 10:12:05 +0100144 .security_level
Alan Stokes337874a2021-06-16 16:49:32 +0100145 .createOperation(&key_descriptor, &operation_parameters, forced)
146 .context("Creating key failed")?;
147 let operation = scopeguard::guard(
148 response.iOperation.ok_or_else(|| anyhow!("No operation created"))?,
149 |op| op.abort().unwrap_or_default(),
150 );
151
152 if response.operationChallenge.is_some() {
153 return Err(anyhow!("Key requires user authorization"));
154 }
155
156 let signature = operation.finish(Some(&data), None).context("Signing failed")?;
157 // Operation has finished, we're no longer responsible for aborting it
158 ScopeGuard::into_inner(operation);
159
160 signature.ok_or_else(|| anyhow!("No signature returned"))
161 }
162}
163
164fn main() -> Result<()> {
165 android_logger::init_once(
166 android_logger::Config::default().with_tag(LOG_TAG).with_min_level(Level::Trace),
167 );
168
169 // We need to start the thread pool for Binder to work properly.
170 ProcessState::start_thread_pool();
171
172 let keystore_service = get_interface::<dyn IKeystoreService>(KEYSTORE_SERVICE_NAME)
173 .context("No Keystore service")?;
174 let service = CompOsKeyService::new(&keystore_service);
175 let service = BnCompOsKeyService::new_binder(service, BinderFeatures::default());
176
177 add_service(OUR_SERVICE_NAME, service.as_binder()).context("Adding service failed")?;
178 info!("It's alive!");
179
180 ProcessState::join_thread_pool();
181
182 Ok(())
183}