blob: d0f321863dfe9d960e4fa81bffa6ae7afc16e413 [file] [log] [blame]
/*
*
* Copyright (c) 2020-2024 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.
* 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.
*/
/**
* @file
* mbedTLS based implementation of CHIP crypto primitives
*/
#include "CHIPCryptoPAL.h"
#include <type_traits>
#include <mbedtls/bignum.h>
#include <mbedtls/ccm.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/ecdh.h>
#include <mbedtls/ecdsa.h>
#include <mbedtls/ecp.h>
#include <mbedtls/entropy.h>
#include <mbedtls/error.h>
#include <mbedtls/hkdf.h>
#include <mbedtls/md.h>
#include <mbedtls/pkcs5.h>
#include <mbedtls/sha1.h>
#include <mbedtls/sha256.h>
#if defined(MBEDTLS_X509_CRT_PARSE_C)
#include <mbedtls/x509_crt.h>
#endif // defined(MBEDTLS_X509_CRT_PARSE_C)
#include <mbedtls/oid.h>
#include <mbedtls/x509.h>
#include <mbedtls/x509_csr.h>
#include <lib/core/CHIPSafeCasts.h>
#include <lib/support/BufferWriter.h>
#include <lib/support/BytesToHex.h>
#include <lib/support/CHIPArgParser.hpp>
#include <lib/support/CodeUtils.h>
#include <lib/support/SafeInt.h>
#include <lib/support/SafePointerCast.h>
#include <lib/support/logging/CHIPLogging.h>
#include <string.h>
namespace chip {
namespace Crypto {
#define MAX_ERROR_STR_LEN 128
#define NUM_BYTES_IN_SHA256_HASH 32
// In mbedTLS 3.0.0 direct access to structure fields was replaced with using MBEDTLS_PRIVATE macro.
#if (MBEDTLS_VERSION_NUMBER >= 0x03000000)
#define CHIP_CRYPTO_PAL_PRIVATE(x) MBEDTLS_PRIVATE(x)
#else
#define CHIP_CRYPTO_PAL_PRIVATE(x) x
#endif
#if (MBEDTLS_VERSION_NUMBER >= 0x03000000 && MBEDTLS_VERSION_NUMBER < 0x03010000)
#define CHIP_CRYPTO_PAL_PRIVATE_X509(x) MBEDTLS_PRIVATE(x)
#else
#define CHIP_CRYPTO_PAL_PRIVATE_X509(x) x
#endif
static void _log_mbedTLS_error(int error_code)
{
if (error_code != 0)
{
#if defined(MBEDTLS_ERROR_C)
char error_str[MAX_ERROR_STR_LEN];
mbedtls_strerror(error_code, error_str, sizeof(error_str));
ChipLogError(Crypto, "mbedTLS error: %s", error_str);
#else
// Error codes defined in 16-bit negative hex numbers. Ease lookup by printing likewise
ChipLogError(Crypto, "mbedTLS error: -0x%04X", -static_cast<uint16_t>(error_code));
#endif
}
}
static_assert(kMAX_Hash_SHA256_Context_Size >= sizeof(mbedtls_sha256_context),
"kMAX_Hash_SHA256_Context_Size is too small for the size of underlying mbedtls_sha256_context");
static inline mbedtls_sha256_context * to_inner_hash_sha256_context(HashSHA256OpaqueContext * context)
{
return SafePointerCast<mbedtls_sha256_context *>(context);
}
static int CryptoRNG(void * ctxt, uint8_t * out_buffer, size_t out_length)
{
return (chip::Crypto::DRBG_get_bytes(out_buffer, out_length) == CHIP_NO_ERROR) ? 0 : 1;
}
extern mbedtls_ecp_group_id MapECPGroupId(SupportedECPKeyTypes keyType);
static inline mbedtls_ecp_keypair * to_keypair(P256KeypairContext * context)
{
return SafePointerCast<mbedtls_ecp_keypair *>(context);
}
static inline const mbedtls_ecp_keypair * to_const_keypair(const P256KeypairContext * context)
{
return SafePointerCast<const mbedtls_ecp_keypair *>(context);
}
void ClearSecretData(uint8_t * buf, size_t len)
{
mbedtls_platform_zeroize(buf, len);
}
CHIP_ERROR Initialize_H(P256Keypair * pk, P256PublicKey * mPublicKey, P256KeypairContext * mKeypair)
{
CHIP_ERROR error = CHIP_NO_ERROR;
int result = 0;
size_t pubkey_size = 0;
pk->Clear();
mbedtls_ecp_group_id group = MapECPGroupId(mPublicKey->Type());
mbedtls_ecp_keypair * keypair = to_keypair(mKeypair);
mbedtls_ecp_keypair_init(keypair);
result = mbedtls_ecp_gen_key(group, keypair, CryptoRNG, nullptr);
VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL);
result = mbedtls_ecp_point_write_binary(&keypair->CHIP_CRYPTO_PAL_PRIVATE(grp), &keypair->CHIP_CRYPTO_PAL_PRIVATE(Q),
MBEDTLS_ECP_PF_UNCOMPRESSED, &pubkey_size, Uint8::to_uchar(mPublicKey->Bytes()),
mPublicKey->Length());
VerifyOrExit(result == 0, error = CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrExit(pubkey_size == mPublicKey->Length(), error = CHIP_ERROR_INVALID_ARGUMENT);
keypair = nullptr;
// mInitialized to be set in caller function
// pk.mInitialized = true;
exit:
if (keypair != nullptr)
{
mbedtls_ecp_keypair_free(keypair);
keypair = nullptr;
}
_log_mbedTLS_error(result);
return error;
}
CHIP_ERROR ECDSA_sign_msg_H(P256KeypairContext * mKeypair, const uint8_t * msg, const size_t msg_length,
P256ECDSASignature & out_signature)
{
// To be checked by the caller
// VerifyOrReturnError(mInitialized, CHIP_ERROR_WELL_UNINITIALIZED);
VerifyOrReturnError((msg != nullptr) && (msg_length > 0), CHIP_ERROR_INVALID_ARGUMENT);
uint8_t digest[kSHA256_Hash_Length];
memset(&digest[0], 0, sizeof(digest));
ReturnErrorOnFailure(Hash_SHA256(msg, msg_length, &digest[0]));
#if defined(MBEDTLS_ECDSA_C)
CHIP_ERROR error = CHIP_NO_ERROR;
int result = 0;
mbedtls_mpi r, s;
mbedtls_mpi_init(&r);
mbedtls_mpi_init(&s);
const mbedtls_ecp_keypair * keypair = to_const_keypair(mKeypair);
mbedtls_ecdsa_context ecdsa_ctxt;
mbedtls_ecdsa_init(&ecdsa_ctxt);
result = mbedtls_ecdsa_from_keypair(&ecdsa_ctxt, keypair);
VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL);
result = mbedtls_ecdsa_sign(&ecdsa_ctxt.CHIP_CRYPTO_PAL_PRIVATE(grp), &r, &s, &ecdsa_ctxt.CHIP_CRYPTO_PAL_PRIVATE(d),
Uint8::to_const_uchar(digest), sizeof(digest), CryptoRNG, nullptr);
VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL);
VerifyOrExit((mbedtls_mpi_size(&r) <= kP256_FE_Length) && (mbedtls_mpi_size(&s) <= kP256_FE_Length),
error = CHIP_ERROR_INTERNAL);
// Concatenate r and s to output. Sizes were checked above.
result = mbedtls_mpi_write_binary(&r, out_signature.Bytes() + 0u, kP256_FE_Length);
VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL);
result = mbedtls_mpi_write_binary(&s, out_signature.Bytes() + kP256_FE_Length, kP256_FE_Length);
VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL);
VerifyOrExit(out_signature.SetLength(kP256_ECDSA_Signature_Length_Raw) == CHIP_NO_ERROR, error = CHIP_ERROR_INTERNAL);
exit:
keypair = nullptr;
mbedtls_ecdsa_free(&ecdsa_ctxt);
mbedtls_mpi_free(&s);
mbedtls_mpi_free(&r);
_log_mbedTLS_error(result);
return error;
#else
return CHIP_ERROR_NOT_IMPLEMENTED;
#endif
}
CHIP_ERROR ECDH_derive_secret_H(P256KeypairContext * mKeypair, const P256PublicKey & remote_public_key,
P256ECDHDerivedSecret & out_secret)
{
#if defined(MBEDTLS_ECDH_C)
CHIP_ERROR error = CHIP_NO_ERROR;
int result = 0;
size_t secret_length = (out_secret.Length() == 0) ? out_secret.Capacity() : out_secret.Length();
mbedtls_ecp_group ecp_grp;
mbedtls_ecp_group_init(&ecp_grp);
mbedtls_mpi mpi_secret;
mbedtls_mpi_init(&mpi_secret);
mbedtls_ecp_point ecp_pubkey;
mbedtls_ecp_point_init(&ecp_pubkey);
const mbedtls_ecp_keypair * keypair = to_const_keypair(mKeypair);
// To be checked by the caller
// VerifyOrExit(mInitialized, error = CHIP_ERROR_WELL_UNINITIALIZED);
result = mbedtls_ecp_group_load(&ecp_grp, MapECPGroupId(remote_public_key.Type()));
VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL);
result =
mbedtls_ecp_point_read_binary(&ecp_grp, &ecp_pubkey, Uint8::to_const_uchar(remote_public_key), remote_public_key.Length());
VerifyOrExit(result == 0, error = CHIP_ERROR_INVALID_ARGUMENT);
result =
mbedtls_ecdh_compute_shared(&ecp_grp, &mpi_secret, &ecp_pubkey, &keypair->CHIP_CRYPTO_PAL_PRIVATE(d), CryptoRNG, nullptr);
VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL);
result = mbedtls_mpi_write_binary(&mpi_secret, out_secret.Bytes() /*Uint8::to_uchar(out_secret)*/, secret_length);
VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL);
out_secret.SetLength(secret_length);
exit:
keypair = nullptr;
mbedtls_ecp_group_free(&ecp_grp);
mbedtls_mpi_free(&mpi_secret);
mbedtls_ecp_point_free(&ecp_pubkey);
_log_mbedTLS_error(result);
return error;
#else
return CHIP_ERROR_NOT_IMPLEMENTED;
#endif
}
CHIP_ERROR ECDSA_validate_hash_signature_H(const P256PublicKey * public_key, const uint8_t * hash, const size_t hash_length,
const P256ECDSASignature & signature)
{
#if defined(MBEDTLS_ECDSA_C)
VerifyOrReturnError(hash != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(hash_length == kSHA256_Hash_Length, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(signature.Length() == kP256_ECDSA_Signature_Length_Raw, CHIP_ERROR_INVALID_ARGUMENT);
CHIP_ERROR error = CHIP_NO_ERROR;
int result = 0;
mbedtls_mpi r, s;
mbedtls_mpi_init(&r);
mbedtls_mpi_init(&s);
mbedtls_ecp_keypair keypair;
mbedtls_ecp_keypair_init(&keypair);
mbedtls_ecdsa_context ecdsa_ctxt;
mbedtls_ecdsa_init(&ecdsa_ctxt);
result = mbedtls_ecp_group_load(&keypair.CHIP_CRYPTO_PAL_PRIVATE(grp), MapECPGroupId(public_key->Type()));
VerifyOrExit(result == 0, error = CHIP_ERROR_INVALID_ARGUMENT);
result = mbedtls_ecp_point_read_binary(&keypair.CHIP_CRYPTO_PAL_PRIVATE(grp), &keypair.CHIP_CRYPTO_PAL_PRIVATE(Q),
Uint8::to_const_uchar(*public_key), public_key->Length());
VerifyOrExit(result == 0, error = CHIP_ERROR_INVALID_ARGUMENT);
result = mbedtls_ecdsa_from_keypair(&ecdsa_ctxt, &keypair);
VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL);
// Read the <r, s> big nums from the signature
result = mbedtls_mpi_read_binary(&r, Uint8::to_const_uchar(signature.ConstBytes()) + 0u, kP256_FE_Length);
VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL);
result = mbedtls_mpi_read_binary(&s, Uint8::to_const_uchar(signature.ConstBytes()) + kP256_FE_Length, kP256_FE_Length);
VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL);
result = mbedtls_ecdsa_verify(&ecdsa_ctxt.CHIP_CRYPTO_PAL_PRIVATE(grp), Uint8::to_const_uchar(hash), hash_length,
&ecdsa_ctxt.CHIP_CRYPTO_PAL_PRIVATE(Q), &r, &s);
VerifyOrExit(result == 0, error = CHIP_ERROR_INVALID_SIGNATURE);
exit:
mbedtls_ecdsa_free(&ecdsa_ctxt);
mbedtls_ecp_keypair_free(&keypair);
mbedtls_mpi_free(&s);
mbedtls_mpi_free(&r);
_log_mbedTLS_error(result);
return error;
#else
return CHIP_ERROR_NOT_IMPLEMENTED;
#endif
}
CHIP_ERROR ECDSA_validate_msg_signature_H(const P256PublicKey * public_key, const uint8_t * msg, const size_t msg_length,
const P256ECDSASignature & signature)
{
#if defined(MBEDTLS_ECDSA_C)
VerifyOrReturnError((msg != nullptr) && (msg_length > 0), CHIP_ERROR_INVALID_ARGUMENT);
uint8_t digest[kSHA256_Hash_Length];
memset(&digest[0], 0, sizeof(digest));
ReturnErrorOnFailure(Hash_SHA256(msg, msg_length, &digest[0]));
return ECDSA_validate_hash_signature_H(public_key, &digest[0], sizeof(digest), signature);
#else
return CHIP_ERROR_NOT_IMPLEMENTED;
#endif
}
CHIP_ERROR NewCertificateSigningRequest_H(P256KeypairContext * mKeypair, uint8_t * out_csr, size_t & csr_length)
{
#if defined(MBEDTLS_X509_CSR_WRITE_C)
CHIP_ERROR error = CHIP_NO_ERROR;
int result = 0;
size_t out_length;
mbedtls_x509write_csr csr;
mbedtls_x509write_csr_init(&csr);
mbedtls_pk_context pk;
pk.CHIP_CRYPTO_PAL_PRIVATE(pk_info) = mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY);
pk.CHIP_CRYPTO_PAL_PRIVATE(pk_ctx) = to_keypair(mKeypair);
VerifyOrExit(pk.CHIP_CRYPTO_PAL_PRIVATE(pk_info) != nullptr, error = CHIP_ERROR_INTERNAL);
// To be checked by the caller
// VerifyOrExit(mInitialized, error = CHIP_ERROR_WELL_UNINITIALIZED);
mbedtls_x509write_csr_set_key(&csr, &pk);
mbedtls_x509write_csr_set_md_alg(&csr, MBEDTLS_MD_SHA256);
// TODO: mbedTLS CSR parser fails if the subject name is not set (or if empty).
// CHIP Spec doesn't specify the subject name that can be used.
// Figure out the correct value and update this code.
result = mbedtls_x509write_csr_set_subject_name(&csr, "O=CSR");
VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL);
result = mbedtls_x509write_csr_der(&csr, out_csr, csr_length, CryptoRNG, nullptr);
VerifyOrExit(result > 0, error = CHIP_ERROR_INTERNAL);
VerifyOrExit(CanCastTo<size_t>(result), error = CHIP_ERROR_INTERNAL);
out_length = static_cast<size_t>(result);
result = 0;
VerifyOrExit(out_length <= csr_length, error = CHIP_ERROR_INTERNAL);
if (csr_length != out_length)
{
// mbedTLS API writes the CSR at the end of the provided buffer.
// Let's move it to the start of the buffer.
size_t offset = csr_length - out_length;
memmove(out_csr, &out_csr[offset], out_length);
}
csr_length = out_length;
exit:
mbedtls_x509write_csr_free(&csr);
_log_mbedTLS_error(result);
return error;
#else
ChipLogError(Crypto, "MBEDTLS_X509_CSR_WRITE_C is not enabled. CSR cannot be created");
return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
#endif
}
CHIP_ERROR Serialize_H(const P256KeypairContext mKeypair, const P256PublicKey mPublicKey, P256SerializedKeypair & output)
{
const mbedtls_ecp_keypair * keypair = to_const_keypair(&mKeypair);
size_t len = output.Length() == 0 ? output.Capacity() : output.Length();
Encoding::BufferWriter bbuf(output.Bytes(), len);
uint8_t privkey[kP256_PrivateKey_Length];
CHIP_ERROR error = CHIP_NO_ERROR;
int result = 0;
bbuf.Put(mPublicKey, mPublicKey.Length());
VerifyOrExit(bbuf.Available() == sizeof(privkey), error = CHIP_ERROR_INTERNAL);
VerifyOrExit(mbedtls_mpi_size(&keypair->CHIP_CRYPTO_PAL_PRIVATE(d)) <= bbuf.Available(), error = CHIP_ERROR_INTERNAL);
result = mbedtls_mpi_write_binary(&keypair->CHIP_CRYPTO_PAL_PRIVATE(d), Uint8::to_uchar(privkey), sizeof(privkey));
VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL);
bbuf.Put(privkey, sizeof(privkey));
VerifyOrExit(bbuf.Fit(), error = CHIP_ERROR_BUFFER_TOO_SMALL);
output.SetLength(bbuf.Needed());
exit:
ClearSecretData(privkey, sizeof(privkey));
_log_mbedTLS_error(result);
return error;
}
CHIP_ERROR Deserialize_H(P256Keypair * pk, P256PublicKey * mPublicKey, P256KeypairContext * mKeypair, P256SerializedKeypair & input)
{
Encoding::BufferWriter bbuf(*mPublicKey, mPublicKey->Length());
int result = 0;
CHIP_ERROR error = CHIP_NO_ERROR;
pk->Clear();
mbedtls_ecp_keypair * keypair = to_keypair(mKeypair);
mbedtls_ecp_keypair_init(keypair);
result = mbedtls_ecp_group_load(&keypair->CHIP_CRYPTO_PAL_PRIVATE(grp), MapECPGroupId(mPublicKey->Type()));
VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL);
VerifyOrExit(input.Length() == mPublicKey->Length() + kP256_PrivateKey_Length, error = CHIP_ERROR_INVALID_ARGUMENT);
bbuf.Put(input.ConstBytes(), mPublicKey->Length());
VerifyOrExit(bbuf.Fit(), error = CHIP_ERROR_NO_MEMORY);
result = mbedtls_ecp_point_read_binary(&keypair->CHIP_CRYPTO_PAL_PRIVATE(grp), &keypair->CHIP_CRYPTO_PAL_PRIVATE(Q),
Uint8::to_const_uchar(*mPublicKey), mPublicKey->Length());
VerifyOrExit(result == 0, error = CHIP_ERROR_INVALID_ARGUMENT);
{
const uint8_t * privkey = input.ConstBytes() /*Uint8::to_const_uchar(input)*/ + mPublicKey->Length();
result = mbedtls_mpi_read_binary(&keypair->CHIP_CRYPTO_PAL_PRIVATE(d), privkey, kP256_PrivateKey_Length);
VerifyOrExit(result == 0, error = CHIP_ERROR_INVALID_ARGUMENT);
}
exit:
_log_mbedTLS_error(result);
return error;
}
CHIP_ERROR HKDF_SHA256_H(const uint8_t * secret, const size_t secret_length, const uint8_t * salt, const size_t salt_length,
const uint8_t * info, const size_t info_length, uint8_t * out_buffer, size_t out_length)
{
VerifyOrReturnError(secret != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(secret_length > 0, CHIP_ERROR_INVALID_ARGUMENT);
// Salt is optional
if (salt_length > 0)
{
VerifyOrReturnError(salt != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
}
VerifyOrReturnError(info_length > 0, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(info != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(out_length > 0, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(out_buffer != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
const mbedtls_md_info_t * const md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
VerifyOrReturnError(md != nullptr, CHIP_ERROR_INTERNAL);
const int result = mbedtls_hkdf(md, Uint8::to_const_uchar(salt), salt_length, Uint8::to_const_uchar(secret), secret_length,
Uint8::to_const_uchar(info), info_length, Uint8::to_uchar(out_buffer), out_length);
_log_mbedTLS_error(result);
VerifyOrReturnError(result == 0, CHIP_ERROR_INTERNAL);
return CHIP_NO_ERROR;
}
CHIP_ERROR HMAC_SHA256_h(const uint8_t * key, size_t key_length, const uint8_t * message, size_t message_length,
uint8_t * out_buffer, size_t out_length)
{
VerifyOrReturnError(key != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(key_length > 0, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(message != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(message_length > 0, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(out_length >= kSHA256_Hash_Length, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(out_buffer != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
const mbedtls_md_info_t * const md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
VerifyOrReturnError(md != nullptr, CHIP_ERROR_INTERNAL);
const int result =
mbedtls_md_hmac(md, Uint8::to_const_uchar(key), key_length, Uint8::to_const_uchar(message), message_length, out_buffer);
_log_mbedTLS_error(result);
VerifyOrReturnError(result == 0, CHIP_ERROR_INTERNAL);
return CHIP_NO_ERROR;
}
} // namespace Crypto
} // namespace chip