mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 11:36:00 +00:00
Merge "Identity: Update for changes to ISO 18013-5." am: 84a6118710
Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/1344923 Change-Id: I388758629a0edbe6f1d531df8a974e95b18791c4
This commit is contained in:
@@ -151,8 +151,8 @@ interface IIdentityCredential {
|
|||||||
* IntentToRetain = bool
|
* IntentToRetain = bool
|
||||||
*
|
*
|
||||||
* For the readerSignature parameter, this can either be empty or if non-empty it
|
* For the readerSignature parameter, this can either be empty or if non-empty it
|
||||||
* must be a COSE_Sign1 structure with an ECDSA signature over the content of the
|
* must be a COSE_Sign1 where the payload is the bytes of the
|
||||||
* CBOR conforming to the following CDDL:
|
* ReaderAuthenticationBytes CBOR defined below:
|
||||||
*
|
*
|
||||||
* ReaderAuthentication = [
|
* ReaderAuthentication = [
|
||||||
* "ReaderAuthentication",
|
* "ReaderAuthentication",
|
||||||
@@ -164,6 +164,8 @@ interface IIdentityCredential {
|
|||||||
*
|
*
|
||||||
* ItemsRequestBytes = #6.24(bstr .cbor ItemsRequest)
|
* ItemsRequestBytes = #6.24(bstr .cbor ItemsRequest)
|
||||||
*
|
*
|
||||||
|
* ReaderAuthenticationBytes = #6.24(bstr .cbor ReaderAuthentication)
|
||||||
|
*
|
||||||
* The public key corresponding to the key used to made signature, can be found in the
|
* The public key corresponding to the key used to made signature, can be found in the
|
||||||
* 'x5chain' unprotected header element of the COSE_Sign1 structure (as as described
|
* 'x5chain' unprotected header element of the COSE_Sign1 structure (as as described
|
||||||
* in 'draft-ietf-cose-x509-04'). There will be at least one certificate in said element
|
* in 'draft-ietf-cose-x509-04'). There will be at least one certificate in said element
|
||||||
@@ -278,7 +280,7 @@ interface IIdentityCredential {
|
|||||||
*
|
*
|
||||||
* @param out mac is empty if signingKeyBlob or the sessionTranscript passed to
|
* @param out mac is empty if signingKeyBlob or the sessionTranscript passed to
|
||||||
* startRetrieval() is empty. Otherwise it is a COSE_Mac0 with empty payload
|
* startRetrieval() is empty. Otherwise it is a COSE_Mac0 with empty payload
|
||||||
* and the detached content is set to DeviceAuthentication as defined below.
|
* and the detached content is set to DeviceAuthenticationBytes as defined below.
|
||||||
* This code is produced by using the key agreement and key derivation function
|
* This code is produced by using the key agreement and key derivation function
|
||||||
* from the ciphersuite with the authentication private key and the reader
|
* from the ciphersuite with the authentication private key and the reader
|
||||||
* ephemeral public key to compute a shared message authentication code (MAC)
|
* ephemeral public key to compute a shared message authentication code (MAC)
|
||||||
@@ -299,6 +301,8 @@ interface IIdentityCredential {
|
|||||||
*
|
*
|
||||||
* DeviceNameSpacesBytes = #6.24(bstr .cbor DeviceNameSpaces)
|
* DeviceNameSpacesBytes = #6.24(bstr .cbor DeviceNameSpaces)
|
||||||
*
|
*
|
||||||
|
* DeviceAuthenticationBytes = #6.24(bstr .cbor DeviceAuthentication)
|
||||||
|
*
|
||||||
* where
|
* where
|
||||||
*
|
*
|
||||||
* DeviceNameSpaces = {
|
* DeviceNameSpaces = {
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ import android.hardware.identity.CipherSuite;
|
|||||||
* Various fields need to be encoded as precisely-specified byte arrays. Where existing standards
|
* Various fields need to be encoded as precisely-specified byte arrays. Where existing standards
|
||||||
* define appropriate encodings, those are used. For example, X.509 certificates. Where new
|
* define appropriate encodings, those are used. For example, X.509 certificates. Where new
|
||||||
* encodings are needed, CBOR is used. CBOR maps are described in CDDL notation
|
* encodings are needed, CBOR is used. CBOR maps are described in CDDL notation
|
||||||
* (https://tools.ietf.org/html/draft-ietf-cbor-cddl-06).
|
* (https://tools.ietf.org/html/rfc8610).
|
||||||
*
|
*
|
||||||
* All binder calls in the HAL may return a ServiceSpecificException with statuses from the
|
* All binder calls in the HAL may return a ServiceSpecificException with statuses from the
|
||||||
* STATUS_* integers defined in this interface. Each method states which status can be returned
|
* STATUS_* integers defined in this interface. Each method states which status can be returned
|
||||||
|
|||||||
@@ -39,6 +39,10 @@ using ::std::optional;
|
|||||||
using namespace ::android::hardware::identity;
|
using namespace ::android::hardware::identity;
|
||||||
|
|
||||||
int IdentityCredential::initialize() {
|
int IdentityCredential::initialize() {
|
||||||
|
if (credentialData_.size() == 0) {
|
||||||
|
LOG(ERROR) << "CredentialData is empty";
|
||||||
|
return IIdentityCredentialStore::STATUS_INVALID_DATA;
|
||||||
|
}
|
||||||
auto [item, _, message] = cppbor::parse(credentialData_);
|
auto [item, _, message] = cppbor::parse(credentialData_);
|
||||||
if (item == nullptr) {
|
if (item == nullptr) {
|
||||||
LOG(ERROR) << "CredentialData is not valid CBOR: " << message;
|
LOG(ERROR) << "CredentialData is not valid CBOR: " << message;
|
||||||
@@ -312,13 +316,16 @@ ndk::ScopedAStatus IdentityCredential::startRetrieval(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const vector<uint8_t>& itemsRequestBytes = itemsRequest;
|
const vector<uint8_t>& itemsRequestBytes = itemsRequest;
|
||||||
vector<uint8_t> dataThatWasSigned = cppbor::Array()
|
vector<uint8_t> encodedReaderAuthentication =
|
||||||
.add("ReaderAuthentication")
|
cppbor::Array()
|
||||||
.add(sessionTranscriptItem_->clone())
|
.add("ReaderAuthentication")
|
||||||
.add(cppbor::Semantic(24, itemsRequestBytes))
|
.add(sessionTranscriptItem_->clone())
|
||||||
.encode();
|
.add(cppbor::Semantic(24, itemsRequestBytes))
|
||||||
|
.encode();
|
||||||
|
vector<uint8_t> encodedReaderAuthenticationBytes =
|
||||||
|
cppbor::Semantic(24, encodedReaderAuthentication).encode();
|
||||||
if (!support::coseCheckEcDsaSignature(readerSignature,
|
if (!support::coseCheckEcDsaSignature(readerSignature,
|
||||||
dataThatWasSigned, // detached content
|
encodedReaderAuthenticationBytes, // detached content
|
||||||
readerPublicKey.value())) {
|
readerPublicKey.value())) {
|
||||||
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
|
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
|
||||||
IIdentityCredentialStore::STATUS_READER_SIGNATURE_CHECK_FAILED,
|
IIdentityCredentialStore::STATUS_READER_SIGNATURE_CHECK_FAILED,
|
||||||
@@ -774,7 +781,7 @@ ndk::ScopedAStatus IdentityCredential::finishRetrieval(vector<uint8_t>* outMac,
|
|||||||
array.add(sessionTranscriptItem_->clone());
|
array.add(sessionTranscriptItem_->clone());
|
||||||
array.add(docType_);
|
array.add(docType_);
|
||||||
array.add(cppbor::Semantic(24, encodedDeviceNameSpaces));
|
array.add(cppbor::Semantic(24, encodedDeviceNameSpaces));
|
||||||
vector<uint8_t> encodedDeviceAuthentication = array.encode();
|
vector<uint8_t> deviceAuthenticationBytes = cppbor::Semantic(24, array.encode()).encode();
|
||||||
|
|
||||||
vector<uint8_t> docTypeAsBlob(docType_.begin(), docType_.end());
|
vector<uint8_t> docTypeAsBlob(docType_.begin(), docType_.end());
|
||||||
optional<vector<uint8_t>> signingKey =
|
optional<vector<uint8_t>> signingKey =
|
||||||
@@ -792,17 +799,24 @@ ndk::ScopedAStatus IdentityCredential::finishRetrieval(vector<uint8_t>* outMac,
|
|||||||
IIdentityCredentialStore::STATUS_FAILED, "Error doing ECDH"));
|
IIdentityCredentialStore::STATUS_FAILED, "Error doing ECDH"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mix-in SessionTranscriptBytes
|
||||||
|
vector<uint8_t> sessionTranscriptBytes = cppbor::Semantic(24, sessionTranscript_).encode();
|
||||||
|
vector<uint8_t> sharedSecretWithSessionTranscriptBytes = sharedSecret.value();
|
||||||
|
std::copy(sessionTranscriptBytes.begin(), sessionTranscriptBytes.end(),
|
||||||
|
std::back_inserter(sharedSecretWithSessionTranscriptBytes));
|
||||||
|
|
||||||
vector<uint8_t> salt = {0x00};
|
vector<uint8_t> salt = {0x00};
|
||||||
vector<uint8_t> info = {};
|
vector<uint8_t> info = {};
|
||||||
optional<vector<uint8_t>> derivedKey = support::hkdf(sharedSecret.value(), salt, info, 32);
|
optional<vector<uint8_t>> derivedKey =
|
||||||
|
support::hkdf(sharedSecretWithSessionTranscriptBytes, salt, info, 32);
|
||||||
if (!derivedKey) {
|
if (!derivedKey) {
|
||||||
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
|
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
|
||||||
IIdentityCredentialStore::STATUS_FAILED,
|
IIdentityCredentialStore::STATUS_FAILED,
|
||||||
"Error deriving key from shared secret"));
|
"Error deriving key from shared secret"));
|
||||||
}
|
}
|
||||||
|
|
||||||
mac = support::coseMac0(derivedKey.value(), {}, // payload
|
mac = support::coseMac0(derivedKey.value(), {}, // payload
|
||||||
encodedDeviceAuthentication); // additionalData
|
deviceAuthenticationBytes); // detached content
|
||||||
if (!mac) {
|
if (!mac) {
|
||||||
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
|
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
|
||||||
IIdentityCredentialStore::STATUS_FAILED, "Error MACing data"));
|
IIdentityCredentialStore::STATUS_FAILED, "Error MACing data"));
|
||||||
|
|||||||
@@ -289,16 +289,19 @@ void ReaderAuthTests::retrieveData(const vector<uint8_t>& readerPrivateKey,
|
|||||||
.add("Accessible by None", false)))
|
.add("Accessible by None", false)))
|
||||||
.encode();
|
.encode();
|
||||||
}
|
}
|
||||||
vector<uint8_t> dataToSign = cppbor::Array()
|
vector<uint8_t> encodedReaderAuthentication =
|
||||||
.add("ReaderAuthentication")
|
cppbor::Array()
|
||||||
.add(sessionTranscript.clone())
|
.add("ReaderAuthentication")
|
||||||
.add(cppbor::Semantic(24, itemsRequestBytes))
|
.add(sessionTranscript.clone())
|
||||||
.encode();
|
.add(cppbor::Semantic(24, itemsRequestBytes))
|
||||||
|
.encode();
|
||||||
|
vector<uint8_t> encodedReaderAuthenticationBytes =
|
||||||
|
cppbor::Semantic(24, encodedReaderAuthentication).encode();
|
||||||
|
|
||||||
optional<vector<uint8_t>> readerSignature =
|
optional<vector<uint8_t>> readerSignature =
|
||||||
support::coseSignEcDsa(readerPrivateKey, // private key for reader
|
support::coseSignEcDsa(readerPrivateKey, // private key for reader
|
||||||
{}, // content
|
{}, // content
|
||||||
dataToSign, // detached content
|
encodedReaderAuthenticationBytes, // detached content
|
||||||
support::certificateChainJoin(readerCertChain));
|
support::certificateChainJoin(readerCertChain));
|
||||||
ASSERT_TRUE(readerSignature);
|
ASSERT_TRUE(readerSignature);
|
||||||
|
|
||||||
@@ -528,17 +531,20 @@ TEST_P(ReaderAuthTests, ephemeralKeyNotInSessionTranscript) {
|
|||||||
.add("Accessible by C", false)
|
.add("Accessible by C", false)
|
||||||
.add("Accessible by None", false)))
|
.add("Accessible by None", false)))
|
||||||
.encode();
|
.encode();
|
||||||
vector<uint8_t> dataToSign = cppbor::Array()
|
vector<uint8_t> encodedReaderAuthentication =
|
||||||
.add("ReaderAuthentication")
|
cppbor::Array()
|
||||||
.add(sessionTranscript.clone())
|
.add("ReaderAuthentication")
|
||||||
.add(cppbor::Semantic(24, itemsRequestBytes))
|
.add(sessionTranscript.clone())
|
||||||
.encode();
|
.add(cppbor::Semantic(24, itemsRequestBytes))
|
||||||
|
.encode();
|
||||||
|
vector<uint8_t> encodedReaderAuthenticationBytes =
|
||||||
|
cppbor::Semantic(24, encodedReaderAuthentication).encode();
|
||||||
|
|
||||||
vector<vector<uint8_t>> readerCertChain = {cert_reader_SelfSigned_};
|
vector<vector<uint8_t>> readerCertChain = {cert_reader_SelfSigned_};
|
||||||
optional<vector<uint8_t>> readerSignature =
|
optional<vector<uint8_t>> readerSignature =
|
||||||
support::coseSignEcDsa(readerPrivateKey_, // private key for reader
|
support::coseSignEcDsa(readerPrivateKey_, // private key for reader
|
||||||
{}, // content
|
{}, // content
|
||||||
dataToSign, // detached content
|
encodedReaderAuthenticationBytes, // detached content
|
||||||
support::certificateChainJoin(readerCertChain));
|
support::certificateChainJoin(readerCertChain));
|
||||||
ASSERT_TRUE(readerSignature);
|
ASSERT_TRUE(readerSignature);
|
||||||
|
|
||||||
|
|||||||
@@ -319,7 +319,7 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) {
|
|||||||
cppbor::Array sessionTranscript = cppbor::Array()
|
cppbor::Array sessionTranscript = cppbor::Array()
|
||||||
.add(cppbor::Semantic(24, deviceEngagementBytes))
|
.add(cppbor::Semantic(24, deviceEngagementBytes))
|
||||||
.add(cppbor::Semantic(24, eReaderPubBytes));
|
.add(cppbor::Semantic(24, eReaderPubBytes));
|
||||||
vector<uint8_t> sessionTranscriptBytes = sessionTranscript.encode();
|
vector<uint8_t> sessionTranscriptEncoded = sessionTranscript.encode();
|
||||||
|
|
||||||
vector<uint8_t> itemsRequestBytes =
|
vector<uint8_t> itemsRequestBytes =
|
||||||
cppbor::Map("nameSpaces",
|
cppbor::Map("nameSpaces",
|
||||||
@@ -347,14 +347,17 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) {
|
|||||||
" },\n"
|
" },\n"
|
||||||
"}",
|
"}",
|
||||||
cborPretty);
|
cborPretty);
|
||||||
vector<uint8_t> dataToSign = cppbor::Array()
|
vector<uint8_t> encodedReaderAuthentication =
|
||||||
.add("ReaderAuthentication")
|
cppbor::Array()
|
||||||
.add(sessionTranscript.clone())
|
.add("ReaderAuthentication")
|
||||||
.add(cppbor::Semantic(24, itemsRequestBytes))
|
.add(sessionTranscript.clone())
|
||||||
.encode();
|
.add(cppbor::Semantic(24, itemsRequestBytes))
|
||||||
|
.encode();
|
||||||
|
vector<uint8_t> encodedReaderAuthenticationBytes =
|
||||||
|
cppbor::Semantic(24, encodedReaderAuthentication).encode();
|
||||||
optional<vector<uint8_t>> readerSignature =
|
optional<vector<uint8_t>> readerSignature =
|
||||||
support::coseSignEcDsa(readerKey, {}, // content
|
support::coseSignEcDsa(readerKey, {}, // content
|
||||||
dataToSign, // detached content
|
encodedReaderAuthenticationBytes, // detached content
|
||||||
readerCertificate.value());
|
readerCertificate.value());
|
||||||
ASSERT_TRUE(readerSignature);
|
ASSERT_TRUE(readerSignature);
|
||||||
|
|
||||||
@@ -388,7 +391,7 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) {
|
|||||||
credential->setVerificationToken(verificationToken);
|
credential->setVerificationToken(verificationToken);
|
||||||
ASSERT_TRUE(credential
|
ASSERT_TRUE(credential
|
||||||
->startRetrieval(secureProfiles.value(), authToken, itemsRequestBytes,
|
->startRetrieval(secureProfiles.value(), authToken, itemsRequestBytes,
|
||||||
signingKeyBlob, sessionTranscriptBytes,
|
signingKeyBlob, sessionTranscriptEncoded,
|
||||||
readerSignature.value(), testEntriesEntryCounts)
|
readerSignature.value(), testEntriesEntryCounts)
|
||||||
.isOk());
|
.isOk());
|
||||||
|
|
||||||
@@ -432,7 +435,7 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) {
|
|||||||
" },\n"
|
" },\n"
|
||||||
"}",
|
"}",
|
||||||
cborPretty);
|
cborPretty);
|
||||||
// The data that is MACed is ["DeviceAuthentication", sessionTranscriptBytes, docType,
|
// The data that is MACed is ["DeviceAuthentication", sessionTranscript, docType,
|
||||||
// deviceNameSpacesBytes] so build up that structure
|
// deviceNameSpacesBytes] so build up that structure
|
||||||
cppbor::Array deviceAuthentication;
|
cppbor::Array deviceAuthentication;
|
||||||
deviceAuthentication.add("DeviceAuthentication");
|
deviceAuthentication.add("DeviceAuthentication");
|
||||||
@@ -441,7 +444,8 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) {
|
|||||||
string docType = "org.iso.18013-5.2019.mdl";
|
string docType = "org.iso.18013-5.2019.mdl";
|
||||||
deviceAuthentication.add(docType);
|
deviceAuthentication.add(docType);
|
||||||
deviceAuthentication.add(cppbor::Semantic(24, deviceNameSpacesBytes));
|
deviceAuthentication.add(cppbor::Semantic(24, deviceNameSpacesBytes));
|
||||||
vector<uint8_t> encodedDeviceAuthentication = deviceAuthentication.encode();
|
vector<uint8_t> deviceAuthenticationBytes =
|
||||||
|
cppbor::Semantic(24, deviceAuthentication.encode()).encode();
|
||||||
|
|
||||||
// Derive the key used for MACing.
|
// Derive the key used for MACing.
|
||||||
optional<vector<uint8_t>> readerEphemeralPrivateKey =
|
optional<vector<uint8_t>> readerEphemeralPrivateKey =
|
||||||
@@ -449,13 +453,20 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) {
|
|||||||
optional<vector<uint8_t>> sharedSecret =
|
optional<vector<uint8_t>> sharedSecret =
|
||||||
support::ecdh(signingPubKey.value(), readerEphemeralPrivateKey.value());
|
support::ecdh(signingPubKey.value(), readerEphemeralPrivateKey.value());
|
||||||
ASSERT_TRUE(sharedSecret);
|
ASSERT_TRUE(sharedSecret);
|
||||||
|
// Mix-in SessionTranscriptBytes
|
||||||
|
vector<uint8_t> sessionTranscriptBytes =
|
||||||
|
cppbor::Semantic(24, sessionTranscript.encode()).encode();
|
||||||
|
vector<uint8_t> sharedSecretWithSessionTranscriptBytes = sharedSecret.value();
|
||||||
|
std::copy(sessionTranscriptBytes.begin(), sessionTranscriptBytes.end(),
|
||||||
|
std::back_inserter(sharedSecretWithSessionTranscriptBytes));
|
||||||
vector<uint8_t> salt = {0x00};
|
vector<uint8_t> salt = {0x00};
|
||||||
vector<uint8_t> info = {};
|
vector<uint8_t> info = {};
|
||||||
optional<vector<uint8_t>> derivedKey = support::hkdf(sharedSecret.value(), salt, info, 32);
|
optional<vector<uint8_t>> derivedKey =
|
||||||
|
support::hkdf(sharedSecretWithSessionTranscriptBytes, salt, info, 32);
|
||||||
ASSERT_TRUE(derivedKey);
|
ASSERT_TRUE(derivedKey);
|
||||||
optional<vector<uint8_t>> calculatedMac =
|
optional<vector<uint8_t>> calculatedMac =
|
||||||
support::coseMac0(derivedKey.value(), {}, // payload
|
support::coseMac0(derivedKey.value(), {}, // payload
|
||||||
encodedDeviceAuthentication); // detached content
|
deviceAuthenticationBytes); // detached content
|
||||||
ASSERT_TRUE(calculatedMac);
|
ASSERT_TRUE(calculatedMac);
|
||||||
EXPECT_EQ(mac, calculatedMac);
|
EXPECT_EQ(mac, calculatedMac);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user