On-device signing: Support keystore2 for keys.
Add code to support Keystore2. Keystore2 will offer a feature similar to
EARLY_BOOT_KEYS in Keymaster 4.1, but it will also be hardware-enforced
in older Keymaster versions. For now, have the code support both paths,
and stick with Keymaster 4.1 until Keystore2 is merged.
Bug: 165630556
Test: Local
Change-Id: If62837bf6fb1398bd30ce9422cbf3082a5cbf1e2
diff --git a/ondevice-signing/Android.bp b/ondevice-signing/Android.bp
index 4cf0bd7..1c3706d 100644
--- a/ondevice-signing/Android.bp
+++ b/ondevice-signing/Android.bp
@@ -86,6 +86,7 @@
"CertUtils.cpp",
"Keymaster.cpp",
"KeymasterSigningKey.cpp",
+ "KeystoreKey.cpp",
"VerityUtils.cpp",
],
@@ -97,7 +98,10 @@
shared_libs: [
"android.hardware.keymaster@4.1",
+ "android.system.keystore2-V1-cpp",
+ "android.hardware.security.keymint-V1-cpp",
"libbase",
+ "libbinder",
"libcrypto",
"libcrypto_utils",
"libfsverity",
diff --git a/ondevice-signing/CertUtils.cpp b/ondevice-signing/CertUtils.cpp
index 6b24391..e74fe9d 100644
--- a/ondevice-signing/CertUtils.cpp
+++ b/ondevice-signing/CertUtils.cpp
@@ -25,6 +25,9 @@
#include <fcntl.h>
#include <vector>
+
+#include "KeyConstants.h"
+
const char kBasicConstraints[] = "CA:TRUE";
const char kKeyUsage[] = "critical,keyCertSign,cRLSign,digitalSignature";
const char kSubjectKeyIdentifier[] = "hash";
@@ -66,8 +69,18 @@
X509_gmtime_adj(X509_get_notBefore(x509.get()), 0);
X509_gmtime_adj(X509_get_notAfter(x509.get()), kCertLifetimeSeconds);
- auto pubKeyData = publicKey.data();
- EVP_PKEY* public_key = d2i_PUBKEY(nullptr, &pubKeyData, publicKey.size());
+ // "publicKey" corresponds to the raw public key bytes - need to create
+ // a new RSA key with the correct exponent.
+ RSA* rsaPubkey = RSA_new();
+ rsaPubkey->n = BN_new();
+ rsaPubkey->e = BN_new();
+
+ BN_bin2bn(publicKey.data(), publicKey.size(), rsaPubkey->n);
+ BN_set_word(rsaPubkey->e, kRsaKeyExponent);
+
+ EVP_PKEY* public_key = EVP_PKEY_new();
+ EVP_PKEY_assign_RSA(public_key, rsaPubkey);
+
if (!X509_set_pubkey(x509.get(), public_key)) {
return Error() << "Unable to set x509 public key";
}
@@ -117,6 +130,7 @@
i2d_X509_fp(f, x509.get());
fclose(f);
+ EVP_PKEY_free(public_key);
return {};
}
@@ -142,13 +156,25 @@
return pubKey;
}
-Result<std::vector<uint8_t>> extractPublicKeyFromX509(const std::vector<uint8_t>& keyData) {
+Result<std::vector<uint8_t>>
+extractPublicKeyFromSubjectPublicKeyInfo(const std::vector<uint8_t>& keyData) {
auto keyDataBytes = keyData.data();
EVP_PKEY* public_key = d2i_PUBKEY(nullptr, &keyDataBytes, keyData.size());
return extractPublicKey(public_key);
}
+Result<std::vector<uint8_t>> extractPublicKeyFromX509(const std::vector<uint8_t>& keyData) {
+ auto keyDataBytes = keyData.data();
+ bssl::UniquePtr<X509> decoded_cert(d2i_X509(nullptr, &keyDataBytes, keyData.size()));
+ if (decoded_cert.get() == nullptr) {
+ return Error() << "Failed to decode X509 certificate.";
+ }
+ bssl::UniquePtr<EVP_PKEY> decoded_pkey(X509_get_pubkey(decoded_cert.get()));
+
+ return extractPublicKey(decoded_pkey.get());
+}
+
Result<std::vector<uint8_t>> extractPublicKeyFromX509(const std::string& path) {
X509* cert;
auto f = fopen(path.c_str(), "r");
diff --git a/ondevice-signing/CertUtils.h b/ondevice-signing/CertUtils.h
index d9172d0..ca06f33 100644
--- a/ondevice-signing/CertUtils.h
+++ b/ondevice-signing/CertUtils.h
@@ -25,5 +25,7 @@
android::base::Result<std::vector<uint8_t>> createPkcs7(const std::vector<uint8_t>& signedData);
android::base::Result<std::vector<uint8_t>>
-extractPublicKeyFromX509(const std::vector<uint8_t>& path);
+extractPublicKeyFromX509(const std::vector<uint8_t>& x509);
+android::base::Result<std::vector<uint8_t>>
+extractPublicKeyFromSubjectPublicKeyInfo(const std::vector<uint8_t>& subjectKeyInfo);
android::base::Result<std::vector<uint8_t>> extractPublicKeyFromX509(const std::string& path);
diff --git a/ondevice-signing/KeyConstants.h b/ondevice-signing/KeyConstants.h
new file mode 100644
index 0000000..9e1a513
--- /dev/null
+++ b/ondevice-signing/KeyConstants.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 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.
+ */
+
+static constexpr int kRsaKeySize = 2048;
+static constexpr int kRsaKeyExponent = 65537;
diff --git a/ondevice-signing/KeymasterSigningKey.cpp b/ondevice-signing/KeymasterSigningKey.cpp
index 2b748e4..dc3ef8a 100644
--- a/ondevice-signing/KeymasterSigningKey.cpp
+++ b/ondevice-signing/KeymasterSigningKey.cpp
@@ -33,30 +33,36 @@
using android::base::Result;
using android::base::unique_fd;
+const std::string kSigningKeyBlob = "/data/misc/odsign/key.blob";
+
KeymasterSigningKey::KeymasterSigningKey() {}
-Result<KeymasterSigningKey> KeymasterSigningKey::loadFromBlobAndVerify(const std::string& path) {
- KeymasterSigningKey signingKey;
+Result<std::unique_ptr<KeymasterSigningKey>>
+KeymasterSigningKey::loadFromBlobAndVerify(const std::string& path) {
+ auto signingKey = std::make_unique<KeymasterSigningKey>();
- auto status = signingKey.initializeFromKeyblob(path);
+ auto status = signingKey->initializeFromKeyblob(path);
if (!status.ok()) {
return status.error();
}
- return std::move(signingKey);
+ return signingKey;
}
-Result<KeymasterSigningKey> KeymasterSigningKey::createNewKey() {
- KeymasterSigningKey signingKey;
+Result<void> KeymasterSigningKey::saveKeyblob(const std::string& path) const {
+ int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC;
- auto status = signingKey.createSigningKey();
-
- if (!status.ok()) {
- return status.error();
+ unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), flags, 0600)));
+ if (fd == -1) {
+ return ErrnoError() << "Error creating key blob file " << path;
}
- return std::move(signingKey);
+ if (!android::base::WriteFully(fd, mVerifiedKeyBlob.data(), mVerifiedKeyBlob.size())) {
+ return ErrnoError() << "Error writing key blob file " << path;
+ } else {
+ return {};
+ }
}
Result<void> KeymasterSigningKey::createSigningKey() {
@@ -78,41 +84,45 @@
return {};
}
-Result<void> KeymasterSigningKey::saveKeyblob(const std::string& path) const {
- int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC;
+Result<std::unique_ptr<KeymasterSigningKey>> KeymasterSigningKey::createAndPersistNewKey() {
+ auto signingKey = std::make_unique<KeymasterSigningKey>();
- unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), flags, 0600)));
- if (fd == -1) {
- return ErrnoError() << "Error creating key blob file " << path;
+ auto status = signingKey->createSigningKey();
+
+ if (!status.ok()) {
+ return status.error();
}
- if (!android::base::WriteFully(fd, mVerifiedKeyBlob.data(), mVerifiedKeyBlob.size())) {
- return ErrnoError() << "Error writing key blob file " << path;
- } else {
- return {};
+ status = signingKey->saveKeyblob(kSigningKeyBlob);
+ if (!status.ok()) {
+ return status.error();
}
+
+ return signingKey;
+}
+
+Result<SigningKey*> KeymasterSigningKey::getInstance() {
+ auto key = loadFromBlobAndVerify(kSigningKeyBlob);
+
+ if (!key.ok()) {
+ key = createAndPersistNewKey();
+ if (!key.ok()) {
+ return key.error();
+ }
+ }
+
+ return key->release();
}
Result<std::vector<uint8_t>> KeymasterSigningKey::getPublicKey() const {
- auto publicKeyX509 = mKeymaster->extractPublicKey(mVerifiedKeyBlob);
- if (!publicKeyX509.ok()) {
- return publicKeyX509.error();
- }
- return extractPublicKeyFromX509(publicKeyX509.value());
-}
-
-Result<void> KeymasterSigningKey::createX509Cert(const std::string& outPath) const {
auto publicKey = mKeymaster->extractPublicKey(mVerifiedKeyBlob);
-
if (!publicKey.ok()) {
return publicKey.error();
}
- auto keymasterSignFunction = [&](const std::string& to_be_signed) {
- return this->sign(to_be_signed);
- };
- createSelfSignedCertificate(*publicKey, keymasterSignFunction, outPath);
- return {};
+ // Keymaster returns the public key not in a full X509 cert, but just the
+ // "SubjectPublicKeyInfo"
+ return extractPublicKeyFromSubjectPublicKeyInfo(publicKey.value());
}
Result<void> KeymasterSigningKey::initializeFromKeyblob(const std::string& path) {
diff --git a/ondevice-signing/KeymasterSigningKey.h b/ondevice-signing/KeymasterSigningKey.h
index 7631059..e66781f 100644
--- a/ondevice-signing/KeymasterSigningKey.h
+++ b/ondevice-signing/KeymasterSigningKey.h
@@ -23,30 +23,36 @@
#include <utils/StrongPointer.h>
#include "Keymaster.h"
+#include "SigningKey.h"
-class KeymasterSigningKey {
+class KeymasterSigningKey : public SigningKey {
using KmDevice = ::android::hardware::keymaster::V4_1::IKeymasterDevice;
public:
+ friend std::unique_ptr<KeymasterSigningKey> std::make_unique<KeymasterSigningKey>();
+ virtual ~KeymasterSigningKey(){};
+
// Allow the key to be moved around
KeymasterSigningKey& operator=(KeymasterSigningKey&& other) = default;
KeymasterSigningKey(KeymasterSigningKey&& other) = default;
- static android::base::Result<KeymasterSigningKey>
- loadFromBlobAndVerify(const std::string& path);
- static android::base::Result<KeymasterSigningKey> createNewKey();
+ static android::base::Result<SigningKey*> getInstance();
- /* Sign a message with an initialized signing key */
- android::base::Result<std::string> sign(const std::string& message) const;
- android::base::Result<void> saveKeyblob(const std::string& path) const;
- android::base::Result<std::vector<uint8_t>> getPublicKey() const;
- android::base::Result<void> createX509Cert(const std::string& path) const;
+ virtual android::base::Result<std::string> sign(const std::string& message) const;
+ virtual android::base::Result<std::vector<uint8_t>> getPublicKey() const;
private:
KeymasterSigningKey();
+ static android::base::Result<std::unique_ptr<KeymasterSigningKey>> createAndPersistNewKey();
+ static android::base::Result<std::unique_ptr<KeymasterSigningKey>>
+ loadFromBlobAndVerify(const std::string& path);
+
android::base::Result<void> createSigningKey();
android::base::Result<void> initializeFromKeyblob(const std::string& path);
+ android::base::Result<void> saveKeyblob(const std::string& path) const;
+
+ static android::base::Result<KeymasterSigningKey> createNewKey();
std::optional<Keymaster> mKeymaster;
std::vector<uint8_t> mVerifiedKeyBlob;
diff --git a/ondevice-signing/KeystoreKey.cpp b/ondevice-signing/KeystoreKey.cpp
new file mode 100644
index 0000000..ea84183
--- /dev/null
+++ b/ondevice-signing/KeystoreKey.cpp
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <binder/IServiceManager.h>
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "CertUtils.h"
+#include "KeyConstants.h"
+#include "KeystoreKey.h"
+
+using android::defaultServiceManager;
+using android::IServiceManager;
+using android::sp;
+using android::String16;
+
+using android::hardware::security::keymint::Algorithm;
+using android::hardware::security::keymint::Digest;
+using android::hardware::security::keymint::KeyParameter;
+using android::hardware::security::keymint::KeyParameterValue;
+using android::hardware::security::keymint::KeyPurpose;
+using android::hardware::security::keymint::PaddingMode;
+using android::hardware::security::keymint::SecurityLevel;
+using android::hardware::security::keymint::Tag;
+
+using android::system::keystore2::CreateOperationResponse;
+using android::system::keystore2::Domain;
+using android::system::keystore2::KeyDescriptor;
+using android::system::keystore2::KeyEntryResponse;
+using android::system::keystore2::KeyMetadata;
+
+using android::base::Error;
+using android::base::Result;
+
+using android::base::unique_fd;
+
+static KeyDescriptor getKeyDescriptor() {
+ // AIDL parcelable objects don't have constructor
+ static KeyDescriptor descriptor;
+ static std::once_flag flag;
+ std::call_once(flag, [&]() {
+ descriptor.domain = Domain::SELINUX;
+ descriptor.alias = String16("ondevice-signing");
+ descriptor.nspace = 101; // odsign_key
+ });
+
+ return descriptor;
+}
+
+KeystoreKey::KeystoreKey() {}
+
+Result<KeyMetadata> KeystoreKey::createNewKey(const KeyDescriptor& descriptor) {
+ std::vector<KeyParameter> params;
+
+ KeyParameter algo;
+ algo.tag = Tag::ALGORITHM;
+ algo.value = KeyParameterValue::make<KeyParameterValue::algorithm>(Algorithm::RSA);
+ params.push_back(algo);
+
+ KeyParameter key_size;
+ key_size.tag = Tag::KEY_SIZE;
+ key_size.value = KeyParameterValue::make<KeyParameterValue::integer>(kRsaKeySize);
+ params.push_back(key_size);
+
+ KeyParameter digest;
+ digest.tag = Tag::DIGEST;
+ digest.value = KeyParameterValue::make<KeyParameterValue::digest>(Digest::SHA_2_256);
+ params.push_back(digest);
+
+ KeyParameter padding;
+ padding.tag = Tag::PADDING;
+ padding.value =
+ KeyParameterValue::make<KeyParameterValue::paddingMode>(PaddingMode::RSA_PKCS1_1_5_SIGN);
+ params.push_back(padding);
+
+ KeyParameter exponent;
+ exponent.tag = Tag::RSA_PUBLIC_EXPONENT;
+ exponent.value = KeyParameterValue::make<KeyParameterValue::longInteger>(kRsaKeyExponent);
+ params.push_back(exponent);
+
+ KeyParameter purpose;
+ purpose.tag = Tag::PURPOSE;
+ purpose.value = KeyParameterValue::make<KeyParameterValue::keyPurpose>(KeyPurpose::SIGN);
+ params.push_back(purpose);
+
+ KeyParameter auth;
+ auth.tag = Tag::NO_AUTH_REQUIRED;
+ auth.value = KeyParameterValue::make<KeyParameterValue::boolValue>(true);
+ params.push_back(auth);
+
+ KeyMetadata metadata;
+ auto status = mSecurityLevel->generateKey(descriptor, {}, params, 0, {}, &metadata);
+ if (!status.isOk()) {
+ return Error() << "Failed to create new key";
+ }
+
+ return metadata;
+}
+
+bool KeystoreKey::initialize() {
+ sp<IServiceManager> sm = defaultServiceManager();
+ if (sm == nullptr) {
+ return false;
+ }
+ auto service = sm->getService(String16("android.system.keystore2"));
+ if (service == nullptr) {
+ return false;
+ }
+ mService = interface_cast<android::system::keystore2::IKeystoreService>(service);
+ if (mService == nullptr) {
+ return false;
+ }
+
+ auto status = mService->getSecurityLevel(SecurityLevel::STRONGBOX, &mSecurityLevel);
+ if (!status.isOk()) {
+ // TODO fallback to TEE
+ return false;
+ }
+
+ auto descriptor = getKeyDescriptor();
+ // See if we can fetch an existing key
+ KeyEntryResponse keyEntryResponse;
+ LOG(INFO) << "Trying to retrieve existing keystore key...";
+ status = mService->getKeyEntry(descriptor, &keyEntryResponse);
+ if (!status.isOk()) {
+ LOG(INFO) << "Existing keystore key not found, creating new key";
+ auto newKeyStatus = createNewKey(descriptor);
+ if (!newKeyStatus.ok()) {
+ LOG(ERROR) << "Failed to create new key";
+ return false;
+ }
+ mKeyMetadata = *newKeyStatus;
+ } else {
+ mKeyMetadata = keyEntryResponse.metadata;
+ }
+
+ LOG(ERROR) << "Initialized Keystore key.";
+ return true;
+}
+
+Result<SigningKey*> KeystoreKey::getInstance() {
+ static KeystoreKey keystoreKey;
+
+ if (!keystoreKey.initialize()) {
+ return Error() << "Failed to initialize keystore key.";
+ } else {
+ return &keystoreKey;
+ }
+}
+
+static std::vector<KeyParameter> getSignOpParameters() {
+ std::vector<KeyParameter> opParameters;
+
+ KeyParameter algo;
+ algo.tag = Tag::ALGORITHM;
+ algo.value = KeyParameterValue::make<KeyParameterValue::algorithm>(Algorithm::RSA);
+ opParameters.push_back(algo);
+
+ KeyParameter digest;
+ digest.tag = Tag::DIGEST;
+ digest.value = KeyParameterValue::make<KeyParameterValue::digest>(Digest::SHA_2_256);
+ opParameters.push_back(digest);
+
+ KeyParameter padding;
+ padding.tag = Tag::PADDING;
+ padding.value =
+ KeyParameterValue::make<KeyParameterValue::paddingMode>(PaddingMode::RSA_PKCS1_1_5_SIGN);
+ opParameters.push_back(padding);
+
+ KeyParameter purpose;
+ purpose.tag = Tag::PURPOSE;
+ purpose.value = KeyParameterValue::make<KeyParameterValue::keyPurpose>(KeyPurpose::SIGN);
+ opParameters.push_back(purpose);
+
+ return opParameters;
+}
+
+Result<std::string> KeystoreKey::sign(const std::string& message) const {
+ static auto opParameters = getSignOpParameters();
+
+ CreateOperationResponse opResponse;
+
+ auto status =
+ mSecurityLevel->createOperation(getKeyDescriptor(), opParameters, false, &opResponse);
+ if (!status.isOk()) {
+ return Error() << "Failed to create keystore signing operation: "
+ << status.serviceSpecificErrorCode();
+ }
+ auto operation = opResponse.iOperation;
+
+ std::optional<std::vector<uint8_t>> out;
+ status = operation->update({message.begin(), message.end()}, &out);
+ if (!status.isOk()) {
+ return Error() << "Failed to call keystore update operation.";
+ }
+
+ std::optional<std::vector<uint8_t>> signature;
+ status = operation->finish({}, {}, &signature);
+ if (!status.isOk()) {
+ return Error() << "Failed to call keystore finish operation.";
+ }
+
+ if (!signature.has_value()) {
+ return Error() << "Didn't receive a signature from keystore finish operation.";
+ }
+
+ std::string result{signature.value().begin(), signature.value().end()};
+
+ return result;
+}
+
+Result<std::vector<uint8_t>> KeystoreKey::getPublicKey() const {
+ return extractPublicKeyFromX509(mKeyMetadata.certificate.value());
+}
diff --git a/ondevice-signing/KeystoreKey.h b/ondevice-signing/KeystoreKey.h
new file mode 100644
index 0000000..6b9cb57
--- /dev/null
+++ b/ondevice-signing/KeystoreKey.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#pragma once
+
+#include <optional>
+
+#include <android-base/macros.h>
+#include <android-base/result.h>
+#include <android-base/unique_fd.h>
+
+#include <utils/StrongPointer.h>
+
+#include <android/system/keystore2/IKeystoreService.h>
+
+#include "SigningKey.h"
+
+class KeystoreKey : public SigningKey {
+ using IKeystoreService = ::android::system::keystore2::IKeystoreService;
+ using IKeystoreSecurityLevel = ::android::system::keystore2::IKeystoreSecurityLevel;
+ using KeyDescriptor = ::android::system::keystore2::KeyDescriptor;
+ using KeyMetadata = ::android::system::keystore2::KeyMetadata;
+
+ public:
+ virtual ~KeystoreKey(){};
+ static android::base::Result<SigningKey*> getInstance();
+
+ virtual android::base::Result<std::string> sign(const std::string& message) const;
+ virtual android::base::Result<std::vector<uint8_t>> getPublicKey() const;
+
+ private:
+ KeystoreKey();
+ bool initialize();
+ android::base::Result<KeyMetadata> createNewKey(const KeyDescriptor& descriptor);
+
+ android::sp<IKeystoreService> mService;
+ android::sp<IKeystoreSecurityLevel> mSecurityLevel;
+ KeyMetadata mKeyMetadata;
+};
diff --git a/ondevice-signing/SigningKey.h b/ondevice-signing/SigningKey.h
new file mode 100644
index 0000000..89294fc
--- /dev/null
+++ b/ondevice-signing/SigningKey.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#pragma once
+
+#include <android-base/macros.h>
+#include <android-base/result.h>
+
+class SigningKey {
+ public:
+ virtual ~SigningKey(){};
+ /* Sign a message with an initialized signing key */
+ virtual android::base::Result<std::string> sign(const std::string& message) const = 0;
+ /* Retrieve the associated public key */
+ virtual android::base::Result<std::vector<uint8_t>> getPublicKey() const = 0;
+};
diff --git a/ondevice-signing/VerityUtils.cpp b/ondevice-signing/VerityUtils.cpp
index 3d0b85a..71ba8f6 100644
--- a/ondevice-signing/VerityUtils.cpp
+++ b/ondevice-signing/VerityUtils.cpp
@@ -15,12 +15,14 @@
*/
#include <filesystem>
+#include <map>
#include <string>
#include <fcntl.h>
#include <linux/fs.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <sys/wait.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
@@ -28,7 +30,7 @@
#include <linux/fsverity.h>
#include "CertUtils.h"
-#include "KeymasterSigningKey.h"
+#include "SigningKey.h"
#define FS_VERITY_MAX_DIGEST_SIZE 64
@@ -37,6 +39,8 @@
using android::base::Result;
using android::base::unique_fd;
+static const char* kFsVerityInitPath = "/system/bin/fsverity_init";
+
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define cpu_to_le16(v) ((__force __le16)(uint16_t)(v))
#define le16_to_cpu(v) ((__force uint16_t)(__le16)(v))
@@ -84,7 +88,7 @@
return std::vector<uint8_t>(&digest->digest[0], &digest->digest[32]);
}
-static Result<std::vector<uint8_t>> signDigest(const KeymasterSigningKey& key,
+static Result<std::vector<uint8_t>> signDigest(const SigningKey& key,
const std::vector<uint8_t>& digest) {
fsverity_signed_digest* d;
size_t signed_digest_size = sizeof(*d) + digest.size();
@@ -104,7 +108,7 @@
return std::vector<uint8_t>(signed_digest->begin(), signed_digest->end());
}
-Result<std::string> enableFsVerity(const std::string& path, const KeymasterSigningKey& key) {
+Result<std::string> enableFsVerity(const std::string& path, const SigningKey& key) {
auto digest = createDigest(path);
if (!digest.ok()) {
return digest.error();
@@ -135,8 +139,8 @@
return toHex(digest.value());
}
-Result<std::map<std::string, std::string>>
-addFilesToVerityRecursive(const std::string& path, const KeymasterSigningKey& key) {
+Result<std::map<std::string, std::string>> addFilesToVerityRecursive(const std::string& path,
+ const SigningKey& key) {
std::map<std::string, std::string> digests;
std::error_code ec;
@@ -213,3 +217,40 @@
return digests;
}
+
+Result<void> addCertToFsVerityKeyring(const std::string& path) {
+ const char* const argv[] = {kFsVerityInitPath, "--load-extra-key", "fsv_ods"};
+
+ int fd = open(path.c_str(), O_RDONLY | O_CLOEXEC);
+ pid_t pid = fork();
+ if (pid == 0) {
+ dup2(fd, STDIN_FILENO);
+ close(fd);
+ int argc = arraysize(argv);
+ char* argv_child[argc + 1];
+ memcpy(argv_child, argv, argc * sizeof(char*));
+ argv_child[argc] = nullptr;
+ execvp(argv_child[0], const_cast<char**>(argv_child));
+ PLOG(ERROR) << "exec in ForkExecvp";
+ _exit(EXIT_FAILURE);
+ } else {
+ close(fd);
+ }
+ if (pid == -1) {
+ return ErrnoError() << "Failed to fork.";
+ }
+ int status;
+ if (waitpid(pid, &status, 0) == -1) {
+ return ErrnoError() << "waitpid() failed.";
+ }
+ if (!WIFEXITED(status)) {
+ return Error() << kFsVerityInitPath << ": abnormal process exit";
+ }
+ if (WEXITSTATUS(status)) {
+ if (status != 0) {
+ return Error() << kFsVerityInitPath << " exited with " << status;
+ }
+ }
+
+ return {};
+}
diff --git a/ondevice-signing/VerityUtils.h b/ondevice-signing/VerityUtils.h
index d913073..84af319 100644
--- a/ondevice-signing/VerityUtils.h
+++ b/ondevice-signing/VerityUtils.h
@@ -18,10 +18,11 @@
#include <android-base/result.h>
-#include "KeymasterSigningKey.h"
+#include "SigningKey.h"
+android::base::Result<void> addCertToFsVerityKeyring(const std::string& path);
android::base::Result<std::vector<uint8_t>> createDigest(const std::string& path);
android::base::Result<std::map<std::string, std::string>>
verifyAllFilesInVerity(const std::string& path);
android::base::Result<std::map<std::string, std::string>>
-addFilesToVerityRecursive(const std::string& path, const KeymasterSigningKey& key);
+addFilesToVerityRecursive(const std::string& path, const SigningKey& key);
diff --git a/ondevice-signing/odsign_main.cpp b/ondevice-signing/odsign_main.cpp
index 1c63ecb..853f349 100644
--- a/ondevice-signing/odsign_main.cpp
+++ b/ondevice-signing/odsign_main.cpp
@@ -22,7 +22,6 @@
#include <iterator>
#include <sys/stat.h>
#include <sys/types.h>
-#include <sys/wait.h>
#include <unistd.h>
#include <android-base/file.h>
@@ -32,6 +31,7 @@
#include "CertUtils.h"
#include "KeymasterSigningKey.h"
+#include "KeystoreKey.h"
#include "VerityUtils.h"
#include "odsign_info.pb.h"
@@ -51,57 +51,12 @@
static const char* kOdrefreshPath = "/apex/com.android.art/bin/odrefresh";
-static const char* kFsVerityInitPath = "/system/bin/fsverity_init";
static const char* kFsVerityProcPath = "/proc/sys/fs/verity";
static const bool kForceCompilation = false;
+static const bool kUseKeystore = false;
-Result<void> addCertToFsVerityKeyring(const std::string& path) {
- const char* const argv[] = {kFsVerityInitPath, "--load-extra-key", "fsv_ods"};
-
- // NOLINTNEXTLINE(android-cloexec-open): Deliberately not O_CLOEXEC
- int fd = open(path.c_str(), O_RDONLY);
- pid_t pid = fork();
- if (pid == 0) {
- dup2(fd, STDIN_FILENO);
- close(fd);
- int argc = arraysize(argv);
- char* argv_child[argc + 1];
- memcpy(argv_child, argv, argc * sizeof(char*));
- argv_child[argc] = nullptr;
- execvp(argv_child[0], const_cast<char**>(argv_child));
- PLOG(ERROR) << "exec in ForkExecvp";
- _exit(EXIT_FAILURE);
- } else {
- close(fd);
- }
- if (pid == -1) {
- return ErrnoError() << "Failed to fork.";
- }
- int status;
- if (waitpid(pid, &status, 0) == -1) {
- return ErrnoError() << "waitpid() failed.";
- }
- if (!WIFEXITED(status)) {
- return Error() << kFsVerityInitPath << ": abnormal process exit";
- }
- if (WEXITSTATUS(status)) {
- if (status != 0) {
- return Error() << kFsVerityInitPath << " exited with " << status;
- }
- }
-
- return {};
-}
-
-Result<KeymasterSigningKey> loadAndVerifyExistingKey() {
- if (access(kSigningKeyBlob.c_str(), F_OK) < 0) {
- return ErrnoError() << "Key blob not found: " << kSigningKeyBlob;
- }
- return KeymasterSigningKey::loadFromBlobAndVerify(kSigningKeyBlob);
-}
-
-Result<void> verifyExistingCert(const KeymasterSigningKey& key) {
+Result<void> verifyExistingCert(const SigningKey& key) {
if (access(kSigningKeyCert.c_str(), F_OK) < 0) {
return ErrnoError() << "Key certificate not found: " << kSigningKeyCert;
}
@@ -123,19 +78,18 @@
return {};
}
-Result<KeymasterSigningKey> createAndPersistKey(const std::string& path) {
- auto key = KeymasterSigningKey::createNewKey();
+Result<void> createX509Cert(const SigningKey& key, const std::string& outPath) {
+ auto publicKey = key.getPublicKey();
- if (!key.ok()) {
- return key.error();
+ if (!publicKey.ok()) {
+ return publicKey.error();
}
- auto result = key->saveKeyblob(path);
- if (!result.ok()) {
- return result.error();
- }
-
- return key;
+ auto keymasterSignFunction = [&](const std::string& to_be_signed) {
+ return key.sign(to_be_signed);
+ };
+ createSelfSignedCertificate(*publicKey, keymasterSignFunction, outPath);
+ return {};
}
bool compileArtifacts(bool force) {
@@ -224,7 +178,7 @@
return verifyDigests(*result, trusted_digests);
}
-Result<OdsignInfo> getOdsignInfo(const KeymasterSigningKey& /* key */) {
+Result<OdsignInfo> getOdsignInfo(const SigningKey& /* key */) {
std::string persistedSignature;
OdsignInfo odsignInfo;
@@ -263,7 +217,7 @@
}
Result<void> persistDigests(const std::map<std::string, std::string>& digests,
- const KeymasterSigningKey& key) {
+ const SigningKey& key) {
OdsignInfo signInfo;
google::protobuf::Map<std::string, std::string> proto_hashes(digests.begin(), digests.end());
auto map = signInfo.mutable_file_hashes();
@@ -304,17 +258,22 @@
// Make sure we delete the artifacts in all early (error) exit paths
auto scope_guard = android::base::make_scope_guard(removeArtifacts);
- auto key = loadAndVerifyExistingKey();
- if (!key.ok()) {
- LOG(WARNING) << key.error().message();
-
- key = createAndPersistKey(kSigningKeyBlob);
- if (!key.ok()) {
- LOG(ERROR) << "Failed to create or persist new key: " << key.error().message();
+ SigningKey* key;
+ if (kUseKeystore) {
+ auto keystoreResult = KeystoreKey::getInstance();
+ if (!keystoreResult.ok()) {
+ LOG(ERROR) << "Could not create keystore key: " << keystoreResult.error().message();
return -1;
}
+ key = keystoreResult.value();
} else {
- LOG(INFO) << "Found and verified existing key: " << kSigningKeyBlob;
+ // TODO - keymaster will go away
+ auto keymasterResult = KeymasterSigningKey::getInstance();
+ if (!keymasterResult.ok()) {
+ LOG(ERROR) << "Failed to create keymaster key: " << keymasterResult.error().message();
+ return -1;
+ }
+ key = keymasterResult.value();
}
bool supportsFsVerity = access(kFsVerityProcPath, F_OK) == 0;
@@ -323,12 +282,12 @@
}
if (supportsFsVerity) {
- auto existing_cert = verifyExistingCert(key.value());
+ auto existing_cert = verifyExistingCert(*key);
if (!existing_cert.ok()) {
LOG(WARNING) << existing_cert.error().message();
// Try to create a new cert
- auto new_cert = key->createX509Cert(kSigningKeyCert);
+ auto new_cert = createX509Cert(*key, kSigningKeyCert);
if (!new_cert.ok()) {
LOG(ERROR) << "Failed to create X509 certificate: " << new_cert.error().message();
// TODO apparently the key become invalid - delete the blob / cert
@@ -345,7 +304,7 @@
}
}
- auto signInfo = getOdsignInfo(key.value());
+ auto signInfo = getOdsignInfo(*key);
if (!signInfo.ok()) {
int num_removed = removeArtifacts();
// Only a warning if there were artifacts to begin with, which suggests tampering or
@@ -381,7 +340,7 @@
Result<std::map<std::string, std::string>> digests;
if (supportsFsVerity) {
- digests = addFilesToVerityRecursive(kArtArtifactsDir, key.value());
+ digests = addFilesToVerityRecursive(kArtArtifactsDir, *key);
} else {
// If we can't use verity, just compute the root hashes and store
// those, so we can reverify them at the next boot.
@@ -392,7 +351,7 @@
return -1;
}
- auto persistStatus = persistDigests(*digests, key.value());
+ auto persistStatus = persistDigests(*digests, *key);
if (!persistStatus.ok()) {
LOG(ERROR) << persistStatus.error().message();
return -1;