Skip to content

Commit

Permalink
Revert "Updated PASEVerifier Format to Match Spec. (project-chip#15070)"
Browse files Browse the repository at this point in the history
This reverts commit dabb721.
  • Loading branch information
mspang committed Feb 12, 2022
1 parent d3adebb commit 59379d0
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 115 deletions.
10 changes: 1 addition & 9 deletions src/crypto/CHIPCryptoPAL.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
*
* Copyright (c) 2020-2022 Project CHIP Authors
* Copyright (c) 2020 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -507,14 +507,6 @@ CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::KDF(const uint8_t * ikm, const size_t
return CHIP_NO_ERROR;
}

CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::ComputeW0(uint8_t * w0out, size_t * w0_len, const uint8_t * w0sin, size_t w0sin_len)
{
ReturnErrorOnFailure(FELoad(w0sin, w0sin_len, w0));
ReturnErrorOnFailure(FEWrite(w0, w0out, *w0_len));

return CHIP_NO_ERROR;
}

CHIP_ERROR ConvertIntegerRawToDerWithoutTag(const ByteSpan & raw_integer, MutableByteSpan & out_der_integer)
{
return ConvertIntegerRawToDerInternal(raw_integer, out_der_integer, /* include_tag_and_length = */ false);
Expand Down
18 changes: 2 additions & 16 deletions src/crypto/CHIPCryptoPAL.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
*
* Copyright (c) 2020-2022 Project CHIP Authors
* Copyright (c) 2020 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -849,7 +849,7 @@ class Spake2p
* @param my_identity_len The verifier identity length.
* @param peer_identity The peer identity. May be NULL if identities are not established.
* @param peer_identity_len The peer identity length.
* @param w0in The input w0 (a parameter baked into the device or computed with ComputeW0).
* @param w0in The input w0 (an output from the PBKDF).
* @param w0in_len The input w0 length.
* @param Lin The input L (a parameter baked into the device or computed with ComputeL).
* @param Lin_len The input L length.
Expand Down Expand Up @@ -1045,18 +1045,6 @@ class Spake2p
*/
virtual CHIP_ERROR PointIsValid(void * R) = 0;

/*
* @synopsis Compute w0sin mod p
*
* @param w0out Output field element (modulo p)
* @param w0_len Output field element length
* @param w1sin Input field element
* @param w1sin_len Input field element length
*
* @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
**/
virtual CHIP_ERROR ComputeW0(uint8_t * w0out, size_t * w0_len, const uint8_t * w0sin, size_t w0sin_len) = 0;

/*
* @synopsis Compute w1in*G
*
Expand Down Expand Up @@ -1220,8 +1208,6 @@ class Spake2p_P256_SHA256_HKDF_HMAC : public Spake2p
CHIP_ERROR PointInvert(void * R) override;
CHIP_ERROR PointCofactorMul(void * R) override;
CHIP_ERROR PointIsValid(void * R) override;

CHIP_ERROR ComputeW0(uint8_t * w0out, size_t * w0_len, const uint8_t * w0sin, size_t w0sin_len) override;
CHIP_ERROR ComputeL(uint8_t * Lout, size_t * L_len, const uint8_t * w1in, size_t w1in_len) override;

protected:
Expand Down
3 changes: 1 addition & 2 deletions src/include/platform/CHIPDeviceConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -911,8 +911,7 @@
*/
#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_VERIFIER
#define CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_VERIFIER \
"uWFwqugDNGiEck/po7KHwwMwwqZgN10XuyBajPGuyzUEV/iree4lOrao5GuwnlQ65CJzbeUB49s31EH+NEkg0JVI5MGCQGMMT/SRPFNRODm3wH/MBiehuFc6FJ/" \
"NH6Rmzw=="
"q6YMMEFrj0F39eFq1RTP2Vd1E/Av1gUGsQSdDyxzEAEOXkC/2GtO9oGoi3Hp4qhTmFp975Fuow4BuHIvv30OOIVsEs1kwiW7JO8hQX4OROU="
#endif

#else
Expand Down
110 changes: 50 additions & 60 deletions src/protocols/secure_channel/PASESession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ void PASESession::Clear()
{
// This function zeroes out and resets the memory used by the object.
// It's done so that no security related information will be leaked.
memset(&mPoint[0], 0, sizeof(mPoint));
memset(&mPASEVerifier, 0, sizeof(mPASEVerifier));
memset(&mKe[0], 0, sizeof(mKe));
mNextExpectedMsg = MsgType::PASE_PakeError;
Expand All @@ -97,6 +98,7 @@ void PASESession::Clear()
}
mKeLen = sizeof(mKe);
mPairingComplete = false;
mComputeVerifier = true;
PairingSession::Clear();
CloseExchange();
}
Expand Down Expand Up @@ -203,68 +205,54 @@ CHIP_ERROR PASESession::Init(uint16_t mySessionId, uint32_t setupCode, SessionEs

ChipLogDetail(SecureChannel, "Assigned local session key ID %d", mySessionId);
SetLocalSessionId(mySessionId);
mSetupPINCode = setupCode;
mSetupPINCode = setupCode;
mComputeVerifier = true;

return CHIP_NO_ERROR;
}

CHIP_ERROR PASESession::ComputeWS(uint32_t setUpPINCode, uint32_t pbkdf2IterCount, const ByteSpan & salt, uint32_t wsSize,
uint8_t * ws)
CHIP_ERROR PASESession::ComputePASEVerifier(uint32_t setUpPINCode, uint32_t pbkdf2IterCount, const ByteSpan & salt,
PASEVerifier & verifier)
{
TRACE_EVENT_SCOPE("ComputePASEVerifier", "PASESession");
ReturnErrorCodeIf(salt.empty(), CHIP_ERROR_INVALID_ARGUMENT);
ReturnErrorCodeIf(salt.data() == nullptr, CHIP_ERROR_INVALID_ARGUMENT);
ReturnErrorCodeIf(setUpPINCode >= (1 << kSetupPINCodeFieldLengthInBits), CHIP_ERROR_INVALID_ARGUMENT);

PBKDF2_sha256_crypto mPBKDF;
uint8_t littleEndianSetupPINCode[sizeof(uint32_t)];
Encoding::LittleEndian::Put32(littleEndianSetupPINCode, setUpPINCode);

ReturnErrorCodeIf(salt.empty(), CHIP_ERROR_INVALID_ARGUMENT);
ReturnErrorCodeIf(setUpPINCode >= (1 << kSetupPINCodeFieldLengthInBits), CHIP_ERROR_INVALID_ARGUMENT);

return mPBKDF.pbkdf2_sha256(littleEndianSetupPINCode, sizeof(littleEndianSetupPINCode), salt.data(), salt.size(),
pbkdf2IterCount, wsSize, ws);
PASEVerifierSerialized serializedVerifier;
ReturnErrorOnFailure(mPBKDF.pbkdf2_sha256(littleEndianSetupPINCode, sizeof(littleEndianSetupPINCode), salt.data(), salt.size(),
pbkdf2IterCount, sizeof(PASEVerifierSerialized), serializedVerifier));
return verifier.Deserialize(ByteSpan(serializedVerifier));
}

CHIP_ERROR PASESession::GeneratePASEVerifier(PASEVerifier & verifier, uint32_t pbkdf2IterCount, const ByteSpan & salt,
bool useRandomPIN, uint32_t & setupPINCode)
bool useRandomPIN, uint32_t & setupPIN)
{
TRACE_EVENT_SCOPE("GeneratePASEVerifier", "PASESession");

if (useRandomPIN)
{
ReturnErrorOnFailure(DRBG_get_bytes(reinterpret_cast<uint8_t *>(&setupPINCode), sizeof(setupPINCode)));
ReturnErrorOnFailure(DRBG_get_bytes(reinterpret_cast<uint8_t *>(&setupPIN), sizeof(setupPIN)));

// Passcodes shall be restricted to the values 00000001 to 99999998 in decimal, see 5.1.1.6
setupPINCode = (setupPINCode % kSetupPINCodeMaximumValue) + 1;
setupPIN = (setupPIN % kSetupPINCodeMaximumValue) + 1;
}

uint8_t serializedWS[kSpake2p_WS_Length * 2] = { 0 };
ReturnErrorOnFailure(ComputeWS(setupPINCode, pbkdf2IterCount, salt, sizeof(serializedWS), serializedWS));

CHIP_ERROR err = CHIP_NO_ERROR;
size_t len;

// Create local spake2p object for W0 and L camputations.
Spake2p_P256_SHA256_HKDF_HMAC spake2p;
uint8_t context[kSHA256_Hash_Length] = { 0 };
SuccessOrExit(err = spake2p.Init(context, sizeof(context)));

// Compute W0
len = sizeof(verifier.mW0);
SuccessOrExit(err = spake2p.ComputeW0(verifier.mW0, &len, &serializedWS[0], kSpake2p_WS_Length));
VerifyOrExit(len == sizeof(verifier.mW0), err = CHIP_ERROR_INTERNAL);

// Compute L
len = sizeof(verifier.mL);
SuccessOrExit(err = spake2p.ComputeL(verifier.mL, &len, &serializedWS[kSpake2p_WS_Length], kSpake2p_WS_Length));
VerifyOrExit(len == sizeof(verifier.mL), err = CHIP_ERROR_INTERNAL);

exit:
spake2p.Clear();
return err;
return PASESession::ComputePASEVerifier(setupPIN, pbkdf2IterCount, salt, verifier);
}

CHIP_ERROR PASESession::SetupSpake2p()
CHIP_ERROR PASESession::SetupSpake2p(uint32_t pbkdf2IterCount, const ByteSpan & salt)
{
TRACE_EVENT_SCOPE("SetupSpake2p", "PASESession");
uint8_t context[kSHA256_Hash_Length] = { 0 };

if (mComputeVerifier)
{
ReturnErrorOnFailure(PASESession::ComputePASEVerifier(mSetupPINCode, pbkdf2IterCount, salt, mPASEVerifier));
}

MutableByteSpan contextSpan{ context };

ReturnErrorOnFailure(mCommissioningHash.Finish(contextSpan));
Expand Down Expand Up @@ -307,6 +295,7 @@ CHIP_ERROR PASESession::WaitForPairing(const PASEVerifier & verifier, uint32_t p
mPairingComplete = false;
mPasscodeID = kDefaultCommissioningPasscodeId;
mLocalMRPConfig = mrpConfig;
mComputeVerifier = false;

SetPeerNodeId(NodeIdFromPAKEKeyId(mPasscodeID));

Expand Down Expand Up @@ -526,7 +515,10 @@ CHIP_ERROR PASESession::SendPBKDFParamResponse(ByteSpan initiatorRandom, bool in

// Update commissioning hash with the pbkdf2 param response that's being sent.
ReturnErrorOnFailure(mCommissioningHash.AddData(ByteSpan{ resp->Start(), resp->DataLength() }));
ReturnErrorOnFailure(SetupSpake2p());
ReturnErrorOnFailure(SetupSpake2p(mIterationCount, ByteSpan(mSalt, mSaltLength)));

size_t sizeof_point = sizeof(mPoint);
ReturnErrorOnFailure(mSpake2p.ComputeL(mPoint, &sizeof_point, mPASEVerifier.mL, kSpake2p_WS_Length));

ReturnErrorOnFailure(
mExchangeCtxt->SendMessage(MsgType::PBKDFParamResponse, std::move(resp), SendFlags(SendMessageFlags::kExpectResponse)));
Expand All @@ -549,8 +541,9 @@ CHIP_ERROR PASESession::HandlePBKDFParamResponse(System::PacketBufferHandle && m
uint8_t random[kPBKDFParamRandomNumberSize];

uint32_t decodeTagIdSeq = 0;
ByteSpan salt;
uint8_t serializedWS[kSpake2p_WS_Length * 2] = { 0 };
uint32_t iterCount = 0;
uint32_t saltLength = 0;
const uint8_t * salt;

ChipLogDetail(SecureChannel, "Received PBKDF param response");

Expand Down Expand Up @@ -586,7 +579,8 @@ CHIP_ERROR PASESession::HandlePBKDFParamResponse(System::PacketBufferHandle && m
}

// TODO - Add a unit test that exercises mHavePBKDFParameters path
salt = ByteSpan(mSalt, mSaltLength);
err = SetupSpake2p(mIterationCount, ByteSpan(mSalt, mSaltLength));
SuccessOrExit(err);
}
else
{
Expand All @@ -596,29 +590,23 @@ CHIP_ERROR PASESession::HandlePBKDFParamResponse(System::PacketBufferHandle && m

SuccessOrExit(err = tlvReader.Next());
VerifyOrExit(TLV::TagNumFromTag(tlvReader.GetTag()) == ++decodeTagIdSeq, err = CHIP_ERROR_INVALID_TLV_TAG);
SuccessOrExit(err = tlvReader.Get(mIterationCount));
SuccessOrExit(err = tlvReader.Get(iterCount));

SuccessOrExit(err = tlvReader.Next());
VerifyOrExit(TLV::TagNumFromTag(tlvReader.GetTag()) == ++decodeTagIdSeq, err = CHIP_ERROR_INVALID_TLV_TAG);
SuccessOrExit(err = tlvReader.Get(salt));
saltLength = tlvReader.GetLength();
SuccessOrExit(err = tlvReader.GetDataPtr(salt));

SuccessOrExit(err = tlvReader.ExitContainer(containerType));

if (tlvReader.Next() != CHIP_END_OF_TLV)
{
SuccessOrExit(err = DecodeMRPParametersIfPresent(TLV::ContextTag(5), tlvReader));
}
}

err = SetupSpake2p();
SuccessOrExit(err);

err = ComputeWS(mSetupPINCode, mIterationCount, salt, sizeof(serializedWS), serializedWS);
SuccessOrExit(err);

err = mSpake2p.BeginProver(nullptr, 0, nullptr, 0, &serializedWS[0], kSpake2p_WS_Length, &serializedWS[kSpake2p_WS_Length],
kSpake2p_WS_Length);
SuccessOrExit(err);
err = SetupSpake2p(iterCount, ByteSpan(salt, saltLength));
SuccessOrExit(err);
}

err = SendMsg1();
SuccessOrExit(err);
Expand Down Expand Up @@ -649,6 +637,8 @@ CHIP_ERROR PASESession::SendMsg1()

constexpr uint8_t kPake1_pA = 1;

ReturnErrorOnFailure(
mSpake2p.BeginProver(nullptr, 0, nullptr, 0, mPASEVerifier.mW0, kSpake2p_WS_Length, mPASEVerifier.mL, kSpake2p_WS_Length));
ReturnErrorOnFailure(mSpake2p.ComputeRoundOne(NULL, 0, X, &X_len));
VerifyOrReturnError(X_len == sizeof(X), CHIP_ERROR_INTERNAL);
ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kPake1_pA), ByteSpan(X)));
Expand Down Expand Up @@ -691,8 +681,8 @@ CHIP_ERROR PASESession::HandleMsg1_and_SendMsg2(System::PacketBufferHandle && ms
VerifyOrExit(TLV::TagNumFromTag(tlvReader.GetTag()) == 1, err = CHIP_ERROR_INVALID_TLV_TAG);
X_len = tlvReader.GetLength();
SuccessOrExit(err = tlvReader.GetDataPtr(X));
SuccessOrExit(err = mSpake2p.BeginVerifier(nullptr, 0, nullptr, 0, mPASEVerifier.mW0, kP256_FE_Length, mPASEVerifier.mL,
kP256_Point_Length));
SuccessOrExit(
err = mSpake2p.BeginVerifier(nullptr, 0, nullptr, 0, mPASEVerifier.mW0, kSpake2p_WS_Length, mPoint, sizeof(mPoint)));

SuccessOrExit(err = mSpake2p.ComputeRoundOne(X, X_len, Y, &Y_len));
VerifyOrReturnError(Y_len == sizeof(Y), CHIP_ERROR_INTERNAL);
Expand Down Expand Up @@ -977,8 +967,8 @@ CHIP_ERROR PASEVerifier::Serialize(MutableByteSpan & outSerialized)
{
VerifyOrReturnError(outSerialized.size() >= kSpake2pSerializedVerifierSize, CHIP_ERROR_INVALID_ARGUMENT);

memcpy(&outSerialized.data()[0], mW0, sizeof(mW0));
memcpy(&outSerialized.data()[sizeof(mW0)], mL, sizeof(mL));
memcpy(&outSerialized.data()[0], mW0, kSpake2p_WS_Length);
memcpy(&outSerialized.data()[kSpake2p_WS_Length], mL, kSpake2p_WS_Length);

outSerialized.reduce_size(kSpake2pSerializedVerifierSize);

Expand All @@ -989,8 +979,8 @@ CHIP_ERROR PASEVerifier::Deserialize(ByteSpan inSerialized)
{
VerifyOrReturnError(inSerialized.size() >= kSpake2pSerializedVerifierSize, CHIP_ERROR_INVALID_ARGUMENT);

memcpy(mW0, &inSerialized.data()[0], sizeof(mW0));
memcpy(mL, &inSerialized.data()[sizeof(mW0)], sizeof(mL));
memcpy(mW0, &inSerialized.data()[0], kSpake2p_WS_Length);
memcpy(mL, &inSerialized.data()[kSpake2p_WS_Length], kSpake2p_WS_Length);

return CHIP_NO_ERROR;
}
Expand Down
23 changes: 14 additions & 9 deletions src/protocols/secure_channel/PASESession.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ constexpr uint32_t kSetupPINCodeUndefinedValue = 0;

using namespace Crypto;

constexpr size_t kSpake2p_WS_Length = kP256_FE_Length + 8;
constexpr size_t kSpake2p_WS_Length = kP256_FE_Length + 8;
constexpr size_t kSpake2pSerializedVerifierSize = kSpake2p_WS_Length * 2;

struct PASESessionSerialized;

Expand All @@ -80,16 +81,16 @@ struct PASESessionSerializable
* This is used when the Verifier should be presented in a serialized form.
* For example, when it is generated using PBKDF function, when stored in the
* memory or when sent over the wire.
* The serialized format is concatentation of 'W0' and 'L' verifier components:
* { PASEVerifier.mW0[kP256_FE_Length], PASEVerifier.mL[kP256_Point_Length] }
* The serialized format is concatentation of 'W0' and 'L' verifier components
* each exactly 'kSpake2p_WS_Length' bytes of length:
* { PASEVerifier.mW0[kSpake2p_WS_Length], PASEVerifier.mL[kSpake2p_WS_Length] }
**/
constexpr size_t kSpake2pSerializedVerifierSize = kP256_FE_Length + kP256_Point_Length;
typedef uint8_t PASEVerifierSerialized[kSpake2pSerializedVerifierSize];

struct PASEVerifier
{
uint8_t mW0[kP256_FE_Length];
uint8_t mL[kP256_Point_Length];
uint8_t mW0[kSpake2p_WS_Length];
uint8_t mL[kSpake2p_WS_Length];

CHIP_ERROR Serialize(MutableByteSpan & outSerialized);
CHIP_ERROR Deserialize(ByteSpan inSerialized);
Expand Down Expand Up @@ -240,10 +241,10 @@ class DLL_EXPORT PASESession : public Messaging::ExchangeDelegate, public Pairin
CHIP_ERROR ValidateReceivedMessage(Messaging::ExchangeContext * exchange, const PayloadHeader & payloadHeader,
System::PacketBufferHandle && msg);

static CHIP_ERROR ComputeWS(uint32_t mySetUpPINCode, uint32_t pbkdf2IterCount, const ByteSpan & salt, uint32_t wsSize,
uint8_t * ws);
static CHIP_ERROR ComputePASEVerifier(uint32_t mySetUpPINCode, uint32_t pbkdf2IterCount, const ByteSpan & salt,
PASEVerifier & verifier);

CHIP_ERROR SetupSpake2p();
CHIP_ERROR SetupSpake2p(uint32_t pbkdf2IterCount, const ByteSpan & salt);

CHIP_ERROR SendPBKDFParamRequest();
CHIP_ERROR HandlePBKDFParamRequest(System::PacketBufferHandle && msg);
Expand Down Expand Up @@ -277,13 +278,17 @@ class DLL_EXPORT PASESession : public Messaging::ExchangeDelegate, public Pairin
#else
Spake2p_P256_SHA256_HKDF_HMAC mSpake2p;
#endif
uint8_t mPoint[kMAX_Point_Length];

/* w0s and w1s */
PASEVerifier mPASEVerifier;

PasscodeId mPasscodeID = kDefaultCommissioningPasscodeId;

uint32_t mSetupPINCode;

bool mComputeVerifier = true;

bool mHavePBKDFParameters = false;

uint8_t mPBKDFLocalRandomData[kPBKDFParamRandomNumberSize];
Expand Down
Loading

0 comments on commit 59379d0

Please sign in to comment.