From 60565eac7cfbf541ddbba7b135a95e9ac969bdbf Mon Sep 17 00:00:00 2001 From: Evgeni Margolis Date: Fri, 11 Feb 2022 00:19:12 -0800 Subject: [PATCH] Updated PASEVerifier Format to Match Spec. In the current SDK implementation the PASEVerifier format is (w0s, w1s). The spec defines PASEVerifier on the device side should have (w0, L) format. This is also the format that devices should store PASEVerifier in the persisted memory. There are some minor changes to adjust to the new implementation. Also updated test vectors and spake2p tool now generates PASEVerifier in a correct format. --- src/crypto/CHIPCryptoPAL.cpp | 10 +- src/crypto/CHIPCryptoPAL.h | 18 ++- src/include/platform/CHIPDeviceConfig.h | 3 +- src/protocols/secure_channel/PASESession.cpp | 110 ++++++++++-------- src/protocols/secure_channel/PASESession.h | 23 ++-- .../secure_channel/tests/TestPASESession.cpp | 34 +++--- 6 files changed, 115 insertions(+), 83 deletions(-) diff --git a/src/crypto/CHIPCryptoPAL.cpp b/src/crypto/CHIPCryptoPAL.cpp index a1664c554812a5..795e7a8a6cb65a 100644 --- a/src/crypto/CHIPCryptoPAL.cpp +++ b/src/crypto/CHIPCryptoPAL.cpp @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020-2022 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. @@ -507,6 +507,14 @@ 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); diff --git a/src/crypto/CHIPCryptoPAL.h b/src/crypto/CHIPCryptoPAL.h index f560ae676b6983..1fc36ddd9fc9dd 100644 --- a/src/crypto/CHIPCryptoPAL.h +++ b/src/crypto/CHIPCryptoPAL.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020-2022 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. @@ -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 (an output from the PBKDF). + * @param w0in The input w0 (a parameter baked into the device or computed with ComputeW0). * @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. @@ -1045,6 +1045,18 @@ 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 * @@ -1208,6 +1220,8 @@ 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: diff --git a/src/include/platform/CHIPDeviceConfig.h b/src/include/platform/CHIPDeviceConfig.h index bb34f8368dcd9d..5ac41ffbe03f0c 100644 --- a/src/include/platform/CHIPDeviceConfig.h +++ b/src/include/platform/CHIPDeviceConfig.h @@ -911,7 +911,8 @@ */ #ifndef CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_VERIFIER #define CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_VERIFIER \ - "q6YMMEFrj0F39eFq1RTP2Vd1E/Av1gUGsQSdDyxzEAEOXkC/2GtO9oGoi3Hp4qhTmFp975Fuow4BuHIvv30OOIVsEs1kwiW7JO8hQX4OROU=" + "uWFwqugDNGiEck/po7KHwwMwwqZgN10XuyBajPGuyzUEV/iree4lOrao5GuwnlQ65CJzbeUB49s31EH+NEkg0JVI5MGCQGMMT/SRPFNRODm3wH/MBiehuFc6FJ/" \ + "NH6Rmzw==" #endif #else diff --git a/src/protocols/secure_channel/PASESession.cpp b/src/protocols/secure_channel/PASESession.cpp index 76ca4f8888812e..1db4db19f934af 100644 --- a/src/protocols/secure_channel/PASESession.cpp +++ b/src/protocols/secure_channel/PASESession.cpp @@ -81,7 +81,6 @@ 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; @@ -98,7 +97,6 @@ void PASESession::Clear() } mKeLen = sizeof(mKe); mPairingComplete = false; - mComputeVerifier = true; PairingSession::Clear(); CloseExchange(); } @@ -205,54 +203,68 @@ CHIP_ERROR PASESession::Init(uint16_t mySessionId, uint32_t setupCode, SessionEs ChipLogDetail(SecureChannel, "Assigned local session key ID %d", mySessionId); SetLocalSessionId(mySessionId); - mSetupPINCode = setupCode; - mComputeVerifier = true; + mSetupPINCode = setupCode; return CHIP_NO_ERROR; } -CHIP_ERROR PASESession::ComputePASEVerifier(uint32_t setUpPINCode, uint32_t pbkdf2IterCount, const ByteSpan & salt, - PASEVerifier & verifier) +CHIP_ERROR PASESession::ComputeWS(uint32_t setUpPINCode, uint32_t pbkdf2IterCount, const ByteSpan & salt, uint32_t wsSize, + uint8_t * ws) { - 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); - PASEVerifierSerialized serializedVerifier; - ReturnErrorOnFailure(mPBKDF.pbkdf2_sha256(littleEndianSetupPINCode, sizeof(littleEndianSetupPINCode), salt.data(), salt.size(), - pbkdf2IterCount, sizeof(PASEVerifierSerialized), serializedVerifier)); - return verifier.Deserialize(ByteSpan(serializedVerifier)); + 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); } CHIP_ERROR PASESession::GeneratePASEVerifier(PASEVerifier & verifier, uint32_t pbkdf2IterCount, const ByteSpan & salt, - bool useRandomPIN, uint32_t & setupPIN) + bool useRandomPIN, uint32_t & setupPINCode) { + TRACE_EVENT_SCOPE("GeneratePASEVerifier", "PASESession"); + if (useRandomPIN) { - ReturnErrorOnFailure(DRBG_get_bytes(reinterpret_cast(&setupPIN), sizeof(setupPIN))); + ReturnErrorOnFailure(DRBG_get_bytes(reinterpret_cast(&setupPINCode), sizeof(setupPINCode))); // Passcodes shall be restricted to the values 00000001 to 99999998 in decimal, see 5.1.1.6 - setupPIN = (setupPIN % kSetupPINCodeMaximumValue) + 1; + setupPINCode = (setupPINCode % kSetupPINCodeMaximumValue) + 1; } - return PASESession::ComputePASEVerifier(setupPIN, pbkdf2IterCount, salt, verifier); + 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; } -CHIP_ERROR PASESession::SetupSpake2p(uint32_t pbkdf2IterCount, const ByteSpan & salt) +CHIP_ERROR PASESession::SetupSpake2p() { 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)); @@ -295,7 +307,6 @@ CHIP_ERROR PASESession::WaitForPairing(const PASEVerifier & verifier, uint32_t p mPairingComplete = false; mPasscodeID = kDefaultCommissioningPasscodeId; mLocalMRPConfig = mrpConfig; - mComputeVerifier = false; SetPeerNodeId(NodeIdFromPAKEKeyId(mPasscodeID)); @@ -515,10 +526,7 @@ 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(mIterationCount, ByteSpan(mSalt, mSaltLength))); - - size_t sizeof_point = sizeof(mPoint); - ReturnErrorOnFailure(mSpake2p.ComputeL(mPoint, &sizeof_point, mPASEVerifier.mL, kSpake2p_WS_Length)); + ReturnErrorOnFailure(SetupSpake2p()); ReturnErrorOnFailure( mExchangeCtxt->SendMessage(MsgType::PBKDFParamResponse, std::move(resp), SendFlags(SendMessageFlags::kExpectResponse))); @@ -541,9 +549,8 @@ CHIP_ERROR PASESession::HandlePBKDFParamResponse(System::PacketBufferHandle && m uint8_t random[kPBKDFParamRandomNumberSize]; uint32_t decodeTagIdSeq = 0; - uint32_t iterCount = 0; - uint32_t saltLength = 0; - const uint8_t * salt; + ByteSpan salt; + uint8_t serializedWS[kSpake2p_WS_Length * 2] = { 0 }; ChipLogDetail(SecureChannel, "Received PBKDF param response"); @@ -579,8 +586,7 @@ CHIP_ERROR PASESession::HandlePBKDFParamResponse(System::PacketBufferHandle && m } // TODO - Add a unit test that exercises mHavePBKDFParameters path - err = SetupSpake2p(mIterationCount, ByteSpan(mSalt, mSaltLength)); - SuccessOrExit(err); + salt = ByteSpan(mSalt, mSaltLength); } else { @@ -590,12 +596,11 @@ 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(iterCount)); + SuccessOrExit(err = tlvReader.Get(mIterationCount)); SuccessOrExit(err = tlvReader.Next()); VerifyOrExit(TLV::TagNumFromTag(tlvReader.GetTag()) == ++decodeTagIdSeq, err = CHIP_ERROR_INVALID_TLV_TAG); - saltLength = tlvReader.GetLength(); - SuccessOrExit(err = tlvReader.GetDataPtr(salt)); + SuccessOrExit(err = tlvReader.Get(salt)); SuccessOrExit(err = tlvReader.ExitContainer(containerType)); @@ -603,11 +608,18 @@ CHIP_ERROR PASESession::HandlePBKDFParamResponse(System::PacketBufferHandle && m { SuccessOrExit(err = DecodeMRPParametersIfPresent(TLV::ContextTag(5), tlvReader)); } - - err = SetupSpake2p(iterCount, ByteSpan(salt, saltLength)); - SuccessOrExit(err); } + 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 = SendMsg1(); SuccessOrExit(err); @@ -637,8 +649,6 @@ 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))); @@ -681,8 +691,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, kSpake2p_WS_Length, mPoint, sizeof(mPoint))); + SuccessOrExit(err = mSpake2p.BeginVerifier(nullptr, 0, nullptr, 0, mPASEVerifier.mW0, kP256_FE_Length, mPASEVerifier.mL, + kP256_Point_Length)); SuccessOrExit(err = mSpake2p.ComputeRoundOne(X, X_len, Y, &Y_len)); VerifyOrReturnError(Y_len == sizeof(Y), CHIP_ERROR_INTERNAL); @@ -967,8 +977,8 @@ CHIP_ERROR PASEVerifier::Serialize(MutableByteSpan & outSerialized) { VerifyOrReturnError(outSerialized.size() >= kSpake2pSerializedVerifierSize, CHIP_ERROR_INVALID_ARGUMENT); - memcpy(&outSerialized.data()[0], mW0, kSpake2p_WS_Length); - memcpy(&outSerialized.data()[kSpake2p_WS_Length], mL, kSpake2p_WS_Length); + memcpy(&outSerialized.data()[0], mW0, sizeof(mW0)); + memcpy(&outSerialized.data()[sizeof(mW0)], mL, sizeof(mL)); outSerialized.reduce_size(kSpake2pSerializedVerifierSize); @@ -979,8 +989,8 @@ CHIP_ERROR PASEVerifier::Deserialize(ByteSpan inSerialized) { VerifyOrReturnError(inSerialized.size() >= kSpake2pSerializedVerifierSize, CHIP_ERROR_INVALID_ARGUMENT); - memcpy(mW0, &inSerialized.data()[0], kSpake2p_WS_Length); - memcpy(mL, &inSerialized.data()[kSpake2p_WS_Length], kSpake2p_WS_Length); + memcpy(mW0, &inSerialized.data()[0], sizeof(mW0)); + memcpy(mL, &inSerialized.data()[sizeof(mW0)], sizeof(mL)); return CHIP_NO_ERROR; } diff --git a/src/protocols/secure_channel/PASESession.h b/src/protocols/secure_channel/PASESession.h index e9a7580c113afb..8cd01feb909826 100644 --- a/src/protocols/secure_channel/PASESession.h +++ b/src/protocols/secure_channel/PASESession.h @@ -62,8 +62,7 @@ constexpr uint32_t kSetupPINCodeUndefinedValue = 0; using namespace Crypto; -constexpr size_t kSpake2p_WS_Length = kP256_FE_Length + 8; -constexpr size_t kSpake2pSerializedVerifierSize = kSpake2p_WS_Length * 2; +constexpr size_t kSpake2p_WS_Length = kP256_FE_Length + 8; struct PASESessionSerialized; @@ -81,16 +80,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 - * each exactly 'kSpake2p_WS_Length' bytes of length: - * { PASEVerifier.mW0[kSpake2p_WS_Length], PASEVerifier.mL[kSpake2p_WS_Length] } + * The serialized format is concatentation of 'W0' and 'L' verifier components: + * { PASEVerifier.mW0[kP256_FE_Length], PASEVerifier.mL[kP256_Point_Length] } **/ +constexpr size_t kSpake2pSerializedVerifierSize = kP256_FE_Length + kP256_Point_Length; typedef uint8_t PASEVerifierSerialized[kSpake2pSerializedVerifierSize]; struct PASEVerifier { - uint8_t mW0[kSpake2p_WS_Length]; - uint8_t mL[kSpake2p_WS_Length]; + uint8_t mW0[kP256_FE_Length]; + uint8_t mL[kP256_Point_Length]; CHIP_ERROR Serialize(MutableByteSpan & outSerialized); CHIP_ERROR Deserialize(ByteSpan inSerialized); @@ -241,10 +240,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 ComputePASEVerifier(uint32_t mySetUpPINCode, uint32_t pbkdf2IterCount, const ByteSpan & salt, - PASEVerifier & verifier); + static CHIP_ERROR ComputeWS(uint32_t mySetUpPINCode, uint32_t pbkdf2IterCount, const ByteSpan & salt, uint32_t wsSize, + uint8_t * ws); - CHIP_ERROR SetupSpake2p(uint32_t pbkdf2IterCount, const ByteSpan & salt); + CHIP_ERROR SetupSpake2p(); CHIP_ERROR SendPBKDFParamRequest(); CHIP_ERROR HandlePBKDFParamRequest(System::PacketBufferHandle && msg); @@ -278,17 +277,13 @@ 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]; diff --git a/src/protocols/secure_channel/tests/TestPASESession.cpp b/src/protocols/secure_channel/tests/TestPASESession.cpp index 3b65431dc0b558..c8b63b1a8b4525 100644 --- a/src/protocols/secure_channel/tests/TestPASESession.cpp +++ b/src/protocols/secure_channel/tests/TestPASESession.cpp @@ -44,23 +44,27 @@ using namespace chip::Protocols; namespace { // Test Set #01 of Spake2p Parameters (PIN Code, Iteration Count, Salt, and matching Verifier): -constexpr uint32_t sTestSpake2p01_PinCode = 20202021; -constexpr uint32_t sTestSpake2p01_IterationCount = 1000; -constexpr uint8_t sTestSpake2p01_Salt[] = { 0x53, 0x50, 0x41, 0x4B, 0x45, 0x32, 0x50, 0x20, +constexpr uint32_t sTestSpake2p01_PinCode = 20202021; +constexpr uint32_t sTestSpake2p01_IterationCount = 1000; +constexpr uint8_t sTestSpake2p01_Salt[] = { 0x53, 0x50, 0x41, 0x4B, 0x45, 0x32, 0x50, 0x20, 0x4B, 0x65, 0x79, 0x20, 0x53, 0x61, 0x6C, 0x74 }; -constexpr PASEVerifier sTestSpake2p01_PASEVerifier = { .mW0 = { 0xab, 0xa6, 0x0c, 0x30, 0x41, 0x6b, 0x8f, 0x41, 0x77, 0xf5, - 0xe1, 0x6a, 0xd5, 0x14, 0xcf, 0xd9, 0x57, 0x75, 0x13, 0xf0, - 0x2f, 0xd6, 0x05, 0x06, 0xb1, 0x04, 0x9d, 0x0f, 0x2c, 0x73, - 0x10, 0x01, 0x0e, 0x5e, 0x40, 0xbf, 0xd8, 0x6b, 0x4e, 0xf6 }, - .mL = { 0x81, 0xa8, 0x8b, 0x71, 0xe9, 0xe2, 0xa8, 0x53, 0x98, 0x5a, - 0x7d, 0xef, 0x91, 0x6e, 0xa3, 0x0e, 0x01, 0xb8, 0x72, 0x2f, - 0xbf, 0x7d, 0x0e, 0x38, 0x85, 0x6c, 0x12, 0xcd, 0x64, 0xc2, - 0x25, 0xbb, 0x24, 0xef, 0x21, 0x41, 0x7e, 0x0e, 0x44, 0xe5 } }; +constexpr PASEVerifier sTestSpake2p01_PASEVerifier = { .mW0 = { + 0xB9, 0x61, 0x70, 0xAA, 0xE8, 0x03, 0x34, 0x68, 0x84, 0x72, 0x4F, 0xE9, 0xA3, 0xB2, 0x87, 0xC3, + 0x03, 0x30, 0xC2, 0xA6, 0x60, 0x37, 0x5D, 0x17, 0xBB, 0x20, 0x5A, 0x8C, 0xF1, 0xAE, 0xCB, 0x35, +}, + .mL = { + 0x04, 0x57, 0xF8, 0xAB, 0x79, 0xEE, 0x25, 0x3A, 0xB6, 0xA8, 0xE4, 0x6B, 0xB0, 0x9E, 0x54, 0x3A, + 0xE4, 0x22, 0x73, 0x6D, 0xE5, 0x01, 0xE3, 0xDB, 0x37, 0xD4, 0x41, 0xFE, 0x34, 0x49, 0x20, 0xD0, + 0x95, 0x48, 0xE4, 0xC1, 0x82, 0x40, 0x63, 0x0C, 0x4F, 0xF4, 0x91, 0x3C, 0x53, 0x51, 0x38, 0x39, + 0xB7, 0xC0, 0x7F, 0xCC, 0x06, 0x27, 0xA1, 0xB8, 0x57, 0x3A, 0x14, 0x9F, 0xCD, 0x1F, 0xA4, 0x66, + 0xCF +} }; constexpr PASEVerifierSerialized sTestSpake2p01_SerializedVerifier = { - 0xab, 0xa6, 0x0c, 0x30, 0x41, 0x6b, 0x8f, 0x41, 0x77, 0xf5, 0xe1, 0x6a, 0xd5, 0x14, 0xcf, 0xd9, 0x57, 0x75, 0x13, 0xf0, - 0x2f, 0xd6, 0x05, 0x06, 0xb1, 0x04, 0x9d, 0x0f, 0x2c, 0x73, 0x10, 0x01, 0x0e, 0x5e, 0x40, 0xbf, 0xd8, 0x6b, 0x4e, 0xf6, - 0x81, 0xa8, 0x8b, 0x71, 0xe9, 0xe2, 0xa8, 0x53, 0x98, 0x5a, 0x7d, 0xef, 0x91, 0x6e, 0xa3, 0x0e, 0x01, 0xb8, 0x72, 0x2f, - 0xbf, 0x7d, 0x0e, 0x38, 0x85, 0x6c, 0x12, 0xcd, 0x64, 0xc2, 0x25, 0xbb, 0x24, 0xef, 0x21, 0x41, 0x7e, 0x0e, 0x44, 0xe5 + 0xB9, 0x61, 0x70, 0xAA, 0xE8, 0x03, 0x34, 0x68, 0x84, 0x72, 0x4F, 0xE9, 0xA3, 0xB2, 0x87, 0xC3, 0x03, 0x30, 0xC2, 0xA6, + 0x60, 0x37, 0x5D, 0x17, 0xBB, 0x20, 0x5A, 0x8C, 0xF1, 0xAE, 0xCB, 0x35, 0x04, 0x57, 0xF8, 0xAB, 0x79, 0xEE, 0x25, 0x3A, + 0xB6, 0xA8, 0xE4, 0x6B, 0xB0, 0x9E, 0x54, 0x3A, 0xE4, 0x22, 0x73, 0x6D, 0xE5, 0x01, 0xE3, 0xDB, 0x37, 0xD4, 0x41, 0xFE, + 0x34, 0x49, 0x20, 0xD0, 0x95, 0x48, 0xE4, 0xC1, 0x82, 0x40, 0x63, 0x0C, 0x4F, 0xF4, 0x91, 0x3C, 0x53, 0x51, 0x38, 0x39, + 0xB7, 0xC0, 0x7F, 0xCC, 0x06, 0x27, 0xA1, 0xB8, 0x57, 0x3A, 0x14, 0x9F, 0xCD, 0x1F, 0xA4, 0x66, 0xCF }; class PASETestLoopbackTransport : public Test::LoopbackTransport