Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SC-3184 #217

Merged
merged 6 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 31 additions & 13 deletions src/modules/mbedtls/nm_mbedtls_spake2.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,15 @@ static void mbedtls_spake2_destroy(struct np_spake2_context* spake)
// pwd [in] from auth req
// S [out] returned to client
// Key [out] used in key_confirmation
static np_error_code mbedtls_spake2_calculate_key(
struct np_spake2_context* spake, struct nc_spake2_password_request* req, const char* password,
uint8_t* resp, size_t* respLen, uint8_t* spake2Key)
np_error_code nm_mbedtls_spake2_calculate_key(
struct np_spake2_context* spake,
struct nc_spake2_password_request* req,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
const char* password,
uint8_t* resp,
size_t* respLen,
uint8_t* spake2Key)
{
mbedtls_ecp_point T;
mbedtls_ecp_group tGrp;
Expand Down Expand Up @@ -125,25 +131,17 @@ static np_error_code mbedtls_spake2_calculate_key(
uint8_t passwordHash[32];

{
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ctr_drbg_init( &ctr_drbg );
mbedtls_entropy_init( &entropy );
status |= mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0);
// Generate random value for y and create Y
status |= mbedtls_ecp_gen_keypair( &grp, &y, &Y, mbedtls_ctr_drbg_random, &ctr_drbg);
status |= mbedtls_ecp_gen_keypair( &grp, &y, &Y, f_rng, p_rng);

// Use dummy pwd if a real one don't exist to mask invalid username
if (password == NULL) {
status |= mbedtls_ctr_drbg_random(&ctr_drbg, passwordHash, 32);
status |= f_rng(p_rng, passwordHash, 32);
} else {
status |= nm_mbedtls_sha256((const uint8_t*)password, strlen(password), passwordHash);
}
// create password hash from binary
status |= mbedtls_mpi_read_binary(&w, passwordHash, sizeof(passwordHash));

mbedtls_entropy_free(&entropy);
mbedtls_ctr_drbg_free(&ctr_drbg);
}

{
Expand Down Expand Up @@ -219,6 +217,26 @@ static np_error_code mbedtls_spake2_calculate_key(
}
}

static np_error_code mbedtls_spake2_calculate_key(
struct np_spake2_context* spake, struct nc_spake2_password_request* req, const char* password,
uint8_t* resp, size_t* respLen, uint8_t* spake2Key)
{
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ctr_drbg_init( &ctr_drbg );
mbedtls_entropy_init( &entropy );
int status = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0);
if (status != 0) {
return NABTO_EC_FAILED;
}

np_error_code ec = nm_mbedtls_spake2_calculate_key(spake, req, mbedtls_ctr_drbg_random, &ctr_drbg, password, resp, respLen, spake2Key);

mbedtls_entropy_free(&entropy);
mbedtls_ctr_drbg_free(&ctr_drbg);
return ec;
}

static np_error_code mbedtls_spake2_key_confirmation(struct np_spake2_context* spake, uint8_t* payload, size_t payloadLen, uint8_t* key, size_t keyLen, uint8_t* hash1, size_t hash1Len)
{
if(payloadLen != 32 || keyLen != 32 || hash1Len != 32) {
Expand Down
10 changes: 10 additions & 0 deletions src/modules/mbedtls/nm_mbedtls_spake2.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@ np_error_code nm_mbedtls_spake2_init(struct np_platform* pl);

void nm_mbedtls_spake2_deinit(struct np_platform* pl);

np_error_code nm_mbedtls_spake2_calculate_key(
struct np_spake2_context* spake,
struct nc_spake2_password_request* req,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
const char* password,
uint8_t* resp,
size_t* respLen,
uint8_t* spake2Key);

#ifdef __cplusplus
} //extern "C"
#endif
Expand Down
1 change: 1 addition & 0 deletions test_cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ set(test_src
tests/core/nc_coap_rest_error_test.cpp
tests/core/watchdog_test.cpp
tests/spake2/spake2_test.cpp
tests/spake2/spake2_mbedtls_test.cpp
tests/spake2/spake2_wolfssl_test.cpp
../src/api_test/nabto_device_test_logging.c
)
Expand Down
82 changes: 82 additions & 0 deletions test_cpp/tests/spake2/spake2_mbedtls_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#include <nabto/nabto_device_config.h>
#if defined(NABTO_DEVICE_MBEDTLS)
#if defined(NABTO_DEVICE_PASSWORD_AUTHENTICATION)

#include <boost/test/unit_test.hpp>

#include "spake2_util.hpp"

#include <boost/test/data/test_case.hpp>
#include <test_platform.hpp>

#include <core/nc_spake2.h>
#include <platform/np_platform.h>
#include <modules/mbedtls/nm_mbedtls_spake2.h>

static int dummyRandom(void* context, unsigned char* output, size_t outputLen)
{
for (size_t i = 0; i < outputLen; i++) {
output[i] = 42;
}
return 0;
}

BOOST_AUTO_TEST_SUITE(mbedtls_spake2)

BOOST_AUTO_TEST_CASE(calculate_mbedtls_key_deterministically, * boost::unit_test::timeout(120))
{
auto req = nc_spake2_password_request_new();
uint8_t clientFp[] = {0xcf, 0xf2, 0xf6, 0x5c, 0xd1, 0x03, 0x48, 0x8b,
0x8c, 0xb2, 0xb9, 0x3e, 0x83, 0x8a, 0xcc, 0x0f,
0x71, 0x9d, 0x6d, 0xea, 0xe3, 0x7f, 0x8a, 0x4b,
0x74, 0xfa, 0x82, 0x52, 0x44, 0xd2, 0x8a, 0xf8};
uint8_t deviceFp[] = {0x73, 0xe5, 0x30, 0x42, 0x55, 0x1c, 0x12, 0x8a,
0x49, 0x2c, 0xfd, 0x91, 0x0b, 0x9b, 0xa6, 0x7f,
0xff, 0xd2, 0xca, 0xb6, 0xc0, 0x23, 0xb5, 0x0c,
0x10, 0x99, 0x22, 0x89, 0xf4, 0xc2, 0x3d, 0x54};

const std::string password = "FFzeqrpJTVF4";
nabto::test::Spake2Client cli(password, clientFp, deviceFp);


std::vector<uint8_t> T;
BOOST_TEST(cli.calculateTWithCustomRandom(T, dummyRandom, NULL) == 0);

std::vector<uint8_t> expectedTValue = std::vector<uint8_t>( {
0x04, 0x67, 0x30, 0xc2, 0x0d, 0x89, 0x65, 0x91, 0xad, 0xb0, 0xd1,
0xf6, 0x7f, 0x64, 0x16, 0x57, 0x6a, 0xee, 0x37, 0x33, 0x84, 0xe6,
0x1e, 0xdb, 0xfd, 0xd9, 0xff, 0xc2, 0xb7, 0x7e, 0x0d, 0x07, 0x07,
0x6e, 0x3c, 0x55, 0xb9, 0x43, 0x45, 0xb1, 0xbb, 0xc6, 0x15, 0x70,
0x25, 0xfd, 0x45, 0x7f, 0xb6, 0x27, 0x9e, 0xdb, 0xdc, 0xcf, 0xef,
0x19, 0xa0, 0x88, 0x04, 0x8a, 0x25, 0x93, 0x6c, 0x76, 0x3f});

BOOST_TEST(T == expectedTValue);

memcpy(req->clientFingerprint, clientFp, 32);
memcpy(req->deviceFingerprint, deviceFp, 32);
req->T = (uint8_t*)calloc(1, T.size());
memcpy(req->T, T.data(), T.size());
req->Tlen = T.size();

uint8_t S[256];
size_t SLen = sizeof(S);
uint8_t key[32];

BOOST_TEST(nm_mbedtls_spake2_calculate_key(NULL, req, dummyRandom, NULL, password.c_str(), S, &SLen, key) == NABTO_EC_OK);

// this reference output was calculated with mbedtls + dummyRandom

uint8_t expectedKey[] = {0x5c, 0x5d, 0x50, 0x41, 0xd4, 0x63, 0x4b, 0x16,
0xcf, 0x7b, 0x79, 0xa7, 0x01, 0xac, 0xd9, 0x25,
0xbe, 0x9a, 0x3e, 0x36, 0x04, 0x36, 0xa5, 0xbb,
0xcb, 0x08, 0xd3, 0x8e, 0xe1, 0xf7, 0x64, 0x10};

BOOST_TEST(memcmp(key, expectedKey, 32) == 0);

nc_spake2_password_request_free(req);
}

BOOST_AUTO_TEST_SUITE_END()

#endif
#endif
2 changes: 1 addition & 1 deletion test_cpp/tests/spake2/spake2_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

#include <core/nc_spake2.h>
#include <platform/np_platform.h>

#include <modules/mbedtls/nm_mbedtls_spake2.h>

BOOST_AUTO_TEST_SUITE(spake2)

Expand Down
27 changes: 18 additions & 9 deletions test_cpp/tests/spake2/spake2_util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

#include <array>

#include <stdio.h>

namespace nabto {
namespace test {

Expand All @@ -30,7 +32,6 @@ static uint8_t Ndata[] = {
0x33, 0x7f, 0x51, 0x68, 0xc6, 0x4d, 0x9b, 0xd3, 0x60, 0x34, 0x80,
0x8c, 0xd5, 0x64, 0x49, 0x0b, 0x1e, 0x65, 0x6e, 0xdb, 0xe7};


class Spake2Client {
public:

Expand Down Expand Up @@ -84,19 +85,29 @@ class Spake2Client {

int calculateT(std::vector<uint8_t>& out)
{
mbedtls_ecp_point X;
mbedtls_ecp_point_init(&X);

mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ctr_drbg_init(&ctr_drbg);

mbedtls_entropy_init(&entropy);

int status = 0;
status |= mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0);
status |= calculateTWithCustomRandom(out, mbedtls_ctr_drbg_random, &ctr_drbg);

mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_entropy_free(&entropy);
return status;
}

int calculateTWithCustomRandom(std::vector<uint8_t>& out, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
{
mbedtls_ecp_point X;
mbedtls_ecp_point_init(&X);

int status = 0;
status |= mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
&entropy, NULL, 0);
status |= mbedtls_ecp_gen_keypair(&grp_, &x_, &X,
mbedtls_ctr_drbg_random, &ctr_drbg);
f_rng, p_rng);

mbedtls_mpi tmp;
mbedtls_mpi_init(&tmp);
Expand All @@ -108,8 +119,6 @@ class Spake2Client {
writePoint(out, &grp_, &T_);

mbedtls_mpi_free(&tmp);
mbedtls_entropy_free(&entropy);
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_ecp_point_free(&X);
return status;
}
Expand Down
Loading