Snap for 6606167 from c539468f28
to rvc-release
Change-Id: I9997967091a9ee0a519f80bb37975586c662294c
This commit is contained in:
commit
6a537544d6
7 changed files with 507 additions and 16 deletions
|
@ -15,12 +15,10 @@
|
|||
cc_defaults {
|
||||
name: "vhal_v2_0_defaults",
|
||||
shared_libs: [
|
||||
"libbinder_ndk",
|
||||
"libhidlbase",
|
||||
"liblog",
|
||||
"libutils",
|
||||
"android.hardware.automotive.vehicle@2.0",
|
||||
"carwatchdog_aidl_interface-ndk_platform",
|
||||
],
|
||||
cflags: [
|
||||
"-Wall",
|
||||
|
@ -29,6 +27,15 @@ cc_defaults {
|
|||
],
|
||||
}
|
||||
|
||||
cc_defaults {
|
||||
name: "vhal_v2_0_target_defaults",
|
||||
defaults: ["vhal_v2_0_defaults"],
|
||||
shared_libs: [
|
||||
"libbinder_ndk",
|
||||
"carwatchdog_aidl_interface-ndk_platform",
|
||||
],
|
||||
}
|
||||
|
||||
cc_library_headers {
|
||||
name: "vhal_v2_0_common_headers",
|
||||
vendor: true,
|
||||
|
@ -39,7 +46,7 @@ cc_library_headers {
|
|||
cc_library {
|
||||
name: "android.hardware.automotive.vehicle@2.0-manager-lib",
|
||||
vendor: true,
|
||||
defaults: ["vhal_v2_0_defaults"],
|
||||
defaults: ["vhal_v2_0_target_defaults"],
|
||||
srcs: [
|
||||
"common/src/Obd2SensorStore.cpp",
|
||||
"common/src/SubscriptionManager.cpp",
|
||||
|
@ -61,7 +68,7 @@ cc_library {
|
|||
cc_library_static {
|
||||
name: "android.hardware.automotive.vehicle@2.0-default-impl-lib",
|
||||
vendor: true,
|
||||
defaults: ["vhal_v2_0_defaults"],
|
||||
defaults: ["vhal_v2_0_target_defaults"],
|
||||
srcs: [
|
||||
"impl/vhal_v2_0/CommConn.cpp",
|
||||
"impl/vhal_v2_0/EmulatedVehicleConnector.cpp",
|
||||
|
@ -97,16 +104,59 @@ cc_library_static {
|
|||
cc_library_static {
|
||||
name: "android.hardware.automotive.vehicle@2.0-emulated-user-hal-lib",
|
||||
vendor: true,
|
||||
defaults: ["vhal_v2_0_defaults"],
|
||||
defaults: ["vhal_v2_0_target_defaults"],
|
||||
srcs: [
|
||||
"impl/vhal_v2_0/EmulatedUserHal.cpp",
|
||||
],
|
||||
}
|
||||
|
||||
// Vehicle HAL Server reference impl lib
|
||||
cc_library_static {
|
||||
name: "android.hardware.automotive.vehicle@2.0-server-common-lib",
|
||||
vendor: true,
|
||||
host_supported: true,
|
||||
defaults: ["vhal_v2_0_defaults"],
|
||||
local_include_dirs: ["common/include/vhal_v2_0"],
|
||||
export_include_dirs: ["common/include"],
|
||||
srcs: [
|
||||
"common/src/Obd2SensorStore.cpp",
|
||||
"common/src/VehicleObjectPool.cpp",
|
||||
"common/src/VehicleUtils.cpp",
|
||||
],
|
||||
}
|
||||
|
||||
// Vehicle HAL Server default implementation
|
||||
cc_library_static {
|
||||
name: "android.hardware.automotive.vehicle@2.0-server-impl-lib",
|
||||
vendor: true,
|
||||
host_supported: true,
|
||||
defaults: ["vhal_v2_0_defaults"],
|
||||
local_include_dirs: ["common/include/vhal_v2_0"],
|
||||
export_include_dirs: ["impl"],
|
||||
srcs: [
|
||||
"impl/vhal_v2_0/EmulatedUserHal.cpp",
|
||||
"impl/vhal_v2_0/GeneratorHub.cpp",
|
||||
"impl/vhal_v2_0/JsonFakeValueGenerator.cpp",
|
||||
"impl/vhal_v2_0/LinearFakeValueGenerator.cpp",
|
||||
"impl/vhal_v2_0/ProtoMessageConverter.cpp",
|
||||
"impl/vhal_v2_0/VehicleHalServer.cpp",
|
||||
],
|
||||
whole_static_libs: [
|
||||
"android.hardware.automotive.vehicle@2.0-server-common-lib",
|
||||
],
|
||||
static_libs: [
|
||||
"android.hardware.automotive.vehicle@2.0-libproto-native",
|
||||
],
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
"libjsoncpp",
|
||||
],
|
||||
}
|
||||
|
||||
cc_test {
|
||||
name: "android.hardware.automotive.vehicle@2.0-manager-unit-tests",
|
||||
vendor: true,
|
||||
defaults: ["vhal_v2_0_defaults"],
|
||||
defaults: ["vhal_v2_0_target_defaults"],
|
||||
whole_static_libs: ["android.hardware.automotive.vehicle@2.0-manager-lib"],
|
||||
srcs: [
|
||||
"tests/RecurrentTimer_test.cpp",
|
||||
|
@ -126,7 +176,7 @@ cc_test {
|
|||
cc_test {
|
||||
name: "android.hardware.automotive.vehicle@2.0-default-impl-unit-tests",
|
||||
vendor: true,
|
||||
defaults: ["vhal_v2_0_defaults"],
|
||||
defaults: ["vhal_v2_0_target_defaults"],
|
||||
srcs: [
|
||||
"impl/vhal_v2_0/tests/ProtoMessageConverter_test.cpp",
|
||||
],
|
||||
|
@ -140,7 +190,7 @@ cc_test {
|
|||
|
||||
cc_binary {
|
||||
name: "android.hardware.automotive.vehicle@2.0-service",
|
||||
defaults: ["vhal_v2_0_defaults"],
|
||||
defaults: ["vhal_v2_0_target_defaults"],
|
||||
vintf_fragments: [
|
||||
"android.hardware.automotive.vehicle@2.0-service.xml",
|
||||
],
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
cc_library_static {
|
||||
name: "android.hardware.automotive.vehicle@2.0-libproto-native",
|
||||
vendor: true,
|
||||
host_supported: true,
|
||||
proto: {
|
||||
export_proto_headers: true,
|
||||
type: "lite",
|
||||
|
|
|
@ -87,8 +87,11 @@ interface ICameraDeviceCallback {
|
|||
* ERROR_RESULT message.
|
||||
*
|
||||
* If an output buffer cannot be filled, its status field must be set to
|
||||
* STATUS_ERROR. In addition, notify() must be called with a ERROR_BUFFER
|
||||
* message.
|
||||
* STATUS_ERROR. In this case, notify() isn't required to be called with
|
||||
* an ERROR_BUFFER message. The framework will simply treat the notify()
|
||||
* call with ERROR_BUFFER as a no-op, and derive whether and when to notify
|
||||
* the application of buffer loss based on the buffer status and whether or not
|
||||
* the entire capture has failed.
|
||||
*
|
||||
* If the entire capture has failed, then this method still needs to be
|
||||
* called to return the output buffers to the framework. All the buffer
|
||||
|
|
|
@ -588,7 +588,7 @@ c3ec182ce325862b7d79e526f3e170c02cfee1497ed309d7c60d0de4ca636b0b android.hardwar
|
|||
578f640c653726d58f99c84a7e1bb63862e21ef7cbb4f7d95c3cc62de00dca35 android.hardware.automotive.evs@1.0::IEvsDisplay
|
||||
f5bc6aa840db933cb9fd36668b06d3e2021cf5384bb70e459f22e2f2f921fba5 android.hardware.automotive.evs@1.0::IEvsEnumerator
|
||||
d3a344b7bd4c0d2658ae7209f55a979b8f53f361fd00f4fca29d5baa56d11fd2 android.hardware.automotive.evs@1.0::types
|
||||
d123013165a19b6353cdc46a57b2ff4a17179619d36dbd595dfcf15dcd099af6 android.hardware.camera.device@3.2::ICameraDeviceCallback # b/155353799
|
||||
2924c3e43858190ee3e2da4c2fb93bba8ae065fe314451f035a7ec52cb80c94a android.hardware.camera.device@3.2::ICameraDeviceCallback # b/155353799
|
||||
2410dd02d67786a732d36e80b0f8ccf55086604ef37f9838e2013ff2c571e404 android.hardware.camera.device@3.5::types
|
||||
cd06a7911b9acd4a653bbf7133888878fbcb3f84be177c7a3f1becaae3d8618f android.hardware.camera.metadata@3.2::types
|
||||
5cf81b1001296fbb3c5b3d275a859244f61cec5fa858d7be9cca46c5b7dfa733 android.hardware.camera.metadata@3.2::types # b/150331548
|
||||
|
|
|
@ -14,19 +14,19 @@ cc_test {
|
|||
"ReaderAuthTests.cpp",
|
||||
],
|
||||
shared_libs: [
|
||||
"android.hardware.keymaster@4.0",
|
||||
"libbinder",
|
||||
"libcrypto",
|
||||
"android.hardware.keymaster-ndk_platform",
|
||||
],
|
||||
static_libs: [
|
||||
"libcppbor",
|
||||
"libkeymaster_portable",
|
||||
"libsoft_attestation_cert",
|
||||
"libpuresoftkeymasterdevice",
|
||||
"android.hardware.keymaster@4.0",
|
||||
"android.hardware.identity-support-lib",
|
||||
"android.hardware.identity-cpp",
|
||||
"android.hardware.keymaster-cpp",
|
||||
"android.hardware.keymaster-ndk_platform",
|
||||
],
|
||||
test_suites: [
|
||||
"general-tests",
|
||||
|
|
|
@ -33,6 +33,7 @@ using ::std::optional;
|
|||
using ::std::string;
|
||||
using ::std::tuple;
|
||||
using ::std::vector;
|
||||
using ::std::pair;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Miscellaneous utilities.
|
||||
|
@ -119,6 +120,12 @@ optional<vector<uint8_t>> encryptAes128Gcm(const vector<uint8_t>& key, const vec
|
|||
optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> createEcKeyPairAndAttestation(
|
||||
const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId);
|
||||
|
||||
// Like createEcKeyPairAndAttestation() but allows you to choose the public key.
|
||||
//
|
||||
optional<vector<vector<uint8_t>>> createAttestationForEcPublicKey(
|
||||
const vector<uint8_t>& publicKey, const vector<uint8_t>& challenge,
|
||||
const vector<uint8_t>& applicationId);
|
||||
|
||||
// Creates an 256-bit EC key using the NID_X9_62_prime256v1 curve, returns the
|
||||
// PKCS#8 encoded key-pair.
|
||||
//
|
||||
|
@ -155,6 +162,12 @@ optional<vector<uint8_t>> ecKeyPairGetPkcs12(const vector<uint8_t>& keyPair, con
|
|||
//
|
||||
optional<vector<uint8_t>> signEcDsa(const vector<uint8_t>& key, const vector<uint8_t>& data);
|
||||
|
||||
// Like signEcDsa() but instead of taking the data to be signed, takes a digest
|
||||
// of it instead.
|
||||
//
|
||||
optional<vector<uint8_t>> signEcDsaDigest(const vector<uint8_t>& key,
|
||||
const vector<uint8_t>& dataDigest);
|
||||
|
||||
// Calculates the HMAC with SHA-256 for |data| using |key|. The calculated HMAC
|
||||
// is returned and will be 32 bytes.
|
||||
//
|
||||
|
@ -175,6 +188,27 @@ bool checkEcDsaSignature(const vector<uint8_t>& digest, const vector<uint8_t>& s
|
|||
//
|
||||
optional<vector<uint8_t>> certificateChainGetTopMostKey(const vector<uint8_t>& certificateChain);
|
||||
|
||||
// Extracts the public-key from the top-most certificate in |certificateChain|
|
||||
// (which should be a concatenated chain of DER-encoded X.509 certificates).
|
||||
//
|
||||
// Return offset and size of the public-key
|
||||
//
|
||||
optional<pair<size_t, size_t>> certificateFindPublicKey(const vector<uint8_t>& x509Certificate);
|
||||
|
||||
// Extracts the TbsCertificate from the top-most certificate in |certificateChain|
|
||||
// (which should be a concatenated chain of DER-encoded X.509 certificates).
|
||||
//
|
||||
// Return offset and size of the TbsCertificate
|
||||
//
|
||||
optional<pair<size_t, size_t>> certificateTbsCertificate(const vector<uint8_t>& x509Certificate);
|
||||
|
||||
// Extracts the Signature from the top-most certificate in |certificateChain|
|
||||
// (which should be a concatenated chain of DER-encoded X.509 certificates).
|
||||
//
|
||||
// Return offset and size of the Signature
|
||||
//
|
||||
optional<pair<size_t, size_t>> certificateFindSignature(const vector<uint8_t>& x509Certificate);
|
||||
|
||||
// Generates a X.509 certificate for |publicKey| (which must be in the format
|
||||
// returned by ecKeyPairGetPublicKey()).
|
||||
//
|
||||
|
@ -231,6 +265,11 @@ optional<vector<vector<uint8_t>>> certificateChainSplit(const vector<uint8_t>& c
|
|||
//
|
||||
bool certificateChainValidate(const vector<uint8_t>& certificateChain);
|
||||
|
||||
// Returns true if |certificate| is signed by |publicKey|.
|
||||
//
|
||||
bool certificateSignedByPublicKey(const vector<uint8_t>& certificate,
|
||||
const vector<uint8_t>& publicKey);
|
||||
|
||||
// Signs |data| and |detachedContent| with |key| (which must be in the format
|
||||
// returned by ecKeyPairGetPrivateKey()).
|
||||
//
|
||||
|
@ -243,6 +282,21 @@ optional<vector<uint8_t>> coseSignEcDsa(const vector<uint8_t>& key, const vector
|
|||
const vector<uint8_t>& detachedContent,
|
||||
const vector<uint8_t>& certificateChain);
|
||||
|
||||
// Creates a COSE_Signature1 where |signatureToBeSigned| is the ECDSA signature
|
||||
// of the ToBeSigned CBOR from RFC 8051 "4.4. Signing and Verification Process".
|
||||
//
|
||||
// The |signatureToBeSigned| is expected to be 64 bytes and contain the R value,
|
||||
// then the S value.
|
||||
//
|
||||
// The |data| parameter will be included in the COSE_Sign1 CBOR.
|
||||
//
|
||||
// If |certificateChain| is non-empty it's included in the 'x5chain'
|
||||
// protected header element (as as described in'draft-ietf-cose-x509-04').
|
||||
//
|
||||
optional<vector<uint8_t>> coseSignEcDsaWithSignature(const vector<uint8_t>& signatureToBeSigned,
|
||||
const vector<uint8_t>& data,
|
||||
const vector<uint8_t>& certificateChain);
|
||||
|
||||
// Checks that |signatureCoseSign1| (in COSE_Sign1 format) is a valid signature
|
||||
// made with |public_key| (which must be in the format returned by
|
||||
// ecKeyPairGetPublicKey()) where |detachedContent| is the detached content.
|
||||
|
@ -251,9 +305,23 @@ bool coseCheckEcDsaSignature(const vector<uint8_t>& signatureCoseSign1,
|
|||
const vector<uint8_t>& detachedContent,
|
||||
const vector<uint8_t>& publicKey);
|
||||
|
||||
// Converts a DER-encoded signature to the format used in 'signature' bstr in COSE_Sign1.
|
||||
bool ecdsaSignatureDerToCose(const vector<uint8_t>& ecdsaDerSignature,
|
||||
vector<uint8_t>& ecdsaCoseSignature);
|
||||
|
||||
// Converts from the format in in 'signature' bstr in COSE_Sign1 to DER encoding.
|
||||
bool ecdsaSignatureCoseToDer(const vector<uint8_t>& ecdsaCoseSignature,
|
||||
vector<uint8_t>& ecdsaDerSignature);
|
||||
|
||||
// Extracts the payload from a COSE_Sign1.
|
||||
optional<vector<uint8_t>> coseSignGetPayload(const vector<uint8_t>& signatureCoseSign1);
|
||||
|
||||
// Extracts the signature (of the ToBeSigned CBOR) from a COSE_Sign1.
|
||||
optional<vector<uint8_t>> coseSignGetSignature(const vector<uint8_t>& signatureCoseSign1);
|
||||
|
||||
// Extracts the signature algorithm from a COSE_Sign1.
|
||||
optional<int> coseSignGetAlg(const vector<uint8_t>& signatureCoseSign1);
|
||||
|
||||
// Extracts the X.509 certificate chain, if present. Returns the data as a
|
||||
// concatenated chain of DER-encoded X.509 certificates
|
||||
//
|
||||
|
@ -269,6 +337,16 @@ optional<vector<uint8_t>> coseSignGetX5Chain(const vector<uint8_t>& signatureCos
|
|||
optional<vector<uint8_t>> coseMac0(const vector<uint8_t>& key, const vector<uint8_t>& data,
|
||||
const vector<uint8_t>& detachedContent);
|
||||
|
||||
// Creates a COSE_Mac0 where |digestToBeMaced| is the HMAC-SHA256
|
||||
// of the ToBeMaced CBOR from RFC 8051 "6.3. How to Compute and Verify a MAC".
|
||||
//
|
||||
// The |digestToBeMaced| is expected to be 32 bytes.
|
||||
//
|
||||
// The |data| parameter will be included in the COSE_Mac0 CBOR.
|
||||
//
|
||||
optional<vector<uint8_t>> coseMacWithDigest(const vector<uint8_t>& digestToBeMaced,
|
||||
const vector<uint8_t>& data);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Utility functions specific to IdentityCredential.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <chrono>
|
||||
#include <iomanip>
|
||||
|
||||
#include <openssl/aes.h>
|
||||
|
@ -684,6 +685,48 @@ static bool parseX509Certificates(const vector<uint8_t>& certificateChain,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool certificateSignedByPublicKey(const vector<uint8_t>& certificate,
|
||||
const vector<uint8_t>& publicKey) {
|
||||
const unsigned char* p = certificate.data();
|
||||
auto x509 = X509_Ptr(d2i_X509(nullptr, &p, certificate.size()));
|
||||
if (x509 == nullptr) {
|
||||
LOG(ERROR) << "Error parsing X509 certificate";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
|
||||
auto point = EC_POINT_Ptr(EC_POINT_new(group.get()));
|
||||
if (EC_POINT_oct2point(group.get(), point.get(), publicKey.data(), publicKey.size(), nullptr) !=
|
||||
1) {
|
||||
LOG(ERROR) << "Error decoding publicKey";
|
||||
return false;
|
||||
}
|
||||
auto ecKey = EC_KEY_Ptr(EC_KEY_new());
|
||||
auto pkey = EVP_PKEY_Ptr(EVP_PKEY_new());
|
||||
if (ecKey.get() == nullptr || pkey.get() == nullptr) {
|
||||
LOG(ERROR) << "Memory allocation failed";
|
||||
return false;
|
||||
}
|
||||
if (EC_KEY_set_group(ecKey.get(), group.get()) != 1) {
|
||||
LOG(ERROR) << "Error setting group";
|
||||
return false;
|
||||
}
|
||||
if (EC_KEY_set_public_key(ecKey.get(), point.get()) != 1) {
|
||||
LOG(ERROR) << "Error setting point";
|
||||
return false;
|
||||
}
|
||||
if (EVP_PKEY_set1_EC_KEY(pkey.get(), ecKey.get()) != 1) {
|
||||
LOG(ERROR) << "Error setting key";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (X509_verify(x509.get(), pkey.get()) != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: Right now the only check we perform is to check that each certificate
|
||||
// is signed by its successor. We should - but currently don't - also check
|
||||
// things like valid dates etc.
|
||||
|
@ -770,7 +813,8 @@ vector<uint8_t> sha256(const vector<uint8_t>& data) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
optional<vector<uint8_t>> signEcDsa(const vector<uint8_t>& key, const vector<uint8_t>& data) {
|
||||
optional<vector<uint8_t>> signEcDsaDigest(const vector<uint8_t>& key,
|
||||
const vector<uint8_t>& dataDigest) {
|
||||
auto bn = BIGNUM_Ptr(BN_bin2bn(key.data(), key.size(), nullptr));
|
||||
if (bn.get() == nullptr) {
|
||||
LOG(ERROR) << "Error creating BIGNUM";
|
||||
|
@ -783,8 +827,7 @@ optional<vector<uint8_t>> signEcDsa(const vector<uint8_t>& key, const vector<uin
|
|||
return {};
|
||||
}
|
||||
|
||||
auto digest = sha256(data);
|
||||
ECDSA_SIG* sig = ECDSA_do_sign(digest.data(), digest.size(), ec_key.get());
|
||||
ECDSA_SIG* sig = ECDSA_do_sign(dataDigest.data(), dataDigest.size(), ec_key.get());
|
||||
if (sig == nullptr) {
|
||||
LOG(ERROR) << "Error signing digest";
|
||||
return {};
|
||||
|
@ -798,6 +841,10 @@ optional<vector<uint8_t>> signEcDsa(const vector<uint8_t>& key, const vector<uin
|
|||
return signature;
|
||||
}
|
||||
|
||||
optional<vector<uint8_t>> signEcDsa(const vector<uint8_t>& key, const vector<uint8_t>& data) {
|
||||
return signEcDsaDigest(key, sha256(data));
|
||||
}
|
||||
|
||||
optional<vector<uint8_t>> hmacSha256(const vector<uint8_t>& key, const vector<uint8_t>& data) {
|
||||
HMAC_CTX ctx;
|
||||
HMAC_CTX_init(&ctx);
|
||||
|
@ -955,6 +1002,51 @@ optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> createEcKeyPairAnd
|
|||
return make_pair(keyPair, attestationCert.value());
|
||||
}
|
||||
|
||||
optional<vector<vector<uint8_t>>> createAttestationForEcPublicKey(
|
||||
const vector<uint8_t>& publicKey, const vector<uint8_t>& challenge,
|
||||
const vector<uint8_t>& applicationId) {
|
||||
auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
|
||||
auto point = EC_POINT_Ptr(EC_POINT_new(group.get()));
|
||||
if (EC_POINT_oct2point(group.get(), point.get(), publicKey.data(), publicKey.size(), nullptr) !=
|
||||
1) {
|
||||
LOG(ERROR) << "Error decoding publicKey";
|
||||
return {};
|
||||
}
|
||||
auto ecKey = EC_KEY_Ptr(EC_KEY_new());
|
||||
auto pkey = EVP_PKEY_Ptr(EVP_PKEY_new());
|
||||
if (ecKey.get() == nullptr || pkey.get() == nullptr) {
|
||||
LOG(ERROR) << "Memory allocation failed";
|
||||
return {};
|
||||
}
|
||||
if (EC_KEY_set_group(ecKey.get(), group.get()) != 1) {
|
||||
LOG(ERROR) << "Error setting group";
|
||||
return {};
|
||||
}
|
||||
if (EC_KEY_set_public_key(ecKey.get(), point.get()) != 1) {
|
||||
LOG(ERROR) << "Error setting point";
|
||||
return {};
|
||||
}
|
||||
if (EVP_PKEY_set1_EC_KEY(pkey.get(), ecKey.get()) != 1) {
|
||||
LOG(ERROR) << "Error setting key";
|
||||
return {};
|
||||
}
|
||||
|
||||
uint64_t now = (std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch()).
|
||||
count()/ 1000000000);
|
||||
uint64_t secondsInOneYear = 365 * 24 * 60 * 60;
|
||||
uint64_t expireTimeMs = (now + secondsInOneYear) * 1000;
|
||||
|
||||
optional<vector<vector<uint8_t>>> attestationCert =
|
||||
createAttestation(pkey.get(), applicationId, challenge, now * 1000, expireTimeMs);
|
||||
if (!attestationCert) {
|
||||
LOG(ERROR) << "Error create attestation from key and challenge";
|
||||
return {};
|
||||
}
|
||||
|
||||
return attestationCert.value();
|
||||
}
|
||||
|
||||
optional<vector<uint8_t>> createEcKeyPair() {
|
||||
auto ec_key = EC_KEY_Ptr(EC_KEY_new());
|
||||
auto pkey = EVP_PKEY_Ptr(EVP_PKEY_new());
|
||||
|
@ -1477,6 +1569,120 @@ optional<vector<uint8_t>> certificateChainGetTopMostKey(const vector<uint8_t>& c
|
|||
return publicKey;
|
||||
}
|
||||
|
||||
optional<pair<size_t, size_t>> certificateFindPublicKey(const vector<uint8_t>& x509Certificate) {
|
||||
vector<X509_Ptr> certs;
|
||||
if (!parseX509Certificates(x509Certificate, certs)) {
|
||||
return {};
|
||||
}
|
||||
if (certs.size() < 1) {
|
||||
LOG(ERROR) << "No certificates in chain";
|
||||
return {};
|
||||
}
|
||||
|
||||
auto pkey = EVP_PKEY_Ptr(X509_get_pubkey(certs[0].get()));
|
||||
if (pkey.get() == nullptr) {
|
||||
LOG(ERROR) << "No public key";
|
||||
return {};
|
||||
}
|
||||
|
||||
auto ecKey = EC_KEY_Ptr(EVP_PKEY_get1_EC_KEY(pkey.get()));
|
||||
if (ecKey.get() == nullptr) {
|
||||
LOG(ERROR) << "Failed getting EC key";
|
||||
return {};
|
||||
}
|
||||
|
||||
auto ecGroup = EC_KEY_get0_group(ecKey.get());
|
||||
auto ecPoint = EC_KEY_get0_public_key(ecKey.get());
|
||||
int size = EC_POINT_point2oct(ecGroup, ecPoint, POINT_CONVERSION_UNCOMPRESSED, nullptr, 0,
|
||||
nullptr);
|
||||
if (size == 0) {
|
||||
LOG(ERROR) << "Error generating public key encoding";
|
||||
return {};
|
||||
}
|
||||
vector<uint8_t> publicKey;
|
||||
publicKey.resize(size);
|
||||
EC_POINT_point2oct(ecGroup, ecPoint, POINT_CONVERSION_UNCOMPRESSED, publicKey.data(),
|
||||
publicKey.size(), nullptr);
|
||||
|
||||
size_t publicKeyOffset = 0;
|
||||
size_t publicKeySize = (size_t)size;
|
||||
void* location = memmem((const void*)x509Certificate.data(), x509Certificate.size(),
|
||||
(const void*)publicKey.data(), publicKey.size());
|
||||
|
||||
if (location == NULL) {
|
||||
LOG(ERROR) << "Error finding publicKey from x509Certificate";
|
||||
return {};
|
||||
}
|
||||
publicKeyOffset = (size_t)((const char*)location - (const char*)x509Certificate.data());
|
||||
|
||||
return std::make_pair(publicKeyOffset, publicKeySize);
|
||||
}
|
||||
|
||||
optional<pair<size_t, size_t>> certificateTbsCertificate(const vector<uint8_t>& x509Certificate) {
|
||||
vector<X509_Ptr> certs;
|
||||
if (!parseX509Certificates(x509Certificate, certs)) {
|
||||
return {};
|
||||
}
|
||||
if (certs.size() < 1) {
|
||||
LOG(ERROR) << "No certificates in chain";
|
||||
return {};
|
||||
}
|
||||
|
||||
unsigned char* buf = NULL;
|
||||
int len = i2d_re_X509_tbs(certs[0].get(), &buf);
|
||||
if ((len < 0) || (buf == NULL)) {
|
||||
LOG(ERROR) << "fail to extract tbsCertificate in x509Certificate";
|
||||
return {};
|
||||
}
|
||||
|
||||
vector<uint8_t> tbsCertificate(len);
|
||||
memcpy(tbsCertificate.data(), buf, len);
|
||||
|
||||
size_t tbsCertificateOffset = 0;
|
||||
size_t tbsCertificateSize = (size_t)len;
|
||||
void* location = memmem((const void*)x509Certificate.data(), x509Certificate.size(),
|
||||
(const void*)tbsCertificate.data(), tbsCertificate.size());
|
||||
|
||||
if (location == NULL) {
|
||||
LOG(ERROR) << "Error finding tbsCertificate from x509Certificate";
|
||||
return {};
|
||||
}
|
||||
tbsCertificateOffset = (size_t)((const char*)location - (const char*)x509Certificate.data());
|
||||
|
||||
return std::make_pair(tbsCertificateOffset, tbsCertificateSize);
|
||||
}
|
||||
|
||||
optional<pair<size_t, size_t>> certificateFindSignature(const vector<uint8_t>& x509Certificate) {
|
||||
vector<X509_Ptr> certs;
|
||||
if (!parseX509Certificates(x509Certificate, certs)) {
|
||||
return {};
|
||||
}
|
||||
if (certs.size() < 1) {
|
||||
LOG(ERROR) << "No certificates in chain";
|
||||
return {};
|
||||
}
|
||||
|
||||
ASN1_BIT_STRING* psig;
|
||||
X509_ALGOR* palg;
|
||||
X509_get0_signature((const ASN1_BIT_STRING**)&psig, (const X509_ALGOR**)&palg, certs[0].get());
|
||||
|
||||
vector<char> signature(psig->length);
|
||||
memcpy(signature.data(), psig->data, psig->length);
|
||||
|
||||
size_t signatureOffset = 0;
|
||||
size_t signatureSize = (size_t)psig->length;
|
||||
void* location = memmem((const void*)x509Certificate.data(), x509Certificate.size(),
|
||||
(const void*)signature.data(), signature.size());
|
||||
|
||||
if (location == NULL) {
|
||||
LOG(ERROR) << "Error finding signature from x509Certificate";
|
||||
return {};
|
||||
}
|
||||
signatureOffset = (size_t)((const char*)location - (const char*)x509Certificate.data());
|
||||
|
||||
return std::make_pair(signatureOffset, signatureSize);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// COSE Utility Functions
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -1574,6 +1780,55 @@ bool ecdsaSignatureDerToCose(const vector<uint8_t>& ecdsaDerSignature,
|
|||
return true;
|
||||
}
|
||||
|
||||
optional<vector<uint8_t>> coseSignEcDsaWithSignature(const vector<uint8_t>& signatureToBeSigned,
|
||||
const vector<uint8_t>& data,
|
||||
const vector<uint8_t>& certificateChain) {
|
||||
if (signatureToBeSigned.size() != 64) {
|
||||
LOG(ERROR) << "Invalid size for signatureToBeSigned, expected 64 got "
|
||||
<< signatureToBeSigned.size();
|
||||
return {};
|
||||
}
|
||||
|
||||
cppbor::Map unprotectedHeaders;
|
||||
cppbor::Map protectedHeaders;
|
||||
|
||||
protectedHeaders.add(COSE_LABEL_ALG, COSE_ALG_ECDSA_256);
|
||||
|
||||
if (certificateChain.size() != 0) {
|
||||
optional<vector<vector<uint8_t>>> certs = support::certificateChainSplit(certificateChain);
|
||||
if (!certs) {
|
||||
LOG(ERROR) << "Error splitting certificate chain";
|
||||
return {};
|
||||
}
|
||||
if (certs.value().size() == 1) {
|
||||
unprotectedHeaders.add(COSE_LABEL_X5CHAIN, certs.value()[0]);
|
||||
} else {
|
||||
cppbor::Array certArray;
|
||||
for (const vector<uint8_t>& cert : certs.value()) {
|
||||
certArray.add(cert);
|
||||
}
|
||||
unprotectedHeaders.add(COSE_LABEL_X5CHAIN, std::move(certArray));
|
||||
}
|
||||
}
|
||||
|
||||
vector<uint8_t> encodedProtectedHeaders = coseEncodeHeaders(protectedHeaders);
|
||||
|
||||
cppbor::Array coseSign1;
|
||||
coseSign1.add(encodedProtectedHeaders);
|
||||
coseSign1.add(std::move(unprotectedHeaders));
|
||||
if (data.size() == 0) {
|
||||
cppbor::Null nullValue;
|
||||
coseSign1.add(std::move(nullValue));
|
||||
} else {
|
||||
coseSign1.add(data);
|
||||
}
|
||||
coseSign1.add(signatureToBeSigned);
|
||||
vector<uint8_t> signatureCoseSign1;
|
||||
signatureCoseSign1 = coseSign1.encode();
|
||||
|
||||
return signatureCoseSign1;
|
||||
}
|
||||
|
||||
optional<vector<uint8_t>> coseSignEcDsa(const vector<uint8_t>& key, const vector<uint8_t>& data,
|
||||
const vector<uint8_t>& detachedContent,
|
||||
const vector<uint8_t>& certificateChain) {
|
||||
|
@ -1709,6 +1964,35 @@ bool coseCheckEcDsaSignature(const vector<uint8_t>& signatureCoseSign1,
|
|||
return true;
|
||||
}
|
||||
|
||||
// Extracts the signature (of the ToBeSigned CBOR) from a COSE_Sign1.
|
||||
optional<vector<uint8_t>> coseSignGetSignature(const vector<uint8_t>& signatureCoseSign1) {
|
||||
auto [item, _, message] = cppbor::parse(signatureCoseSign1);
|
||||
if (item == nullptr) {
|
||||
LOG(ERROR) << "Passed-in COSE_Sign1 is not valid CBOR: " << message;
|
||||
return {};
|
||||
}
|
||||
const cppbor::Array* array = item->asArray();
|
||||
if (array == nullptr) {
|
||||
LOG(ERROR) << "Value for COSE_Sign1 is not an array";
|
||||
return {};
|
||||
}
|
||||
if (array->size() != 4) {
|
||||
LOG(ERROR) << "Value for COSE_Sign1 is not an array of size 4";
|
||||
return {};
|
||||
}
|
||||
|
||||
vector<uint8_t> signature;
|
||||
const cppbor::Bstr* signatureAsBstr = (*array)[3]->asBstr();
|
||||
if (signatureAsBstr == nullptr) {
|
||||
LOG(ERROR) << "Value for signature is not a bstr";
|
||||
return {};
|
||||
}
|
||||
// Copy payload into |data|
|
||||
signature = signatureAsBstr->value();
|
||||
|
||||
return signature;
|
||||
}
|
||||
|
||||
optional<vector<uint8_t>> coseSignGetPayload(const vector<uint8_t>& signatureCoseSign1) {
|
||||
auto [item, _, message] = cppbor::parse(signatureCoseSign1);
|
||||
if (item == nullptr) {
|
||||
|
@ -1746,6 +2030,59 @@ optional<vector<uint8_t>> coseSignGetPayload(const vector<uint8_t>& signatureCos
|
|||
return data;
|
||||
}
|
||||
|
||||
optional<int> coseSignGetAlg(const vector<uint8_t>& signatureCoseSign1) {
|
||||
auto [item, _, message] = cppbor::parse(signatureCoseSign1);
|
||||
if (item == nullptr) {
|
||||
LOG(ERROR) << "Passed-in COSE_Sign1 is not valid CBOR: " << message;
|
||||
return {};
|
||||
}
|
||||
const cppbor::Array* array = item->asArray();
|
||||
if (array == nullptr) {
|
||||
LOG(ERROR) << "Value for COSE_Sign1 is not an array";
|
||||
return {};
|
||||
}
|
||||
if (array->size() != 4) {
|
||||
LOG(ERROR) << "Value for COSE_Sign1 is not an array of size 4";
|
||||
return {};
|
||||
}
|
||||
|
||||
const cppbor::Bstr* protectedHeadersBytes = (*array)[0]->asBstr();
|
||||
if (protectedHeadersBytes == nullptr) {
|
||||
LOG(ERROR) << "Value for protectedHeaders is not a bstr";
|
||||
return {};
|
||||
}
|
||||
auto [item2, _2, message2] = cppbor::parse(protectedHeadersBytes->value());
|
||||
if (item2 == nullptr) {
|
||||
LOG(ERROR) << "Error parsing protectedHeaders: " << message2;
|
||||
return {};
|
||||
}
|
||||
const cppbor::Map* protectedHeaders = item2->asMap();
|
||||
if (protectedHeaders == nullptr) {
|
||||
LOG(ERROR) << "Decoded CBOR for protectedHeaders is not a map";
|
||||
return {};
|
||||
}
|
||||
|
||||
for (size_t n = 0; n < protectedHeaders->size(); n++) {
|
||||
auto [keyItem, valueItem] = (*protectedHeaders)[n];
|
||||
const cppbor::Int* number = keyItem->asInt();
|
||||
if (number == nullptr) {
|
||||
LOG(ERROR) << "Key item in top-level map is not a number";
|
||||
return {};
|
||||
}
|
||||
int label = number->value();
|
||||
if (label == COSE_LABEL_ALG) {
|
||||
const cppbor::Int* number = valueItem->asInt();
|
||||
if (number != nullptr) {
|
||||
return number->value();
|
||||
}
|
||||
LOG(ERROR) << "Value for COSE_LABEL_ALG label is not a number";
|
||||
return {};
|
||||
}
|
||||
}
|
||||
LOG(ERROR) << "Did not find COSE_LABEL_ALG label in protected headers";
|
||||
return {};
|
||||
}
|
||||
|
||||
optional<vector<uint8_t>> coseSignGetX5Chain(const vector<uint8_t>& signatureCoseSign1) {
|
||||
auto [item, _, message] = cppbor::parse(signatureCoseSign1);
|
||||
if (item == nullptr) {
|
||||
|
@ -1861,6 +2198,28 @@ optional<vector<uint8_t>> coseMac0(const vector<uint8_t>& key, const vector<uint
|
|||
return array.encode();
|
||||
}
|
||||
|
||||
optional<vector<uint8_t>> coseMacWithDigest(const vector<uint8_t>& digestToBeMaced,
|
||||
const vector<uint8_t>& data) {
|
||||
cppbor::Map unprotectedHeaders;
|
||||
cppbor::Map protectedHeaders;
|
||||
|
||||
protectedHeaders.add(COSE_LABEL_ALG, COSE_ALG_HMAC_256_256);
|
||||
|
||||
vector<uint8_t> encodedProtectedHeaders = coseEncodeHeaders(protectedHeaders);
|
||||
|
||||
cppbor::Array array;
|
||||
array.add(encodedProtectedHeaders);
|
||||
array.add(std::move(unprotectedHeaders));
|
||||
if (data.size() == 0) {
|
||||
cppbor::Null nullValue;
|
||||
array.add(std::move(nullValue));
|
||||
} else {
|
||||
array.add(data);
|
||||
}
|
||||
array.add(digestToBeMaced);
|
||||
return array.encode();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Utility functions specific to IdentityCredential.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
Loading…
Reference in a new issue