blob: dd28faa9459d28feaf385dcd3267cfa0eef91b31 [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
Alan Stokes7ec4e7f2021-07-21 11:29:10 +010019use crate::compsvc;
20use crate::signer::Signer;
Alan Stokes337874a2021-06-16 16:49:32 +010021use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
22 Algorithm::Algorithm, Digest::Digest, KeyParameter::KeyParameter,
23 KeyParameterValue::KeyParameterValue, KeyPurpose::KeyPurpose, PaddingMode::PaddingMode,
24 SecurityLevel::SecurityLevel, Tag::Tag,
25};
26use android_system_keystore2::aidl::android::system::keystore2::{
27 Domain::Domain, IKeystoreSecurityLevel::IKeystoreSecurityLevel,
28 IKeystoreService::IKeystoreService, KeyDescriptor::KeyDescriptor,
29};
30use anyhow::{anyhow, Context, Result};
31use compos_aidl_interface::aidl::com::android::compos::{
Alan Stokes7ec4e7f2021-07-21 11:29:10 +010032 CompOsKeyData::CompOsKeyData,
33 ICompOsKeyService::{BnCompOsKeyService, ICompOsKeyService},
Victor Hsieha64194b2021-08-06 17:43:36 -070034 ICompOsService::ICompOsService,
Alan Stokes337874a2021-06-16 16:49:32 +010035};
36use compos_aidl_interface::binder::{
Alan Stokes7ec4e7f2021-07-21 11:29:10 +010037 self, wait_for_interface, BinderFeatures, ExceptionCode, Interface, Status, Strong,
Alan Stokes337874a2021-06-16 16:49:32 +010038};
Alan Stokes8ccebf12021-07-14 12:04:31 +010039use log::warn;
Alan Stokes337874a2021-06-16 16:49:32 +010040use ring::rand::{SecureRandom, SystemRandom};
41use ring::signature;
42use scopeguard::ScopeGuard;
43use std::ffi::CString;
Alan Stokes337874a2021-06-16 16:49:32 +010044
Alan Stokesb15c93f2021-07-15 16:21:50 +010045/// Keystore2 namespace IDs, used for access control to keys.
46#[derive(Copy, Clone, Debug, PartialEq, Eq)]
47pub enum KeystoreNamespace {
48 /// In the host we re-use the ID assigned to odsign. See system/sepolicy/private/keystore2_key_contexts.
49 // TODO(alanstokes): Remove this.
50 Odsign = 101,
51 /// In a VM we can use the generic ID allocated for payloads. See microdroid's keystore2_key_contexts.
52 VmPayload = 140,
53}
54
Alan Stokes7ec4e7f2021-07-21 11:29:10 +010055/// Constructs a binder object that implements ICompOsKeyService. namespace is the Keystore2 namespace to
56/// use for the keys.
Victor Hsieha64194b2021-08-06 17:43:36 -070057#[allow(dead_code)] // for compsvc
Alan Stokes7ec4e7f2021-07-21 11:29:10 +010058pub fn new(namespace: KeystoreNamespace) -> Result<Strong<dyn ICompOsKeyService>> {
Victor Hsieha64194b2021-08-06 17:43:36 -070059 let service = CompOsKeyService::new(namespace)?;
Alan Stokes7ec4e7f2021-07-21 11:29:10 +010060 Ok(BnCompOsKeyService::new_binder(service, BinderFeatures::default()))
61}
62
Alan Stokes337874a2021-06-16 16:49:32 +010063const KEYSTORE_SERVICE_NAME: &str = "android.system.keystore2.IKeystoreService/default";
Alan Stokes337874a2021-06-16 16:49:32 +010064const PURPOSE_SIGN: KeyParameter =
65 KeyParameter { tag: Tag::PURPOSE, value: KeyParameterValue::KeyPurpose(KeyPurpose::SIGN) };
66const ALGORITHM: KeyParameter =
67 KeyParameter { tag: Tag::ALGORITHM, value: KeyParameterValue::Algorithm(Algorithm::RSA) };
68const PADDING: KeyParameter = KeyParameter {
69 tag: Tag::PADDING,
70 value: KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
71};
72const DIGEST: KeyParameter =
73 KeyParameter { tag: Tag::DIGEST, value: KeyParameterValue::Digest(Digest::SHA_2_256) };
74const KEY_SIZE: KeyParameter =
75 KeyParameter { tag: Tag::KEY_SIZE, value: KeyParameterValue::Integer(2048) };
76const EXPONENT: KeyParameter =
77 KeyParameter { tag: Tag::RSA_PUBLIC_EXPONENT, value: KeyParameterValue::LongInteger(65537) };
78const NO_AUTH_REQUIRED: KeyParameter =
79 KeyParameter { tag: Tag::NO_AUTH_REQUIRED, value: KeyParameterValue::BoolValue(true) };
80
Alan Stokesb15c93f2021-07-15 16:21:50 +010081const BLOB_KEY_DESCRIPTOR: KeyDescriptor =
82 KeyDescriptor { domain: Domain::BLOB, nspace: 0, alias: None, blob: None };
Alan Stokes337874a2021-06-16 16:49:32 +010083
Victor Hsieha64194b2021-08-06 17:43:36 -070084/// An internal service for CompOS key management.
Alan Stokes7ec4e7f2021-07-21 11:29:10 +010085#[derive(Clone)]
Victor Hsieha64194b2021-08-06 17:43:36 -070086pub struct CompOsKeyService {
Alan Stokesb15c93f2021-07-15 16:21:50 +010087 namespace: KeystoreNamespace,
Alan Stokes337874a2021-06-16 16:49:32 +010088 random: SystemRandom,
Alan Stokes337874a2021-06-16 16:49:32 +010089 security_level: Strong<dyn IKeystoreSecurityLevel>,
90}
91
92impl Interface for CompOsKeyService {}
93
94impl ICompOsKeyService for CompOsKeyService {
95 fn generateSigningKey(&self) -> binder::Result<CompOsKeyData> {
96 self.do_generate()
97 .map_err(|e| new_binder_exception(ExceptionCode::ILLEGAL_STATE, e.to_string()))
98 }
99
100 fn verifySigningKey(&self, key_blob: &[u8], public_key: &[u8]) -> binder::Result<bool> {
101 Ok(if let Err(e) = self.do_verify(key_blob, public_key) {
102 warn!("Signing key verification failed: {}", e.to_string());
103 false
104 } else {
105 true
106 })
107 }
Alan Stokesc3bab542021-07-06 15:48:33 +0100108
109 fn sign(&self, key_blob: &[u8], data: &[u8]) -> binder::Result<Vec<u8>> {
110 self.do_sign(key_blob, data)
111 .map_err(|e| new_binder_exception(ExceptionCode::ILLEGAL_STATE, e.to_string()))
112 }
Alan Stokes7ec4e7f2021-07-21 11:29:10 +0100113
Victor Hsieha64194b2021-08-06 17:43:36 -0700114 fn getCompOsService(&self, key_blob: &[u8]) -> binder::Result<Strong<dyn ICompOsService>> {
Alan Stokes7ec4e7f2021-07-21 11:29:10 +0100115 let signer =
116 Box::new(CompOsSigner { key_blob: key_blob.to_owned(), key_service: self.clone() });
Victor Hsieha64194b2021-08-06 17:43:36 -0700117 let rpc_binder = true; // don't care
118 compsvc::new_binder(rpc_binder, Some(signer))
119 .map_err(|e| new_binder_exception(ExceptionCode::ILLEGAL_STATE, e.to_string()))
Alan Stokes7ec4e7f2021-07-21 11:29:10 +0100120 }
Alan Stokes337874a2021-06-16 16:49:32 +0100121}
122
123/// Constructs a new Binder error `Status` with the given `ExceptionCode` and message.
124fn new_binder_exception<T: AsRef<str>>(exception: ExceptionCode, message: T) -> Status {
125 Status::new_exception(exception, CString::new(message.as_ref()).ok().as_deref())
126}
127
Alan Stokes7ec4e7f2021-07-21 11:29:10 +0100128struct CompOsSigner {
129 key_blob: Vec<u8>,
130 key_service: CompOsKeyService,
131}
Alan Stokes8ccebf12021-07-14 12:04:31 +0100132
Alan Stokes7ec4e7f2021-07-21 11:29:10 +0100133impl Signer for CompOsSigner {
134 fn sign(&self, data: &[u8]) -> Result<Vec<u8>> {
135 self.key_service.do_sign(&self.key_blob, data)
Alan Stokes337874a2021-06-16 16:49:32 +0100136 }
Alan Stokes7ec4e7f2021-07-21 11:29:10 +0100137}
Alan Stokes337874a2021-06-16 16:49:32 +0100138
Alan Stokes7ec4e7f2021-07-21 11:29:10 +0100139impl CompOsKeyService {
Victor Hsieha64194b2021-08-06 17:43:36 -0700140 pub fn new(namespace: KeystoreNamespace) -> Result<Self> {
141 let keystore_service = wait_for_interface::<dyn IKeystoreService>(KEYSTORE_SERVICE_NAME)
142 .context("No Keystore service")?;
143
144 Ok(CompOsKeyService {
145 namespace,
146 random: SystemRandom::new(),
147 security_level: keystore_service
148 .getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT)
149 .context("Getting SecurityLevel failed")?,
150 })
151 }
152
Alan Stokes337874a2021-06-16 16:49:32 +0100153 fn do_generate(&self) -> Result<CompOsKeyData> {
Alan Stokesb15c93f2021-07-15 16:21:50 +0100154 let key_descriptor = KeyDescriptor { nspace: self.namespace as i64, ..BLOB_KEY_DESCRIPTOR };
Alan Stokes337874a2021-06-16 16:49:32 +0100155 let key_parameters =
156 [PURPOSE_SIGN, ALGORITHM, PADDING, DIGEST, KEY_SIZE, EXPONENT, NO_AUTH_REQUIRED];
157 let attestation_key = None;
158 let flags = 0;
159 let entropy = [];
160
161 let key_metadata = self
Alan Stokes4a489d42021-06-28 10:12:05 +0100162 .security_level
Alan Stokesb15c93f2021-07-15 16:21:50 +0100163 .generateKey(&key_descriptor, attestation_key, &key_parameters, flags, &entropy)
Alan Stokes337874a2021-06-16 16:49:32 +0100164 .context("Generating key failed")?;
165
166 if let (Some(certificate), Some(blob)) = (key_metadata.certificate, key_metadata.key.blob) {
167 Ok(CompOsKeyData { certificate, keyBlob: blob })
168 } else {
169 Err(anyhow!("Missing cert or blob"))
170 }
171 }
172
173 fn do_verify(&self, key_blob: &[u8], public_key: &[u8]) -> Result<()> {
174 let mut data = [0u8; 32];
175 self.random.fill(&mut data).context("No random data")?;
176
Alan Stokesc3bab542021-07-06 15:48:33 +0100177 let signature = self.do_sign(key_blob, &data)?;
Alan Stokes337874a2021-06-16 16:49:32 +0100178
179 let public_key =
180 signature::UnparsedPublicKey::new(&signature::RSA_PKCS1_2048_8192_SHA256, public_key);
181 public_key.verify(&data, &signature).context("Signature verification failed")?;
182
183 Ok(())
184 }
185
Alan Stokesc3bab542021-07-06 15:48:33 +0100186 fn do_sign(&self, key_blob: &[u8], data: &[u8]) -> Result<Vec<u8>> {
Alan Stokesb15c93f2021-07-15 16:21:50 +0100187 let key_descriptor = KeyDescriptor {
188 nspace: self.namespace as i64,
189 blob: Some(key_blob.to_vec()),
190 ..BLOB_KEY_DESCRIPTOR
191 };
Alan Stokes337874a2021-06-16 16:49:32 +0100192 let operation_parameters = [PURPOSE_SIGN, ALGORITHM, PADDING, DIGEST];
193 let forced = false;
194
195 let response = self
Alan Stokes4a489d42021-06-28 10:12:05 +0100196 .security_level
Alan Stokes337874a2021-06-16 16:49:32 +0100197 .createOperation(&key_descriptor, &operation_parameters, forced)
198 .context("Creating key failed")?;
199 let operation = scopeguard::guard(
200 response.iOperation.ok_or_else(|| anyhow!("No operation created"))?,
201 |op| op.abort().unwrap_or_default(),
202 );
203
204 if response.operationChallenge.is_some() {
205 return Err(anyhow!("Key requires user authorization"));
206 }
207
Chris Wailes68c39f82021-07-27 16:03:44 -0700208 let signature = operation.finish(Some(data), None).context("Signing failed")?;
Alan Stokes337874a2021-06-16 16:49:32 +0100209 // Operation has finished, we're no longer responsible for aborting it
210 ScopeGuard::into_inner(operation);
211
212 signature.ok_or_else(|| anyhow!("No signature returned"))
213 }
214}