/* * Copyright (c) 2022 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 #include namespace chip { namespace DeviceLayer { namespace Internal { typedef uint16_t EFR32OpaqueKeyId; inline constexpr EFR32OpaqueKeyId kEFR32OpaqueKeyIdUnknown = 0xFFFFU; // Do not modify, will impact existing deployments inline constexpr EFR32OpaqueKeyId kEFR32OpaqueKeyIdVolatile = 0xFFFEU; // Do not modify, will impact existing deployments inline constexpr EFR32OpaqueKeyId kEFR32OpaqueKeyIdPersistentMin = 0x0U; // Do not modify, will impact existing deployments inline constexpr EFR32OpaqueKeyId kEFR32OpaqueKeyIdPersistentMax = 0x1FFU; // Do not decrease, will impact existing deployments enum class EFR32OpaqueKeyUsages : uint8_t { ECDSA_P256_SHA256 = 0, ECDH_P256 = 1, }; /** * @brief Base class for opaque keys * * Deriving from this class allows using it as a base class for operations * which don't expose the private key independant of key size. **/ class EFR32OpaqueKeypair { public: EFR32OpaqueKeypair(); virtual ~EFR32OpaqueKeypair(); /** * @brief Load a keypair with given key ID * * If no key exists under the given ID, an error is returned * and the object is unusable for operations. * * @param key_id key ID under which this key was created * * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise **/ CHIP_ERROR Load(EFR32OpaqueKeyId key_id); /** * @brief Create a new keypair with given ID and usage * * If a key already exists under the given ID, an error is returned * and no new key is created. * * @param key_id key ID under which to store this key. Set to 0 * for a non-persistent key which gets destructed * when the lifetime of this object ends, or set * to any other value to store the key under that * ID. * * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise **/ CHIP_ERROR Create(EFR32OpaqueKeyId key_id, EFR32OpaqueKeyUsages usage); /** * @brief Get the public key for this keypair * * @param output Output buffer to put public key (in 0x04 || X || Y format) * @param output_size Size of \p output * @param output_length Amount of bytes put in \p output on success * * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise **/ CHIP_ERROR GetPublicKey(uint8_t * output, size_t output_size, size_t * output_length) const; /** * @brief Get the key ID for this keypair * * @return Returns kEFR32OpaqueKeyIdUnknown for an uninitialised/invalid * key, kEFR32OpaqueKeyIdVolatile for a volatile key, and a key * ID in the range [kEFR32OpaqueKeyIdPersistentMin, kEFR32OpaqueKeyIdPersistentMax] * for valid persistent keys. **/ EFR32OpaqueKeyId GetKeyId() const; /** * @brief Use this keypair to sign a message using the ECDSA-SHA256 algorithm * * @param msg Message buffer to sign * @param msg_len Size of \p msg in bytes * @param output Output buffer to write signature to. Signature * is in raw format (i.e. binary concatenation of * r and s) * @param output_size Size of output buffer * @param output_length Amount of bytes written into output buffer * * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise **/ CHIP_ERROR Sign(const uint8_t * msg, size_t msg_len, uint8_t * output, size_t output_size, size_t * output_length) const; /** * @brief Use this keypair to derive a key using the raw ECDH algorithm * * @param their_key Buffer containing raw uncompressed public key * of party to derive with * @param their_key_len Size of \p their_key in bytes * @param output Output buffer to write derived bytes to * @param output_size Size of output buffer * @param output_length Amount of bytes written into output buffer * * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise **/ CHIP_ERROR Derive(const uint8_t * their_key, size_t their_key_len, uint8_t * output, size_t output_size, size_t * output_length) const; /** * @brief Delete the keypair from storage * * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise **/ CHIP_ERROR DestroyKey(); protected: void * mContext = nullptr; bool mHasKey = false; bool mIsPersistent = false; uint8_t * mPubkeyRef = nullptr; size_t mPubkeySize = 0; size_t mPubkeyLength = 0; }; /** * @brief Derived class of P256Keypair for using opaque keys * * The signature and compiled form of this class is suboptimal due to how * the P256Keypair isn't really an abstract interface, but rather partly * interface / partly implementation. Future optimisation should look at * converting P256Keypair to a fully abstract interface. **/ class EFR32OpaqueP256Keypair : public chip::Crypto::P256Keypair, public EFR32OpaqueKeypair { public: EFR32OpaqueP256Keypair(); ~EFR32OpaqueP256Keypair() override; /** * @brief Initialize the keypair. * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise **/ CHIP_ERROR Initialize(chip::Crypto::ECPKeyTarget key_target) override; /** * @brief Serialize the keypair (unsupported on opaque keys) * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise **/ CHIP_ERROR Serialize(chip::Crypto::P256SerializedKeypair & output) const override; /** * @brief Deserialize the keypair (unsupported on opaque keys) * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise **/ CHIP_ERROR Deserialize(chip::Crypto::P256SerializedKeypair & input) override; /** * @brief Generate a new Certificate Signing Request (CSR). * @param csr Newly generated CSR in DER format * @param csr_length The caller provides the length of input buffer (csr). The function returns the actual length of generated *CSR. * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise **/ CHIP_ERROR NewCertificateSigningRequest(uint8_t * csr, size_t & csr_length) const override; /** * @brief A function to sign a msg using ECDSA * @param msg Message that needs to be signed * @param msg_length Length of message * @param out_signature Buffer that will hold the output signature. The signature consists of: 2 EC elements (r and s), * in raw point form (see SEC1). * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise **/ CHIP_ERROR ECDSA_sign_msg(const uint8_t * msg, size_t msg_length, chip::Crypto::P256ECDSASignature & out_signature) const override; /** * @brief A function to derive a shared secret using ECDH * * This implements the CHIP_Crypto_ECDH(PrivateKey myPrivateKey, PublicKey theirPublicKey) cryptographic primitive * from the specification, using this class's private key from `mKeypair` as `myPrivateKey` and the remote * public key from `remote_public_key` as `theirPublicKey`. * * @param remote_public_key Public key of remote peer with which we are trying to establish secure channel. remote_public_key is * ASN.1 DER encoded as padded big-endian field elements as described in SEC 1: Elliptic Curve Cryptography * [https://www.secg.org/sec1-v2.pdf] * @param out_secret Buffer to write out secret into. This is a byte array representing the x coordinate of the shared secret. * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise **/ CHIP_ERROR ECDH_derive_secret(const chip::Crypto::P256PublicKey & remote_public_key, chip::Crypto::P256ECDHDerivedSecret & out_secret) const override; /** @brief Return public key for the keypair. **/ const chip::Crypto::P256PublicKey & Pubkey() const override; private: chip::Crypto::P256PublicKey mPubKey; }; } // namespace Internal } // namespace DeviceLayer } // namespace chip