blob: 163769037005d5f8447cadf10a38916c1ab994f5 [file] [log] [blame]
/*
* 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 <psa/crypto.h>
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 w0sin The input w0s (an output from the PBKDF).
* @param w0sin_len The input w0s length.
* @param w1sin The input w1s (an output from the PBKDF).
* @param w1sin_len The input w1s 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 * w0sin, size_t w0sin_len, const uint8_t * w1sin,
size_t w1sin_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