From feab5d932fdea408ce67cb643f3c4a813a4f436e Mon Sep 17 00:00:00 2001 From: David Drysdale Date: Thu, 6 Jan 2022 15:46:23 +0000 Subject: [PATCH] KeyMint VTS: police Ed25519 msg size limit Ed25519 signing operations require the secure world to accumulate the entirety of the message; consequently, impose a limit on message size for this operation. Bug: 194358913 Test: VtsAidlKeyMintTargetTest Change-Id: Ibfb6a54c1d546b5b4e51f42795d2bb4660add772 --- .../security/keymint/IKeyMintDevice.aidl | 4 +- .../vts/functional/KeyMintAidlTestBase.cpp | 7 +- .../aidl/vts/functional/KeyMintTest.cpp | 94 +++++++++++++++++++ 3 files changed, 103 insertions(+), 2 deletions(-) diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl index 9846ee91ac..4b637993f1 100644 --- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl +++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl @@ -96,7 +96,9 @@ import android.hardware.security.secureclock.TimeStampToken; * - TRUSTED_ENVRIONMENT IKeyMintDevices must support curve 25519 for Purpose::SIGN (Ed25519, * as specified in RFC 8032), Purpose::ATTEST_KEY (Ed25519) or for KeyPurpose::AGREE_KEY * (X25519, as specified in RFC 7748). However, a key must have exactly one of these - * purpose values; the same key cannot be used for multiple purposes. + * purpose values; the same key cannot be used for multiple purposes. Signing operations + * (Purpose::SIGN) have a message size limit of 16 KiB; operations on messages longer than + * this limit must fail with ErrorCode::INVALID_INPUT_LENGTH. * STRONGBOX IKeyMintDevices do not support curve 25519. * * o AES diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp index 8382781368..49665b10ce 100644 --- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp +++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp @@ -559,7 +559,12 @@ ErrorCode KeyMintAidlTestBase::Update(const string& input, string* output) { std::vector o_put; result = op_->update(vector(input.begin(), input.end()), {}, {}, &o_put); - if (result.isOk()) output->append(o_put.begin(), o_put.end()); + if (result.isOk()) { + output->append(o_put.begin(), o_put.end()); + } else { + // Failure always terminates the operation. + op_ = {}; + } return GetReturnErrorCode(result); } diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp index 7f35f342b6..dc1d843bd2 100644 --- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp +++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp @@ -70,6 +70,9 @@ namespace aidl::android::hardware::security::keymint::test { namespace { +// Maximum supported Ed25519 message size. +const size_t MAX_ED25519_MSG_SIZE = 16 * 1024; + // Whether to check that BOOT_PATCHLEVEL is populated. bool check_boot_pl = true; @@ -3126,6 +3129,97 @@ TEST_P(SigningOperationsTest, EcdsaCurve25519) { CheckedDeleteKey(); } +/* + * SigningOperationsTest.EcdsaCurve25519MaxSize + * + * Verifies that EDDSA operations with curve25519 under the maximum message size succeed. + */ +TEST_P(SigningOperationsTest, EcdsaCurve25519MaxSize) { + if (!Curve25519Supported()) { + GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519"; + } + + EcCurve curve = EcCurve::CURVE_25519; + ErrorCode error = GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(curve) + .Digest(Digest::NONE) + .SetDefaultValidity()); + ASSERT_EQ(ErrorCode::OK, error) << "Failed to generate ECDSA key with curve " << curve; + + auto params = AuthorizationSetBuilder().Digest(Digest::NONE); + + for (size_t msg_size : {MAX_ED25519_MSG_SIZE - 1, MAX_ED25519_MSG_SIZE}) { + SCOPED_TRACE(testing::Message() << "-msg-size=" << msg_size); + string message(msg_size, 'a'); + + // Attempt to sign via Begin+Finish. + AuthorizationSet out_params; + ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, key_blob_, params, &out_params)); + EXPECT_TRUE(out_params.empty()); + string signature; + auto result = Finish(message, &signature); + EXPECT_EQ(result, ErrorCode::OK); + LocalVerifyMessage(message, signature, params); + + // Attempt to sign via Begin+Update+Finish + ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, key_blob_, params, &out_params)); + EXPECT_TRUE(out_params.empty()); + string output; + result = Update(message, &output); + EXPECT_EQ(result, ErrorCode::OK); + EXPECT_EQ(output.size(), 0); + string signature2; + EXPECT_EQ(ErrorCode::OK, Finish({}, &signature2)); + LocalVerifyMessage(message, signature2, params); + } + + CheckedDeleteKey(); +} + +/* + * SigningOperationsTest.EcdsaCurve25519MaxSizeFail + * + * Verifies that EDDSA operations with curve25519 fail when message size is too large. + */ +TEST_P(SigningOperationsTest, EcdsaCurve25519MaxSizeFail) { + if (!Curve25519Supported()) { + GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519"; + } + + EcCurve curve = EcCurve::CURVE_25519; + ErrorCode error = GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(curve) + .Digest(Digest::NONE) + .SetDefaultValidity()); + ASSERT_EQ(ErrorCode::OK, error) << "Failed to generate ECDSA key with curve " << curve; + + auto params = AuthorizationSetBuilder().Digest(Digest::NONE); + + for (size_t msg_size : {MAX_ED25519_MSG_SIZE + 1, MAX_ED25519_MSG_SIZE * 2}) { + SCOPED_TRACE(testing::Message() << "-msg-size=" << msg_size); + string message(msg_size, 'a'); + + // Attempt to sign via Begin+Finish. + AuthorizationSet out_params; + ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, key_blob_, params, &out_params)); + EXPECT_TRUE(out_params.empty()); + string signature; + auto result = Finish(message, &signature); + EXPECT_EQ(result, ErrorCode::INVALID_INPUT_LENGTH); + + // Attempt to sign via Begin+Update (but never get to Finish) + ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, key_blob_, params, &out_params)); + EXPECT_TRUE(out_params.empty()); + string output; + result = Update(message, &output); + EXPECT_EQ(result, ErrorCode::INVALID_INPUT_LENGTH); + } + + CheckedDeleteKey(); +} + /* * SigningOperationsTest.EcdsaNoDigestHugeData *