summaryrefslogtreecommitdiff
path: root/keystore2/src/remote_provisioning.rs
blob: 14c61fb02253ffb8ab923e0328d7264880979cc5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Copyright 2020, The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! This is the implementation for the remote provisioning AIDL interface between
//! the network providers for remote provisioning and the system. This interface
//! allows the caller to prompt the Remote Provisioning HAL to generate keys and
//! CBOR blobs that can be ferried to a provisioning server that will return
//! certificate chains signed by some root authority and stored in a keystore SQLite
//! DB.

use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
    Algorithm::Algorithm, AttestationKey::AttestationKey, Certificate::Certificate,
    KeyParameter::KeyParameter, KeyParameterValue::KeyParameterValue, SecurityLevel::SecurityLevel,
    Tag::Tag,
};
use android_system_keystore2::aidl::android::system::keystore2::{
    Domain::Domain, KeyDescriptor::KeyDescriptor,
};
use anyhow::{Context, Result};
use keystore2_crypto::parse_subject_from_certificate;

use crate::database::Uuid;
use crate::error::wrapped_rkpd_error_to_ks_error;
use crate::globals::get_remotely_provisioned_component_name;
use crate::ks_err;
use crate::metrics_store::log_rkp_error_stats;
use crate::rkpd_client::get_rkpd_attestation_key;
use crate::watchdog_helper::watchdog as wd;
use android_security_metrics::aidl::android::security::metrics::RkpError::RkpError as MetricsRkpError;

/// Contains helper functions to check if remote provisioning is enabled on the system and, if so,
/// to assign and retrieve attestation keys and certificate chains.
#[derive(Default)]
pub struct RemProvState {
    security_level: SecurityLevel,
    km_uuid: Uuid,
}

impl RemProvState {
    /// Creates a RemProvState struct.
    pub fn new(security_level: SecurityLevel, km_uuid: Uuid) -> Self {
        Self { security_level, km_uuid }
    }

    /// Returns the uuid for the KM instance attached to this RemProvState struct.
    pub fn get_uuid(&self) -> Uuid {
        self.km_uuid
    }

    fn is_rkp_only(&self) -> bool {
        let default_value = false;

        let property_name = match self.security_level {
            SecurityLevel::STRONGBOX => "remote_provisioning.strongbox.rkp_only",
            SecurityLevel::TRUSTED_ENVIRONMENT => "remote_provisioning.tee.rkp_only",
            _ => return default_value,
        };

        rustutils::system_properties::read_bool(property_name, default_value)
            .unwrap_or(default_value)
    }

    fn is_asymmetric_key(&self, params: &[KeyParameter]) -> bool {
        params.iter().any(|kp| {
            matches!(
                kp,
                KeyParameter {
                    tag: Tag::ALGORITHM,
                    value: KeyParameterValue::Algorithm(Algorithm::RSA)
                } | KeyParameter {
                    tag: Tag::ALGORITHM,
                    value: KeyParameterValue::Algorithm(Algorithm::EC)
                }
            )
        })
    }

    /// Fetches attestation key and corresponding certificates from RKPD.
    pub fn get_rkpd_attestation_key_and_certs(
        &self,
        key: &KeyDescriptor,
        caller_uid: u32,
        params: &[KeyParameter],
    ) -> Result<Option<(AttestationKey, Certificate)>> {
        if !self.is_asymmetric_key(params) || key.domain != Domain::APP {
            Ok(None)
        } else {
            let rpc_name = get_remotely_provisioned_component_name(&self.security_level)
                .context(ks_err!("Trying to get IRPC name."))?;
            let _wd = wd::watch_millis("Calling get_rkpd_attestation_key()", 500);
            match get_rkpd_attestation_key(&rpc_name, caller_uid) {
                Err(e) => {
                    if self.is_rkp_only() {
                        log::error!("Error occurred: {:?}", e);
                        return Err(wrapped_rkpd_error_to_ks_error(&e)).context(format!("{e:?}"));
                    }
                    log::warn!("Error occurred: {:?}", e);
                    log_rkp_error_stats(
                        MetricsRkpError::FALL_BACK_DURING_HYBRID,
                        &self.security_level,
                    );
                    Ok(None)
                }
                Ok(rkpd_key) => Ok(Some((
                    AttestationKey {
                        keyBlob: rkpd_key.keyBlob,
                        attestKeyParams: vec![],
                        // Batch certificate is at the beginning of the certificate chain.
                        issuerSubjectName: parse_subject_from_certificate(
                            &rkpd_key.encodedCertChain,
                        )
                        .context(ks_err!("Failed to parse subject."))?,
                    },
                    Certificate { encodedCertificate: rkpd_key.encodedCertChain },
                ))),
            }
        }
    }
}