Implement ATTEST_KEY support.

Test: atest CtsKeyStoreTestCases:AttestKeyTest
Change-Id: Ib2a8b0cb21b418b9d36df58836290c2e3e94cfa7
diff --git a/keystore2/src/crypto/Android.bp b/keystore2/src/crypto/Android.bp
index 7673400..e386735 100644
--- a/keystore2/src/crypto/Android.bp
+++ b/keystore2/src/crypto/Android.bp
@@ -74,6 +74,7 @@
         "--whitelist-function", "ECPOINTOct2Point",
         "--whitelist-function", "EC_KEY_free",
         "--whitelist-function", "EC_POINT_free",
+        "--whitelist-function", "extractSubjectFromCertificate",
         "--whitelist-type", "EC_KEY",
         "--whitelist-type", "EC_POINT",
         "--whitelist-var", "EC_MAX_BYTES",
diff --git a/keystore2/src/crypto/crypto.cpp b/keystore2/src/crypto/crypto.cpp
index 3cc19c5..2e613fd 100644
--- a/keystore2/src/crypto/crypto.cpp
+++ b/keystore2/src/crypto/crypto.cpp
@@ -26,6 +26,7 @@
 #include <openssl/evp.h>
 #include <openssl/hkdf.h>
 #include <openssl/rand.h>
+#include <openssl/x509.h>
 
 #include <vector>
 
@@ -261,3 +262,42 @@
     }
     return point;
 }
+
+int extractSubjectFromCertificate(const uint8_t* cert_buf, size_t cert_len, uint8_t* subject_buf,
+                                  size_t subject_buf_len) {
+    if (!cert_buf || !subject_buf) {
+        ALOGE("extractSubjectFromCertificate: received null pointer");
+        return 0;
+    }
+
+    const uint8_t* p = cert_buf;
+    bssl::UniquePtr<X509> cert(d2i_X509(nullptr /* Allocate X509 struct */, &p, cert_len));
+    if (!cert) {
+        ALOGE("extractSubjectFromCertificate: failed to parse certificate");
+        return 0;
+    }
+
+    X509_NAME* subject = X509_get_subject_name(cert.get());
+    if (!subject) {
+        ALOGE("extractSubjectFromCertificate: failed to retrieve subject name");
+        return 0;
+    }
+
+    int subject_len = i2d_X509_NAME(subject, nullptr /* Don't copy the data */);
+    if (subject_len < 0) {
+        ALOGE("extractSubjectFromCertificate: error obtaining encoded subject name length");
+        return 0;
+    }
+
+    if (subject_len > subject_buf_len) {
+        // Return the subject length, negated, so the caller knows how much
+        // buffer space is required.
+        ALOGI("extractSubjectFromCertificate: needed %d bytes for subject, caller provided %zu",
+              subject_len, subject_buf_len);
+        return -subject_len;
+    }
+
+    // subject_buf has enough space.
+    uint8_t* tmp = subject_buf;
+    return i2d_X509_NAME(subject, &tmp);
+}
diff --git a/keystore2/src/crypto/crypto.hpp b/keystore2/src/crypto/crypto.hpp
index 9bd7758..1b8971f 100644
--- a/keystore2/src/crypto/crypto.hpp
+++ b/keystore2/src/crypto/crypto.hpp
@@ -60,6 +60,29 @@
   size_t ECPOINTPoint2Oct(const EC_POINT *point, uint8_t *buf, size_t len);
 
   EC_POINT* ECPOINTOct2Point(const uint8_t *buf, size_t len);
+
 }
 
+// Parse a DER-encoded X.509 certificate contained in cert_buf, with length
+// cert_len, extract the subject, DER-encode it and write the result to
+// subject_buf, which has subject_buf_len capacity.
+//
+// Because the length of the issuer is unknown, and becaue we'd like to (a) be
+// able to handle subjects of any size and (b) avoid parsing the certificate
+// twice most of the time, once to discover the length and once to parse it, the
+// return value is overloaded.
+//
+// If the return value > 0 it specifies the number of bytes written into
+// subject_buf; the operation was successful.
+//
+// If the return value == 0, certificate parsing failed unrecoverably.  The
+// reason will be logged.
+//
+// If the return value < 0, the operation failed because the subject size >
+// subject_buf_len.  The return value is -(subject_size), where subject_size is
+// the size of the extracted DER-encoded subject field.  Call
+// extractSubjectFromCertificate again with a sufficiently-large buffer.
+int extractSubjectFromCertificate(const uint8_t* cert_buf, size_t cert_len,
+                                  uint8_t* subject_buf, size_t subject_buf_len);
+
 #endif  //  __CRYPTO_H__
diff --git a/keystore2/src/crypto/error.rs b/keystore2/src/crypto/error.rs
index 1e84fc6..1eec321 100644
--- a/keystore2/src/crypto/error.rs
+++ b/keystore2/src/crypto/error.rs
@@ -85,4 +85,8 @@
     /// This is returned if the C implementation of ECPOINTOct2Point returned null.
     #[error("Failed to convert oct to point.")]
     ECOct2PointFailed,
+
+    /// This is returned if the C implementation of extractSubjectFromCertificate failed.
+    #[error("Failed to extract certificate subject.")]
+    ExtractSubjectFailed,
 }
diff --git a/keystore2/src/crypto/lib.rs b/keystore2/src/crypto/lib.rs
index 92b257c..f23778c 100644
--- a/keystore2/src/crypto/lib.rs
+++ b/keystore2/src/crypto/lib.rs
@@ -19,11 +19,12 @@
 mod zvec;
 pub use error::Error;
 use keystore2_crypto_bindgen::{
-    generateKeyFromPassword, randomBytes, AES_gcm_decrypt, AES_gcm_encrypt, ECDHComputeKey,
-    ECKEYDeriveFromSecret, ECKEYGenerateKey, ECPOINTOct2Point, ECPOINTPoint2Oct, EC_KEY_free,
-    EC_KEY_get0_public_key, EC_POINT_free, HKDFExpand, HKDFExtract, EC_KEY, EC_MAX_BYTES, EC_POINT,
-    EVP_MAX_MD_SIZE,
+    extractSubjectFromCertificate, generateKeyFromPassword, randomBytes, AES_gcm_decrypt,
+    AES_gcm_encrypt, ECDHComputeKey, ECKEYDeriveFromSecret, ECKEYGenerateKey, ECPOINTOct2Point,
+    ECPOINTPoint2Oct, EC_KEY_free, EC_KEY_get0_public_key, EC_POINT_free, HKDFExpand, HKDFExtract,
+    EC_KEY, EC_MAX_BYTES, EC_POINT, EVP_MAX_MD_SIZE,
 };
+use std::convert::TryFrom;
 use std::convert::TryInto;
 use std::marker::PhantomData;
 pub use zvec::ZVec;
@@ -353,6 +354,59 @@
     Ok(OwnedECPoint(result))
 }
 
+/// Uses BoringSSL to extract the DER-encoded issuer subject from a
+/// DER-encoded X.509 certificate.
+pub fn parse_issuer_subject_from_certificate(cert_buf: &[u8]) -> Result<Vec<u8>, Error> {
+    // Try with a 200-byte output buffer, should be enough in all but bizarre cases.
+    let mut retval = vec![0; 200];
+    let mut size = unsafe {
+        extractSubjectFromCertificate(
+            cert_buf.as_ptr(),
+            cert_buf.len(),
+            retval.as_mut_ptr(),
+            retval.len(),
+        )
+    };
+
+    if size == 0 {
+        return Err(Error::ExtractSubjectFailed);
+    }
+
+    if size < 0 {
+        // Our buffer wasn't big enough.  Make one that is just the right size and try again.
+        let negated_size = usize::try_from(-size);
+        retval = match negated_size.ok() {
+            None => return Err(Error::ExtractSubjectFailed),
+            Some(size) => vec![0; size],
+        };
+
+        size = unsafe {
+            extractSubjectFromCertificate(
+                cert_buf.as_ptr(),
+                cert_buf.len(),
+                retval.as_mut_ptr(),
+                retval.len(),
+            )
+        };
+
+        if size <= 0 {
+            return Err(Error::ExtractSubjectFailed);
+        }
+    }
+
+    // Reduce buffer size to the amount written.
+    let safe_size = usize::try_from(size);
+    retval.resize(
+        match safe_size.ok() {
+            None => return Err(Error::ExtractSubjectFailed),
+            Some(size) => size,
+        },
+        0,
+    );
+
+    Ok(retval)
+}
+
 #[cfg(test)]
 mod tests {
 
diff --git a/keystore2/src/security_level.rs b/keystore2/src/security_level.rs
index b96aea8..37e43c6 100644
--- a/keystore2/src/security_level.rs
+++ b/keystore2/src/security_level.rs
@@ -18,8 +18,9 @@
 
 use crate::globals::get_keymint_device;
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
-    Algorithm::Algorithm, HardwareAuthenticatorType::HardwareAuthenticatorType,
-    IKeyMintDevice::IKeyMintDevice, KeyCreationResult::KeyCreationResult, KeyFormat::KeyFormat,
+    Algorithm::Algorithm, AttestationKey::AttestationKey,
+    HardwareAuthenticatorType::HardwareAuthenticatorType, IKeyMintDevice::IKeyMintDevice,
+    KeyCreationResult::KeyCreationResult, KeyFormat::KeyFormat,
     KeyMintHardwareInfo::KeyMintHardwareInfo, KeyParameter::KeyParameter,
     KeyParameterValue::KeyParameterValue, SecurityLevel::SecurityLevel, Tag::Tag,
 };
@@ -54,6 +55,7 @@
 };
 use anyhow::{anyhow, Context, Result};
 use binder::{IBinder, Strong, ThreadState};
+use keystore2_crypto::parse_issuer_subject_from_certificate;
 
 /// Implementation of the IKeystoreSecurityLevel Interface.
 pub struct KeystoreSecurityLevel {
@@ -359,7 +361,7 @@
     fn generate_key(
         &self,
         key: &KeyDescriptor,
-        attestation_key: Option<&KeyDescriptor>,
+        attest_key_descriptor: Option<&KeyDescriptor>,
         params: &[KeyParameter],
         flags: i32,
         entropy: &[u8],
@@ -383,19 +385,78 @@
         // generate_key requires the rebind permission.
         check_key_permission(KeyPerm::rebind(), &key, &None).context("In generate_key.")?;
 
+        let attest_key = match attest_key_descriptor {
+            None => None,
+            Some(key) => Some(
+                self.get_attest_key(key, caller_uid)
+                    .context("In generate_key: Trying to load attest key")?,
+            ),
+        };
+
         let params = Self::add_certificate_parameters(caller_uid, params, &key)
             .context("In generate_key: Trying to get aaid.")?;
 
         let km_dev: Strong<dyn IKeyMintDevice> = self.keymint.get_interface()?;
         map_km_error(km_dev.addRngEntropy(entropy))
             .context("In generate_key: Trying to add entropy.")?;
-        let creation_result = map_km_error(km_dev.generateKey(&params, None /* attestKey */))
+        let creation_result = map_km_error(km_dev.generateKey(&params, attest_key.as_ref()))
             .context("In generate_key: While generating Key")?;
 
         let user_id = uid_to_android_user(caller_uid);
         self.store_new_key(key, creation_result, user_id).context("In generate_key.")
     }
 
+    fn get_attest_key(&self, key: &KeyDescriptor, caller_uid: u32) -> Result<AttestationKey> {
+        let (km_blob, cert) = self
+            .load_attest_key_blob_and_cert(&key, caller_uid)
+            .context("In get_attest_key: Failed to load blob and cert")?;
+
+        let issuer_subject: Vec<u8> = parse_issuer_subject_from_certificate(&cert)
+            .context("In get_attest_key: Failed to parse subject from certificate.")?;
+
+        Ok(AttestationKey {
+            keyBlob: km_blob.to_vec(),
+            attestKeyParams: [].to_vec(),
+            issuerSubjectName: issuer_subject,
+        })
+    }
+
+    fn load_attest_key_blob_and_cert(
+        &self,
+        key: &KeyDescriptor,
+        caller_uid: u32,
+    ) -> Result<(Vec<u8>, Vec<u8>)> {
+        match key.domain {
+            Domain::BLOB => Err(error::Error::Km(ErrorCode::INVALID_ARGUMENT)).context(
+                "In load_attest_key_blob_and_cert: Domain::BLOB attestation keys not supported",
+            ),
+            _ => {
+                let (key_id_guard, mut key_entry) = DB
+                    .with::<_, Result<(KeyIdGuard, KeyEntry)>>(|db| {
+                        db.borrow_mut().load_key_entry(
+                            &key,
+                            KeyType::Client,
+                            KeyEntryLoadBits::BOTH,
+                            caller_uid,
+                            |k, av| check_key_permission(KeyPerm::use_(), k, &av),
+                        )
+                    })
+                    .context("In load_attest_key_blob_and_cert: Failed to load key.")?;
+
+                let (blob, _) =
+                    key_entry.take_key_blob_info().ok_or_else(Error::sys).context(concat!(
+                        "In load_attest_key_blob_and_cert: Successfully loaded key entry,",
+                        " but KM blob was missing."
+                    ))?;
+                let cert = key_entry.take_cert().ok_or_else(Error::sys).context(concat!(
+                    "In load_attest_key_blob_and_cert: Successfully loaded key entry,",
+                    " but cert was missing."
+                ))?;
+                Ok((blob, cert))
+            }
+        }
+    }
+
     fn import_key(
         &self,
         key: &KeyDescriptor,