/* * Copyright (c) 2024 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "CHIPCryptoPAL.h" #include namespace chip { namespace Crypto { /** * The below class implements the draft 01 version of the Spake2+ protocol as * defined in https://www.ietf.org/id/draft-bar-cfrg-spake2plus-01.html. * * The following describes the protocol flows: * * Commissioner Accessory * ------------ --------- * * Init * BeginProver * ComputeRoundOne -------------> * Init * BeginVerifier * /- ComputeRoundOne * <------------- ComputeRoundTwo * ComputeRoundTwo -------------> * KeyConfirm KeyConfirm * GetKeys GetKeys * **/ class PSASpake2p_P256_SHA256_HKDF_HMAC { public: /** * @brief Initialize Spake2+ with some context specific information. * * @param context The context is arbitrary but should include information about the * protocol being run, contain the transcript for negotiation, include * the PKBDF parameters, etc. * @param context_len The length of the context. * * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise **/ CHIP_ERROR Init(const uint8_t * context, size_t context_len); /** * @brief Free Spake2+ underlying objects. **/ void Clear(); /** * @brief Start the Spake2+ process as a verifier (i.e. an accessory being provisioned). * * @param my_identity The verifier identity. May be NULL if identities are not established. * @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_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. * * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise **/ CHIP_ERROR BeginVerifier(const uint8_t * my_identity, size_t my_identity_len, const uint8_t * peer_identity, size_t peer_identity_len, const uint8_t * w0in, size_t w0in_len, const uint8_t * Lin, size_t Lin_len); /** * @brief Start the Spake2+ process as a prover (i.e. a commissioner). * * @param my_identity The prover identity. May be NULL if identities are not established. * @param my_identity_len The prover 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_len The input w0 length. * @param w1in The input w1 (an output from the PBKDF). * @param w1in_len The input w1 length. * * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise **/ CHIP_ERROR BeginProver(const uint8_t * my_identity, size_t my_identity_len, const uint8_t * peer_identity, size_t peer_identity_len, const uint8_t * w0in, size_t w0in_len, const uint8_t * w1in, size_t w1in_len); /** * @brief Compute the first round of the protocol. * * @param pab X value from commissioner. * @param pab_len X length. * @param out The output first round Spake2+ contribution. * @param out_len The output first round Spake2+ contribution length. * * The out_len parameter is expected to point to an integer that holds * the size of the buffer to put the first round Spake2+ contribution. * After successful execution of this method, the variable is set to the * actual size of the generated output. * * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise **/ CHIP_ERROR ComputeRoundOne(const uint8_t * pab, size_t pab_len, uint8_t * out, size_t * out_len); /** * @brief Compute the second round of the protocol. * * @param in The peer first round Spake2+ contribution. * @param in_len The peer first round Spake2+ contribution length. * @param out The output second round Spake2+ contribution. * @param out_len The output second round Spake2+ contribution length. * * The out_len parameter is expected to point to an integer that holds * the size of the buffer to put the second round Spake2+ contribution. * After successful execution of this method, the variable is set to the * actual size of the generated output. * * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise **/ CHIP_ERROR ComputeRoundTwo(const uint8_t * in, size_t in_len, uint8_t * out, size_t * out_len); /** * @brief Confirm that each party computed the same keys. * * @param in The peer second round Spake2+ contribution. * @param in_len The peer second round Spake2+ contribution length. * * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise **/ CHIP_ERROR KeyConfirm(const uint8_t * in, size_t in_len); /** * @brief Return the shared secret. * * @param out The output secret. * @param out_len The output secret length. * * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise **/ CHIP_ERROR GetKeys(SessionKeystore & keystore, HkdfKeyHandle & key); private: psa_pake_operation_t mOperation = PSA_PAKE_OPERATION_INIT; psa_key_id_t mKey = PSA_KEY_ID_NULL; psa_pake_role_t mRole; uint8_t mContext[kSHA256_Hash_Length]; size_t mContextLen; }; } // namespace Crypto } // namespace chip