Merge "Log keystore2 crash events."
diff --git a/keystore2/src/fuzzers/Android.bp b/keystore2/src/fuzzers/Android.bp
new file mode 100644
index 0000000..384ab77
--- /dev/null
+++ b/keystore2/src/fuzzers/Android.bp
@@ -0,0 +1,29 @@
+// Copyright 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.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_fuzz {
+ name: "legacy_blob_fuzzer",
+ srcs: ["legacy_blob_fuzzer.rs"],
+ rustlibs: [
+ "libkeystore2",
+ ],
+ fuzz_config: {
+ fuzz_on_haiku_device: true,
+ fuzz_on_haiku_host: false,
+ },
+}
diff --git a/keystore2/src/fuzzers/legacy_blob_fuzzer.rs b/keystore2/src/fuzzers/legacy_blob_fuzzer.rs
new file mode 100644
index 0000000..5c89ca4
--- /dev/null
+++ b/keystore2/src/fuzzers/legacy_blob_fuzzer.rs
@@ -0,0 +1,24 @@
+// Copyright 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.
+
+#![allow(missing_docs)]
+#![no_main]
+#[macro_use]
+extern crate libfuzzer_sys;
+use keystore2::legacy_blob::LegacyBlobLoader;
+
+fuzz_target!(|data: &[u8]| {
+ let string = data.iter().filter_map(|c| std::char::from_u32(*c as u32)).collect::<String>();
+ let _res = LegacyBlobLoader::decode_alias(&string);
+});
diff --git a/ondevice-signing/Android.bp b/ondevice-signing/Android.bp
index c8ce373..5219240 100644
--- a/ondevice-signing/Android.bp
+++ b/ondevice-signing/Android.bp
@@ -107,7 +107,7 @@
"libcrypto_utils",
"libfsverity",
"liblogwrap",
- "libprotobuf-cpp-full",
+ "libprotobuf-cpp-lite",
"libutils",
],
}
diff --git a/ondevice-signing/CertUtils.cpp b/ondevice-signing/CertUtils.cpp
index d2f19ce..8d4f273 100644
--- a/ondevice-signing/CertUtils.cpp
+++ b/ondevice-signing/CertUtils.cpp
@@ -77,7 +77,7 @@
reinterpret_cast<const unsigned char*>(value), -1, -1, 0);
}
-Result<bssl::UniquePtr<RSA>> getRsa(const std::vector<uint8_t>& publicKey) {
+static Result<bssl::UniquePtr<RSA>> getRsaFromModulus(const std::vector<uint8_t>& publicKey) {
bssl::UniquePtr<BIGNUM> n(BN_new());
bssl::UniquePtr<BIGNUM> e(BN_new());
bssl::UniquePtr<RSA> rsaPubkey(RSA_new());
@@ -93,9 +93,53 @@
return rsaPubkey;
}
+static Result<bssl::UniquePtr<RSA>>
+getRsaFromRsaPublicKey(const std::vector<uint8_t>& rsaPublicKey) {
+ auto derBytes = rsaPublicKey.data();
+ bssl::UniquePtr<RSA> rsaKey(d2i_RSAPublicKey(nullptr, &derBytes, rsaPublicKey.size()));
+ if (rsaKey.get() == nullptr) {
+ return Error() << "Failed to parse RsaPublicKey";
+ }
+ if (derBytes != rsaPublicKey.data() + rsaPublicKey.size()) {
+ return Error() << "Key has unexpected trailing data";
+ }
+
+ return rsaKey;
+}
+
+static Result<bssl::UniquePtr<EVP_PKEY>> modulusToRsaPkey(const std::vector<uint8_t>& publicKey) {
+ // "publicKey" corresponds to the raw public key bytes - need to create
+ // a new RSA key with the correct exponent.
+ auto rsaPubkey = getRsaFromModulus(publicKey);
+ if (!rsaPubkey.ok()) {
+ return rsaPubkey.error();
+ }
+
+ bssl::UniquePtr<EVP_PKEY> public_key(EVP_PKEY_new());
+ if (!EVP_PKEY_assign_RSA(public_key.get(), rsaPubkey->release())) {
+ return Error() << "Failed to assign key";
+ }
+ return public_key;
+}
+
+static Result<bssl::UniquePtr<EVP_PKEY>>
+rsaPublicKeyToRsaPkey(const std::vector<uint8_t>& rsaPublicKey) {
+ // rsaPublicKey contains both modulus and exponent, DER-encoded.
+ auto rsaKey = getRsaFromRsaPublicKey(rsaPublicKey);
+ if (!rsaKey.ok()) {
+ return rsaKey.error();
+ }
+
+ bssl::UniquePtr<EVP_PKEY> public_key(EVP_PKEY_new());
+ if (!EVP_PKEY_assign_RSA(public_key.get(), rsaKey->release())) {
+ return Error() << "Failed to assign key";
+ }
+ return public_key;
+}
+
Result<void> verifySignature(const std::string& message, const std::string& signature,
const std::vector<uint8_t>& publicKey) {
- auto rsaKey = getRsa(publicKey);
+ auto rsaKey = getRsaFromModulus(publicKey);
if (!rsaKey.ok()) {
return rsaKey.error();
}
@@ -112,23 +156,27 @@
return {};
}
-static Result<bssl::UniquePtr<EVP_PKEY>> toRsaPkey(const std::vector<uint8_t>& publicKey) {
- // "publicKey" corresponds to the raw public key bytes - need to create
- // a new RSA key with the correct exponent.
- auto rsaPubkey = getRsa(publicKey);
- if (!rsaPubkey.ok()) {
- return rsaPubkey.error();
+Result<void> verifyRsaPublicKeySignature(const std::string& message, const std::string& signature,
+ const std::vector<uint8_t>& rsaPublicKey) {
+ auto rsaKey = getRsaFromRsaPublicKey(rsaPublicKey);
+ if (!rsaKey.ok()) {
+ return rsaKey.error();
}
- bssl::UniquePtr<EVP_PKEY> public_key(EVP_PKEY_new());
- if (!EVP_PKEY_assign_RSA(public_key.get(), rsaPubkey->release())) {
- return Error() << "Failed to assign key";
+ uint8_t hashBuf[SHA256_DIGEST_LENGTH];
+ SHA256(reinterpret_cast<const uint8_t*>(message.data()), message.size(), hashBuf);
+
+ bool success = RSA_verify(NID_sha256, hashBuf, sizeof(hashBuf),
+ reinterpret_cast<const uint8_t*>(signature.data()), signature.size(),
+ rsaKey->get());
+ if (!success) {
+ return Error() << "Failed to verify signature";
}
- return public_key;
+ return {};
}
static Result<void> createCertificate(
- const CertSubject& subject, const std::vector<uint8_t>& publicKey,
+ const CertSubject& subject, EVP_PKEY* publicKey,
const std::function<android::base::Result<std::string>(const std::string&)>& signFunction,
const std::optional<std::string>& issuerCertPath, const std::string& path) {
@@ -153,12 +201,7 @@
return Error() << "Unable to set x509 signature algorithm";
}
- auto public_key = toRsaPkey(publicKey);
- if (!public_key.ok()) {
- return public_key.error();
- }
-
- if (!X509_set_pubkey(x509.get(), public_key.value().get())) {
+ if (!X509_set_pubkey(x509.get(), publicKey)) {
return Error() << "Unable to set x509 public key";
}
@@ -241,14 +284,24 @@
const std::vector<uint8_t>& publicKey,
const std::function<Result<std::string>(const std::string&)>& signFunction,
const std::string& path) {
- return createCertificate(kRootSubject, publicKey, signFunction, {}, path);
+ auto rsa_pkey = modulusToRsaPkey(publicKey);
+ if (!rsa_pkey.ok()) {
+ return rsa_pkey.error();
+ }
+
+ return createCertificate(kRootSubject, rsa_pkey.value().get(), signFunction, {}, path);
}
android::base::Result<void> createLeafCertificate(
- const CertSubject& subject, const std::vector<uint8_t>& publicKey,
+ const CertSubject& subject, const std::vector<uint8_t>& rsaPublicKey,
const std::function<android::base::Result<std::string>(const std::string&)>& signFunction,
const std::string& issuerCertPath, const std::string& path) {
- return createCertificate(subject, publicKey, signFunction, issuerCertPath, path);
+ auto rsa_pkey = rsaPublicKeyToRsaPkey(rsaPublicKey);
+ if (!rsa_pkey.ok()) {
+ return rsa_pkey.error();
+ }
+
+ return createCertificate(subject, rsa_pkey.value().get(), signFunction, issuerCertPath, path);
}
Result<std::vector<uint8_t>> extractPublicKey(EVP_PKEY* pkey) {
@@ -332,7 +385,7 @@
Result<CertInfo> verifyAndExtractCertInfoFromX509(const std::string& path,
const std::vector<uint8_t>& publicKey) {
- auto public_key = toRsaPkey(publicKey);
+ auto public_key = modulusToRsaPkey(publicKey);
if (!public_key.ok()) {
return public_key.error();
}
@@ -349,7 +402,7 @@
}
bssl::UniquePtr<EVP_PKEY> pkey(X509_get_pubkey(x509));
- auto subject_key = extractPublicKey(pkey.get());
+ auto subject_key = extractRsaPublicKey(pkey.get());
if (!subject_key.ok()) {
return subject_key.error();
}
@@ -382,20 +435,20 @@
BIGNUM* serial = BN_new();
int sig_nid = NID_rsaEncryption;
- X509_NAME* name = X509_NAME_new();
- if (!name) {
- return Error() << "Unable to get x509 subject name";
+ X509_NAME* issuer_name = X509_NAME_new();
+ if (!issuer_name) {
+ return Error() << "Unable to create x509 subject name";
}
- X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC,
+ X509_NAME_add_entry_by_txt(issuer_name, "C", MBSTRING_ASC,
reinterpret_cast<const unsigned char*>(kIssuerCountry), -1, -1, 0);
- X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC,
+ X509_NAME_add_entry_by_txt(issuer_name, "O", MBSTRING_ASC,
reinterpret_cast<const unsigned char*>(kIssuerOrg), -1, -1, 0);
- X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
- reinterpret_cast<const unsigned char*>(signer.commonName), -1, -1,
- 0);
+ X509_NAME_add_entry_by_txt(issuer_name, "CN", MBSTRING_ASC,
+ reinterpret_cast<const unsigned char*>(kRootSubject.commonName), -1,
+ -1, 0);
BN_set_word(serial, signer.serialNumber);
- name_der_len = i2d_X509_NAME(name, &name_der);
+ name_der_len = i2d_X509_NAME(issuer_name, &name_der);
CBB_init(&out, 1024);
if (!CBB_add_asn1(&out, &outer_seq, CBS_ASN1_SEQUENCE) ||
diff --git a/ondevice-signing/CertUtils.h b/ondevice-signing/CertUtils.h
index fd6080d..1ed4c06 100644
--- a/ondevice-signing/CertUtils.h
+++ b/ondevice-signing/CertUtils.h
@@ -25,7 +25,7 @@
// Information extracted from a certificate.
struct CertInfo {
std::string subjectCn;
- std::vector<uint8_t> subjectKey;
+ std::vector<uint8_t> subjectRsaPublicKey;
};
// Subjects of certificates we issue.
@@ -69,3 +69,7 @@
android::base::Result<void> verifySignature(const std::string& message,
const std::string& signature,
const std::vector<uint8_t>& publicKey);
+
+android::base::Result<void> verifyRsaPublicKeySignature(const std::string& message,
+ const std::string& signature,
+ const std::vector<uint8_t>& rsaPublicKey);
diff --git a/ondevice-signing/FakeCompOs.cpp b/ondevice-signing/FakeCompOs.cpp
index 637fe5c..e2273a3 100644
--- a/ondevice-signing/FakeCompOs.cpp
+++ b/ondevice-signing/FakeCompOs.cpp
@@ -16,6 +16,7 @@
#include "FakeCompOs.h"
+#include "CertUtils.h"
#include "KeyConstants.h"
#include <android-base/file.h>
@@ -212,28 +213,6 @@
return signature.value();
}
-Result<void> FakeCompOs::verifySignature(const ByteVector& message, const ByteVector& signature,
- const ByteVector& rsaPublicKey) const {
- auto derBytes = rsaPublicKey.data();
- bssl::UniquePtr<RSA> rsaKey(d2i_RSAPublicKey(nullptr, &derBytes, rsaPublicKey.size()));
- if (rsaKey.get() == nullptr) {
- return Error() << "Failed to parse RsaPublicKey";
- }
- if (derBytes != rsaPublicKey.data() + rsaPublicKey.size()) {
- return Error() << "Key has unexpected trailing data";
- }
-
- uint8_t hashBuf[SHA256_DIGEST_LENGTH];
- SHA256(message.data(), message.size(), hashBuf);
-
- bool success = RSA_verify(NID_sha256, hashBuf, sizeof(hashBuf), signature.data(),
- signature.size(), rsaKey.get());
- if (!success) {
- return Error() << "Failed to verify signature";
- }
- return {};
-}
-
Result<void> FakeCompOs::loadAndVerifyKey(const ByteVector& keyBlob,
const ByteVector& publicKey) const {
// To verify the key is valid, we use it to sign some data, and then verify the signature using
@@ -249,5 +228,8 @@
return signature.error();
}
- return verifySignature(data, signature.value(), publicKey);
+ std::string signatureString(reinterpret_cast<char*>(signature.value().data()),
+ signature.value().size());
+ std::string dataString(reinterpret_cast<char*>(data.data()), data.size());
+ return verifySignature(dataString, signatureString, publicKey);
}
diff --git a/ondevice-signing/FakeCompOs.h b/ondevice-signing/FakeCompOs.h
index 6c12c60..7d76938 100644
--- a/ondevice-signing/FakeCompOs.h
+++ b/ondevice-signing/FakeCompOs.h
@@ -53,9 +53,6 @@
android::base::Result<ByteVector> signData(const ByteVector& keyBlob,
const ByteVector& data) const;
- android::base::Result<void> verifySignature(const ByteVector& message,
- const ByteVector& signature,
- const ByteVector& rsaPublicKey) const;
KeyDescriptor mDescriptor;
android::sp<IKeystoreService> mService;
diff --git a/ondevice-signing/VerityUtils.cpp b/ondevice-signing/VerityUtils.cpp
index 543e5a4..e58de68 100644
--- a/ondevice-signing/VerityUtils.cpp
+++ b/ondevice-signing/VerityUtils.cpp
@@ -27,6 +27,7 @@
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
+#include <asm/byteorder.h>
#include <libfsverity.h>
#include <linux/fsverity.h>
@@ -46,14 +47,6 @@
static const char* kFsVerityInitPath = "/system/bin/fsverity_init";
static const char* kSignatureExtension = ".signature";
-#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))
-#else
-#define cpu_to_le16(v) ((__force __le16)__builtin_bswap16(v))
-#define le16_to_cpu(v) (__builtin_bswap16((__force uint16_t)(v)))
-#endif
-
static bool isSignatureFile(const std::filesystem::path& path) {
return path.extension().native() == kSignatureExtension;
}
@@ -128,8 +121,8 @@
auto d = makeUniqueWithTrailingData<fsverity_formatted_digest>(digest.size());
memcpy(d->magic, "FSVerity", 8);
- d->digest_algorithm = cpu_to_le16(FS_VERITY_HASH_ALG_SHA256);
- d->digest_size = cpu_to_le16(digest.size());
+ d->digest_algorithm = __cpu_to_le16(FS_VERITY_HASH_ALG_SHA256);
+ d->digest_size = __cpu_to_le16(digest.size());
memcpy(d->digest, digest.data(), digest.size());
auto signed_digest = key.sign(std::string((char*)d.get(), sizeof(*d) + digest.size()));
@@ -314,9 +307,20 @@
auto& raw_digest = signature->digest();
auto& raw_signature = signature->signature();
+ // Re-construct the fsverity_formatted_digest that was signed, so we
+ // can verify the signature.
+ std::vector<uint8_t> buffer(sizeof(fsverity_formatted_digest) + raw_digest.size());
+ auto signed_data = new (buffer.data()) fsverity_formatted_digest;
+ memcpy(signed_data->magic, "FSVerity", sizeof signed_data->magic);
+ signed_data->digest_algorithm = __cpu_to_le16(FS_VERITY_HASH_ALG_SHA256);
+ signed_data->digest_size = __cpu_to_le16(raw_digest.size());
+ memcpy(signed_data->digest, raw_digest.data(), raw_digest.size());
+
// Make sure the signature matches the CompOs public key, and not some other
// fs-verity trusted key.
- auto verified = verifySignature(raw_digest, raw_signature, compos_key);
+ std::string to_verify(reinterpret_cast<char*>(buffer.data()), buffer.size());
+
+ auto verified = verifyRsaPublicKeySignature(to_verify, raw_signature, compos_key);
if (!verified.ok()) {
return Error() << verified.error() << ": " << path;
}
diff --git a/ondevice-signing/odsign_main.cpp b/ondevice-signing/odsign_main.cpp
index b14a91e..d11107f 100644
--- a/ondevice-signing/odsign_main.cpp
+++ b/ondevice-signing/odsign_main.cpp
@@ -162,9 +162,9 @@
return createSelfSignedCertificate(*publicKey, keySignFunction, outPath);
}
-Result<std::vector<uint8_t>> extractPublicKeyFromLeafCert(const SigningKey& key,
- const std::string& certPath,
- const std::string& expectedCn) {
+Result<std::vector<uint8_t>> extractRsaPublicKeyFromLeafCert(const SigningKey& key,
+ const std::string& certPath,
+ const std::string& expectedCn) {
if (access(certPath.c_str(), F_OK) < 0) {
return ErrnoError() << "Certificate not found: " << certPath;
}
@@ -185,7 +185,7 @@
<< ", should be " << expectedCn;
}
- return existingCertInfo.value().subjectKey;
+ return existingCertInfo.value().subjectRsaPublicKey;
}
Result<std::vector<uint8_t>> verifyOrGenerateCompOsKey(const SigningKey& signingKey) {
@@ -403,7 +403,7 @@
Result<std::vector<uint8_t>> addCompOsCertToFsVerityKeyring(const SigningKey& signingKey) {
std::vector<uint8_t> compos_key;
auto existing_key =
- extractPublicKeyFromLeafCert(signingKey, kCompOsCert, kCompOsSubject.commonName);
+ extractRsaPublicKeyFromLeafCert(signingKey, kCompOsCert, kCompOsSubject.commonName);
if (existing_key.ok()) {
LOG(INFO) << "Found and verified existing CompOs public key certificate: " << kCompOsCert;
compos_key = std::move(existing_key.value());
diff --git a/ondevice-signing/proto/Android.bp b/ondevice-signing/proto/Android.bp
index fc08677..c042b8e 100644
--- a/ondevice-signing/proto/Android.bp
+++ b/ondevice-signing/proto/Android.bp
@@ -23,7 +23,7 @@
host_supported: true,
proto: {
export_proto_headers: true,
- type: "full",
+ type: "lite",
},
srcs: ["odsign_info.proto"],
}
@@ -33,7 +33,11 @@
host_supported: true,
proto: {
export_proto_headers: true,
- type: "full",
+ type: "lite",
},
srcs: ["compos_signature.proto"],
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.compos",
+ ],
}
diff --git a/ondevice-signing/proto/compos_signature.proto b/ondevice-signing/proto/compos_signature.proto
index 0659ade..2f7d09f 100644
--- a/ondevice-signing/proto/compos_signature.proto
+++ b/ondevice-signing/proto/compos_signature.proto
@@ -20,10 +20,11 @@
// Data provided by CompOS to allow validation of a file it generated.
message Signature {
- // The fs-verity digest (root hash of the Merkle tree) of the file
- // contents.
+ // The fs-verity digest (which is derived from the root hash of
+ // the Merkle tree) of the file contents.
bytes digest = 1;
- // Signature of the digest, signed using CompOS's private key.
+ // Signature of a fsverity_formatted_digest structure containing
+ // the digest, signed using CompOS's private key.
bytes signature = 2;
}