1*d289c2baSAndroid Build Coastguard Worker // Copyright 2024, The Android Open Source Project
2*d289c2baSAndroid Build Coastguard Worker //
3*d289c2baSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*d289c2baSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*d289c2baSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*d289c2baSAndroid Build Coastguard Worker //
7*d289c2baSAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
8*d289c2baSAndroid Build Coastguard Worker //
9*d289c2baSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*d289c2baSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*d289c2baSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*d289c2baSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*d289c2baSAndroid Build Coastguard Worker // limitations under the License.
14*d289c2baSAndroid Build Coastguard Worker
15*d289c2baSAndroid Build Coastguard Worker //! libavb_cert support.
16*d289c2baSAndroid Build Coastguard Worker //!
17*d289c2baSAndroid Build Coastguard Worker //! libavb_cert is an optional extension on top of the standard libavb API. It provides two
18*d289c2baSAndroid Build Coastguard Worker //! additional features:
19*d289c2baSAndroid Build Coastguard Worker //!
20*d289c2baSAndroid Build Coastguard Worker //! 1. Key management
21*d289c2baSAndroid Build Coastguard Worker //! 2. Authenticated unlock
22*d289c2baSAndroid Build Coastguard Worker //!
23*d289c2baSAndroid Build Coastguard Worker //! # Key management
24*d289c2baSAndroid Build Coastguard Worker //! The standard avb `Ops` must provide callbacks to manually validate vbmeta signing keys. This can
25*d289c2baSAndroid Build Coastguard Worker //! become complicated when using best-practices such as key heirarchies and rotations, which often
26*d289c2baSAndroid Build Coastguard Worker //! results in implementations omitting these features and just using a single fixed key.
27*d289c2baSAndroid Build Coastguard Worker //!
28*d289c2baSAndroid Build Coastguard Worker //! libavb_cert enables these features more easily by internally managing a set of related keys:
29*d289c2baSAndroid Build Coastguard Worker //!
30*d289c2baSAndroid Build Coastguard Worker //! * Product root key (PRK): un-rotateable root key
31*d289c2baSAndroid Build Coastguard Worker //! * Product intermediate key (PIK): rotateable key signed by the PRK
32*d289c2baSAndroid Build Coastguard Worker //! * Product signing key (PSK): rotateable key signed by the PIK, used as the vbmeta key
33*d289c2baSAndroid Build Coastguard Worker //!
34*d289c2baSAndroid Build Coastguard Worker //! PIK and PSK rotations are supported by storing their versions as rollback indices, so that
35*d289c2baSAndroid Build Coastguard Worker //! once the keys have been rotated the rollback value updates and the older keys will no longer
36*d289c2baSAndroid Build Coastguard Worker //! be accepted.
37*d289c2baSAndroid Build Coastguard Worker //!
38*d289c2baSAndroid Build Coastguard Worker //! The device validates keys using a fixed blob of data called "permanent attributes", which can
39*d289c2baSAndroid Build Coastguard Worker //! authenticate via the PRK and never needs to change even when PIK/PSK are rotated.
40*d289c2baSAndroid Build Coastguard Worker //!
41*d289c2baSAndroid Build Coastguard Worker //! To use this functionality, implement the `CertOps` trait and forward
42*d289c2baSAndroid Build Coastguard Worker //! `validate_vbmeta_public_key()` and/or `validate_public_key_for_partition()` to the provided
43*d289c2baSAndroid Build Coastguard Worker //! `cert_validate_vbmeta_public_key()` implementation.
44*d289c2baSAndroid Build Coastguard Worker //!
45*d289c2baSAndroid Build Coastguard Worker //! # Authenticated unlock
46*d289c2baSAndroid Build Coastguard Worker //! Typically devices support fastboot commands such as `fastboot flashing unlock` to unlock the
47*d289c2baSAndroid Build Coastguard Worker //! bootloader. Authenticated unlock is an optional feature that additionally adds an authentication
48*d289c2baSAndroid Build Coastguard Worker //! requirement in order to unlock the bootloader.
49*d289c2baSAndroid Build Coastguard Worker //!
50*d289c2baSAndroid Build Coastguard Worker //! Authenticated unlock introduces one additional key, the product unlock key (PUK), which is
51*d289c2baSAndroid Build Coastguard Worker //! signed by the PIK. The PUK is in the same key heirarchy but a distinct key, so that access to
52*d289c2baSAndroid Build Coastguard Worker //! the PUK does not give the ability to sign images. When authenticated unlock is requested,
53*d289c2baSAndroid Build Coastguard Worker //! libavb_cert produces a randomized "challenge token" which the user must then properly sign with
54*d289c2baSAndroid Build Coastguard Worker //! the PUK in order to unlock.
55*d289c2baSAndroid Build Coastguard Worker //!
56*d289c2baSAndroid Build Coastguard Worker //! It's up to individual device policy how to use authenticated unlock. For example a device may
57*d289c2baSAndroid Build Coastguard Worker //! want to support standard un-authenticated unlock for most operations, but then additionally
58*d289c2baSAndroid Build Coastguard Worker //! use authenticated unlock to enable higher-privileged operations.
59*d289c2baSAndroid Build Coastguard Worker //!
60*d289c2baSAndroid Build Coastguard Worker //! An example unlock flow using fastboot might look like this:
61*d289c2baSAndroid Build Coastguard Worker //!
62*d289c2baSAndroid Build Coastguard Worker //! ```ignore
63*d289c2baSAndroid Build Coastguard Worker //! # 1. Generate an unlock challenge (the exact fastboot command is device-specific).
64*d289c2baSAndroid Build Coastguard Worker //! $ fastboot oem get-auth-unlock-challenge
65*d289c2baSAndroid Build Coastguard Worker //!
66*d289c2baSAndroid Build Coastguard Worker //! # Internally, the device calls `cert_generate_unlock_challenge()` to generate the token.
67*d289c2baSAndroid Build Coastguard Worker //!
68*d289c2baSAndroid Build Coastguard Worker //! # 2. Download the challenge token from the device.
69*d289c2baSAndroid Build Coastguard Worker //! $ fastboot get_staged /tmp/challenge.bin
70*d289c2baSAndroid Build Coastguard Worker //!
71*d289c2baSAndroid Build Coastguard Worker //! # 3. Sign the challenge with the PUK.
72*d289c2baSAndroid Build Coastguard Worker //! $ avbtool make_cert_unlock_credential \
73*d289c2baSAndroid Build Coastguard Worker //! --challenge /tmp/challenge.bin \
74*d289c2baSAndroid Build Coastguard Worker //! --output /tmp/signed.bin \
75*d289c2baSAndroid Build Coastguard Worker //! ... # see --help for full args
76*d289c2baSAndroid Build Coastguard Worker //!
77*d289c2baSAndroid Build Coastguard Worker //! # 4. Upload the signed credential back to the device.
78*d289c2baSAndroid Build Coastguard Worker //! $ fastboot stage /tmp/signed.bin
79*d289c2baSAndroid Build Coastguard Worker //!
80*d289c2baSAndroid Build Coastguard Worker //! # 5. Unlock the device (the exact fastboot command is device-specific).
81*d289c2baSAndroid Build Coastguard Worker //! $ fastboot oem auth-unlock
82*d289c2baSAndroid Build Coastguard Worker //!
83*d289c2baSAndroid Build Coastguard Worker //! # Internally, the device calls `cert_validate_unlock_credential()` to verify the credential.
84*d289c2baSAndroid Build Coastguard Worker //! ```
85*d289c2baSAndroid Build Coastguard Worker
86*d289c2baSAndroid Build Coastguard Worker use crate::{error::io_enum_to_result, ops, IoError, IoResult, Ops, PublicKeyForPartitionInfo};
87*d289c2baSAndroid Build Coastguard Worker use avb_bindgen::{
88*d289c2baSAndroid Build Coastguard Worker avb_cert_generate_unlock_challenge, avb_cert_validate_unlock_credential,
89*d289c2baSAndroid Build Coastguard Worker avb_cert_validate_vbmeta_public_key,
90*d289c2baSAndroid Build Coastguard Worker };
91*d289c2baSAndroid Build Coastguard Worker use core::{ffi::CStr, pin::pin};
92*d289c2baSAndroid Build Coastguard Worker #[cfg(feature = "uuid")]
93*d289c2baSAndroid Build Coastguard Worker use uuid::Uuid;
94*d289c2baSAndroid Build Coastguard Worker
95*d289c2baSAndroid Build Coastguard Worker /// libavb_cert permanent attributes.
96*d289c2baSAndroid Build Coastguard Worker pub use avb_bindgen::AvbCertPermanentAttributes as CertPermanentAttributes;
97*d289c2baSAndroid Build Coastguard Worker
98*d289c2baSAndroid Build Coastguard Worker /// Authenticated unlock challenge.
99*d289c2baSAndroid Build Coastguard Worker pub use avb_bindgen::AvbCertUnlockChallenge as CertUnlockChallenge;
100*d289c2baSAndroid Build Coastguard Worker
101*d289c2baSAndroid Build Coastguard Worker /// Signed authenticated unlock credential.
102*d289c2baSAndroid Build Coastguard Worker pub use avb_bindgen::AvbCertUnlockCredential as CertUnlockCredential;
103*d289c2baSAndroid Build Coastguard Worker
104*d289c2baSAndroid Build Coastguard Worker /// Size in bytes of a SHA256 digest.
105*d289c2baSAndroid Build Coastguard Worker pub const SHA256_DIGEST_SIZE: usize = avb_bindgen::AVB_SHA256_DIGEST_SIZE as usize;
106*d289c2baSAndroid Build Coastguard Worker
107*d289c2baSAndroid Build Coastguard Worker /// Product intermediate key (PIK) rollback index location.
108*d289c2baSAndroid Build Coastguard Worker ///
109*d289c2baSAndroid Build Coastguard Worker /// If using libavb_cert, make sure no vbmetas use this location, it must be reserved for the PIK.
110*d289c2baSAndroid Build Coastguard Worker pub const CERT_PIK_VERSION_LOCATION: usize = avb_bindgen::AVB_CERT_PIK_VERSION_LOCATION as usize;
111*d289c2baSAndroid Build Coastguard Worker
112*d289c2baSAndroid Build Coastguard Worker /// Product signing key (PSK) rollback index location.
113*d289c2baSAndroid Build Coastguard Worker ///
114*d289c2baSAndroid Build Coastguard Worker /// If using libavb_cert, make sure no vbmetas use this location, it must be reserved for the PSK.
115*d289c2baSAndroid Build Coastguard Worker pub const CERT_PSK_VERSION_LOCATION: usize = avb_bindgen::AVB_CERT_PSK_VERSION_LOCATION as usize;
116*d289c2baSAndroid Build Coastguard Worker
117*d289c2baSAndroid Build Coastguard Worker /// libavb_cert extension callbacks.
118*d289c2baSAndroid Build Coastguard Worker pub trait CertOps {
119*d289c2baSAndroid Build Coastguard Worker /// Reads the device's permanent attributes.
120*d289c2baSAndroid Build Coastguard Worker ///
121*d289c2baSAndroid Build Coastguard Worker /// The full permanent attributes are not required to be securely stored; corruption of this
122*d289c2baSAndroid Build Coastguard Worker /// data will result in failing to verify the images (denial-of-service), but will not change
123*d289c2baSAndroid Build Coastguard Worker /// the signing keys or allow improperly-signed images to verify.
124*d289c2baSAndroid Build Coastguard Worker ///
125*d289c2baSAndroid Build Coastguard Worker /// # Arguments
126*d289c2baSAndroid Build Coastguard Worker /// * `attributes`: permanent attributes to update; passed as an output parameter rather than a
127*d289c2baSAndroid Build Coastguard Worker /// return value due to the size (>1KiB).
128*d289c2baSAndroid Build Coastguard Worker ///
129*d289c2baSAndroid Build Coastguard Worker /// # Returns
130*d289c2baSAndroid Build Coastguard Worker /// Unit on success, error on failure.
read_permanent_attributes( &mut self, attributes: &mut CertPermanentAttributes, ) -> IoResult<()>131*d289c2baSAndroid Build Coastguard Worker fn read_permanent_attributes(
132*d289c2baSAndroid Build Coastguard Worker &mut self,
133*d289c2baSAndroid Build Coastguard Worker attributes: &mut CertPermanentAttributes,
134*d289c2baSAndroid Build Coastguard Worker ) -> IoResult<()>;
135*d289c2baSAndroid Build Coastguard Worker
136*d289c2baSAndroid Build Coastguard Worker /// Reads the SHA256 hash of the device's permanent attributes.
137*d289c2baSAndroid Build Coastguard Worker ///
138*d289c2baSAndroid Build Coastguard Worker /// This hash must be sourced from secure storage whenever the device is locked; corruption
139*d289c2baSAndroid Build Coastguard Worker /// of this data could result in changing the signing keys and allowing improperly-signed images
140*d289c2baSAndroid Build Coastguard Worker /// to pass verification.
141*d289c2baSAndroid Build Coastguard Worker ///
142*d289c2baSAndroid Build Coastguard Worker /// This may be calculated at runtime from `read_permanent_attributes()` only if the entire
143*d289c2baSAndroid Build Coastguard Worker /// permanent attributes are sourced from secure storage, but secure storage space is often
144*d289c2baSAndroid Build Coastguard Worker /// limited so it can be useful to only store the hash securely.
145*d289c2baSAndroid Build Coastguard Worker ///
146*d289c2baSAndroid Build Coastguard Worker /// # Returns
147*d289c2baSAndroid Build Coastguard Worker /// The 32-byte SHA256 digest on success, error on failure.
read_permanent_attributes_hash(&mut self) -> IoResult<[u8; SHA256_DIGEST_SIZE]>148*d289c2baSAndroid Build Coastguard Worker fn read_permanent_attributes_hash(&mut self) -> IoResult<[u8; SHA256_DIGEST_SIZE]>;
149*d289c2baSAndroid Build Coastguard Worker
150*d289c2baSAndroid Build Coastguard Worker /// Provides the key version for the rotateable keys.
151*d289c2baSAndroid Build Coastguard Worker ///
152*d289c2baSAndroid Build Coastguard Worker /// libavb_cert stores signing key versions as rollback indices; when this function is called it
153*d289c2baSAndroid Build Coastguard Worker /// indicates that the key at the given index location is using the given version.
154*d289c2baSAndroid Build Coastguard Worker ///
155*d289c2baSAndroid Build Coastguard Worker /// The exact steps to take when receiving this callback depend on device policy, but generally
156*d289c2baSAndroid Build Coastguard Worker /// these values should only be cached in this callback, and written to the rollback storage
157*d289c2baSAndroid Build Coastguard Worker /// only after the images are known to be successful.
158*d289c2baSAndroid Build Coastguard Worker ///
159*d289c2baSAndroid Build Coastguard Worker /// For example, a device using A/B boot slots should not update the key version rollbacks
160*d289c2baSAndroid Build Coastguard Worker /// until it knows for sure the new image works, otherwise an OTA could break the A/B fallback
161*d289c2baSAndroid Build Coastguard Worker /// behavior by updating the key version too soon and preventing falling back to the previous
162*d289c2baSAndroid Build Coastguard Worker /// slot.
163*d289c2baSAndroid Build Coastguard Worker ///
164*d289c2baSAndroid Build Coastguard Worker /// # Arguments
165*d289c2baSAndroid Build Coastguard Worker /// * `rollback_index_location`: rollback location to store this key version
166*d289c2baSAndroid Build Coastguard Worker /// * `key_version`: value to store in the rollback location
167*d289c2baSAndroid Build Coastguard Worker ///
168*d289c2baSAndroid Build Coastguard Worker /// # Returns
169*d289c2baSAndroid Build Coastguard Worker /// `None`; since the rollback should be cached rather than written immediately, this function
170*d289c2baSAndroid Build Coastguard Worker /// cannot fail.
set_key_version(&mut self, rollback_index_location: usize, key_version: u64)171*d289c2baSAndroid Build Coastguard Worker fn set_key_version(&mut self, rollback_index_location: usize, key_version: u64);
172*d289c2baSAndroid Build Coastguard Worker
173*d289c2baSAndroid Build Coastguard Worker /// Generates random bytes.
174*d289c2baSAndroid Build Coastguard Worker ///
175*d289c2baSAndroid Build Coastguard Worker /// This is only used for authenticated unlock. If authenticated unlock is not needed, this can
176*d289c2baSAndroid Build Coastguard Worker /// just return `IoError::NotImplemented`.
177*d289c2baSAndroid Build Coastguard Worker ///
178*d289c2baSAndroid Build Coastguard Worker /// # Arguments
179*d289c2baSAndroid Build Coastguard Worker /// * `bytes`: buffer to completely fill with random bytes.
180*d289c2baSAndroid Build Coastguard Worker ///
181*d289c2baSAndroid Build Coastguard Worker /// # Returns
182*d289c2baSAndroid Build Coastguard Worker /// Unit on success, error on failure.
get_random(&mut self, bytes: &mut [u8]) -> IoResult<()>183*d289c2baSAndroid Build Coastguard Worker fn get_random(&mut self, bytes: &mut [u8]) -> IoResult<()>;
184*d289c2baSAndroid Build Coastguard Worker }
185*d289c2baSAndroid Build Coastguard Worker
186*d289c2baSAndroid Build Coastguard Worker /// Certificate-based vbmeta key validation.
187*d289c2baSAndroid Build Coastguard Worker ///
188*d289c2baSAndroid Build Coastguard Worker /// This can be called from `validate_vbmeta_public_key()` or `validate_public_key_for_partition()`
189*d289c2baSAndroid Build Coastguard Worker /// to provide the correct behavior using the libavb_cert keys, such as:
190*d289c2baSAndroid Build Coastguard Worker ///
191*d289c2baSAndroid Build Coastguard Worker /// ```
192*d289c2baSAndroid Build Coastguard Worker /// impl avb::Ops for MyOps {
193*d289c2baSAndroid Build Coastguard Worker /// fn validate_vbmeta_public_key(
194*d289c2baSAndroid Build Coastguard Worker /// &mut self,
195*d289c2baSAndroid Build Coastguard Worker /// public_key: &[u8],
196*d289c2baSAndroid Build Coastguard Worker /// public_key_metadata: Option<&[u8]>,
197*d289c2baSAndroid Build Coastguard Worker /// ) -> IoResult<bool> {
198*d289c2baSAndroid Build Coastguard Worker /// cert_validate_vbmeta_public_key(self, public_key, public_key_metadata)
199*d289c2baSAndroid Build Coastguard Worker /// }
200*d289c2baSAndroid Build Coastguard Worker /// }
201*d289c2baSAndroid Build Coastguard Worker /// ```
202*d289c2baSAndroid Build Coastguard Worker ///
203*d289c2baSAndroid Build Coastguard Worker /// We don't automatically call this from the validation functions because it's up to the device
204*d289c2baSAndroid Build Coastguard Worker /// when to use certificate authentication e.g. a device may want to use libavb_cert only for
205*d289c2baSAndroid Build Coastguard Worker /// specific partitions.
206*d289c2baSAndroid Build Coastguard Worker ///
207*d289c2baSAndroid Build Coastguard Worker /// # Arguments
208*d289c2baSAndroid Build Coastguard Worker /// * `ops`: the `Ops` callback implementations, which must provide a `cert_ops()` implementation.
209*d289c2baSAndroid Build Coastguard Worker /// * `public_key`: the public key.
210*d289c2baSAndroid Build Coastguard Worker /// * `public_key_metadata`: public key metadata.
211*d289c2baSAndroid Build Coastguard Worker ///
212*d289c2baSAndroid Build Coastguard Worker /// # Returns
213*d289c2baSAndroid Build Coastguard Worker /// * `Ok(true)` if the given key is valid according to the permanent attributes.
214*d289c2baSAndroid Build Coastguard Worker /// * `Ok(false)` if the given key is invalid.
215*d289c2baSAndroid Build Coastguard Worker /// * `Err(IoError::NotImplemented)` if `ops` does not provide the required `cert_ops()`.
216*d289c2baSAndroid Build Coastguard Worker /// * `Err(IoError)` on `ops` callback error.
cert_validate_vbmeta_public_key( ops: &mut dyn Ops, public_key: &[u8], public_key_metadata: Option<&[u8]>, ) -> IoResult<bool>217*d289c2baSAndroid Build Coastguard Worker pub fn cert_validate_vbmeta_public_key(
218*d289c2baSAndroid Build Coastguard Worker ops: &mut dyn Ops,
219*d289c2baSAndroid Build Coastguard Worker public_key: &[u8],
220*d289c2baSAndroid Build Coastguard Worker public_key_metadata: Option<&[u8]>,
221*d289c2baSAndroid Build Coastguard Worker ) -> IoResult<bool> {
222*d289c2baSAndroid Build Coastguard Worker // This API requires both AVB and cert ops.
223*d289c2baSAndroid Build Coastguard Worker if ops.cert_ops().is_none() {
224*d289c2baSAndroid Build Coastguard Worker return Err(IoError::NotImplemented);
225*d289c2baSAndroid Build Coastguard Worker }
226*d289c2baSAndroid Build Coastguard Worker
227*d289c2baSAndroid Build Coastguard Worker let ops_bridge = pin!(ops::OpsBridge::new(ops));
228*d289c2baSAndroid Build Coastguard Worker let public_key_metadata = public_key_metadata.unwrap_or(&[]);
229*d289c2baSAndroid Build Coastguard Worker let mut trusted = false;
230*d289c2baSAndroid Build Coastguard Worker io_enum_to_result(
231*d289c2baSAndroid Build Coastguard Worker // SAFETY:
232*d289c2baSAndroid Build Coastguard Worker // * `ops_bridge.init_and_get_c_ops()` gives us a valid `AvbOps` with cert.
233*d289c2baSAndroid Build Coastguard Worker // * `public_key` args are C-compatible pointer + size byte buffers.
234*d289c2baSAndroid Build Coastguard Worker // * `trusted` is a C-compatible bool.
235*d289c2baSAndroid Build Coastguard Worker // * this function does not retain references to any of these arguments.
236*d289c2baSAndroid Build Coastguard Worker unsafe {
237*d289c2baSAndroid Build Coastguard Worker avb_cert_validate_vbmeta_public_key(
238*d289c2baSAndroid Build Coastguard Worker ops_bridge.init_and_get_c_ops(),
239*d289c2baSAndroid Build Coastguard Worker public_key.as_ptr(),
240*d289c2baSAndroid Build Coastguard Worker public_key.len(),
241*d289c2baSAndroid Build Coastguard Worker public_key_metadata.as_ptr(),
242*d289c2baSAndroid Build Coastguard Worker public_key_metadata.len(),
243*d289c2baSAndroid Build Coastguard Worker &mut trusted,
244*d289c2baSAndroid Build Coastguard Worker )
245*d289c2baSAndroid Build Coastguard Worker },
246*d289c2baSAndroid Build Coastguard Worker )?;
247*d289c2baSAndroid Build Coastguard Worker Ok(trusted)
248*d289c2baSAndroid Build Coastguard Worker }
249*d289c2baSAndroid Build Coastguard Worker
250*d289c2baSAndroid Build Coastguard Worker /// Generates a challenge for authenticated unlock.
251*d289c2baSAndroid Build Coastguard Worker ///
252*d289c2baSAndroid Build Coastguard Worker /// Used to create a challenge token to be signed with the PUK.
253*d289c2baSAndroid Build Coastguard Worker ///
254*d289c2baSAndroid Build Coastguard Worker /// The user can sign the resulting token via `avbtool make_cert_unlock_credential`.
255*d289c2baSAndroid Build Coastguard Worker ///
256*d289c2baSAndroid Build Coastguard Worker /// # Arguments
257*d289c2baSAndroid Build Coastguard Worker /// * `cert_ops`: the `CertOps` callback implementations; base `Ops` are not required here.
258*d289c2baSAndroid Build Coastguard Worker ///
259*d289c2baSAndroid Build Coastguard Worker /// # Returns
260*d289c2baSAndroid Build Coastguard Worker /// The challenge to sign with the PUK, or `IoError` on `cert_ops` failure.
cert_generate_unlock_challenge(cert_ops: &mut dyn CertOps) -> IoResult<CertUnlockChallenge>261*d289c2baSAndroid Build Coastguard Worker pub fn cert_generate_unlock_challenge(cert_ops: &mut dyn CertOps) -> IoResult<CertUnlockChallenge> {
262*d289c2baSAndroid Build Coastguard Worker // `OpsBridge` requires a full `Ops` object, so we wrap `cert_ops` in a do-nothing `Ops`
263*d289c2baSAndroid Build Coastguard Worker // implementation. This is simpler than teaching `OpsBridge` to handle the cert-only case.
264*d289c2baSAndroid Build Coastguard Worker let mut ops = CertOnlyOps { cert_ops };
265*d289c2baSAndroid Build Coastguard Worker let ops_bridge = pin!(ops::OpsBridge::new(&mut ops));
266*d289c2baSAndroid Build Coastguard Worker let mut challenge = CertUnlockChallenge::default();
267*d289c2baSAndroid Build Coastguard Worker io_enum_to_result(
268*d289c2baSAndroid Build Coastguard Worker // SAFETY:
269*d289c2baSAndroid Build Coastguard Worker // * `ops_bridge.init_and_get_c_ops()` gives us a valid `AvbOps` with cert.
270*d289c2baSAndroid Build Coastguard Worker // * `challenge` is a valid C-compatible `CertUnlockChallenge`.
271*d289c2baSAndroid Build Coastguard Worker // * this function does not retain references to any of these arguments.
272*d289c2baSAndroid Build Coastguard Worker unsafe {
273*d289c2baSAndroid Build Coastguard Worker avb_cert_generate_unlock_challenge(
274*d289c2baSAndroid Build Coastguard Worker ops_bridge.init_and_get_c_ops().cert_ops,
275*d289c2baSAndroid Build Coastguard Worker &mut challenge,
276*d289c2baSAndroid Build Coastguard Worker )
277*d289c2baSAndroid Build Coastguard Worker },
278*d289c2baSAndroid Build Coastguard Worker )?;
279*d289c2baSAndroid Build Coastguard Worker Ok(challenge)
280*d289c2baSAndroid Build Coastguard Worker }
281*d289c2baSAndroid Build Coastguard Worker
282*d289c2baSAndroid Build Coastguard Worker /// Validates a signed credential for authenticated unlock.
283*d289c2baSAndroid Build Coastguard Worker ///
284*d289c2baSAndroid Build Coastguard Worker /// Used to check that an unlock credential was properly signed with the PUK according to the
285*d289c2baSAndroid Build Coastguard Worker /// device's permanent attributes.
286*d289c2baSAndroid Build Coastguard Worker ///
287*d289c2baSAndroid Build Coastguard Worker /// # Arguments
288*d289c2baSAndroid Build Coastguard Worker /// * `ops`: the `Ops` callback implementations, which must provide a `cert_ops()` implementation.
289*d289c2baSAndroid Build Coastguard Worker /// * `credential`: the signed unlock credential to verify.
290*d289c2baSAndroid Build Coastguard Worker ///
291*d289c2baSAndroid Build Coastguard Worker /// # Returns
292*d289c2baSAndroid Build Coastguard Worker /// * `Ok(true)` if the credential validated
293*d289c2baSAndroid Build Coastguard Worker /// * `Ok(false)` if it failed validation
294*d289c2baSAndroid Build Coastguard Worker /// * `Err(IoError::NotImplemented)` if `ops` does not provide the required `cert_ops()`.
295*d289c2baSAndroid Build Coastguard Worker /// * `Err(IoError)` on `ops` failure
cert_validate_unlock_credential( ops: &mut dyn Ops, credential: &CertUnlockCredential, ) -> IoResult<bool>296*d289c2baSAndroid Build Coastguard Worker pub fn cert_validate_unlock_credential(
297*d289c2baSAndroid Build Coastguard Worker // Note: in the libavb C API this function takes an `AvbCertOps` rather than `AvbOps`, but
298*d289c2baSAndroid Build Coastguard Worker // the implementation requires both, so we need an `Ops` here. This is also more consistent
299*d289c2baSAndroid Build Coastguard Worker // with `validate_vbmeta_public_key()` which similarly requires both but takes `AvbOps`.
300*d289c2baSAndroid Build Coastguard Worker ops: &mut dyn Ops,
301*d289c2baSAndroid Build Coastguard Worker credential: &CertUnlockCredential,
302*d289c2baSAndroid Build Coastguard Worker ) -> IoResult<bool> {
303*d289c2baSAndroid Build Coastguard Worker // This API requires both AVB and cert ops.
304*d289c2baSAndroid Build Coastguard Worker if ops.cert_ops().is_none() {
305*d289c2baSAndroid Build Coastguard Worker return Err(IoError::NotImplemented);
306*d289c2baSAndroid Build Coastguard Worker }
307*d289c2baSAndroid Build Coastguard Worker
308*d289c2baSAndroid Build Coastguard Worker let ops_bridge = pin!(ops::OpsBridge::new(ops));
309*d289c2baSAndroid Build Coastguard Worker let mut trusted = false;
310*d289c2baSAndroid Build Coastguard Worker io_enum_to_result(
311*d289c2baSAndroid Build Coastguard Worker // SAFETY:
312*d289c2baSAndroid Build Coastguard Worker // * `ops_bridge.init_and_get_c_ops()` gives us a valid `AvbOps` with cert.
313*d289c2baSAndroid Build Coastguard Worker // * `credential` is a valid C-compatible `CertUnlockCredential`.
314*d289c2baSAndroid Build Coastguard Worker // * `trusted` is a C-compatible bool.
315*d289c2baSAndroid Build Coastguard Worker // * this function does not retain references to any of these arguments.
316*d289c2baSAndroid Build Coastguard Worker unsafe {
317*d289c2baSAndroid Build Coastguard Worker avb_cert_validate_unlock_credential(
318*d289c2baSAndroid Build Coastguard Worker ops_bridge.init_and_get_c_ops().cert_ops,
319*d289c2baSAndroid Build Coastguard Worker credential,
320*d289c2baSAndroid Build Coastguard Worker &mut trusted,
321*d289c2baSAndroid Build Coastguard Worker )
322*d289c2baSAndroid Build Coastguard Worker },
323*d289c2baSAndroid Build Coastguard Worker )?;
324*d289c2baSAndroid Build Coastguard Worker Ok(trusted)
325*d289c2baSAndroid Build Coastguard Worker }
326*d289c2baSAndroid Build Coastguard Worker
327*d289c2baSAndroid Build Coastguard Worker /// An `Ops` implementation that only provides the `cert_ops()` callback.
328*d289c2baSAndroid Build Coastguard Worker struct CertOnlyOps<'a> {
329*d289c2baSAndroid Build Coastguard Worker cert_ops: &'a mut dyn CertOps,
330*d289c2baSAndroid Build Coastguard Worker }
331*d289c2baSAndroid Build Coastguard Worker
332*d289c2baSAndroid Build Coastguard Worker impl<'a> Ops<'static> for CertOnlyOps<'a> {
read_from_partition( &mut self, _partition: &CStr, _offset: i64, _buffer: &mut [u8], ) -> IoResult<usize>333*d289c2baSAndroid Build Coastguard Worker fn read_from_partition(
334*d289c2baSAndroid Build Coastguard Worker &mut self,
335*d289c2baSAndroid Build Coastguard Worker _partition: &CStr,
336*d289c2baSAndroid Build Coastguard Worker _offset: i64,
337*d289c2baSAndroid Build Coastguard Worker _buffer: &mut [u8],
338*d289c2baSAndroid Build Coastguard Worker ) -> IoResult<usize> {
339*d289c2baSAndroid Build Coastguard Worker Err(IoError::NotImplemented)
340*d289c2baSAndroid Build Coastguard Worker }
341*d289c2baSAndroid Build Coastguard Worker
validate_vbmeta_public_key( &mut self, _public_key: &[u8], _public_key_metadata: Option<&[u8]>, ) -> IoResult<bool>342*d289c2baSAndroid Build Coastguard Worker fn validate_vbmeta_public_key(
343*d289c2baSAndroid Build Coastguard Worker &mut self,
344*d289c2baSAndroid Build Coastguard Worker _public_key: &[u8],
345*d289c2baSAndroid Build Coastguard Worker _public_key_metadata: Option<&[u8]>,
346*d289c2baSAndroid Build Coastguard Worker ) -> IoResult<bool> {
347*d289c2baSAndroid Build Coastguard Worker Err(IoError::NotImplemented)
348*d289c2baSAndroid Build Coastguard Worker }
349*d289c2baSAndroid Build Coastguard Worker
read_rollback_index(&mut self, _rollback_index_location: usize) -> IoResult<u64>350*d289c2baSAndroid Build Coastguard Worker fn read_rollback_index(&mut self, _rollback_index_location: usize) -> IoResult<u64> {
351*d289c2baSAndroid Build Coastguard Worker Err(IoError::NotImplemented)
352*d289c2baSAndroid Build Coastguard Worker }
353*d289c2baSAndroid Build Coastguard Worker
write_rollback_index( &mut self, _rollback_index_location: usize, _index: u64, ) -> IoResult<()>354*d289c2baSAndroid Build Coastguard Worker fn write_rollback_index(
355*d289c2baSAndroid Build Coastguard Worker &mut self,
356*d289c2baSAndroid Build Coastguard Worker _rollback_index_location: usize,
357*d289c2baSAndroid Build Coastguard Worker _index: u64,
358*d289c2baSAndroid Build Coastguard Worker ) -> IoResult<()> {
359*d289c2baSAndroid Build Coastguard Worker Err(IoError::NotImplemented)
360*d289c2baSAndroid Build Coastguard Worker }
361*d289c2baSAndroid Build Coastguard Worker
read_is_device_unlocked(&mut self) -> IoResult<bool>362*d289c2baSAndroid Build Coastguard Worker fn read_is_device_unlocked(&mut self) -> IoResult<bool> {
363*d289c2baSAndroid Build Coastguard Worker Err(IoError::NotImplemented)
364*d289c2baSAndroid Build Coastguard Worker }
365*d289c2baSAndroid Build Coastguard Worker
366*d289c2baSAndroid Build Coastguard Worker #[cfg(feature = "uuid")]
get_unique_guid_for_partition(&mut self, _partition: &CStr) -> IoResult<Uuid>367*d289c2baSAndroid Build Coastguard Worker fn get_unique_guid_for_partition(&mut self, _partition: &CStr) -> IoResult<Uuid> {
368*d289c2baSAndroid Build Coastguard Worker Err(IoError::NotImplemented)
369*d289c2baSAndroid Build Coastguard Worker }
370*d289c2baSAndroid Build Coastguard Worker
get_size_of_partition(&mut self, _partition: &CStr) -> IoResult<u64>371*d289c2baSAndroid Build Coastguard Worker fn get_size_of_partition(&mut self, _partition: &CStr) -> IoResult<u64> {
372*d289c2baSAndroid Build Coastguard Worker Err(IoError::NotImplemented)
373*d289c2baSAndroid Build Coastguard Worker }
374*d289c2baSAndroid Build Coastguard Worker
read_persistent_value(&mut self, _name: &CStr, _value: &mut [u8]) -> IoResult<usize>375*d289c2baSAndroid Build Coastguard Worker fn read_persistent_value(&mut self, _name: &CStr, _value: &mut [u8]) -> IoResult<usize> {
376*d289c2baSAndroid Build Coastguard Worker Err(IoError::NotImplemented)
377*d289c2baSAndroid Build Coastguard Worker }
378*d289c2baSAndroid Build Coastguard Worker
write_persistent_value(&mut self, _name: &CStr, _value: &[u8]) -> IoResult<()>379*d289c2baSAndroid Build Coastguard Worker fn write_persistent_value(&mut self, _name: &CStr, _value: &[u8]) -> IoResult<()> {
380*d289c2baSAndroid Build Coastguard Worker Err(IoError::NotImplemented)
381*d289c2baSAndroid Build Coastguard Worker }
382*d289c2baSAndroid Build Coastguard Worker
erase_persistent_value(&mut self, _name: &CStr) -> IoResult<()>383*d289c2baSAndroid Build Coastguard Worker fn erase_persistent_value(&mut self, _name: &CStr) -> IoResult<()> {
384*d289c2baSAndroid Build Coastguard Worker Err(IoError::NotImplemented)
385*d289c2baSAndroid Build Coastguard Worker }
386*d289c2baSAndroid Build Coastguard Worker
validate_public_key_for_partition( &mut self, _partition: &CStr, _public_key: &[u8], _public_key_metadata: Option<&[u8]>, ) -> IoResult<PublicKeyForPartitionInfo>387*d289c2baSAndroid Build Coastguard Worker fn validate_public_key_for_partition(
388*d289c2baSAndroid Build Coastguard Worker &mut self,
389*d289c2baSAndroid Build Coastguard Worker _partition: &CStr,
390*d289c2baSAndroid Build Coastguard Worker _public_key: &[u8],
391*d289c2baSAndroid Build Coastguard Worker _public_key_metadata: Option<&[u8]>,
392*d289c2baSAndroid Build Coastguard Worker ) -> IoResult<PublicKeyForPartitionInfo> {
393*d289c2baSAndroid Build Coastguard Worker Err(IoError::NotImplemented)
394*d289c2baSAndroid Build Coastguard Worker }
395*d289c2baSAndroid Build Coastguard Worker
cert_ops(&mut self) -> Option<&mut dyn CertOps>396*d289c2baSAndroid Build Coastguard Worker fn cert_ops(&mut self) -> Option<&mut dyn CertOps> {
397*d289c2baSAndroid Build Coastguard Worker Some(self.cert_ops)
398*d289c2baSAndroid Build Coastguard Worker }
399*d289c2baSAndroid Build Coastguard Worker }
400