chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

View File

@@ -0,0 +1,124 @@
// Copyright 2018-2022 The OpenSSL Project Authors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
#include <openssl/digest.h>
#include <openssl/mem.h>
#include <openssl/sshkdf.h>
#include "../service_indicator/internal.h"
#include "../../internal.h"
int SSHKDF(const EVP_MD *evp_md,
const uint8_t *key, size_t key_len,
const uint8_t *xcghash, size_t xcghash_len,
const uint8_t *session_id, size_t session_id_len,
char type,
uint8_t *out, size_t out_len)
{
SET_DIT_AUTO_RESET;
EVP_MD_CTX *md = NULL;
uint8_t digest[EVP_MAX_MD_SIZE];
unsigned int digest_size = 0;
size_t cursize = 0;
int ret = 0;
// Sanity-check.
if (evp_md == NULL) {
return 0;
}
if (key == NULL || key_len == 0) {
return 0;
}
if (xcghash == NULL || xcghash_len == 0) {
return 0;
}
if (session_id == NULL || session_id_len == 0) {
return 0;
}
if (type < EVP_KDF_SSHKDF_TYPE_INITIAL_IV_CLI_TO_SRV ||
type > EVP_KDF_SSHKDF_TYPE_INTEGRITY_KEY_SRV_TO_CLI) {
return 0;
}
FIPS_service_indicator_lock_state();
md = EVP_MD_CTX_new();
if (md == NULL) {
goto out;
}
if (!EVP_DigestInit_ex(md, evp_md, NULL)) {
goto out;
}
if (!EVP_DigestUpdate(md, key, key_len)) {
goto out;
}
if (!EVP_DigestUpdate(md, xcghash, xcghash_len)) {
goto out;
}
if (!EVP_DigestUpdate(md, &type, 1)) {
goto out;
}
if (!EVP_DigestUpdate(md, session_id, session_id_len)) {
goto out;
}
if (!EVP_DigestFinal_ex(md, digest, &digest_size)) {
goto out;
}
if (out_len < digest_size) {
memcpy(out, digest, out_len);
ret = 1;
goto out;
}
memcpy(out, digest, digest_size);
for (cursize = digest_size; cursize < out_len; cursize += digest_size) {
if (!EVP_DigestInit_ex(md, evp_md, NULL)) {
goto out;
}
if (!EVP_DigestUpdate(md, key, key_len)) {
goto out;
}
if (!EVP_DigestUpdate(md, xcghash, xcghash_len)) {
goto out;
}
if (!EVP_DigestUpdate(md, out, cursize)) {
goto out;
}
if (!EVP_DigestFinal_ex(md, digest, (unsigned int *)&digest_size)) {
goto out;
}
if (out_len < cursize + digest_size) {
memcpy(out + cursize, digest, out_len - cursize);
ret = 1;
goto out;
}
memcpy(out + cursize, digest, digest_size);
}
ret = 1;
out:
EVP_MD_CTX_free(md);
OPENSSL_cleanse(digest, EVP_MAX_MD_SIZE);
FIPS_service_indicator_unlock_state();
if (ret) {
SSHKDF_verify_service_indicator(evp_md);
}
return ret;
}

View File

@@ -0,0 +1,203 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC
#include <gtest/gtest.h>
#include <openssl/crypto.h>
#include <openssl/digest.h>
#include <openssl/sshkdf.h>
#include "../../internal.h"
#include "../../test/file_test.h"
#include "../../test/test_util.h"
TEST(SSHKDFTest, SSHKDF_INPUT_INSANITY) {
uint8_t not_empty[] = {'t', 'e', 's', 't'};
size_t not_empty_len = sizeof(not_empty);
uint8_t output[] = {0};
size_t output_len = sizeof(output);
const EVP_MD *md = EVP_sha256(); // Not actually used.
ASSERT_FALSE(SSHKDF(nullptr, not_empty, not_empty_len,
not_empty, not_empty_len, not_empty, not_empty_len,
EVP_KDF_SSHKDF_TYPE_INITIAL_IV_CLI_TO_SRV,
output, output_len));
ASSERT_FALSE(SSHKDF(md, nullptr, not_empty_len,
not_empty, not_empty_len, not_empty, not_empty_len,
EVP_KDF_SSHKDF_TYPE_INITIAL_IV_CLI_TO_SRV,
output, output_len));
ASSERT_FALSE(SSHKDF(md, not_empty, 0,
not_empty, not_empty_len, not_empty, not_empty_len,
EVP_KDF_SSHKDF_TYPE_INITIAL_IV_CLI_TO_SRV,
output, output_len));
ASSERT_FALSE(SSHKDF(md, not_empty, not_empty_len,
nullptr, not_empty_len, not_empty, not_empty_len,
EVP_KDF_SSHKDF_TYPE_INITIAL_IV_CLI_TO_SRV,
output, output_len));
ASSERT_FALSE(SSHKDF(md, not_empty, not_empty_len,
not_empty, 0, not_empty, not_empty_len,
EVP_KDF_SSHKDF_TYPE_INITIAL_IV_CLI_TO_SRV,
output, output_len));
ASSERT_FALSE(SSHKDF(md, not_empty, not_empty_len,
not_empty, not_empty_len, nullptr, not_empty_len,
EVP_KDF_SSHKDF_TYPE_INITIAL_IV_CLI_TO_SRV,
output, output_len));
ASSERT_FALSE(SSHKDF(md, not_empty, not_empty_len,
not_empty, not_empty_len, not_empty, 0,
EVP_KDF_SSHKDF_TYPE_INITIAL_IV_CLI_TO_SRV,
output, output_len));
ASSERT_FALSE(SSHKDF(md, not_empty, not_empty_len,
not_empty, not_empty_len, not_empty, not_empty_len,
EVP_KDF_SSHKDF_TYPE_INITIAL_IV_CLI_TO_SRV - 1,
output, output_len));
ASSERT_FALSE(SSHKDF(md, not_empty, not_empty_len,
not_empty, not_empty_len, not_empty, not_empty_len,
EVP_KDF_SSHKDF_TYPE_INTEGRITY_KEY_SRV_TO_CLI + 1,
output, output_len));
}
static void RunTest(FileTest *t)
{
std::string count;
std::vector<uint8_t> key, xcghash, session_id, initial_iv_c2s, initial_iv_s2c,
encryption_key_c2s, encryption_key_s2c, integrity_key_c2s,
integrity_key_s2c;
t->IgnoreAllUnusedInstructions();
const EVP_MD *md = NULL;
if (t->HasInstruction("SHA-1")) {
md = EVP_sha1();
} else if (t->HasInstruction("SHA-224")) {
md = EVP_sha224();
} else if (t->HasInstruction("SHA-256")) {
md = EVP_sha256();
} else if (t->HasInstruction("SHA-384")) {
md = EVP_sha384();
} else if (t->HasInstruction("SHA-512")) {
md = EVP_sha512();
} else {
// Unknown/unsupported hash in test input. Did someone update the test
// data without updating the code?
ASSERT_NE(md, nullptr);
}
// These are all specified in bits.
std::string iv_len_str, encryption_key_len_str;
ASSERT_TRUE(t->GetInstruction(&iv_len_str, "IV length"));
unsigned long iv_len = std::stoul(iv_len_str) / 8;
ASSERT_TRUE(t->GetInstruction(&encryption_key_len_str, "encryption key length"));
unsigned long encryption_key_len = std::stoul(encryption_key_len_str) / 8;
ASSERT_TRUE(t->GetAttribute(&count, "COUNT"));
ASSERT_TRUE(t->GetBytes(&key, "K"));
ASSERT_TRUE(t->GetBytes(&xcghash, "H"));
ASSERT_TRUE(t->GetBytes(&session_id, "session_id"));
ASSERT_TRUE(t->GetBytes(&initial_iv_c2s, "Initial IV (client to server)"));
ASSERT_TRUE(t->GetBytes(&initial_iv_s2c, "Initial IV (server to client)"));
ASSERT_TRUE(t->GetBytes(&encryption_key_c2s, "Encryption key (client to server)"));
ASSERT_TRUE(t->GetBytes(&encryption_key_s2c, "Encryption key (server to client)"));
ASSERT_TRUE(t->GetBytes(&integrity_key_c2s, "Integrity key (client to server)"));
ASSERT_TRUE(t->GetBytes(&integrity_key_s2c, "Integrity key (server to client)"));
// The CAVP test data shows its work, repeatedly. Ignore these.
t->IgnoreAttribute("K || H || K1");
t->IgnoreAttribute("K || H || K1/2");
t->IgnoreAttribute("K || H || X || session id");
t->IgnoreAttribute("K || H || X || session id/2");
t->IgnoreAttribute("K || H || X || session id/3");
t->IgnoreAttribute("K || H || X || session id/4");
t->IgnoreAttribute("K || H || X || session id/5");
t->IgnoreAttribute("K || H || X || session id/6");
t->IgnoreAttribute("K/2");
t->IgnoreAttribute("K/3");
t->IgnoreAttribute("K/4");
t->IgnoreAttribute("K/5");
t->IgnoreAttribute("K/6");
t->IgnoreAttribute("K/7");
t->IgnoreAttribute("K1");
t->IgnoreAttribute("K1/2");
t->IgnoreAttribute("K1/3");
t->IgnoreAttribute("K1/4");
t->IgnoreAttribute("K1/5");
t->IgnoreAttribute("K1/6");
t->IgnoreAttribute("K2");
t->IgnoreAttribute("K2/2");
t->IgnoreAttribute("X");
t->IgnoreAttribute("X/2");
t->IgnoreAttribute("X/3");
t->IgnoreAttribute("X/4");
t->IgnoreAttribute("X/5");
t->IgnoreAttribute("X/6");
// Why isn't this output length specified in the data file? It is a mystery.
unsigned integrity_key_len = integrity_key_c2s.size();
// Initial IVs
uint8_t *output = static_cast<uint8_t *>(new uint8_t[iv_len]);
ASSERT_TRUE(SSHKDF(md, key.data(), key.size(), xcghash.data(), xcghash.size(),
session_id.data(), session_id.size(),
EVP_KDF_SSHKDF_TYPE_INITIAL_IV_CLI_TO_SRV,
output, iv_len));
EXPECT_EQ(Bytes(initial_iv_c2s.data(), initial_iv_c2s.size()),
Bytes(output, iv_len));
ASSERT_TRUE(SSHKDF(md, key.data(), key.size(), xcghash.data(), xcghash.size(),
session_id.data(), session_id.size(),
EVP_KDF_SSHKDF_TYPE_INITIAL_IV_SRV_TO_CLI,
output, iv_len));
EXPECT_EQ(Bytes(initial_iv_s2c.data(), initial_iv_s2c.size()),
Bytes(output, iv_len));
delete[] output;
output = NULL;
// Encryption keys
output = static_cast<uint8_t *>(new uint8_t[encryption_key_len]);
ASSERT_TRUE(SSHKDF(md, key.data(), key.size(), xcghash.data(), xcghash.size(),
session_id.data(), session_id.size(),
EVP_KDF_SSHKDF_TYPE_ENCRYPTION_KEY_CLI_TO_SRV,
output, encryption_key_len));
EXPECT_EQ(Bytes(encryption_key_c2s.data(), encryption_key_c2s.size()),
Bytes(output, encryption_key_len));
ASSERT_TRUE(SSHKDF(md, key.data(), key.size(), xcghash.data(), xcghash.size(),
session_id.data(), session_id.size(),
EVP_KDF_SSHKDF_TYPE_ENCRYPTION_KEY_SRV_TO_CLI,
output, encryption_key_len));
EXPECT_EQ(Bytes(encryption_key_s2c.data(), encryption_key_s2c.size()),
Bytes(output, encryption_key_len));
delete[] output;
output = NULL;
// Integrity keys
output = static_cast<uint8_t *>(new uint8_t[integrity_key_len]);
ASSERT_TRUE(SSHKDF(md, key.data(), key.size(), xcghash.data(), xcghash.size(),
session_id.data(), session_id.size(),
EVP_KDF_SSHKDF_TYPE_INTEGRITY_KEY_CLI_TO_SRV,
output, integrity_key_len));
EXPECT_EQ(Bytes(integrity_key_c2s.data(), integrity_key_c2s.size()),
Bytes(output, integrity_key_len));
ASSERT_TRUE(SSHKDF(md, key.data(), key.size(), xcghash.data(), xcghash.size(),
session_id.data(), session_id.size(),
EVP_KDF_SSHKDF_TYPE_INTEGRITY_KEY_SRV_TO_CLI,
output, integrity_key_len));
EXPECT_EQ(Bytes(integrity_key_s2c.data(), integrity_key_s2c.size()),
Bytes(output, integrity_key_len));
delete[] output;
output = NULL;
}
TEST(SSHKDFTest, KAT) {
FileTestGTest("crypto/evp_extra/sshkdf_tests.txt", RunTest);
}