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

Commit 83ef19fb authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Perform sanity checks on generated P256 points" into main

parents e4c85333 f2946ab5
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()