Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f2946ab5 authored by Sean Thomas's avatar Sean Thomas
Browse files

Perform sanity checks on generated P256 points

adds a test to VtsRemotelyProvisionedComponentTests that generates 256
P256 keypairs and adds functionality that makes sure the points (public
keys) lie on the curve, are not infinity, and are not equal to the base
point (generator).

Test: atest VtsHalRemotelyProvisionedComponentTargetTest
Bug: 327026543
Change-Id: I4002b9e5ed5dbc366a14ff5c16e2c4cfd7d14485
parent 43a2bd1a
Loading
Loading
Loading
Loading
+45 −0
Original line number Diff line number Diff line
@@ -2232,6 +2232,33 @@ void KeyMintAidlTestBase::assert_mgf_digests_present_or_not_in_key_characteristi

namespace {

std::optional<std::string> validateP256Point(const std::vector<uint8_t>& x_buffer,
                                             const std::vector<uint8_t>& y_buffer) {
    auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
    if (group.get() == nullptr) {
        return "Error creating EC group by curve name for prime256v1";
    }

    auto point = EC_POINT_Ptr(EC_POINT_new(group.get()));
    BIGNUM_Ptr x(BN_bin2bn(x_buffer.data(), x_buffer.size(), nullptr));
    BIGNUM_Ptr y(BN_bin2bn(y_buffer.data(), y_buffer.size(), nullptr));
    if (!EC_POINT_set_affine_coordinates_GFp(group.get(), point.get(), x.get(), y.get(), nullptr)) {
        return "Failed to set affine coordinates.";
    }
    if (!EC_POINT_is_on_curve(group.get(), point.get(), nullptr)) {
        return "Point is not on curve.";
    }
    if (EC_POINT_is_at_infinity(group.get(), point.get())) {
        return "Point is at infinity.";
    }
    const auto* generator = EC_GROUP_get0_generator(group.get());
    if (!EC_POINT_cmp(group.get(), generator, point.get(), nullptr)) {
        return "Point is equal to generator.";
    }

    return std::nullopt;
}

void check_cose_key(const vector<uint8_t>& data, bool testMode) {
    auto [parsedPayload, __, payloadParseErr] = cppbor::parse(data);
    ASSERT_TRUE(parsedPayload) << "Key parse failed: " << payloadParseErr;
@@ -2265,6 +2292,24 @@ void check_cose_key(const vector<uint8_t>& data, bool testMode) {
                             "  -3 : \\{(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}\\},\n"  // pub_y: data
                             "\\}"));
    }

    ASSERT_TRUE(parsedPayload->asMap()) << "CBOR item was not a map";

    ASSERT_TRUE(parsedPayload->asMap()->get(CoseKey::Label::PUBKEY_X))
            << "CBOR map did not contain x coordinate of public key";
    ASSERT_TRUE(parsedPayload->asMap()->get(CoseKey::Label::PUBKEY_X)->asBstr())
            << "x coordinate of public key was not a bstr";
    const auto& x = parsedPayload->asMap()->get(CoseKey::Label::PUBKEY_X)->asBstr()->value();

    ASSERT_TRUE(parsedPayload->asMap()->get(CoseKey::Label::PUBKEY_Y))
            << "CBOR map did not contain y coordinate of public key";
    ASSERT_TRUE(parsedPayload->asMap()->get(CoseKey::Label::PUBKEY_Y)->asBstr())
            << "y coordinate of public key was not a bstr";
    const auto& y = parsedPayload->asMap()->get(CoseKey::Label::PUBKEY_Y)->asBstr()->value();

    auto errorMessage = validateP256Point(x, y);
    EXPECT_EQ(errorMessage, std::nullopt)
            << *errorMessage << " x: " << bin2hex(x) << " y: " << bin2hex(y);
}

}  // namespace
+26 −0
Original line number Diff line number Diff line
@@ -416,6 +416,32 @@ TEST_P(GenerateKeyTests, generateEcdsaP256Key_testMode) {
    check_maced_pubkey(macedPubKey, testMode, nullptr);
}

/**
 * Generate and validate at most 2**16 production-mode keys. This aims to catch issues that do not
 * deterministically show up. In practice, this will test far fewer keys, but a certain number are
 * tested at a minimum.
 */
TEST_P(GenerateKeyTests, generateManyEcdsaP256KeysInProdMode) {
    const auto start = std::chrono::steady_clock::now();
    const auto time_bound = std::chrono::seconds(5);
    const auto upper_bound = 1 << 16;
    const auto lower_bound = 1 << 8;
    for (auto iteration = 0; iteration < upper_bound; iteration++) {
        MacedPublicKey macedPubKey;
        bytevec privateKeyBlob;
        bool testMode = false;
        auto status =
                provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
        ASSERT_TRUE(status.isOk());
        vector<uint8_t> coseKeyData;
        check_maced_pubkey(macedPubKey, testMode, &coseKeyData);
        const auto current_time = std::chrono::steady_clock::now() - start;
        if (iteration >= lower_bound && current_time >= time_bound) {
            break;
        }
    }
}

class CertificateRequestTestBase : public VtsRemotelyProvisionedComponentTests {
  protected:
    CertificateRequestTestBase()