init:初始框架

This commit is contained in:
SkyLi
2026-06-06 20:50:54 +08:00
commit b5be64b642
685 changed files with 398844 additions and 0 deletions
@@ -0,0 +1,68 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2019 Linaro Limited
*
* 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.
*/
#ifndef H_BOOTUTIL_BENCH_H__
#define H_BOOTUTIL_BENCH_H__
#include "ignore.h"
#ifdef MCUBOOT_USE_BENCH
/* The platform-specific benchmark code should define a
* `bench_state_t` type that holds the information needed for the
* benchmark. This is generally something small, such as an integer
* holding the state. This should also define plat_bench_start and
* plat_bench_end, which likely have to be macros so that log messages
* come from the right place in the code. */
#include <platform-bench.h>
/*
* These are simple barrier-type benchmarks. If a platform has
* benchmarks that are enabled, calling `boot_bench_start()` before a
* block of code and `boot_bench_stop()` after that block of code will
* present this information in some manner (usually through logging).
* The details of what is measured and how it is printed are specific
* to the platform and the implementation. A pointer to the
* platform-specific state should be passed in.
*/
#define boot_bench_start(_state) do { \
plat_bench_start(_state); \
} while (0)
#define boot_bench_stop(_state) do { \
plat_bench_stop(_state); \
} while (0)
#else /* not MCUBOOT_USE_BENCH */
/* The type needs to take space. As long as it remains unused, the C
* compiler should eliminate this value entirely. */
typedef int bench_state_t;
/* Without benchmarking enabled, these are just empty. */
#define boot_bench_start(_state) do { \
IGNORE(_state); \
} while(0)
#define boot_bench_stop(_state) do { \
IGNORE(_state); \
} while(0)
#endif /* not MCUBOOT_USE_BENCH */
#endif /* not H_BOOTUTIL_BENCH_H__ */
@@ -0,0 +1,73 @@
/*
* Copyright (c) 2018-2021 Arm Limited
*
* 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.
*/
#ifndef __BOOT_RECORD_H__
#define __BOOT_RECORD_H__
#include <stdint.h>
#include "bootutil/image.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Add a data item to the shared data area between bootloader and
* runtime SW
*
* @param[in] major_type TLV major type, identify consumer
* @param[in] minor_type TLV minor type, identify TLV type
* @param[in] size length of added data
* @param[in] data pointer to data
*
* @return 0 on success; nonzero on failure.
*/
int boot_add_data_to_shared_area(uint8_t major_type,
uint16_t minor_type,
size_t size,
const uint8_t *data);
/**
* Add an image's all boot status information to the shared memory area
* between the bootloader and runtime SW.
*
* @param[in] sw_module Identifier of the SW component.
* @param[in] hdr Pointer to the image header stored in RAM.
* @param[in] fap Pointer to the flash area where image is stored.
*
* @return 0 on success; nonzero on failure.
*/
int boot_save_boot_status(uint8_t sw_module,
const struct image_header *hdr,
const struct flash_area *fap);
/**
* Add application specific data to the shared memory area between the
* bootloader and runtime SW.
*
* @param[in] hdr Pointer to the image header stored in RAM.
* @param[in] fap Pointer to the flash area where image is stored.
*
* @return 0 on success; nonzero on failure.
*/
int boot_save_shared_data(const struct image_header *hdr,
const struct flash_area *fap);
#ifdef __cplusplus
}
#endif
#endif /* __BOOT_RECORD_H__ */
@@ -0,0 +1,150 @@
/*
* Copyright (c) 2018-2020 Arm Limited
* Copyright (c) 2020 Linaro Limited
*
* 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.
*/
#ifndef __BOOT_STATUS_H__
#define __BOOT_STATUS_H__
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* The shared data between boot loader and runtime SW is TLV encoded. The
* shared data is stored in a well known location in memory and this is a
* contract between boot loader and runtime SW.
*
* The structure of shared data must be the following:
* - At the beginning there must be a header: struct shared_data_tlv_header
* This contains a magic number and a size field which covers the entire
* size of the shared data area including this header.
* - After the header there come the entries which are composed from an entry
* header structure: struct shared_data_tlv_entry and the data. In the entry
* header is a type field (tly_type) which identify the consumer of the
* entry in the runtime SW and specify the subtype of that data item. There
* is a size field (tlv_len) which covers the size of the the data. After
* this structure comes the actual data.
*
* - Arbitrary number and size of data entry can be in the shared memory area.
*
* This table gives of overview about the tlv_type field in the entry header.
* The tlv_type always composed from a major and minor number. Major number
* identifies the addressee in runtime SW, who should process the data entry.
* Minor number used to encode more info about the data entry. The actual
* definition of minor number could change per major number.
*
* In case of boot status data, which can be processed by an attestation
* service the minor number is split further to two part: sw_module and claim.
* The sw_module identifies the SW component in the system which the data item
* belongs to and the claim part identifies the exact type of the data.
*
* |---------------------------------------|
* | tlv_type (16) |
* |---------------------------------------|
* | tlv_major(4)| tlv_minor(12) |
* |---------------------------------------|
* | MAJOR_IAS | sw_module(6) | claim(6) |
* |---------------------------------------|
*/
/* General macros to handle TLV type */
#define MAJOR_MASK 0xF /* 4 bit */
#define MAJOR_POS 12 /* 12 bit */
#define MINOR_MASK 0xFFF /* 12 bit */
#define SET_TLV_TYPE(major, minor) \
(((uint16_t)((major) & MAJOR_MASK) << MAJOR_POS) \
| ((minor) & MINOR_MASK))
#define GET_MAJOR(tlv_type) ((uint16_t)(tlv_type) >> MAJOR_POS)
#define GET_MINOR(tlv_type) ((tlv_type) & MINOR_MASK)
/* Magic value which marks the beginning of shared data area in memory */
#define SHARED_DATA_TLV_INFO_MAGIC 0x2016
/* Initial attestation specific macros */
/**
* Major numbers (4 bit) to identify the
* consumer of shared data in runtime SW.
*/
#define TLV_MAJOR_IAS 0x1
/* Initial attestation: Claim per SW components / SW modules */
/* Bits: 0-2 */
#define SW_VERSION 0x00
#define SW_SIGNER_ID 0x01
/* Reserved 0x02 */
#define SW_TYPE 0x03
/* Bits: 3-5 */
#define SW_MEASURE_VALUE 0x08
#define SW_MEASURE_TYPE 0x09
#define SW_BOOT_RECORD 0x3F
#define MODULE_POS 6 /* 6 bit */
#define CLAIM_MASK 0x3F /* 6 bit */
#define MEASUREMENT_CLAIM_POS 3 /* 3 bit */
#define GET_IAS_MODULE(tlv_type) ((uint16_t)GET_MINOR(tlv_type) >> MODULE_POS)
#define GET_IAS_CLAIM(tlv_type) (GET_MINOR(tlv_type) & CLAIM_MASK)
#define SET_IAS_MINOR(sw_module, claim) \
(((uint16_t)(sw_module) << MODULE_POS) | (claim))
/**
* Shared data TLV header. All fields in little endian.
*
* -----------------------------------
* | tlv_magic(16) | tlv_tot_len(16) |
* -----------------------------------
*/
struct shared_data_tlv_header {
uint16_t tlv_magic;
uint16_t tlv_tot_len; /* size of whole TLV area (including this header) */
};
#define SHARED_DATA_HEADER_SIZE sizeof(struct shared_data_tlv_header)
/**
* Shared data TLV entry header format. All fields in little endian.
*
* -------------------------------
* | tlv_type(16) | tlv_len(16) |
* -------------------------------
* | Raw data |
* -------------------------------
*/
struct shared_data_tlv_entry {
uint16_t tlv_type;
uint16_t tlv_len; /* TLV data length (not including this header). */
};
#define SHARED_DATA_ENTRY_HEADER_SIZE sizeof(struct shared_data_tlv_entry)
#define SHARED_DATA_ENTRY_SIZE(size) (size + SHARED_DATA_ENTRY_HEADER_SIZE)
/* Structure to store the boot data for the runtime SW. */
struct shared_boot_data {
struct shared_data_tlv_header header;
uint8_t data[];
};
#ifdef __cplusplus
}
#endif
#endif /* __BOOT_STATUS_H__ */
@@ -0,0 +1,88 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2017-2019 Linaro LTD
* Copyright (c) 2016-2019 JUUL Labs
* Copyright (c) 2019-2020 Arm Limited
*
* Original license:
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#ifndef H_BOOTUTIL_
#define H_BOOTUTIL_
#include <inttypes.h>
#include "bootutil/fault_injection_hardening.h"
#include "bootutil/bootutil_public.h"
#ifdef __cplusplus
extern "C" {
#endif
struct image_header;
/**
* A response object provided by the boot loader code; indicates where to jump
* to execute the main image.
*/
struct boot_rsp {
/** A pointer to the header of the image to be executed. */
const struct image_header *br_hdr;
/**
* The flash offset of the image to execute. Indicates the position of
* the image header within its flash device.
*/
uint8_t br_flash_dev_id;
uint32_t br_image_off;
};
/* This is not actually used by mcuboot's code but can be used by apps
* when attempting to read/write a trailer.
*/
struct image_trailer {
uint8_t swap_type;
uint8_t pad1[BOOT_MAX_ALIGN - 1];
uint8_t copy_done;
uint8_t pad2[BOOT_MAX_ALIGN - 1];
uint8_t image_ok;
uint8_t pad3[BOOT_MAX_ALIGN - 1];
uint8_t magic[16];
};
/* you must have pre-allocated all the entries within this structure */
fih_int boot_go(struct boot_rsp *rsp);
struct boot_loader_state;
fih_int context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp);
#define SPLIT_GO_OK (0)
#define SPLIT_GO_NON_MATCHING (-1)
#define SPLIT_GO_ERR (-2)
fih_int split_go(int loader_slot, int split_slot, void **entry);
/* The following was added by TI */
fih_int boot_return_highest_version(struct boot_rsp *rsp);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,53 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2017 Linaro Limited
*
* 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.
*/
#ifndef H_BOOTUTIL_LOG_H_
#define H_BOOTUTIL_LOG_H_
#include "ignore.h"
#ifdef __cplusplus
extern "C" {
#endif
#include <mcuboot_config/mcuboot_config.h>
#include <mcuboot_config/mcuboot_logging.h>
#ifdef MCUBOOT_HAVE_LOGGING
#define BOOT_LOG_ERR(...) MCUBOOT_LOG_ERR(__VA_ARGS__)
#define BOOT_LOG_WRN(...) MCUBOOT_LOG_WRN(__VA_ARGS__)
#define BOOT_LOG_INF(...) MCUBOOT_LOG_INF(__VA_ARGS__)
#define BOOT_LOG_DBG(...) MCUBOOT_LOG_DBG(__VA_ARGS__)
#define BOOT_LOG_SIM(...) MCUBOOT_LOG_SIM(__VA_ARGS__)
#else
#define BOOT_LOG_ERR(...) IGNORE(__VA_ARGS__)
#define BOOT_LOG_WRN(...) IGNORE(__VA_ARGS__)
#define BOOT_LOG_INF(...) IGNORE(__VA_ARGS__)
#define BOOT_LOG_DBG(...) IGNORE(__VA_ARGS__)
#define BOOT_LOG_SIM(...) IGNORE(__VA_ARGS__)
#endif /* MCUBOOT_HAVE_LOGGING */
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,184 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2017-2019 Linaro LTD
* Copyright (c) 2016-2019 JUUL Labs
* Copyright (c) 2019-2020 Arm Limited
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* Original license:
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
* @brief Public MCUBoot interface API
*
* This file contains API which can be combined with the application in order
* to interact with the MCUBoot bootloader. This API are shared code-base betwen
* MCUBoot and the application which controls DFU process.
*/
#ifndef H_BOOTUTIL_PUBLIC
#define H_BOOTUTIL_PUBLIC
#include <inttypes.h>
#include <string.h>
#include <flash_map_backend/flash_map_backend.h>
#ifdef __cplusplus
extern "C" {
#endif
/** Attempt to boot the contents of the primary slot. */
#define BOOT_SWAP_TYPE_NONE 1
/**
* Swap to the secondary slot.
* Absent a confirm command, revert back on next boot.
*/
#define BOOT_SWAP_TYPE_TEST 2
/**
* Swap to the secondary slot,
* and permanently switch to booting its contents.
*/
#define BOOT_SWAP_TYPE_PERM 3
/** Swap back to alternate slot. A confirm changes this state to NONE. */
#define BOOT_SWAP_TYPE_REVERT 4
/** Swap failed because image to be run is not valid */
#define BOOT_SWAP_TYPE_FAIL 5
/** Swapping encountered an unrecoverable error */
#define BOOT_SWAP_TYPE_PANIC 0xff
#define BOOT_MAX_ALIGN 8
#define BOOT_MAGIC_GOOD 1
#define BOOT_MAGIC_BAD 2
#define BOOT_MAGIC_UNSET 3
#define BOOT_MAGIC_ANY 4 /* NOTE: control only, not dependent on sector */
#define BOOT_MAGIC_NOTGOOD 5 /* NOTE: control only, not dependent on sector */
/*
* NOTE: leave BOOT_FLAG_SET equal to one, this is written to flash!
*/
#define BOOT_FLAG_SET 1
#define BOOT_FLAG_BAD 2
#define BOOT_FLAG_UNSET 3
#define BOOT_FLAG_ANY 4 /* NOTE: control only, not dependent on sector */
#define BOOT_MAGIC_SZ (sizeof boot_img_magic)
struct boot_swap_state {
uint8_t magic; /* One of the BOOT_MAGIC_[...] values. */
uint8_t swap_type; /* One of the BOOT_SWAP_TYPE_[...] values. */
uint8_t copy_done; /* One of the BOOT_FLAG_[...] values. */
uint8_t image_ok; /* One of the BOOT_FLAG_[...] values. */
uint8_t image_num; /* Boot status belongs to this image */
};
/**
* @brief Determines the action, if any, that mcuboot will take on a image pair.
*
* @param image_index Image pair index.
*
* @return a BOOT_SWAP_TYPE_[...] constant on success, negative errno code on
* fail.
*/
int boot_swap_type_multi(int image_index);
/**
* @brief Determines the action, if any, that mcuboot will take.
*
* Works the same as a boot_swap_type_multi(0) call;
*
* @return a BOOT_SWAP_TYPE_[...] constant on success, negative errno code on
* fail.
*/
int boot_swap_type(void);
/**
* Marks the image in the secondary slot as pending. On the next reboot,
* the system will perform a one-time boot of the the secondary slot image.
*
* @param permanent Whether the image should be used permanently or
* only tested once:
* 0=run image once, then confirm or revert.
* 1=run image forever.
*
* @return 0 on success; nonzero on failure.
*/
int boot_set_pending(int permanent);
/**
* @brief Marks the image in the primary slot as confirmed.
*
* The system will continue booting into the image in the primary slot until
* told to boot from a different slot.
*
* @return 0 on success; nonzero on failure.
*/
int boot_set_confirmed(void);
/**
* @brief Get offset of the swap info field in the image trailer.
*
* @param fap Flash are for which offset is determined.
*
* @retval offset of the swap info field.
*/
uint32_t boot_swap_info_off(const struct flash_area *fap);
/**
* @brief Get value of image-ok flag of the image.
*
* If called from chin-loaded image the image-ok flag value can be used to check
* whether application itself is already confirmed.
*
* @param fap Flash area of the image.
* @param image_ok[out] image-ok value.
*
* @return 0 on success; nonzero on failure.
*/
int boot_read_image_ok(const struct flash_area *fap, uint8_t *image_ok);
/**
* @brief Read the image swap state
*
* @param flash_area_id Id of flash parttition from which trailer will be read.
* @param state Struture for holding swap state.
*
* @return 0 on success, nonzero errno code on fail.
*/
int
boot_read_swap_state_by_id(int flash_area_id, struct boot_swap_state *state);
#define BOOT_MAGIC_ARR_SZ \
(sizeof boot_img_magic / sizeof boot_img_magic[0])
extern const uint32_t boot_img_magic[4];
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,35 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#ifndef H_BOOTUTIL_TEST_
#define H_BOOTUTIL_TEST_
#ifdef __cplusplus
extern "C" {
#endif
int boot_test_all(void);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,61 @@
/*
* Copyright (c) 2017 Linaro Limited
*
* 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.
*/
#ifndef H_BOOTUTIL_CAPS_H_
#define H_BOOTUTIL_CAPS_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* The bootloader can be compile with different capabilities selected
* at compile time. This function provides runtime access to these
* capabilities. This is intended primarily for testing, although
* these will possibly be available at runtime to the application
* running within the bootloader.
*/
uint32_t bootutil_get_caps(void);
#define BOOTUTIL_CAP_RSA2048 (1<<0)
#define BOOTUTIL_CAP_ECDSA_P224 (1<<1)
#define BOOTUTIL_CAP_ECDSA_P256 (1<<2)
#define BOOTUTIL_CAP_SWAP_USING_SCRATCH (1<<3)
#define BOOTUTIL_CAP_OVERWRITE_UPGRADE (1<<4)
#define BOOTUTIL_CAP_ENC_RSA (1<<5)
#define BOOTUTIL_CAP_ENC_KW (1<<6)
#define BOOTUTIL_CAP_VALIDATE_PRIMARY_SLOT (1<<7)
#define BOOTUTIL_CAP_RSA3072 (1<<8)
#define BOOTUTIL_CAP_ED25519 (1<<9)
#define BOOTUTIL_CAP_ENC_EC256 (1<<10)
#define BOOTUTIL_CAP_SWAP_USING_MOVE (1<<11)
#define BOOTUTIL_CAP_DOWNGRADE_PREVENTION (1<<12)
#define BOOTUTIL_CAP_ENC_X25519 (1<<13)
#define BOOTUTIL_CAP_BOOTSTRAP (1<<14)
/*
* Query the number of images this bootloader is configured for. This
* is also primarily used for testing.
*/
uint32_t bootutil_get_num_images(void);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,122 @@
/*
* This module provides a thin abstraction over some of the crypto
* primitives to make it easier to swap out the used crypto library.
*
* At this point, there are two choices: MCUBOOT_USE_MBED_TLS, or
* MCUBOOT_USE_TINYCRYPT. It is a compile error there is not exactly
* one of these defined.
*/
#ifndef __BOOTUTIL_CRYPTO_AES_CTR_H_
#define __BOOTUTIL_CRYPTO_AES_CTR_H_
#include <string.h>
#include "mcuboot_config/mcuboot_config.h"
#if (defined(MCUBOOT_USE_MBED_TLS) + \
defined(MCUBOOT_USE_TINYCRYPT)) != 1
#error "One crypto backend must be defined: either MBED_TLS or TINYCRYPT"
#endif
#if defined(MCUBOOT_USE_MBED_TLS)
#include <mbedtls/aes.h>
#define BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE (16)
#define BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE (16)
#endif /* MCUBOOT_USE_MBED_TLS */
#if defined(MCUBOOT_USE_TINYCRYPT)
#include <string.h>
#include <tinycrypt/aes.h>
#include <tinycrypt/ctr_mode.h>
#include <tinycrypt/constants.h>
#define BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE TC_AES_KEY_SIZE
#define BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE TC_AES_BLOCK_SIZE
#endif /* MCUBOOT_USE_TINYCRYPT */
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#if defined(MCUBOOT_USE_MBED_TLS)
typedef mbedtls_aes_context bootutil_aes_ctr_context;
static inline void bootutil_aes_ctr_init(bootutil_aes_ctr_context *ctx)
{
(void)mbedtls_aes_init(ctx);
}
static inline void bootutil_aes_ctr_drop(bootutil_aes_ctr_context *ctx)
{
/* XXX: config defines MBEDTLS_PLATFORM_NO_STD_FUNCTIONS so no need to free */
/* (void)mbedtls_aes_free(ctx); */
(void)ctx;
}
static inline int bootutil_aes_ctr_set_key(bootutil_aes_ctr_context *ctx, const uint8_t *k)
{
return mbedtls_aes_setkey_enc(ctx, k, BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE * 8);
}
static inline int bootutil_aes_ctr_encrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, const uint8_t *m, uint32_t mlen, size_t blk_off, uint8_t *c)
{
uint8_t stream_block[BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE];
return mbedtls_aes_crypt_ctr(ctx, mlen, &blk_off, counter, stream_block, m, c);
}
static inline int bootutil_aes_ctr_decrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, const uint8_t *c, uint32_t clen, size_t blk_off, uint8_t *m)
{
uint8_t stream_block[BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE];
return mbedtls_aes_crypt_ctr(ctx, clen, &blk_off, counter, stream_block, c, m);
}
#endif /* MCUBOOT_USE_MBED_TLS */
#if defined(MCUBOOT_USE_TINYCRYPT)
typedef struct tc_aes_key_sched_struct bootutil_aes_ctr_context;
static inline void bootutil_aes_ctr_init(bootutil_aes_ctr_context *ctx)
{
(void)ctx;
}
static inline void bootutil_aes_ctr_drop(bootutil_aes_ctr_context *ctx)
{
(void)ctx;
}
static inline int bootutil_aes_ctr_set_key(bootutil_aes_ctr_context *ctx, const uint8_t *k)
{
int rc;
rc = tc_aes128_set_encrypt_key(ctx, k);
if (rc != TC_CRYPTO_SUCCESS) {
return -1;
}
return 0;
}
static int _bootutil_aes_ctr_crypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, const uint8_t *in, uint32_t inlen, uint32_t blk_off, uint8_t *out)
{
int rc;
rc = tc_ctr_mode(out, inlen, in, inlen, counter, &blk_off, ctx);
if (rc != TC_CRYPTO_SUCCESS) {
return -1;
}
return 0;
}
static inline int bootutil_aes_ctr_encrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, const uint8_t *m, uint32_t mlen, uint32_t blk_off, uint8_t *c)
{
return _bootutil_aes_ctr_crypt(ctx, counter, m, mlen, blk_off, c);
}
static inline int bootutil_aes_ctr_decrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, const uint8_t *c, uint32_t clen, uint32_t blk_off, uint8_t *m)
{
return _bootutil_aes_ctr_crypt(ctx, counter, c, clen, blk_off, m);
}
#endif /* MCUBOOT_USE_TINYCRYPT */
#ifdef __cplusplus
}
#endif
#endif /* __BOOTUTIL_CRYPTO_AES_CTR_H_ */
@@ -0,0 +1,141 @@
/*
* This module provides a thin abstraction over some of the crypto
* primitives to make it easier to swap out the used crypto library.
*
* At this point, there are two choices: MCUBOOT_USE_MBED_TLS, or
* MCUBOOT_USE_TINYCRYPT. It is a compile error there is not exactly
* one of these defined.
*/
#ifndef __BOOTUTIL_CRYPTO_AES_KW_H_
#define __BOOTUTIL_CRYPTO_AES_KW_H_
#include "mcuboot_config/mcuboot_config.h"
#if (defined(MCUBOOT_USE_MBED_TLS) + \
defined(MCUBOOT_USE_TINYCRYPT)) != 1
#error "One crypto backend must be defined: either MBED_TLS or TINYCRYPT"
#endif
#if defined(MCUBOOT_USE_MBED_TLS)
#include <mbedtls/aes.h>
#include <mbedtls/nist_kw.h>
#endif /* MCUBOOT_USE_MBED_TLS */
#if defined(MCUBOOT_USE_TINYCRYPT)
#include <tinycrypt/aes.h>
#include <tinycrypt/constants.h>
#endif /* MCUBOOT_USE_TINYCRYPT */
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#if defined(MCUBOOT_USE_MBED_TLS)
typedef mbedtls_nist_kw_context bootutil_aes_kw_context;
static inline void bootutil_aes_kw_init(bootutil_aes_kw_context *ctx)
{
(void)mbedtls_nist_kw_init(ctx);
}
static inline void bootutil_aes_kw_drop(bootutil_aes_kw_context *ctx)
{
/* XXX: config defines MBEDTLS_PLATFORM_NO_STD_FUNCTIONS so no need to free */
/* (void)mbedtls_aes_free(ctx); */
(void)ctx;
}
static inline int bootutil_aes_kw_set_unwrap_key(bootutil_aes_kw_context *ctx, const uint8_t *k, uint32_t klen)
{
return mbedtls_nist_kw_setkey(ctx, MBEDTLS_CIPHER_ID_AES, k, klen * 8, 0);
}
static inline int bootutil_aes_kw_unwrap(bootutil_aes_kw_context *ctx, const uint8_t *wrapped_key, uint32_t wrapped_key_len, uint8_t *key, uint32_t key_len)
{
size_t olen;
return mbedtls_nist_kw_unwrap(ctx, MBEDTLS_KW_MODE_KW, wrapped_key, wrapped_key_len, key, &olen, key_len);
}
#endif /* MCUBOOT_USE_MBED_TLS */
#if defined(MCUBOOT_USE_TINYCRYPT)
typedef struct tc_aes_key_sched_struct bootutil_aes_kw_context;
static inline void bootutil_aes_kw_init(bootutil_aes_kw_context *ctx)
{
(void)ctx;
}
static inline void bootutil_aes_kw_drop(bootutil_aes_kw_context *ctx)
{
(void)ctx;
}
static inline int bootutil_aes_kw_set_unwrap_key(bootutil_aes_kw_context *ctx, const uint8_t *k, uint32_t klen)
{
int rc;
if (klen != 16) {
return -1;
}
rc = tc_aes128_set_decrypt_key(ctx, k);
if (rc != TC_CRYPTO_SUCCESS) {
return -1;
}
return 0;
}
/*
* Implements AES key unwrapping following RFC-3394 section 2.2.2, using
* tinycrypt for AES-128 decryption.
*/
static int bootutil_aes_kw_unwrap(bootutil_aes_kw_context *ctx, const uint8_t *wrapped_key, uint32_t wrapped_key_len, uint8_t *key, uint32_t key_len)
{
uint8_t A[8];
uint8_t B[16];
int8_t i, j, k;
if (wrapped_key_len != 24 || key_len != 16) {
return -1;
}
for (k = 0; k < 8; k++) {
A[k] = wrapped_key[k];
key[k] = wrapped_key[8 + k];
key[8 + k] = wrapped_key[16 + k];
}
for (j = 5; j >= 0; j--) {
for (i = 2; i > 0; i--) {
for (k = 0; k < 8; k++) {
B[k] = A[k];
B[8 + k] = key[((i-1) * 8) + k];
}
B[7] ^= 2 * j + i;
if (tc_aes_decrypt((uint8_t *)&B, (uint8_t *)&B, ctx) != TC_CRYPTO_SUCCESS) {
return -1;
}
for (k = 0; k < 8; k++) {
A[k] = B[k];
key[((i-1) * 8) + k] = B[8 + k];
}
}
}
for (i = 0, k = 0; i < 8; i++) {
k |= A[i] ^ 0xa6;
}
if (k) {
return -1;
}
return 0;
}
#endif /* MCUBOOT_USE_TINYCRYPT */
#ifdef __cplusplus
}
#endif
#endif /* __BOOTUTIL_CRYPTO_AES_KW_H_ */
@@ -0,0 +1,63 @@
/*
* This module provides a thin abstraction over some of the crypto
* primitives to make it easier to swap out the used crypto library.
*
* At this point, there are two choices: MCUBOOT_USE_MBED_TLS, or
* MCUBOOT_USE_TINYCRYPT. It is a compile error there is not exactly
* one of these defined.
*/
#ifndef __BOOTUTIL_CRYPTO_ECDH_P256_H_
#define __BOOTUTIL_CRYPTO_ECDH_P256_H_
#include "mcuboot_config/mcuboot_config.h"
#if (defined(MCUBOOT_USE_TINYCRYPT)) != 1
#error "One crypto backend must be defined: TINYCRYPT"
#endif
#if defined(MCUBOOT_USE_TINYCRYPT)
#include <tinycrypt/ecc_dh.h>
#include <tinycrypt/constants.h>
#define BOOTUTIL_CRYPTO_ECDH_P256_HASH_SIZE (4 * 8)
#endif /* MCUBOOT_USE_TINYCRYPT */
#ifdef __cplusplus
extern "C" {
#endif
#if defined(MCUBOOT_USE_TINYCRYPT)
typedef uintptr_t bootutil_ecdh_p256_context;
static inline void bootutil_ecdh_p256_init(bootutil_ecdh_p256_context *ctx)
{
(void)ctx;
}
static inline void bootutil_ecdh_p256_drop(bootutil_ecdh_p256_context *ctx)
{
(void)ctx;
}
static inline int bootutil_ecdh_p256_shared_secret(bootutil_ecdh_p256_context *ctx, const uint8_t *pk, const uint8_t *sk, uint8_t *z)
{
int rc;
(void)ctx;
rc = uECC_valid_public_key(pk, uECC_secp256r1());
if (rc != 0) {
return -1;
}
rc = uECC_shared_secret(pk, sk, z, uECC_secp256r1());
if (rc != TC_CRYPTO_SUCCESS) {
return -1;
}
return 0;
}
#endif /* MCUBOOT_USE_TINYCRYPT */
#ifdef __cplusplus
}
#endif
#endif /* __BOOTUTIL_CRYPTO_ECDH_P256_H_ */
@@ -0,0 +1,57 @@
/*
* This module provides a thin abstraction over some of the crypto
* primitives to make it easier to swap out the used crypto library.
*
* At this point, there are two choices: MCUBOOT_USE_MBED_TLS, or
* MCUBOOT_USE_TINYCRYPT. It is a compile error there is not exactly
* one of these defined.
*/
#ifndef __BOOTUTIL_CRYPTO_ECDH_X25519_H_
#define __BOOTUTIL_CRYPTO_ECDH_X25519_H_
#include "mcuboot_config/mcuboot_config.h"
#if (defined(MCUBOOT_USE_MBED_TLS) + \
defined(MCUBOOT_USE_TINYCRYPT)) != 1
#error "One crypto backend must be defined: either MBED_TLS or TINYCRYPT"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if defined(MCUBOOT_USE_TINYCRYPT) || defined(MCUBOOT_USE_MBED_TLS)
extern int X25519(uint8_t out_shared_key[32], const uint8_t private_key[32],
const uint8_t peer_public_value[32]);
typedef uintptr_t bootutil_ecdh_x25519_context;
static inline void bootutil_ecdh_x25519_init(bootutil_ecdh_x25519_context *ctx)
{
(void)ctx;
}
static inline void bootutil_ecdh_x25519_drop(bootutil_ecdh_x25519_context *ctx)
{
(void)ctx;
}
static inline int bootutil_ecdh_x25519_shared_secret(bootutil_ecdh_x25519_context *ctx, const uint8_t *pk, const uint8_t *sk, uint8_t *z)
{
int rc;
(void)ctx;
rc = X25519(z, sk, pk);
if (rc != 0) {
return -1;
}
return 0;
}
#endif /* MCUBOOT_USE_TINYCRYPT */
#ifdef __cplusplus
}
#endif
#endif /* __BOOTUTIL_CRYPTO_ECDH_X25519_H_ */
@@ -0,0 +1,131 @@
/*
* This module provides a thin abstraction over some of the crypto
* primitives to make it easier to swap out the used crypto library.
*
* At this point, there are two choices: MCUBOOT_USE_MBED_TLS, or
* MCUBOOT_USE_TINYCRYPT. It is a compile error there is not exactly
* one of these defined.
*/
#ifndef __BOOTUTIL_CRYPTO_ECDSA_P256_H_
#define __BOOTUTIL_CRYPTO_ECDSA_P256_H_
#include "mcuboot_config/mcuboot_config.h"
#if (defined(MCUBOOT_USE_TINYCRYPT) + \
defined(MCUBOOT_USE_CC310) + \
defined(MCUBOOT_USE_TI_CRYPTO) + \
defined(MCUBOOT_USE_MSP_CRYPTO) + \
defined(MCUBOOT_USE_MBED_TLS)) != 1
#error "One crypto backend must be defined: either CC310 or TINYCRYPT"
#endif
#if defined(MCUBOOT_USE_TINYCRYPT)
#include <tinycrypt/ecc_dsa.h>
#include <tinycrypt/constants.h>
#define BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE (4 * 8)
#endif /* MCUBOOT_USE_TINYCRYPT */
#if defined(MCUBOOT_USE_CC310)
#include <cc310_glue.h>
#define BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE (4 * 8)
#endif /* MCUBOOT_USE_CC310 */
#if defined(MCUBOOT_USE_TI_CRYPTO)
#define BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE (4 * 8)
#endif /* MCUBOOT_USE_TI_CRYPTO */
#if defined(MCUBOOT_USE_MSP_CRYPTO)
#define BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE (4 * 8)
#endif /* MCUBOOT_USE_TI_CRYPTO */
#ifdef __cplusplus
extern "C" {
#endif
#if defined(MCUBOOT_USE_TINYCRYPT)
typedef uintptr_t bootutil_ecdsa_p256_context;
static inline void bootutil_ecdsa_p256_init(bootutil_ecdsa_p256_context *ctx)
{
(void)ctx;
}
static inline void bootutil_ecdsa_p256_drop(bootutil_ecdsa_p256_context *ctx)
{
(void)ctx;
}
static inline int bootutil_ecdsa_p256_verify(bootutil_ecdsa_p256_context *ctx, const uint8_t *pk, const uint8_t *hash, const uint8_t *sig)
{
int rc;
(void)ctx;
rc = uECC_verify(pk, hash, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE, sig, uECC_secp256r1());
if (rc != TC_CRYPTO_SUCCESS) {
return -1;
}
return 0;
}
#endif /* MCUBOOT_USE_TINYCRYPT */
#if defined(MCUBOOT_USE_CC310)
typedef uintptr_t bootutil_ecdsa_p256_context;
static inline void bootutil_ecdsa_p256_init(bootutil_ecdsa_p256_context *ctx)
{
(void)ctx;
}
static inline void bootutil_ecdsa_p256_drop(bootutil_ecdsa_p256_context *ctx)
{
(void)ctx;
}
static inline int bootutil_ecdsa_p256_verify(bootutil_ecdsa_p256_context *ctx, uint8_t *pk, uint8_t *hash, uint8_t *sig)
{
(void)ctx;
return cc310_ecdsa_verify_secp256r1(hash, pk, sig, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE);
}
#endif /* MCUBOOT_USE_CC310 */
#if defined(MCUBOOT_USE_TI_CRYPTO)
#include "ti-crypto/sl_crypto.h"
typedef void* bootutil_ecdsa_p256_context;
static inline void bootutil_ecdsa_p256_init(bootutil_ecdsa_p256_context *ctx)
{
SlCrypto_ecdsa_p256_init();
}
static inline void bootutil_ecdsa_p256_drop(bootutil_ecdsa_p256_context *ctx)
{
SlCrypto_ecdsa_p256_drop();
}
static inline int bootutil_ecdsa_p256_verify(bootutil_ecdsa_p256_context *ctx, const uint8_t *pk, const uint8_t *hash, const uint8_t *sig)
{
return SlCrypto_ecdsa_p256_verify(pk, hash, sig);
}
#endif /* MCUBOOT_USE_TI_CRYPTO */
#if defined(MCUBOOT_USE_MSP_CRYPTO)
#include "msp-crypto/msp_crypto.h"
typedef void* bootutil_ecdsa_p256_context;
static inline void bootutil_ecdsa_p256_init(bootutil_ecdsa_p256_context *ctx)
{
MSPCrypto_ecdsa_p256_init();
}
static inline void bootutil_ecdsa_p256_drop(bootutil_ecdsa_p256_context *ctx)
{
MSPCrypto_ecdsa_p256_drop();
}
static inline int bootutil_ecdsa_p256_verify(bootutil_ecdsa_p256_context *ctx, const uint8_t *pk, const uint8_t *hash, const uint8_t *sig)
{
return MSPCrypto_ecdsa_p256_verify(pk, hash, sig);
}
#endif /* MCUBOOT_USE_MSP_CRYPTO */
#ifdef __cplusplus
}
#endif
#endif /* __BOOTUTIL_CRYPTO_ECDSA_P256_H_ */
@@ -0,0 +1,83 @@
/*
* This module provides a thin abstraction over some of the crypto
* primitives to make it easier to swap out the used crypto library.
*
* At this point, there are two choices: MCUBOOT_USE_MBED_TLS, or
* MCUBOOT_USE_TINYCRYPT. It is a compile error there is not exactly
* one of these defined.
*/
#ifndef __BOOTUTIL_CRYPTO_HMAC_SHA256_H_
#define __BOOTUTIL_CRYPTO_HMAC_SHA256_H_
#include "mcuboot_config/mcuboot_config.h"
#if (defined(MCUBOOT_USE_TINYCRYPT)) != 1
#error "One crypto backend must be defined: TINYCRYPT"
#endif
#if defined(MCUBOOT_USE_TINYCRYPT)
#include <tinycrypt/sha256.h>
#include <tinycrypt/utils.h>
#include <tinycrypt/constants.h>
#include <tinycrypt/hmac.h>
#endif /* MCUBOOT_USE_TINYCRYPT */
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#if defined(MCUBOOT_USE_TINYCRYPT)
typedef struct tc_hmac_state_struct bootutil_hmac_sha256_context;
static inline void bootutil_hmac_sha256_init(bootutil_hmac_sha256_context *ctx)
{
(void)ctx;
}
static inline void bootutil_hmac_sha256_drop(bootutil_hmac_sha256_context *ctx)
{
(void)ctx;
}
static inline int bootutil_hmac_sha256_set_key(bootutil_hmac_sha256_context *ctx, const uint8_t *key, unsigned int key_size)
{
int rc;
rc = tc_hmac_set_key(ctx, key, key_size);
if (rc != TC_CRYPTO_SUCCESS) {
return -1;
}
rc = tc_hmac_init(ctx);
if (rc != TC_CRYPTO_SUCCESS) {
return -1;
}
return 0;
}
static inline int bootutil_hmac_sha256_update(bootutil_hmac_sha256_context *ctx, const void *data, unsigned int data_length)
{
int rc;
rc = tc_hmac_update(ctx, data, data_length);
if (rc != TC_CRYPTO_SUCCESS) {
return -1;
}
return 0;
}
static inline int bootutil_hmac_sha256_finish(bootutil_hmac_sha256_context *ctx, uint8_t *tag, unsigned int taglen)
{
int rc;
rc = tc_hmac_final(tag, taglen, ctx);
if (rc != TC_CRYPTO_SUCCESS) {
return -1;
}
return 0;
}
#endif /* MCUBOOT_USE_TINYCRYPT */
#ifdef __cplusplus
}
#endif
#endif /* __BOOTUTIL_CRYPTO_HMAC_SHA256_H_ */
@@ -0,0 +1,205 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2017-2019 Linaro LTD
* Copyright (c) 2017-2019 JUUL Labs
*/
/*
* This module provides a thin abstraction over some of the crypto
* primitives to make it easier to swap out the used crypto library.
*
* At this point, there are two choices: MCUBOOT_USE_MBED_TLS, or
* MCUBOOT_USE_TINYCRYPT. It is a compile error there is not exactly
* one of these defined.
*/
#ifndef __BOOTUTIL_CRYPTO_SHA256_H_
#define __BOOTUTIL_CRYPTO_SHA256_H_
#include "mcuboot_config/mcuboot_config.h"
#if (defined(MCUBOOT_USE_MBED_TLS) + \
defined(MCUBOOT_USE_TINYCRYPT) + \
defined(MCUBOOT_USE_TI_CRYPTO) + \
defined(MCUBOOT_USE_MSP_CRYPTO) + \
defined(MCUBOOT_USE_CC310)) != 1
#error "One crypto backend must be defined: either CC310, MBED_TLS or TINYCRYPT"
#endif
#if defined(MCUBOOT_USE_MBED_TLS)
#include <mbedtls/sha256.h>
#define BOOTUTIL_CRYPTO_SHA256_BLOCK_SIZE (64)
#define BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE (32)
#endif /* MCUBOOT_USE_MBED_TLS */
#if defined(MCUBOOT_USE_TINYCRYPT)
#include <tinycrypt/sha256.h>
#include <tinycrypt/constants.h>
#define BOOTUTIL_CRYPTO_SHA256_BLOCK_SIZE TC_SHA256_BLOCK_SIZE
#define BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE TC_SHA256_DIGEST_SIZE
#endif /* MCUBOOT_USE_TINYCRYPT */
#if defined(MCUBOOT_USE_CC310)
#include <cc310_glue.h>
#define BOOTUTIL_CRYPTO_SHA256_BLOCK_SIZE (64)
#define BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE (32)
#endif /* MCUBOOT_USE_CC310 */
#if defined(MCUBOOT_USE_TI_CRYPTO) || defined(MCUBOOT_USE_MSP_CRYPTO)
#define BOOTUTIL_CRYPTO_SHA256_BLOCK_SIZE (64)
#define BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE (32)
#endif /* MCUBOOT_USE_TI_CRYPTO */
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#if defined(MCUBOOT_USE_MBED_TLS)
typedef mbedtls_sha256_context bootutil_sha256_context;
static inline void bootutil_sha256_init(bootutil_sha256_context *ctx)
{
mbedtls_sha256_init(ctx);
(void)mbedtls_sha256_starts_ret(ctx, 0);
}
static inline void bootutil_sha256_drop(bootutil_sha256_context *ctx)
{
/* XXX: config defines MBEDTLS_PLATFORM_NO_STD_FUNCTIONS so no need to free */
/* (void)mbedtls_sha256_free(ctx); */
(void)ctx;
}
static inline int bootutil_sha256_update(bootutil_sha256_context *ctx,
const void *data,
uint32_t data_len)
{
return mbedtls_sha256_update_ret(ctx, data, data_len);
}
static inline int bootutil_sha256_finish(bootutil_sha256_context *ctx,
uint8_t *output)
{
return mbedtls_sha256_finish_ret(ctx, output);
}
#endif /* MCUBOOT_USE_MBED_TLS */
#if defined(MCUBOOT_USE_TINYCRYPT)
typedef struct tc_sha256_state_struct bootutil_sha256_context;
static inline void bootutil_sha256_init(bootutil_sha256_context *ctx)
{
tc_sha256_init(ctx);
}
static inline void bootutil_sha256_drop(bootutil_sha256_context *ctx)
{
(void)ctx;
}
static inline int bootutil_sha256_update(bootutil_sha256_context *ctx,
const void *data,
uint32_t data_len)
{
return tc_sha256_update(ctx, data, data_len);
}
static inline int bootutil_sha256_finish(bootutil_sha256_context *ctx,
uint8_t *output)
{
return tc_sha256_final(output, ctx);
}
#endif /* MCUBOOT_USE_TINYCRYPT */
#if defined(MCUBOOT_USE_CC310)
static inline void bootutil_sha256_init(bootutil_sha256_context *ctx)
{
cc310_sha256_init(ctx);
}
static inline void bootutil_sha256_drop(bootutil_sha256_context *ctx)
{
(void)ctx;
nrf_cc310_disable();
}
static inline int bootutil_sha256_update(bootutil_sha256_context *ctx,
const void *data,
uint32_t data_len)
{
cc310_sha256_update(ctx, data, data_len);
return 0;
}
static inline int bootutil_sha256_finish(bootutil_sha256_context *ctx,
uint8_t *output)
{
cc310_sha256_finalize(ctx, output);
return 0;
}
#endif /* MCUBOOT_USE_CC310 */
#if defined(MCUBOOT_USE_TI_CRYPTO)
#include "ti-crypto/sl_crypto.h"
typedef void* bootutil_sha256_context;
static inline void bootutil_sha256_init(bootutil_sha256_context *ctx)
{
SlCrypto_sha256_init();
}
static inline void bootutil_sha256_drop(bootutil_sha256_context *ctx)
{
SlCrypto_sha256_drop();
}
static inline int bootutil_sha256_update(bootutil_sha256_context *ctx,
const void *data,
uint32_t data_len)
{
return SlCrypto_sha256_update(data, data_len);
}
static inline int bootutil_sha256_finish(bootutil_sha256_context *ctx,
uint8_t *output)
{
return SlCrypto_sha256_final(output);
}
#endif /* MCUBOOT_USE_TI_CRYPTO */
#if defined(MCUBOOT_USE_MSP_CRYPTO)
#include "msp-crypto/msp_crypto.h"
typedef uint32_t bootutil_sha256_context;
static inline void bootutil_sha256_init(bootutil_sha256_context *ctx)
{
MSPCrypto_sha256_init();
}
static inline void bootutil_sha256_drop(bootutil_sha256_context *ctx)
{
MSPCrypto_sha256_drop();
}
static inline int bootutil_sha256_update(bootutil_sha256_context *ctx,
const void *data,
uint32_t data_len)
{
return MSPCrypto_sha256_update(data, data_len);
}
static inline int bootutil_sha256_finish(bootutil_sha256_context *ctx,
uint8_t *output)
{
return MSPCrypto_sha256_finish(output);
}
#endif /* MCUBOOT_USE_MSP_CRYPTO */
#ifdef __cplusplus
}
#endif
#endif /* __BOOTUTIL_CRYPTO_SHA256_H_ */
@@ -0,0 +1,88 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2018-2019 JUUL Labs
* Copyright (c) 2019 Arm Limited
*
* Original license:
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#ifndef BOOTUTIL_ENC_KEY_H
#define BOOTUTIL_ENC_KEY_H
#include <stdbool.h>
#include <stdint.h>
#include <flash_map_backend/flash_map_backend.h>
#include "bootutil/crypto/aes_ctr.h"
#include "bootutil/image.h"
#ifdef __cplusplus
extern "C" {
#endif
#define BOOT_ENC_KEY_SIZE 16
#define BOOT_ENC_KEY_SIZE_BITS (BOOT_ENC_KEY_SIZE * 8)
#define TLV_ENC_RSA_SZ 256
#define TLV_ENC_KW_SZ 24
#define TLV_ENC_EC256_SZ (65 + 32 + 16)
#define TLV_ENC_X25519_SZ (32 + 32 + 16)
#if defined(MCUBOOT_ENCRYPT_RSA)
#define BOOT_ENC_TLV_SIZE TLV_ENC_RSA_SZ
#elif defined(MCUBOOT_ENCRYPT_EC256)
#define BOOT_ENC_TLV_SIZE TLV_ENC_EC256_SZ
#elif defined(MCUBOOT_ENCRYPT_X25519)
#define BOOT_ENC_TLV_SIZE TLV_ENC_X25519_SZ
#else
#define BOOT_ENC_TLV_SIZE TLV_ENC_KW_SZ
#endif
#define BOOT_ENC_TLV_ALIGN_SIZE \
((((BOOT_ENC_TLV_SIZE - 1) / BOOT_MAX_ALIGN) + 1) * BOOT_MAX_ALIGN)
struct enc_key_data {
uint8_t valid;
bootutil_aes_ctr_context aes_ctr;
};
extern const struct bootutil_key bootutil_enc_key;
struct boot_status;
int boot_enc_init(struct enc_key_data *enc_state, uint8_t slot);
int boot_enc_drop(struct enc_key_data *enc_state, uint8_t slot);
int boot_enc_set_key(struct enc_key_data *enc_state, uint8_t slot,
const struct boot_status *bs);
int boot_enc_load(struct enc_key_data *enc_state, int image_index,
const struct image_header *hdr, const struct flash_area *fap,
struct boot_status *bs);
int boot_enc_decrypt(const uint8_t *buf, uint8_t *enckey);
bool boot_enc_valid(struct enc_key_data *enc_state, int image_index,
const struct flash_area *fap);
void boot_encrypt(struct enc_key_data *enc_state, int image_index,
const struct flash_area *fap, uint32_t off, uint32_t sz,
uint32_t blk_off, uint8_t *buf);
void boot_enc_zeroize(struct enc_key_data *enc_state);
#ifdef __cplusplus
}
#endif
#endif /* BOOTUTIL_ENC_KEY_H */
@@ -0,0 +1,377 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2020 Arm Limited
*/
#ifndef __FAULT_INJECTION_HARDENING_H__
#define __FAULT_INJECTION_HARDENING_H__
/* Fault injection mitigation library.
*
* Has support for different measures, which can either be enabled/disabled
* separately or by defining one of the MCUBOOT_FIH_PROFILEs.
*
* NOTE: These constructs against fault injection attacks are not guaranteed to
* be secure for all compilers, but execution is going to be correct and
* including them will certainly help to harden the code.
*
* FIH_ENABLE_DOUBLE_VARS makes critical variables into a tuple (x, x ^ msk).
* Then the correctness of x can be checked by XORing the two tuple values
* together. This also means that comparisons between fih_ints can be verified
* by doing x == y && x_msk == y_msk.
*
* FIH_ENABLE_GLOBAL_FAIL makes all while(1) failure loops redirect to a global
* failure loop. This loop has mitigations against loop escapes / unlooping.
* This also means that any unlooping won't immediately continue executing the
* function that was executing before the failure.
*
* FIH_ENABLE_CFI (Control Flow Integrity) creates a global counter that is
* incremented before every FIH_CALL of vulnerable functions. On the function
* return the counter is decremented, and after the return it is verified that
* the counter has the same value as before this process. This can be used to
* verify that the function has actually been called. This protection is
* intended to discover that important functions are called in an expected
* sequence and neither of them is missed due to an instruction skip which could
* be a result of glitching attack. It does not provide protection against ROP
* or JOP attacks.
*
* FIH_ENABLE_DELAY causes random delays. This makes it hard to cause faults
* precisely. It requires an RNG. An mbedtls integration is provided in
* fault_injection_hardening_delay_mbedtls.h, but any RNG that has an entropy
* source can be used by implementing the fih_delay_random_uchar function.
*
* The basic call pattern is:
*
* fih_int fih_rc = FIH_FAILURE;
* FIH_CALL(vulnerable_function, fih_rc, arg1, arg2);
* if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
* FIH_PANIC;
* }
*
* Note that any function called by FIH_CALL must only return using FIH_RETURN,
* as otherwise the CFI counter will not be decremented and the CFI check will
* fail causing a panic.
*/
#include "mcuboot_config/mcuboot_config.h"
#if defined(MCUBOOT_FIH_PROFILE_HIGH)
#define FIH_ENABLE_DELAY /* Requires an entropy source */
#define FIH_ENABLE_DOUBLE_VARS
#define FIH_ENABLE_GLOBAL_FAIL
#define FIH_ENABLE_CFI
#elif defined(MCUBOOT_FIH_PROFILE_MEDIUM)
#define FIH_ENABLE_DOUBLE_VARS
#define FIH_ENABLE_GLOBAL_FAIL
#define FIH_ENABLE_CFI
#elif defined(MCUBOOT_FIH_PROFILE_LOW)
#define FIH_ENABLE_GLOBAL_FAIL
#define FIH_ENABLE_CFI
#elif !defined(MCUBOOT_FIH_PROFILE_OFF)
#define MCUBOOT_FIH_PROFILE_OFF
#endif /* MCUBOOT_FIH_PROFILE */
#ifdef FIH_ENABLE_DELAY
#include "fault_injection_hardening_delay_rng.h"
#endif /* FIH_ENABLE_DELAY */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Non-zero success value to defend against register resets. Zero is the most
* common value for a corrupted register so complex bit-patterns are used
*/
#ifndef MCUBOOT_FIH_PROFILE_OFF
#define FIH_POSITIVE_VALUE 0x1AAAAAAA
#define FIH_NEGATIVE_VALUE 0x15555555
#else
#define FIH_POSITIVE_VALUE 0
#define FIH_NEGATIVE_VALUE -1
#endif
/* A volatile mask is used to prevent compiler optimization - the mask is xored
* with the variable to create the backup and the integrity can be checked with
* another xor. The mask value doesn't _really_ matter that much, as long as
* it has reasonably high hamming weight.
*/
#define _FIH_MASK_VALUE 0xBEEF
#ifdef FIH_ENABLE_DOUBLE_VARS
/* All ints are replaced with two int - the normal one and a backup which is
* XORed with the mask.
*/
extern volatile int _fih_mask;
typedef volatile struct {
volatile int val;
volatile int msk;
} fih_int;
#else
typedef int fih_int;
#endif /* FIH_ENABLE_DOUBLE_VARS */
extern fih_int FIH_SUCCESS;
extern fih_int FIH_FAILURE;
#ifdef FIH_ENABLE_GLOBAL_FAIL
/* Global failure handler - more resistant to unlooping. noinline and used are
* used to prevent optimization
*/
__attribute__((noinline)) __attribute__((used))
void fih_panic_loop(void);
#define FIH_PANIC fih_panic_loop()
#else
#define FIH_PANIC while (1) {}
#endif /* FIH_ENABLE_GLOBAL_FAIL */
/* NOTE: For functions to be inlined outside their compilation unit they have to
* have the body in the header file. This is required as function calls are easy
* to skip.
*/
#ifdef FIH_ENABLE_DELAY
/* Delaying logic, with randomness from a CSPRNG */
__attribute__((always_inline)) inline
int fih_delay(void)
{
unsigned char delay;
int foo = 0;
volatile int rc;
delay = fih_delay_random_uchar();
for (volatile int i = 0; i < delay; i++) {
foo++;
}
rc = 1;
/* rc is volatile so if it is the return value then the function cannot be
* optimized
*/
return rc;
}
#else
__attribute__((always_inline)) inline
int fih_delay_init(void)
{
return 1;
}
__attribute__((always_inline)) inline
int fih_delay(void)
{
return 1;
}
#endif /* FIH_ENABLE_DELAY */
#ifdef FIH_ENABLE_DOUBLE_VARS
__attribute__((always_inline)) inline
void fih_int_validate(fih_int x)
{
if (x.val != (x.msk ^ _fih_mask)) {
FIH_PANIC;
}
}
/* Convert a fih_int to an int. Validate for tampering. */
__attribute__((always_inline)) inline
int fih_int_decode(fih_int x)
{
fih_int_validate(x);
return x.val;
}
/* Convert an int to a fih_int, can be used to encode specific error codes. */
__attribute__((always_inline)) inline
fih_int fih_int_encode(int x)
{
fih_int ret = {x, x ^ _fih_mask};
return ret;
}
/* Standard equality. If A == B then 1, else 0 */
__attribute__((always_inline)) inline
int fih_eq(fih_int x, fih_int y)
{
fih_int_validate(x);
fih_int_validate(y);
return (x.val == y.val) && fih_delay() && (x.msk == y.msk);
}
__attribute__((always_inline)) inline
int fih_not_eq(fih_int x, fih_int y)
{
fih_int_validate(x);
fih_int_validate(y);
return (x.val != y.val) && fih_delay() && (x.msk != y.msk);
}
#else
/* NOOP */
__attribute__((always_inline)) inline
void fih_int_validate(fih_int x)
{
(void) x;
return;
}
/* NOOP */
__attribute__((always_inline)) inline
int fih_int_decode(fih_int x)
{
return x;
}
/* NOOP */
__attribute__((always_inline)) inline
fih_int fih_int_encode(int x)
{
return x;
}
__attribute__((always_inline)) inline
int fih_eq(fih_int x, fih_int y)
{
return x == y;
}
__attribute__((always_inline)) inline
int fih_not_eq(fih_int x, fih_int y)
{
return x != y;
}
#endif /* FIH_ENABLE_DOUBLE_VARS */
/* C has a common return pattern where 0 is a correct value and all others are
* errors. This function converts 0 to FIH_SUCCESS and any other number to a
* value that is not FIH_SUCCESS
*/
__attribute__((always_inline)) inline
fih_int fih_int_encode_zero_equality(int x)
{
if (x) {
return FIH_FAILURE;
} else {
return FIH_SUCCESS;
}
}
#ifdef FIH_ENABLE_CFI
extern fih_int _fih_cfi_ctr;
#endif /* FIH_ENABLE_CFI */
fih_int fih_cfi_get_and_increment(void);
void fih_cfi_validate(fih_int saved);
void fih_cfi_decrement(void);
/* Label for interacting with FIH testing tool. Can be parsed from the elf file
* after compilation. Does not require debug symbols.
*/
#if defined(__ICCARM__)
#define FIH_LABEL(str, lin, cnt) __asm volatile ("FIH_LABEL_" str "_" #lin "_" #cnt "::" ::);
#else
#define FIH_LABEL(str) __asm volatile ("FIH_LABEL_" str "_%=:" ::);
#endif
/* Main FIH calling macro. return variable is second argument. Does some setup
* before and validation afterwards. Inserts labels for use with testing script.
*
* First perform the precall step - this gets the current value of the CFI
* counter and saves it to a local variable, and then increments the counter.
*
* Then set the return variable to FIH_FAILURE as a base case.
*
* Then perform the function call. As part of the funtion FIH_RET must be called
* which will decrement the counter.
*
* The postcall step gets the value of the counter and compares it to the
* previously saved value. If this is equal then the function call and all child
* function calls were performed.
*/
#if defined(__ICCARM__)
#define FIH_CALL(f, ret, ...) FIH_CALL2(f, ret, __LINE__, __COUNTER__, __VA_ARGS__)
#define FIH_CALL2(f, ret, l, c, ...) \
do { \
FIH_LABEL("FIH_CALL_START", l, c); \
FIH_CFI_PRECALL_BLOCK; \
ret = FIH_FAILURE; \
if (fih_delay()) { \
ret = f(__VA_ARGS__); \
} \
FIH_CFI_POSTCALL_BLOCK; \
FIH_LABEL("FIH_CALL_END", l, c); \
} while (0)
#else
#define FIH_CALL(f, ret, ...) \
do { \
FIH_LABEL("FIH_CALL_START"); \
FIH_CFI_PRECALL_BLOCK; \
ret = FIH_FAILURE; \
if (fih_delay()) { \
ret = f(__VA_ARGS__); \
} \
FIH_CFI_POSTCALL_BLOCK; \
FIH_LABEL("FIH_CALL_END"); \
} while (0)
#endif
/* FIH return changes the state of the internal state machine. If you do a
* FIH_CALL then you need to do a FIH_RET else the state machine will detect
* tampering and panic.
*/
#define FIH_RET(ret) \
do { \
FIH_CFI_PRERET; \
return ret; \
} while (0)
#ifdef FIH_ENABLE_CFI
/* Macro wrappers for functions - Even when the functions have zero body this
* saves a few bytes on noop functions as it doesn't generate the call/ret
*
* CFI precall function saves the CFI counter and then increments it - the
* postcall then checks if the counter is equal to the saved value. In order for
* this to be the case a FIH_RET must have been performed inside the called
* function in order to decrement the counter, so the function must have been
* called.
*/
#define FIH_CFI_PRECALL_BLOCK \
fih_int _fih_cfi_saved_value = fih_cfi_get_and_increment()
#define FIH_CFI_POSTCALL_BLOCK \
fih_cfi_validate(_fih_cfi_saved_value)
#define FIH_CFI_PRERET \
fih_cfi_decrement()
#else
#define FIH_CFI_PRECALL_BLOCK
#define FIH_CFI_POSTCALL_BLOCK
#define FIH_CFI_PRERET
#endif /* FIH_ENABLE_CFI */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __FAULT_INJECTION_HARDENING_H__ */
@@ -0,0 +1,30 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2020 Arm Limited
*/
#ifndef __FAULT_INJECTION_HARDENING_DELAY_RNG_H__
#define __FAULT_INJECTION_HARDENING_DELAY_RNG_H__
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/**
* \brief Set up the RNG for use with random delays. Called once at startup.
*/
int fih_delay_init(void);
/**
* \brief Get a random unsigned char from an RNG seeded with an entropy source.
*
* \return A random value that fits inside an unsigned char.
*/
unsigned char fih_delay_random_uchar(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __FAULT_INJECTION_HARDENING_DELAY_RNG_H__ */
@@ -0,0 +1,70 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2017 Nordic Semiconductor ASA
*
* Original license:
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#ifndef H_IGNORE_
#define H_IGNORE_
#ifdef __cplusplus
extern "C" {
#endif
/**
* These macros prevent the "set but not used" warnings for log writes below
* the log level.
*/
#define IGN_1(X) ((void)(X))
#define IGN_2(X, ...) ((void)(X));IGN_1(__VA_ARGS__)
#define IGN_3(X, ...) ((void)(X));IGN_2(__VA_ARGS__)
#define IGN_4(X, ...) ((void)(X));IGN_3(__VA_ARGS__)
#define IGN_5(X, ...) ((void)(X));IGN_4(__VA_ARGS__)
#define IGN_6(X, ...) ((void)(X));IGN_5(__VA_ARGS__)
#define IGN_7(X, ...) ((void)(X));IGN_6(__VA_ARGS__)
#define IGN_8(X, ...) ((void)(X));IGN_7(__VA_ARGS__)
#define IGN_9(X, ...) ((void)(X));IGN_8(__VA_ARGS__)
#define IGN_10(X, ...) ((void)(X));IGN_9(__VA_ARGS__)
#define IGN_11(X, ...) ((void)(X));IGN_10(__VA_ARGS__)
#define IGN_12(X, ...) ((void)(X));IGN_11(__VA_ARGS__)
#define IGN_13(X, ...) ((void)(X));IGN_12(__VA_ARGS__)
#define IGN_14(X, ...) ((void)(X));IGN_13(__VA_ARGS__)
#define IGN_15(X, ...) ((void)(X));IGN_14(__VA_ARGS__)
#define IGN_16(X, ...) ((void)(X));IGN_15(__VA_ARGS__)
#define IGN_17(X, ...) ((void)(X));IGN_16(__VA_ARGS__)
#define IGN_18(X, ...) ((void)(X));IGN_17(__VA_ARGS__)
#define IGN_19(X, ...) ((void)(X));IGN_18(__VA_ARGS__)
#define IGN_20(X, ...) ((void)(X));IGN_19(__VA_ARGS__)
#define GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, \
_13, _14, _15, _16, _17, _18, _19, _20, NAME, ...) NAME
#define IGNORE(...) \
GET_MACRO(__VA_ARGS__, IGN_20, IGN_19, IGN_18, IGN_17, IGN_16, IGN_15, \
IGN_14, IGN_13, IGN_12, IGN_11, IGN_10, IGN_9, IGN_8, IGN_7, \
IGN_6, IGN_5, IGN_4, IGN_3, IGN_2, IGN_1)(__VA_ARGS__)
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,191 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2016-2019 Linaro LTD
* Copyright (c) 2016-2019 JUUL Labs
* Copyright (c) 2019-2020 Arm Limited
*
* Original license:
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#ifndef H_IMAGE_
#define H_IMAGE_
#include <inttypes.h>
#include <stdbool.h>
#include "bootutil/fault_injection_hardening.h"
#ifdef __cplusplus
extern "C" {
#endif
struct flash_area;
#define IMAGE_MAGIC 0x96f3b83d
#define IMAGE_MAGIC_V1 0x96f3b83c
#define IMAGE_MAGIC_NONE 0xffffffff
#define IMAGE_TLV_INFO_MAGIC 0x6907
#define IMAGE_TLV_PROT_INFO_MAGIC 0x6908
#define IMAGE_HEADER_SIZE 32
/*
* Image header flags.
*/
#define IMAGE_F_PIC 0x00000001 /* Not supported. */
#define IMAGE_F_NON_BOOTABLE 0x00000010 /* Split image app. */
#define IMAGE_F_ENCRYPTED 0x00000004 /* Encrypted. */
/*
* Indicates that this image should be loaded into RAM instead of run
* directly from flash. The address to load should be in the
* ih_load_addr field of the header.
*/
#define IMAGE_F_RAM_LOAD 0x00000020
/*
* ECSDA224 is with NIST P-224
* ECSDA256 is with NIST P-256
*/
/*
* Image trailer TLV types.
*
* Signature is generated by computing signature over the image hash.
* Currently the only image hash type is SHA256.
*
* Signature comes in the form of 2 TLVs.
* 1st on identifies the public key which should be used to verify it.
* 2nd one is the actual signature.
*/
#define IMAGE_TLV_KEYHASH 0x01 /* hash of the public key */
#define IMAGE_TLV_PUBKEY 0x02 /* public key */
#define IMAGE_TLV_SHA256 0x10 /* SHA256 of image hdr and body */
#define IMAGE_TLV_RSA2048_PSS 0x20 /* RSA2048 of hash output */
#define IMAGE_TLV_ECDSA224 0x21 /* ECDSA of hash output */
#define IMAGE_TLV_ECDSA256 0x22 /* ECDSA of hash output */
#define IMAGE_TLV_RSA3072_PSS 0x23 /* RSA3072 of hash output */
#define IMAGE_TLV_ED25519 0x24 /* ed25519 of hash output */
#define IMAGE_TLV_ENC_RSA2048 0x30 /* Key encrypted with RSA-OAEP-2048 */
#define IMAGE_TLV_ENC_KW128 0x31 /* Key encrypted with AES-KW-128 */
#define IMAGE_TLV_ENC_EC256 0x32 /* Key encrypted with ECIES-EC256 */
#define IMAGE_TLV_ENC_X25519 0x33 /* Key encrypted with ECIES-X25519 */
#define IMAGE_TLV_DEPENDENCY 0x40 /* Image depends on other image */
#define IMAGE_TLV_SEC_CNT 0x50 /* security counter */
#define IMAGE_TLV_BOOT_RECORD 0x60 /* measured boot record */
/*
* vendor reserved TLVs at xxA0-xxFF,
* where xx denotes the upper byte
* range. Examples:
* 0x00a0 - 0x00ff
* 0x01a0 - 0x01ff
* 0x02a0 - 0x02ff
* ...
* 0xffa0 - 0xfffe
*/
#define IMAGE_TLV_CUSTOM_TI_ADD_KEY 0xCC /* Custom TLV to add key based on hash */
#define IMAGE_TLV_CUSTOM_TI_REVOKE_KEY 0xCD /* Custom TLV to revoke key based on hash */
#define IMAGE_TLV_ANY 0xffff /* Used to iterate over all TLV */
struct image_version {
uint8_t iv_major;
uint8_t iv_minor;
uint16_t iv_revision;
uint32_t iv_build_num;
};
struct image_dependency {
uint8_t image_id; /* Image index (from 0) */
uint8_t _pad1;
uint16_t _pad2;
struct image_version image_min_version; /* Indicates at minimum which
* version of firmware must be
* available to satisfy compliance
*/
};
/** Image header. All fields are in little endian byte order. */
struct image_header {
uint32_t ih_magic;
uint32_t ih_load_addr;
uint16_t ih_hdr_size; /* Size of image header (bytes). */
uint16_t ih_protect_tlv_size; /* Size of protected TLV area (bytes). */
uint32_t ih_img_size; /* Does not include header. */
uint32_t ih_flags; /* IMAGE_F_[...]. */
struct image_version ih_ver;
uint32_t _pad1;
};
/** Image TLV header. All fields in little endian. */
struct image_tlv_info {
uint16_t it_magic;
uint16_t it_tlv_tot; /* size of TLV area (including tlv_info header) */
};
/** Image trailer TLV format. All fields in little endian. */
struct image_tlv {
uint16_t it_type; /* IMAGE_TLV_[...]. */
uint16_t it_len; /* Data length (not including TLV header). */
};
#define IS_ENCRYPTED(hdr) ((hdr)->ih_flags & IMAGE_F_ENCRYPTED)
#define MUST_DECRYPT(fap, idx, hdr) \
((fap)->fa_id == FLASH_AREA_IMAGE_SECONDARY(idx) && IS_ENCRYPTED(hdr))
_Static_assert(sizeof(struct image_header) == IMAGE_HEADER_SIZE,
"struct image_header not required size");
struct enc_key_data;
fih_int bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
struct image_header *hdr,
const struct flash_area *fap,
uint8_t *tmp_buf, uint32_t tmp_buf_sz,
uint8_t *seed, int seed_len, uint8_t *out_hash);
struct image_tlv_iter {
const struct image_header *hdr;
const struct flash_area *fap;
uint16_t type;
bool prot;
uint32_t prot_end;
uint32_t tlv_off;
uint32_t tlv_end;
};
int bootutil_tlv_iter_begin(struct image_tlv_iter *it,
const struct image_header *hdr,
const struct flash_area *fap, uint16_t type,
bool prot);
int bootutil_tlv_iter_next(struct image_tlv_iter *it, uint32_t *off,
uint16_t *len, uint16_t *type);
int32_t bootutil_get_img_security_cnt(struct image_header *hdr,
const struct flash_area *fap,
uint32_t *security_cnt);
int boot_compare_version(struct image_version *ver1,
volatile const struct image_version *ver2);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,103 @@
/*
* Copyright (c) 2019-2020, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __SECURITY_CNT_H__
#define __SECURITY_CNT_H__
/**
* @file security_cnt.h
*
* @note The interface must be implemented in a fail-safe way that is
* resistant to asynchronous power failures or it can use hardware
* counters that have this capability, if supported by the platform.
* When a counter incrementation was interrupted it must be able to
* continue the incrementation process or recover the previous consistent
* status of the counters. If the counters have reached a stable status
* (every counter incrementation operation has finished), from that point
* their value cannot decrease due to any kind of power failure.
*
* @note A security counter might be implemented using non-volatile OTP memory
* (i.e. fuses) in which case it is the responsibility of the platform
* code to map each possible security counter values onto the fuse bits
* as the direct usage of counter values can be costly / impractical.
*/
#include <stdint.h>
#include "bootutil/fault_injection_hardening.h"
#ifdef __cplusplus
extern "C" {
#endif
#define BIM_INFO_PAGE_MAGIC 0x96fa
#define BIM_INFO_PAGE_ERASED 0xFFFF
#define BIM_INFO_MAGIC_SZ 2
#define BIM_ITEM_SZ 10
#define BIMINFO_SUCCESS 0
#define BIMINFO_FAIL 22
#define BIMINFO_FULL 0xFF
/* each item consists of status (2 bytes) + image id (4 bytes) + security counter (4 bytes) + item id (2 bytes) */
#define SC_ITEM_ID 0x9373
#define SC_STATUS_EMPTY 0xFFFF
#define SC_STATUS_VALID 0xFCFC
#define SC_STATUS_INVALID 0xF0F0
typedef struct sc_page_head {
uint16_t sc_page_id;
}sc_page_head_t;
typedef struct sc_item {
uint16_t sc_status;
uint16_t image_id;
uint32_t security_counter;
uint16_t item_id;
}sc_item_t;
/**
* Initialises the security counters.
*
* @return FIH_SUCCESS on success
*/
fih_int boot_nv_security_counter_init(void);
/**
* Reads the stored value of a given image's security counter.
*
* @param image_id Index of the image (from 0).
* @param security_cnt Pointer to store the security counter value.
*
* @return FIH_SUCCESS on success
*/
fih_int boot_nv_security_counter_get(uint32_t image_id, fih_int *security_cnt);
/**
* Updates the stored value of a given image's security counter with a new
* security counter value if the new one is greater.
*
* @param image_id Index of the image (from 0).
* @param img_security_cnt New security counter value. The new value must be
* between 0 and UINT32_MAX and it must be greater than
* or equal to the current security counter value.
*
* @return 0 on success; nonzero on failure.
*/
int32_t boot_nv_security_counter_update(uint32_t image_id,
uint32_t img_security_cnt);
/**
* Lock the BIM INFO sector
*/
void lockBimSector(void);
#ifdef __cplusplus
}
#endif
#endif /* __SECURITY_CNT_H__ */
@@ -0,0 +1,68 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#ifndef __BOOTUTIL_SIGN_KEY_H_
#define __BOOTUTIL_SIGN_KEY_H_
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef MCUBOOT_HW_KEY
struct bootutil_key {
const uint8_t *key;
const unsigned int *len;
};
extern const struct bootutil_key bootutil_keys[];
#else
struct bootutil_key {
uint8_t *key;
unsigned int *len;
};
extern struct bootutil_key bootutil_keys[];
/**
* Retrieve the hash of the corresponding public key for image authentication.
*
* @param[in] image_index Index of the image to be authenticated.
* @param[out] public_key_hash Buffer to store the key-hash in.
* @param[in,out] key_hash_size As input the size of the buffer. As output
* the actual key-hash length.
*
* @return 0 on success; nonzero on failure.
*/
int boot_retrieve_public_key_hash(uint8_t image_index,
uint8_t *public_key_hash,
size_t *key_hash_size);
#endif /* !MCUBOOT_HW_KEY */
extern const int bootutil_key_cnt;
#ifdef __cplusplus
}
#endif
#endif /* __BOOTUTIL_SIGN_KEY_H_ */
@@ -0,0 +1,225 @@
/*
* Copyright (c) 2018-2021 Arm Limited
* Copyright (c) 2020 Linaro Limited
*
* 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.
*/
#include <stddef.h>
#include <stdint.h>
#include <limits.h>
#include <stdbool.h>
#include <string.h>
#include "mcuboot_config/mcuboot_config.h"
#if defined(MCUBOOT_MEASURED_BOOT) || defined(MCUBOOT_DATA_SHARING)
#include "bootutil/boot_record.h"
#include "bootutil/boot_status.h"
#include "bootutil_priv.h"
#include "bootutil/image.h"
#include "flash_map_backend/flash_map_backend.h"
/* Error codes for using the shared memory area. */
#define SHARED_MEMORY_OK (0)
#define SHARED_MEMORY_OVERFLOW (1)
#define SHARED_MEMORY_OVERWRITE (2)
#define SHARED_MEMORY_GEN_ERROR (3)
/**
* @var shared_memory_init_done
*
* @brief Indicates whether shared memory area was already initialized.
*
*/
static bool shared_memory_init_done;
/* See in boot_record.h */
int
boot_add_data_to_shared_area(uint8_t major_type,
uint16_t minor_type,
size_t size,
const uint8_t *data)
{
struct shared_data_tlv_entry tlv_entry = {0};
struct shared_boot_data *boot_data;
uint16_t boot_data_size;
uintptr_t tlv_end, offset;
if (data == NULL) {
return SHARED_MEMORY_GEN_ERROR;
}
boot_data = (struct shared_boot_data *)MCUBOOT_SHARED_DATA_BASE;
/* Check whether first time to call this function. If does then initialise
* shared data area.
*/
if (!shared_memory_init_done) {
memset((void *)MCUBOOT_SHARED_DATA_BASE, 0, MCUBOOT_SHARED_DATA_SIZE);
boot_data->header.tlv_magic = SHARED_DATA_TLV_INFO_MAGIC;
boot_data->header.tlv_tot_len = SHARED_DATA_HEADER_SIZE;
shared_memory_init_done = true;
}
/* Check whether TLV entry is already added.
* Get the boundaries of TLV section
*/
tlv_end = MCUBOOT_SHARED_DATA_BASE + boot_data->header.tlv_tot_len;
offset = MCUBOOT_SHARED_DATA_BASE + SHARED_DATA_HEADER_SIZE;
/* Iterates over the TLV section looks for the same entry if found then
* returns with error: SHARED_MEMORY_OVERWRITE
*/
while (offset < tlv_end) {
/* Create local copy to avoid unaligned access */
memcpy(&tlv_entry, (const void *)offset, SHARED_DATA_ENTRY_HEADER_SIZE);
if (GET_MAJOR(tlv_entry.tlv_type) == major_type &&
GET_MINOR(tlv_entry.tlv_type) == minor_type) {
return SHARED_MEMORY_OVERWRITE;
}
offset += SHARED_DATA_ENTRY_SIZE(tlv_entry.tlv_len);
}
/* Add TLV entry */
tlv_entry.tlv_type = SET_TLV_TYPE(major_type, minor_type);
tlv_entry.tlv_len = size;
if (!boot_u16_safe_add(&boot_data_size, boot_data->header.tlv_tot_len,
SHARED_DATA_ENTRY_SIZE(size))) {
return SHARED_MEMORY_GEN_ERROR;
}
/* Verify overflow of shared area */
if (boot_data_size > MCUBOOT_SHARED_DATA_SIZE) {
return SHARED_MEMORY_OVERFLOW;
}
offset = tlv_end;
memcpy((void *)offset, &tlv_entry, SHARED_DATA_ENTRY_HEADER_SIZE);
offset += SHARED_DATA_ENTRY_HEADER_SIZE;
memcpy((void *)offset, data, size);
boot_data->header.tlv_tot_len += SHARED_DATA_ENTRY_SIZE(size);
return SHARED_MEMORY_OK;
}
#endif /* MCUBOOT_MEASURED_BOOT OR MCUBOOT_DATA_SHARING */
#ifdef MCUBOOT_MEASURED_BOOT
/* See in boot_record.h */
int
boot_save_boot_status(uint8_t sw_module,
const struct image_header *hdr,
const struct flash_area *fap)
{
struct image_tlv_iter it;
uint32_t offset;
uint16_t len;
uint16_t type;
uint16_t ias_minor;
size_t record_len = 0;
uint8_t image_hash[32]; /* SHA256 - 32 Bytes */
uint8_t buf[MAX_BOOT_RECORD_SZ];
bool boot_record_found = false;
bool hash_found = false;
int rc;
/* Manifest data is concatenated to the end of the image.
* It is encoded in TLV format.
*/
rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, false);
if (rc) {
return -1;
}
/* Traverse through the TLV area to find the boot record
* and image hash TLVs.
*/
while (true) {
rc = bootutil_tlv_iter_next(&it, &offset, &len, &type);
if (rc < 0) {
return -1;
} else if (rc > 0) {
break;
}
if (type == IMAGE_TLV_BOOT_RECORD) {
if (len > sizeof(buf)) {
return -1;
}
rc = flash_area_read(fap, offset, buf, len);
if (rc) {
return -1;
}
record_len = len;
boot_record_found = true;
} else if (type == IMAGE_TLV_SHA256) {
/* Get the image's hash value from the manifest section. */
if (len > sizeof(image_hash)) {
return -1;
}
rc = flash_area_read(fap, offset, image_hash, len);
if (rc) {
return -1;
}
hash_found = true;
/* The boot record TLV is part of the protected TLV area which is
* located before the other parts of the TLV area (including the
* image hash) so at this point it is okay to break the loop
* as the boot record TLV should have already been found.
*/
break;
}
}
if (!boot_record_found || !hash_found) {
return -1;
}
/* Update the measurement value (hash of the image) data item in the
* boot record. It is always the last item in the structure to make
* it easy to calculate its position.
* The image hash is computed over the image header, the image itself and
* the protected TLV area (which should already include the image hash as
* part of the boot record TLV). For this reason this field has been
* filled with zeros during the image signing process.
*/
offset = record_len - sizeof(image_hash);
/* The size of 'buf' has already been checked when
* the BOOT_RECORD TLV was read, it won't overflow.
*/
memcpy(buf + offset, image_hash, sizeof(image_hash));
/* Add the CBOR encoded boot record to the shared data area. */
ias_minor = SET_IAS_MINOR(sw_module, SW_BOOT_RECORD);
rc = boot_add_data_to_shared_area(TLV_MAJOR_IAS,
ias_minor,
record_len,
buf);
if (rc != SHARED_MEMORY_OK) {
return rc;
}
return 0;
}
#endif /* MCUBOOT_MEASURED_BOOT */
@@ -0,0 +1,385 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2017-2019 Linaro LTD
* Copyright (c) 2016-2019 JUUL Labs
* Copyright (c) 2019-2020 Arm Limited
*
* Original license:
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#include <string.h>
#include <inttypes.h>
#include <stddef.h>
#include "sysflash/sysflash.h"
#include "flash_map_backend/flash_map_backend.h"
#include "bootutil/image.h"
#include "bootutil/bootutil.h"
#include "bootutil_priv.h"
#include "bootutil/bootutil_log.h"
#include "bootutil/fault_injection_hardening.h"
#ifdef MCUBOOT_ENC_IMAGES
#include "bootutil/enc_key.h"
#endif
MCUBOOT_LOG_MODULE_DECLARE(mcuboot);
/* Currently only used by imgmgr */
int boot_current_slot;
extern const uint32_t boot_img_magic[];
#define BOOT_MAGIC_ARR_SZ \
(sizeof boot_img_magic / sizeof boot_img_magic[0])
/**
* @brief Determine if the data at two memory addresses is equal
*
* @param s1 The first memory region to compare.
* @param s2 The second memory region to compare.
* @param n The amount of bytes to compare.
*
* @note This function does not comply with the specification of memcmp,
* so should not be considered a drop-in replacement. It has no
* constant time execution. The point is to make sure that all the
* bytes are compared and detect if loop was abused and some cycles
* was skipped due to fault injection.
*
* @return FIH_SUCCESS if memory regions are equal, otherwise FIH_FAILURE
*/
#ifdef MCUBOOT_FIH_PROFILE_OFF
inline
fih_int boot_fih_memequal(const void *s1, const void *s2, size_t n)
{
return memcmp(s1, s2, n);
}
#else
fih_int boot_fih_memequal(const void *s1, const void *s2, size_t n)
{
size_t i;
uint8_t *s1_p = (uint8_t*) s1;
uint8_t *s2_p = (uint8_t*) s2;
fih_int ret = FIH_FAILURE;
for (i = 0; i < n; i++) {
if (s1_p[i] != s2_p[i]) {
goto out;
}
}
if (i == n) {
ret = FIH_SUCCESS;
}
out:
FIH_RET(ret);
}
#endif
uint32_t
boot_status_sz(uint32_t min_write_sz)
{
return /* state for all sectors */
BOOT_STATUS_MAX_ENTRIES * BOOT_STATUS_STATE_COUNT * min_write_sz;
}
uint32_t
boot_trailer_sz(uint32_t min_write_sz)
{
return /* state for all sectors */
boot_status_sz(min_write_sz) +
#ifdef MCUBOOT_ENC_IMAGES
/* encryption keys */
# if MCUBOOT_SWAP_SAVE_ENCTLV
BOOT_ENC_TLV_ALIGN_SIZE * 2 +
# else
BOOT_ENC_KEY_SIZE * 2 +
# endif
#endif
/* swap_type + copy_done + image_ok + swap_size */
BOOT_MAX_ALIGN * 4 +
BOOT_MAGIC_SZ;
}
int
boot_status_entries(int image_index, const struct flash_area *fap)
{
#if MCUBOOT_SWAP_USING_SCRATCH
if (fap->fa_id == FLASH_AREA_IMAGE_SCRATCH) {
return BOOT_STATUS_STATE_COUNT;
} else
#endif
if (fap->fa_id == FLASH_AREA_IMAGE_PRIMARY(image_index) ||
fap->fa_id == FLASH_AREA_IMAGE_SECONDARY(image_index)) {
return BOOT_STATUS_STATE_COUNT * BOOT_STATUS_MAX_ENTRIES;
}
return -1;
}
uint32_t
boot_status_off(const struct flash_area *fap)
{
uint32_t off_from_end;
uint8_t elem_sz;
elem_sz = flash_area_align(fap);
off_from_end = boot_trailer_sz(elem_sz);
assert(off_from_end <= fap->fa_size);
return fap->fa_size - off_from_end;
}
static inline uint32_t
boot_magic_off(const struct flash_area *fap)
{
return fap->fa_size - BOOT_MAGIC_SZ;
}
static inline uint32_t
boot_image_ok_off(const struct flash_area *fap)
{
return boot_magic_off(fap) - BOOT_MAX_ALIGN;
}
static inline uint32_t
boot_copy_done_off(const struct flash_area *fap)
{
return boot_image_ok_off(fap) - BOOT_MAX_ALIGN;
}
static inline uint32_t
boot_swap_size_off(const struct flash_area *fap)
{
return boot_swap_info_off(fap) - BOOT_MAX_ALIGN;
}
#ifdef MCUBOOT_ENC_IMAGES
static inline uint32_t
boot_enc_key_off(const struct flash_area *fap, uint8_t slot)
{
#if MCUBOOT_SWAP_SAVE_ENCTLV
return boot_swap_size_off(fap) - ((slot + 1) *
((((BOOT_ENC_TLV_SIZE - 1) / BOOT_MAX_ALIGN) + 1) * BOOT_MAX_ALIGN));
#else
return boot_swap_size_off(fap) - ((slot + 1) * BOOT_ENC_KEY_SIZE);
#endif
}
#endif
/**
* This functions tries to locate the status area after an aborted swap,
* by looking for the magic in the possible locations.
*
* If the magic is successfully found, a flash_area * is returned and it
* is the responsibility of the called to close it.
*
* @returns 0 on success, -1 on errors
*/
static int
boot_find_status(int image_index, const struct flash_area **fap)
{
uint32_t magic[BOOT_MAGIC_ARR_SZ];
uint32_t off;
uint8_t areas[2] = {
#if MCUBOOT_SWAP_USING_SCRATCH
FLASH_AREA_IMAGE_SCRATCH,
#endif
FLASH_AREA_IMAGE_PRIMARY(image_index),
};
unsigned int i;
int rc;
/*
* In the middle a swap, tries to locate the area that is currently
* storing a valid magic, first on the primary slot, then on scratch.
* Both "slots" can end up being temporary storage for a swap and it
* is assumed that if magic is valid then other metadata is too,
* because magic is always written in the last step.
*/
for (i = 0; i < sizeof(areas) / sizeof(areas[0]); i++) {
rc = flash_area_open(areas[i], fap);
if (rc != 0) {
return rc;
}
off = boot_magic_off(*fap);
rc = flash_area_read(*fap, off, magic, BOOT_MAGIC_SZ);
if (rc != 0) {
flash_area_close(*fap);
return rc;
}
if (memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ) == 0) {
return 0;
}
flash_area_close(*fap);
}
/* If we got here, no magic was found */
return -1;
}
int
boot_read_swap_size(int image_index, uint32_t *swap_size)
{
uint32_t off;
const struct flash_area *fap;
int rc;
rc = boot_find_status(image_index, &fap);
if (rc == 0) {
off = boot_swap_size_off(fap);
rc = flash_area_read(fap, off, swap_size, sizeof *swap_size);
flash_area_close(fap);
}
return rc;
}
#ifdef MCUBOOT_ENC_IMAGES
int
boot_read_enc_key(int image_index, uint8_t slot, struct boot_status *bs)
{
uint32_t off;
const struct flash_area *fap;
#if MCUBOOT_SWAP_SAVE_ENCTLV
int i;
#endif
int rc;
rc = boot_find_status(image_index, &fap);
if (rc == 0) {
off = boot_enc_key_off(fap, slot);
#if MCUBOOT_SWAP_SAVE_ENCTLV
rc = flash_area_read(fap, off, bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE);
if (rc == 0) {
for (i = 0; i < BOOT_ENC_TLV_ALIGN_SIZE; i++) {
if (bs->enctlv[slot][i] != 0xff) {
break;
}
}
/* Only try to decrypt non-erased TLV metadata */
if (i != BOOT_ENC_TLV_ALIGN_SIZE) {
rc = boot_enc_decrypt(bs->enctlv[slot], bs->enckey[slot]);
}
}
#else
rc = flash_area_read(fap, off, bs->enckey[slot], BOOT_ENC_KEY_SIZE);
#endif
flash_area_close(fap);
}
return rc;
}
#endif
/**
* Write trailer data; status bytes, swap_size, etc
*
* @returns 0 on success, != 0 on error.
*/
static int
boot_write_trailer(const struct flash_area *fap, uint32_t off,
const uint8_t *inbuf, uint8_t inlen)
{
uint8_t buf[BOOT_MAX_ALIGN];
uint8_t align;
uint8_t erased_val;
int rc;
align = flash_area_align(fap);
if (inlen > BOOT_MAX_ALIGN || align > BOOT_MAX_ALIGN) {
return -1;
}
erased_val = flash_area_erased_val(fap);
if (align < inlen) {
align = inlen;
}
memcpy(buf, inbuf, inlen);
memset(&buf[inlen], erased_val, align - inlen);
rc = flash_area_write(fap, off, buf, align);
if (rc != 0) {
return BOOT_EFLASH;
}
return 0;
}
static int
boot_write_trailer_flag(const struct flash_area *fap, uint32_t off,
uint8_t flag_val)
{
const uint8_t buf[1] = { flag_val };
return boot_write_trailer(fap, off, buf, 1);
}
int
boot_write_copy_done(const struct flash_area *fap)
{
uint32_t off;
off = boot_copy_done_off(fap);
BOOT_LOG_DBG("writing copy_done; fa_id=%d off=0x%lx (0x%lx)",
fap->fa_id, (unsigned long)off,
(unsigned long)(fap->fa_off + off));
return boot_write_trailer_flag(fap, off, BOOT_FLAG_SET);
}
int
boot_write_swap_size(const struct flash_area *fap, uint32_t swap_size)
{
uint32_t off;
off = boot_swap_size_off(fap);
BOOT_LOG_DBG("writing swap_size; fa_id=%d off=0x%lx (0x%lx)",
fap->fa_id, (unsigned long)off,
(unsigned long)fap->fa_off + off);
return boot_write_trailer(fap, off, (const uint8_t *) &swap_size, 4);
}
#ifdef MCUBOOT_ENC_IMAGES
int
boot_write_enc_key(const struct flash_area *fap, uint8_t slot,
const struct boot_status *bs)
{
uint32_t off;
int rc;
off = boot_enc_key_off(fap, slot);
BOOT_LOG_DBG("writing enc_key; fa_id=%d off=0x%lx (0x%lx)",
fap->fa_id, (unsigned long)off,
(unsigned long)fap->fa_off + off);
#if MCUBOOT_SWAP_SAVE_ENCTLV
rc = flash_area_write(fap, off, bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE);
#else
rc = flash_area_write(fap, off, bs->enckey[slot], BOOT_ENC_KEY_SIZE);
#endif
if (rc != 0) {
return BOOT_EFLASH;
}
return 0;
}
#endif
@@ -0,0 +1,448 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2017-2020 Linaro LTD
* Copyright (c) 2017-2019 JUUL Labs
* Copyright (c) 2019-2020 Arm Limited
*
* Original license:
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#ifndef H_BOOTUTIL_PRIV_
#define H_BOOTUTIL_PRIV_
#include <string.h>
#include "sysflash/sysflash.h"
#include <flash_map_backend/flash_map_backend.h>
#include "bootutil/bootutil.h"
#include "bootutil/image.h"
#include "bootutil/fault_injection_hardening.h"
#include "mcuboot_config/mcuboot_config.h"
#ifdef MCUBOOT_ENC_IMAGES
#include "bootutil/enc_key.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifdef MCUBOOT_HAVE_ASSERT_H
#include "mcuboot_config/mcuboot_assert.h"
#else
#include <assert.h>
#define ASSERT assert
#endif
struct flash_area;
#define BOOT_EFLASH 1
#define BOOT_EFILE 2
#define BOOT_EBADIMAGE 3
#define BOOT_EBADVECT 4
#define BOOT_EBADSTATUS 5
#define BOOT_ENOMEM 6
#define BOOT_EBADARGS 7
#define BOOT_EBADVERSION 8
#define BOOT_TMPBUF_SZ 256
/** Number of image slots in flash; currently limited to two. */
#define BOOT_NUM_SLOTS 2
#if (defined(MCUBOOT_OVERWRITE_ONLY) + \
defined(MCUBOOT_SWAP_USING_MOVE) + \
defined(MCUBOOT_DIRECT_XIP) + \
defined(MCUBOOT_RAM_LOAD)) > 1
#error "Please enable only one of MCUBOOT_OVERWRITE_ONLY, MCUBOOT_SWAP_USING_MOVE, MCUBOOT_DIRECT_XIP or MCUBOOT_RAM_LOAD"
#endif
#if !defined(MCUBOOT_OVERWRITE_ONLY) && \
!defined(MCUBOOT_SWAP_USING_MOVE) && \
!defined(MCUBOOT_DIRECT_XIP) && \
!defined(MCUBOOT_RAM_LOAD)
#define MCUBOOT_SWAP_USING_SCRATCH 1
#endif
#define BOOT_STATUS_OP_MOVE 1
#define BOOT_STATUS_OP_SWAP 2
/*
* Maintain state of copy progress.
*/
struct boot_status {
uint32_t idx; /* Which area we're operating on */
uint8_t state; /* Which part of the swapping process are we at */
uint8_t op; /* What operation are we performing? */
uint8_t use_scratch; /* Are status bytes ever written to scratch? */
uint8_t swap_type; /* The type of swap in effect */
uint32_t swap_size; /* Total size of swapped image */
#ifdef MCUBOOT_ENC_IMAGES
uint8_t enckey[BOOT_NUM_SLOTS][BOOT_ENC_KEY_SIZE];
#if MCUBOOT_SWAP_SAVE_ENCTLV
uint8_t enctlv[BOOT_NUM_SLOTS][BOOT_ENC_TLV_ALIGN_SIZE];
#endif
#endif
int source; /* Which slot contains swap status metadata */
};
#define BOOT_STATUS_IDX_0 1
#define BOOT_STATUS_STATE_0 1
#define BOOT_STATUS_STATE_1 2
#define BOOT_STATUS_STATE_2 3
/**
* End-of-image slot structure.
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* ~ ~
* ~ Swap status (BOOT_MAX_IMG_SECTORS * min-write-size * 3) ~
* ~ ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Encryption key 0 (16 octets) [*] |
* | |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Encryption key 1 (16 octets) [*] |
* | |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Swap size (4 octets) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Swap info | 0xff padding (7 octets) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Copy done | 0xff padding (7 octets) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Image OK | 0xff padding (7 octets) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | MAGIC (16 octets) |
* | |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* [*]: Only present if the encryption option is enabled
* (`MCUBOOT_ENC_IMAGES`).
*/
extern const uint32_t boot_img_magic[4];
#ifdef MCUBOOT_IMAGE_NUMBER
#define BOOT_IMAGE_NUMBER MCUBOOT_IMAGE_NUMBER
#else
#define BOOT_IMAGE_NUMBER 1
#endif
_Static_assert(BOOT_IMAGE_NUMBER > 0, "Invalid value for BOOT_IMAGE_NUMBER");
#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
#define ARE_SLOTS_EQUIVALENT() 0
#else
#define ARE_SLOTS_EQUIVALENT() 1
#if (BOOT_IMAGE_NUMBER != 1)
#error "The MCUBOOT_DIRECT_XIP and MCUBOOT_RAM_LOAD mode only supports single-image boot (MCUBOOT_IMAGE_NUMBER=1)."
#endif
#ifdef MCUBOOT_ENC_IMAGES
#error "Image encryption (MCUBOOT_ENC_IMAGES) is not supported when MCUBOOT_DIRECT_XIP or MCUBOOT_RAM_LOAD mode is selected."
#endif
#endif /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */
#define BOOT_MAX_IMG_SECTORS MCUBOOT_MAX_IMG_SECTORS
/*
* Extract the swap type and image number from image trailers's swap_info
* filed.
*/
#define BOOT_GET_SWAP_TYPE(swap_info) ((swap_info) & 0x0F)
#define BOOT_GET_IMAGE_NUM(swap_info) ((swap_info) >> 4)
/* Construct the swap_info field from swap type and image number */
#define BOOT_SET_SWAP_INFO(swap_info, image, type) { \
assert((image) < 0xF); \
assert((type) < 0xF); \
(swap_info) = (image) << 4 \
| (type); \
}
#define BOOT_LOG_IMAGE_INFO(slot, hdr) \
BOOT_LOG_INF("%-9s slot: version=%u.%u.%u+%u", \
((slot) == BOOT_PRIMARY_SLOT) ? "Primary" : "Secondary", \
(hdr)->ih_ver.iv_major, \
(hdr)->ih_ver.iv_minor, \
(hdr)->ih_ver.iv_revision, \
(hdr)->ih_ver.iv_build_num)
/*
* The current flashmap API does not check the amount of space allocated when
* loading sector data from the flash device, allowing for smaller counts here
* would most surely incur in overruns.
*
* TODO: make flashmap API receive the current sector array size.
*/
#if BOOT_MAX_IMG_SECTORS < 32
#error "Too few sectors, please increase BOOT_MAX_IMG_SECTORS to at least 32"
#endif
#if MCUBOOT_SWAP_USING_MOVE
#define BOOT_STATUS_MOVE_STATE_COUNT 1
#define BOOT_STATUS_SWAP_STATE_COUNT 2
#define BOOT_STATUS_STATE_COUNT (BOOT_STATUS_MOVE_STATE_COUNT + BOOT_STATUS_SWAP_STATE_COUNT)
#else
#define BOOT_STATUS_STATE_COUNT 3
#endif
/** Maximum number of image sectors supported by the bootloader. */
#define BOOT_STATUS_MAX_ENTRIES BOOT_MAX_IMG_SECTORS
#define BOOT_PRIMARY_SLOT 0
#define BOOT_SECONDARY_SLOT 1
#define BOOT_STATUS_SOURCE_NONE 0
#define BOOT_STATUS_SOURCE_SCRATCH 1
#define BOOT_STATUS_SOURCE_PRIMARY_SLOT 2
/**
* Compatibility shim for flash sector type.
*
* This can be deleted when flash_area_to_sectors() is removed.
*/
#ifdef MCUBOOT_USE_FLASH_AREA_GET_SECTORS
typedef struct flash_sector boot_sector_t;
#else
typedef struct flash_area boot_sector_t;
#endif
/** Private state maintained during boot. */
struct boot_loader_state {
struct {
struct image_header hdr;
const struct flash_area *area;
boot_sector_t *sectors;
size_t num_sectors;
} imgs[BOOT_IMAGE_NUMBER][BOOT_NUM_SLOTS];
#if MCUBOOT_SWAP_USING_SCRATCH
struct {
const struct flash_area *area;
boot_sector_t *sectors;
size_t num_sectors;
} scratch;
#endif
uint8_t swap_type[BOOT_IMAGE_NUMBER];
uint32_t write_sz;
#if defined(MCUBOOT_ENC_IMAGES)
struct enc_key_data enc[BOOT_IMAGE_NUMBER][BOOT_NUM_SLOTS];
#endif
#if (BOOT_IMAGE_NUMBER > 1)
uint8_t curr_img_idx;
#endif
};
fih_int bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig,
size_t slen, uint8_t key_id);
fih_int boot_fih_memequal(const void *s1, const void *s2, size_t n);
int boot_magic_compatible_check(uint8_t tbl_val, uint8_t val);
uint32_t boot_status_sz(uint32_t min_write_sz);
uint32_t boot_trailer_sz(uint32_t min_write_sz);
int boot_status_entries(int image_index, const struct flash_area *fap);
uint32_t boot_status_off(const struct flash_area *fap);
int boot_read_swap_state(const struct flash_area *fap,
struct boot_swap_state *state);
int boot_read_swap_state_by_id(int flash_area_id,
struct boot_swap_state *state);
int boot_write_magic(const struct flash_area *fap);
int boot_write_status(const struct boot_loader_state *state, struct boot_status *bs);
int boot_write_copy_done(const struct flash_area *fap);
int boot_write_image_ok(const struct flash_area *fap);
int boot_write_swap_info(const struct flash_area *fap, uint8_t swap_type,
uint8_t image_num);
int boot_write_swap_size(const struct flash_area *fap, uint32_t swap_size);
int boot_read_swap_size(int image_index, uint32_t *swap_size);
int boot_slots_compatible(struct boot_loader_state *state);
uint32_t boot_status_internal_off(const struct boot_status *bs, int elem_sz);
int boot_read_image_header(struct boot_loader_state *state, int slot,
struct image_header *out_hdr, struct boot_status *bs);
int boot_copy_region(struct boot_loader_state *state,
const struct flash_area *fap_src,
const struct flash_area *fap_dst,
uint32_t off_src, uint32_t off_dst, uint32_t sz);
int boot_erase_region(const struct flash_area *fap, uint32_t off, uint32_t sz);
bool boot_status_is_reset(const struct boot_status *bs);
#ifdef MCUBOOT_ENC_IMAGES
int boot_write_enc_key(const struct flash_area *fap, uint8_t slot,
const struct boot_status *bs);
int boot_read_enc_key(int image_index, uint8_t slot, struct boot_status *bs);
#endif
/**
* Checks that a buffer is erased according to what the erase value for the
* flash device provided in `flash_area` is.
*
* @returns true if the buffer is erased; false if any of the bytes is not
* erased, or when buffer is NULL, or when len == 0.
*/
bool bootutil_buffer_is_erased(const struct flash_area *area,
const void *buffer, size_t len);
/**
* Safe (non-overflowing) uint32_t addition. Returns true, and stores
* the result in *dest if it can be done without overflow. Otherwise,
* returns false.
*/
static inline bool boot_u32_safe_add(uint32_t *dest, uint32_t a, uint32_t b)
{
/*
* "a + b <= UINT32_MAX", subtract 'b' from both sides to avoid
* the overflow.
*/
if (a > UINT32_MAX - b) {
return false;
} else {
*dest = a + b;
return true;
}
}
/**
* Safe (non-overflowing) uint16_t addition. Returns true, and stores
* the result in *dest if it can be done without overflow. Otherwise,
* returns false.
*/
static inline bool boot_u16_safe_add(uint16_t *dest, uint16_t a, uint16_t b)
{
uint32_t tmp = a + b;
if (tmp > UINT16_MAX) {
return false;
} else {
*dest = tmp;
return true;
}
}
/*
* Accessors for the contents of struct boot_loader_state.
*/
/* These are macros so they can be used as lvalues. */
#if (BOOT_IMAGE_NUMBER > 1)
#define BOOT_CURR_IMG(state) ((state)->curr_img_idx)
#else
#define BOOT_CURR_IMG(state) 0
#endif
#ifdef MCUBOOT_ENC_IMAGES
#define BOOT_CURR_ENC(state) ((state)->enc[BOOT_CURR_IMG(state)])
#else
#define BOOT_CURR_ENC(state) NULL
#endif
#define BOOT_IMG(state, slot) ((state)->imgs[BOOT_CURR_IMG(state)][(slot)])
#define BOOT_IMG_AREA(state, slot) (BOOT_IMG(state, slot).area)
#define BOOT_WRITE_SZ(state) ((state)->write_sz)
#define BOOT_SWAP_TYPE(state) ((state)->swap_type[BOOT_CURR_IMG(state)])
#define BOOT_TLV_OFF(hdr) ((hdr)->ih_hdr_size + (hdr)->ih_img_size)
#define BOOT_IS_UPGRADE(swap_type) \
(((swap_type) == BOOT_SWAP_TYPE_TEST) || \
((swap_type) == BOOT_SWAP_TYPE_REVERT) || \
((swap_type) == BOOT_SWAP_TYPE_PERM))
static inline struct image_header*
boot_img_hdr(struct boot_loader_state *state, size_t slot)
{
return &BOOT_IMG(state, slot).hdr;
}
static inline size_t
boot_img_num_sectors(const struct boot_loader_state *state, size_t slot)
{
return BOOT_IMG(state, slot).num_sectors;
}
/*
* Offset of the slot from the beginning of the flash device.
*/
static inline uint32_t
boot_img_slot_off(struct boot_loader_state *state, size_t slot)
{
return BOOT_IMG(state, slot).area->fa_off;
}
#ifndef MCUBOOT_USE_FLASH_AREA_GET_SECTORS
static inline size_t
boot_img_sector_size(const struct boot_loader_state *state,
size_t slot, size_t sector)
{
return BOOT_IMG(state, slot).sectors[sector].fa_size;
}
/*
* Offset of the sector from the beginning of the image, NOT the flash
* device.
*/
static inline uint32_t
boot_img_sector_off(const struct boot_loader_state *state, size_t slot,
size_t sector)
{
return BOOT_IMG(state, slot).sectors[sector].fa_off -
BOOT_IMG(state, slot).sectors[0].fa_off;
}
#else /* defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */
static inline size_t
boot_img_sector_size(const struct boot_loader_state *state,
size_t slot, size_t sector)
{
return BOOT_IMG(state, slot).sectors[sector].fs_size;
}
static inline uint32_t
boot_img_sector_off(const struct boot_loader_state *state, size_t slot,
size_t sector)
{
return BOOT_IMG(state, slot).sectors[sector].fs_off -
BOOT_IMG(state, slot).sectors[0].fs_off;
}
#endif /* !defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */
#ifdef MCUBOOT_RAM_LOAD
#define LOAD_IMAGE_DATA(hdr, fap, start, output, size) \
(memcpy((output),(void*)((hdr)->ih_load_addr + (start)), \
(size)), 0)
#else
#define LOAD_IMAGE_DATA(hdr, fap, start, output, size) \
(flash_area_read((fap), (start), (output), (size)))
#endif /* MCUBOOT_RAM_LOAD */
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,604 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2017-2019 Linaro LTD
* Copyright (c) 2016-2019 JUUL Labs
* Copyright (c) 2019-2020 Arm Limited
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* Original license:
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
* @brief Public MCUBoot interface API implementation
*
* This file contains API implementation which can be combined with
* the application in order to interact with the MCUBoot bootloader.
* This file contains shared code-base betwen MCUBoot and the application
* which controls DFU process.
*/
#include <string.h>
#include <inttypes.h>
#include <stddef.h>
#include "sysflash/sysflash.h"
#include "flash_map_backend/flash_map_backend.h"
#include "bootutil/image.h"
#include "bootutil/bootutil_public.h"
#include "bootutil_priv.h"
#include "bootutil/bootutil_log.h"
#ifdef MCUBOOT_ENC_IMAGES
#include "bootutil/enc_key.h"
#endif
#ifdef CONFIG_MCUBOOT
MCUBOOT_LOG_MODULE_DECLARE(mcuboot);
#else
MCUBOOT_LOG_MODULE_REGISTER(mcuboot_util);
#endif
const uint32_t boot_img_magic[] = {
0xf395c277,
0x7fefd260,
0x0f505235,
0x8079b62c,
};
#define BOOT_MAGIC_ARR_SZ \
(sizeof boot_img_magic / sizeof boot_img_magic[0])
struct boot_swap_table {
uint8_t magic_primary_slot;
uint8_t magic_secondary_slot;
uint8_t image_ok_primary_slot;
uint8_t image_ok_secondary_slot;
uint8_t copy_done_primary_slot;
uint8_t swap_type;
};
/**
* This set of tables maps image trailer contents to swap operation type.
* When searching for a match, these tables must be iterated sequentially.
*
* NOTE: the table order is very important. The settings in the secondary
* slot always are priority to the primary slot and should be located
* earlier in the table.
*
* The table lists only states where there is action needs to be taken by
* the bootloader, as in starting/finishing a swap operation.
*/
static const struct boot_swap_table boot_swap_tables[] = {
{
.magic_primary_slot = BOOT_MAGIC_ANY,
.magic_secondary_slot = BOOT_MAGIC_GOOD,
.image_ok_primary_slot = BOOT_FLAG_ANY,
.image_ok_secondary_slot = BOOT_FLAG_UNSET,
.copy_done_primary_slot = BOOT_FLAG_ANY,
.swap_type = BOOT_SWAP_TYPE_TEST,
},
{
.magic_primary_slot = BOOT_MAGIC_ANY,
.magic_secondary_slot = BOOT_MAGIC_GOOD,
.image_ok_primary_slot = BOOT_FLAG_ANY,
.image_ok_secondary_slot = BOOT_FLAG_SET,
.copy_done_primary_slot = BOOT_FLAG_ANY,
.swap_type = BOOT_SWAP_TYPE_PERM,
},
{
.magic_primary_slot = BOOT_MAGIC_GOOD,
.magic_secondary_slot = BOOT_MAGIC_UNSET,
.image_ok_primary_slot = BOOT_FLAG_UNSET,
.image_ok_secondary_slot = BOOT_FLAG_ANY,
.copy_done_primary_slot = BOOT_FLAG_SET,
.swap_type = BOOT_SWAP_TYPE_REVERT,
},
};
#define BOOT_SWAP_TABLES_COUNT \
(sizeof boot_swap_tables / sizeof boot_swap_tables[0])
static int
boot_magic_decode(const uint32_t *magic)
{
if (memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ) == 0) {
return BOOT_MAGIC_GOOD;
}
return BOOT_MAGIC_BAD;
}
static int
boot_flag_decode(uint8_t flag)
{
if (flag != BOOT_FLAG_SET) {
return BOOT_FLAG_BAD;
}
return BOOT_FLAG_SET;
}
static inline uint32_t
boot_magic_off(const struct flash_area *fap)
{
return fap->fa_size - BOOT_MAGIC_SZ;
}
static inline uint32_t
boot_image_ok_off(const struct flash_area *fap)
{
return boot_magic_off(fap) - BOOT_MAX_ALIGN;
}
static inline uint32_t
boot_copy_done_off(const struct flash_area *fap)
{
return boot_image_ok_off(fap) - BOOT_MAX_ALIGN;
}
static inline uint32_t
boot_swap_size_off(const struct flash_area *fap)
{
return boot_swap_info_off(fap) - BOOT_MAX_ALIGN;
}
uint32_t
boot_swap_info_off(const struct flash_area *fap)
{
return boot_copy_done_off(fap) - BOOT_MAX_ALIGN;
}
/**
* Determines if a status source table is satisfied by the specified magic
* code.
*
* @param tbl_val A magic field from a status source table.
* @param val The magic value in a trailer, encoded as a
* BOOT_MAGIC_[...].
*
* @return 1 if the two values are compatible;
* 0 otherwise.
*/
int
boot_magic_compatible_check(uint8_t tbl_val, uint8_t val)
{
switch (tbl_val) {
case BOOT_MAGIC_ANY:
return 1;
case BOOT_MAGIC_NOTGOOD:
return val != BOOT_MAGIC_GOOD;
default:
return tbl_val == val;
}
}
#ifdef MCUBOOT_ENC_IMAGES
static inline uint32_t
boot_enc_key_off(const struct flash_area *fap, uint8_t slot)
{
#if MCUBOOT_SWAP_SAVE_ENCTLV
return boot_swap_size_off(fap) - ((slot + 1) *
((((BOOT_ENC_TLV_SIZE - 1) / BOOT_MAX_ALIGN) + 1) * BOOT_MAX_ALIGN));
#else
return boot_swap_size_off(fap) - ((slot + 1) * BOOT_ENC_KEY_SIZE);
#endif
}
#endif
bool bootutil_buffer_is_erased(const struct flash_area *area,
const void *buffer, size_t len)
{
size_t i;
uint8_t *u8b;
uint8_t erased_val;
if (buffer == NULL || len == 0) {
return false;
}
erased_val = flash_area_erased_val(area);
for (i = 0, u8b = (uint8_t *)buffer; i < len; i++) {
if (u8b[i] != erased_val) {
return false;
}
}
return true;
}
static int
boot_read_flag(const struct flash_area *fap, uint8_t *flag, uint32_t off)
{
int rc;
rc = flash_area_read(fap, off, flag, sizeof *flag);
if (rc < 0) {
return BOOT_EFLASH;
}
if (bootutil_buffer_is_erased(fap, flag, sizeof *flag)) {
*flag = BOOT_FLAG_UNSET;
} else {
*flag = boot_flag_decode(*flag);
}
return 0;
}
static inline int
boot_read_copy_done(const struct flash_area *fap, uint8_t *copy_done)
{
return boot_read_flag(fap, copy_done, boot_copy_done_off(fap));
}
int
boot_read_swap_state(const struct flash_area *fap,
struct boot_swap_state *state)
{
uint32_t magic[BOOT_MAGIC_ARR_SZ];
uint32_t off;
uint8_t swap_info;
int rc;
off = boot_magic_off(fap);
rc = flash_area_read(fap, off, magic, BOOT_MAGIC_SZ);
if (rc < 0) {
return BOOT_EFLASH;
}
if (bootutil_buffer_is_erased(fap, magic, BOOT_MAGIC_SZ)) {
state->magic = BOOT_MAGIC_UNSET;
} else {
state->magic = boot_magic_decode(magic);
}
off = boot_swap_info_off(fap);
rc = flash_area_read(fap, off, &swap_info, sizeof swap_info);
if (rc < 0) {
return BOOT_EFLASH;
}
/* Extract the swap type and image number */
state->swap_type = BOOT_GET_SWAP_TYPE(swap_info);
state->image_num = BOOT_GET_IMAGE_NUM(swap_info);
if (bootutil_buffer_is_erased(fap, &swap_info, sizeof swap_info) ||
state->swap_type > BOOT_SWAP_TYPE_REVERT) {
state->swap_type = BOOT_SWAP_TYPE_NONE;
state->image_num = 0;
}
rc = boot_read_copy_done(fap, &state->copy_done);
if (rc) {
return BOOT_EFLASH;
}
return boot_read_image_ok(fap, &state->image_ok);
}
int
boot_read_swap_state_by_id(int flash_area_id, struct boot_swap_state *state)
{
const struct flash_area *fap;
int rc;
rc = flash_area_open(flash_area_id, &fap);
if (rc != 0) {
return BOOT_EFLASH;
}
rc = boot_read_swap_state(fap, state);
flash_area_close(fap);
return rc;
}
int
boot_write_magic(const struct flash_area *fap)
{
uint32_t off;
int rc;
off = boot_magic_off(fap);
BOOT_LOG_DBG("writing magic; fa_id=%d off=0x%lx (0x%lx)",
fap->fa_id, (unsigned long)off,
(unsigned long)(fap->fa_off + off));
rc = flash_area_write(fap, off, boot_img_magic, BOOT_MAGIC_SZ);
if (rc != 0) {
return BOOT_EFLASH;
}
return 0;
}
/**
* Write trailer data; status bytes, swap_size, etc
*
* @returns 0 on success, != 0 on error.
*/
static int
boot_write_trailer(const struct flash_area *fap, uint32_t off,
const uint8_t *inbuf, uint8_t inlen)
{
uint8_t buf[BOOT_MAX_ALIGN];
uint8_t align;
uint8_t erased_val;
int rc;
align = flash_area_align(fap);
if (inlen > BOOT_MAX_ALIGN || align > BOOT_MAX_ALIGN) {
return -1;
}
erased_val = flash_area_erased_val(fap);
if (align < inlen) {
align = inlen;
}
memcpy(buf, inbuf, inlen);
memset(&buf[inlen], erased_val, align - inlen);
rc = flash_area_write(fap, off, buf, align);
if (rc != 0) {
return BOOT_EFLASH;
}
return 0;
}
static int
boot_write_trailer_flag(const struct flash_area *fap, uint32_t off,
uint8_t flag_val)
{
const uint8_t buf[1] = { flag_val };
return boot_write_trailer(fap, off, buf, 1);
}
int
boot_write_image_ok(const struct flash_area *fap)
{
uint32_t off;
off = boot_image_ok_off(fap);
BOOT_LOG_DBG("writing image_ok; fa_id=%d off=0x%lx (0x%lx)",
fap->fa_id, (unsigned long)off,
(unsigned long)(fap->fa_off + off));
return boot_write_trailer_flag(fap, off, BOOT_FLAG_SET);
}
int
boot_read_image_ok(const struct flash_area *fap, uint8_t *image_ok)
{
return boot_read_flag(fap, image_ok, boot_image_ok_off(fap));
}
/**
* Writes the specified value to the `swap-type` field of an image trailer.
* This value is persisted so that the boot loader knows what swap operation to
* resume in case of an unexpected reset.
*/
int
boot_write_swap_info(const struct flash_area *fap, uint8_t swap_type,
uint8_t image_num)
{
uint32_t off;
uint8_t swap_info;
BOOT_SET_SWAP_INFO(swap_info, image_num, swap_type);
off = boot_swap_info_off(fap);
BOOT_LOG_DBG("writing swap_info; fa_id=%d off=0x%lx (0x%lx), swap_type=0x%x"
" image_num=0x%x",
fap->fa_id, (unsigned long)off,
(unsigned long)(fap->fa_off + off), swap_type, image_num);
return boot_write_trailer(fap, off, (const uint8_t *) &swap_info, 1);
}
int
boot_swap_type_multi(int image_index)
{
const struct boot_swap_table *table;
struct boot_swap_state primary_slot;
struct boot_swap_state secondary_slot;
int rc;
size_t i;
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY(image_index),
&primary_slot);
if (rc) {
return BOOT_SWAP_TYPE_PANIC;
}
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY(image_index),
&secondary_slot);
if (rc) {
return BOOT_SWAP_TYPE_PANIC;
}
for (i = 0; i < BOOT_SWAP_TABLES_COUNT; i++) {
table = boot_swap_tables + i;
if (boot_magic_compatible_check(table->magic_primary_slot,
primary_slot.magic) &&
boot_magic_compatible_check(table->magic_secondary_slot,
secondary_slot.magic) &&
(table->image_ok_primary_slot == BOOT_FLAG_ANY ||
table->image_ok_primary_slot == primary_slot.image_ok) &&
(table->image_ok_secondary_slot == BOOT_FLAG_ANY ||
table->image_ok_secondary_slot == secondary_slot.image_ok) &&
(table->copy_done_primary_slot == BOOT_FLAG_ANY ||
table->copy_done_primary_slot == primary_slot.copy_done)) {
BOOT_LOG_INF("Swap type: %s",
table->swap_type == BOOT_SWAP_TYPE_TEST ? "test" :
table->swap_type == BOOT_SWAP_TYPE_PERM ? "perm" :
table->swap_type == BOOT_SWAP_TYPE_REVERT ? "revert" :
"BUG; can't happen");
if (table->swap_type != BOOT_SWAP_TYPE_TEST &&
table->swap_type != BOOT_SWAP_TYPE_PERM &&
table->swap_type != BOOT_SWAP_TYPE_REVERT) {
return BOOT_SWAP_TYPE_PANIC;
}
return table->swap_type;
}
}
BOOT_LOG_INF("Swap type: none");
return BOOT_SWAP_TYPE_NONE;
}
/*
* This function is not used by the bootloader itself, but its required API
* by external tooling like mcumgr.
*/
int
boot_swap_type(void)
{
return boot_swap_type_multi(0);
}
/**
* Marks the image in the secondary slot as pending. On the next reboot,
* the system will perform a one-time boot of the the secondary slot image.
*
* @param permanent Whether the image should be used permanently or
* only tested once:
* 0=run image once, then confirm or revert.
* 1=run image forever.
*
* @return 0 on success; nonzero on failure.
*/
int
boot_set_pending(int permanent)
{
const struct flash_area *fap;
struct boot_swap_state state_secondary_slot;
uint8_t swap_type;
int rc;
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY(0),
&state_secondary_slot);
if (rc != 0) {
return rc;
}
switch (state_secondary_slot.magic) {
case BOOT_MAGIC_GOOD:
/* Swap already scheduled. */
return 0;
case BOOT_MAGIC_UNSET:
rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(0), &fap);
if (rc != 0) {
rc = BOOT_EFLASH;
} else {
rc = boot_write_magic(fap);
}
if (rc == 0 && permanent) {
rc = boot_write_image_ok(fap);
}
if (rc == 0) {
if (permanent) {
swap_type = BOOT_SWAP_TYPE_PERM;
} else {
swap_type = BOOT_SWAP_TYPE_TEST;
}
rc = boot_write_swap_info(fap, swap_type, 0);
}
flash_area_close(fap);
return rc;
case BOOT_MAGIC_BAD:
/* The image slot is corrupt. There is no way to recover, so erase the
* slot to allow future upgrades.
*/
rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(0), &fap);
if (rc != 0) {
return BOOT_EFLASH;
}
flash_area_erase(fap, 0, fap->fa_size);
flash_area_close(fap);
return BOOT_EBADIMAGE;
default:
assert(0);
return BOOT_EBADIMAGE;
}
}
/**
* Marks the image in the primary slot as confirmed. The system will continue
* booting into the image in the primary slot until told to boot from a
* different slot.
*
* @return 0 on success; nonzero on failure.
*/
int
boot_set_confirmed(void)
{
const struct flash_area *fap;
struct boot_swap_state state_primary_slot;
int rc;
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY(0),
&state_primary_slot);
if (rc != 0) {
return rc;
}
switch (state_primary_slot.magic) {
case BOOT_MAGIC_GOOD:
/* Confirm needed; proceed. */
break;
case BOOT_MAGIC_UNSET:
/* Already confirmed. */
return 0;
case BOOT_MAGIC_BAD:
/* Unexpected state. */
return BOOT_EBADVECT;
}
rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(0), &fap);
if (rc) {
rc = BOOT_EFLASH;
goto done;
}
if (state_primary_slot.copy_done == BOOT_FLAG_UNSET) {
/* Swap never completed. This is unexpected. */
rc = BOOT_EBADVECT;
goto done;
}
if (state_primary_slot.image_ok != BOOT_FLAG_UNSET) {
/* Already confirmed. */
goto done;
}
rc = boot_write_image_ok(fap);
done:
flash_area_close(fap);
return rc;
}
@@ -0,0 +1,82 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2017 Linaro Limited
*
* 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.
*/
#include <bootutil/caps.h>
#include "mcuboot_config/mcuboot_config.h"
uint32_t bootutil_get_caps(void)
{
uint32_t res = 0;
#if defined(MCUBOOT_SIGN_RSA)
#if MCUBOOT_SIGN_RSA_LEN == 2048
res |= BOOTUTIL_CAP_RSA2048;
#endif
#if MCUBOOT_SIGN_RSA_LEN == 3072
res |= BOOTUTIL_CAP_RSA3072;
#endif
#endif
#if defined(MCUBOOT_SIGN_EC)
res |= BOOTUTIL_CAP_ECDSA_P224;
#endif
#if defined(MCUBOOT_SIGN_EC256)
res |= BOOTUTIL_CAP_ECDSA_P256;
#endif
#if defined(MCUBOOT_SIGN_ED25519)
res |= BOOTUTIL_CAP_ED25519;
#endif
#if defined(MCUBOOT_OVERWRITE_ONLY)
res |= BOOTUTIL_CAP_OVERWRITE_UPGRADE;
#elif defined(MCUBOOT_SWAP_USING_MOVE)
res |= BOOTUTIL_CAP_SWAP_USING_MOVE;
#else
res |= BOOTUTIL_CAP_SWAP_USING_SCRATCH;
#endif
#if defined(MCUBOOT_ENCRYPT_RSA)
res |= BOOTUTIL_CAP_ENC_RSA;
#endif
#if defined(MCUBOOT_ENCRYPT_KW)
res |= BOOTUTIL_CAP_ENC_KW;
#endif
#if defined(MCUBOOT_ENCRYPT_EC256)
res |= BOOTUTIL_CAP_ENC_EC256;
#endif
#if defined(MCUBOOT_ENCRYPT_X25519)
res |= BOOTUTIL_CAP_ENC_X25519;
#endif
#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
res |= BOOTUTIL_CAP_VALIDATE_PRIMARY_SLOT;
#endif
#if defined(MCUBOOT_DOWNGRADE_PREVENTION)
res |= BOOTUTIL_CAP_DOWNGRADE_PREVENTION;
#endif
#if defined(MCUBOOT_BOOTSTRAP)
res |= BOOTUTIL_CAP_BOOTSTRAP;
#endif
return res;
}
uint32_t bootutil_get_num_images(void)
{
#if defined(MCUBOOT_IMAGE_NUMBER)
return MCUBOOT_IMAGE_NUMBER;
#else
return 1;
#endif
}
@@ -0,0 +1,774 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2018-2019 JUUL Labs
* Copyright (c) 2019 Arm Limited
*/
#include "mcuboot_config/mcuboot_config.h"
#if defined(MCUBOOT_ENC_IMAGES)
#include <stddef.h>
#include <inttypes.h>
#include <string.h>
#if defined(MCUBOOT_ENCRYPT_RSA)
#include "mbedtls/rsa.h"
#include "mbedtls/rsa_internal.h"
#include "mbedtls/asn1.h"
#endif
#if defined(MCUBOOT_ENCRYPT_KW)
#include "bootutil/crypto/aes_kw.h"
#endif
#if defined(MCUBOOT_ENCRYPT_EC256)
#include "bootutil/crypto/ecdh_p256.h"
#endif
#if defined(MCUBOOT_ENCRYPT_X25519)
#include "bootutil/crypto/ecdh_x25519.h"
#endif
#if defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519)
#include "bootutil/crypto/sha256.h"
#include "bootutil/crypto/hmac_sha256.h"
#include "mbedtls/oid.h"
#include "mbedtls/asn1.h"
#endif
#include "bootutil/image.h"
#include "bootutil/enc_key.h"
#include "bootutil/sign_key.h"
#include "bootutil_priv.h"
#if defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519)
#if defined(_compare)
static inline int bootutil_constant_time_compare(const uint8_t *a, const uint8_t *b, size_t size)
{
return _compare(a, b, size);
}
#else
static int bootutil_constant_time_compare(const uint8_t *a, const uint8_t *b, size_t size)
{
const uint8_t *tempa = a;
const uint8_t *tempb = b;
uint8_t result = 0;
unsigned int i;
for (i = 0; i < size; i++) {
result |= tempa[i] ^ tempb[i];
}
return result;
}
#endif
#endif
#if defined(MCUBOOT_ENCRYPT_KW)
static int
key_unwrap(const uint8_t *wrapped, uint8_t *enckey)
{
bootutil_aes_kw_context aes_kw;
int rc;
bootutil_aes_kw_init(&aes_kw);
rc = bootutil_aes_kw_set_unwrap_key(&aes_kw, bootutil_enc_key.key, *bootutil_enc_key.len);
if (rc != 0) {
goto done;
}
rc = bootutil_aes_kw_unwrap(&aes_kw, wrapped, TLV_ENC_KW_SZ, enckey, BOOT_ENC_KEY_SIZE);
if (rc != 0) {
goto done;
}
done:
bootutil_aes_kw_drop(&aes_kw);
return rc;
}
#endif /* MCUBOOT_ENCRYPT_KW */
#if defined(MCUBOOT_ENCRYPT_RSA)
static int
parse_rsa_enckey(mbedtls_rsa_context *ctx, uint8_t **p, uint8_t *end)
{
size_t len;
if (mbedtls_asn1_get_tag(p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) {
return -1;
}
if (*p + len != end) {
return -2;
}
/* Non-optional fields. */
if ( /* version */
mbedtls_asn1_get_int(p, end, &ctx->ver) != 0 ||
/* public modulus */
mbedtls_asn1_get_mpi(p, end, &ctx->N) != 0 ||
/* public exponent */
mbedtls_asn1_get_mpi(p, end, &ctx->E) != 0 ||
/* private exponent */
mbedtls_asn1_get_mpi(p, end, &ctx->D) != 0 ||
/* primes */
mbedtls_asn1_get_mpi(p, end, &ctx->P) != 0 ||
mbedtls_asn1_get_mpi(p, end, &ctx->Q) != 0) {
return -3;
}
#if !defined(MBEDTLS_RSA_NO_CRT)
/*
* DP/DQ/QP are only used inside mbedTLS if it was built with the
* Chinese Remainder Theorem enabled (default). In case it is disabled
* we parse, or if not available, we calculate those values.
*/
if (*p < end) {
if ( /* d mod (p-1) and d mod (q-1) */
mbedtls_asn1_get_mpi(p, end, &ctx->DP) != 0 ||
mbedtls_asn1_get_mpi(p, end, &ctx->DQ) != 0 ||
/* q ^ (-1) mod p */
mbedtls_asn1_get_mpi(p, end, &ctx->QP) != 0) {
return -4;
}
} else {
if (mbedtls_rsa_deduce_crt(&ctx->P, &ctx->Q, &ctx->D,
&ctx->DP, &ctx->DQ, &ctx->QP) != 0) {
return -5;
}
}
#endif
ctx->len = mbedtls_mpi_size(&ctx->N);
if (mbedtls_rsa_check_privkey(ctx) != 0) {
return -6;
}
return 0;
}
#endif
#if defined(MCUBOOT_ENCRYPT_EC256)
static const uint8_t ec_pubkey_oid[] = MBEDTLS_OID_EC_ALG_UNRESTRICTED;
static const uint8_t ec_secp256r1_oid[] = MBEDTLS_OID_EC_GRP_SECP256R1;
#define SHARED_KEY_LEN NUM_ECC_BYTES
#define PRIV_KEY_LEN NUM_ECC_BYTES
/*
* Parses the output of `imgtool keygen`, which produces a PKCS#8 elliptic
* curve keypair. See RFC5208 and RFC5915.
*/
static int
parse_ec256_enckey(uint8_t **p, uint8_t *end, uint8_t *private_key)
{
int rc;
size_t len;
int version;
mbedtls_asn1_buf alg;
mbedtls_asn1_buf param;
if ((rc = mbedtls_asn1_get_tag(p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
return -1;
}
if (*p + len != end) {
return -2;
}
version = 0;
if (mbedtls_asn1_get_int(p, end, &version) || version != 0) {
return -3;
}
if ((rc = mbedtls_asn1_get_alg(p, end, &alg, &param)) != 0) {
return -5;
}
if (alg.len != sizeof(ec_pubkey_oid) - 1 ||
memcmp(alg.p, ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) {
return -6;
}
if (param.len != sizeof(ec_secp256r1_oid) - 1 ||
memcmp(param.p, ec_secp256r1_oid, sizeof(ec_secp256r1_oid) - 1)) {
return -7;
}
if ((rc = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_OCTET_STRING)) != 0) {
return -8;
}
/* RFC5915 - ECPrivateKey */
if ((rc = mbedtls_asn1_get_tag(p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
return -9;
}
version = 0;
if (mbedtls_asn1_get_int(p, end, &version) || version != 1) {
return -10;
}
/* privateKey */
if ((rc = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_OCTET_STRING)) != 0) {
return -11;
}
if (len != NUM_ECC_BYTES) {
return -12;
}
memcpy(private_key, *p, len);
/* publicKey usually follows but is not parsed here */
return 0;
}
#endif /* defined(MCUBOOT_ENCRYPT_EC256) */
#if defined(MCUBOOT_ENCRYPT_X25519)
#define X25519_OID "\x6e"
static const uint8_t ec_pubkey_oid[] = MBEDTLS_OID_ISO_IDENTIFIED_ORG \
MBEDTLS_OID_ORG_GOV X25519_OID;
#define SHARED_KEY_LEN 32
#define PRIV_KEY_LEN 32
static int
parse_x25519_enckey(uint8_t **p, uint8_t *end, uint8_t *private_key)
{
size_t len;
int version;
mbedtls_asn1_buf alg;
mbedtls_asn1_buf param;
if (mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
MBEDTLS_ASN1_SEQUENCE) != 0) {
return -1;
}
if (*p + len != end) {
return -2;
}
version = 0;
if (mbedtls_asn1_get_int(p, end, &version) || version != 0) {
return -3;
}
if (mbedtls_asn1_get_alg(p, end, &alg, &param) != 0) {
return -4;
}
if (alg.len != sizeof(ec_pubkey_oid) - 1 ||
memcmp(alg.p, ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) {
return -5;
}
if (mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_OCTET_STRING) != 0) {
return -6;
}
if (mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_OCTET_STRING) != 0) {
return -7;
}
if (len != PRIV_KEY_LEN) {
return -8;
}
memcpy(private_key, *p, PRIV_KEY_LEN);
return 0;
}
#endif /* defined(MCUBOOT_ENCRYPT_X25519) */
#if defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519)
/*
* HKDF as described by RFC5869.
*
* @param ikm The input data to be derived.
* @param ikm_len Length of the input data.
* @param info An information tag.
* @param info_len Length of the information tag.
* @param okm Output of the KDF computation.
* @param okm_len On input the requested length; on output the generated length
*/
static int
hkdf(uint8_t *ikm, uint16_t ikm_len, uint8_t *info, uint16_t info_len,
uint8_t *okm, uint16_t *okm_len)
{
bootutil_hmac_sha256_context hmac;
uint8_t salt[BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE];
uint8_t prk[BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE];
uint8_t T[BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE];
uint16_t off;
uint16_t len;
uint8_t counter;
bool first;
int rc;
/*
* Extract
*/
if (ikm == NULL || okm == NULL || ikm_len == 0) {
return -1;
}
bootutil_hmac_sha256_init(&hmac);
memset(salt, 0, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
rc = bootutil_hmac_sha256_set_key(&hmac, salt, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
if (rc != 0) {
goto error;
}
rc = bootutil_hmac_sha256_update(&hmac, ikm, ikm_len);
if (rc != 0) {
goto error;
}
rc = bootutil_hmac_sha256_finish(&hmac, prk, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
if (rc != 0) {
goto error;
}
/*
* Expand
*/
len = *okm_len;
counter = 1;
first = true;
for (off = 0; len > 0; off += BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE, ++counter) {
bootutil_hmac_sha256_init(&hmac);
rc = bootutil_hmac_sha256_set_key(&hmac, prk, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
if (rc != 0) {
goto error;
}
if (first) {
first = false;
} else {
rc = bootutil_hmac_sha256_update(&hmac, T, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
if (rc != 0) {
goto error;
}
}
rc = bootutil_hmac_sha256_update(&hmac, info, info_len);
if (rc != 0) {
goto error;
}
rc = bootutil_hmac_sha256_update(&hmac, &counter, 1);
if (rc != 0) {
goto error;
}
rc = bootutil_hmac_sha256_finish(&hmac, T, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
if (rc != 0) {
goto error;
}
if (len > BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE) {
memcpy(&okm[off], T, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
len -= BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE;
} else {
memcpy(&okm[off], T, len);
len = 0;
}
}
bootutil_hmac_sha256_drop(&hmac);
return 0;
error:
bootutil_hmac_sha256_drop(&hmac);
return -1;
}
#endif
int
boot_enc_init(struct enc_key_data *enc_state, uint8_t slot)
{
bootutil_aes_ctr_init(&enc_state[slot].aes_ctr);
return 0;
}
int
boot_enc_drop(struct enc_key_data *enc_state, uint8_t slot)
{
bootutil_aes_ctr_drop(&enc_state[slot].aes_ctr);
return 0;
}
int
boot_enc_set_key(struct enc_key_data *enc_state, uint8_t slot,
const struct boot_status *bs)
{
int rc;
rc = bootutil_aes_ctr_set_key(&enc_state[slot].aes_ctr, bs->enckey[slot]);
if (rc != 0) {
boot_enc_drop(enc_state, slot);
enc_state[slot].valid = 0;
return -1;
}
enc_state[slot].valid = 1;
return 0;
}
#define EXPECTED_ENC_LEN BOOT_ENC_TLV_SIZE
#if defined(MCUBOOT_ENCRYPT_RSA)
# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_RSA2048
#elif defined(MCUBOOT_ENCRYPT_KW)
# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_KW128
#elif defined(MCUBOOT_ENCRYPT_EC256)
# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_EC256
# define EC_PUBK_INDEX (1)
# define EC_TAG_INDEX (65)
# define EC_CIPHERKEY_INDEX (65 + 32)
_Static_assert(EC_CIPHERKEY_INDEX + 16 == EXPECTED_ENC_LEN,
"Please fix ECIES-P256 component indexes");
#elif defined(MCUBOOT_ENCRYPT_X25519)
# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_X25519
# define EC_PUBK_INDEX (0)
# define EC_TAG_INDEX (32)
# define EC_CIPHERKEY_INDEX (32 + 32)
_Static_assert(EC_CIPHERKEY_INDEX + 16 == EXPECTED_ENC_LEN,
"Please fix ECIES-X25519 component indexes");
#endif
/*
* Decrypt an encryption key TLV.
*
* @param buf An encryption TLV read from flash (build time fixed length)
* @param enckey An AES-128 key sized buffer to store to plain key.
*/
int
boot_enc_decrypt(const uint8_t *buf, uint8_t *enckey)
{
#if defined(MCUBOOT_ENCRYPT_RSA)
mbedtls_rsa_context rsa;
uint8_t *cp;
uint8_t *cpend;
size_t olen;
#endif
#if defined(MCUBOOT_ENCRYPT_EC256)
bootutil_ecdh_p256_context ecdh_p256;
#endif
#if defined(MCUBOOT_ENCRYPT_X25519)
bootutil_ecdh_x25519_context ecdh_x25519;
#endif
#if defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519)
bootutil_hmac_sha256_context hmac;
bootutil_aes_ctr_context aes_ctr;
uint8_t tag[BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE];
uint8_t shared[SHARED_KEY_LEN];
uint8_t derived_key[BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE];
uint8_t *cp;
uint8_t *cpend;
uint8_t private_key[PRIV_KEY_LEN];
uint8_t counter[BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE];
uint16_t len;
#endif
int rc = -1;
#if defined(MCUBOOT_ENCRYPT_RSA)
mbedtls_rsa_init(&rsa, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
cp = (uint8_t *)bootutil_enc_key.key;
cpend = cp + *bootutil_enc_key.len;
rc = parse_rsa_enckey(&rsa, &cp, cpend);
if (rc) {
mbedtls_rsa_free(&rsa);
return rc;
}
rc = mbedtls_rsa_rsaes_oaep_decrypt(&rsa, NULL, NULL, MBEDTLS_RSA_PRIVATE,
NULL, 0, &olen, buf, enckey, BOOT_ENC_KEY_SIZE);
mbedtls_rsa_free(&rsa);
#endif /* defined(MCUBOOT_ENCRYPT_RSA) */
#if defined(MCUBOOT_ENCRYPT_KW)
assert(*bootutil_enc_key.len == 16);
rc = key_unwrap(buf, enckey);
#endif /* defined(MCUBOOT_ENCRYPT_KW) */
#if defined(MCUBOOT_ENCRYPT_EC256)
cp = (uint8_t *)bootutil_enc_key.key;
cpend = cp + *bootutil_enc_key.len;
/*
* Load the stored EC256 decryption private key
*/
rc = parse_ec256_enckey(&cp, cpend, private_key);
if (rc) {
return rc;
}
/* is EC point uncompressed? */
if (buf[0] != 0x04) {
return -1;
}
/*
* First "element" in the TLV is the curve point (public key)
*/
bootutil_ecdh_p256_init(&ecdh_p256);
rc = bootutil_ecdh_p256_shared_secret(&ecdh_p256, &buf[EC_PUBK_INDEX], private_key, shared);
bootutil_ecdh_p256_drop(&ecdh_p256);
if (rc != 0) {
return -1;
}
#endif /* defined(MCUBOOT_ENCRYPT_EC256) */
#if defined(MCUBOOT_ENCRYPT_X25519)
cp = (uint8_t *)bootutil_enc_key.key;
cpend = cp + *bootutil_enc_key.len;
/*
* Load the stored X25519 decryption private key
*/
rc = parse_x25519_enckey(&cp, cpend, private_key);
if (rc) {
return rc;
}
/*
* First "element" in the TLV is the curve point (public key)
*/
bootutil_ecdh_x25519_init(&ecdh_x25519);
rc = bootutil_ecdh_x25519_shared_secret(&ecdh_x25519, &buf[EC_PUBK_INDEX], private_key, shared);
bootutil_ecdh_x25519_drop(&ecdh_x25519);
if (!rc) {
return -1;
}
#endif /* defined(MCUBOOT_ENCRYPT_X25519) */
#if defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519)
/*
* Expand shared secret to create keys for AES-128-CTR + HMAC-SHA256
*/
len = BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE;
rc = hkdf(shared, SHARED_KEY_LEN, (uint8_t *)"MCUBoot_ECIES_v1", 16,
derived_key, &len);
if (rc != 0 || len != (BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE)) {
return -1;
}
/*
* HMAC the key and check that our received MAC matches the generated tag
*/
bootutil_hmac_sha256_init(&hmac);
rc = bootutil_hmac_sha256_set_key(&hmac, &derived_key[16], 32);
if (rc != 0) {
(void)bootutil_hmac_sha256_drop(&hmac);
return -1;
}
rc = bootutil_hmac_sha256_update(&hmac, &buf[EC_CIPHERKEY_INDEX], 16);
if (rc != 0) {
(void)bootutil_hmac_sha256_drop(&hmac);
return -1;
}
/* Assumes the tag bufer is at least sizeof(hmac_tag_size(state)) bytes */
rc = bootutil_hmac_sha256_finish(&hmac, tag, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
if (rc != 0) {
(void)bootutil_hmac_sha256_drop(&hmac);
return -1;
}
if (bootutil_constant_time_compare(tag, &buf[EC_TAG_INDEX], 32) != 0) {
(void)bootutil_hmac_sha256_drop(&hmac);
return -1;
}
bootutil_hmac_sha256_drop(&hmac);
/*
* Finally decrypt the received ciphered key
*/
bootutil_aes_ctr_init(&aes_ctr);
if (rc != 0) {
bootutil_aes_ctr_drop(&aes_ctr);
return -1;
}
rc = bootutil_aes_ctr_set_key(&aes_ctr, derived_key);
if (rc != 0) {
bootutil_aes_ctr_drop(&aes_ctr);
return -1;
}
memset(counter, 0, BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE);
rc = bootutil_aes_ctr_decrypt(&aes_ctr, counter, &buf[EC_CIPHERKEY_INDEX], BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE, 0, enckey);
if (rc != 0) {
bootutil_aes_ctr_drop(&aes_ctr);
return -1;
}
bootutil_aes_ctr_drop(&aes_ctr);
rc = 0;
#endif /* defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519) */
return rc;
}
/*
* Load encryption key.
*/
int
boot_enc_load(struct enc_key_data *enc_state, int image_index,
const struct image_header *hdr, const struct flash_area *fap,
struct boot_status *bs)
{
uint32_t off;
uint16_t len;
struct image_tlv_iter it;
#if MCUBOOT_SWAP_SAVE_ENCTLV
uint8_t *buf;
#else
uint8_t buf[EXPECTED_ENC_LEN];
#endif
uint8_t slot;
int rc;
rc = flash_area_id_to_multi_image_slot(image_index, fap->fa_id);
if (rc < 0) {
return rc;
}
slot = rc;
/* Already loaded... */
if (enc_state[slot].valid) {
return 1;
}
/* Initialize the AES context */
boot_enc_init(enc_state, slot);
rc = bootutil_tlv_iter_begin(&it, hdr, fap, EXPECTED_ENC_TLV, false);
if (rc) {
return -1;
}
rc = bootutil_tlv_iter_next(&it, &off, &len, NULL);
if (rc != 0) {
return rc;
}
if (len != EXPECTED_ENC_LEN) {
return -1;
}
#if MCUBOOT_SWAP_SAVE_ENCTLV
buf = bs->enctlv[slot];
memset(buf, 0xff, BOOT_ENC_TLV_ALIGN_SIZE);
#endif
rc = flash_area_read(fap, off, buf, EXPECTED_ENC_LEN);
if (rc) {
return -1;
}
return boot_enc_decrypt(buf, bs->enckey[slot]);
}
bool
boot_enc_valid(struct enc_key_data *enc_state, int image_index,
const struct flash_area *fap)
{
int rc;
rc = flash_area_id_to_multi_image_slot(image_index, fap->fa_id);
if (rc < 0) {
/* can't get proper slot number - skip encryption, */
/* postpone the error for a upper layer */
return false;
}
return enc_state[rc].valid;
}
void
boot_encrypt(struct enc_key_data *enc_state, int image_index,
const struct flash_area *fap, uint32_t off, uint32_t sz,
uint32_t blk_off, uint8_t *buf)
{
struct enc_key_data *enc;
uint8_t nonce[16];
int rc;
/* boot_copy_region will call boot_encrypt with sz = 0 when skipping over
the TLVs. */
if (sz == 0) {
return;
}
memset(nonce, 0, 12);
off >>= 4;
nonce[12] = (uint8_t)(off >> 24);
nonce[13] = (uint8_t)(off >> 16);
nonce[14] = (uint8_t)(off >> 8);
nonce[15] = (uint8_t)off;
rc = flash_area_id_to_multi_image_slot(image_index, fap->fa_id);
if (rc < 0) {
assert(0);
return;
}
enc = &enc_state[rc];
assert(enc->valid == 1);
bootutil_aes_ctr_encrypt(&enc->aes_ctr, nonce, buf, sz, blk_off, buf);
}
/**
* Clears encrypted state after use.
*/
void
boot_enc_zeroize(struct enc_key_data *enc_state)
{
uint8_t slot;
for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
(void)boot_enc_drop(enc_state, slot);
}
memset(enc_state, 0, sizeof(struct enc_key_data) * BOOT_NUM_SLOTS);
}
#endif /* MCUBOOT_ENC_IMAGES */
@@ -0,0 +1,78 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2020 Arm Limited
*/
#include "bootutil/fault_injection_hardening.h"
#ifdef FIH_ENABLE_DOUBLE_VARS
/* Variable that could be (but isn't) changed at runtime to force the compiler
* not to optimize the double check. Value doesn't matter.
*/
volatile int _fih_mask = _FIH_MASK_VALUE;
fih_int FIH_SUCCESS = {FIH_POSITIVE_VALUE, _FIH_MASK_VALUE ^ FIH_POSITIVE_VALUE};
fih_int FIH_FAILURE = {FIH_NEGATIVE_VALUE, _FIH_MASK_VALUE ^ FIH_NEGATIVE_VALUE};
#else
fih_int FIH_SUCCESS = {FIH_POSITIVE_VALUE};
fih_int FIH_FAILURE = {FIH_NEGATIVE_VALUE};
#endif /* FIH_ENABLE_DOUBLE_VARS */
#ifdef FIH_ENABLE_CFI
#ifdef FIH_ENABLE_DOUBLE_VARS
fih_int _fih_cfi_ctr = {0, 0 ^ _FIH_MASK_VALUE};
#else
fih_int _fih_cfi_ctr = {0};
#endif /* FIH_ENABLE_DOUBLE_VARS */
/* Increment the CFI counter by one, and return the value before the increment.
*/
fih_int fih_cfi_get_and_increment(void)
{
fih_int saved = _fih_cfi_ctr;
_fih_cfi_ctr = fih_int_encode(fih_int_decode(saved) + 1);
return saved;
}
/* Validate that the saved precall value is the same as the value of the global
* counter. For this to be the case, a fih_ret must have been called between
* these functions being executed. If the values aren't the same then panic.
*/
void fih_cfi_validate(fih_int saved)
{
if (fih_int_decode(saved) != fih_int_decode(_fih_cfi_ctr)) {
FIH_PANIC;
}
}
/* Decrement the global CFI counter by one, so that it has the same value as
* before the cfi_precall
*/
void fih_cfi_decrement(void)
{
_fih_cfi_ctr = fih_int_encode(fih_int_decode(_fih_cfi_ctr) - 1);
}
#endif /* FIH_ENABLE_CFI */
#ifdef FIH_ENABLE_GLOBAL_FAIL
/* Global failure loop for bootloader code. Uses attribute used to prevent
* compiler removing due to non-standard calling procedure. Multiple loop jumps
* used to make unlooping difficult.
*/
__attribute__((used))
__attribute__((noinline))
void fih_panic_loop(void)
{
__asm volatile ("b fih_panic_loop");
__asm volatile ("b fih_panic_loop");
__asm volatile ("b fih_panic_loop");
__asm volatile ("b fih_panic_loop");
__asm volatile ("b fih_panic_loop");
__asm volatile ("b fih_panic_loop");
__asm volatile ("b fih_panic_loop");
__asm volatile ("b fih_panic_loop");
__asm volatile ("b fih_panic_loop");
}
#endif /* FIH_ENABLE_GLOBAL_FAIL */
@@ -0,0 +1,48 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2020 Arm Limited
*/
#include "bootutil/fault_injection_hardening.h"
#ifdef FIH_ENABLE_DELAY
#include "mcuboot-mbedtls-cfg.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/entropy.h"
/* Mbedtls implementation of the delay RNG. Can be replaced by any other RNG
* implementation that is backed by an entropy source by altering these
* functions. This is not provided as a header API and a C file implementation
* due to issues with inlining.
*/
#ifdef MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
#error "FIH_ENABLE_DELAY requires an entropy source"
#endif /* MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES */
mbedtls_entropy_context fih_entropy_ctx;
mbedtls_ctr_drbg_context fih_drbg_ctx;
int fih_delay_init(void)
{
mbedtls_entropy_init(&fih_entropy_ctx);
mbedtls_ctr_drbg_init(&fih_drbg_ctx);
mbedtls_ctr_drbg_seed(&fih_drbg_ctx , mbedtls_entropy_func,
&fih_entropy_ctx, NULL, 0);
return 1;
}
unsigned char fih_delay_random_uchar(void)
{
unsigned char delay;
mbedtls_ctr_drbg_random(&fih_drbg_ctx,(unsigned char*) &delay,
sizeof(delay));
return delay;
}
#endif /* FIH_ENABLE_DELAY */
@@ -0,0 +1,128 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2016-2018 JUUL Labs
*
* Original license:
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#include <string.h>
#include "mcuboot_config/mcuboot_config.h"
#ifdef MCUBOOT_SIGN_EC
#include "bootutil/sign_key.h"
#include "mbedtls/ecdsa.h"
#include "mbedtls/oid.h"
#include "mbedtls/asn1.h"
#include "bootutil_priv.h"
/*
* Declaring these like this adds NULL termination.
*/
static const uint8_t ec_pubkey_oid[] = MBEDTLS_OID_EC_ALG_UNRESTRICTED;
static const uint8_t ec_secp224r1_oid[] = MBEDTLS_OID_EC_GRP_SECP224R1;
/*
* Parse the public key used for signing.
*/
static int
bootutil_parse_eckey(mbedtls_ecdsa_context *ctx, uint8_t **p, uint8_t *end)
{
size_t len;
mbedtls_asn1_buf alg;
mbedtls_asn1_buf param;
if (mbedtls_asn1_get_tag(p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) {
return -1;
}
end = *p + len;
if (mbedtls_asn1_get_alg(p, end, &alg, &param)) {
return -2;
}
if (alg.len != sizeof(ec_pubkey_oid) - 1 ||
memcmp(alg.p, ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) {
return -3;
}
if (param.len != sizeof(ec_secp224r1_oid) - 1||
memcmp(param.p, ec_secp224r1_oid, sizeof(ec_secp224r1_oid) - 1)) {
return -4;
}
if (mbedtls_ecp_group_load(&ctx->grp, MBEDTLS_ECP_DP_SECP224R1)) {
return -5;
}
if (mbedtls_asn1_get_bitstring_null(p, end, &len)) {
return -6;
}
if (*p + len != end) {
return -7;
}
if (mbedtls_ecp_point_read_binary(&ctx->grp, &ctx->Q, *p, end - *p)) {
return -8;
}
if (mbedtls_ecp_check_pubkey(&ctx->grp, &ctx->Q)) {
return -9;
}
return 0;
}
static int
bootutil_cmp_sig(mbedtls_ecdsa_context *ctx, uint8_t *hash, uint32_t hlen,
uint8_t *sig, size_t slen)
{
return mbedtls_ecdsa_read_signature(ctx, hash, hlen, sig, slen);
}
int
bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen,
uint8_t key_id)
{
int rc;
uint8_t *cp;
uint8_t *end;
mbedtls_ecdsa_context ctx;
mbedtls_ecdsa_init(&ctx);
cp = (uint8_t *)bootutil_keys[key_id].key;
end = cp + *bootutil_keys[key_id].len;
rc = bootutil_parse_eckey(&ctx, &cp, end);
if (rc) {
return -1;
}
while (sig[slen - 1] == '\0') {
slen--;
}
rc = bootutil_cmp_sig(&ctx, hash, hlen, sig, slen);
mbedtls_ecdsa_free(&ctx);
return rc;
}
#endif /* MCUBOOT_SIGN_EC */
@@ -0,0 +1,192 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2016-2019 JUUL Labs
* Copyright (c) 2017 Linaro LTD
*
* Original license:
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#include <string.h>
#include "mcuboot_config/mcuboot_config.h"
#ifdef MCUBOOT_SIGN_EC256
#if defined (MCUBOOT_USE_CC310) || defined (MCUBOOT_USE_TI_CRYPTO)|| \
defined(MCUBOOT_USE_MSP_CRYPTO)
#define NUM_ECC_BYTES (256 / 8)
#endif
#if defined (MCUBOOT_USE_TINYCRYPT) || defined (MCUBOOT_USE_CC310) || \
defined (MCUBOOT_USE_TI_CRYPTO) || defined(MCUBOOT_USE_MSP_CRYPTO)
#include "bootutil/sign_key.h"
#include "mbedtls/oid.h"
#include "mbedtls/asn1.h"
#include "bootutil/crypto/ecdsa_p256.h"
#include "bootutil_priv.h"
/*
* Declaring these like this adds NULL termination.
*/
static const uint8_t ec_pubkey_oid[] = MBEDTLS_OID_EC_ALG_UNRESTRICTED;
static const uint8_t ec_secp256r1_oid[] = MBEDTLS_OID_EC_GRP_SECP256R1;
/*
* Parse the public key used for signing.
*/
static int
bootutil_import_key(uint8_t **cp, uint8_t *end)
{
size_t len;
mbedtls_asn1_buf alg;
mbedtls_asn1_buf param;
if (mbedtls_asn1_get_tag(cp, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) {
return -1;
}
end = *cp + len;
/* ECParameters (RFC5480) */
if (mbedtls_asn1_get_alg(cp, end, &alg, &param)) {
return -2;
}
/* id-ecPublicKey (RFC5480) */
if (alg.len != sizeof(ec_pubkey_oid) - 1 ||
memcmp(alg.p, ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) {
return -3;
}
/* namedCurve (RFC5480) */
if (param.len != sizeof(ec_secp256r1_oid) - 1 ||
memcmp(param.p, ec_secp256r1_oid, sizeof(ec_secp256r1_oid) - 1)) {
return -4;
}
/* ECPoint (RFC5480) */
if (mbedtls_asn1_get_bitstring_null(cp, end, &len)) {
return -6;
}
if (*cp + len != end) {
return -7;
}
if (len != 2 * NUM_ECC_BYTES + 1) {
return -8;
}
/* Is uncompressed? */
if (*cp[0] != 0x04) {
return -9;
}
(*cp)++;
return 0;
}
/*
* cp points to ASN1 string containing an integer.
* Verify the tag, and that the length is 32 bytes.
*/
static int
bootutil_read_bigint(uint8_t i[NUM_ECC_BYTES], uint8_t **cp, uint8_t *end)
{
size_t len;
if (mbedtls_asn1_get_tag(cp, end, &len, MBEDTLS_ASN1_INTEGER)) {
return -3;
}
if (len >= NUM_ECC_BYTES) {
memcpy(i, *cp + len - NUM_ECC_BYTES, NUM_ECC_BYTES);
} else {
memset(i, 0, NUM_ECC_BYTES - len);
memcpy(i + NUM_ECC_BYTES - len, *cp, len);
}
*cp += len;
return 0;
}
/*
* Read in signature. Signature has r and s encoded as integers.
*/
static int
bootutil_decode_sig(uint8_t signature[NUM_ECC_BYTES * 2], uint8_t *cp, uint8_t *end)
{
int rc;
size_t len;
rc = mbedtls_asn1_get_tag(&cp, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
if (rc) {
return -1;
}
if (cp + len > end) {
return -2;
}
rc = bootutil_read_bigint(signature, &cp, end);
if (rc) {
return -3;
}
rc = bootutil_read_bigint(signature + NUM_ECC_BYTES, &cp, end);
if (rc) {
return -4;
}
return 0;
}
int
bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen,
uint8_t key_id)
{
int rc;
bootutil_ecdsa_p256_context ctx;
uint8_t *pubkey;
uint8_t *end;
uint8_t signature[2 * NUM_ECC_BYTES];
pubkey = (uint8_t *)bootutil_keys[key_id].key;
end = pubkey + *bootutil_keys[key_id].len;
rc = bootutil_import_key(&pubkey, end);
if (rc) {
return -1;
}
rc = bootutil_decode_sig(signature, sig, sig + slen);
if (rc) {
return -1;
}
/*
* This is simplified, as the hash length is also 32 bytes.
*/
if (hlen != NUM_ECC_BYTES) {
return -1;
}
bootutil_ecdsa_p256_init(&ctx);
rc = bootutil_ecdsa_p256_verify(&ctx, pubkey, hash, signature);
bootutil_ecdsa_p256_drop(&ctx);
return rc;
}
#endif /* MCUBOOT_USE_TINYCRYPT || defined MCUBOOT_USE_CC310 || MCUBOOT_USE_TI_CRYPTO */
#endif /* MCUBOOT_SIGN_EC256 */
@@ -0,0 +1,93 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2019 JUUL Labs
*/
#include <string.h>
#include "mcuboot_config/mcuboot_config.h"
#ifdef MCUBOOT_SIGN_ED25519
#include "bootutil/sign_key.h"
#include "mbedtls/oid.h"
#include "mbedtls/asn1.h"
#include "bootutil_priv.h"
static const uint8_t ed25519_pubkey_oid[] = MBEDTLS_OID_ISO_IDENTIFIED_ORG "\x65\x70";
#define NUM_ED25519_BYTES 32
extern int ED25519_verify(const uint8_t *message, size_t message_len,
const uint8_t signature[64],
const uint8_t public_key[32]);
/*
* Parse the public key used for signing.
*/
static int
bootutil_import_key(uint8_t **cp, uint8_t *end)
{
size_t len;
mbedtls_asn1_buf alg;
mbedtls_asn1_buf param;
if (mbedtls_asn1_get_tag(cp, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) {
return -1;
}
end = *cp + len;
if (mbedtls_asn1_get_alg(cp, end, &alg, &param)) {
return -2;
}
if (alg.len != sizeof(ed25519_pubkey_oid) - 1 ||
memcmp(alg.p, ed25519_pubkey_oid, sizeof(ed25519_pubkey_oid) - 1)) {
return -3;
}
if (mbedtls_asn1_get_bitstring_null(cp, end, &len)) {
return -4;
}
if (*cp + len != end) {
return -5;
}
if (len != NUM_ED25519_BYTES) {
return -6;
}
return 0;
}
int
bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen,
uint8_t key_id)
{
int rc;
uint8_t *pubkey;
uint8_t *end;
if (hlen != 32 || slen != 64) {
return -1;
}
pubkey = (uint8_t *)bootutil_keys[key_id].key;
end = pubkey + *bootutil_keys[key_id].len;
rc = bootutil_import_key(&pubkey, end);
if (rc) {
return -1;
}
rc = ED25519_verify(hash, 32, sig, pubkey);
if (rc == 0) {
return -2;
}
return 0;
}
#endif /* MCUBOOT_SIGN_ED25519 */
@@ -0,0 +1,316 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2017-2018 Linaro LTD
* Copyright (c) 2017-2019 JUUL Labs
* Copyright (c) 2020 Arm Limited
*
* Original license:
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#include <string.h>
#include "mcuboot_config/mcuboot_config.h"
#ifdef MCUBOOT_SIGN_RSA
#include "bootutil/sign_key.h"
#include "bootutil/crypto/sha256.h"
#include "mbedtls/rsa.h"
#include "mbedtls/asn1.h"
#include "mbedtls/version.h"
#include "bootutil_priv.h"
#include "bootutil/fault_injection_hardening.h"
/*
* Constants for this particular constrained implementation of
* RSA-PSS. In particular, we support RSA 2048, with a SHA256 hash,
* and a 32-byte salt. A signature with different parameters will be
* rejected as invalid.
*/
/* The size, in octets, of the message. */
#define PSS_EMLEN (MCUBOOT_SIGN_RSA_LEN / 8)
/* The size of the hash function. For SHA256, this is 32 bytes. */
#define PSS_HLEN 32
/* Size of the salt, should be fixed. */
#define PSS_SLEN 32
/* The length of the mask: emLen - hLen - 1. */
#define PSS_MASK_LEN (PSS_EMLEN - PSS_HLEN - 1)
#define PSS_HASH_OFFSET PSS_MASK_LEN
/* For the mask itself, how many bytes should be all zeros. */
#define PSS_MASK_ZERO_COUNT (PSS_MASK_LEN - PSS_SLEN - 1)
#define PSS_MASK_ONE_POS PSS_MASK_ZERO_COUNT
/* Where the salt starts. */
#define PSS_MASK_SALT_POS (PSS_MASK_ONE_POS + 1)
static const uint8_t pss_zeros[8] = {0};
/*
* Parse the public key used for signing. Simple RSA format.
*/
static int
bootutil_parse_rsakey(mbedtls_rsa_context *ctx, uint8_t **p, uint8_t *end)
{
int rc;
size_t len;
if ((rc = mbedtls_asn1_get_tag(p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
return -1;
}
if (*p + len != end) {
return -2;
}
if ((rc = mbedtls_asn1_get_mpi(p, end, &ctx->N)) != 0 ||
(rc = mbedtls_asn1_get_mpi(p, end, &ctx->E)) != 0) {
return -3;
}
ctx->len = mbedtls_mpi_size(&ctx->N);
if (*p != end) {
return -4;
}
/* The mbedtls version is more than 2.6.1 */
#if MBEDTLS_VERSION_NUMBER > 0x02060100
rc = mbedtls_rsa_import(ctx, &ctx->N, NULL, NULL, NULL, &ctx->E);
if (rc != 0) {
return -5;
}
#endif
rc = mbedtls_rsa_check_pubkey(ctx);
if (rc != 0) {
return -6;
}
ctx->len = mbedtls_mpi_size(&ctx->N);
return 0;
}
/*
* Compute the RSA-PSS mask-generation function, MGF1. Assumptions
* are that the mask length will be less than 256 * PSS_HLEN, and
* therefore we never need to increment anything other than the low
* byte of the counter.
*
* This is described in PKCS#1, B.2.1.
*/
static void
pss_mgf1(uint8_t *mask, const uint8_t *hash)
{
bootutil_sha256_context ctx;
uint8_t counter[4] = { 0, 0, 0, 0 };
uint8_t htmp[PSS_HLEN];
int count = PSS_MASK_LEN;
int bytes;
while (count > 0) {
bootutil_sha256_init(&ctx);
bootutil_sha256_update(&ctx, hash, PSS_HLEN);
bootutil_sha256_update(&ctx, counter, 4);
bootutil_sha256_finish(&ctx, htmp);
counter[3]++;
bytes = PSS_HLEN;
if (bytes > count)
bytes = count;
memcpy(mask, htmp, bytes);
mask += bytes;
count -= bytes;
}
bootutil_sha256_drop(&ctx);
}
/*
* Validate an RSA signature, using RSA-PSS, as described in PKCS #1
* v2.2, section 9.1.2, with many parameters required to have fixed
* values.
*/
static fih_int
bootutil_cmp_rsasig(mbedtls_rsa_context *ctx, uint8_t *hash, uint32_t hlen,
uint8_t *sig)
{
bootutil_sha256_context shactx;
uint8_t em[MBEDTLS_MPI_MAX_SIZE];
uint8_t db_mask[PSS_MASK_LEN];
uint8_t h2[PSS_HLEN];
int i;
int rc = 0;
fih_int fih_rc = FIH_FAILURE;
if (ctx->len != PSS_EMLEN || PSS_EMLEN > MBEDTLS_MPI_MAX_SIZE) {
rc = -1;
goto out;
}
if (hlen != PSS_HLEN) {
rc = -1;
goto out;
}
if (mbedtls_rsa_public(ctx, sig, em)) {
rc = -1;
goto out;
}
/*
* PKCS #1 v2.2, 9.1.2 EMSA-PSS-Verify
*
* emBits is 2048
* emLen = ceil(emBits/8) = 256
*
* The salt length is not known at the beginning.
*/
/* Step 1. The message is constrained by the address space of a
* 32-bit processor, which is far less than the 2^61-1 limit of
* SHA-256.
*/
/* Step 2. mHash is passed in as 'hash', with hLen the hlen
* argument. */
/* Step 3. if emLen < hLen + sLen + 2, inconsistent and stop.
* The salt length is not known at this point.
*/
/* Step 4. If the rightmost octet of EM does have the value
* 0xbc, output inconsistent and stop.
*/
if (em[PSS_EMLEN - 1] != 0xbc) {
rc = -1;
goto out;
}
/* Step 5. Let maskedDB be the leftmost emLen - hLen - 1 octets
* of EM, and H be the next hLen octets.
*
* maskedDB is then the first 256 - 32 - 1 = 0-222
* H is 32 bytes 223-254
*/
/* Step 6. If the leftmost 8emLen - emBits bits of the leftmost
* octet in maskedDB are not all equal to zero, output
* inconsistent and stop.
*
* 8emLen - emBits is zero, so there is nothing to test here.
*/
/* Step 7. let dbMask = MGF(H, emLen - hLen - 1). */
pss_mgf1(db_mask, &em[PSS_HASH_OFFSET]);
/* Step 8. let DB = maskedDB xor dbMask.
* To avoid needing an additional buffer, store the 'db' in the
* same buffer as db_mask. From now, to the end of this function,
* db_mask refers to the unmasked 'db'. */
for (i = 0; i < PSS_MASK_LEN; i++) {
db_mask[i] ^= em[i];
}
/* Step 9. Set the leftmost 8emLen - emBits bits of the leftmost
* octet in DB to zero.
* pycrypto seems to always make the emBits 2047, so we need to
* clear the top bit. */
db_mask[0] &= 0x7F;
/* Step 10. If the emLen - hLen - sLen - 2 leftmost octets of DB
* are not zero or if the octet at position emLen - hLen - sLen -
* 1 (the leftmost position is "position 1") does not have
* hexadecimal value 0x01, output "inconsistent" and stop. */
for (i = 0; i < PSS_MASK_ZERO_COUNT; i++) {
if (db_mask[i] != 0) {
rc = -1;
goto out;
}
}
if (db_mask[PSS_MASK_ONE_POS] != 1) {
rc = -1;
goto out;
}
/* Step 11. Let salt be the last sLen octets of DB */
/* Step 12. Let M' = 0x00 00 00 00 00 00 00 00 || mHash || salt; */
/* Step 13. Let H' = Hash(M') */
bootutil_sha256_init(&shactx);
bootutil_sha256_update(&shactx, pss_zeros, 8);
bootutil_sha256_update(&shactx, hash, PSS_HLEN);
bootutil_sha256_update(&shactx, &db_mask[PSS_MASK_SALT_POS], PSS_SLEN);
bootutil_sha256_finish(&shactx, h2);
bootutil_sha256_drop(&shactx);
/* Step 14. If H = H', output "consistent". Otherwise, output
* "inconsistent". */
FIH_CALL(boot_fih_memequal, fih_rc, h2, &em[PSS_HASH_OFFSET], PSS_HLEN);
out:
if (rc) {
fih_rc = fih_int_encode(rc);
}
FIH_RET(fih_rc);
}
fih_int
bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen,
uint8_t key_id)
{
mbedtls_rsa_context ctx;
int rc;
fih_int fih_rc = FIH_FAILURE;
uint8_t *cp;
uint8_t *end;
mbedtls_rsa_init(&ctx, 0, 0);
cp = (uint8_t *)bootutil_keys[key_id].key;
end = cp + *bootutil_keys[key_id].len;
rc = bootutil_parse_rsakey(&ctx, &cp, end);
if (rc || slen != ctx.len) {
mbedtls_rsa_free(&ctx);
goto out;
}
FIH_CALL(bootutil_cmp_rsasig, fih_rc, &ctx, hash, hlen, sig);
out:
mbedtls_rsa_free(&ctx);
FIH_RET(fih_rc);
}
#endif /* MCUBOOT_SIGN_RSA */
@@ -0,0 +1,545 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2017-2019 Linaro LTD
* Copyright (c) 2016-2019 JUUL Labs
* Copyright (c) 2019-2020 Arm Limited
*
* Original license:
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#include <stddef.h>
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
#include <flash_map_backend/flash_map_backend.h>
#include "bootutil/image.h"
#include "bootutil/crypto/sha256.h"
#include "bootutil/sign_key.h"
#include "bootutil/security_cnt.h"
#include "bootutil/fault_injection_hardening.h"
#include "mcuboot_config/mcuboot_config.h"
#ifdef MCUBOOT_ENC_IMAGES
#include "bootutil/enc_key.h"
#endif
#if defined(MCUBOOT_SIGN_RSA)
#include "mbedtls/rsa.h"
#endif
#if defined(MCUBOOT_SIGN_EC) || defined(MCUBOOT_SIGN_EC256)
#include "mbedtls/ecdsa.h"
#endif
#if defined(MCUBOOT_ENC_IMAGES) || defined(MCUBOOT_SIGN_RSA) || \
defined(MCUBOOT_SIGN_EC) || defined(MCUBOOT_SIGN_EC256)
#include "mbedtls/asn1.h"
#endif
#ifdef TI_CUSTOM_TLV_DYNAMIC_KEY_MANAGEMENT
#include "keystore.h"
#endif
#include "bootutil_priv.h"
/*
* Compute SHA256 over the image.
*/
static int
bootutil_img_hash(struct enc_key_data *enc_state, int image_index,
struct image_header *hdr, const struct flash_area *fap,
uint8_t *tmp_buf, uint32_t tmp_buf_sz, uint8_t *hash_result,
uint8_t *seed, int seed_len)
{
bootutil_sha256_context sha256_ctx;
uint32_t blk_sz;
uint32_t size;
uint16_t hdr_size;
uint32_t off;
int rc;
uint32_t blk_off;
uint32_t tlv_off;
#if (BOOT_IMAGE_NUMBER == 1) || !defined(MCUBOOT_ENC_IMAGES) || \
defined(MCUBOOT_RAM_LOAD)
(void)enc_state;
(void)image_index;
(void)hdr_size;
(void)blk_off;
(void)tlv_off;
#ifdef MCUBOOT_RAM_LOAD
(void)blk_sz;
(void)off;
(void)rc;
#endif
#endif
#ifdef MCUBOOT_ENC_IMAGES
/* Encrypted images only exist in the secondary slot */
if (MUST_DECRYPT(fap, image_index, hdr) &&
!boot_enc_valid(enc_state, image_index, fap)) {
return -1;
}
#endif
bootutil_sha256_init(&sha256_ctx);
/* in some cases (split image) the hash is seeded with data from
* the loader image */
if (seed && (seed_len > 0)) {
bootutil_sha256_update(&sha256_ctx, seed, seed_len);
}
/* Hash is computed over image header and image itself. */
size = hdr_size = hdr->ih_hdr_size;
size += hdr->ih_img_size;
tlv_off = size;
/* If protected TLVs are present they are also hashed. */
size += hdr->ih_protect_tlv_size;
#ifdef MCUBOOT_RAM_LOAD
bootutil_sha256_update(&sha256_ctx,(void*)(hdr->ih_load_addr), size);
#else
for (off = 0; off < size; off += blk_sz) {
blk_sz = size - off;
if (blk_sz > tmp_buf_sz) {
blk_sz = tmp_buf_sz;
}
#ifdef MCUBOOT_ENC_IMAGES
/* The only data that is encrypted in an image is the payload;
* both header and TLVs (when protected) are not.
*/
if ((off < hdr_size) && ((off + blk_sz) > hdr_size)) {
/* read only the header */
blk_sz = hdr_size - off;
}
if ((off < tlv_off) && ((off + blk_sz) > tlv_off)) {
/* read only up to the end of the image payload */
blk_sz = tlv_off - off;
}
#endif
rc = flash_area_read(fap, off, tmp_buf, blk_sz);
if (rc) {
bootutil_sha256_drop(&sha256_ctx);
return rc;
}
#ifdef MCUBOOT_ENC_IMAGES
if (MUST_DECRYPT(fap, image_index, hdr)) {
/* Only payload is encrypted (area between header and TLVs) */
if (off >= hdr_size && off < tlv_off) {
blk_off = (off - hdr_size) & 0xf;
boot_encrypt(enc_state, image_index, fap, off - hdr_size,
blk_sz, blk_off, tmp_buf);
}
}
#endif
bootutil_sha256_update(&sha256_ctx, tmp_buf, blk_sz);
}
#endif /* MCUBOOT_RAM_LOAD */
bootutil_sha256_finish(&sha256_ctx, hash_result);
bootutil_sha256_drop(&sha256_ctx);
return 0;
}
/*
* Currently, we only support being able to verify one type of
* signature, because there is a single verification function that we
* call. List the type of TLV we are expecting. If we aren't
* configured for any signature, don't define this macro.
*/
#if (defined(MCUBOOT_SIGN_RSA) + \
defined(MCUBOOT_SIGN_EC) + \
defined(MCUBOOT_SIGN_EC256) + \
defined(MCUBOOT_SIGN_ED25519)) > 1
#error "Only a single signature type is supported!"
#endif
#if defined(MCUBOOT_SIGN_RSA)
# if MCUBOOT_SIGN_RSA_LEN == 2048
# define EXPECTED_SIG_TLV IMAGE_TLV_RSA2048_PSS
# elif MCUBOOT_SIGN_RSA_LEN == 3072
# define EXPECTED_SIG_TLV IMAGE_TLV_RSA3072_PSS
# else
# error "Unsupported RSA signature length"
# endif
# define SIG_BUF_SIZE (MCUBOOT_SIGN_RSA_LEN / 8)
# define EXPECTED_SIG_LEN(x) ((x) == SIG_BUF_SIZE) /* 2048 bits */
#elif defined(MCUBOOT_SIGN_EC)
# define EXPECTED_SIG_TLV IMAGE_TLV_ECDSA224
# define SIG_BUF_SIZE 128
# define EXPECTED_SIG_LEN(x) (1) /* always true, ASN.1 will validate */
#elif defined(MCUBOOT_SIGN_EC256)
# define EXPECTED_SIG_TLV IMAGE_TLV_ECDSA256
# define SIG_BUF_SIZE 128
# define EXPECTED_SIG_LEN(x) (1) /* always true, ASN.1 will validate */
#elif defined(MCUBOOT_SIGN_ED25519)
# define EXPECTED_SIG_TLV IMAGE_TLV_ED25519
# define SIG_BUF_SIZE 64
# define EXPECTED_SIG_LEN(x) ((x) == SIG_BUF_SIZE)
#else
# define SIG_BUF_SIZE 32 /* no signing, sha256 digest only */
#endif
#ifdef EXPECTED_SIG_TLV
#if !defined(MCUBOOT_HW_KEY)
static int
bootutil_find_key(uint8_t *keyhash, uint8_t keyhash_len)
{
bootutil_sha256_context sha256_ctx;
int i;
const struct bootutil_key *key;
uint8_t hash[32];
if (keyhash_len > 32) {
return -1;
}
for (i = 0; i < bootutil_key_cnt; i++) {
key = &bootutil_keys[i];
bootutil_sha256_init(&sha256_ctx);
bootutil_sha256_update(&sha256_ctx, key->key, *key->len);
bootutil_sha256_finish(&sha256_ctx, hash);
if (!memcmp(hash, keyhash, keyhash_len)) {
bootutil_sha256_drop(&sha256_ctx);
return i;
}
}
bootutil_sha256_drop(&sha256_ctx);
return -1;
}
#else
extern unsigned int pub_key_len;
static int
bootutil_find_key(uint8_t image_index, uint8_t *key, uint16_t key_len)
{
bootutil_sha256_context sha256_ctx;
uint8_t hash[32];
uint8_t key_hash[32];
size_t key_hash_size = sizeof(key_hash);
int rc;
fih_int fih_rc;
bootutil_sha256_init(&sha256_ctx);
bootutil_sha256_update(&sha256_ctx, key, key_len);
bootutil_sha256_finish(&sha256_ctx, hash);
bootutil_sha256_drop(&sha256_ctx);
rc = boot_retrieve_public_key_hash(image_index, key_hash, &key_hash_size);
if (rc) {
return rc;
}
/* Adding hardening to avoid this potential attack:
* - Image is signed with an arbitrary key and the corresponding public
* key is added as a TLV field.
* - During public key validation (comparing against key-hash read from
* HW) a fault is injected to accept the public key as valid one.
*/
FIH_CALL(boot_fih_memequal, fih_rc, hash, key_hash, key_hash_size);
if (fih_eq(fih_rc, FIH_SUCCESS)) {
bootutil_keys[0].key = key;
pub_key_len = key_len;
return 0;
}
return -1;
}
#endif /* !MCUBOOT_HW_KEY */
#endif
#ifdef MCUBOOT_HW_ROLLBACK_PROT
/**
* Reads the value of an image's security counter.
*
* @param hdr Pointer to the image header structure.
* @param fap Pointer to a description structure of the image's
* flash area.
* @param security_cnt Pointer to store the security counter value.
*
* @return 0 on success; nonzero on failure.
*/
int32_t
bootutil_get_img_security_cnt(struct image_header *hdr,
const struct flash_area *fap,
uint32_t *img_security_cnt)
{
struct image_tlv_iter it;
uint32_t off;
uint16_t len;
int32_t rc;
if ((hdr == NULL) ||
(fap == NULL) ||
(img_security_cnt == NULL)) {
/* Invalid parameter. */
return BOOT_EBADARGS;
}
/* The security counter TLV is in the protected part of the TLV area. */
if (hdr->ih_protect_tlv_size == 0) {
return BOOT_EBADIMAGE;
}
rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_SEC_CNT, true);
if (rc) {
return rc;
}
/* Traverse through the protected TLV area to find
* the security counter TLV.
*/
rc = bootutil_tlv_iter_next(&it, &off, &len, NULL);
if (rc != 0) {
/* Security counter TLV has not been found. */
return -1;
}
if (len != sizeof(*img_security_cnt)) {
/* Security counter is not valid. */
return BOOT_EBADIMAGE;
}
rc = LOAD_IMAGE_DATA(hdr, fap, off, img_security_cnt, len);
if (rc != 0) {
return BOOT_EFLASH;
}
return 0;
}
#endif /* MCUBOOT_HW_ROLLBACK_PROT */
/*
* Verify the integrity of the image.
* Return non-zero if image could not be validated/does not validate.
*/
fih_int
bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
struct image_header *hdr, const struct flash_area *fap,
uint8_t *tmp_buf, uint32_t tmp_buf_sz, uint8_t *seed,
int seed_len, uint8_t *out_hash)
{
uint32_t off;
uint16_t len;
uint16_t type;
int sha256_valid = 0;
#ifdef EXPECTED_SIG_TLV
fih_int valid_signature = FIH_FAILURE;
int key_id = -1;
#ifdef MCUBOOT_HW_KEY
/* Few extra bytes for encoding and for public exponent. */
uint8_t key_buf[SIG_BUF_SIZE + 24];
#endif
#endif /* EXPECTED_SIG_TLV */
struct image_tlv_iter it;
uint8_t buf[SIG_BUF_SIZE];
uint8_t hash[32];
int rc = 0;
fih_int fih_rc = FIH_FAILURE;
#ifdef MCUBOOT_HW_ROLLBACK_PROT
fih_int security_cnt = fih_int_encode(INT_MAX);
uint32_t img_security_cnt = 0;
fih_int security_counter_valid = FIH_FAILURE;
#endif
rc = bootutil_img_hash(enc_state, image_index, hdr, fap, tmp_buf,
tmp_buf_sz, hash, seed, seed_len);
if (rc) {
goto out;
}
if (out_hash) {
memcpy(out_hash, hash, 32);
}
rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, false);
if (rc) {
goto out;
}
/*
* Traverse through all of the TLVs, performing any checks we know
* and are able to do.
*/
while (true) {
rc = bootutil_tlv_iter_next(&it, &off, &len, &type);
if (rc < 0) {
goto out;
} else if (rc > 0) {
break;
}
if (type == IMAGE_TLV_SHA256) {
/*
* Verify the SHA256 image hash. This must always be
* present.
*/
if (len != sizeof(hash)) {
rc = -1;
goto out;
}
rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, sizeof(hash));
if (rc) {
goto out;
}
FIH_CALL(boot_fih_memequal, fih_rc, hash, buf, sizeof(hash));
if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
goto out;
}
sha256_valid = 1;
#ifdef EXPECTED_SIG_TLV
#ifndef MCUBOOT_HW_KEY
} else if (type == IMAGE_TLV_KEYHASH) {
/*
* Determine which key we should be checking.
*/
if (len > 32) {
rc = -1;
goto out;
}
rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, len);
if (rc) {
goto out;
}
key_id = bootutil_find_key(buf, len);
/*
* The key may not be found, which is acceptable. There
* can be multiple signatures, each preceded by a key.
*/
#else
} else if (type == IMAGE_TLV_PUBKEY) {
/*
* Determine which key we should be checking.
*/
if (len > sizeof(key_buf)) {
rc = -1;
goto out;
}
rc = LOAD_IMAGE_DATA(hdr, fap, off, key_buf, len);
if (rc) {
goto out;
}
key_id = bootutil_find_key(image_index, key_buf, len);
/*
* The key may not be found, which is acceptable. There
* can be multiple signatures, each preceded by a key.
*/
#endif /* !MCUBOOT_HW_KEY */
} else if (type == EXPECTED_SIG_TLV) {
/* Ignore this signature if it is out of bounds. */
if (key_id < 0 || key_id >= bootutil_key_cnt) {
key_id = -1;
continue;
}
if (!EXPECTED_SIG_LEN(len) || len > sizeof(buf)) {
rc = -1;
goto out;
}
rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, len);
if (rc) {
goto out;
}
FIH_CALL(bootutil_verify_sig, valid_signature, hash, sizeof(hash),
buf, len, key_id);
key_id = -1;
#endif /* EXPECTED_SIG_TLV */
#ifdef MCUBOOT_HW_ROLLBACK_PROT
} else if (type == IMAGE_TLV_SEC_CNT) {
/*
* Verify the image's security counter.
* This must always be present.
*/
if (len != sizeof(img_security_cnt)) {
/* Security counter is not valid. */
rc = -1;
goto out;
}
rc = LOAD_IMAGE_DATA(hdr, fap, off, &img_security_cnt, len);
if (rc) {
goto out;
}
FIH_CALL(boot_nv_security_counter_get, fih_rc, image_index,
&security_cnt);
if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
goto out;
}
/* Compare the new image's security counter value against the
* stored security counter value.
*/
fih_rc = fih_int_encode_zero_equality(img_security_cnt <
fih_int_decode(security_cnt));
if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
goto out;
}
/* The image's security counter has been successfully verified. */
security_counter_valid = fih_rc;
#endif /* MCUBOOT_HW_ROLLBACK_PROT */
#ifdef TI_CUSTOM_TLV_DYNAMIC_KEY_MANAGEMENT
} else if (type == IMAGE_TLV_CUSTOM_TI_ADD_KEY){
/* Check if Length is correct, and contains a full 256-bit hash */
if(len != 0x20){
// not a complete hash
rc = -1;
goto out;
}
/* The address of the hash pointer will be the current flash area
* plus the provided offset. */
FIH_CALL(Keystore_newKeyRequest, fih_rc, (fap->fa_off + off));
} else if (type == IMAGE_TLV_CUSTOM_TI_REVOKE_KEY){
if(len != 0x20){
// not a complete hash
rc = -1;
goto out;
}
FIH_CALL(Keystore_revokeKeyRequest, fih_rc, (fap->fa_off + off));
#endif
}
}
rc = !sha256_valid;
if (rc) {
goto out;
}
#ifdef EXPECTED_SIG_TLV
fih_rc = fih_int_encode_zero_equality(fih_not_eq(valid_signature,
FIH_SUCCESS));
#endif
#ifdef MCUBOOT_HW_ROLLBACK_PROT
if (fih_not_eq(security_counter_valid, FIH_SUCCESS)) {
rc = -1;
goto out;
}
#endif
out:
if (rc) {
fih_rc = fih_int_encode(rc);
}
FIH_RET(fih_rc);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,232 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2019 JUUL Labs
*
* 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.
*/
#include <stddef.h>
#include <stdbool.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include "bootutil/bootutil.h"
#include "bootutil_priv.h"
#include "swap_priv.h"
#include "bootutil/bootutil_log.h"
#include "mcuboot_config/mcuboot_config.h"
MCUBOOT_LOG_MODULE_DECLARE(mcuboot);
#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE)
int
swap_erase_trailer_sectors(const struct boot_loader_state *state,
const struct flash_area *fap)
{
uint8_t slot;
uint32_t sector;
uint32_t trailer_sz;
uint32_t total_sz;
uint32_t off;
uint32_t sz;
int fa_id_primary;
int fa_id_secondary;
uint8_t image_index;
int rc;
BOOT_LOG_DBG("erasing trailer; fa_id=%d", fap->fa_id);
image_index = BOOT_CURR_IMG(state);
fa_id_primary = flash_area_id_from_multi_image_slot(image_index,
BOOT_PRIMARY_SLOT);
fa_id_secondary = flash_area_id_from_multi_image_slot(image_index,
BOOT_SECONDARY_SLOT);
if (fap->fa_id == fa_id_primary) {
slot = BOOT_PRIMARY_SLOT;
} else if (fap->fa_id == fa_id_secondary) {
slot = BOOT_SECONDARY_SLOT;
} else {
return BOOT_EFLASH;
}
/* delete starting from last sector and moving to beginning */
sector = boot_img_num_sectors(state, slot) - 1;
trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
total_sz = 0;
do {
sz = boot_img_sector_size(state, slot, sector);
off = boot_img_sector_off(state, slot, sector);
rc = boot_erase_region(fap, off, sz);
assert(rc == 0);
sector--;
total_sz += sz;
} while (total_sz < trailer_sz);
return rc;
}
int
swap_status_init(const struct boot_loader_state *state,
const struct flash_area *fap,
const struct boot_status *bs)
{
struct boot_swap_state swap_state;
uint8_t image_index;
int rc;
#if (BOOT_IMAGE_NUMBER == 1)
(void)state;
#endif
image_index = BOOT_CURR_IMG(state);
BOOT_LOG_DBG("initializing status; fa_id=%d", fap->fa_id);
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY(image_index),
&swap_state);
assert(rc == 0);
if (bs->swap_type != BOOT_SWAP_TYPE_NONE) {
rc = boot_write_swap_info(fap, bs->swap_type, image_index);
assert(rc == 0);
}
if (swap_state.image_ok == BOOT_FLAG_SET) {
rc = boot_write_image_ok(fap);
assert(rc == 0);
}
rc = boot_write_swap_size(fap, bs->swap_size);
assert(rc == 0);
#ifdef MCUBOOT_ENC_IMAGES
rc = boot_write_enc_key(fap, 0, bs);
assert(rc == 0);
rc = boot_write_enc_key(fap, 1, bs);
assert(rc == 0);
#endif
rc = boot_write_magic(fap);
assert(rc == 0);
return 0;
}
int
swap_read_status(struct boot_loader_state *state, struct boot_status *bs)
{
const struct flash_area *fap;
uint32_t off;
uint8_t swap_info;
int area_id;
int rc;
bs->source = swap_status_source(state);
switch (bs->source) {
case BOOT_STATUS_SOURCE_NONE:
return 0;
#if MCUBOOT_SWAP_USING_SCRATCH
case BOOT_STATUS_SOURCE_SCRATCH:
area_id = FLASH_AREA_IMAGE_SCRATCH;
break;
#endif
case BOOT_STATUS_SOURCE_PRIMARY_SLOT:
area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
break;
default:
assert(0);
return BOOT_EBADARGS;
}
rc = flash_area_open(area_id, &fap);
if (rc != 0) {
return BOOT_EFLASH;
}
rc = swap_read_status_bytes(fap, state, bs);
if (rc == 0) {
off = boot_swap_info_off(fap);
rc = flash_area_read(fap, off, &swap_info, sizeof swap_info);
if (rc != 0) {
return BOOT_EFLASH;
}
if (bootutil_buffer_is_erased(fap, &swap_info, sizeof swap_info)) {
BOOT_SET_SWAP_INFO(swap_info, 0, BOOT_SWAP_TYPE_NONE);
rc = 0;
}
/* Extract the swap type info */
bs->swap_type = BOOT_GET_SWAP_TYPE(swap_info);
}
flash_area_close(fap);
return rc;
}
int
swap_set_copy_done(uint8_t image_index)
{
const struct flash_area *fap;
int rc;
rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
&fap);
if (rc != 0) {
return BOOT_EFLASH;
}
rc = boot_write_copy_done(fap);
flash_area_close(fap);
return rc;
}
int
swap_set_image_ok(uint8_t image_index)
{
const struct flash_area *fap;
struct boot_swap_state state;
int rc;
rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
&fap);
if (rc != 0) {
return BOOT_EFLASH;
}
rc = boot_read_swap_state(fap, &state);
if (rc != 0) {
rc = BOOT_EFLASH;
goto out;
}
if (state.image_ok == BOOT_FLAG_UNSET) {
rc = boot_write_image_ok(fap);
}
out:
flash_area_close(fap);
return rc;
}
#endif /* defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE) */
@@ -0,0 +1,523 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2019 JUUL Labs
*
* 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.
*/
#include <stddef.h>
#include <stdbool.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include "bootutil/bootutil.h"
#include "bootutil_priv.h"
#include "swap_priv.h"
#include "bootutil/bootutil_log.h"
#include "mcuboot_config/mcuboot_config.h"
MCUBOOT_LOG_MODULE_DECLARE(mcuboot);
#ifdef MCUBOOT_SWAP_USING_MOVE
#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
/*
* FIXME: this might have to be updated for threaded sim
*/
int boot_status_fails = 0;
#define BOOT_STATUS_ASSERT(x) \
do { \
if (!(x)) { \
boot_status_fails++; \
} \
} while (0)
#else
#define BOOT_STATUS_ASSERT(x) ASSERT(x)
#endif
static uint32_t g_last_idx = UINT32_MAX;
int
boot_read_image_header(struct boot_loader_state *state, int slot,
struct image_header *out_hdr, struct boot_status *bs)
{
const struct flash_area *fap;
uint32_t off;
uint32_t sz;
int area_id;
int rc;
#if (BOOT_IMAGE_NUMBER == 1)
(void)state;
#endif
off = 0;
if (bs) {
sz = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, 0);
if (bs->op == BOOT_STATUS_OP_MOVE) {
if (slot == 0 && bs->idx > g_last_idx) {
/* second sector */
off = sz;
}
} else if (bs->op == BOOT_STATUS_OP_SWAP) {
if (bs->idx > 1 && bs->idx <= g_last_idx) {
if (slot == 0) {
slot = 1;
} else {
slot = 0;
}
} else if (bs->idx == 1) {
if (slot == 0) {
off = sz;
}
if (slot == 1 && bs->state == 2) {
slot = 0;
}
}
}
}
area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
rc = flash_area_open(area_id, &fap);
if (rc != 0) {
rc = BOOT_EFLASH;
goto done;
}
rc = flash_area_read(fap, off, out_hdr, sizeof *out_hdr);
if (rc != 0) {
rc = BOOT_EFLASH;
goto done;
}
/* We only know where the headers are located when bs is valid */
if (bs != NULL && out_hdr->ih_magic != IMAGE_MAGIC) {
rc = -1;
goto done;
}
rc = 0;
done:
flash_area_close(fap);
return rc;
}
int
swap_read_status_bytes(const struct flash_area *fap,
struct boot_loader_state *state, struct boot_status *bs)
{
uint32_t off;
uint8_t status;
int max_entries;
int found_idx;
uint8_t write_sz;
int move_entries;
int rc;
int last_rc;
int erased_sections;
int i;
max_entries = boot_status_entries(BOOT_CURR_IMG(state), fap);
if (max_entries < 0) {
return BOOT_EBADARGS;
}
erased_sections = 0;
found_idx = -1;
/* skip erased sectors at the end */
last_rc = 1;
write_sz = BOOT_WRITE_SZ(state);
off = boot_status_off(fap);
for (i = max_entries; i > 0; i--) {
rc = flash_area_read(fap, off + (i - 1) * write_sz, &status, 1);
if (rc < 0) {
return BOOT_EFLASH;
}
if (bootutil_buffer_is_erased(fap, &status, 1)) {
if (rc != last_rc) {
erased_sections++;
}
} else {
if (found_idx == -1) {
found_idx = i;
}
}
last_rc = rc;
}
if (erased_sections > 1) {
/* This means there was an error writing status on the last
* swap. Tell user and move on to validation!
*/
#if !defined(__BOOTSIM__)
BOOT_LOG_ERR("Detected inconsistent status!");
#endif
#if !defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
/* With validation of the primary slot disabled, there is no way
* to be sure the swapped primary slot is OK, so abort!
*/
assert(0);
#endif
}
move_entries = BOOT_MAX_IMG_SECTORS * BOOT_STATUS_MOVE_STATE_COUNT;
if (found_idx == -1) {
/* no swap status found; nothing to do */
} else if (found_idx < move_entries) {
bs->op = BOOT_STATUS_OP_MOVE;
bs->idx = (found_idx / BOOT_STATUS_MOVE_STATE_COUNT) + BOOT_STATUS_IDX_0;
bs->state = (found_idx % BOOT_STATUS_MOVE_STATE_COUNT) + BOOT_STATUS_STATE_0;;
} else {
bs->op = BOOT_STATUS_OP_SWAP;
bs->idx = ((found_idx - move_entries) / BOOT_STATUS_SWAP_STATE_COUNT) + BOOT_STATUS_IDX_0;
bs->state = ((found_idx - move_entries) % BOOT_STATUS_SWAP_STATE_COUNT) + BOOT_STATUS_STATE_0;
}
return 0;
}
uint32_t
boot_status_internal_off(const struct boot_status *bs, int elem_sz)
{
uint32_t off;
int idx_sz;
idx_sz = elem_sz * ((bs->op == BOOT_STATUS_OP_MOVE) ?
BOOT_STATUS_MOVE_STATE_COUNT : BOOT_STATUS_SWAP_STATE_COUNT);
off = ((bs->op == BOOT_STATUS_OP_MOVE) ?
0 : (BOOT_MAX_IMG_SECTORS * BOOT_STATUS_MOVE_STATE_COUNT * elem_sz)) +
(bs->idx - BOOT_STATUS_IDX_0) * idx_sz +
(bs->state - BOOT_STATUS_STATE_0) * elem_sz;
return off;
}
int
boot_slots_compatible(struct boot_loader_state *state)
{
size_t num_sectors_pri;
size_t num_sectors_sec;
size_t sector_sz_pri = 0;
size_t sector_sz_sec = 0;
size_t i;
num_sectors_pri = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
num_sectors_sec = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT);
if ((num_sectors_pri != num_sectors_sec) &&
(num_sectors_pri != (num_sectors_sec + 1))) {
BOOT_LOG_WRN("Cannot upgrade: not a compatible amount of sectors");
return 0;
}
if (num_sectors_pri > BOOT_MAX_IMG_SECTORS) {
BOOT_LOG_WRN("Cannot upgrade: more sectors than allowed");
return 0;
}
for (i = 0; i < num_sectors_sec; i++) {
sector_sz_pri = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
sector_sz_sec = boot_img_sector_size(state, BOOT_SECONDARY_SLOT, i);
if (sector_sz_pri != sector_sz_sec) {
BOOT_LOG_WRN("Cannot upgrade: not same sector layout");
return 0;
}
}
if (num_sectors_pri > num_sectors_sec) {
if (sector_sz_pri != boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i)) {
BOOT_LOG_WRN("Cannot upgrade: not same sector layout");
return 0;
}
}
return 1;
}
#define BOOT_LOG_SWAP_STATE(area, state) \
BOOT_LOG_INF("%s: magic=%s, swap_type=0x%x, copy_done=0x%x, " \
"image_ok=0x%x", \
(area), \
((state)->magic == BOOT_MAGIC_GOOD ? "good" : \
(state)->magic == BOOT_MAGIC_UNSET ? "unset" : \
"bad"), \
(state)->swap_type, \
(state)->copy_done, \
(state)->image_ok)
int
swap_status_source(struct boot_loader_state *state)
{
struct boot_swap_state state_primary_slot;
struct boot_swap_state state_secondary_slot;
int rc;
uint8_t source;
uint8_t image_index;
#if (BOOT_IMAGE_NUMBER == 1)
(void)state;
#endif
image_index = BOOT_CURR_IMG(state);
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY(image_index),
&state_primary_slot);
assert(rc == 0);
BOOT_LOG_SWAP_STATE("Primary image", &state_primary_slot);
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY(image_index),
&state_secondary_slot);
assert(rc == 0);
BOOT_LOG_SWAP_STATE("Secondary image", &state_secondary_slot);
if (state_primary_slot.magic == BOOT_MAGIC_GOOD &&
state_primary_slot.copy_done == BOOT_FLAG_UNSET &&
state_secondary_slot.magic != BOOT_MAGIC_GOOD) {
source = BOOT_STATUS_SOURCE_PRIMARY_SLOT;
BOOT_LOG_INF("Boot source: primary slot");
return source;
}
BOOT_LOG_INF("Boot source: none");
return BOOT_STATUS_SOURCE_NONE;
}
/*
* "Moves" the sector located at idx - 1 to idx.
*/
static void
boot_move_sector_up(int idx, uint32_t sz, struct boot_loader_state *state,
struct boot_status *bs, const struct flash_area *fap_pri,
const struct flash_area *fap_sec)
{
uint32_t new_off;
uint32_t old_off;
int rc;
/*
* FIXME: assuming sectors of size == sz, a single off variable
* would be enough
*/
/* Calculate offset from start of image area. */
new_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx);
old_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx - 1);
if (bs->idx == BOOT_STATUS_IDX_0) {
if (bs->source != BOOT_STATUS_SOURCE_PRIMARY_SLOT) {
rc = swap_erase_trailer_sectors(state, fap_pri);
assert(rc == 0);
rc = swap_status_init(state, fap_pri, bs);
assert(rc == 0);
}
rc = swap_erase_trailer_sectors(state, fap_sec);
assert(rc == 0);
}
rc = boot_erase_region(fap_pri, new_off, sz);
assert(rc == 0);
rc = boot_copy_region(state, fap_pri, fap_pri, old_off, new_off, sz);
assert(rc == 0);
rc = boot_write_status(state, bs);
bs->idx++;
BOOT_STATUS_ASSERT(rc == 0);
}
static void
boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *state,
struct boot_status *bs, const struct flash_area *fap_pri,
const struct flash_area *fap_sec)
{
uint32_t pri_off;
uint32_t pri_up_off;
uint32_t sec_off;
int rc;
pri_up_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx);
pri_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx - 1);
sec_off = boot_img_sector_off(state, BOOT_SECONDARY_SLOT, idx - 1);
if (bs->state == BOOT_STATUS_STATE_0) {
rc = boot_erase_region(fap_pri, pri_off, sz);
assert(rc == 0);
rc = boot_copy_region(state, fap_sec, fap_pri, sec_off, pri_off, sz);
assert(rc == 0);
rc = boot_write_status(state, bs);
bs->state = BOOT_STATUS_STATE_1;
BOOT_STATUS_ASSERT(rc == 0);
}
if (bs->state == BOOT_STATUS_STATE_1) {
rc = boot_erase_region(fap_sec, sec_off, sz);
assert(rc == 0);
rc = boot_copy_region(state, fap_pri, fap_sec, pri_up_off, sec_off, sz);
assert(rc == 0);
rc = boot_write_status(state, bs);
bs->idx++;
bs->state = BOOT_STATUS_STATE_0;
BOOT_STATUS_ASSERT(rc == 0);
}
}
/*
* When starting a revert the swap status exists in the primary slot, and
* the status in the secondary slot is erased. To start the swap, the status
* area in the primary slot must be re-initialized; if during the small
* window of time between re-initializing it and writing the first metadata
* a reset happens, the swap process is broken and cannot be resumed.
*
* This function handles the issue by making the revert look like a permanent
* upgrade (by initializing the secondary slot).
*/
void
fixup_revert(const struct boot_loader_state *state, struct boot_status *bs,
const struct flash_area *fap_sec, uint8_t sec_id)
{
struct boot_swap_state swap_state;
int rc;
#if (BOOT_IMAGE_NUMBER == 1)
(void)state;
#endif
/* No fixup required */
if (bs->swap_type != BOOT_SWAP_TYPE_REVERT ||
bs->op != BOOT_STATUS_OP_MOVE ||
bs->idx != BOOT_STATUS_IDX_0) {
return;
}
rc = boot_read_swap_state_by_id(sec_id, &swap_state);
assert(rc == 0);
BOOT_LOG_SWAP_STATE("Secondary image", &swap_state);
if (swap_state.magic == BOOT_MAGIC_UNSET) {
rc = swap_erase_trailer_sectors(state, fap_sec);
assert(rc == 0);
rc = boot_write_image_ok(fap_sec);
assert(rc == 0);
rc = boot_write_swap_size(fap_sec, bs->swap_size);
assert(rc == 0);
rc = boot_write_magic(fap_sec);
assert(rc == 0);
}
}
void
swap_run(struct boot_loader_state *state, struct boot_status *bs,
uint32_t copy_size)
{
uint32_t sz;
uint32_t sector_sz;
uint32_t idx;
uint32_t trailer_sz;
uint32_t first_trailer_idx;
uint8_t image_index;
const struct flash_area *fap_pri;
const struct flash_area *fap_sec;
int rc;
sz = 0;
g_last_idx = 0;
sector_sz = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, 0);
while (1) {
sz += sector_sz;
/* Skip to next sector because all sectors will be moved up. */
g_last_idx++;
if (sz >= copy_size) {
break;
}
}
/*
* When starting a new swap upgrade, check that there is enough space.
*/
if (boot_status_is_reset(bs)) {
sz = 0;
trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
first_trailer_idx = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT) - 1;
while (1) {
sz += sector_sz;
if (sz >= trailer_sz) {
break;
}
first_trailer_idx--;
}
if (g_last_idx >= first_trailer_idx) {
BOOT_LOG_WRN("Not enough free space to run swap upgrade");
bs->swap_type = BOOT_SWAP_TYPE_NONE;
return;
}
}
image_index = BOOT_CURR_IMG(state);
rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index), &fap_pri);
assert (rc == 0);
rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index), &fap_sec);
assert (rc == 0);
fixup_revert(state, bs, fap_sec, FLASH_AREA_IMAGE_SECONDARY(image_index));
if (bs->op == BOOT_STATUS_OP_MOVE) {
idx = g_last_idx;
while (idx > 0) {
if (idx <= (g_last_idx - bs->idx + 1)) {
boot_move_sector_up(idx, sector_sz, state, bs, fap_pri, fap_sec);
}
idx--;
}
bs->idx = BOOT_STATUS_IDX_0;
}
bs->op = BOOT_STATUS_OP_SWAP;
idx = 1;
while (idx <= g_last_idx) {
if (idx >= bs->idx) {
boot_swap_sectors(idx, sector_sz, state, bs, fap_pri, fap_sec);
}
idx++;
}
flash_area_close(fap_pri);
flash_area_close(fap_sec);
}
#endif
@@ -0,0 +1,104 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2019 JUUL Labs
*
* 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.
*/
#ifndef H_SWAP_PRIV_
#define H_SWAP_PRIV_
#include "mcuboot_config/mcuboot_config.h"
#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE)
/**
* Calculates the amount of space required to store the trailer, and erases
* all sectors required for this storage in the given flash_area.
*/
int swap_erase_trailer_sectors(const struct boot_loader_state *state,
const struct flash_area *fap);
/**
* Initialize the given flash_area with the metadata required to start a new
* swap upgrade.
*/
int swap_status_init(const struct boot_loader_state *state,
const struct flash_area *fap,
const struct boot_status *bs);
/**
* Tries to locate an interrupted swap status (metadata). If not metadata
* was found returns BOOT_STATUS_SOURCE_NONE.
*
* Must return one of:
* - BOOT_STATUS_SOURCE_NONE
* - BOOT_STATUS_SOURCE_SCRATCH
* - BOOT_STATUS_SOURCE_PRIMARY_SLOT
*/
int swap_status_source(struct boot_loader_state *state);
/**
* Reads the boot status from the flash. The boot status contains
* the current state of an interrupted image copy operation. If the boot
* status is not present, or it indicates that previous copy finished,
* there is no operation in progress.
*/
int swap_read_status(struct boot_loader_state *state, struct boot_status *bs);
/**
* Iterate over the swap status bytes in the given flash_area and populate
* the given boot_status with the calculated index where a swap upgrade was
* interrupted.
*/
int swap_read_status_bytes(const struct flash_area *fap,
struct boot_loader_state *state,
struct boot_status *bs);
/**
* Marks the image in the primary slot as fully copied.
*/
int swap_set_copy_done(uint8_t image_index);
/**
* Marks a reverted image in the primary slot as confirmed. This is necessary to
* ensure the status bytes from the image revert operation don't get processed
* on a subsequent boot.
*
* NOTE: image_ok is tested before writing because if there's a valid permanent
* image installed on the primary slot and the new image to be upgrade to has a
* bad sig, image_ok would be overwritten.
*/
int swap_set_image_ok(uint8_t image_index);
/**
* Start a new or resume an interrupted swap according to the parameters
* found in the given boot_status.
*/
void swap_run(struct boot_loader_state *state,
struct boot_status *bs,
uint32_t copy_size);
#if MCUBOOT_SWAP_USING_SCRATCH
#define BOOT_SCRATCH_AREA(state) ((state)->scratch.area)
static inline size_t boot_scratch_area_size(const struct boot_loader_state *state)
{
return BOOT_SCRATCH_AREA(state)->fa_size;
}
#endif
#endif /* defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE) */
#endif /* H_SWAP_PRIV_ */
@@ -0,0 +1,728 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2019 JUUL Labs
*
* 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.
*/
#include <stddef.h>
#include <stdbool.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include "bootutil/bootutil.h"
#include "bootutil_priv.h"
#include "swap_priv.h"
#include "bootutil/bootutil_log.h"
#include "mcuboot_config/mcuboot_config.h"
MCUBOOT_LOG_MODULE_DECLARE(mcuboot);
#if !defined(MCUBOOT_SWAP_USING_MOVE)
#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
/*
* FIXME: this might have to be updated for threaded sim
*/
int boot_status_fails = 0;
#define BOOT_STATUS_ASSERT(x) \
do { \
if (!(x)) { \
boot_status_fails++; \
} \
} while (0)
#else
#define BOOT_STATUS_ASSERT(x) ASSERT(x)
#endif
int
boot_read_image_header(struct boot_loader_state *state, int slot,
struct image_header *out_hdr, struct boot_status *bs)
{
const struct flash_area *fap;
int area_id;
int rc;
(void)bs;
#if (BOOT_IMAGE_NUMBER == 1)
(void)state;
#endif
area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
rc = flash_area_open(area_id, &fap);
if (rc != 0) {
rc = BOOT_EFLASH;
goto done;
}
rc = flash_area_read(fap, 0, out_hdr, sizeof *out_hdr);
if (rc != 0) {
rc = BOOT_EFLASH;
goto done;
}
rc = 0;
done:
flash_area_close(fap);
return rc;
}
#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
/**
* Reads the status of a partially-completed swap, if any. This is necessary
* to recover in case the boot lodaer was reset in the middle of a swap
* operation.
*/
int
swap_read_status_bytes(const struct flash_area *fap,
struct boot_loader_state *state, struct boot_status *bs)
{
uint32_t off;
uint8_t status;
int max_entries;
int found;
int found_idx;
int invalid;
int rc;
int i;
off = boot_status_off(fap);
max_entries = boot_status_entries(BOOT_CURR_IMG(state), fap);
if (max_entries < 0) {
return BOOT_EBADARGS;
}
found = 0;
found_idx = 0;
invalid = 0;
for (i = 0; i < max_entries; i++) {
rc = flash_area_read(fap, off + i * BOOT_WRITE_SZ(state),
&status, 1);
if (rc < 0) {
return BOOT_EFLASH;
}
if (bootutil_buffer_is_erased(fap, &status, 1)) {
if (found && !found_idx) {
found_idx = i;
}
} else if (!found) {
found = 1;
} else if (found_idx) {
invalid = 1;
break;
}
}
if (invalid) {
/* This means there was an error writing status on the last
* swap. Tell user and move on to validation!
*/
#if !defined(__BOOTSIM__)
BOOT_LOG_ERR("Detected inconsistent status!");
#endif
#if !defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
/* With validation of the primary slot disabled, there is no way
* to be sure the swapped primary slot is OK, so abort!
*/
assert(0);
#endif
}
if (found) {
if (!found_idx) {
found_idx = i;
}
bs->idx = (found_idx / BOOT_STATUS_STATE_COUNT) + 1;
bs->state = (found_idx % BOOT_STATUS_STATE_COUNT) + 1;
}
return 0;
}
uint32_t
boot_status_internal_off(const struct boot_status *bs, int elem_sz)
{
int idx_sz;
idx_sz = elem_sz * BOOT_STATUS_STATE_COUNT;
return (bs->idx - BOOT_STATUS_IDX_0) * idx_sz +
(bs->state - BOOT_STATUS_STATE_0) * elem_sz;
}
/*
* Slots are compatible when all sectors that store up to to size of the image
* round up to sector size, in both slot's are able to fit in the scratch
* area, and have sizes that are a multiple of each other (powers of two
* presumably!).
*/
int
boot_slots_compatible(struct boot_loader_state *state)
{
size_t num_sectors_primary;
size_t num_sectors_secondary;
size_t sz0, sz1;
size_t primary_slot_sz, secondary_slot_sz;
#ifndef MCUBOOT_OVERWRITE_ONLY
size_t scratch_sz;
#endif
size_t i, j;
int8_t smaller;
num_sectors_primary = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
num_sectors_secondary = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT);
if ((num_sectors_primary > BOOT_MAX_IMG_SECTORS) ||
(num_sectors_secondary > BOOT_MAX_IMG_SECTORS)) {
BOOT_LOG_WRN("Cannot upgrade: more sectors than allowed");
return 0;
}
#ifndef MCUBOOT_OVERWRITE_ONLY
scratch_sz = boot_scratch_area_size(state);
#endif
/*
* The following loop scans all sectors in a linear fashion, assuring that
* for each possible sector in each slot, it is able to fit in the other
* slot's sector or sectors. Slot's should be compatible as long as any
* number of a slot's sectors are able to fit into another, which only
* excludes cases where sector sizes are not a multiple of each other.
*/
i = sz0 = primary_slot_sz = 0;
j = sz1 = secondary_slot_sz = 0;
smaller = 0;
while (i < num_sectors_primary || j < num_sectors_secondary) {
if (sz0 == sz1) {
sz0 += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
sz1 += boot_img_sector_size(state, BOOT_SECONDARY_SLOT, j);
i++;
j++;
} else if (sz0 < sz1) {
sz0 += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
/* Guarantee that multiple sectors of the secondary slot
* fit into the primary slot.
*/
if (smaller == 2) {
BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible sectors");
return 0;
}
smaller = 1;
i++;
} else {
sz1 += boot_img_sector_size(state, BOOT_SECONDARY_SLOT, j);
/* Guarantee that multiple sectors of the primary slot
* fit into the secondary slot.
*/
if (smaller == 1) {
BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible sectors");
return 0;
}
smaller = 2;
j++;
}
#ifndef MCUBOOT_OVERWRITE_ONLY
if (sz0 == sz1) {
primary_slot_sz += sz0;
secondary_slot_sz += sz1;
/* Scratch has to fit each swap operation to the size of the larger
* sector among the primary slot and the secondary slot.
*/
if (sz0 > scratch_sz || sz1 > scratch_sz) {
BOOT_LOG_WRN("Cannot upgrade: not all sectors fit inside scratch");
return 0;
}
smaller = sz0 = sz1 = 0;
}
#endif
}
if ((i != num_sectors_primary) ||
(j != num_sectors_secondary) ||
(primary_slot_sz != secondary_slot_sz)) {
BOOT_LOG_WRN("Cannot upgrade: slots are not compatible");
return 0;
}
return 1;
}
#define BOOT_LOG_SWAP_STATE(area, state) \
BOOT_LOG_INF("%s: magic=%s, swap_type=0x%x, copy_done=0x%x, " \
"image_ok=0x%x", \
(area), \
((state)->magic == BOOT_MAGIC_GOOD ? "good" : \
(state)->magic == BOOT_MAGIC_UNSET ? "unset" : \
"bad"), \
(state)->swap_type, \
(state)->copy_done, \
(state)->image_ok)
struct boot_status_table {
uint8_t bst_magic_primary_slot;
uint8_t bst_magic_scratch;
uint8_t bst_copy_done_primary_slot;
uint8_t bst_status_source;
};
/**
* This set of tables maps swap state contents to boot status location.
* When searching for a match, these tables must be iterated in order.
*/
static const struct boot_status_table boot_status_tables[] = {
{
/* | primary slot | scratch |
* ----------+--------------+--------------|
* magic | Good | Any |
* copy-done | Set | N/A |
* ----------+--------------+--------------'
* source: none |
* ----------------------------------------'
*/
.bst_magic_primary_slot = BOOT_MAGIC_GOOD,
.bst_magic_scratch = BOOT_MAGIC_NOTGOOD,
.bst_copy_done_primary_slot = BOOT_FLAG_SET,
.bst_status_source = BOOT_STATUS_SOURCE_NONE,
},
{
/* | primary slot | scratch |
* ----------+--------------+--------------|
* magic | Good | Any |
* copy-done | Unset | N/A |
* ----------+--------------+--------------'
* source: primary slot |
* ----------------------------------------'
*/
.bst_magic_primary_slot = BOOT_MAGIC_GOOD,
.bst_magic_scratch = BOOT_MAGIC_NOTGOOD,
.bst_copy_done_primary_slot = BOOT_FLAG_UNSET,
.bst_status_source = BOOT_STATUS_SOURCE_PRIMARY_SLOT,
},
{
/* | primary slot | scratch |
* ----------+--------------+--------------|
* magic | Any | Good |
* copy-done | Any | N/A |
* ----------+--------------+--------------'
* source: scratch |
* ----------------------------------------'
*/
.bst_magic_primary_slot = BOOT_MAGIC_ANY,
.bst_magic_scratch = BOOT_MAGIC_GOOD,
.bst_copy_done_primary_slot = BOOT_FLAG_ANY,
.bst_status_source = BOOT_STATUS_SOURCE_SCRATCH,
},
{
/* | primary slot | scratch |
* ----------+--------------+--------------|
* magic | Unset | Any |
* copy-done | Unset | N/A |
* ----------+--------------+--------------|
* source: varies |
* ----------------------------------------+--------------------------+
* This represents one of two cases: |
* o No swaps ever (no status to read, so no harm in checking). |
* o Mid-revert; status in primary slot. |
* -------------------------------------------------------------------'
*/
.bst_magic_primary_slot = BOOT_MAGIC_UNSET,
.bst_magic_scratch = BOOT_MAGIC_ANY,
.bst_copy_done_primary_slot = BOOT_FLAG_UNSET,
.bst_status_source = BOOT_STATUS_SOURCE_PRIMARY_SLOT,
},
};
#define BOOT_STATUS_TABLES_COUNT \
(sizeof boot_status_tables / sizeof boot_status_tables[0])
/**
* Determines where in flash the most recent boot status is stored. The boot
* status is necessary for completing a swap that was interrupted by a boot
* loader reset.
*
* @return A BOOT_STATUS_SOURCE_[...] code indicating where status should
* be read from.
*/
int
swap_status_source(struct boot_loader_state *state)
{
const struct boot_status_table *table;
struct boot_swap_state state_scratch;
struct boot_swap_state state_primary_slot;
int rc;
size_t i;
uint8_t source;
uint8_t image_index;
#if (BOOT_IMAGE_NUMBER == 1)
(void)state;
#endif
image_index = BOOT_CURR_IMG(state);
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY(image_index),
&state_primary_slot);
assert(rc == 0);
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH, &state_scratch);
assert(rc == 0);
BOOT_LOG_SWAP_STATE("Primary image", &state_primary_slot);
BOOT_LOG_SWAP_STATE("Scratch", &state_scratch);
for (i = 0; i < BOOT_STATUS_TABLES_COUNT; i++) {
table = &boot_status_tables[i];
if (boot_magic_compatible_check(table->bst_magic_primary_slot,
state_primary_slot.magic) &&
boot_magic_compatible_check(table->bst_magic_scratch,
state_scratch.magic) &&
(table->bst_copy_done_primary_slot == BOOT_FLAG_ANY ||
table->bst_copy_done_primary_slot == state_primary_slot.copy_done))
{
source = table->bst_status_source;
#if (BOOT_IMAGE_NUMBER > 1)
/* In case of multi-image boot it can happen that if boot status
* info is found on scratch area then it does not belong to the
* currently examined image.
*/
if (source == BOOT_STATUS_SOURCE_SCRATCH &&
state_scratch.image_num != BOOT_CURR_IMG(state)) {
source = BOOT_STATUS_SOURCE_NONE;
}
#endif
BOOT_LOG_INF("Boot source: %s",
source == BOOT_STATUS_SOURCE_NONE ? "none" :
source == BOOT_STATUS_SOURCE_SCRATCH ? "scratch" :
source == BOOT_STATUS_SOURCE_PRIMARY_SLOT ?
"primary slot" : "BUG; can't happen");
return source;
}
}
BOOT_LOG_INF("Boot source: none");
return BOOT_STATUS_SOURCE_NONE;
}
#ifndef MCUBOOT_OVERWRITE_ONLY
/**
* Calculates the number of sectors the scratch area can contain. A "last"
* source sector is specified because images are copied backwards in flash
* (final index to index number 0).
*
* @param last_sector_idx The index of the last source sector
* (inclusive).
* @param out_first_sector_idx The index of the first source sector
* (inclusive) gets written here.
*
* @return The number of bytes comprised by the
* [first-sector, last-sector] range.
*/
static uint32_t
boot_copy_sz(const struct boot_loader_state *state, int last_sector_idx,
int *out_first_sector_idx)
{
size_t scratch_sz;
uint32_t new_sz;
uint32_t sz;
int i;
sz = 0;
scratch_sz = boot_scratch_area_size(state);
for (i = last_sector_idx; i >= 0; i--) {
new_sz = sz + boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
/*
* The secondary slot is not being checked here, because
* `boot_slots_compatible` already provides assurance that the copy size
* will be compatible with the primary slot and scratch.
*/
if (new_sz > scratch_sz) {
break;
}
sz = new_sz;
}
/* i currently refers to a sector that doesn't fit or it is -1 because all
* sectors have been processed. In both cases, exclude sector i.
*/
*out_first_sector_idx = i + 1;
return sz;
}
/**
* Swaps the contents of two flash regions within the two image slots.
*
* @param idx The index of the first sector in the range of
* sectors being swapped.
* @param sz The number of bytes to swap.
* @param bs The current boot status. This struct gets
* updated according to the outcome.
*
* @return 0 on success; nonzero on failure.
*/
static void
boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *state,
struct boot_status *bs)
{
const struct flash_area *fap_primary_slot;
const struct flash_area *fap_secondary_slot;
const struct flash_area *fap_scratch;
uint32_t copy_sz;
uint32_t trailer_sz;
uint32_t img_off;
uint32_t scratch_trailer_off;
struct boot_swap_state swap_state;
size_t last_sector;
bool erase_scratch;
uint8_t image_index;
int rc;
/* Calculate offset from start of image area. */
img_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx);
copy_sz = sz;
trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
/* sz in this function is always sized on a multiple of the sector size.
* The check against the start offset of the last sector
* is to determine if we're swapping the last sector. The last sector
* needs special handling because it's where the trailer lives. If we're
* copying it, we need to use scratch to write the trailer temporarily.
*
* NOTE: `use_scratch` is a temporary flag (never written to flash) which
* controls if special handling is needed (swapping last sector).
*/
last_sector = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT) - 1;
if ((img_off + sz) >
boot_img_sector_off(state, BOOT_PRIMARY_SLOT, last_sector)) {
copy_sz -= trailer_sz;
}
bs->use_scratch = (bs->idx == BOOT_STATUS_IDX_0 && copy_sz != sz);
image_index = BOOT_CURR_IMG(state);
rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
&fap_primary_slot);
assert (rc == 0);
rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index),
&fap_secondary_slot);
assert (rc == 0);
rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &fap_scratch);
assert (rc == 0);
if (bs->state == BOOT_STATUS_STATE_0) {
BOOT_LOG_DBG("erasing scratch area");
rc = boot_erase_region(fap_scratch, 0, fap_scratch->fa_size);
assert(rc == 0);
if (bs->idx == BOOT_STATUS_IDX_0) {
/* Write a trailer to the scratch area, even if we don't need the
* scratch area for status. We need a temporary place to store the
* `swap-type` while we erase the primary trailer.
*/
rc = swap_status_init(state, fap_scratch, bs);
assert(rc == 0);
if (!bs->use_scratch) {
/* Prepare the primary status area... here it is known that the
* last sector is not being used by the image data so it's safe
* to erase.
*/
rc = swap_erase_trailer_sectors(state, fap_primary_slot);
assert(rc == 0);
rc = swap_status_init(state, fap_primary_slot, bs);
assert(rc == 0);
/* Erase the temporary trailer from the scratch area. */
rc = boot_erase_region(fap_scratch, 0, fap_scratch->fa_size);
assert(rc == 0);
}
}
rc = boot_copy_region(state, fap_secondary_slot, fap_scratch,
img_off, 0, copy_sz);
assert(rc == 0);
rc = boot_write_status(state, bs);
bs->state = BOOT_STATUS_STATE_1;
BOOT_STATUS_ASSERT(rc == 0);
}
if (bs->state == BOOT_STATUS_STATE_1) {
rc = boot_erase_region(fap_secondary_slot, img_off, sz);
assert(rc == 0);
rc = boot_copy_region(state, fap_primary_slot, fap_secondary_slot,
img_off, img_off, copy_sz);
assert(rc == 0);
if (bs->idx == BOOT_STATUS_IDX_0 && !bs->use_scratch) {
/* If not all sectors of the slot are being swapped,
* guarantee here that only the primary slot will have the state.
*/
rc = swap_erase_trailer_sectors(state, fap_secondary_slot);
assert(rc == 0);
}
rc = boot_write_status(state, bs);
bs->state = BOOT_STATUS_STATE_2;
BOOT_STATUS_ASSERT(rc == 0);
}
if (bs->state == BOOT_STATUS_STATE_2) {
rc = boot_erase_region(fap_primary_slot, img_off, sz);
assert(rc == 0);
/* NOTE: If this is the final sector, we exclude the image trailer from
* this copy (copy_sz was truncated earlier).
*/
rc = boot_copy_region(state, fap_scratch, fap_primary_slot,
0, img_off, copy_sz);
assert(rc == 0);
if (bs->use_scratch) {
scratch_trailer_off = boot_status_off(fap_scratch);
/* copy current status that is being maintained in scratch */
rc = boot_copy_region(state, fap_scratch, fap_primary_slot,
scratch_trailer_off, img_off + copy_sz,
(BOOT_STATUS_STATE_COUNT - 1) * BOOT_WRITE_SZ(state));
BOOT_STATUS_ASSERT(rc == 0);
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH,
&swap_state);
assert(rc == 0);
if (swap_state.image_ok == BOOT_FLAG_SET) {
rc = boot_write_image_ok(fap_primary_slot);
assert(rc == 0);
}
if (swap_state.swap_type != BOOT_SWAP_TYPE_NONE) {
rc = boot_write_swap_info(fap_primary_slot,
swap_state.swap_type, image_index);
assert(rc == 0);
}
rc = boot_write_swap_size(fap_primary_slot, bs->swap_size);
assert(rc == 0);
#ifdef MCUBOOT_ENC_IMAGES
rc = boot_write_enc_key(fap_primary_slot, 0, bs);
assert(rc == 0);
rc = boot_write_enc_key(fap_primary_slot, 1, bs);
assert(rc == 0);
#endif
rc = boot_write_magic(fap_primary_slot);
assert(rc == 0);
}
/* If we wrote a trailer to the scratch area, erase it after we persist
* a trailer to the primary slot. We do this to prevent mcuboot from
* reading a stale status from the scratch area in case of immediate
* reset.
*/
erase_scratch = bs->use_scratch;
bs->use_scratch = 0;
rc = boot_write_status(state, bs);
bs->idx++;
bs->state = BOOT_STATUS_STATE_0;
BOOT_STATUS_ASSERT(rc == 0);
if (erase_scratch) {
rc = boot_erase_region(fap_scratch, 0, sz);
assert(rc == 0);
}
}
flash_area_close(fap_primary_slot);
flash_area_close(fap_secondary_slot);
flash_area_close(fap_scratch);
}
void
swap_run(struct boot_loader_state *state, struct boot_status *bs,
uint32_t copy_size)
{
uint32_t sz;
int first_sector_idx;
int last_sector_idx;
uint32_t swap_idx;
int last_idx_secondary_slot;
uint32_t primary_slot_size;
uint32_t secondary_slot_size;
primary_slot_size = 0;
secondary_slot_size = 0;
last_sector_idx = 0;
last_idx_secondary_slot = 0;
/*
* Knowing the size of the largest image between both slots, here we
* find what is the last sector in the primary slot that needs swapping.
* Since we already know that both slots are compatible, the secondary
* slot's last sector is not really required after this check is finished.
*/
while (1) {
if ((primary_slot_size < copy_size) ||
(primary_slot_size < secondary_slot_size)) {
primary_slot_size += boot_img_sector_size(state,
BOOT_PRIMARY_SLOT,
last_sector_idx);
}
if ((secondary_slot_size < copy_size) ||
(secondary_slot_size < primary_slot_size)) {
secondary_slot_size += boot_img_sector_size(state,
BOOT_SECONDARY_SLOT,
last_idx_secondary_slot);
}
if (primary_slot_size >= copy_size &&
secondary_slot_size >= copy_size &&
primary_slot_size == secondary_slot_size) {
break;
}
last_sector_idx++;
last_idx_secondary_slot++;
}
swap_idx = 0;
while (last_sector_idx >= 0) {
sz = boot_copy_sz(state, last_sector_idx, &first_sector_idx);
if (swap_idx >= (bs->idx - BOOT_STATUS_IDX_0)) {
boot_swap_sectors(first_sector_idx, sz, state, bs);
}
last_sector_idx = first_sector_idx - 1;
swap_idx++;
}
}
#endif /* !MCUBOOT_OVERWRITE_ONLY */
#endif /* !MCUBOOT_DIRECT_XIP && !MCUBOOT_RAM_LOAD */
#endif /* !MCUBOOT_SWAP_USING_MOVE */
@@ -0,0 +1,134 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2019 JUUL Labs
* Copyright (c) 2020 Arm Limited
*
* 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.
*/
#include <stddef.h>
#include "bootutil/bootutil.h"
#include "bootutil/image.h"
#include "bootutil_priv.h"
/*
* Initialize a TLV iterator.
*
* @param it An iterator struct
* @param hdr image_header of the slot's image
* @param fap flash_area of the slot which is storing the image
* @param type Type of TLV to look for
* @param prot true if TLV has to be stored in the protected area, false otherwise
*
* @returns 0 if the TLV iterator was successfully started
* -1 on errors
*/
int
bootutil_tlv_iter_begin(struct image_tlv_iter *it, const struct image_header *hdr,
const struct flash_area *fap, uint16_t type, bool prot)
{
uint32_t off_;
struct image_tlv_info info;
if (it == NULL || hdr == NULL || fap == NULL) {
return -1;
}
off_ = BOOT_TLV_OFF(hdr);
if (LOAD_IMAGE_DATA(hdr, fap, off_, &info, sizeof(info))) {
return -1;
}
if (info.it_magic == IMAGE_TLV_PROT_INFO_MAGIC) {
if (hdr->ih_protect_tlv_size != info.it_tlv_tot) {
return -1;
}
if (LOAD_IMAGE_DATA(hdr, fap, off_ + info.it_tlv_tot,
&info, sizeof(info))) {
return -1;
}
} else if (hdr->ih_protect_tlv_size != 0) {
return -1;
}
if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
return -1;
}
it->hdr = hdr;
it->fap = fap;
it->type = type;
it->prot = prot;
it->prot_end = off_ + it->hdr->ih_protect_tlv_size;
it->tlv_end = off_ + it->hdr->ih_protect_tlv_size + info.it_tlv_tot;
// position on first TLV
it->tlv_off = off_ + sizeof(info);
return 0;
}
/*
* Find next TLV
*
* @param it The image TLV iterator struct
* @param off The offset of the TLV's payload in flash
* @param len The length of the TLV's payload
* @param type If not NULL returns the type of TLV found
*
* @returns 0 if a TLV with with matching type was found
* 1 if no more TLVs with matching type are available
* -1 on errors
*/
int
bootutil_tlv_iter_next(struct image_tlv_iter *it, uint32_t *off, uint16_t *len,
uint16_t *type)
{
struct image_tlv tlv;
int rc;
if (it == NULL || it->hdr == NULL || it->fap == NULL) {
return -1;
}
while (it->tlv_off < it->tlv_end) {
if (it->hdr->ih_protect_tlv_size > 0 && it->tlv_off == it->prot_end) {
it->tlv_off += sizeof(struct image_tlv_info);
}
rc = LOAD_IMAGE_DATA(it->hdr, it->fap, it->tlv_off, &tlv, sizeof tlv);
if (rc) {
return -1;
}
/* No more TLVs in the protected area */
if (it->prot && it->tlv_off >= it->prot_end) {
return 1;
}
if (it->type == IMAGE_TLV_ANY || tlv.it_type == it->type) {
if (type != NULL) {
*type = tlv.it_type;
}
*off = it->tlv_off + sizeof(tlv);
*len = tlv.it_len;
it->tlv_off += sizeof(tlv) + tlv.it_len;
return 0;
}
it->tlv_off += sizeof(tlv) + tlv.it_len;
}
return 1;
}
@@ -0,0 +1,358 @@
/**
* \file asn1.h
*
* \brief Generic ASN.1 parsing
*/
/*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#ifndef MBEDTLS_ASN1_H
#define MBEDTLS_ASN1_H
#if !defined(MBEDTLS_CONFIG_FILE)
#include "config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#include <stddef.h>
#if defined(MBEDTLS_BIGNUM_C)
#include "bignum.h"
#endif
/**
* \addtogroup asn1_module
* \{
*/
/**
* \name ASN1 Error codes
* These error codes are OR'ed to X509 error codes for
* higher error granularity.
* ASN1 is a standard to specify data structures.
* \{
*/
#define MBEDTLS_ERR_ASN1_OUT_OF_DATA -0x0060 /**< Out of data when parsing an ASN1 data structure. */
#define MBEDTLS_ERR_ASN1_UNEXPECTED_TAG -0x0062 /**< ASN1 tag was of an unexpected value. */
#define MBEDTLS_ERR_ASN1_INVALID_LENGTH -0x0064 /**< Error when trying to determine the length or invalid length. */
#define MBEDTLS_ERR_ASN1_LENGTH_MISMATCH -0x0066 /**< Actual length differs from expected length. */
#define MBEDTLS_ERR_ASN1_INVALID_DATA -0x0068 /**< Data is invalid. (not used) */
#define MBEDTLS_ERR_ASN1_ALLOC_FAILED -0x006A /**< Memory allocation failed */
#define MBEDTLS_ERR_ASN1_BUF_TOO_SMALL -0x006C /**< Buffer too small when writing ASN.1 data structure. */
/* \} name */
/**
* \name DER constants
* These constants comply with the DER encoded ASN.1 type tags.
* DER encoding uses hexadecimal representation.
* An example DER sequence is:\n
* - 0x02 -- tag indicating INTEGER
* - 0x01 -- length in octets
* - 0x05 -- value
* Such sequences are typically read into \c ::mbedtls_x509_buf.
* \{
*/
#define MBEDTLS_ASN1_BOOLEAN 0x01
#define MBEDTLS_ASN1_INTEGER 0x02
#define MBEDTLS_ASN1_BIT_STRING 0x03
#define MBEDTLS_ASN1_OCTET_STRING 0x04
#define MBEDTLS_ASN1_NULL 0x05
#define MBEDTLS_ASN1_OID 0x06
#define MBEDTLS_ASN1_UTF8_STRING 0x0C
#define MBEDTLS_ASN1_SEQUENCE 0x10
#define MBEDTLS_ASN1_SET 0x11
#define MBEDTLS_ASN1_PRINTABLE_STRING 0x13
#define MBEDTLS_ASN1_T61_STRING 0x14
#define MBEDTLS_ASN1_IA5_STRING 0x16
#define MBEDTLS_ASN1_UTC_TIME 0x17
#define MBEDTLS_ASN1_GENERALIZED_TIME 0x18
#define MBEDTLS_ASN1_UNIVERSAL_STRING 0x1C
#define MBEDTLS_ASN1_BMP_STRING 0x1E
#define MBEDTLS_ASN1_PRIMITIVE 0x00
#define MBEDTLS_ASN1_CONSTRUCTED 0x20
#define MBEDTLS_ASN1_CONTEXT_SPECIFIC 0x80
/*
* Bit masks for each of the components of an ASN.1 tag as specified in
* ITU X.690 (08/2015), section 8.1 "General rules for encoding",
* paragraph 8.1.2.2:
*
* Bit 8 7 6 5 1
* +-------+-----+------------+
* | Class | P/C | Tag number |
* +-------+-----+------------+
*/
#define MBEDTLS_ASN1_TAG_CLASS_MASK 0xC0
#define MBEDTLS_ASN1_TAG_PC_MASK 0x20
#define MBEDTLS_ASN1_TAG_VALUE_MASK 0x1F
/* \} name */
/* \} addtogroup asn1_module */
/** Returns the size of the binary string, without the trailing \\0 */
#define MBEDTLS_OID_SIZE(x) (sizeof(x) - 1)
/**
* Compares an mbedtls_asn1_buf structure to a reference OID.
*
* Only works for 'defined' oid_str values (MBEDTLS_OID_HMAC_SHA1), you cannot use a
* 'unsigned char *oid' here!
*/
#define MBEDTLS_OID_CMP(oid_str, oid_buf) \
( ( MBEDTLS_OID_SIZE(oid_str) != (oid_buf)->len ) || \
memcmp( (oid_str), (oid_buf)->p, (oid_buf)->len) != 0 )
#ifdef __cplusplus
extern "C" {
#endif
/**
* \name Functions to parse ASN.1 data structures
* \{
*/
/**
* Type-length-value structure that allows for ASN1 using DER.
*/
typedef struct mbedtls_asn1_buf
{
int tag; /**< ASN1 type, e.g. MBEDTLS_ASN1_UTF8_STRING. */
size_t len; /**< ASN1 length, in octets. */
unsigned char *p; /**< ASN1 data, e.g. in ASCII. */
}
mbedtls_asn1_buf;
/**
* Container for ASN1 bit strings.
*/
typedef struct mbedtls_asn1_bitstring
{
size_t len; /**< ASN1 length, in octets. */
unsigned char unused_bits; /**< Number of unused bits at the end of the string */
unsigned char *p; /**< Raw ASN1 data for the bit string */
}
mbedtls_asn1_bitstring;
/**
* Container for a sequence of ASN.1 items
*/
typedef struct mbedtls_asn1_sequence
{
mbedtls_asn1_buf buf; /**< Buffer containing the given ASN.1 item. */
struct mbedtls_asn1_sequence *next; /**< The next entry in the sequence. */
}
mbedtls_asn1_sequence;
/**
* Container for a sequence or list of 'named' ASN.1 data items
*/
typedef struct mbedtls_asn1_named_data
{
mbedtls_asn1_buf oid; /**< The object identifier. */
mbedtls_asn1_buf val; /**< The named value. */
struct mbedtls_asn1_named_data *next; /**< The next entry in the sequence. */
unsigned char next_merged; /**< Merge next item into the current one? */
}
mbedtls_asn1_named_data;
/**
* \brief Get the length of an ASN.1 element.
* Updates the pointer to immediately behind the length.
*
* \param p The position in the ASN.1 data
* \param end End of data
* \param len The variable that will receive the value
*
* \return 0 if successful, MBEDTLS_ERR_ASN1_OUT_OF_DATA on reaching
* end of data, MBEDTLS_ERR_ASN1_INVALID_LENGTH if length is
* unparseable.
*/
int mbedtls_asn1_get_len( unsigned char **p,
const unsigned char *end,
size_t *len );
/**
* \brief Get the tag and length of the tag. Check for the requested tag.
* Updates the pointer to immediately behind the tag and length.
*
* \param p The position in the ASN.1 data
* \param end End of data
* \param len The variable that will receive the length
* \param tag The expected tag
*
* \return 0 if successful, MBEDTLS_ERR_ASN1_UNEXPECTED_TAG if tag did
* not match requested tag, or another specific ASN.1 error code.
*/
int mbedtls_asn1_get_tag( unsigned char **p,
const unsigned char *end,
size_t *len, int tag );
/**
* \brief Retrieve a boolean ASN.1 tag and its value.
* Updates the pointer to immediately behind the full tag.
*
* \param p The position in the ASN.1 data
* \param end End of data
* \param val The variable that will receive the value
*
* \return 0 if successful or a specific ASN.1 error code.
*/
int mbedtls_asn1_get_bool( unsigned char **p,
const unsigned char *end,
int *val );
/**
* \brief Retrieve an integer ASN.1 tag and its value.
* Updates the pointer to immediately behind the full tag.
*
* \param p The position in the ASN.1 data
* \param end End of data
* \param val The variable that will receive the value
*
* \return 0 if successful or a specific ASN.1 error code.
*/
int mbedtls_asn1_get_int( unsigned char **p,
const unsigned char *end,
int *val );
/**
* \brief Retrieve a bitstring ASN.1 tag and its value.
* Updates the pointer to immediately behind the full tag.
*
* \param p The position in the ASN.1 data
* \param end End of data
* \param bs The variable that will receive the value
*
* \return 0 if successful or a specific ASN.1 error code.
*/
int mbedtls_asn1_get_bitstring( unsigned char **p, const unsigned char *end,
mbedtls_asn1_bitstring *bs);
/**
* \brief Retrieve a bitstring ASN.1 tag without unused bits and its
* value.
* Updates the pointer to the beginning of the bit/octet string.
*
* \param p The position in the ASN.1 data
* \param end End of data
* \param len Length of the actual bit/octect string in bytes
*
* \return 0 if successful or a specific ASN.1 error code.
*/
int mbedtls_asn1_get_bitstring_null( unsigned char **p, const unsigned char *end,
size_t *len );
/**
* \brief Parses and splits an ASN.1 "SEQUENCE OF <tag>"
* Updated the pointer to immediately behind the full sequence tag.
*
* \param p The position in the ASN.1 data
* \param end End of data
* \param cur First variable in the chain to fill
* \param tag Type of sequence
*
* \return 0 if successful or a specific ASN.1 error code.
*/
int mbedtls_asn1_get_sequence_of( unsigned char **p,
const unsigned char *end,
mbedtls_asn1_sequence *cur,
int tag);
#if defined(MBEDTLS_BIGNUM_C)
/**
* \brief Retrieve a MPI value from an integer ASN.1 tag.
* Updates the pointer to immediately behind the full tag.
*
* \param p The position in the ASN.1 data
* \param end End of data
* \param X The MPI that will receive the value
*
* \return 0 if successful or a specific ASN.1 or MPI error code.
*/
int mbedtls_asn1_get_mpi( unsigned char **p,
const unsigned char *end,
mbedtls_mpi *X );
#endif /* MBEDTLS_BIGNUM_C */
/**
* \brief Retrieve an AlgorithmIdentifier ASN.1 sequence.
* Updates the pointer to immediately behind the full
* AlgorithmIdentifier.
*
* \param p The position in the ASN.1 data
* \param end End of data
* \param alg The buffer to receive the OID
* \param params The buffer to receive the params (if any)
*
* \return 0 if successful or a specific ASN.1 or MPI error code.
*/
int mbedtls_asn1_get_alg( unsigned char **p,
const unsigned char *end,
mbedtls_asn1_buf *alg, mbedtls_asn1_buf *params );
/**
* \brief Retrieve an AlgorithmIdentifier ASN.1 sequence with NULL or no
* params.
* Updates the pointer to immediately behind the full
* AlgorithmIdentifier.
*
* \param p The position in the ASN.1 data
* \param end End of data
* \param alg The buffer to receive the OID
*
* \return 0 if successful or a specific ASN.1 or MPI error code.
*/
int mbedtls_asn1_get_alg_null( unsigned char **p,
const unsigned char *end,
mbedtls_asn1_buf *alg );
/**
* \brief Find a specific named_data entry in a sequence or list based on
* the OID.
*
* \param list The list to seek through
* \param oid The OID to look for
* \param len Size of the OID
*
* \return NULL if not found, or a pointer to the existing entry.
*/
mbedtls_asn1_named_data *mbedtls_asn1_find_named_data( mbedtls_asn1_named_data *list,
const char *oid, size_t len );
/**
* \brief Free a mbedtls_asn1_named_data entry
*
* \param entry The named data entry to free
*/
void mbedtls_asn1_free_named_data( mbedtls_asn1_named_data *entry );
/**
* \brief Free all entries in a mbedtls_asn1_named_data list
* Head will be set to NULL
*
* \param head Pointer to the head of the list of named data entries to free
*/
void mbedtls_asn1_free_named_data_list( mbedtls_asn1_named_data **head );
#ifdef __cplusplus
}
#endif
#endif /* asn1.h */
@@ -0,0 +1,821 @@
/**
* \file bignum.h
*
* \brief Multi-precision integer library
*/
/*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#ifndef MBEDTLS_BIGNUM_H
#define MBEDTLS_BIGNUM_H
#if !defined(MBEDTLS_CONFIG_FILE)
#include "config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#include <stddef.h>
#include <stdint.h>
#if defined(MBEDTLS_FS_IO)
#include <stdio.h>
#endif
#define MBEDTLS_ERR_MPI_FILE_IO_ERROR -0x0002 /**< An error occurred while reading from or writing to a file. */
#define MBEDTLS_ERR_MPI_BAD_INPUT_DATA -0x0004 /**< Bad input parameters to function. */
#define MBEDTLS_ERR_MPI_INVALID_CHARACTER -0x0006 /**< There is an invalid character in the digit string. */
#define MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL -0x0008 /**< The buffer is too small to write to. */
#define MBEDTLS_ERR_MPI_NEGATIVE_VALUE -0x000A /**< The input arguments are negative or result in illegal output. */
#define MBEDTLS_ERR_MPI_DIVISION_BY_ZERO -0x000C /**< The input argument for division is zero, which is not allowed. */
#define MBEDTLS_ERR_MPI_NOT_ACCEPTABLE -0x000E /**< The input arguments are not acceptable. */
#define MBEDTLS_ERR_MPI_ALLOC_FAILED -0x0010 /**< Memory allocation failed. */
#define MBEDTLS_MPI_CHK(f) do { if( ( ret = f ) != 0 ) goto cleanup; } while( 0 )
/*
* Maximum size MPIs are allowed to grow to in number of limbs.
*/
#define MBEDTLS_MPI_MAX_LIMBS 10000
#if !defined(MBEDTLS_MPI_WINDOW_SIZE)
/*
* Maximum window size used for modular exponentiation. Default: 6
* Minimum value: 1. Maximum value: 6.
*
* Result is an array of ( 2 << MBEDTLS_MPI_WINDOW_SIZE ) MPIs used
* for the sliding window calculation. (So 64 by default)
*
* Reduction in size, reduces speed.
*/
#define MBEDTLS_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */
#endif /* !MBEDTLS_MPI_WINDOW_SIZE */
#if !defined(MBEDTLS_MPI_MAX_SIZE)
/*
* Maximum size of MPIs allowed in bits and bytes for user-MPIs.
* ( Default: 512 bytes => 4096 bits, Maximum tested: 2048 bytes => 16384 bits )
*
* Note: Calculations can temporarily result in larger MPIs. So the number
* of limbs required (MBEDTLS_MPI_MAX_LIMBS) is higher.
*/
#define MBEDTLS_MPI_MAX_SIZE 1024 /**< Maximum number of bytes for usable MPIs. */
#endif /* !MBEDTLS_MPI_MAX_SIZE */
#define MBEDTLS_MPI_MAX_BITS ( 8 * MBEDTLS_MPI_MAX_SIZE ) /**< Maximum number of bits for usable MPIs. */
/*
* When reading from files with mbedtls_mpi_read_file() and writing to files with
* mbedtls_mpi_write_file() the buffer should have space
* for a (short) label, the MPI (in the provided radix), the newline
* characters and the '\0'.
*
* By default we assume at least a 10 char label, a minimum radix of 10
* (decimal) and a maximum of 4096 bit numbers (1234 decimal chars).
* Autosized at compile time for at least a 10 char label, a minimum radix
* of 10 (decimal) for a number of MBEDTLS_MPI_MAX_BITS size.
*
* This used to be statically sized to 1250 for a maximum of 4096 bit
* numbers (1234 decimal chars).
*
* Calculate using the formula:
* MBEDTLS_MPI_RW_BUFFER_SIZE = ceil(MBEDTLS_MPI_MAX_BITS / ln(10) * ln(2)) +
* LabelSize + 6
*/
#define MBEDTLS_MPI_MAX_BITS_SCALE100 ( 100 * MBEDTLS_MPI_MAX_BITS )
#define MBEDTLS_LN_2_DIV_LN_10_SCALE100 332
#define MBEDTLS_MPI_RW_BUFFER_SIZE ( ((MBEDTLS_MPI_MAX_BITS_SCALE100 + MBEDTLS_LN_2_DIV_LN_10_SCALE100 - 1) / MBEDTLS_LN_2_DIV_LN_10_SCALE100) + 10 + 6 )
/*
* Define the base integer type, architecture-wise.
*
* 32 or 64-bit integer types can be forced regardless of the underlying
* architecture by defining MBEDTLS_HAVE_INT32 or MBEDTLS_HAVE_INT64
* respectively and undefining MBEDTLS_HAVE_ASM.
*
* Double-width integers (e.g. 128-bit in 64-bit architectures) can be
* disabled by defining MBEDTLS_NO_UDBL_DIVISION.
*/
#if !defined(MBEDTLS_HAVE_INT32)
#if defined(_MSC_VER) && defined(_M_AMD64)
/* Always choose 64-bit when using MSC */
#if !defined(MBEDTLS_HAVE_INT64)
#define MBEDTLS_HAVE_INT64
#endif /* !MBEDTLS_HAVE_INT64 */
typedef int64_t mbedtls_mpi_sint;
typedef uint64_t mbedtls_mpi_uint;
#elif defined(__GNUC__) && ( \
defined(__amd64__) || defined(__x86_64__) || \
defined(__ppc64__) || defined(__powerpc64__) || \
defined(__ia64__) || defined(__alpha__) || \
( defined(__sparc__) && defined(__arch64__) ) || \
defined(__s390x__) || defined(__mips64) )
#if !defined(MBEDTLS_HAVE_INT64)
#define MBEDTLS_HAVE_INT64
#endif /* MBEDTLS_HAVE_INT64 */
typedef int64_t mbedtls_mpi_sint;
typedef uint64_t mbedtls_mpi_uint;
#if !defined(MBEDTLS_NO_UDBL_DIVISION)
/* mbedtls_t_udbl defined as 128-bit unsigned int */
typedef unsigned int mbedtls_t_udbl __attribute__((mode(TI)));
#define MBEDTLS_HAVE_UDBL
#endif /* !MBEDTLS_NO_UDBL_DIVISION */
#elif defined(__ARMCC_VERSION) && defined(__aarch64__)
/*
* __ARMCC_VERSION is defined for both armcc and armclang and
* __aarch64__ is only defined by armclang when compiling 64-bit code
*/
#if !defined(MBEDTLS_HAVE_INT64)
#define MBEDTLS_HAVE_INT64
#endif /* !MBEDTLS_HAVE_INT64 */
typedef int64_t mbedtls_mpi_sint;
typedef uint64_t mbedtls_mpi_uint;
#if !defined(MBEDTLS_NO_UDBL_DIVISION)
/* mbedtls_t_udbl defined as 128-bit unsigned int */
typedef __uint128_t mbedtls_t_udbl;
#define MBEDTLS_HAVE_UDBL
#endif /* !MBEDTLS_NO_UDBL_DIVISION */
#elif defined(MBEDTLS_HAVE_INT64)
/* Force 64-bit integers with unknown compiler */
typedef int64_t mbedtls_mpi_sint;
typedef uint64_t mbedtls_mpi_uint;
#endif
#endif /* !MBEDTLS_HAVE_INT32 */
#if !defined(MBEDTLS_HAVE_INT64)
/* Default to 32-bit compilation */
#if !defined(MBEDTLS_HAVE_INT32)
#define MBEDTLS_HAVE_INT32
#endif /* !MBEDTLS_HAVE_INT32 */
typedef int32_t mbedtls_mpi_sint;
typedef uint32_t mbedtls_mpi_uint;
#if !defined(MBEDTLS_NO_UDBL_DIVISION)
typedef uint64_t mbedtls_t_udbl;
#define MBEDTLS_HAVE_UDBL
#endif /* !MBEDTLS_NO_UDBL_DIVISION */
#endif /* !MBEDTLS_HAVE_INT64 */
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief MPI structure
*/
typedef struct mbedtls_mpi
{
int s; /*!< integer sign */
size_t n; /*!< total # of limbs */
mbedtls_mpi_uint *p; /*!< pointer to limbs */
}
mbedtls_mpi;
/**
* \brief Initialize one MPI (make internal references valid)
* This just makes it ready to be set or freed,
* but does not define a value for the MPI.
*
* \param X One MPI to initialize.
*/
void mbedtls_mpi_init( mbedtls_mpi *X );
/**
* \brief Unallocate one MPI
*
* \param X One MPI to unallocate.
*/
void mbedtls_mpi_free( mbedtls_mpi *X );
/**
* \brief Enlarge to the specified number of limbs
*
* This function does nothing if the MPI is already large enough.
*
* \param X MPI to grow
* \param nblimbs The target number of limbs
*
* \return 0 if successful,
* MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
*/
int mbedtls_mpi_grow( mbedtls_mpi *X, size_t nblimbs );
/**
* \brief Resize down, keeping at least the specified number of limbs
*
* If \c X is smaller than \c nblimbs, it is resized up
* instead.
*
* \param X MPI to shrink
* \param nblimbs The minimum number of limbs to keep
*
* \return 0 if successful,
* MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
* (this can only happen when resizing up).
*/
int mbedtls_mpi_shrink( mbedtls_mpi *X, size_t nblimbs );
/**
* \brief Copy the contents of Y into X
*
* \param X Destination MPI. It is enlarged if necessary.
* \param Y Source MPI.
*
* \return 0 if successful,
* MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
*/
int mbedtls_mpi_copy( mbedtls_mpi *X, const mbedtls_mpi *Y );
/**
* \brief Swap the contents of X and Y
*
* \param X First MPI value
* \param Y Second MPI value
*/
void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y );
/**
* \brief Safe conditional assignement X = Y if assign is 1
*
* \param X MPI to conditionally assign to
* \param Y Value to be assigned
* \param assign 1: perform the assignment, 0: keep X's original value
*
* \return 0 if successful,
* MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed,
*
* \note This function is equivalent to
* if( assign ) mbedtls_mpi_copy( X, Y );
* except that it avoids leaking any information about whether
* the assignment was done or not (the above code may leak
* information through branch prediction and/or memory access
* patterns analysis).
*/
int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned char assign );
/**
* \brief Safe conditional swap X <-> Y if swap is 1
*
* \param X First mbedtls_mpi value
* \param Y Second mbedtls_mpi value
* \param assign 1: perform the swap, 0: keep X and Y's original values
*
* \return 0 if successful,
* MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed,
*
* \note This function is equivalent to
* if( assign ) mbedtls_mpi_swap( X, Y );
* except that it avoids leaking any information about whether
* the assignment was done or not (the above code may leak
* information through branch prediction and/or memory access
* patterns analysis).
*/
int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char assign );
/**
* \brief Set value from integer
*
* \param X MPI to set
* \param z Value to use
*
* \return 0 if successful,
* MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
*/
int mbedtls_mpi_lset( mbedtls_mpi *X, mbedtls_mpi_sint z );
/**
* \brief Get a specific bit from X
*
* \param X MPI to use
* \param pos Zero-based index of the bit in X
*
* \return Either a 0 or a 1
*/
int mbedtls_mpi_get_bit( const mbedtls_mpi *X, size_t pos );
/**
* \brief Set a bit of X to a specific value of 0 or 1
*
* \note Will grow X if necessary to set a bit to 1 in a not yet
* existing limb. Will not grow if bit should be set to 0
*
* \param X MPI to use
* \param pos Zero-based index of the bit in X
* \param val The value to set the bit to (0 or 1)
*
* \return 0 if successful,
* MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed,
* MBEDTLS_ERR_MPI_BAD_INPUT_DATA if val is not 0 or 1
*/
int mbedtls_mpi_set_bit( mbedtls_mpi *X, size_t pos, unsigned char val );
/**
* \brief Return the number of zero-bits before the least significant
* '1' bit
*
* Note: Thus also the zero-based index of the least significant '1' bit
*
* \param X MPI to use
*/
size_t mbedtls_mpi_lsb( const mbedtls_mpi *X );
/**
* \brief Return the number of bits up to and including the most
* significant '1' bit'
*
* Note: Thus also the one-based index of the most significant '1' bit
*
* \param X MPI to use
*/
size_t mbedtls_mpi_bitlen( const mbedtls_mpi *X );
/**
* \brief Return the total size in bytes
*
* \param X MPI to use
*/
size_t mbedtls_mpi_size( const mbedtls_mpi *X );
/**
* \brief Import from an ASCII string
*
* \param X Destination MPI
* \param radix Input numeric base
* \param s Null-terminated string buffer
*
* \return 0 if successful, or a MBEDTLS_ERR_MPI_XXX error code
*/
int mbedtls_mpi_read_string( mbedtls_mpi *X, int radix, const char *s );
/**
* \brief Export into an ASCII string
*
* \param X Source MPI
* \param radix Output numeric base
* \param buf Buffer to write the string to
* \param buflen Length of buf
* \param olen Length of the string written, including final NUL byte
*
* \return 0 if successful, or a MBEDTLS_ERR_MPI_XXX error code.
* *olen is always updated to reflect the amount
* of data that has (or would have) been written.
*
* \note Call this function with buflen = 0 to obtain the
* minimum required buffer size in *olen.
*/
int mbedtls_mpi_write_string( const mbedtls_mpi *X, int radix,
char *buf, size_t buflen, size_t *olen );
#if defined(MBEDTLS_FS_IO)
/**
* \brief Read MPI from a line in an opened file
*
* \param X Destination MPI
* \param radix Input numeric base
* \param fin Input file handle
*
* \return 0 if successful, MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if
* the file read buffer is too small or a
* MBEDTLS_ERR_MPI_XXX error code
*
* \note On success, this function advances the file stream
* to the end of the current line or to EOF.
*
* The function returns 0 on an empty line.
*
* Leading whitespaces are ignored, as is a
* '0x' prefix for radix 16.
*
*/
int mbedtls_mpi_read_file( mbedtls_mpi *X, int radix, FILE *fin );
/**
* \brief Write X into an opened file, or stdout if fout is NULL
*
* \param p Prefix, can be NULL
* \param X Source MPI
* \param radix Output numeric base
* \param fout Output file handle (can be NULL)
*
* \return 0 if successful, or a MBEDTLS_ERR_MPI_XXX error code
*
* \note Set fout == NULL to print X on the console.
*/
int mbedtls_mpi_write_file( const char *p, const mbedtls_mpi *X, int radix, FILE *fout );
#endif /* MBEDTLS_FS_IO */
/**
* \brief Import X from unsigned binary data, big endian
*
* \param X Destination MPI
* \param buf Input buffer
* \param buflen Input buffer size
*
* \return 0 if successful,
* MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
*/
int mbedtls_mpi_read_binary( mbedtls_mpi *X, const unsigned char *buf, size_t buflen );
/**
* \brief Export X into unsigned binary data, big endian.
* Always fills the whole buffer, which will start with zeros
* if the number is smaller.
*
* \param X Source MPI
* \param buf Output buffer
* \param buflen Output buffer size
*
* \return 0 if successful,
* MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if buf isn't large enough
*/
int mbedtls_mpi_write_binary( const mbedtls_mpi *X, unsigned char *buf, size_t buflen );
/**
* \brief Left-shift: X <<= count
*
* \param X MPI to shift
* \param count Amount to shift
*
* \return 0 if successful,
* MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
*/
int mbedtls_mpi_shift_l( mbedtls_mpi *X, size_t count );
/**
* \brief Right-shift: X >>= count
*
* \param X MPI to shift
* \param count Amount to shift
*
* \return 0 if successful,
* MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
*/
int mbedtls_mpi_shift_r( mbedtls_mpi *X, size_t count );
/**
* \brief Compare unsigned values
*
* \param X Left-hand MPI
* \param Y Right-hand MPI
*
* \return 1 if |X| is greater than |Y|,
* -1 if |X| is lesser than |Y| or
* 0 if |X| is equal to |Y|
*/
int mbedtls_mpi_cmp_abs( const mbedtls_mpi *X, const mbedtls_mpi *Y );
/**
* \brief Compare signed values
*
* \param X Left-hand MPI
* \param Y Right-hand MPI
*
* \return 1 if X is greater than Y,
* -1 if X is lesser than Y or
* 0 if X is equal to Y
*/
int mbedtls_mpi_cmp_mpi( const mbedtls_mpi *X, const mbedtls_mpi *Y );
/**
* \brief Compare signed values
*
* \param X Left-hand MPI
* \param z The integer value to compare to
*
* \return 1 if X is greater than z,
* -1 if X is lesser than z or
* 0 if X is equal to z
*/
int mbedtls_mpi_cmp_int( const mbedtls_mpi *X, mbedtls_mpi_sint z );
/**
* \brief Unsigned addition: X = |A| + |B|
*
* \param X Destination MPI
* \param A Left-hand MPI
* \param B Right-hand MPI
*
* \return 0 if successful,
* MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
*/
int mbedtls_mpi_add_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B );
/**
* \brief Unsigned subtraction: X = |A| - |B|
*
* \param X Destination MPI
* \param A Left-hand MPI
* \param B Right-hand MPI
*
* \return 0 if successful,
* MBEDTLS_ERR_MPI_NEGATIVE_VALUE if B is greater than A
*/
int mbedtls_mpi_sub_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B );
/**
* \brief Signed addition: X = A + B
*
* \param X Destination MPI
* \param A Left-hand MPI
* \param B Right-hand MPI
*
* \return 0 if successful,
* MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
*/
int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B );
/**
* \brief Signed subtraction: X = A - B
*
* \param X Destination MPI
* \param A Left-hand MPI
* \param B Right-hand MPI
*
* \return 0 if successful,
* MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
*/
int mbedtls_mpi_sub_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B );
/**
* \brief Signed addition: X = A + b
*
* \param X Destination MPI
* \param A Left-hand MPI
* \param b The integer value to add
*
* \return 0 if successful,
* MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
*/
int mbedtls_mpi_add_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b );
/**
* \brief Signed subtraction: X = A - b
*
* \param X Destination MPI
* \param A Left-hand MPI
* \param b The integer value to subtract
*
* \return 0 if successful,
* MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
*/
int mbedtls_mpi_sub_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b );
/**
* \brief Baseline multiplication: X = A * B
*
* \param X Destination MPI
* \param A Left-hand MPI
* \param B Right-hand MPI
*
* \return 0 if successful,
* MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
*/
int mbedtls_mpi_mul_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B );
/**
* \brief Baseline multiplication: X = A * b
*
* \param X Destination MPI
* \param A Left-hand MPI
* \param b The unsigned integer value to multiply with
*
* \note b is unsigned
*
* \return 0 if successful,
* MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
*/
int mbedtls_mpi_mul_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b );
/**
* \brief Division by mbedtls_mpi: A = Q * B + R
*
* \param Q Destination MPI for the quotient
* \param R Destination MPI for the rest value
* \param A Left-hand MPI
* \param B Right-hand MPI
*
* \return 0 if successful,
* MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed,
* MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if B == 0
*
* \note Either Q or R can be NULL.
*/
int mbedtls_mpi_div_mpi( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B );
/**
* \brief Division by int: A = Q * b + R
*
* \param Q Destination MPI for the quotient
* \param R Destination MPI for the rest value
* \param A Left-hand MPI
* \param b Integer to divide by
*
* \return 0 if successful,
* MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed,
* MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if b == 0
*
* \note Either Q or R can be NULL.
*/
int mbedtls_mpi_div_int( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, mbedtls_mpi_sint b );
/**
* \brief Modulo: R = A mod B
*
* \param R Destination MPI for the rest value
* \param A Left-hand MPI
* \param B Right-hand MPI
*
* \return 0 if successful,
* MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed,
* MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if B == 0,
* MBEDTLS_ERR_MPI_NEGATIVE_VALUE if B < 0
*/
int mbedtls_mpi_mod_mpi( mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B );
/**
* \brief Modulo: r = A mod b
*
* \param r Destination mbedtls_mpi_uint
* \param A Left-hand MPI
* \param b Integer to divide by
*
* \return 0 if successful,
* MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed,
* MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if b == 0,
* MBEDTLS_ERR_MPI_NEGATIVE_VALUE if b < 0
*/
int mbedtls_mpi_mod_int( mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b );
/**
* \brief Sliding-window exponentiation: X = A^E mod N
*
* \param X Destination MPI
* \param A Left-hand MPI
* \param E Exponent MPI
* \param N Modular MPI
* \param _RR Speed-up MPI used for recalculations
*
* \return 0 if successful,
* MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed,
* MBEDTLS_ERR_MPI_BAD_INPUT_DATA if N is negative or even or
* if E is negative
*
* \note _RR is used to avoid re-computing R*R mod N across
* multiple calls, which speeds up things a bit. It can
* be set to NULL if the extra performance is unneeded.
*/
int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *E, const mbedtls_mpi *N, mbedtls_mpi *_RR );
/**
* \brief Fill an MPI X with size bytes of random
*
* \param X Destination MPI
* \param size Size in bytes
* \param f_rng RNG function
* \param p_rng RNG parameter
*
* \return 0 if successful,
* MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
*
* \note The bytes obtained from the PRNG are interpreted
* as a big-endian representation of an MPI; this can
* be relevant in applications like deterministic ECDSA.
*/
int mbedtls_mpi_fill_random( mbedtls_mpi *X, size_t size,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng );
/**
* \brief Greatest common divisor: G = gcd(A, B)
*
* \param G Destination MPI
* \param A Left-hand MPI
* \param B Right-hand MPI
*
* \return 0 if successful,
* MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
*/
int mbedtls_mpi_gcd( mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B );
/**
* \brief Modular inverse: X = A^-1 mod N
*
* \param X Destination MPI
* \param A Left-hand MPI
* \param N Right-hand MPI
*
* \return 0 if successful,
* MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed,
* MBEDTLS_ERR_MPI_BAD_INPUT_DATA if N is <= 1,
MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if A has no inverse mod N.
*/
int mbedtls_mpi_inv_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N );
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
#if defined(MBEDTLS_DEPRECATED_WARNING)
#define MBEDTLS_DEPRECATED __attribute__((deprecated))
#else
#define MBEDTLS_DEPRECATED
#endif
/**
* \brief Miller-Rabin primality test with error probability of
* 2<sup>-80</sup>
*
* \deprecated Superseded by mbedtls_mpi_is_prime_ext() which allows
* specifying the number of Miller-Rabin rounds.
*
* \param X MPI to check
* \param f_rng RNG function
* \param p_rng RNG parameter
*
* \return 0 if successful (probably prime),
* MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed,
* MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if X is not prime
*/
MBEDTLS_DEPRECATED int mbedtls_mpi_is_prime( const mbedtls_mpi *X,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng );
#undef MBEDTLS_DEPRECATED
#endif /* !MBEDTLS_DEPRECATED_REMOVED */
/**
* \brief Miller-Rabin primality test.
*
* \warning If \p X is potentially generated by an adversary, for example
* when validating cryptographic parameters that you didn't
* generate yourself and that are supposed to be prime, then
* \p rounds should be at least the half of the security
* strength of the cryptographic algorithm. On the other hand,
* if \p X is chosen uniformly or non-adversially (as is the
* case when mbedtls_mpi_gen_prime calls this function), then
* \p rounds can be much lower.
*
* \param X MPI to check
* \param rounds Number of bases to perform Miller-Rabin primality test for.
* The probability of returning 0 on a composite is at most
* 2<sup>-2*\p rounds</sup>.
* \param f_rng RNG function
* \param p_rng RNG parameter
*
* \return 0 if successful (probably prime),
* MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed,
* MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if X is not prime
*/
int mbedtls_mpi_is_prime_ext( const mbedtls_mpi *X, int rounds,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng );
/**
* \brief Flags for mbedtls_mpi_gen_prime()
*
* Each of these flags is a constraint on the result X returned by
* mbedtls_mpi_gen_prime().
*/
typedef enum {
MBEDTLS_MPI_GEN_PRIME_FLAG_DH = 0x0001, /**< (X-1)/2 is prime too */
MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR = 0x0002, /**< lower error rate from 2<sup>-80</sup> to 2<sup>-128</sup> */
} mbedtls_mpi_gen_prime_flag_t;
/**
* \brief Prime number generation
*
* \param X Destination MPI
* \param nbits Required size of X in bits
* ( 3 <= nbits <= MBEDTLS_MPI_MAX_BITS )
* \param flags Mask of flags of type #mbedtls_mpi_gen_prime_flag_t
* \param f_rng RNG function
* \param p_rng RNG parameter
*
* \return 0 if successful (probably prime),
* MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed,
* MBEDTLS_ERR_MPI_BAD_INPUT_DATA if nbits is < 3
*/
int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int flags,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng );
/**
* \brief Checkup routine
*
* \return 0 if successful, or 1 if the test failed
*/
int mbedtls_mpi_self_test( int verbose );
#ifdef __cplusplus
}
#endif
#endif /* bignum.h */
@@ -0,0 +1,693 @@
/**
* \file check_config.h
*
* \brief Consistency checks for configuration options
*/
/*
* Copyright (C) 2006-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* It is recommended to include this file from your config.h
* in order to catch dependency issues early.
*/
#ifndef MBEDTLS_CHECK_CONFIG_H
#define MBEDTLS_CHECK_CONFIG_H
/*
* We assume CHAR_BIT is 8 in many places. In practice, this is true on our
* target platforms, so not an issue, but let's just be extra sure.
*/
#include <limits.h>
#if CHAR_BIT != 8
#error "mbed TLS requires a platform with 8-bit chars"
#endif
#if defined(_WIN32)
#if !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_C is required on Windows"
#endif
/* Fix the config here. Not convenient to put an #ifdef _WIN32 in config.h as
* it would confuse config.pl. */
#if !defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) && \
!defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO)
#define MBEDTLS_PLATFORM_SNPRINTF_ALT
#endif
#endif /* _WIN32 */
#if defined(TARGET_LIKE_MBED) && \
( defined(MBEDTLS_NET_C) || defined(MBEDTLS_TIMING_C) )
#error "The NET and TIMING modules are not available for mbed OS - please use the network and timing functions provided by mbed OS"
#endif
#if defined(MBEDTLS_DEPRECATED_WARNING) && \
!defined(__GNUC__) && !defined(__clang__)
#error "MBEDTLS_DEPRECATED_WARNING only works with GCC and Clang"
#endif
#if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_HAVE_TIME)
#error "MBEDTLS_HAVE_TIME_DATE without MBEDTLS_HAVE_TIME does not make sense"
#endif
#if defined(MBEDTLS_AESNI_C) && !defined(MBEDTLS_HAVE_ASM)
#error "MBEDTLS_AESNI_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_CTR_DRBG_C) && !defined(MBEDTLS_AES_C)
#error "MBEDTLS_CTR_DRBG_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_DHM_C) && !defined(MBEDTLS_BIGNUM_C)
#error "MBEDTLS_DHM_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT) && !defined(MBEDTLS_SSL_TRUNCATED_HMAC)
#error "MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_CMAC_C) && \
!defined(MBEDTLS_AES_C) && !defined(MBEDTLS_DES_C)
#error "MBEDTLS_CMAC_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_NIST_KW_C) && \
( !defined(MBEDTLS_AES_C) || !defined(MBEDTLS_CIPHER_C) )
#error "MBEDTLS_NIST_KW_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ECDH_C) && !defined(MBEDTLS_ECP_C)
#error "MBEDTLS_ECDH_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ECDSA_C) && \
( !defined(MBEDTLS_ECP_C) || \
!defined(MBEDTLS_ASN1_PARSE_C) || \
!defined(MBEDTLS_ASN1_WRITE_C) )
#error "MBEDTLS_ECDSA_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ECJPAKE_C) && \
( !defined(MBEDTLS_ECP_C) || !defined(MBEDTLS_MD_C) )
#error "MBEDTLS_ECJPAKE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ECP_RESTARTABLE) && \
( defined(MBEDTLS_ECDH_COMPUTE_SHARED_ALT) || \
defined(MBEDTLS_ECDH_GEN_PUBLIC_ALT) || \
defined(MBEDTLS_ECDSA_SIGN_ALT) || \
defined(MBEDTLS_ECDSA_VERIFY_ALT) || \
defined(MBEDTLS_ECDSA_GENKEY_ALT) || \
defined(MBEDTLS_ECP_ALT) )
#error "MBEDTLS_ECP_RESTARTABLE defined, but it cannot coexist with an alternative ECP implementation"
#endif
#if defined(MBEDTLS_ECDSA_DETERMINISTIC) && !defined(MBEDTLS_HMAC_DRBG_C)
#error "MBEDTLS_ECDSA_DETERMINISTIC defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ECP_C) && ( !defined(MBEDTLS_BIGNUM_C) || ( \
!defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) ) )
#error "MBEDTLS_ECP_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ENTROPY_C) && (!defined(MBEDTLS_SHA512_C) && \
!defined(MBEDTLS_SHA256_C))
#error "MBEDTLS_ENTROPY_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_SHA512_C) && \
defined(MBEDTLS_CTR_DRBG_ENTROPY_LEN) && (MBEDTLS_CTR_DRBG_ENTROPY_LEN > 64)
#error "MBEDTLS_CTR_DRBG_ENTROPY_LEN value too high"
#endif
#if defined(MBEDTLS_ENTROPY_C) && \
( !defined(MBEDTLS_SHA512_C) || defined(MBEDTLS_ENTROPY_FORCE_SHA256) ) \
&& defined(MBEDTLS_CTR_DRBG_ENTROPY_LEN) && (MBEDTLS_CTR_DRBG_ENTROPY_LEN > 32)
#error "MBEDTLS_CTR_DRBG_ENTROPY_LEN value too high"
#endif
#if defined(MBEDTLS_ENTROPY_C) && \
defined(MBEDTLS_ENTROPY_FORCE_SHA256) && !defined(MBEDTLS_SHA256_C)
#error "MBEDTLS_ENTROPY_FORCE_SHA256 defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_TEST_NULL_ENTROPY) && \
( !defined(MBEDTLS_ENTROPY_C) || !defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES) )
#error "MBEDTLS_TEST_NULL_ENTROPY defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_TEST_NULL_ENTROPY) && \
( defined(MBEDTLS_ENTROPY_NV_SEED) || defined(MBEDTLS_ENTROPY_HARDWARE_ALT) || \
defined(MBEDTLS_HAVEGE_C) )
#error "MBEDTLS_TEST_NULL_ENTROPY defined, but entropy sources too"
#endif
#if defined(MBEDTLS_GCM_C) && ( \
!defined(MBEDTLS_AES_C) && !defined(MBEDTLS_CAMELLIA_C) )
#error "MBEDTLS_GCM_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ECP_RANDOMIZE_JAC_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT)
#error "MBEDTLS_ECP_RANDOMIZE_JAC_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ECP_ADD_MIXED_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT)
#error "MBEDTLS_ECP_ADD_MIXED_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT)
#error "MBEDTLS_ECP_DOUBLE_JAC_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT)
#error "MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT)
#error "MBEDTLS_ECP_NORMALIZE_JAC_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT)
#error "MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ECP_RANDOMIZE_MXZ_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT)
#error "MBEDTLS_ECP_RANDOMIZE_MXZ_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ECP_NORMALIZE_MXZ_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT)
#error "MBEDTLS_ECP_NORMALIZE_MXZ_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_HAVEGE_C) && !defined(MBEDTLS_TIMING_C)
#error "MBEDTLS_HAVEGE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_HKDF_C) && !defined(MBEDTLS_MD_C)
#error "MBEDTLS_HKDF_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_HMAC_DRBG_C) && !defined(MBEDTLS_MD_C)
#error "MBEDTLS_HMAC_DRBG_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) && \
( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) )
#error "MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) && \
( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) )
#error "MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) && !defined(MBEDTLS_DHM_C)
#error "MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) && \
!defined(MBEDTLS_ECDH_C)
#error "MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) && \
( !defined(MBEDTLS_DHM_C) || !defined(MBEDTLS_RSA_C) || \
!defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_PKCS1_V15) )
#error "MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \
( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_RSA_C) || \
!defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_PKCS1_V15) )
#error "MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) && \
( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_ECDSA_C) || \
!defined(MBEDTLS_X509_CRT_PARSE_C) )
#error "MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) && \
( !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) || \
!defined(MBEDTLS_PKCS1_V15) )
#error "MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) && \
( !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) || \
!defined(MBEDTLS_PKCS1_V15) )
#error "MBEDTLS_KEY_EXCHANGE_RSA_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) && \
( !defined(MBEDTLS_ECJPAKE_C) || !defined(MBEDTLS_SHA256_C) || \
!defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) )
#error "MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) && \
( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) )
#error "MBEDTLS_MEMORY_BUFFER_ALLOC_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PADLOCK_C) && !defined(MBEDTLS_HAVE_ASM)
#error "MBEDTLS_PADLOCK_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PEM_PARSE_C) && !defined(MBEDTLS_BASE64_C)
#error "MBEDTLS_PEM_PARSE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PEM_WRITE_C) && !defined(MBEDTLS_BASE64_C)
#error "MBEDTLS_PEM_WRITE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PK_C) && \
( !defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_ECP_C) )
#error "MBEDTLS_PK_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PK_PARSE_C) && !defined(MBEDTLS_PK_C)
#error "MBEDTLS_PK_PARSE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PK_WRITE_C) && !defined(MBEDTLS_PK_C)
#error "MBEDTLS_PK_WRITE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PKCS11_C) && !defined(MBEDTLS_PK_C)
#error "MBEDTLS_PKCS11_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_EXIT_ALT) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_EXIT_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_EXIT_MACRO) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_EXIT_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_EXIT_MACRO) &&\
( defined(MBEDTLS_PLATFORM_STD_EXIT) ||\
defined(MBEDTLS_PLATFORM_EXIT_ALT) )
#error "MBEDTLS_PLATFORM_EXIT_MACRO and MBEDTLS_PLATFORM_STD_EXIT/MBEDTLS_PLATFORM_EXIT_ALT cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_TIME_ALT) &&\
( !defined(MBEDTLS_PLATFORM_C) ||\
!defined(MBEDTLS_HAVE_TIME) )
#error "MBEDTLS_PLATFORM_TIME_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_TIME_MACRO) &&\
( !defined(MBEDTLS_PLATFORM_C) ||\
!defined(MBEDTLS_HAVE_TIME) )
#error "MBEDTLS_PLATFORM_TIME_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_TIME_TYPE_MACRO) &&\
( !defined(MBEDTLS_PLATFORM_C) ||\
!defined(MBEDTLS_HAVE_TIME) )
#error "MBEDTLS_PLATFORM_TIME_TYPE_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_TIME_MACRO) &&\
( defined(MBEDTLS_PLATFORM_STD_TIME) ||\
defined(MBEDTLS_PLATFORM_TIME_ALT) )
#error "MBEDTLS_PLATFORM_TIME_MACRO and MBEDTLS_PLATFORM_STD_TIME/MBEDTLS_PLATFORM_TIME_ALT cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_TIME_TYPE_MACRO) &&\
( defined(MBEDTLS_PLATFORM_STD_TIME) ||\
defined(MBEDTLS_PLATFORM_TIME_ALT) )
#error "MBEDTLS_PLATFORM_TIME_TYPE_MACRO and MBEDTLS_PLATFORM_STD_TIME/MBEDTLS_PLATFORM_TIME_ALT cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_FPRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_FPRINTF_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_FPRINTF_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO) &&\
( defined(MBEDTLS_PLATFORM_STD_FPRINTF) ||\
defined(MBEDTLS_PLATFORM_FPRINTF_ALT) )
#error "MBEDTLS_PLATFORM_FPRINTF_MACRO and MBEDTLS_PLATFORM_STD_FPRINTF/MBEDTLS_PLATFORM_FPRINTF_ALT cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_FREE_MACRO) &&\
( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) )
#error "MBEDTLS_PLATFORM_FREE_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_FREE_MACRO) &&\
defined(MBEDTLS_PLATFORM_STD_FREE)
#error "MBEDTLS_PLATFORM_FREE_MACRO and MBEDTLS_PLATFORM_STD_FREE cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_FREE_MACRO) && !defined(MBEDTLS_PLATFORM_CALLOC_MACRO)
#error "MBEDTLS_PLATFORM_CALLOC_MACRO must be defined if MBEDTLS_PLATFORM_FREE_MACRO is"
#endif
#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) &&\
( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) )
#error "MBEDTLS_PLATFORM_CALLOC_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) &&\
defined(MBEDTLS_PLATFORM_STD_CALLOC)
#error "MBEDTLS_PLATFORM_CALLOC_MACRO and MBEDTLS_PLATFORM_STD_CALLOC cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) && !defined(MBEDTLS_PLATFORM_FREE_MACRO)
#error "MBEDTLS_PLATFORM_FREE_MACRO must be defined if MBEDTLS_PLATFORM_CALLOC_MACRO is"
#endif
#if defined(MBEDTLS_PLATFORM_MEMORY) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_MEMORY defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_PRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_PRINTF_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_PRINTF_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO) &&\
( defined(MBEDTLS_PLATFORM_STD_PRINTF) ||\
defined(MBEDTLS_PLATFORM_PRINTF_ALT) )
#error "MBEDTLS_PLATFORM_PRINTF_MACRO and MBEDTLS_PLATFORM_STD_PRINTF/MBEDTLS_PLATFORM_PRINTF_ALT cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_SNPRINTF_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_SNPRINTF_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO) &&\
( defined(MBEDTLS_PLATFORM_STD_SNPRINTF) ||\
defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) )
#error "MBEDTLS_PLATFORM_SNPRINTF_MACRO and MBEDTLS_PLATFORM_STD_SNPRINTF/MBEDTLS_PLATFORM_SNPRINTF_ALT cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_STD_MEM_HDR) &&\
!defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS)
#error "MBEDTLS_PLATFORM_STD_MEM_HDR defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_CALLOC) && !defined(MBEDTLS_PLATFORM_MEMORY)
#error "MBEDTLS_PLATFORM_STD_CALLOC defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_CALLOC) && !defined(MBEDTLS_PLATFORM_MEMORY)
#error "MBEDTLS_PLATFORM_STD_CALLOC defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_FREE) && !defined(MBEDTLS_PLATFORM_MEMORY)
#error "MBEDTLS_PLATFORM_STD_FREE defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_EXIT) &&\
!defined(MBEDTLS_PLATFORM_EXIT_ALT)
#error "MBEDTLS_PLATFORM_STD_EXIT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_TIME) &&\
( !defined(MBEDTLS_PLATFORM_TIME_ALT) ||\
!defined(MBEDTLS_HAVE_TIME) )
#error "MBEDTLS_PLATFORM_STD_TIME defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_FPRINTF) &&\
!defined(MBEDTLS_PLATFORM_FPRINTF_ALT)
#error "MBEDTLS_PLATFORM_STD_FPRINTF defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_PRINTF) &&\
!defined(MBEDTLS_PLATFORM_PRINTF_ALT)
#error "MBEDTLS_PLATFORM_STD_PRINTF defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_SNPRINTF) &&\
!defined(MBEDTLS_PLATFORM_SNPRINTF_ALT)
#error "MBEDTLS_PLATFORM_STD_SNPRINTF defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ENTROPY_NV_SEED) &&\
( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_ENTROPY_C) )
#error "MBEDTLS_ENTROPY_NV_SEED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_NV_SEED_ALT) &&\
!defined(MBEDTLS_ENTROPY_NV_SEED)
#error "MBEDTLS_PLATFORM_NV_SEED_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ) &&\
!defined(MBEDTLS_PLATFORM_NV_SEED_ALT)
#error "MBEDTLS_PLATFORM_STD_NV_SEED_READ defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE) &&\
!defined(MBEDTLS_PLATFORM_NV_SEED_ALT)
#error "MBEDTLS_PLATFORM_STD_NV_SEED_WRITE defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_NV_SEED_READ_MACRO) &&\
( defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ) ||\
defined(MBEDTLS_PLATFORM_NV_SEED_ALT) )
#error "MBEDTLS_PLATFORM_NV_SEED_READ_MACRO and MBEDTLS_PLATFORM_STD_NV_SEED_READ cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO) &&\
( defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE) ||\
defined(MBEDTLS_PLATFORM_NV_SEED_ALT) )
#error "MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO and MBEDTLS_PLATFORM_STD_NV_SEED_WRITE cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_RSA_C) && ( !defined(MBEDTLS_BIGNUM_C) || \
!defined(MBEDTLS_OID_C) )
#error "MBEDTLS_RSA_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_RSA_C) && ( !defined(MBEDTLS_PKCS1_V21) && \
!defined(MBEDTLS_PKCS1_V15) )
#error "MBEDTLS_RSA_C defined, but none of the PKCS1 versions enabled"
#endif
#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) && \
( !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_PKCS1_V21) )
#error "MBEDTLS_X509_RSASSA_PSS_SUPPORT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_PROTO_SSL3) && ( !defined(MBEDTLS_MD5_C) || \
!defined(MBEDTLS_SHA1_C) )
#error "MBEDTLS_SSL_PROTO_SSL3 defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_PROTO_TLS1) && ( !defined(MBEDTLS_MD5_C) || \
!defined(MBEDTLS_SHA1_C) )
#error "MBEDTLS_SSL_PROTO_TLS1 defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_PROTO_TLS1_1) && ( !defined(MBEDTLS_MD5_C) || \
!defined(MBEDTLS_SHA1_C) )
#error "MBEDTLS_SSL_PROTO_TLS1_1 defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && ( !defined(MBEDTLS_SHA1_C) && \
!defined(MBEDTLS_SHA256_C) && !defined(MBEDTLS_SHA512_C) )
#error "MBEDTLS_SSL_PROTO_TLS1_2 defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_PROTO_DTLS) && \
!defined(MBEDTLS_SSL_PROTO_TLS1_1) && \
!defined(MBEDTLS_SSL_PROTO_TLS1_2)
#error "MBEDTLS_SSL_PROTO_DTLS defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_CLI_C) && !defined(MBEDTLS_SSL_TLS_C)
#error "MBEDTLS_SSL_CLI_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_TLS_C) && ( !defined(MBEDTLS_CIPHER_C) || \
!defined(MBEDTLS_MD_C) )
#error "MBEDTLS_SSL_TLS_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_SRV_C) && !defined(MBEDTLS_SSL_TLS_C)
#error "MBEDTLS_SSL_SRV_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_TLS_C) && (!defined(MBEDTLS_SSL_PROTO_SSL3) && \
!defined(MBEDTLS_SSL_PROTO_TLS1) && !defined(MBEDTLS_SSL_PROTO_TLS1_1) && \
!defined(MBEDTLS_SSL_PROTO_TLS1_2))
#error "MBEDTLS_SSL_TLS_C defined, but no protocols are active"
#endif
#if defined(MBEDTLS_SSL_TLS_C) && (defined(MBEDTLS_SSL_PROTO_SSL3) && \
defined(MBEDTLS_SSL_PROTO_TLS1_1) && !defined(MBEDTLS_SSL_PROTO_TLS1))
#error "Illegal protocol selection"
#endif
#if defined(MBEDTLS_SSL_TLS_C) && (defined(MBEDTLS_SSL_PROTO_TLS1) && \
defined(MBEDTLS_SSL_PROTO_TLS1_2) && !defined(MBEDTLS_SSL_PROTO_TLS1_1))
#error "Illegal protocol selection"
#endif
#if defined(MBEDTLS_SSL_TLS_C) && (defined(MBEDTLS_SSL_PROTO_SSL3) && \
defined(MBEDTLS_SSL_PROTO_TLS1_2) && (!defined(MBEDTLS_SSL_PROTO_TLS1) || \
!defined(MBEDTLS_SSL_PROTO_TLS1_1)))
#error "Illegal protocol selection"
#endif
#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && !defined(MBEDTLS_SSL_PROTO_DTLS)
#error "MBEDTLS_SSL_DTLS_HELLO_VERIFY defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && \
!defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY)
#error "MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) && \
( !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_PROTO_DTLS) )
#error "MBEDTLS_SSL_DTLS_ANTI_REPLAY defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT) && \
( !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_PROTO_DTLS) )
#error "MBEDTLS_SSL_DTLS_BADMAC_LIMIT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) && \
!defined(MBEDTLS_SSL_PROTO_TLS1) && \
!defined(MBEDTLS_SSL_PROTO_TLS1_1) && \
!defined(MBEDTLS_SSL_PROTO_TLS1_2)
#error "MBEDTLS_SSL_ENCRYPT_THEN_MAC defined, but not all prerequsites"
#endif
#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) && \
!defined(MBEDTLS_SSL_PROTO_TLS1) && \
!defined(MBEDTLS_SSL_PROTO_TLS1_1) && \
!defined(MBEDTLS_SSL_PROTO_TLS1_2)
#error "MBEDTLS_SSL_EXTENDED_MASTER_SECRET defined, but not all prerequsites"
#endif
#if defined(MBEDTLS_SSL_TICKET_C) && !defined(MBEDTLS_CIPHER_C)
#error "MBEDTLS_SSL_TICKET_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) && \
!defined(MBEDTLS_SSL_PROTO_SSL3) && !defined(MBEDTLS_SSL_PROTO_TLS1)
#error "MBEDTLS_SSL_CBC_RECORD_SPLITTING defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) && \
!defined(MBEDTLS_X509_CRT_PARSE_C)
#error "MBEDTLS_SSL_SERVER_NAME_INDICATION defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_THREADING_PTHREAD)
#if !defined(MBEDTLS_THREADING_C) || defined(MBEDTLS_THREADING_IMPL)
#error "MBEDTLS_THREADING_PTHREAD defined, but not all prerequisites"
#endif
#define MBEDTLS_THREADING_IMPL
#endif
#if defined(MBEDTLS_THREADING_ALT)
#if !defined(MBEDTLS_THREADING_C) || defined(MBEDTLS_THREADING_IMPL)
#error "MBEDTLS_THREADING_ALT defined, but not all prerequisites"
#endif
#define MBEDTLS_THREADING_IMPL
#endif
#if defined(MBEDTLS_THREADING_C) && !defined(MBEDTLS_THREADING_IMPL)
#error "MBEDTLS_THREADING_C defined, single threading implementation required"
#endif
#undef MBEDTLS_THREADING_IMPL
#if defined(MBEDTLS_VERSION_FEATURES) && !defined(MBEDTLS_VERSION_C)
#error "MBEDTLS_VERSION_FEATURES defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_X509_USE_C) && ( !defined(MBEDTLS_BIGNUM_C) || \
!defined(MBEDTLS_OID_C) || !defined(MBEDTLS_ASN1_PARSE_C) || \
!defined(MBEDTLS_PK_PARSE_C) )
#error "MBEDTLS_X509_USE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_X509_CREATE_C) && ( !defined(MBEDTLS_BIGNUM_C) || \
!defined(MBEDTLS_OID_C) || !defined(MBEDTLS_ASN1_WRITE_C) || \
!defined(MBEDTLS_PK_WRITE_C) )
#error "MBEDTLS_X509_CREATE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_X509_CRT_PARSE_C) && ( !defined(MBEDTLS_X509_USE_C) )
#error "MBEDTLS_X509_CRT_PARSE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_X509_CRL_PARSE_C) && ( !defined(MBEDTLS_X509_USE_C) )
#error "MBEDTLS_X509_CRL_PARSE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_X509_CSR_PARSE_C) && ( !defined(MBEDTLS_X509_USE_C) )
#error "MBEDTLS_X509_CSR_PARSE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_X509_CRT_WRITE_C) && ( !defined(MBEDTLS_X509_CREATE_C) )
#error "MBEDTLS_X509_CRT_WRITE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_X509_CSR_WRITE_C) && ( !defined(MBEDTLS_X509_CREATE_C) )
#error "MBEDTLS_X509_CSR_WRITE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_HAVE_INT32) && defined(MBEDTLS_HAVE_INT64)
#error "MBEDTLS_HAVE_INT32 and MBEDTLS_HAVE_INT64 cannot be defined simultaneously"
#endif /* MBEDTLS_HAVE_INT32 && MBEDTLS_HAVE_INT64 */
#if ( defined(MBEDTLS_HAVE_INT32) || defined(MBEDTLS_HAVE_INT64) ) && \
defined(MBEDTLS_HAVE_ASM)
#error "MBEDTLS_HAVE_INT32/MBEDTLS_HAVE_INT64 and MBEDTLS_HAVE_ASM cannot be defined simultaneously"
#endif /* (MBEDTLS_HAVE_INT32 || MBEDTLS_HAVE_INT64) && MBEDTLS_HAVE_ASM */
/*
* Avoid warning from -pedantic. This is a convenient place for this
* workaround since this is included by every single file before the
* #if defined(MBEDTLS_xxx_C) that results in emtpy translation units.
*/
typedef int mbedtls_iso_c_forbids_empty_translation_units;
#endif /* MBEDTLS_CHECK_CONFIG_H */
@@ -0,0 +1,96 @@
/**
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#ifndef MBEDTLS_CONFIG_H
#define MBEDTLS_CONFIG_H
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
#define _CRT_SECURE_NO_DEPRECATE 1
#endif
//#define MBEDTLS_PLATFORM_MEMORY
#define MBEDTLS_FS_IO
//#define MBEDTLS_VERSION_FEATURES
#define MBEDTLS_ASN1_PARSE_C
#define MBEDTLS_BASE64_C
#define MBEDTLS_BIGNUM_C
#define MBEDTLS_MD_C
#define MBEDTLS_OID_C
#define MBEDTLS_PEM_PARSE_C
/**
* \def MBEDTLS_PLATFORM_C
*
* Enable the platform abstraction layer that allows you to re-assign
* functions like calloc(), free(), snprintf(), printf(), fprintf(), exit().
*
* Enabling MBEDTLS_PLATFORM_C enables to use of MBEDTLS_PLATFORM_XXX_ALT
* or MBEDTLS_PLATFORM_XXX_MACRO directives, allowing the functions mentioned
* above to be specified at runtime or compile time respectively.
*
* \note This abstraction layer must be enabled on Windows (including MSYS2)
* as other module rely on it for a fixed snprintf implementation.
*
* Module: library/platform.c
* Caller: Most other .c files
*
* This module enables abstraction of common (libc) functions.
*/
#define MBEDTLS_PLATFORM_C
/**
* \def MBEDTLS_TIMING_C
*
* Enable the semi-portable timing interface.
*
* \note The provided implementation only works on POSIX/Unix (including Linux,
* BSD and OS X) and Windows. On other platforms, you can either disable that
* module and provide your own implementations of the callbacks needed by
* \c mbedtls_ssl_set_timer_cb() for DTLS, or leave it enabled and provide
* your own implementation of the whole module by setting
* \c MBEDTLS_TIMING_ALT in the current file.
*
* \note See also our Knowledge Base article about porting to a new
* environment:
* https://tls.mbed.org/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS
*
* Module: library/timing.c
* Caller: library/havege.c
*
* This module is used by the HAVEGE random number generator.
*/
#define MBEDTLS_TIMING_C
//#define MBEDTLS_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */
//#define MBEDTLS_MPI_MAX_SIZE 1024 /**< Maximum number of bytes for usable MPIs. */
//#define MBEDTLS_MEMORY_ALIGN_MULTIPLE 4 /**< Align on multiples of this value */
#if defined(TARGET_LIKE_MBED) && defined(YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE)
#include YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE
#endif
#if defined(YOTTA_CFG_MBEDTLS_USER_CONFIG_FILE)
#include YOTTA_CFG_MBEDTLS_USER_CONFIG_FILE
#elif defined(MBEDTLS_USER_CONFIG_FILE)
#include MBEDTLS_USER_CONFIG_FILE
#endif
#include "check_config.h"
#endif /* MBEDTLS_CONFIG_H */
@@ -0,0 +1,466 @@
/**
* \file ecdsa.h
*
* \brief This file contains ECDSA definitions and functions.
*
* The Elliptic Curve Digital Signature Algorithm (ECDSA) is defined in
* <em>Standards for Efficient Cryptography Group (SECG):
* SEC1 Elliptic Curve Cryptography</em>.
* The use of ECDSA for TLS is defined in <em>RFC-4492: Elliptic Curve
* Cryptography (ECC) Cipher Suites for Transport Layer Security (TLS)</em>.
*
*/
/*
* Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
* This file is part of Mbed TLS (https://tls.mbed.org)
*/
#ifndef MBEDTLS_ECDSA_H
#define MBEDTLS_ECDSA_H
#include "ecp.h"
#include "md.h"
/*
* RFC-4492 page 20:
*
* Ecdsa-Sig-Value ::= SEQUENCE {
* r INTEGER,
* s INTEGER
* }
*
* Size is at most
* 1 (tag) + 1 (len) + 1 (initial 0) + ECP_MAX_BYTES for each of r and s,
* twice that + 1 (tag) + 2 (len) for the sequence
* (assuming ECP_MAX_BYTES is less than 126 for r and s,
* and less than 124 (total len <= 255) for the sequence)
*/
#if MBEDTLS_ECP_MAX_BYTES > 124
#error "MBEDTLS_ECP_MAX_BYTES bigger than expected, please fix MBEDTLS_ECDSA_MAX_LEN"
#endif
/** The maximal size of an ECDSA signature in Bytes. */
#define MBEDTLS_ECDSA_MAX_LEN ( 3 + 2 * ( 3 + MBEDTLS_ECP_MAX_BYTES ) )
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief The ECDSA context structure.
*
* \warning Performing multiple operations concurrently on the same
* ECDSA context is not supported; objects of this type
* should not be shared between multiple threads.
*/
typedef mbedtls_ecp_keypair mbedtls_ecdsa_context;
#if defined(MBEDTLS_ECP_RESTARTABLE)
/**
* \brief Internal restart context for ecdsa_verify()
*
* \note Opaque struct, defined in ecdsa.c
*/
typedef struct mbedtls_ecdsa_restart_ver mbedtls_ecdsa_restart_ver_ctx;
/**
* \brief Internal restart context for ecdsa_sign()
*
* \note Opaque struct, defined in ecdsa.c
*/
typedef struct mbedtls_ecdsa_restart_sig mbedtls_ecdsa_restart_sig_ctx;
#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
/**
* \brief Internal restart context for ecdsa_sign_det()
*
* \note Opaque struct, defined in ecdsa.c
*/
typedef struct mbedtls_ecdsa_restart_det mbedtls_ecdsa_restart_det_ctx;
#endif
/**
* \brief General context for resuming ECDSA operations
*/
typedef struct
{
mbedtls_ecp_restart_ctx ecp; /*!< base context for ECP restart and
shared administrative info */
mbedtls_ecdsa_restart_ver_ctx *ver; /*!< ecdsa_verify() sub-context */
mbedtls_ecdsa_restart_sig_ctx *sig; /*!< ecdsa_sign() sub-context */
#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
mbedtls_ecdsa_restart_det_ctx *det; /*!< ecdsa_sign_det() sub-context */
#endif
} mbedtls_ecdsa_restart_ctx;
#else /* MBEDTLS_ECP_RESTARTABLE */
/* Now we can declare functions that take a pointer to that */
typedef void mbedtls_ecdsa_restart_ctx;
#endif /* MBEDTLS_ECP_RESTARTABLE */
/**
* \brief This function computes the ECDSA signature of a
* previously-hashed message.
*
* \note The deterministic version is usually preferred.
*
* \note If the bitlength of the message hash is larger than the
* bitlength of the group order, then the hash is truncated
* as defined in <em>Standards for Efficient Cryptography Group
* (SECG): SEC1 Elliptic Curve Cryptography</em>, section
* 4.1.3, step 5.
*
* \see ecp.h
*
* \param grp The ECP group.
* \param r The first output integer.
* \param s The second output integer.
* \param d The private signing key.
* \param buf The message hash.
* \param blen The length of \p buf.
* \param f_rng The RNG function.
* \param p_rng The RNG context.
*
* \return \c 0 on success.
* \return An \c MBEDTLS_ERR_ECP_XXX
* or \c MBEDTLS_MPI_XXX error code on failure.
*/
int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
const mbedtls_mpi *d, const unsigned char *buf, size_t blen,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng );
#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
/**
* \brief This function computes the ECDSA signature of a
* previously-hashed message, deterministic version.
*
* For more information, see <em>RFC-6979: Deterministic
* Usage of the Digital Signature Algorithm (DSA) and Elliptic
* Curve Digital Signature Algorithm (ECDSA)</em>.
*
* \note If the bitlength of the message hash is larger than the
* bitlength of the group order, then the hash is truncated as
* defined in <em>Standards for Efficient Cryptography Group
* (SECG): SEC1 Elliptic Curve Cryptography</em>, section
* 4.1.3, step 5.
*
* \see ecp.h
*
* \param grp The ECP group.
* \param r The first output integer.
* \param s The second output integer.
* \param d The private signing key.
* \param buf The message hash.
* \param blen The length of \p buf.
* \param md_alg The MD algorithm used to hash the message.
*
* \return \c 0 on success.
* \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX
* error code on failure.
*/
int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
const mbedtls_mpi *d, const unsigned char *buf, size_t blen,
mbedtls_md_type_t md_alg );
#endif /* MBEDTLS_ECDSA_DETERMINISTIC */
/**
* \brief This function verifies the ECDSA signature of a
* previously-hashed message.
*
* \note If the bitlength of the message hash is larger than the
* bitlength of the group order, then the hash is truncated as
* defined in <em>Standards for Efficient Cryptography Group
* (SECG): SEC1 Elliptic Curve Cryptography</em>, section
* 4.1.4, step 3.
*
* \see ecp.h
*
* \param grp The ECP group.
* \param buf The message hash.
* \param blen The length of \p buf.
* \param Q The public key to use for verification.
* \param r The first integer of the signature.
* \param s The second integer of the signature.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if the signature
* is invalid.
* \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX
* error code on failure for any other reason.
*/
int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp,
const unsigned char *buf, size_t blen,
const mbedtls_ecp_point *Q, const mbedtls_mpi *r, const mbedtls_mpi *s);
/**
* \brief This function computes the ECDSA signature and writes it
* to a buffer, serialized as defined in <em>RFC-4492:
* Elliptic Curve Cryptography (ECC) Cipher Suites for
* Transport Layer Security (TLS)</em>.
*
* \warning It is not thread-safe to use the same context in
* multiple threads.
*
* \note The deterministic version is used if
* #MBEDTLS_ECDSA_DETERMINISTIC is defined. For more
* information, see <em>RFC-6979: Deterministic Usage
* of the Digital Signature Algorithm (DSA) and Elliptic
* Curve Digital Signature Algorithm (ECDSA)</em>.
*
* \note The \p sig buffer must be at least twice as large as the
* size of the curve used, plus 9. For example, 73 Bytes if
* a 256-bit curve is used. A buffer length of
* #MBEDTLS_ECDSA_MAX_LEN is always safe.
*
* \note If the bitlength of the message hash is larger than the
* bitlength of the group order, then the hash is truncated as
* defined in <em>Standards for Efficient Cryptography Group
* (SECG): SEC1 Elliptic Curve Cryptography</em>, section
* 4.1.3, step 5.
*
* \see ecp.h
*
* \param ctx The ECDSA context.
* \param md_alg The message digest that was used to hash the message.
* \param hash The message hash.
* \param hlen The length of the hash.
* \param sig The buffer that holds the signature.
* \param slen The length of the signature written.
* \param f_rng The RNG function.
* \param p_rng The RNG context.
*
* \return \c 0 on success.
* \return An \c MBEDTLS_ERR_ECP_XXX, \c MBEDTLS_ERR_MPI_XXX or
* \c MBEDTLS_ERR_ASN1_XXX error code on failure.
*/
int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t md_alg,
const unsigned char *hash, size_t hlen,
unsigned char *sig, size_t *slen,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng );
/**
* \brief This function computes the ECDSA signature and writes it
* to a buffer, in a restartable way.
*
* \see \c mbedtls_ecdsa_write_signature()
*
* \note This function is like \c mbedtls_ecdsa_write_signature()
* but it can return early and restart according to the limit
* set with \c mbedtls_ecp_set_max_ops() to reduce blocking.
*
* \param ctx The ECDSA context.
* \param md_alg The message digest that was used to hash the message.
* \param hash The message hash.
* \param hlen The length of the hash.
* \param sig The buffer that holds the signature.
* \param slen The length of the signature written.
* \param f_rng The RNG function.
* \param p_rng The RNG context.
* \param rs_ctx The restart context (NULL disables restart).
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of
* operations was reached: see \c mbedtls_ecp_set_max_ops().
* \return Another \c MBEDTLS_ERR_ECP_XXX, \c MBEDTLS_ERR_MPI_XXX or
* \c MBEDTLS_ERR_ASN1_XXX error code on failure.
*/
int mbedtls_ecdsa_write_signature_restartable( mbedtls_ecdsa_context *ctx,
mbedtls_md_type_t md_alg,
const unsigned char *hash, size_t hlen,
unsigned char *sig, size_t *slen,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
mbedtls_ecdsa_restart_ctx *rs_ctx );
#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
#if ! defined(MBEDTLS_DEPRECATED_REMOVED)
#if defined(MBEDTLS_DEPRECATED_WARNING)
#define MBEDTLS_DEPRECATED __attribute__((deprecated))
#else
#define MBEDTLS_DEPRECATED
#endif
/**
* \brief This function computes an ECDSA signature and writes
* it to a buffer, serialized as defined in <em>RFC-4492:
* Elliptic Curve Cryptography (ECC) Cipher Suites for
* Transport Layer Security (TLS)</em>.
*
* The deterministic version is defined in <em>RFC-6979:
* Deterministic Usage of the Digital Signature Algorithm (DSA)
* and Elliptic Curve Digital Signature Algorithm (ECDSA)</em>.
*
* \warning It is not thread-safe to use the same context in
* multiple threads.
*
* \note The \p sig buffer must be at least twice as large as the
* size of the curve used, plus 9. For example, 73 Bytes if a
* 256-bit curve is used. A buffer length of
* #MBEDTLS_ECDSA_MAX_LEN is always safe.
*
* \note If the bitlength of the message hash is larger than the
* bitlength of the group order, then the hash is truncated as
* defined in <em>Standards for Efficient Cryptography Group
* (SECG): SEC1 Elliptic Curve Cryptography</em>, section
* 4.1.3, step 5.
*
* \see ecp.h
*
* \deprecated Superseded by mbedtls_ecdsa_write_signature() in
* Mbed TLS version 2.0 and later.
*
* \param ctx The ECDSA context.
* \param hash The message hash.
* \param hlen The length of the hash.
* \param sig The buffer that holds the signature.
* \param slen The length of the signature written.
* \param md_alg The MD algorithm used to hash the message.
*
* \return \c 0 on success.
* \return An \c MBEDTLS_ERR_ECP_XXX, \c MBEDTLS_ERR_MPI_XXX or
* \c MBEDTLS_ERR_ASN1_XXX error code on failure.
*/
int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx,
const unsigned char *hash, size_t hlen,
unsigned char *sig, size_t *slen,
mbedtls_md_type_t md_alg ) MBEDTLS_DEPRECATED;
#undef MBEDTLS_DEPRECATED
#endif /* MBEDTLS_DEPRECATED_REMOVED */
#endif /* MBEDTLS_ECDSA_DETERMINISTIC */
/**
* \brief This function reads and verifies an ECDSA signature.
*
* \note If the bitlength of the message hash is larger than the
* bitlength of the group order, then the hash is truncated as
* defined in <em>Standards for Efficient Cryptography Group
* (SECG): SEC1 Elliptic Curve Cryptography</em>, section
* 4.1.4, step 3.
*
* \see ecp.h
*
* \param ctx The ECDSA context.
* \param hash The message hash.
* \param hlen The size of the hash.
* \param sig The signature to read and verify.
* \param slen The size of \p sig.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if signature is invalid.
* \return #MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH if there is a valid
* signature in \p sig, but its length is less than \p siglen.
* \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_ERR_MPI_XXX
* error code on failure for any other reason.
*/
int mbedtls_ecdsa_read_signature( mbedtls_ecdsa_context *ctx,
const unsigned char *hash, size_t hlen,
const unsigned char *sig, size_t slen );
/**
* \brief This function reads and verifies an ECDSA signature,
* in a restartable way.
*
* \see \c mbedtls_ecdsa_read_signature()
*
* \note This function is like \c mbedtls_ecdsa_read_signature()
* but it can return early and restart according to the limit
* set with \c mbedtls_ecp_set_max_ops() to reduce blocking.
*
* \param ctx The ECDSA context.
* \param hash The message hash.
* \param hlen The size of the hash.
* \param sig The signature to read and verify.
* \param slen The size of \p sig.
* \param rs_ctx The restart context (NULL disables restart).
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if signature is invalid.
* \return #MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH if there is a valid
* signature in \p sig, but its length is less than \p siglen.
* \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of
* operations was reached: see \c mbedtls_ecp_set_max_ops().
* \return Another \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_ERR_MPI_XXX
* error code on failure for any other reason.
*/
int mbedtls_ecdsa_read_signature_restartable( mbedtls_ecdsa_context *ctx,
const unsigned char *hash, size_t hlen,
const unsigned char *sig, size_t slen,
mbedtls_ecdsa_restart_ctx *rs_ctx );
/**
* \brief This function generates an ECDSA keypair on the given curve.
*
* \see ecp.h
*
* \param ctx The ECDSA context to store the keypair in.
* \param gid The elliptic curve to use. One of the various
* \c MBEDTLS_ECP_DP_XXX macros depending on configuration.
* \param f_rng The RNG function.
* \param p_rng The RNG context.
*
* \return \c 0 on success.
* \return An \c MBEDTLS_ERR_ECP_XXX code on failure.
*/
int mbedtls_ecdsa_genkey( mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id gid,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng );
/**
* \brief This function sets an ECDSA context from an EC key pair.
*
* \see ecp.h
*
* \param ctx The ECDSA context to set.
* \param key The EC key to use.
*
* \return \c 0 on success.
* \return An \c MBEDTLS_ERR_ECP_XXX code on failure.
*/
int mbedtls_ecdsa_from_keypair( mbedtls_ecdsa_context *ctx, const mbedtls_ecp_keypair *key );
/**
* \brief This function initializes an ECDSA context.
*
* \param ctx The ECDSA context to initialize.
*/
void mbedtls_ecdsa_init( mbedtls_ecdsa_context *ctx );
/**
* \brief This function frees an ECDSA context.
*
* \param ctx The ECDSA context to free.
*/
void mbedtls_ecdsa_free( mbedtls_ecdsa_context *ctx );
#if defined(MBEDTLS_ECP_RESTARTABLE)
/**
* \brief Initialize a restart context
*/
void mbedtls_ecdsa_restart_init( mbedtls_ecdsa_restart_ctx *ctx );
/**
* \brief Free the components of a restart context
*/
void mbedtls_ecdsa_restart_free( mbedtls_ecdsa_restart_ctx *ctx );
#endif /* MBEDTLS_ECP_RESTARTABLE */
#ifdef __cplusplus
}
#endif
#endif /* ecdsa.h */
@@ -0,0 +1,993 @@
/**
* \file ecp.h
*
* \brief This file provides an API for Elliptic Curves over GF(P) (ECP).
*
* The use of ECP in cryptography and TLS is defined in
* <em>Standards for Efficient Cryptography Group (SECG): SEC1
* Elliptic Curve Cryptography</em> and
* <em>RFC-4492: Elliptic Curve Cryptography (ECC) Cipher Suites
* for Transport Layer Security (TLS)</em>.
*
* <em>RFC-2409: The Internet Key Exchange (IKE)</em> defines ECP
* group types.
*
*/
/*
* Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
* This file is part of Mbed TLS (https://tls.mbed.org)
*/
#ifndef MBEDTLS_ECP_H
#define MBEDTLS_ECP_H
#include "bignum.h"
/*
* ECP error codes
*/
#define MBEDTLS_ERR_ECP_BAD_INPUT_DATA -0x4F80 /**< Bad input parameters to function. */
#define MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL -0x4F00 /**< The buffer is too small to write to. */
#define MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE -0x4E80 /**< The requested feature is not available, for example, the requested curve is not supported. */
#define MBEDTLS_ERR_ECP_VERIFY_FAILED -0x4E00 /**< The signature is not valid. */
#define MBEDTLS_ERR_ECP_ALLOC_FAILED -0x4D80 /**< Memory allocation failed. */
#define MBEDTLS_ERR_ECP_RANDOM_FAILED -0x4D00 /**< Generation of random value, such as ephemeral key, failed. */
#define MBEDTLS_ERR_ECP_INVALID_KEY -0x4C80 /**< Invalid private or public key. */
#define MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH -0x4C00 /**< The buffer contains a valid signature followed by more data. */
/* MBEDTLS_ERR_ECP_HW_ACCEL_FAILED is deprecated and should not be used. */
#define MBEDTLS_ERR_ECP_HW_ACCEL_FAILED -0x4B80 /**< The ECP hardware accelerator failed. */
#define MBEDTLS_ERR_ECP_IN_PROGRESS -0x4B00 /**< Operation in progress, call again with the same parameters to continue. */
#ifdef __cplusplus
extern "C" {
#endif
/**
* Domain-parameter identifiers: curve, subgroup, and generator.
*
* \note Only curves over prime fields are supported.
*
* \warning This library does not support validation of arbitrary domain
* parameters. Therefore, only standardized domain parameters from trusted
* sources should be used. See mbedtls_ecp_group_load().
*/
typedef enum
{
MBEDTLS_ECP_DP_NONE = 0, /*!< Curve not defined. */
MBEDTLS_ECP_DP_SECP192R1, /*!< Domain parameters for the 192-bit curve defined by FIPS 186-4 and SEC1. */
MBEDTLS_ECP_DP_SECP224R1, /*!< Domain parameters for the 224-bit curve defined by FIPS 186-4 and SEC1. */
MBEDTLS_ECP_DP_SECP256R1, /*!< Domain parameters for the 256-bit curve defined by FIPS 186-4 and SEC1. */
MBEDTLS_ECP_DP_SECP384R1, /*!< Domain parameters for the 384-bit curve defined by FIPS 186-4 and SEC1. */
MBEDTLS_ECP_DP_SECP521R1, /*!< Domain parameters for the 521-bit curve defined by FIPS 186-4 and SEC1. */
MBEDTLS_ECP_DP_BP256R1, /*!< Domain parameters for 256-bit Brainpool curve. */
MBEDTLS_ECP_DP_BP384R1, /*!< Domain parameters for 384-bit Brainpool curve. */
MBEDTLS_ECP_DP_BP512R1, /*!< Domain parameters for 512-bit Brainpool curve. */
MBEDTLS_ECP_DP_CURVE25519, /*!< Domain parameters for Curve25519. */
MBEDTLS_ECP_DP_SECP192K1, /*!< Domain parameters for 192-bit "Koblitz" curve. */
MBEDTLS_ECP_DP_SECP224K1, /*!< Domain parameters for 224-bit "Koblitz" curve. */
MBEDTLS_ECP_DP_SECP256K1, /*!< Domain parameters for 256-bit "Koblitz" curve. */
MBEDTLS_ECP_DP_CURVE448, /*!< Domain parameters for Curve448. */
} mbedtls_ecp_group_id;
/**
* The number of supported curves, plus one for #MBEDTLS_ECP_DP_NONE.
*
* \note Montgomery curves are currently excluded.
*/
#define MBEDTLS_ECP_DP_MAX 12
/**
* Curve information, for use by other modules.
*/
typedef struct mbedtls_ecp_curve_info
{
mbedtls_ecp_group_id grp_id; /*!< An internal identifier. */
uint16_t tls_id; /*!< The TLS NamedCurve identifier. */
uint16_t bit_size; /*!< The curve size in bits. */
const char *name; /*!< A human-friendly name. */
} mbedtls_ecp_curve_info;
/**
* \brief The ECP point structure, in Jacobian coordinates.
*
* \note All functions expect and return points satisfying
* the following condition: <code>Z == 0</code> or
* <code>Z == 1</code>. Other values of \p Z are
* used only by internal functions.
* The point is zero, or "at infinity", if <code>Z == 0</code>.
* Otherwise, \p X and \p Y are its standard (affine)
* coordinates.
*/
typedef struct mbedtls_ecp_point
{
mbedtls_mpi X; /*!< The X coordinate of the ECP point. */
mbedtls_mpi Y; /*!< The Y coordinate of the ECP point. */
mbedtls_mpi Z; /*!< The Z coordinate of the ECP point. */
}
mbedtls_ecp_point;
#if !defined(MBEDTLS_ECP_ALT)
/*
* default mbed TLS elliptic curve arithmetic implementation
*
* (in case MBEDTLS_ECP_ALT is defined then the developer has to provide an
* alternative implementation for the whole module and it will replace this
* one.)
*/
/**
* \brief The ECP group structure.
*
* We consider two types of curve equations:
* <ul><li>Short Weierstrass: <code>y^2 = x^3 + A x + B mod P</code>
* (SEC1 + RFC-4492)</li>
* <li>Montgomery: <code>y^2 = x^3 + A x^2 + x mod P</code> (Curve25519,
* Curve448)</li></ul>
* In both cases, the generator (\p G) for a prime-order subgroup is fixed.
*
* For Short Weierstrass, this subgroup is the whole curve, and its
* cardinality is denoted by \p N. Our code requires that \p N is an
* odd prime as mbedtls_ecp_mul() requires an odd number, and
* mbedtls_ecdsa_sign() requires that it is prime for blinding purposes.
*
* For Montgomery curves, we do not store \p A, but <code>(A + 2) / 4</code>,
* which is the quantity used in the formulas. Additionally, \p nbits is
* not the size of \p N but the required size for private keys.
*
* If \p modp is NULL, reduction modulo \p P is done using a generic algorithm.
* Otherwise, \p modp must point to a function that takes an \p mbedtls_mpi in the
* range of <code>0..2^(2*pbits)-1</code>, and transforms it in-place to an integer
* which is congruent mod \p P to the given MPI, and is close enough to \p pbits
* in size, so that it may be efficiently brought in the 0..P-1 range by a few
* additions or subtractions. Therefore, it is only an approximative modular
* reduction. It must return 0 on success and non-zero on failure.
*
*/
typedef struct mbedtls_ecp_group
{
mbedtls_ecp_group_id id; /*!< An internal group identifier. */
mbedtls_mpi P; /*!< The prime modulus of the base field. */
mbedtls_mpi A; /*!< For Short Weierstrass: \p A in the equation. For
Montgomery curves: <code>(A + 2) / 4</code>. */
mbedtls_mpi B; /*!< For Short Weierstrass: \p B in the equation.
For Montgomery curves: unused. */
mbedtls_ecp_point G; /*!< The generator of the subgroup used. */
mbedtls_mpi N; /*!< The order of \p G. */
size_t pbits; /*!< The number of bits in \p P.*/
size_t nbits; /*!< For Short Weierstrass: The number of bits in \p P.
For Montgomery curves: the number of bits in the
private keys. */
unsigned int h; /*!< \internal 1 if the constants are static. */
int (*modp)(mbedtls_mpi *); /*!< The function for fast pseudo-reduction
mod \p P (see above).*/
int (*t_pre)(mbedtls_ecp_point *, void *); /*!< Unused. */
int (*t_post)(mbedtls_ecp_point *, void *); /*!< Unused. */
void *t_data; /*!< Unused. */
mbedtls_ecp_point *T; /*!< Pre-computed points for ecp_mul_comb(). */
size_t T_size; /*!< The number of pre-computed points. */
}
mbedtls_ecp_group;
#if defined(MBEDTLS_ECP_RESTARTABLE)
/**
* \brief Internal restart context for multiplication
*
* \note Opaque struct
*/
typedef struct mbedtls_ecp_restart_mul mbedtls_ecp_restart_mul_ctx;
/**
* \brief Internal restart context for ecp_muladd()
*
* \note Opaque struct
*/
typedef struct mbedtls_ecp_restart_muladd mbedtls_ecp_restart_muladd_ctx;
/**
* \brief General context for resuming ECC operations
*/
typedef struct
{
unsigned ops_done; /*!< current ops count */
unsigned depth; /*!< call depth (0 = top-level) */
mbedtls_ecp_restart_mul_ctx *rsm; /*!< ecp_mul_comb() sub-context */
mbedtls_ecp_restart_muladd_ctx *ma; /*!< ecp_muladd() sub-context */
} mbedtls_ecp_restart_ctx;
/*
* Operation counts for restartable functions
*/
#define MBEDTLS_ECP_OPS_CHK 3 /*!< basic ops count for ecp_check_pubkey() */
#define MBEDTLS_ECP_OPS_DBL 8 /*!< basic ops count for ecp_double_jac() */
#define MBEDTLS_ECP_OPS_ADD 11 /*!< basic ops count for see ecp_add_mixed() */
#define MBEDTLS_ECP_OPS_INV 120 /*!< empirical equivalent for mpi_mod_inv() */
/**
* \brief Internal; for restartable functions in other modules.
* Check and update basic ops budget.
*
* \param grp Group structure
* \param rs_ctx Restart context
* \param ops Number of basic ops to do
*
* \return \c 0 if doing \p ops basic ops is still allowed,
* \return #MBEDTLS_ERR_ECP_IN_PROGRESS otherwise.
*/
int mbedtls_ecp_check_budget( const mbedtls_ecp_group *grp,
mbedtls_ecp_restart_ctx *rs_ctx,
unsigned ops );
/* Utility macro for checking and updating ops budget */
#define MBEDTLS_ECP_BUDGET( ops ) \
MBEDTLS_MPI_CHK( mbedtls_ecp_check_budget( grp, rs_ctx, \
(unsigned) (ops) ) );
#else /* MBEDTLS_ECP_RESTARTABLE */
#define MBEDTLS_ECP_BUDGET( ops ) /* no-op; for compatibility */
/* We want to declare restartable versions of existing functions anyway */
typedef void mbedtls_ecp_restart_ctx;
#endif /* MBEDTLS_ECP_RESTARTABLE */
/**
* \name SECTION: Module settings
*
* The configuration options you can set for this module are in this section.
* Either change them in config.h, or define them using the compiler command line.
* \{
*/
#if !defined(MBEDTLS_ECP_MAX_BITS)
/**
* The maximum size of the groups, that is, of \c N and \c P.
*/
#define MBEDTLS_ECP_MAX_BITS 521 /**< The maximum size of groups, in bits. */
#endif
#define MBEDTLS_ECP_MAX_BYTES ( ( MBEDTLS_ECP_MAX_BITS + 7 ) / 8 )
#define MBEDTLS_ECP_MAX_PT_LEN ( 2 * MBEDTLS_ECP_MAX_BYTES + 1 )
#if !defined(MBEDTLS_ECP_WINDOW_SIZE)
/*
* Maximum "window" size used for point multiplication.
* Default: 6.
* Minimum value: 2. Maximum value: 7.
*
* Result is an array of at most ( 1 << ( MBEDTLS_ECP_WINDOW_SIZE - 1 ) )
* points used for point multiplication. This value is directly tied to EC
* peak memory usage, so decreasing it by one should roughly cut memory usage
* by two (if large curves are in use).
*
* Reduction in size may reduce speed, but larger curves are impacted first.
* Sample performances (in ECDHE handshakes/s, with FIXED_POINT_OPTIM = 1):
* w-size: 6 5 4 3 2
* 521 145 141 135 120 97
* 384 214 209 198 177 146
* 256 320 320 303 262 226
* 224 475 475 453 398 342
* 192 640 640 633 587 476
*/
#define MBEDTLS_ECP_WINDOW_SIZE 6 /**< The maximum window size used. */
#endif /* MBEDTLS_ECP_WINDOW_SIZE */
#if !defined(MBEDTLS_ECP_FIXED_POINT_OPTIM)
/*
* Trade memory for speed on fixed-point multiplication.
*
* This speeds up repeated multiplication of the generator (that is, the
* multiplication in ECDSA signatures, and half of the multiplications in
* ECDSA verification and ECDHE) by a factor roughly 3 to 4.
*
* The cost is increasing EC peak memory usage by a factor roughly 2.
*
* Change this value to 0 to reduce peak memory usage.
*/
#define MBEDTLS_ECP_FIXED_POINT_OPTIM 1 /**< Enable fixed-point speed-up. */
#endif /* MBEDTLS_ECP_FIXED_POINT_OPTIM */
/* \} name SECTION: Module settings */
#else /* MBEDTLS_ECP_ALT */
#include "ecp_alt.h"
#endif /* MBEDTLS_ECP_ALT */
/**
* \brief The ECP key-pair structure.
*
* A generic key-pair that may be used for ECDSA and fixed ECDH, for example.
*
* \note Members are deliberately in the same order as in the
* ::mbedtls_ecdsa_context structure.
*/
typedef struct mbedtls_ecp_keypair
{
mbedtls_ecp_group grp; /*!< Elliptic curve and base point */
mbedtls_mpi d; /*!< our secret value */
mbedtls_ecp_point Q; /*!< our public value */
}
mbedtls_ecp_keypair;
/*
* Point formats, from RFC 4492's enum ECPointFormat
*/
#define MBEDTLS_ECP_PF_UNCOMPRESSED 0 /**< Uncompressed point format. */
#define MBEDTLS_ECP_PF_COMPRESSED 1 /**< Compressed point format. */
/*
* Some other constants from RFC 4492
*/
#define MBEDTLS_ECP_TLS_NAMED_CURVE 3 /**< The named_curve of ECCurveType. */
#if defined(MBEDTLS_ECP_RESTARTABLE)
/**
* \brief Set the maximum number of basic operations done in a row.
*
* If more operations are needed to complete a computation,
* #MBEDTLS_ERR_ECP_IN_PROGRESS will be returned by the
* function performing the computation. It is then the
* caller's responsibility to either call again with the same
* parameters until it returns 0 or an error code; or to free
* the restart context if the operation is to be aborted.
*
* It is strictly required that all input parameters and the
* restart context be the same on successive calls for the
* same operation, but output parameters need not be the
* same; they must not be used until the function finally
* returns 0.
*
* This only applies to functions whose documentation
* mentions they may return #MBEDTLS_ERR_ECP_IN_PROGRESS (or
* #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS for functions in the
* SSL module). For functions that accept a "restart context"
* argument, passing NULL disables restart and makes the
* function equivalent to the function with the same name
* with \c _restartable removed. For functions in the ECDH
* module, restart is disabled unless the function accepts
* an "ECDH context" argument and
* mbedtls_ecdh_enable_restart() was previously called on
* that context. For function in the SSL module, restart is
* only enabled for specific sides and key exchanges
* (currently only for clients and ECDHE-ECDSA).
*
* \param max_ops Maximum number of basic operations done in a row.
* Default: 0 (unlimited).
* Lower (non-zero) values mean ECC functions will block for
* a lesser maximum amount of time.
*
* \note A "basic operation" is defined as a rough equivalent of a
* multiplication in GF(p) for the NIST P-256 curve.
* As an indication, with default settings, a scalar
* multiplication (full run of \c mbedtls_ecp_mul()) is:
* - about 3300 basic operations for P-256
* - about 9400 basic operations for P-384
*
* \note Very low values are not always respected: sometimes
* functions need to block for a minimum number of
* operations, and will do so even if max_ops is set to a
* lower value. That minimum depends on the curve size, and
* can be made lower by decreasing the value of
* \c MBEDTLS_ECP_WINDOW_SIZE. As an indication, here is the
* lowest effective value for various curves and values of
* that parameter (w for short):
* w=6 w=5 w=4 w=3 w=2
* P-256 208 208 160 136 124
* P-384 682 416 320 272 248
* P-521 1364 832 640 544 496
*
* \note This setting is currently ignored by Curve25519.
*/
void mbedtls_ecp_set_max_ops( unsigned max_ops );
/**
* \brief Check if restart is enabled (max_ops != 0)
*
* \return \c 0 if \c max_ops == 0 (restart disabled)
* \return \c 1 otherwise (restart enabled)
*/
int mbedtls_ecp_restart_is_enabled( void );
#endif /* MBEDTLS_ECP_RESTARTABLE */
/**
* \brief This function retrieves the information defined in
* mbedtls_ecp_curve_info() for all supported curves in order
* of preference.
*
* \return A statically allocated array. The last entry is 0.
*/
const mbedtls_ecp_curve_info *mbedtls_ecp_curve_list( void );
/**
* \brief This function retrieves the list of internal group
* identifiers of all supported curves in the order of
* preference.
*
* \return A statically allocated array,
* terminated with MBEDTLS_ECP_DP_NONE.
*/
const mbedtls_ecp_group_id *mbedtls_ecp_grp_id_list( void );
/**
* \brief This function retrieves curve information from an internal
* group identifier.
*
* \param grp_id An \c MBEDTLS_ECP_DP_XXX value.
*
* \return The associated curve information on success.
* \return NULL on failure.
*/
const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_grp_id( mbedtls_ecp_group_id grp_id );
/**
* \brief This function retrieves curve information from a TLS
* NamedCurve value.
*
* \param tls_id An \c MBEDTLS_ECP_DP_XXX value.
*
* \return The associated curve information on success.
* \return NULL on failure.
*/
const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_tls_id( uint16_t tls_id );
/**
* \brief This function retrieves curve information from a
* human-readable name.
*
* \param name The human-readable name.
*
* \return The associated curve information on success.
* \return NULL on failure.
*/
const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_name( const char *name );
/**
* \brief This function initializes a point as zero.
*
* \param pt The point to initialize.
*/
void mbedtls_ecp_point_init( mbedtls_ecp_point *pt );
/**
* \brief This function initializes an ECP group context
* without loading any domain parameters.
*
* \note After this function is called, domain parameters
* for various ECP groups can be loaded through the
* mbedtls_ecp_load() or mbedtls_ecp_tls_read_group()
* functions.
*/
void mbedtls_ecp_group_init( mbedtls_ecp_group *grp );
/**
* \brief This function initializes a key pair as an invalid one.
*
* \param key The key pair to initialize.
*/
void mbedtls_ecp_keypair_init( mbedtls_ecp_keypair *key );
/**
* \brief This function frees the components of a point.
*
* \param pt The point to free.
*/
void mbedtls_ecp_point_free( mbedtls_ecp_point *pt );
/**
* \brief This function frees the components of an ECP group.
* \param grp The group to free.
*/
void mbedtls_ecp_group_free( mbedtls_ecp_group *grp );
/**
* \brief This function frees the components of a key pair.
* \param key The key pair to free.
*/
void mbedtls_ecp_keypair_free( mbedtls_ecp_keypair *key );
#if defined(MBEDTLS_ECP_RESTARTABLE)
/**
* \brief Initialize a restart context
*/
void mbedtls_ecp_restart_init( mbedtls_ecp_restart_ctx *ctx );
/**
* \brief Free the components of a restart context
*/
void mbedtls_ecp_restart_free( mbedtls_ecp_restart_ctx *ctx );
#endif /* MBEDTLS_ECP_RESTARTABLE */
/**
* \brief This function copies the contents of point \p Q into
* point \p P.
*
* \param P The destination point.
* \param Q The source point.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure.
*/
int mbedtls_ecp_copy( mbedtls_ecp_point *P, const mbedtls_ecp_point *Q );
/**
* \brief This function copies the contents of group \p src into
* group \p dst.
*
* \param dst The destination group.
* \param src The source group.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure.
*/
int mbedtls_ecp_group_copy( mbedtls_ecp_group *dst, const mbedtls_ecp_group *src );
/**
* \brief This function sets a point to zero.
*
* \param pt The point to set.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure.
*/
int mbedtls_ecp_set_zero( mbedtls_ecp_point *pt );
/**
* \brief This function checks if a point is zero.
*
* \param pt The point to test.
*
* \return \c 1 if the point is zero.
* \return \c 0 if the point is non-zero.
*/
int mbedtls_ecp_is_zero( mbedtls_ecp_point *pt );
/**
* \brief This function compares two points.
*
* \note This assumes that the points are normalized. Otherwise,
* they may compare as "not equal" even if they are.
*
* \param P The first point to compare.
* \param Q The second point to compare.
*
* \return \c 0 if the points are equal.
* \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if the points are not equal.
*/
int mbedtls_ecp_point_cmp( const mbedtls_ecp_point *P,
const mbedtls_ecp_point *Q );
/**
* \brief This function imports a non-zero point from two ASCII
* strings.
*
* \param P The destination point.
* \param radix The numeric base of the input.
* \param x The first affine coordinate, as a null-terminated string.
* \param y The second affine coordinate, as a null-terminated string.
*
* \return \c 0 on success.
* \return An \c MBEDTLS_ERR_MPI_XXX error code on failure.
*/
int mbedtls_ecp_point_read_string( mbedtls_ecp_point *P, int radix,
const char *x, const char *y );
/**
* \brief This function exports a point into unsigned binary data.
*
* \param grp The group to which the point should belong.
* \param P The point to export.
* \param format The point format. Should be an \c MBEDTLS_ECP_PF_XXX macro.
* \param olen The length of the output.
* \param buf The output buffer.
* \param buflen The length of the output buffer.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA
* or #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL on failure.
*/
int mbedtls_ecp_point_write_binary( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *P,
int format, size_t *olen,
unsigned char *buf, size_t buflen );
/**
* \brief This function imports a point from unsigned binary data.
*
* \note This function does not check that the point actually
* belongs to the given group, see mbedtls_ecp_check_pubkey()
* for that.
*
* \param grp The group to which the point should belong.
* \param P The point to import.
* \param buf The input buffer.
* \param ilen The length of the input.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid.
* \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure.
* \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the point format
* is not implemented.
*
*/
int mbedtls_ecp_point_read_binary( const mbedtls_ecp_group *grp, mbedtls_ecp_point *P,
const unsigned char *buf, size_t ilen );
/**
* \brief This function imports a point from a TLS ECPoint record.
*
* \note On function return, \p buf is updated to point to immediately
* after the ECPoint record.
*
* \param grp The ECP group used.
* \param pt The destination point.
* \param buf The address of the pointer to the start of the input buffer.
* \param len The length of the buffer.
*
* \return \c 0 on success.
* \return An \c MBEDTLS_ERR_MPI_XXX error code on initialization failure.
* \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid.
*/
int mbedtls_ecp_tls_read_point( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt,
const unsigned char **buf, size_t len );
/**
* \brief This function exports a point as a TLS ECPoint record.
*
* \param grp The ECP group used.
* \param pt The point format to export to. The point format is an
* \c MBEDTLS_ECP_PF_XXX constant.
* \param format The export format.
* \param olen The length of the data written.
* \param buf The buffer to write to.
* \param blen The length of the buffer.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA or
* #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL on failure.
*/
int mbedtls_ecp_tls_write_point( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt,
int format, size_t *olen,
unsigned char *buf, size_t blen );
/**
* \brief This function sets a group using standardized domain parameters.
*
* \note The index should be a value of the NamedCurve enum,
* as defined in <em>RFC-4492: Elliptic Curve Cryptography
* (ECC) Cipher Suites for Transport Layer Security (TLS)</em>,
* usually in the form of an \c MBEDTLS_ECP_DP_XXX macro.
*
* \param grp The destination group.
* \param id The identifier of the domain parameter set to load.
*
* \return \c 0 on success,
* \return An \c MBEDTLS_ERR_MPI_XXX error code on initialization failure.
* \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE for unkownn groups.
*/
int mbedtls_ecp_group_load( mbedtls_ecp_group *grp, mbedtls_ecp_group_id id );
/**
* \brief This function sets a group from a TLS ECParameters record.
*
* \note \p buf is updated to point right after the ECParameters record
* on exit.
*
* \param grp The destination group.
* \param buf The address of the pointer to the start of the input buffer.
* \param len The length of the buffer.
*
* \return \c 0 on success.
* \return An \c MBEDTLS_ERR_MPI_XXX error code on initialization failure.
* \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid.
*/
int mbedtls_ecp_tls_read_group( mbedtls_ecp_group *grp, const unsigned char **buf, size_t len );
/**
* \brief This function writes the TLS ECParameters record for a group.
*
* \param grp The ECP group used.
* \param olen The number of Bytes written.
* \param buf The buffer to write to.
* \param blen The length of the buffer.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL on failure.
*/
int mbedtls_ecp_tls_write_group( const mbedtls_ecp_group *grp, size_t *olen,
unsigned char *buf, size_t blen );
/**
* \brief This function performs multiplication of a point by
* an integer: \p R = \p m * \p P.
*
* It is not thread-safe to use same group in multiple threads.
*
* \note To prevent timing attacks, this function
* executes the exact same sequence of base-field
* operations for any valid \p m. It avoids any if-branch or
* array index depending on the value of \p m.
*
* \note If \p f_rng is not NULL, it is used to randomize
* intermediate results to prevent potential timing attacks
* targeting these results. We recommend always providing
* a non-NULL \p f_rng. The overhead is negligible.
*
* \param grp The ECP group.
* \param R The destination point.
* \param m The integer by which to multiply.
* \param P The point to multiply.
* \param f_rng The RNG function.
* \param p_rng The RNG context.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_ECP_INVALID_KEY if \p m is not a valid private
* key, or \p P is not a valid public key.
* \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure.
*/
int mbedtls_ecp_mul( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
const mbedtls_mpi *m, const mbedtls_ecp_point *P,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng );
/**
* \brief This function performs multiplication of a point by
* an integer: \p R = \p m * \p P in a restartable way.
*
* \see mbedtls_ecp_mul()
*
* \note This function does the same as \c mbedtls_ecp_mul(), but
* it can return early and restart according to the limit set
* with \c mbedtls_ecp_set_max_ops() to reduce blocking.
*
* \param grp The ECP group.
* \param R The destination point.
* \param m The integer by which to multiply.
* \param P The point to multiply.
* \param f_rng The RNG function.
* \param p_rng The RNG context.
* \param rs_ctx The restart context (NULL disables restart).
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_ECP_INVALID_KEY if \p m is not a valid private
* key, or \p P is not a valid public key.
* \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure.
* \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of
* operations was reached: see \c mbedtls_ecp_set_max_ops().
*/
int mbedtls_ecp_mul_restartable( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
const mbedtls_mpi *m, const mbedtls_ecp_point *P,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
mbedtls_ecp_restart_ctx *rs_ctx );
/**
* \brief This function performs multiplication and addition of two
* points by integers: \p R = \p m * \p P + \p n * \p Q
*
* It is not thread-safe to use same group in multiple threads.
*
* \note In contrast to mbedtls_ecp_mul(), this function does not
* guarantee a constant execution flow and timing.
*
* \param grp The ECP group.
* \param R The destination point.
* \param m The integer by which to multiply \p P.
* \param P The point to multiply by \p m.
* \param n The integer by which to multiply \p Q.
* \param Q The point to be multiplied by \p n.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_ECP_INVALID_KEY if \p m or \p n are not
* valid private keys, or \p P or \p Q are not valid public
* keys.
* \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure.
*/
int mbedtls_ecp_muladd( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
const mbedtls_mpi *m, const mbedtls_ecp_point *P,
const mbedtls_mpi *n, const mbedtls_ecp_point *Q );
/**
* \brief This function performs multiplication and addition of two
* points by integers: \p R = \p m * \p P + \p n * \p Q in a
* restartable way.
*
* \see \c mbedtls_ecp_muladd()
*
* \note This function works the same as \c mbedtls_ecp_muladd(),
* but it can return early and restart according to the limit
* set with \c mbedtls_ecp_set_max_ops() to reduce blocking.
*
* \param grp The ECP group.
* \param R The destination point.
* \param m The integer by which to multiply \p P.
* \param P The point to multiply by \p m.
* \param n The integer by which to multiply \p Q.
* \param Q The point to be multiplied by \p n.
* \param rs_ctx The restart context (NULL disables restart).
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_ECP_INVALID_KEY if \p m or \p n are not
* valid private keys, or \p P or \p Q are not valid public
* keys.
* \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure.
* \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of
* operations was reached: see \c mbedtls_ecp_set_max_ops().
*/
int mbedtls_ecp_muladd_restartable(
mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
const mbedtls_mpi *m, const mbedtls_ecp_point *P,
const mbedtls_mpi *n, const mbedtls_ecp_point *Q,
mbedtls_ecp_restart_ctx *rs_ctx );
/**
* \brief This function checks that a point is a valid public key
* on this curve.
*
* It only checks that the point is non-zero, has
* valid coordinates and lies on the curve. It does not verify
* that it is indeed a multiple of \p G. This additional
* check is computationally more expensive, is not required
* by standards, and should not be necessary if the group
* used has a small cofactor. In particular, it is useless for
* the NIST groups which all have a cofactor of 1.
*
* \note This function uses bare components rather than an
* ::mbedtls_ecp_keypair structure, to ease use with other
* structures, such as ::mbedtls_ecdh_context or
* ::mbedtls_ecdsa_context.
*
* \param grp The curve the point should lie on.
* \param pt The point to check.
*
* \return \c 0 if the point is a valid public key.
* \return #MBEDTLS_ERR_ECP_INVALID_KEY on failure.
*/
int mbedtls_ecp_check_pubkey( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt );
/**
* \brief This function checks that an \p mbedtls_mpi is a valid private
* key for this curve.
*
* \note This function uses bare components rather than an
* ::mbedtls_ecp_keypair structure to ease use with other
* structures, such as ::mbedtls_ecdh_context or
* ::mbedtls_ecdsa_context.
*
* \param grp The group used.
* \param d The integer to check.
*
* \return \c 0 if the point is a valid private key.
* \return #MBEDTLS_ERR_ECP_INVALID_KEY on failure.
*/
int mbedtls_ecp_check_privkey( const mbedtls_ecp_group *grp, const mbedtls_mpi *d );
/**
* \brief This function generates a private key.
*
* \param grp The ECP group.
* \param d The destination MPI (secret part).
* \param f_rng The RNG function.
* \param p_rng The RNG parameter.
*
* \return \c 0 on success.
* \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX error code
* on failure.
*/
int mbedtls_ecp_gen_privkey( const mbedtls_ecp_group *grp,
mbedtls_mpi *d,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng );
/**
* \brief This function generates a keypair with a configurable base
* point.
*
* \note This function uses bare components rather than an
* ::mbedtls_ecp_keypair structure to ease use with other
* structures, such as ::mbedtls_ecdh_context or
* ::mbedtls_ecdsa_context.
*
* \param grp The ECP group.
* \param G The chosen base point.
* \param d The destination MPI (secret part).
* \param Q The destination point (public part).
* \param f_rng The RNG function.
* \param p_rng The RNG context.
*
* \return \c 0 on success.
* \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX error code
* on failure.
*/
int mbedtls_ecp_gen_keypair_base( mbedtls_ecp_group *grp,
const mbedtls_ecp_point *G,
mbedtls_mpi *d, mbedtls_ecp_point *Q,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng );
/**
* \brief This function generates an ECP keypair.
*
* \note This function uses bare components rather than an
* ::mbedtls_ecp_keypair structure to ease use with other
* structures, such as ::mbedtls_ecdh_context or
* ::mbedtls_ecdsa_context.
*
* \param grp The ECP group.
* \param d The destination MPI (secret part).
* \param Q The destination point (public part).
* \param f_rng The RNG function.
* \param p_rng The RNG context.
*
* \return \c 0 on success.
* \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX error code
* on failure.
*/
int mbedtls_ecp_gen_keypair( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng );
/**
* \brief This function generates an ECP key.
*
* \param grp_id The ECP group identifier.
* \param key The destination key.
* \param f_rng The RNG function.
* \param p_rng The RNG context.
*
* \return \c 0 on success.
* \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX error code
* on failure.
*/
int mbedtls_ecp_gen_key( mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng );
/**
* \brief This function checks that the keypair objects
* \p pub and \p prv have the same group and the
* same public point, and that the private key in
* \p prv is consistent with the public key.
*
* \param pub The keypair structure holding the public key.
* If it contains a private key, that part is ignored.
* \param prv The keypair structure holding the full keypair.
*
* \return \c 0 on success, meaning that the keys are valid and match.
* \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if the keys are invalid or do not match.
* \return An \c MBEDTLS_ERR_ECP_XXX or an \c MBEDTLS_ERR_MPI_XXX
* error code on calculation failure.
*/
int mbedtls_ecp_check_pub_priv( const mbedtls_ecp_keypair *pub, const mbedtls_ecp_keypair *prv );
#if defined(MBEDTLS_SELF_TEST)
/**
* \brief The ECP checkup routine.
*
* \return \c 0 on success.
* \return \c 1 on failure.
*/
int mbedtls_ecp_self_test( int verbose );
#endif /* MBEDTLS_SELF_TEST */
#ifdef __cplusplus
}
#endif
#endif /* ecp.h */
@@ -0,0 +1,468 @@
/**
* \file md.h
*
* \brief This file contains the generic message-digest wrapper.
*
* \author Adriaan de Jong <dejong@fox-it.com>
*/
/*
* Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
* This file is part of Mbed TLS (https://tls.mbed.org)
*/
#ifndef MBEDTLS_MD_H
#define MBEDTLS_MD_H
#include <stddef.h>
#if !defined(MBEDTLS_CONFIG_FILE)
#include "config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#define MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE -0x5080 /**< The selected feature is not available. */
#define MBEDTLS_ERR_MD_BAD_INPUT_DATA -0x5100 /**< Bad input parameters to function. */
#define MBEDTLS_ERR_MD_ALLOC_FAILED -0x5180 /**< Failed to allocate memory. */
#define MBEDTLS_ERR_MD_FILE_IO_ERROR -0x5200 /**< Opening or reading of file failed. */
/* MBEDTLS_ERR_MD_HW_ACCEL_FAILED is deprecated and should not be used. */
#define MBEDTLS_ERR_MD_HW_ACCEL_FAILED -0x5280 /**< MD hardware accelerator failed. */
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Supported message digests.
*
* \warning MD2, MD4, MD5 and SHA-1 are considered weak message digests and
* their use constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
typedef enum {
MBEDTLS_MD_NONE=0, /**< None. */
MBEDTLS_MD_MD2, /**< The MD2 message digest. */
MBEDTLS_MD_MD4, /**< The MD4 message digest. */
MBEDTLS_MD_MD5, /**< The MD5 message digest. */
MBEDTLS_MD_SHA1, /**< The SHA-1 message digest. */
MBEDTLS_MD_SHA224, /**< The SHA-224 message digest. */
MBEDTLS_MD_SHA256, /**< The SHA-256 message digest. */
MBEDTLS_MD_SHA384, /**< The SHA-384 message digest. */
MBEDTLS_MD_SHA512, /**< The SHA-512 message digest. */
MBEDTLS_MD_RIPEMD160, /**< The RIPEMD-160 message digest. */
} mbedtls_md_type_t;
#if defined(MBEDTLS_SHA512_C)
#define MBEDTLS_MD_MAX_SIZE 64 /* longest known is SHA512 */
#else
#define MBEDTLS_MD_MAX_SIZE 32 /* longest known is SHA256 or less */
#endif
/**
* Opaque struct defined in md_internal.h.
*/
typedef struct mbedtls_md_info_t mbedtls_md_info_t;
/**
* The generic message-digest context.
*/
typedef struct mbedtls_md_context_t
{
/** Information about the associated message digest. */
const mbedtls_md_info_t *md_info;
/** The digest-specific context. */
void *md_ctx;
/** The HMAC part of the context. */
void *hmac_ctx;
} mbedtls_md_context_t;
/**
* \brief This function returns the list of digests supported by the
* generic digest module.
*
* \return A statically allocated array of digests. Each element
* in the returned list is an integer belonging to the
* message-digest enumeration #mbedtls_md_type_t.
* The last entry is 0.
*/
const int *mbedtls_md_list( void );
/**
* \brief This function returns the message-digest information
* associated with the given digest name.
*
* \param md_name The name of the digest to search for.
*
* \return The message-digest information associated with \p md_name.
* \return NULL if the associated message-digest information is not found.
*/
const mbedtls_md_info_t *mbedtls_md_info_from_string( const char *md_name );
/**
* \brief This function returns the message-digest information
* associated with the given digest type.
*
* \param md_type The type of digest to search for.
*
* \return The message-digest information associated with \p md_type.
* \return NULL if the associated message-digest information is not found.
*/
const mbedtls_md_info_t *mbedtls_md_info_from_type( mbedtls_md_type_t md_type );
/**
* \brief This function initializes a message-digest context without
* binding it to a particular message-digest algorithm.
*
* This function should always be called first. It prepares the
* context for mbedtls_md_setup() for binding it to a
* message-digest algorithm.
*/
void mbedtls_md_init( mbedtls_md_context_t *ctx );
/**
* \brief This function clears the internal structure of \p ctx and
* frees any embedded internal structure, but does not free
* \p ctx itself.
*
* If you have called mbedtls_md_setup() on \p ctx, you must
* call mbedtls_md_free() when you are no longer using the
* context.
* Calling this function if you have previously
* called mbedtls_md_init() and nothing else is optional.
* You must not call this function if you have not called
* mbedtls_md_init().
*/
void mbedtls_md_free( mbedtls_md_context_t *ctx );
#if ! defined(MBEDTLS_DEPRECATED_REMOVED)
#if defined(MBEDTLS_DEPRECATED_WARNING)
#define MBEDTLS_DEPRECATED __attribute__((deprecated))
#else
#define MBEDTLS_DEPRECATED
#endif
/**
* \brief This function selects the message digest algorithm to use,
* and allocates internal structures.
*
* It should be called after mbedtls_md_init() or mbedtls_md_free().
* Makes it necessary to call mbedtls_md_free() later.
*
* \deprecated Superseded by mbedtls_md_setup() in 2.0.0
*
* \param ctx The context to set up.
* \param md_info The information structure of the message-digest algorithm
* to use.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification
* failure.
* \return #MBEDTLS_ERR_MD_ALLOC_FAILED on memory-allocation failure.
*/
int mbedtls_md_init_ctx( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info ) MBEDTLS_DEPRECATED;
#undef MBEDTLS_DEPRECATED
#endif /* MBEDTLS_DEPRECATED_REMOVED */
/**
* \brief This function selects the message digest algorithm to use,
* and allocates internal structures.
*
* It should be called after mbedtls_md_init() or
* mbedtls_md_free(). Makes it necessary to call
* mbedtls_md_free() later.
*
* \param ctx The context to set up.
* \param md_info The information structure of the message-digest algorithm
* to use.
* \param hmac Defines if HMAC is used. 0: HMAC is not used (saves some memory),
* or non-zero: HMAC is used with this context.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification
* failure.
* \return #MBEDTLS_ERR_MD_ALLOC_FAILED on memory-allocation failure.
*/
int mbedtls_md_setup( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info, int hmac );
/**
* \brief This function clones the state of an message-digest
* context.
*
* \note You must call mbedtls_md_setup() on \c dst before calling
* this function.
*
* \note The two contexts must have the same type,
* for example, both are SHA-256.
*
* \warning This function clones the message-digest state, not the
* HMAC state.
*
* \param dst The destination context.
* \param src The context to be cloned.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification failure.
*/
int mbedtls_md_clone( mbedtls_md_context_t *dst,
const mbedtls_md_context_t *src );
/**
* \brief This function extracts the message-digest size from the
* message-digest information structure.
*
* \param md_info The information structure of the message-digest algorithm
* to use.
*
* \return The size of the message-digest output in Bytes.
*/
unsigned char mbedtls_md_get_size( const mbedtls_md_info_t *md_info );
/**
* \brief This function extracts the message-digest type from the
* message-digest information structure.
*
* \param md_info The information structure of the message-digest algorithm
* to use.
*
* \return The type of the message digest.
*/
mbedtls_md_type_t mbedtls_md_get_type( const mbedtls_md_info_t *md_info );
/**
* \brief This function extracts the message-digest name from the
* message-digest information structure.
*
* \param md_info The information structure of the message-digest algorithm
* to use.
*
* \return The name of the message digest.
*/
const char *mbedtls_md_get_name( const mbedtls_md_info_t *md_info );
/**
* \brief This function starts a message-digest computation.
*
* You must call this function after setting up the context
* with mbedtls_md_setup(), and before passing data with
* mbedtls_md_update().
*
* \param ctx The generic message-digest context.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification
* failure.
*/
int mbedtls_md_starts( mbedtls_md_context_t *ctx );
/**
* \brief This function feeds an input buffer into an ongoing
* message-digest computation.
*
* You must call mbedtls_md_starts() before calling this
* function. You may call this function multiple times.
* Afterwards, call mbedtls_md_finish().
*
* \param ctx The generic message-digest context.
* \param input The buffer holding the input data.
* \param ilen The length of the input data.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification
* failure.
*/
int mbedtls_md_update( mbedtls_md_context_t *ctx, const unsigned char *input, size_t ilen );
/**
* \brief This function finishes the digest operation,
* and writes the result to the output buffer.
*
* Call this function after a call to mbedtls_md_starts(),
* followed by any number of calls to mbedtls_md_update().
* Afterwards, you may either clear the context with
* mbedtls_md_free(), or call mbedtls_md_starts() to reuse
* the context for another digest operation with the same
* algorithm.
*
* \param ctx The generic message-digest context.
* \param output The buffer for the generic message-digest checksum result.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification
* failure.
*/
int mbedtls_md_finish( mbedtls_md_context_t *ctx, unsigned char *output );
/**
* \brief This function calculates the message-digest of a buffer,
* with respect to a configurable message-digest algorithm
* in a single call.
*
* The result is calculated as
* Output = message_digest(input buffer).
*
* \param md_info The information structure of the message-digest algorithm
* to use.
* \param input The buffer holding the data.
* \param ilen The length of the input data.
* \param output The generic message-digest checksum result.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification
* failure.
*/
int mbedtls_md( const mbedtls_md_info_t *md_info, const unsigned char *input, size_t ilen,
unsigned char *output );
#if defined(MBEDTLS_FS_IO)
/**
* \brief This function calculates the message-digest checksum
* result of the contents of the provided file.
*
* The result is calculated as
* Output = message_digest(file contents).
*
* \param md_info The information structure of the message-digest algorithm
* to use.
* \param path The input file name.
* \param output The generic message-digest checksum result.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_MD_FILE_IO_ERROR on an I/O error accessing
* the file pointed by \p path.
* \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA if \p md_info was NULL.
*/
int mbedtls_md_file( const mbedtls_md_info_t *md_info, const char *path,
unsigned char *output );
#endif /* MBEDTLS_FS_IO */
/**
* \brief This function sets the HMAC key and prepares to
* authenticate a new message.
*
* Call this function after mbedtls_md_setup(), to use
* the MD context for an HMAC calculation, then call
* mbedtls_md_hmac_update() to provide the input data, and
* mbedtls_md_hmac_finish() to get the HMAC value.
*
* \param ctx The message digest context containing an embedded HMAC
* context.
* \param key The HMAC secret key.
* \param keylen The length of the HMAC key in Bytes.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification
* failure.
*/
int mbedtls_md_hmac_starts( mbedtls_md_context_t *ctx, const unsigned char *key,
size_t keylen );
/**
* \brief This function feeds an input buffer into an ongoing HMAC
* computation.
*
* Call mbedtls_md_hmac_starts() or mbedtls_md_hmac_reset()
* before calling this function.
* You may call this function multiple times to pass the
* input piecewise.
* Afterwards, call mbedtls_md_hmac_finish().
*
* \param ctx The message digest context containing an embedded HMAC
* context.
* \param input The buffer holding the input data.
* \param ilen The length of the input data.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification
* failure.
*/
int mbedtls_md_hmac_update( mbedtls_md_context_t *ctx, const unsigned char *input,
size_t ilen );
/**
* \brief This function finishes the HMAC operation, and writes
* the result to the output buffer.
*
* Call this function after mbedtls_md_hmac_starts() and
* mbedtls_md_hmac_update() to get the HMAC value. Afterwards
* you may either call mbedtls_md_free() to clear the context,
* or call mbedtls_md_hmac_reset() to reuse the context with
* the same HMAC key.
*
* \param ctx The message digest context containing an embedded HMAC
* context.
* \param output The generic HMAC checksum result.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification
* failure.
*/
int mbedtls_md_hmac_finish( mbedtls_md_context_t *ctx, unsigned char *output);
/**
* \brief This function prepares to authenticate a new message with
* the same key as the previous HMAC operation.
*
* You may call this function after mbedtls_md_hmac_finish().
* Afterwards call mbedtls_md_hmac_update() to pass the new
* input.
*
* \param ctx The message digest context containing an embedded HMAC
* context.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification
* failure.
*/
int mbedtls_md_hmac_reset( mbedtls_md_context_t *ctx );
/**
* \brief This function calculates the full generic HMAC
* on the input buffer with the provided key.
*
* The function allocates the context, performs the
* calculation, and frees the context.
*
* The HMAC result is calculated as
* output = generic HMAC(hmac key, input buffer).
*
* \param md_info The information structure of the message-digest algorithm
* to use.
* \param key The HMAC secret key.
* \param keylen The length of the HMAC secret key in Bytes.
* \param input The buffer holding the input data.
* \param ilen The length of the input data.
* \param output The generic HMAC result.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification
* failure.
*/
int mbedtls_md_hmac( const mbedtls_md_info_t *md_info, const unsigned char *key, size_t keylen,
const unsigned char *input, size_t ilen,
unsigned char *output );
/* Internal use */
int mbedtls_md_process( mbedtls_md_context_t *ctx, const unsigned char *data );
#ifdef __cplusplus
}
#endif
#endif /* MBEDTLS_MD_H */
@@ -0,0 +1,570 @@
/**
* \file oid.h
*
* \brief Object Identifier (OID) database
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#ifndef MBEDTLS_OID_H
#define MBEDTLS_OID_H
#if !defined(MBEDTLS_CONFIG_FILE)
#include "config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#include "asn1.h"
#include "pk.h"
#include <stddef.h>
#if defined(MBEDTLS_CIPHER_C)
#include "cipher.h"
#endif
#if defined(MBEDTLS_MD_C)
#include "md.h"
#endif
#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C)
#include "x509.h"
#endif
#define MBEDTLS_ERR_OID_NOT_FOUND -0x002E /**< OID is not found. */
#define MBEDTLS_ERR_OID_BUF_TOO_SMALL -0x000B /**< output buffer is too small */
/*
* Top level OID tuples
*/
#define MBEDTLS_OID_ISO_MEMBER_BODIES "\x2a" /* {iso(1) member-body(2)} */
#define MBEDTLS_OID_ISO_IDENTIFIED_ORG "\x2b" /* {iso(1) identified-organization(3)} */
#define MBEDTLS_OID_ISO_CCITT_DS "\x55" /* {joint-iso-ccitt(2) ds(5)} */
#define MBEDTLS_OID_ISO_ITU_COUNTRY "\x60" /* {joint-iso-itu-t(2) country(16)} */
/*
* ISO Member bodies OID parts
*/
#define MBEDTLS_OID_COUNTRY_US "\x86\x48" /* {us(840)} */
#define MBEDTLS_OID_ORG_RSA_DATA_SECURITY "\x86\xf7\x0d" /* {rsadsi(113549)} */
#define MBEDTLS_OID_RSA_COMPANY MBEDTLS_OID_ISO_MEMBER_BODIES MBEDTLS_OID_COUNTRY_US \
MBEDTLS_OID_ORG_RSA_DATA_SECURITY /* {iso(1) member-body(2) us(840) rsadsi(113549)} */
#define MBEDTLS_OID_ORG_ANSI_X9_62 "\xce\x3d" /* ansi-X9-62(10045) */
#define MBEDTLS_OID_ANSI_X9_62 MBEDTLS_OID_ISO_MEMBER_BODIES MBEDTLS_OID_COUNTRY_US \
MBEDTLS_OID_ORG_ANSI_X9_62
/*
* ISO Identified organization OID parts
*/
#define MBEDTLS_OID_ORG_DOD "\x06" /* {dod(6)} */
#define MBEDTLS_OID_ORG_OIW "\x0e"
#define MBEDTLS_OID_OIW_SECSIG MBEDTLS_OID_ORG_OIW "\x03"
#define MBEDTLS_OID_OIW_SECSIG_ALG MBEDTLS_OID_OIW_SECSIG "\x02"
#define MBEDTLS_OID_OIW_SECSIG_SHA1 MBEDTLS_OID_OIW_SECSIG_ALG "\x1a"
#define MBEDTLS_OID_ORG_CERTICOM "\x81\x04" /* certicom(132) */
#define MBEDTLS_OID_CERTICOM MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_ORG_CERTICOM
#define MBEDTLS_OID_ORG_TELETRUST "\x24" /* teletrust(36) */
#define MBEDTLS_OID_TELETRUST MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_ORG_TELETRUST
/*
* ISO ITU OID parts
*/
#define MBEDTLS_OID_ORGANIZATION "\x01" /* {organization(1)} */
#define MBEDTLS_OID_ISO_ITU_US_ORG MBEDTLS_OID_ISO_ITU_COUNTRY MBEDTLS_OID_COUNTRY_US MBEDTLS_OID_ORGANIZATION /* {joint-iso-itu-t(2) country(16) us(840) organization(1)} */
#define MBEDTLS_OID_ORG_GOV "\x65" /* {gov(101)} */
#define MBEDTLS_OID_GOV MBEDTLS_OID_ISO_ITU_US_ORG MBEDTLS_OID_ORG_GOV /* {joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101)} */
#define MBEDTLS_OID_ORG_NETSCAPE "\x86\xF8\x42" /* {netscape(113730)} */
#define MBEDTLS_OID_NETSCAPE MBEDTLS_OID_ISO_ITU_US_ORG MBEDTLS_OID_ORG_NETSCAPE /* Netscape OID {joint-iso-itu-t(2) country(16) us(840) organization(1) netscape(113730)} */
/* ISO arc for standard certificate and CRL extensions */
#define MBEDTLS_OID_ID_CE MBEDTLS_OID_ISO_CCITT_DS "\x1D" /**< id-ce OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) ds(5) 29} */
/**
* Private Internet Extensions
* { iso(1) identified-organization(3) dod(6) internet(1)
* security(5) mechanisms(5) pkix(7) }
*/
#define MBEDTLS_OID_PKIX MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_ORG_DOD "\x01\x05\x05\x07"
/*
* Arc for standard naming attributes
*/
#define MBEDTLS_OID_AT MBEDTLS_OID_ISO_CCITT_DS "\x04" /**< id-at OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) ds(5) 4} */
#define MBEDTLS_OID_AT_CN MBEDTLS_OID_AT "\x03" /**< id-at-commonName AttributeType:= {id-at 3} */
#define MBEDTLS_OID_AT_SUR_NAME MBEDTLS_OID_AT "\x04" /**< id-at-surName AttributeType:= {id-at 4} */
#define MBEDTLS_OID_AT_SERIAL_NUMBER MBEDTLS_OID_AT "\x05" /**< id-at-serialNumber AttributeType:= {id-at 5} */
#define MBEDTLS_OID_AT_COUNTRY MBEDTLS_OID_AT "\x06" /**< id-at-countryName AttributeType:= {id-at 6} */
#define MBEDTLS_OID_AT_LOCALITY MBEDTLS_OID_AT "\x07" /**< id-at-locality AttributeType:= {id-at 7} */
#define MBEDTLS_OID_AT_STATE MBEDTLS_OID_AT "\x08" /**< id-at-state AttributeType:= {id-at 8} */
#define MBEDTLS_OID_AT_ORGANIZATION MBEDTLS_OID_AT "\x0A" /**< id-at-organizationName AttributeType:= {id-at 10} */
#define MBEDTLS_OID_AT_ORG_UNIT MBEDTLS_OID_AT "\x0B" /**< id-at-organizationalUnitName AttributeType:= {id-at 11} */
#define MBEDTLS_OID_AT_TITLE MBEDTLS_OID_AT "\x0C" /**< id-at-title AttributeType:= {id-at 12} */
#define MBEDTLS_OID_AT_POSTAL_ADDRESS MBEDTLS_OID_AT "\x10" /**< id-at-postalAddress AttributeType:= {id-at 16} */
#define MBEDTLS_OID_AT_POSTAL_CODE MBEDTLS_OID_AT "\x11" /**< id-at-postalCode AttributeType:= {id-at 17} */
#define MBEDTLS_OID_AT_GIVEN_NAME MBEDTLS_OID_AT "\x2A" /**< id-at-givenName AttributeType:= {id-at 42} */
#define MBEDTLS_OID_AT_INITIALS MBEDTLS_OID_AT "\x2B" /**< id-at-initials AttributeType:= {id-at 43} */
#define MBEDTLS_OID_AT_GENERATION_QUALIFIER MBEDTLS_OID_AT "\x2C" /**< id-at-generationQualifier AttributeType:= {id-at 44} */
#define MBEDTLS_OID_AT_UNIQUE_IDENTIFIER MBEDTLS_OID_AT "\x2D" /**< id-at-uniqueIdentifier AttributType:= {id-at 45} */
#define MBEDTLS_OID_AT_DN_QUALIFIER MBEDTLS_OID_AT "\x2E" /**< id-at-dnQualifier AttributeType:= {id-at 46} */
#define MBEDTLS_OID_AT_PSEUDONYM MBEDTLS_OID_AT "\x41" /**< id-at-pseudonym AttributeType:= {id-at 65} */
#define MBEDTLS_OID_DOMAIN_COMPONENT "\x09\x92\x26\x89\x93\xF2\x2C\x64\x01\x19" /** id-domainComponent AttributeType:= {itu-t(0) data(9) pss(2342) ucl(19200300) pilot(100) pilotAttributeType(1) domainComponent(25)} */
/*
* OIDs for standard certificate extensions
*/
#define MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER MBEDTLS_OID_ID_CE "\x23" /**< id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 35 } */
#define MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER MBEDTLS_OID_ID_CE "\x0E" /**< id-ce-subjectKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 14 } */
#define MBEDTLS_OID_KEY_USAGE MBEDTLS_OID_ID_CE "\x0F" /**< id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 } */
#define MBEDTLS_OID_CERTIFICATE_POLICIES MBEDTLS_OID_ID_CE "\x20" /**< id-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-ce 32 } */
#define MBEDTLS_OID_POLICY_MAPPINGS MBEDTLS_OID_ID_CE "\x21" /**< id-ce-policyMappings OBJECT IDENTIFIER ::= { id-ce 33 } */
#define MBEDTLS_OID_SUBJECT_ALT_NAME MBEDTLS_OID_ID_CE "\x11" /**< id-ce-subjectAltName OBJECT IDENTIFIER ::= { id-ce 17 } */
#define MBEDTLS_OID_ISSUER_ALT_NAME MBEDTLS_OID_ID_CE "\x12" /**< id-ce-issuerAltName OBJECT IDENTIFIER ::= { id-ce 18 } */
#define MBEDTLS_OID_SUBJECT_DIRECTORY_ATTRS MBEDTLS_OID_ID_CE "\x09" /**< id-ce-subjectDirectoryAttributes OBJECT IDENTIFIER ::= { id-ce 9 } */
#define MBEDTLS_OID_BASIC_CONSTRAINTS MBEDTLS_OID_ID_CE "\x13" /**< id-ce-basicConstraints OBJECT IDENTIFIER ::= { id-ce 19 } */
#define MBEDTLS_OID_NAME_CONSTRAINTS MBEDTLS_OID_ID_CE "\x1E" /**< id-ce-nameConstraints OBJECT IDENTIFIER ::= { id-ce 30 } */
#define MBEDTLS_OID_POLICY_CONSTRAINTS MBEDTLS_OID_ID_CE "\x24" /**< id-ce-policyConstraints OBJECT IDENTIFIER ::= { id-ce 36 } */
#define MBEDTLS_OID_EXTENDED_KEY_USAGE MBEDTLS_OID_ID_CE "\x25" /**< id-ce-extKeyUsage OBJECT IDENTIFIER ::= { id-ce 37 } */
#define MBEDTLS_OID_CRL_DISTRIBUTION_POINTS MBEDTLS_OID_ID_CE "\x1F" /**< id-ce-cRLDistributionPoints OBJECT IDENTIFIER ::= { id-ce 31 } */
#define MBEDTLS_OID_INIHIBIT_ANYPOLICY MBEDTLS_OID_ID_CE "\x36" /**< id-ce-inhibitAnyPolicy OBJECT IDENTIFIER ::= { id-ce 54 } */
#define MBEDTLS_OID_FRESHEST_CRL MBEDTLS_OID_ID_CE "\x2E" /**< id-ce-freshestCRL OBJECT IDENTIFIER ::= { id-ce 46 } */
/*
* Netscape certificate extensions
*/
#define MBEDTLS_OID_NS_CERT MBEDTLS_OID_NETSCAPE "\x01"
#define MBEDTLS_OID_NS_CERT_TYPE MBEDTLS_OID_NS_CERT "\x01"
#define MBEDTLS_OID_NS_BASE_URL MBEDTLS_OID_NS_CERT "\x02"
#define MBEDTLS_OID_NS_REVOCATION_URL MBEDTLS_OID_NS_CERT "\x03"
#define MBEDTLS_OID_NS_CA_REVOCATION_URL MBEDTLS_OID_NS_CERT "\x04"
#define MBEDTLS_OID_NS_RENEWAL_URL MBEDTLS_OID_NS_CERT "\x07"
#define MBEDTLS_OID_NS_CA_POLICY_URL MBEDTLS_OID_NS_CERT "\x08"
#define MBEDTLS_OID_NS_SSL_SERVER_NAME MBEDTLS_OID_NS_CERT "\x0C"
#define MBEDTLS_OID_NS_COMMENT MBEDTLS_OID_NS_CERT "\x0D"
#define MBEDTLS_OID_NS_DATA_TYPE MBEDTLS_OID_NETSCAPE "\x02"
#define MBEDTLS_OID_NS_CERT_SEQUENCE MBEDTLS_OID_NS_DATA_TYPE "\x05"
/*
* OIDs for CRL extensions
*/
#define MBEDTLS_OID_PRIVATE_KEY_USAGE_PERIOD MBEDTLS_OID_ID_CE "\x10"
#define MBEDTLS_OID_CRL_NUMBER MBEDTLS_OID_ID_CE "\x14" /**< id-ce-cRLNumber OBJECT IDENTIFIER ::= { id-ce 20 } */
/*
* X.509 v3 Extended key usage OIDs
*/
#define MBEDTLS_OID_ANY_EXTENDED_KEY_USAGE MBEDTLS_OID_EXTENDED_KEY_USAGE "\x00" /**< anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 } */
#define MBEDTLS_OID_KP MBEDTLS_OID_PKIX "\x03" /**< id-kp OBJECT IDENTIFIER ::= { id-pkix 3 } */
#define MBEDTLS_OID_SERVER_AUTH MBEDTLS_OID_KP "\x01" /**< id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 } */
#define MBEDTLS_OID_CLIENT_AUTH MBEDTLS_OID_KP "\x02" /**< id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 } */
#define MBEDTLS_OID_CODE_SIGNING MBEDTLS_OID_KP "\x03" /**< id-kp-codeSigning OBJECT IDENTIFIER ::= { id-kp 3 } */
#define MBEDTLS_OID_EMAIL_PROTECTION MBEDTLS_OID_KP "\x04" /**< id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 } */
#define MBEDTLS_OID_TIME_STAMPING MBEDTLS_OID_KP "\x08" /**< id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 } */
#define MBEDTLS_OID_OCSP_SIGNING MBEDTLS_OID_KP "\x09" /**< id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 } */
/*
* PKCS definition OIDs
*/
#define MBEDTLS_OID_PKCS MBEDTLS_OID_RSA_COMPANY "\x01" /**< pkcs OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) 1 } */
#define MBEDTLS_OID_PKCS1 MBEDTLS_OID_PKCS "\x01" /**< pkcs-1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 } */
#define MBEDTLS_OID_PKCS5 MBEDTLS_OID_PKCS "\x05" /**< pkcs-5 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 5 } */
#define MBEDTLS_OID_PKCS9 MBEDTLS_OID_PKCS "\x09" /**< pkcs-9 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 } */
#define MBEDTLS_OID_PKCS12 MBEDTLS_OID_PKCS "\x0c" /**< pkcs-12 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 12 } */
/*
* PKCS#1 OIDs
*/
#define MBEDTLS_OID_PKCS1_RSA MBEDTLS_OID_PKCS1 "\x01" /**< rsaEncryption OBJECT IDENTIFIER ::= { pkcs-1 1 } */
#define MBEDTLS_OID_PKCS1_MD2 MBEDTLS_OID_PKCS1 "\x02" /**< md2WithRSAEncryption ::= { pkcs-1 2 } */
#define MBEDTLS_OID_PKCS1_MD4 MBEDTLS_OID_PKCS1 "\x03" /**< md4WithRSAEncryption ::= { pkcs-1 3 } */
#define MBEDTLS_OID_PKCS1_MD5 MBEDTLS_OID_PKCS1 "\x04" /**< md5WithRSAEncryption ::= { pkcs-1 4 } */
#define MBEDTLS_OID_PKCS1_SHA1 MBEDTLS_OID_PKCS1 "\x05" /**< sha1WithRSAEncryption ::= { pkcs-1 5 } */
#define MBEDTLS_OID_PKCS1_SHA224 MBEDTLS_OID_PKCS1 "\x0e" /**< sha224WithRSAEncryption ::= { pkcs-1 14 } */
#define MBEDTLS_OID_PKCS1_SHA256 MBEDTLS_OID_PKCS1 "\x0b" /**< sha256WithRSAEncryption ::= { pkcs-1 11 } */
#define MBEDTLS_OID_PKCS1_SHA384 MBEDTLS_OID_PKCS1 "\x0c" /**< sha384WithRSAEncryption ::= { pkcs-1 12 } */
#define MBEDTLS_OID_PKCS1_SHA512 MBEDTLS_OID_PKCS1 "\x0d" /**< sha512WithRSAEncryption ::= { pkcs-1 13 } */
#define MBEDTLS_OID_RSA_SHA_OBS "\x2B\x0E\x03\x02\x1D"
#define MBEDTLS_OID_PKCS9_EMAIL MBEDTLS_OID_PKCS9 "\x01" /**< emailAddress AttributeType ::= { pkcs-9 1 } */
/* RFC 4055 */
#define MBEDTLS_OID_RSASSA_PSS MBEDTLS_OID_PKCS1 "\x0a" /**< id-RSASSA-PSS ::= { pkcs-1 10 } */
#define MBEDTLS_OID_MGF1 MBEDTLS_OID_PKCS1 "\x08" /**< id-mgf1 ::= { pkcs-1 8 } */
/*
* Digest algorithms
*/
#define MBEDTLS_OID_DIGEST_ALG_MD2 MBEDTLS_OID_RSA_COMPANY "\x02\x02" /**< id-mbedtls_md2 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 2 } */
#define MBEDTLS_OID_DIGEST_ALG_MD4 MBEDTLS_OID_RSA_COMPANY "\x02\x04" /**< id-mbedtls_md4 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 4 } */
#define MBEDTLS_OID_DIGEST_ALG_MD5 MBEDTLS_OID_RSA_COMPANY "\x02\x05" /**< id-mbedtls_md5 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 5 } */
#define MBEDTLS_OID_DIGEST_ALG_SHA1 MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_OIW_SECSIG_SHA1 /**< id-mbedtls_sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 } */
#define MBEDTLS_OID_DIGEST_ALG_SHA224 MBEDTLS_OID_GOV "\x03\x04\x02\x04" /**< id-sha224 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 4 } */
#define MBEDTLS_OID_DIGEST_ALG_SHA256 MBEDTLS_OID_GOV "\x03\x04\x02\x01" /**< id-mbedtls_sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 1 } */
#define MBEDTLS_OID_DIGEST_ALG_SHA384 MBEDTLS_OID_GOV "\x03\x04\x02\x02" /**< id-sha384 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 2 } */
#define MBEDTLS_OID_DIGEST_ALG_SHA512 MBEDTLS_OID_GOV "\x03\x04\x02\x03" /**< id-mbedtls_sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 3 } */
#define MBEDTLS_OID_HMAC_SHA1 MBEDTLS_OID_RSA_COMPANY "\x02\x07" /**< id-hmacWithSHA1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 7 } */
/*
* Encryption algorithms
*/
#define MBEDTLS_OID_DES_CBC MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_OIW_SECSIG_ALG "\x07" /**< desCBC OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 7 } */
#define MBEDTLS_OID_DES_EDE3_CBC MBEDTLS_OID_RSA_COMPANY "\x03\x07" /**< des-ede3-cbc OBJECT IDENTIFIER ::= { iso(1) member-body(2) -- us(840) rsadsi(113549) encryptionAlgorithm(3) 7 } */
/*
* PKCS#5 OIDs
*/
#define MBEDTLS_OID_PKCS5_PBKDF2 MBEDTLS_OID_PKCS5 "\x0c" /**< id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12} */
#define MBEDTLS_OID_PKCS5_PBES2 MBEDTLS_OID_PKCS5 "\x0d" /**< id-PBES2 OBJECT IDENTIFIER ::= {pkcs-5 13} */
#define MBEDTLS_OID_PKCS5_PBMAC1 MBEDTLS_OID_PKCS5 "\x0e" /**< id-PBMAC1 OBJECT IDENTIFIER ::= {pkcs-5 14} */
/*
* PKCS#5 PBES1 algorithms
*/
#define MBEDTLS_OID_PKCS5_PBE_MD2_DES_CBC MBEDTLS_OID_PKCS5 "\x01" /**< pbeWithMD2AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 1} */
#define MBEDTLS_OID_PKCS5_PBE_MD2_RC2_CBC MBEDTLS_OID_PKCS5 "\x04" /**< pbeWithMD2AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 4} */
#define MBEDTLS_OID_PKCS5_PBE_MD5_DES_CBC MBEDTLS_OID_PKCS5 "\x03" /**< pbeWithMD5AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 3} */
#define MBEDTLS_OID_PKCS5_PBE_MD5_RC2_CBC MBEDTLS_OID_PKCS5 "\x06" /**< pbeWithMD5AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 6} */
#define MBEDTLS_OID_PKCS5_PBE_SHA1_DES_CBC MBEDTLS_OID_PKCS5 "\x0a" /**< pbeWithSHA1AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 10} */
#define MBEDTLS_OID_PKCS5_PBE_SHA1_RC2_CBC MBEDTLS_OID_PKCS5 "\x0b" /**< pbeWithSHA1AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 11} */
/*
* PKCS#8 OIDs
*/
#define MBEDTLS_OID_PKCS9_CSR_EXT_REQ MBEDTLS_OID_PKCS9 "\x0e" /**< extensionRequest OBJECT IDENTIFIER ::= {pkcs-9 14} */
/*
* PKCS#12 PBE OIDs
*/
#define MBEDTLS_OID_PKCS12_PBE MBEDTLS_OID_PKCS12 "\x01" /**< pkcs-12PbeIds OBJECT IDENTIFIER ::= {pkcs-12 1} */
#define MBEDTLS_OID_PKCS12_PBE_SHA1_RC4_128 MBEDTLS_OID_PKCS12_PBE "\x01" /**< pbeWithSHAAnd128BitRC4 OBJECT IDENTIFIER ::= {pkcs-12PbeIds 1} */
#define MBEDTLS_OID_PKCS12_PBE_SHA1_RC4_40 MBEDTLS_OID_PKCS12_PBE "\x02" /**< pbeWithSHAAnd40BitRC4 OBJECT IDENTIFIER ::= {pkcs-12PbeIds 2} */
#define MBEDTLS_OID_PKCS12_PBE_SHA1_DES3_EDE_CBC MBEDTLS_OID_PKCS12_PBE "\x03" /**< pbeWithSHAAnd3-KeyTripleDES-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 3} */
#define MBEDTLS_OID_PKCS12_PBE_SHA1_DES2_EDE_CBC MBEDTLS_OID_PKCS12_PBE "\x04" /**< pbeWithSHAAnd2-KeyTripleDES-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 4} */
#define MBEDTLS_OID_PKCS12_PBE_SHA1_RC2_128_CBC MBEDTLS_OID_PKCS12_PBE "\x05" /**< pbeWithSHAAnd128BitRC2-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 5} */
#define MBEDTLS_OID_PKCS12_PBE_SHA1_RC2_40_CBC MBEDTLS_OID_PKCS12_PBE "\x06" /**< pbeWithSHAAnd40BitRC2-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 6} */
/*
* EC key algorithms from RFC 5480
*/
/* id-ecPublicKey OBJECT IDENTIFIER ::= {
* iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 } */
#define MBEDTLS_OID_EC_ALG_UNRESTRICTED MBEDTLS_OID_ANSI_X9_62 "\x02\01"
/* id-ecDH OBJECT IDENTIFIER ::= {
* iso(1) identified-organization(3) certicom(132)
* schemes(1) ecdh(12) } */
#define MBEDTLS_OID_EC_ALG_ECDH MBEDTLS_OID_CERTICOM "\x01\x0c"
/*
* ECParameters namedCurve identifiers, from RFC 5480, RFC 5639, and SEC2
*/
/* secp192r1 OBJECT IDENTIFIER ::= {
* iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) prime(1) 1 } */
#define MBEDTLS_OID_EC_GRP_SECP192R1 MBEDTLS_OID_ANSI_X9_62 "\x03\x01\x01"
/* secp224r1 OBJECT IDENTIFIER ::= {
* iso(1) identified-organization(3) certicom(132) curve(0) 33 } */
#define MBEDTLS_OID_EC_GRP_SECP224R1 MBEDTLS_OID_CERTICOM "\x00\x21"
/* secp256r1 OBJECT IDENTIFIER ::= {
* iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) prime(1) 7 } */
#define MBEDTLS_OID_EC_GRP_SECP256R1 MBEDTLS_OID_ANSI_X9_62 "\x03\x01\x07"
/* secp384r1 OBJECT IDENTIFIER ::= {
* iso(1) identified-organization(3) certicom(132) curve(0) 34 } */
#define MBEDTLS_OID_EC_GRP_SECP384R1 MBEDTLS_OID_CERTICOM "\x00\x22"
/* secp521r1 OBJECT IDENTIFIER ::= {
* iso(1) identified-organization(3) certicom(132) curve(0) 35 } */
#define MBEDTLS_OID_EC_GRP_SECP521R1 MBEDTLS_OID_CERTICOM "\x00\x23"
/* secp192k1 OBJECT IDENTIFIER ::= {
* iso(1) identified-organization(3) certicom(132) curve(0) 31 } */
#define MBEDTLS_OID_EC_GRP_SECP192K1 MBEDTLS_OID_CERTICOM "\x00\x1f"
/* secp224k1 OBJECT IDENTIFIER ::= {
* iso(1) identified-organization(3) certicom(132) curve(0) 32 } */
#define MBEDTLS_OID_EC_GRP_SECP224K1 MBEDTLS_OID_CERTICOM "\x00\x20"
/* secp256k1 OBJECT IDENTIFIER ::= {
* iso(1) identified-organization(3) certicom(132) curve(0) 10 } */
#define MBEDTLS_OID_EC_GRP_SECP256K1 MBEDTLS_OID_CERTICOM "\x00\x0a"
/* RFC 5639 4.1
* ecStdCurvesAndGeneration OBJECT IDENTIFIER::= {iso(1)
* identified-organization(3) teletrust(36) algorithm(3) signature-
* algorithm(3) ecSign(2) 8}
* ellipticCurve OBJECT IDENTIFIER ::= {ecStdCurvesAndGeneration 1}
* versionOne OBJECT IDENTIFIER ::= {ellipticCurve 1} */
#define MBEDTLS_OID_EC_BRAINPOOL_V1 MBEDTLS_OID_TELETRUST "\x03\x03\x02\x08\x01\x01"
/* brainpoolP256r1 OBJECT IDENTIFIER ::= {versionOne 7} */
#define MBEDTLS_OID_EC_GRP_BP256R1 MBEDTLS_OID_EC_BRAINPOOL_V1 "\x07"
/* brainpoolP384r1 OBJECT IDENTIFIER ::= {versionOne 11} */
#define MBEDTLS_OID_EC_GRP_BP384R1 MBEDTLS_OID_EC_BRAINPOOL_V1 "\x0B"
/* brainpoolP512r1 OBJECT IDENTIFIER ::= {versionOne 13} */
#define MBEDTLS_OID_EC_GRP_BP512R1 MBEDTLS_OID_EC_BRAINPOOL_V1 "\x0D"
/*
* SEC1 C.1
*
* prime-field OBJECT IDENTIFIER ::= { id-fieldType 1 }
* id-fieldType OBJECT IDENTIFIER ::= { ansi-X9-62 fieldType(1)}
*/
#define MBEDTLS_OID_ANSI_X9_62_FIELD_TYPE MBEDTLS_OID_ANSI_X9_62 "\x01"
#define MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD MBEDTLS_OID_ANSI_X9_62_FIELD_TYPE "\x01"
/*
* ECDSA signature identifiers, from RFC 5480
*/
#define MBEDTLS_OID_ANSI_X9_62_SIG MBEDTLS_OID_ANSI_X9_62 "\x04" /* signatures(4) */
#define MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 MBEDTLS_OID_ANSI_X9_62_SIG "\x03" /* ecdsa-with-SHA2(3) */
/* ecdsa-with-SHA1 OBJECT IDENTIFIER ::= {
* iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) 1 } */
#define MBEDTLS_OID_ECDSA_SHA1 MBEDTLS_OID_ANSI_X9_62_SIG "\x01"
/* ecdsa-with-SHA224 OBJECT IDENTIFIER ::= {
* iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4)
* ecdsa-with-SHA2(3) 1 } */
#define MBEDTLS_OID_ECDSA_SHA224 MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 "\x01"
/* ecdsa-with-SHA256 OBJECT IDENTIFIER ::= {
* iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4)
* ecdsa-with-SHA2(3) 2 } */
#define MBEDTLS_OID_ECDSA_SHA256 MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 "\x02"
/* ecdsa-with-SHA384 OBJECT IDENTIFIER ::= {
* iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4)
* ecdsa-with-SHA2(3) 3 } */
#define MBEDTLS_OID_ECDSA_SHA384 MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 "\x03"
/* ecdsa-with-SHA512 OBJECT IDENTIFIER ::= {
* iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4)
* ecdsa-with-SHA2(3) 4 } */
#define MBEDTLS_OID_ECDSA_SHA512 MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 "\x04"
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Base OID descriptor structure
*/
typedef struct {
const char *asn1; /*!< OID ASN.1 representation */
size_t asn1_len; /*!< length of asn1 */
const char *name; /*!< official name (e.g. from RFC) */
const char *description; /*!< human friendly description */
} mbedtls_oid_descriptor_t;
/**
* \brief Translate an ASN.1 OID into its numeric representation
* (e.g. "\x2A\x86\x48\x86\xF7\x0D" into "1.2.840.113549")
*
* \param buf buffer to put representation in
* \param size size of the buffer
* \param oid OID to translate
*
* \return Length of the string written (excluding final NULL) or
* MBEDTLS_ERR_OID_BUF_TOO_SMALL in case of error
*/
int mbedtls_oid_get_numeric_string( char *buf, size_t size, const mbedtls_asn1_buf *oid );
#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C)
/**
* \brief Translate an X.509 extension OID into local values
*
* \param oid OID to use
* \param ext_type place to store the extension type
*
* \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
*/
int mbedtls_oid_get_x509_ext_type( const mbedtls_asn1_buf *oid, int *ext_type );
#endif
/**
* \brief Translate an X.509 attribute type OID into the short name
* (e.g. the OID for an X520 Common Name into "CN")
*
* \param oid OID to use
* \param short_name place to store the string pointer
*
* \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
*/
int mbedtls_oid_get_attr_short_name( const mbedtls_asn1_buf *oid, const char **short_name );
/**
* \brief Translate PublicKeyAlgorithm OID into pk_type
*
* \param oid OID to use
* \param pk_alg place to store public key algorithm
*
* \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
*/
int mbedtls_oid_get_pk_alg( const mbedtls_asn1_buf *oid, mbedtls_pk_type_t *pk_alg );
/**
* \brief Translate pk_type into PublicKeyAlgorithm OID
*
* \param pk_alg Public key type to look for
* \param oid place to store ASN.1 OID string pointer
* \param olen length of the OID
*
* \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
*/
int mbedtls_oid_get_oid_by_pk_alg( mbedtls_pk_type_t pk_alg,
const char **oid, size_t *olen );
#if defined(MBEDTLS_ECP_C)
/**
* \brief Translate NamedCurve OID into an EC group identifier
*
* \param oid OID to use
* \param grp_id place to store group id
*
* \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
*/
int mbedtls_oid_get_ec_grp( const mbedtls_asn1_buf *oid, mbedtls_ecp_group_id *grp_id );
/**
* \brief Translate EC group identifier into NamedCurve OID
*
* \param grp_id EC group identifier
* \param oid place to store ASN.1 OID string pointer
* \param olen length of the OID
*
* \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
*/
int mbedtls_oid_get_oid_by_ec_grp( mbedtls_ecp_group_id grp_id,
const char **oid, size_t *olen );
#endif /* MBEDTLS_ECP_C */
#if defined(MBEDTLS_MD_C)
/**
* \brief Translate SignatureAlgorithm OID into md_type and pk_type
*
* \param oid OID to use
* \param md_alg place to store message digest algorithm
* \param pk_alg place to store public key algorithm
*
* \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
*/
int mbedtls_oid_get_sig_alg( const mbedtls_asn1_buf *oid,
mbedtls_md_type_t *md_alg, mbedtls_pk_type_t *pk_alg );
/**
* \brief Translate SignatureAlgorithm OID into description
*
* \param oid OID to use
* \param desc place to store string pointer
*
* \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
*/
int mbedtls_oid_get_sig_alg_desc( const mbedtls_asn1_buf *oid, const char **desc );
/**
* \brief Translate md_type and pk_type into SignatureAlgorithm OID
*
* \param md_alg message digest algorithm
* \param pk_alg public key algorithm
* \param oid place to store ASN.1 OID string pointer
* \param olen length of the OID
*
* \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
*/
int mbedtls_oid_get_oid_by_sig_alg( mbedtls_pk_type_t pk_alg, mbedtls_md_type_t md_alg,
const char **oid, size_t *olen );
/**
* \brief Translate hash algorithm OID into md_type
*
* \param oid OID to use
* \param md_alg place to store message digest algorithm
*
* \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
*/
int mbedtls_oid_get_md_alg( const mbedtls_asn1_buf *oid, mbedtls_md_type_t *md_alg );
#endif /* MBEDTLS_MD_C */
/**
* \brief Translate Extended Key Usage OID into description
*
* \param oid OID to use
* \param desc place to store string pointer
*
* \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
*/
int mbedtls_oid_get_extended_key_usage( const mbedtls_asn1_buf *oid, const char **desc );
/**
* \brief Translate md_type into hash algorithm OID
*
* \param md_alg message digest algorithm
* \param oid place to store ASN.1 OID string pointer
* \param olen length of the OID
*
* \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
*/
int mbedtls_oid_get_oid_by_md( mbedtls_md_type_t md_alg, const char **oid, size_t *olen );
#if defined(MBEDTLS_CIPHER_C)
/**
* \brief Translate encryption algorithm OID into cipher_type
*
* \param oid OID to use
* \param cipher_alg place to store cipher algorithm
*
* \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
*/
int mbedtls_oid_get_cipher_alg( const mbedtls_asn1_buf *oid, mbedtls_cipher_type_t *cipher_alg );
#endif /* MBEDTLS_CIPHER_C */
#if defined(MBEDTLS_PKCS12_C)
/**
* \brief Translate PKCS#12 PBE algorithm OID into md_type and
* cipher_type
*
* \param oid OID to use
* \param md_alg place to store message digest algorithm
* \param cipher_alg place to store cipher algorithm
*
* \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
*/
int mbedtls_oid_get_pkcs12_pbe_alg( const mbedtls_asn1_buf *oid, mbedtls_md_type_t *md_alg,
mbedtls_cipher_type_t *cipher_alg );
#endif /* MBEDTLS_PKCS12_C */
#ifdef __cplusplus
}
#endif
#endif /* oid.h */
@@ -0,0 +1,701 @@
/**
* \file pk.h
*
* \brief Public Key abstraction layer
*/
/*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#ifndef MBEDTLS_PK_H
#define MBEDTLS_PK_H
#if !defined(MBEDTLS_CONFIG_FILE)
#include "config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#include "md.h"
#if defined(MBEDTLS_RSA_C)
#include "rsa.h"
#endif
#if defined(MBEDTLS_ECP_C)
#include "ecp.h"
#endif
#if defined(MBEDTLS_ECDSA_C)
#include "ecdsa.h"
#endif
#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
!defined(inline) && !defined(__cplusplus)
#define inline __inline
#endif
#define MBEDTLS_ERR_PK_ALLOC_FAILED -0x3F80 /**< Memory allocation failed. */
#define MBEDTLS_ERR_PK_TYPE_MISMATCH -0x3F00 /**< Type mismatch, eg attempt to encrypt with an ECDSA key */
#define MBEDTLS_ERR_PK_BAD_INPUT_DATA -0x3E80 /**< Bad input parameters to function. */
#define MBEDTLS_ERR_PK_FILE_IO_ERROR -0x3E00 /**< Read/write of file failed. */
#define MBEDTLS_ERR_PK_KEY_INVALID_VERSION -0x3D80 /**< Unsupported key version */
#define MBEDTLS_ERR_PK_KEY_INVALID_FORMAT -0x3D00 /**< Invalid key tag or value. */
#define MBEDTLS_ERR_PK_UNKNOWN_PK_ALG -0x3C80 /**< Key algorithm is unsupported (only RSA and EC are supported). */
#define MBEDTLS_ERR_PK_PASSWORD_REQUIRED -0x3C00 /**< Private key password can't be empty. */
#define MBEDTLS_ERR_PK_PASSWORD_MISMATCH -0x3B80 /**< Given private key password does not allow for correct decryption. */
#define MBEDTLS_ERR_PK_INVALID_PUBKEY -0x3B00 /**< The pubkey tag or value is invalid (only RSA and EC are supported). */
#define MBEDTLS_ERR_PK_INVALID_ALG -0x3A80 /**< The algorithm tag or value is invalid. */
#define MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE -0x3A00 /**< Elliptic curve is unsupported (only NIST curves are supported). */
#define MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE -0x3980 /**< Unavailable feature, e.g. RSA disabled for RSA key. */
#define MBEDTLS_ERR_PK_SIG_LEN_MISMATCH -0x3900 /**< The buffer contains a valid signature followed by more data. */
/* MBEDTLS_ERR_PK_HW_ACCEL_FAILED is deprecated and should not be used. */
#define MBEDTLS_ERR_PK_HW_ACCEL_FAILED -0x3880 /**< PK hardware accelerator failed. */
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Public key types
*/
typedef enum {
MBEDTLS_PK_NONE=0,
MBEDTLS_PK_RSA,
MBEDTLS_PK_ECKEY,
MBEDTLS_PK_ECKEY_DH,
MBEDTLS_PK_ECDSA,
MBEDTLS_PK_RSA_ALT,
MBEDTLS_PK_RSASSA_PSS,
} mbedtls_pk_type_t;
/**
* \brief Options for RSASSA-PSS signature verification.
* See \c mbedtls_rsa_rsassa_pss_verify_ext()
*/
typedef struct mbedtls_pk_rsassa_pss_options
{
mbedtls_md_type_t mgf1_hash_id;
int expected_salt_len;
} mbedtls_pk_rsassa_pss_options;
/**
* \brief Types for interfacing with the debug module
*/
typedef enum
{
MBEDTLS_PK_DEBUG_NONE = 0,
MBEDTLS_PK_DEBUG_MPI,
MBEDTLS_PK_DEBUG_ECP,
} mbedtls_pk_debug_type;
/**
* \brief Item to send to the debug module
*/
typedef struct mbedtls_pk_debug_item
{
mbedtls_pk_debug_type type;
const char *name;
void *value;
} mbedtls_pk_debug_item;
/** Maximum number of item send for debugging, plus 1 */
#define MBEDTLS_PK_DEBUG_MAX_ITEMS 3
/**
* \brief Public key information and operations
*/
typedef struct mbedtls_pk_info_t mbedtls_pk_info_t;
/**
* \brief Public key container
*/
typedef struct mbedtls_pk_context
{
const mbedtls_pk_info_t * pk_info; /**< Public key information */
void * pk_ctx; /**< Underlying public key context */
} mbedtls_pk_context;
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
/**
* \brief Context for resuming operations
*/
typedef struct
{
const mbedtls_pk_info_t * pk_info; /**< Public key information */
void * rs_ctx; /**< Underlying restart context */
} mbedtls_pk_restart_ctx;
#else /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
/* Now we can declare functions that take a pointer to that */
typedef void mbedtls_pk_restart_ctx;
#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
#if defined(MBEDTLS_RSA_C)
/**
* Quick access to an RSA context inside a PK context.
*
* \warning You must make sure the PK context actually holds an RSA context
* before using this function!
*/
static inline mbedtls_rsa_context *mbedtls_pk_rsa( const mbedtls_pk_context pk )
{
return( (mbedtls_rsa_context *) (pk).pk_ctx );
}
#endif /* MBEDTLS_RSA_C */
#if defined(MBEDTLS_ECP_C)
/**
* Quick access to an EC context inside a PK context.
*
* \warning You must make sure the PK context actually holds an EC context
* before using this function!
*/
static inline mbedtls_ecp_keypair *mbedtls_pk_ec( const mbedtls_pk_context pk )
{
return( (mbedtls_ecp_keypair *) (pk).pk_ctx );
}
#endif /* MBEDTLS_ECP_C */
#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT)
/**
* \brief Types for RSA-alt abstraction
*/
typedef int (*mbedtls_pk_rsa_alt_decrypt_func)( void *ctx, int mode, size_t *olen,
const unsigned char *input, unsigned char *output,
size_t output_max_len );
typedef int (*mbedtls_pk_rsa_alt_sign_func)( void *ctx,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
int mode, mbedtls_md_type_t md_alg, unsigned int hashlen,
const unsigned char *hash, unsigned char *sig );
typedef size_t (*mbedtls_pk_rsa_alt_key_len_func)( void *ctx );
#endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */
/**
* \brief Return information associated with the given PK type
*
* \param pk_type PK type to search for.
*
* \return The PK info associated with the type or NULL if not found.
*/
const mbedtls_pk_info_t *mbedtls_pk_info_from_type( mbedtls_pk_type_t pk_type );
/**
* \brief Initialize a mbedtls_pk_context (as NONE)
*/
void mbedtls_pk_init( mbedtls_pk_context *ctx );
/**
* \brief Free a mbedtls_pk_context
*/
void mbedtls_pk_free( mbedtls_pk_context *ctx );
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
/**
* \brief Initialize a restart context
*/
void mbedtls_pk_restart_init( mbedtls_pk_restart_ctx *ctx );
/**
* \brief Free the components of a restart context
*/
void mbedtls_pk_restart_free( mbedtls_pk_restart_ctx *ctx );
#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
/**
* \brief Initialize a PK context with the information given
* and allocates the type-specific PK subcontext.
*
* \param ctx Context to initialize. Must be empty (type NONE).
* \param info Information to use
*
* \return 0 on success,
* MBEDTLS_ERR_PK_BAD_INPUT_DATA on invalid input,
* MBEDTLS_ERR_PK_ALLOC_FAILED on allocation failure.
*
* \note For contexts holding an RSA-alt key, use
* \c mbedtls_pk_setup_rsa_alt() instead.
*/
int mbedtls_pk_setup( mbedtls_pk_context *ctx, const mbedtls_pk_info_t *info );
#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT)
/**
* \brief Initialize an RSA-alt context
*
* \param ctx Context to initialize. Must be empty (type NONE).
* \param key RSA key pointer
* \param decrypt_func Decryption function
* \param sign_func Signing function
* \param key_len_func Function returning key length in bytes
*
* \return 0 on success, or MBEDTLS_ERR_PK_BAD_INPUT_DATA if the
* context wasn't already initialized as RSA_ALT.
*
* \note This function replaces \c mbedtls_pk_setup() for RSA-alt.
*/
int mbedtls_pk_setup_rsa_alt( mbedtls_pk_context *ctx, void * key,
mbedtls_pk_rsa_alt_decrypt_func decrypt_func,
mbedtls_pk_rsa_alt_sign_func sign_func,
mbedtls_pk_rsa_alt_key_len_func key_len_func );
#endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */
/**
* \brief Get the size in bits of the underlying key
*
* \param ctx Context to use
*
* \return Key size in bits, or 0 on error
*/
size_t mbedtls_pk_get_bitlen( const mbedtls_pk_context *ctx );
/**
* \brief Get the length in bytes of the underlying key
* \param ctx Context to use
*
* \return Key length in bytes, or 0 on error
*/
static inline size_t mbedtls_pk_get_len( const mbedtls_pk_context *ctx )
{
return( ( mbedtls_pk_get_bitlen( ctx ) + 7 ) / 8 );
}
/**
* \brief Tell if a context can do the operation given by type
*
* \param ctx Context to test
* \param type Target type
*
* \return 0 if context can't do the operations,
* 1 otherwise.
*/
int mbedtls_pk_can_do( const mbedtls_pk_context *ctx, mbedtls_pk_type_t type );
/**
* \brief Verify signature (including padding if relevant).
*
* \param ctx PK context to use
* \param md_alg Hash algorithm used (see notes)
* \param hash Hash of the message to sign
* \param hash_len Hash length or 0 (see notes)
* \param sig Signature to verify
* \param sig_len Signature length
*
* \return 0 on success (signature is valid),
* #MBEDTLS_ERR_PK_SIG_LEN_MISMATCH if there is a valid
* signature in sig but its length is less than \p siglen,
* or a specific error code.
*
* \note For RSA keys, the default padding type is PKCS#1 v1.5.
* Use \c mbedtls_pk_verify_ext( MBEDTLS_PK_RSASSA_PSS, ... )
* to verify RSASSA_PSS signatures.
*
* \note If hash_len is 0, then the length associated with md_alg
* is used instead, or an error returned if it is invalid.
*
* \note md_alg may be MBEDTLS_MD_NONE, only if hash_len != 0
*/
int mbedtls_pk_verify( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg,
const unsigned char *hash, size_t hash_len,
const unsigned char *sig, size_t sig_len );
/**
* \brief Restartable version of \c mbedtls_pk_verify()
*
* \note Performs the same job as \c mbedtls_pk_verify(), but can
* return early and restart according to the limit set with
* \c mbedtls_ecp_set_max_ops() to reduce blocking for ECC
* operations. For RSA, same as \c mbedtls_pk_verify().
*
* \param ctx PK context to use
* \param md_alg Hash algorithm used (see notes)
* \param hash Hash of the message to sign
* \param hash_len Hash length or 0 (see notes)
* \param sig Signature to verify
* \param sig_len Signature length
* \param rs_ctx Restart context (NULL to disable restart)
*
* \return See \c mbedtls_pk_verify(), or
* \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of
* operations was reached: see \c mbedtls_ecp_set_max_ops().
*/
int mbedtls_pk_verify_restartable( mbedtls_pk_context *ctx,
mbedtls_md_type_t md_alg,
const unsigned char *hash, size_t hash_len,
const unsigned char *sig, size_t sig_len,
mbedtls_pk_restart_ctx *rs_ctx );
/**
* \brief Verify signature, with options.
* (Includes verification of the padding depending on type.)
*
* \param type Signature type (inc. possible padding type) to verify
* \param options Pointer to type-specific options, or NULL
* \param ctx PK context to use
* \param md_alg Hash algorithm used (see notes)
* \param hash Hash of the message to sign
* \param hash_len Hash length or 0 (see notes)
* \param sig Signature to verify
* \param sig_len Signature length
*
* \return 0 on success (signature is valid),
* #MBEDTLS_ERR_PK_TYPE_MISMATCH if the PK context can't be
* used for this type of signatures,
* #MBEDTLS_ERR_PK_SIG_LEN_MISMATCH if there is a valid
* signature in sig but its length is less than \p siglen,
* or a specific error code.
*
* \note If hash_len is 0, then the length associated with md_alg
* is used instead, or an error returned if it is invalid.
*
* \note md_alg may be MBEDTLS_MD_NONE, only if hash_len != 0
*
* \note If type is MBEDTLS_PK_RSASSA_PSS, then options must point
* to a mbedtls_pk_rsassa_pss_options structure,
* otherwise it must be NULL.
*/
int mbedtls_pk_verify_ext( mbedtls_pk_type_t type, const void *options,
mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg,
const unsigned char *hash, size_t hash_len,
const unsigned char *sig, size_t sig_len );
/**
* \brief Make signature, including padding if relevant.
*
* \param ctx PK context to use - must hold a private key
* \param md_alg Hash algorithm used (see notes)
* \param hash Hash of the message to sign
* \param hash_len Hash length or 0 (see notes)
* \param sig Place to write the signature
* \param sig_len Number of bytes written
* \param f_rng RNG function
* \param p_rng RNG parameter
*
* \return 0 on success, or a specific error code.
*
* \note For RSA keys, the default padding type is PKCS#1 v1.5.
* There is no interface in the PK module to make RSASSA-PSS
* signatures yet.
*
* \note If hash_len is 0, then the length associated with md_alg
* is used instead, or an error returned if it is invalid.
*
* \note For RSA, md_alg may be MBEDTLS_MD_NONE if hash_len != 0.
* For ECDSA, md_alg may never be MBEDTLS_MD_NONE.
*/
int mbedtls_pk_sign( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg,
const unsigned char *hash, size_t hash_len,
unsigned char *sig, size_t *sig_len,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng );
/**
* \brief Restartable version of \c mbedtls_pk_sign()
*
* \note Performs the same job as \c mbedtls_pk_sign(), but can
* return early and restart according to the limit set with
* \c mbedtls_ecp_set_max_ops() to reduce blocking for ECC
* operations. For RSA, same as \c mbedtls_pk_sign().
*
* \param ctx PK context to use - must hold a private key
* \param md_alg Hash algorithm used (see notes)
* \param hash Hash of the message to sign
* \param hash_len Hash length or 0 (see notes)
* \param sig Place to write the signature
* \param sig_len Number of bytes written
* \param f_rng RNG function
* \param p_rng RNG parameter
* \param rs_ctx Restart context (NULL to disable restart)
*
* \return See \c mbedtls_pk_sign(), or
* \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of
* operations was reached: see \c mbedtls_ecp_set_max_ops().
*/
int mbedtls_pk_sign_restartable( mbedtls_pk_context *ctx,
mbedtls_md_type_t md_alg,
const unsigned char *hash, size_t hash_len,
unsigned char *sig, size_t *sig_len,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
mbedtls_pk_restart_ctx *rs_ctx );
/**
* \brief Decrypt message (including padding if relevant).
*
* \param ctx PK context to use - must hold a private key
* \param input Input to decrypt
* \param ilen Input size
* \param output Decrypted output
* \param olen Decrypted message length
* \param osize Size of the output buffer
* \param f_rng RNG function
* \param p_rng RNG parameter
*
* \note For RSA keys, the default padding type is PKCS#1 v1.5.
*
* \return 0 on success, or a specific error code.
*/
int mbedtls_pk_decrypt( mbedtls_pk_context *ctx,
const unsigned char *input, size_t ilen,
unsigned char *output, size_t *olen, size_t osize,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng );
/**
* \brief Encrypt message (including padding if relevant).
*
* \param ctx PK context to use
* \param input Message to encrypt
* \param ilen Message size
* \param output Encrypted output
* \param olen Encrypted output length
* \param osize Size of the output buffer
* \param f_rng RNG function
* \param p_rng RNG parameter
*
* \note For RSA keys, the default padding type is PKCS#1 v1.5.
*
* \return 0 on success, or a specific error code.
*/
int mbedtls_pk_encrypt( mbedtls_pk_context *ctx,
const unsigned char *input, size_t ilen,
unsigned char *output, size_t *olen, size_t osize,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng );
/**
* \brief Check if a public-private pair of keys matches.
*
* \param pub Context holding a public key.
* \param prv Context holding a private (and public) key.
*
* \return 0 on success or MBEDTLS_ERR_PK_BAD_INPUT_DATA
*/
int mbedtls_pk_check_pair( const mbedtls_pk_context *pub, const mbedtls_pk_context *prv );
/**
* \brief Export debug information
*
* \param ctx Context to use
* \param items Place to write debug items
*
* \return 0 on success or MBEDTLS_ERR_PK_BAD_INPUT_DATA
*/
int mbedtls_pk_debug( const mbedtls_pk_context *ctx, mbedtls_pk_debug_item *items );
/**
* \brief Access the type name
*
* \param ctx Context to use
*
* \return Type name on success, or "invalid PK"
*/
const char * mbedtls_pk_get_name( const mbedtls_pk_context *ctx );
/**
* \brief Get the key type
*
* \param ctx Context to use
*
* \return Type on success, or MBEDTLS_PK_NONE
*/
mbedtls_pk_type_t mbedtls_pk_get_type( const mbedtls_pk_context *ctx );
#if defined(MBEDTLS_PK_PARSE_C)
/** \ingroup pk_module */
/**
* \brief Parse a private key in PEM or DER format
*
* \param ctx key to be initialized
* \param key input buffer
* \param keylen size of the buffer
* (including the terminating null byte for PEM data)
* \param pwd password for decryption (optional)
* \param pwdlen size of the password
*
* \note On entry, ctx must be empty, either freshly initialised
* with mbedtls_pk_init() or reset with mbedtls_pk_free(). If you need a
* specific key type, check the result with mbedtls_pk_can_do().
*
* \note The key is also checked for correctness.
*
* \return 0 if successful, or a specific PK or PEM error code
*/
int mbedtls_pk_parse_key( mbedtls_pk_context *ctx,
const unsigned char *key, size_t keylen,
const unsigned char *pwd, size_t pwdlen );
/** \ingroup pk_module */
/**
* \brief Parse a public key in PEM or DER format
*
* \param ctx key to be initialized
* \param key input buffer
* \param keylen size of the buffer
* (including the terminating null byte for PEM data)
*
* \note On entry, ctx must be empty, either freshly initialised
* with mbedtls_pk_init() or reset with mbedtls_pk_free(). If you need a
* specific key type, check the result with mbedtls_pk_can_do().
*
* \note The key is also checked for correctness.
*
* \return 0 if successful, or a specific PK or PEM error code
*/
int mbedtls_pk_parse_public_key( mbedtls_pk_context *ctx,
const unsigned char *key, size_t keylen );
#if defined(MBEDTLS_FS_IO)
/** \ingroup pk_module */
/**
* \brief Load and parse a private key
*
* \param ctx key to be initialized
* \param path filename to read the private key from
* \param password password to decrypt the file (can be NULL)
*
* \note On entry, ctx must be empty, either freshly initialised
* with mbedtls_pk_init() or reset with mbedtls_pk_free(). If you need a
* specific key type, check the result with mbedtls_pk_can_do().
*
* \note The key is also checked for correctness.
*
* \return 0 if successful, or a specific PK or PEM error code
*/
int mbedtls_pk_parse_keyfile( mbedtls_pk_context *ctx,
const char *path, const char *password );
/** \ingroup pk_module */
/**
* \brief Load and parse a public key
*
* \param ctx key to be initialized
* \param path filename to read the public key from
*
* \note On entry, ctx must be empty, either freshly initialised
* with mbedtls_pk_init() or reset with mbedtls_pk_free(). If
* you need a specific key type, check the result with
* mbedtls_pk_can_do().
*
* \note The key is also checked for correctness.
*
* \return 0 if successful, or a specific PK or PEM error code
*/
int mbedtls_pk_parse_public_keyfile( mbedtls_pk_context *ctx, const char *path );
#endif /* MBEDTLS_FS_IO */
#endif /* MBEDTLS_PK_PARSE_C */
#if defined(MBEDTLS_PK_WRITE_C)
/**
* \brief Write a private key to a PKCS#1 or SEC1 DER structure
* Note: data is written at the end of the buffer! Use the
* return value to determine where you should start
* using the buffer
*
* \param ctx private to write away
* \param buf buffer to write to
* \param size size of the buffer
*
* \return length of data written if successful, or a specific
* error code
*/
int mbedtls_pk_write_key_der( mbedtls_pk_context *ctx, unsigned char *buf, size_t size );
/**
* \brief Write a public key to a SubjectPublicKeyInfo DER structure
* Note: data is written at the end of the buffer! Use the
* return value to determine where you should start
* using the buffer
*
* \param ctx public key to write away
* \param buf buffer to write to
* \param size size of the buffer
*
* \return length of data written if successful, or a specific
* error code
*/
int mbedtls_pk_write_pubkey_der( mbedtls_pk_context *ctx, unsigned char *buf, size_t size );
#if defined(MBEDTLS_PEM_WRITE_C)
/**
* \brief Write a public key to a PEM string
*
* \param ctx public key to write away
* \param buf buffer to write to
* \param size size of the buffer
*
* \return 0 if successful, or a specific error code
*/
int mbedtls_pk_write_pubkey_pem( mbedtls_pk_context *ctx, unsigned char *buf, size_t size );
/**
* \brief Write a private key to a PKCS#1 or SEC1 PEM string
*
* \param ctx private to write away
* \param buf buffer to write to
* \param size size of the buffer
*
* \return 0 if successful, or a specific error code
*/
int mbedtls_pk_write_key_pem( mbedtls_pk_context *ctx, unsigned char *buf, size_t size );
#endif /* MBEDTLS_PEM_WRITE_C */
#endif /* MBEDTLS_PK_WRITE_C */
/*
* WARNING: Low-level functions. You probably do not want to use these unless
* you are certain you do ;)
*/
#if defined(MBEDTLS_PK_PARSE_C)
/**
* \brief Parse a SubjectPublicKeyInfo DER structure
*
* \param p the position in the ASN.1 data
* \param end end of the buffer
* \param pk the key to fill
*
* \return 0 if successful, or a specific PK error code
*/
int mbedtls_pk_parse_subpubkey( unsigned char **p, const unsigned char *end,
mbedtls_pk_context *pk );
#endif /* MBEDTLS_PK_PARSE_C */
#if defined(MBEDTLS_PK_WRITE_C)
/**
* \brief Write a subjectPublicKey to ASN.1 data
* Note: function works backwards in data buffer
*
* \param p reference to current position pointer
* \param start start of the buffer (for bounds-checking)
* \param key public key to write away
*
* \return the length written or a negative error code
*/
int mbedtls_pk_write_pubkey( unsigned char **p, unsigned char *start,
const mbedtls_pk_context *key );
#endif /* MBEDTLS_PK_WRITE_C */
/*
* Internal module functions. You probably do not want to use these unless you
* know you do.
*/
#if defined(MBEDTLS_FS_IO)
int mbedtls_pk_load_file( const char *path, unsigned char **buf, size_t *n );
#endif
#ifdef __cplusplus
}
#endif
#endif /* MBEDTLS_PK_H */
@@ -0,0 +1,367 @@
/**
* \file platform.h
*
* \brief This file contains the definitions and functions of the
* Mbed TLS platform abstraction layer.
*
* The platform abstraction layer removes the need for the library
* to directly link to standard C library functions or operating
* system services, making the library easier to port and embed.
* Application developers and users of the library can provide their own
* implementations of these functions, or implementations specific to
* their platform, which can be statically linked to the library or
* dynamically configured at runtime.
*/
/*
* Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
* This file is part of Mbed TLS (https://tls.mbed.org)
*/
#ifndef MBEDTLS_PLATFORM_H
#define MBEDTLS_PLATFORM_H
#if !defined(MBEDTLS_CONFIG_FILE)
#include "config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_HAVE_TIME)
#include "platform_time.h"
#endif
#define MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED -0x0070 /**< Hardware accelerator failed */
#define MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED -0x0072 /**< The requested feature is not supported by the platform */
#ifdef __cplusplus
extern "C" {
#endif
/**
* \name SECTION: Module settings
*
* The configuration options you can set for this module are in this section.
* Either change them in config.h or define them on the compiler command line.
* \{
*/
#if !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS)
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#if !defined(MBEDTLS_PLATFORM_STD_SNPRINTF)
#if defined(_WIN32)
#define MBEDTLS_PLATFORM_STD_SNPRINTF mbedtls_platform_win32_snprintf /**< The default \c snprintf function to use. */
#else
#define MBEDTLS_PLATFORM_STD_SNPRINTF snprintf /**< The default \c snprintf function to use. */
#endif
#endif
#if !defined(MBEDTLS_PLATFORM_STD_PRINTF)
#define MBEDTLS_PLATFORM_STD_PRINTF printf /**< The default \c printf function to use. */
#endif
#if !defined(MBEDTLS_PLATFORM_STD_FPRINTF)
#define MBEDTLS_PLATFORM_STD_FPRINTF fprintf /**< The default \c fprintf function to use. */
#endif
#if !defined(MBEDTLS_PLATFORM_STD_CALLOC)
#define MBEDTLS_PLATFORM_STD_CALLOC calloc /**< The default \c calloc function to use. */
#endif
#if !defined(MBEDTLS_PLATFORM_STD_FREE)
#define MBEDTLS_PLATFORM_STD_FREE free /**< The default \c free function to use. */
#endif
#if !defined(MBEDTLS_PLATFORM_STD_EXIT)
#define MBEDTLS_PLATFORM_STD_EXIT exit /**< The default \c exit function to use. */
#endif
#if !defined(MBEDTLS_PLATFORM_STD_TIME)
#define MBEDTLS_PLATFORM_STD_TIME time /**< The default \c time function to use. */
#endif
#if !defined(MBEDTLS_PLATFORM_STD_EXIT_SUCCESS)
#define MBEDTLS_PLATFORM_STD_EXIT_SUCCESS EXIT_SUCCESS /**< The default exit value to use. */
#endif
#if !defined(MBEDTLS_PLATFORM_STD_EXIT_FAILURE)
#define MBEDTLS_PLATFORM_STD_EXIT_FAILURE EXIT_FAILURE /**< The default exit value to use. */
#endif
#if defined(MBEDTLS_FS_IO)
#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ)
#define MBEDTLS_PLATFORM_STD_NV_SEED_READ mbedtls_platform_std_nv_seed_read
#endif
#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE)
#define MBEDTLS_PLATFORM_STD_NV_SEED_WRITE mbedtls_platform_std_nv_seed_write
#endif
#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_FILE)
#define MBEDTLS_PLATFORM_STD_NV_SEED_FILE "seedfile"
#endif
#endif /* MBEDTLS_FS_IO */
#else /* MBEDTLS_PLATFORM_NO_STD_FUNCTIONS */
#if defined(MBEDTLS_PLATFORM_STD_MEM_HDR)
#include MBEDTLS_PLATFORM_STD_MEM_HDR
#endif
#endif /* MBEDTLS_PLATFORM_NO_STD_FUNCTIONS */
/* \} name SECTION: Module settings */
/*
* The function pointers for calloc and free.
*/
#if defined(MBEDTLS_PLATFORM_MEMORY)
#if defined(MBEDTLS_PLATFORM_FREE_MACRO) && \
defined(MBEDTLS_PLATFORM_CALLOC_MACRO)
#define mbedtls_free MBEDTLS_PLATFORM_FREE_MACRO
#define mbedtls_calloc MBEDTLS_PLATFORM_CALLOC_MACRO
#else
/* For size_t */
#include <stddef.h>
extern void *mbedtls_calloc( size_t n, size_t size );
extern void mbedtls_free( void *ptr );
/**
* \brief This function dynamically sets the memory-management
* functions used by the library, during runtime.
*
* \param calloc_func The \c calloc function implementation.
* \param free_func The \c free function implementation.
*
* \return \c 0.
*/
int mbedtls_platform_set_calloc_free( void * (*calloc_func)( size_t, size_t ),
void (*free_func)( void * ) );
#endif /* MBEDTLS_PLATFORM_FREE_MACRO && MBEDTLS_PLATFORM_CALLOC_MACRO */
#else /* !MBEDTLS_PLATFORM_MEMORY */
#define mbedtls_free free
#define mbedtls_calloc calloc
#endif /* MBEDTLS_PLATFORM_MEMORY && !MBEDTLS_PLATFORM_{FREE,CALLOC}_MACRO */
/*
* The function pointers for fprintf
*/
#if defined(MBEDTLS_PLATFORM_FPRINTF_ALT)
/* We need FILE * */
#include <stdio.h>
extern int (*mbedtls_fprintf)( FILE *stream, const char *format, ... );
/**
* \brief This function dynamically configures the fprintf
* function that is called when the
* mbedtls_fprintf() function is invoked by the library.
*
* \param fprintf_func The \c fprintf function implementation.
*
* \return \c 0.
*/
int mbedtls_platform_set_fprintf( int (*fprintf_func)( FILE *stream, const char *,
... ) );
#else
#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO)
#define mbedtls_fprintf MBEDTLS_PLATFORM_FPRINTF_MACRO
#else
#define mbedtls_fprintf fprintf
#endif /* MBEDTLS_PLATFORM_FPRINTF_MACRO */
#endif /* MBEDTLS_PLATFORM_FPRINTF_ALT */
/*
* The function pointers for printf
*/
#if defined(MBEDTLS_PLATFORM_PRINTF_ALT)
extern int (*mbedtls_printf)( const char *format, ... );
/**
* \brief This function dynamically configures the snprintf
* function that is called when the mbedtls_snprintf()
* function is invoked by the library.
*
* \param printf_func The \c printf function implementation.
*
* \return \c 0 on success.
*/
int mbedtls_platform_set_printf( int (*printf_func)( const char *, ... ) );
#else /* !MBEDTLS_PLATFORM_PRINTF_ALT */
#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO)
#define mbedtls_printf MBEDTLS_PLATFORM_PRINTF_MACRO
#else
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_PRINTF_MACRO */
#endif /* MBEDTLS_PLATFORM_PRINTF_ALT */
/*
* The function pointers for snprintf
*
* The snprintf implementation should conform to C99:
* - it *must* always correctly zero-terminate the buffer
* (except when n == 0, then it must leave the buffer untouched)
* - however it is acceptable to return -1 instead of the required length when
* the destination buffer is too short.
*/
#if defined(_WIN32)
/* For Windows (inc. MSYS2), we provide our own fixed implementation */
int mbedtls_platform_win32_snprintf( char *s, size_t n, const char *fmt, ... );
#endif
#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT)
extern int (*mbedtls_snprintf)( char * s, size_t n, const char * format, ... );
/**
* \brief This function allows configuring a custom
* \c snprintf function pointer.
*
* \param snprintf_func The \c snprintf function implementation.
*
* \return \c 0 on success.
*/
int mbedtls_platform_set_snprintf( int (*snprintf_func)( char * s, size_t n,
const char * format, ... ) );
#else /* MBEDTLS_PLATFORM_SNPRINTF_ALT */
#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO)
#define mbedtls_snprintf MBEDTLS_PLATFORM_SNPRINTF_MACRO
#else
#define mbedtls_snprintf MBEDTLS_PLATFORM_STD_SNPRINTF
#endif /* MBEDTLS_PLATFORM_SNPRINTF_MACRO */
#endif /* MBEDTLS_PLATFORM_SNPRINTF_ALT */
/*
* The function pointers for exit
*/
#if defined(MBEDTLS_PLATFORM_EXIT_ALT)
extern void (*mbedtls_exit)( int status );
/**
* \brief This function dynamically configures the exit
* function that is called when the mbedtls_exit()
* function is invoked by the library.
*
* \param exit_func The \c exit function implementation.
*
* \return \c 0 on success.
*/
int mbedtls_platform_set_exit( void (*exit_func)( int status ) );
#else
#if defined(MBEDTLS_PLATFORM_EXIT_MACRO)
#define mbedtls_exit MBEDTLS_PLATFORM_EXIT_MACRO
#else
#define mbedtls_exit exit
#endif /* MBEDTLS_PLATFORM_EXIT_MACRO */
#endif /* MBEDTLS_PLATFORM_EXIT_ALT */
/*
* The default exit values
*/
#if defined(MBEDTLS_PLATFORM_STD_EXIT_SUCCESS)
#define MBEDTLS_EXIT_SUCCESS MBEDTLS_PLATFORM_STD_EXIT_SUCCESS
#else
#define MBEDTLS_EXIT_SUCCESS 0
#endif
#if defined(MBEDTLS_PLATFORM_STD_EXIT_FAILURE)
#define MBEDTLS_EXIT_FAILURE MBEDTLS_PLATFORM_STD_EXIT_FAILURE
#else
#define MBEDTLS_EXIT_FAILURE 1
#endif
/*
* The function pointers for reading from and writing a seed file to
* Non-Volatile storage (NV) in a platform-independent way
*
* Only enabled when the NV seed entropy source is enabled
*/
#if defined(MBEDTLS_ENTROPY_NV_SEED)
#if !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS) && defined(MBEDTLS_FS_IO)
/* Internal standard platform definitions */
int mbedtls_platform_std_nv_seed_read( unsigned char *buf, size_t buf_len );
int mbedtls_platform_std_nv_seed_write( unsigned char *buf, size_t buf_len );
#endif
#if defined(MBEDTLS_PLATFORM_NV_SEED_ALT)
extern int (*mbedtls_nv_seed_read)( unsigned char *buf, size_t buf_len );
extern int (*mbedtls_nv_seed_write)( unsigned char *buf, size_t buf_len );
/**
* \brief This function allows configuring custom seed file writing and
* reading functions.
*
* \param nv_seed_read_func The seed reading function implementation.
* \param nv_seed_write_func The seed writing function implementation.
*
* \return \c 0 on success.
*/
int mbedtls_platform_set_nv_seed(
int (*nv_seed_read_func)( unsigned char *buf, size_t buf_len ),
int (*nv_seed_write_func)( unsigned char *buf, size_t buf_len )
);
#else
#if defined(MBEDTLS_PLATFORM_NV_SEED_READ_MACRO) && \
defined(MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO)
#define mbedtls_nv_seed_read MBEDTLS_PLATFORM_NV_SEED_READ_MACRO
#define mbedtls_nv_seed_write MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO
#else
#define mbedtls_nv_seed_read mbedtls_platform_std_nv_seed_read
#define mbedtls_nv_seed_write mbedtls_platform_std_nv_seed_write
#endif
#endif /* MBEDTLS_PLATFORM_NV_SEED_ALT */
#endif /* MBEDTLS_ENTROPY_NV_SEED */
#if !defined(MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT)
/**
* \brief The platform context structure.
*
* \note This structure may be used to assist platform-specific
* setup or teardown operations.
*/
typedef struct mbedtls_platform_context
{
char dummy; /**< A placeholder member, as empty structs are not portable. */
}
mbedtls_platform_context;
#else
#include "platform_alt.h"
#endif /* !MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT */
/**
* \brief This function performs any platform-specific initialization
* operations.
*
* \note This function should be called before any other library functions.
*
* Its implementation is platform-specific, and unless
* platform-specific code is provided, it does nothing.
*
* \note The usage and necessity of this function is dependent on the platform.
*
* \param ctx The platform context.
*
* \return \c 0 on success.
*/
int mbedtls_platform_setup( mbedtls_platform_context *ctx );
/**
* \brief This function performs any platform teardown operations.
*
* \note This function should be called after every other Mbed TLS module
* has been correctly freed using the appropriate free function.
*
* Its implementation is platform-specific, and unless
* platform-specific code is provided, it does nothing.
*
* \note The usage and necessity of this function is dependent on the platform.
*
* \param ctx The platform context.
*
*/
void mbedtls_platform_teardown( mbedtls_platform_context *ctx );
#ifdef __cplusplus
}
#endif
#endif /* platform.h */
@@ -0,0 +1,103 @@
/**
* \file platform_util.h
*
* \brief Common and shared functions used by multiple modules in the Mbed TLS
* library.
*/
/*
* Copyright (C) 2018, Arm Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
* This file is part of Mbed TLS (https://tls.mbed.org)
*/
#ifndef MBEDTLS_PLATFORM_UTIL_H
#define MBEDTLS_PLATFORM_UTIL_H
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#include <stddef.h>
#if defined(MBEDTLS_HAVE_TIME_DATE)
#include "mbedtls/platform_time.h"
#include <time.h>
#endif /* MBEDTLS_HAVE_TIME_DATE */
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Securely zeroize a buffer
*
* The function is meant to wipe the data contained in a buffer so
* that it can no longer be recovered even if the program memory
* is later compromised. Call this function on sensitive data
* stored on the stack before returning from a function, and on
* sensitive data stored on the heap before freeing the heap
* object.
*
* It is extremely difficult to guarantee that calls to
* mbedtls_platform_zeroize() are not removed by aggressive
* compiler optimizations in a portable way. For this reason, Mbed
* TLS provides the configuration option
* MBEDTLS_PLATFORM_ZEROIZE_ALT, which allows users to configure
* mbedtls_platform_zeroize() to use a suitable implementation for
* their platform and needs
*
* \param buf Buffer to be zeroized
* \param len Length of the buffer in bytes
*
*/
void mbedtls_platform_zeroize( void *buf, size_t len );
#if defined(MBEDTLS_HAVE_TIME_DATE)
/**
* \brief Platform-specific implementation of gmtime_r()
*
* The function is a thread-safe abstraction that behaves
* similarly to the gmtime_r() function from Unix/POSIX.
*
* Mbed TLS will try to identify the underlying platform and
* make use of an appropriate underlying implementation (e.g.
* gmtime_r() for POSIX and gmtime_s() for Windows). If this is
* not possible, then gmtime() will be used. In this case, calls
* from the library to gmtime() will be guarded by the mutex
* mbedtls_threading_gmtime_mutex if MBEDTLS_THREADING_C is
* enabled. It is recommended that calls from outside the library
* are also guarded by this mutex.
*
* If MBEDTLS_PLATFORM_GMTIME_R_ALT is defined, then Mbed TLS will
* unconditionally use the alternative implementation for
* mbedtls_platform_gmtime_r() supplied by the user at compile time.
*
* \param tt Pointer to an object containing time (in seconds) since the
* epoch to be converted
* \param tm_buf Pointer to an object where the results will be stored
*
* \return Pointer to an object of type struct tm on success, otherwise
* NULL
*/
struct tm *mbedtls_platform_gmtime_r( const mbedtls_time_t *tt,
struct tm *tm_buf );
#endif /* MBEDTLS_HAVE_TIME_DATE */
#ifdef __cplusplus
}
#endif
#endif /* MBEDTLS_PLATFORM_UTIL_H */
@@ -0,0 +1,122 @@
/**
* \file threading.h
*
* \brief Threading abstraction layer
*/
/*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#ifndef MBEDTLS_THREADING_H
#define MBEDTLS_THREADING_H
#if !defined(MBEDTLS_CONFIG_FILE)
#include "config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
/* MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE is deprecated and should not be
* used. */
#define MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE -0x001A /**< The selected feature is not available. */
#define MBEDTLS_ERR_THREADING_BAD_INPUT_DATA -0x001C /**< Bad input parameters to function. */
#define MBEDTLS_ERR_THREADING_MUTEX_ERROR -0x001E /**< Locking / unlocking / free failed with error code. */
#if defined(MBEDTLS_THREADING_PTHREAD)
#include <pthread.h>
typedef struct mbedtls_threading_mutex_t
{
pthread_mutex_t mutex;
char is_valid;
} mbedtls_threading_mutex_t;
#endif
#if defined(MBEDTLS_THREADING_ALT)
/* You should define the mbedtls_threading_mutex_t type in your header */
#include "threading_alt.h"
/**
* \brief Set your alternate threading implementation function
* pointers and initialize global mutexes. If used, this
* function must be called once in the main thread before any
* other mbed TLS function is called, and
* mbedtls_threading_free_alt() must be called once in the main
* thread after all other mbed TLS functions.
*
* \note mutex_init() and mutex_free() don't return a status code.
* If mutex_init() fails, it should leave its argument (the
* mutex) in a state such that mutex_lock() will fail when
* called with this argument.
*
* \param mutex_init the init function implementation
* \param mutex_free the free function implementation
* \param mutex_lock the lock function implementation
* \param mutex_unlock the unlock function implementation
*/
void mbedtls_threading_set_alt( void (*mutex_init)( mbedtls_threading_mutex_t * ),
void (*mutex_free)( mbedtls_threading_mutex_t * ),
int (*mutex_lock)( mbedtls_threading_mutex_t * ),
int (*mutex_unlock)( mbedtls_threading_mutex_t * ) );
/**
* \brief Free global mutexes.
*/
void mbedtls_threading_free_alt( void );
#endif /* MBEDTLS_THREADING_ALT */
#if defined(MBEDTLS_THREADING_C)
/*
* The function pointers for mutex_init, mutex_free, mutex_ and mutex_unlock
*
* All these functions are expected to work or the result will be undefined.
*/
extern void (*mbedtls_mutex_init)( mbedtls_threading_mutex_t *mutex );
extern void (*mbedtls_mutex_free)( mbedtls_threading_mutex_t *mutex );
extern int (*mbedtls_mutex_lock)( mbedtls_threading_mutex_t *mutex );
extern int (*mbedtls_mutex_unlock)( mbedtls_threading_mutex_t *mutex );
/*
* Global mutexes
*/
#if defined(MBEDTLS_FS_IO)
extern mbedtls_threading_mutex_t mbedtls_threading_readdir_mutex;
#endif
#if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_PLATFORM_GMTIME_R_ALT)
/* This mutex may or may not be used in the default definition of
* mbedtls_platform_gmtime_r(), but in order to determine that,
* we need to check POSIX features, hence modify _POSIX_C_SOURCE.
* With the current approach, this declaration is orphaned, lacking
* an accompanying definition, in case mbedtls_platform_gmtime_r()
* doesn't need it, but that's not a problem. */
extern mbedtls_threading_mutex_t mbedtls_threading_gmtime_mutex;
#endif /* MBEDTLS_HAVE_TIME_DATE && !MBEDTLS_PLATFORM_GMTIME_R_ALT */
#endif /* MBEDTLS_THREADING_C */
#ifdef __cplusplus
}
#endif
#endif /* threading.h */
@@ -0,0 +1,389 @@
/*
* Generic ASN.1 parsing
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_ASN1_PARSE_C)
#include "mbedtls/asn1.h"
#include "mbedtls/platform_util.h"
#include <string.h>
#if defined(MBEDTLS_BIGNUM_C)
#include "mbedtls/bignum.h"
#endif
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdlib.h>
#define mbedtls_calloc calloc
#define mbedtls_free free
#endif
/*
* ASN.1 DER decoding routines
*/
int mbedtls_asn1_get_len( unsigned char **p,
const unsigned char *end,
size_t *len )
{
if( ( end - *p ) < 1 )
return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
if( ( **p & 0x80 ) == 0 )
*len = *(*p)++;
else
{
switch( **p & 0x7F )
{
case 1:
if( ( end - *p ) < 2 )
return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
*len = (*p)[1];
(*p) += 2;
break;
case 2:
if( ( end - *p ) < 3 )
return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
*len = ( (size_t)(*p)[1] << 8 ) | (*p)[2];
(*p) += 3;
break;
case 3:
if( ( end - *p ) < 4 )
return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
*len = ( (size_t)(*p)[1] << 16 ) |
( (size_t)(*p)[2] << 8 ) | (*p)[3];
(*p) += 4;
break;
case 4:
if( ( end - *p ) < 5 )
return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
*len = ( (size_t)(*p)[1] << 24 ) | ( (size_t)(*p)[2] << 16 ) |
( (size_t)(*p)[3] << 8 ) | (*p)[4];
(*p) += 5;
break;
default:
return( MBEDTLS_ERR_ASN1_INVALID_LENGTH );
}
}
if( *len > (size_t) ( end - *p ) )
return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
return( 0 );
}
int mbedtls_asn1_get_tag( unsigned char **p,
const unsigned char *end,
size_t *len, int tag )
{
if( ( end - *p ) < 1 )
return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
if( **p != tag )
return( MBEDTLS_ERR_ASN1_UNEXPECTED_TAG );
(*p)++;
return( mbedtls_asn1_get_len( p, end, len ) );
}
int mbedtls_asn1_get_bool( unsigned char **p,
const unsigned char *end,
int *val )
{
int ret;
size_t len;
if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_BOOLEAN ) ) != 0 )
return( ret );
if( len != 1 )
return( MBEDTLS_ERR_ASN1_INVALID_LENGTH );
*val = ( **p != 0 ) ? 1 : 0;
(*p)++;
return( 0 );
}
int mbedtls_asn1_get_int( unsigned char **p,
const unsigned char *end,
int *val )
{
int ret;
size_t len;
if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 )
return( ret );
if( len == 0 || len > sizeof( int ) || ( **p & 0x80 ) != 0 )
return( MBEDTLS_ERR_ASN1_INVALID_LENGTH );
*val = 0;
while( len-- > 0 )
{
*val = ( *val << 8 ) | **p;
(*p)++;
}
return( 0 );
}
#if defined(MBEDTLS_BIGNUM_C)
int mbedtls_asn1_get_mpi( unsigned char **p,
const unsigned char *end,
mbedtls_mpi *X )
{
int ret;
size_t len;
if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 )
return( ret );
ret = mbedtls_mpi_read_binary( X, *p, len );
*p += len;
return( ret );
}
#endif /* MBEDTLS_BIGNUM_C */
int mbedtls_asn1_get_bitstring( unsigned char **p, const unsigned char *end,
mbedtls_asn1_bitstring *bs)
{
int ret;
/* Certificate type is a single byte bitstring */
if( ( ret = mbedtls_asn1_get_tag( p, end, &bs->len, MBEDTLS_ASN1_BIT_STRING ) ) != 0 )
return( ret );
/* Check length, subtract one for actual bit string length */
if( bs->len < 1 )
return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
bs->len -= 1;
/* Get number of unused bits, ensure unused bits <= 7 */
bs->unused_bits = **p;
if( bs->unused_bits > 7 )
return( MBEDTLS_ERR_ASN1_INVALID_LENGTH );
(*p)++;
/* Get actual bitstring */
bs->p = *p;
*p += bs->len;
if( *p != end )
return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
return( 0 );
}
/*
* Get a bit string without unused bits
*/
int mbedtls_asn1_get_bitstring_null( unsigned char **p, const unsigned char *end,
size_t *len )
{
int ret;
if( ( ret = mbedtls_asn1_get_tag( p, end, len, MBEDTLS_ASN1_BIT_STRING ) ) != 0 )
return( ret );
if( (*len)-- < 2 || *(*p)++ != 0 )
return( MBEDTLS_ERR_ASN1_INVALID_DATA );
return( 0 );
}
/*
* Parses and splits an ASN.1 "SEQUENCE OF <tag>"
*/
int mbedtls_asn1_get_sequence_of( unsigned char **p,
const unsigned char *end,
mbedtls_asn1_sequence *cur,
int tag)
{
int ret;
size_t len;
mbedtls_asn1_buf *buf;
/* Get main sequence tag */
if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
return( ret );
if( *p + len != end )
return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
while( *p < end )
{
buf = &(cur->buf);
buf->tag = **p;
if( ( ret = mbedtls_asn1_get_tag( p, end, &buf->len, tag ) ) != 0 )
return( ret );
buf->p = *p;
*p += buf->len;
/* Allocate and assign next pointer */
if( *p < end )
{
cur->next = (mbedtls_asn1_sequence*)mbedtls_calloc( 1,
sizeof( mbedtls_asn1_sequence ) );
if( cur->next == NULL )
return( MBEDTLS_ERR_ASN1_ALLOC_FAILED );
cur = cur->next;
}
}
/* Set final sequence entry's next pointer to NULL */
cur->next = NULL;
if( *p != end )
return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
return( 0 );
}
int mbedtls_asn1_get_alg( unsigned char **p,
const unsigned char *end,
mbedtls_asn1_buf *alg, mbedtls_asn1_buf *params )
{
int ret;
size_t len;
if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
return( ret );
if( ( end - *p ) < 1 )
return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
alg->tag = **p;
end = *p + len;
if( ( ret = mbedtls_asn1_get_tag( p, end, &alg->len, MBEDTLS_ASN1_OID ) ) != 0 )
return( ret );
alg->p = *p;
*p += alg->len;
if( *p == end )
{
mbedtls_platform_zeroize( params, sizeof(mbedtls_asn1_buf) );
return( 0 );
}
params->tag = **p;
(*p)++;
if( ( ret = mbedtls_asn1_get_len( p, end, &params->len ) ) != 0 )
return( ret );
params->p = *p;
*p += params->len;
if( *p != end )
return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
return( 0 );
}
int mbedtls_asn1_get_alg_null( unsigned char **p,
const unsigned char *end,
mbedtls_asn1_buf *alg )
{
int ret;
mbedtls_asn1_buf params;
memset( &params, 0, sizeof(mbedtls_asn1_buf) );
if( ( ret = mbedtls_asn1_get_alg( p, end, alg, &params ) ) != 0 )
return( ret );
if( ( params.tag != MBEDTLS_ASN1_NULL && params.tag != 0 ) || params.len != 0 )
return( MBEDTLS_ERR_ASN1_INVALID_DATA );
return( 0 );
}
void mbedtls_asn1_free_named_data( mbedtls_asn1_named_data *cur )
{
if( cur == NULL )
return;
mbedtls_free( cur->oid.p );
mbedtls_free( cur->val.p );
mbedtls_platform_zeroize( cur, sizeof( mbedtls_asn1_named_data ) );
}
void mbedtls_asn1_free_named_data_list( mbedtls_asn1_named_data **head )
{
mbedtls_asn1_named_data *cur;
while( ( cur = *head ) != NULL )
{
*head = cur->next;
mbedtls_asn1_free_named_data( cur );
mbedtls_free( cur );
}
}
mbedtls_asn1_named_data *mbedtls_asn1_find_named_data( mbedtls_asn1_named_data *list,
const char *oid, size_t len )
{
while( list != NULL )
{
if( list->oid.len == len &&
memcmp( list->oid.p, oid, len ) == 0 )
{
break;
}
list = list->next;
}
return( list );
}
#endif /* MBEDTLS_ASN1_PARSE_C */
@@ -0,0 +1,135 @@
/*
* Common and shared functions used by multiple modules in the Mbed TLS
* library.
*
* Copyright (C) 2018, Arm Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
* This file is part of Mbed TLS (https://tls.mbed.org)
*/
/*
* Ensure gmtime_r is available even with -std=c99; must be defined before
* config.h, which pulls in glibc's features.h. Harmless on other platforms.
*/
#if !defined(_POSIX_C_SOURCE)
#define _POSIX_C_SOURCE 200112L
#endif
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#include "mbedtls/platform_util.h"
#include "mbedtls/threading.h"
#include <stddef.h>
#include <string.h>
#if !defined(MBEDTLS_PLATFORM_ZEROIZE_ALT)
/*
* This implementation should never be optimized out by the compiler
*
* This implementation for mbedtls_platform_zeroize() was inspired from Colin
* Percival's blog article at:
*
* http://www.daemonology.net/blog/2014-09-04-how-to-zero-a-buffer.html
*
* It uses a volatile function pointer to the standard memset(). Because the
* pointer is volatile the compiler expects it to change at
* any time and will not optimize out the call that could potentially perform
* other operations on the input buffer instead of just setting it to 0.
* Nevertheless, as pointed out by davidtgoldblatt on Hacker News
* (refer to http://www.daemonology.net/blog/2014-09-05-erratum.html for
* details), optimizations of the following form are still possible:
*
* if( memset_func != memset )
* memset_func( buf, 0, len );
*
* Note that it is extremely difficult to guarantee that
* mbedtls_platform_zeroize() will not be optimized out by aggressive compilers
* in a portable way. For this reason, Mbed TLS also provides the configuration
* option MBEDTLS_PLATFORM_ZEROIZE_ALT, which allows users to configure
* mbedtls_platform_zeroize() to use a suitable implementation for their
* platform and needs.
*/
static void * (* const volatile memset_func)( void *, int, size_t ) = memset;
void mbedtls_platform_zeroize( void *buf, size_t len )
{
memset_func( buf, 0, len );
}
#endif /* MBEDTLS_PLATFORM_ZEROIZE_ALT */
#if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_PLATFORM_GMTIME_R_ALT)
#include <time.h>
#if !defined(_WIN32) && (defined(unix) || \
defined(__unix) || defined(__unix__) || (defined(__APPLE__) && \
defined(__MACH__)))
#include <unistd.h>
#endif /* !_WIN32 && (unix || __unix || __unix__ ||
* (__APPLE__ && __MACH__)) */
#if !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) || \
( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) && \
_POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) )
/*
* This is a convenience shorthand macro to avoid checking the long
* preprocessor conditions above. Ideally, we could expose this macro in
* platform_util.h and simply use it in platform_util.c, threading.c and
* threading.h. However, this macro is not part of the Mbed TLS public API, so
* we keep it private by only defining it in this file
*/
#if ! ( defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) )
#define PLATFORM_UTIL_USE_GMTIME
#endif /* ! ( defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) ) */
#endif /* !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) || \
( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) && \
_POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) ) */
struct tm *mbedtls_platform_gmtime_r( const mbedtls_time_t *tt,
struct tm *tm_buf )
{
#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
return( ( gmtime_s( tm_buf, tt ) == 0 ) ? tm_buf : NULL );
#elif !defined(PLATFORM_UTIL_USE_GMTIME)
return( gmtime_r( tt, tm_buf ) );
#else
struct tm *lt;
#if defined(MBEDTLS_THREADING_C)
if( mbedtls_mutex_lock( &mbedtls_threading_gmtime_mutex ) != 0 )
return( NULL );
#endif /* MBEDTLS_THREADING_C */
lt = gmtime( tt );
if( lt != NULL )
{
memcpy( tm_buf, lt, sizeof( struct tm ) );
}
#if defined(MBEDTLS_THREADING_C)
if( mbedtls_mutex_unlock( &mbedtls_threading_gmtime_mutex ) != 0 )
return( NULL );
#endif /* MBEDTLS_THREADING_C */
return( ( lt == NULL ) ? NULL : tm_buf );
#endif /* _WIN32 && !EFIX64 && !EFI32 */
}
#endif /* MBEDTLS_HAVE_TIME_DATE && MBEDTLS_PLATFORM_GMTIME_R_ALT */
@@ -0,0 +1,207 @@
/*
* Copyright (c) 2015-2023, Texas Instruments Incorporated
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "msp-crypto/msp_crypto.h"
#include <stdint.h>
#include "mcuboot_config/mcuboot_logging.h"
#include "string.h"
#include "sha256sw.h"
#include "ECCSW.h"
#include "scalarMul.h"
#define MAXLEN 8 // for NIST-256
#define KEYLEN 32 // in bytes
#define ECDSA_SHA_TEMPWORKSZONE_LEN (6 * KEYLEN)
/* NIST p256 curve parameters, DO NOT EDIT */
const uint32_t NIST256_p[MAXLEN + 1] = {8ul, 4294967295ul, 4294967295ul,
4294967295ul, 0ul, 0ul, 0ul, 1ul, 4294967295ul};
const uint32_t NIST256_r[MAXLEN + 1] = {8ul, 4234356049ul, 4089039554ul,
2803342980ul, 3169254061ul, 4294967295ul, 4294967295ul, 0ul, 4294967295ul};
const uint32_t NIST256_a[MAXLEN + 1] = {8ul, 4294967292ul, 4294967295ul,
4294967295ul, 0ul, 0ul, 0ul, 1ul, 4294967295ul};
const uint32_t NIST256_b[MAXLEN + 1] = {8ul, 668098635ul, 1003371582ul,
3428036854ul, 1696401072ul, 1989707452ul, 3018571093ul, 2855965671ul,
1522939352ul};
const uint32_t NIST256_Gx[MAXLEN + 1] = {8ul, 3633889942ul, 4104206661ul,
770388896ul, 1996717441ul, 1671708914ul, 4173129445ul, 3777774151ul,
1796723186ul};
const uint32_t NIST256_Gy[MAXLEN + 1] = {8ul, 935285237ul, 3417718888ul,
1798397646ul, 734933847ul, 2081398294ul, 2397563722ul, 4263149467ul,
1340293858ul};
/* SHA256 Objects */
SHA256SW_Object sha256SWObject;
SHA256SW_Handle sha256SWHandle = &sha256SWObject;
int_fast16_t sha2SWresult;
uint32_t finalDigest[8];
/* ECC Workzone declared
*
* Size considerations:
* Window Size: 2 (currently used and non adjustable)
* Maximum workzone size: 904 (0x388)
*
*/
uint32_t ecc_workzone[ECC_WORKZONE_SIZE / sizeof(uint32_t)];
/* ECC Defines */
uint8_t ret;
uint32_t len;
volatile uint32_t err = 0;
volatile uint8_t j, w;
ECC_State ecc_state;
void copy(uint8_t *to, const uint8_t *from, int len)
{
for (int i = 0; i < len; i++) {
to[i] = from[i];
}
}
/*********************************************************************
* @fn reverseOrder
* @brief Reverse the byte order and copy to output buffer
*
* @param pBufIn - pointer to input buffer
* @param pBufOut - pointer to output buffer
*/
static void reverseOrder(const uint8_t *pBufIn, uint8_t *pBufOut)
{
uint8_t i = 0;
uint32_t sign_length = 32;
for (i = 0; i < sign_length; i++) {
pBufOut[i] = pBufIn[sign_length - 1 - i];
}
}
/*********************************************************************
* @fn copyBytes
* @brief Copy data between memory locatins
*
* @param pDst - pointer to destination buffer
* @param pSrc - pointer to source buffer
* @param len - length of data to be copied
*/
static void copyBytes(uint8_t *pDst, const uint8_t *pSrc, uint32_t len)
{
uint32_t i;
for (i = 0; i < len; i++) {
pDst[i] = pSrc[i];
}
}
void MSPCrypto_sha256_init(void)
{
sha2SWresult = SHA256SW_start(sha256SWHandle, SHA2SW_HASH_TYPE_256);
}
void MSPCrypto_sha256_drop(void)
{
SHA256SW_cancel(sha256SWHandle);
return;
}
int MSPCrypto_sha256_update(const void *data, uint32_t data_len)
{
if (sha2SWresult == SHA2SW_STATUS_SUCCESS) {
sha2SWresult = SHA256SW_addData(sha256SWHandle, data, data_len);
}
return sha2SWresult;
}
int MSPCrypto_sha256_finish(uint8_t *output)
{
if (sha2SWresult == SHA2SW_STATUS_SUCCESS) {
sha2SWresult = SHA256SW_finalize(sha256SWHandle, (uint32_t *) output);
}
return sha2SWresult;
}
void MSPCrypto_ecdsa_p256_init(void)
{
ecc_state.data_p = NIST256_p;
ecc_state.data_r = NIST256_r;
ecc_state.data_a = NIST256_a;
ecc_state.data_b = NIST256_b;
ecc_state.data_Gx = NIST256_Gx;
ecc_state.data_Gy = NIST256_Gy;
ecc_state.workzone = ecc_workzone;
ecc_state.win = SECURE_FW_ECC_WINDOW_SIZE;
}
void MSPCrypto_ecdsa_p256_drop(void)
{
/* Nothing required to drop */
return;
}
int MSPCrypto_ecdsa_p256_verify(
const uint8_t *pk, const uint8_t *hash, const uint8_t *sig)
{
/* Key comes in pre-processed from DER format with x coordinate, then y. */
uint32_t publicKeyXBuf[MAXLEN + 1] = {0};
uint32_t publicKeyYBuf[MAXLEN + 1] = {0};
uint32_t digest[MAXLEN + 1] = {0};
uint32_t sign1[MAXLEN + 1] = {0};
uint32_t sign2[MAXLEN + 1] = {0};
uint32_t ret;
/* ECC library expects inputs in uint32_t format, whereas mcuboot provides
* byte length. Set length accordingly */
publicKeyXBuf[0] = KEYLEN / 4;
reverseOrder(pk, (uint8_t *) &publicKeyXBuf[1]);
publicKeyYBuf[0] = KEYLEN / 4;
reverseOrder(pk + KEYLEN, (uint8_t *) &publicKeyYBuf[1]);
digest[0] = KEYLEN / 4;
reverseOrder(hash, (uint8_t *) &digest[1]);
sign1[0] = KEYLEN / 4;
reverseOrder(sig, (uint8_t *) &sign1[1]);
sign2[0] = KEYLEN / 4;
reverseOrder(sig + KEYLEN, (uint8_t *) &sign2[1]);
ret = ECCSW_ECDSAVerify(
&ecc_state, publicKeyXBuf, publicKeyYBuf, digest, sign1, sign2);
if (ret != STATUS_ECDSA_VALID_SIGNATURE) {
MCUBOOT_LOG_ERR("MSPCrypto_ecdsa_p256_verify: fail");
return -1;
}
return 0;
}
@@ -0,0 +1,131 @@
/*
* Copyright (c) 2015-2023, Texas Instruments Incorporated
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __TI_MSP_CRYPTO_H__
#define __TI_MSP_CRYPTO_H__
#include <stdint.h>
#include "sha256sw.h"
/*********************************************************************
* GLOBAL VARIABLES
*/
/*********************************************************************
* MACROS
*/
/* ECC Window Size. Determines speed and workzone size of ECC operations.
Recommended setting is 3. */
/*
* Measured workspace memory size with the corresponding measured measured workzone usage
*
* Window Size: 2 max Workzone 904 (0x388)
* Window Size: 3 max Workzone size: 1012 (0x3F4)
* Window Size: 4 max Workzone size: 1228 (0x4CC)
* Window Size: 5 max Workzone size: 1660 (0x67C)
*
* Recommended to add some safety factor for buffer overflow
* ex: window size 2, use size 960/3C0
* */
#define SECURE_FW_ECC_WINDOW_SIZE 2
#define ECC_WORKZONE_SIZE 960
/*! Invalid ECC Signature */
#define SECURE_FW_ECC_STATUS_INVALID_SIGNATURE 0x5A
/*! ECC Signature Successfully Verified */
#define SECURE_FW_ECC_STATUS_VALID_SIGNATURE 0xA5
#define ECDSA_KEY_LEN 32 //!< Length of the ECDSA security key
#define ECDSA_SHA_TEMPWORKZONE_LEN \
ECDSA_KEY_LEN * \
6 //!< space for six buffers finalHash, reverseHash, pubkeyX, pubKeyY, sign1, sign2
/* Offset value for number of bytes occupied by length field */
#define SECURE_FW_ECC_KEY_OFFSET 4
/* Offset of Key Length field */
#define SECURE_FW_ECC_KEY_LEN_OFFSET 0
/*!
* ECC key length in bytes for NIST P-256 keys.
*/
#define SECURE_FW_ECC_NIST_P256_KEY_LEN_IN_BYTES 32
/*!
* ECC Workzone length in bytes for NIST P-256 key and shared secret generation.
* For use with ECC Window Size 3 only. Used to store intermediary values in
* ECC calculations. */
#define BIM_ECC_NIST_P256_WORKZONE_LEN_IN_BYTES 1100
#ifndef SECURE_FW_ECC_NIST_P256_WORKZONE_LEN_IN_BYTES
#define SECURE_FW_ECC_NIST_P256_WORKZONE_LEN_IN_BYTES \
(BIM_ECC_NIST_P256_WORKZONE_LEN_IN_BYTES)
#endif
/*! Length of Sign */
#define SECURE_FW_SIGN_LEN 32
/* Total buffer size */
#define SECURE_FW_ECC_BUF_TOTAL_LEN(len) ((len) + SECURE_FW_ECC_KEY_OFFSET)
/* Key size in uint32_t blocks */
#define SECURE_FW_ECC_UINT32_BLK_LEN(len) (((len) + 3) / 4)
/* Return Codes for the SHA256 */
#define MSP_CRYPTO_SHA256_STATUS_SUCCESS SHA2SW_STATUS_SUCCESS
#define MSP_CRYPTO_SHA256_STATUS_ERROR SHA2SW_STATUS_ERROR
#define MSP_CRYPTO_SHA256_STATUS_UNSUPPORTED SHA2SW_STATUS_UNSUPPORTED
#define MSP_CRYPTO_SHA256_STATUS_LENGTH_TOO_LARGE SHA2SW_STATUS_LENGTH_TOO_LARGE
#define MSP_CRYPTO_SHA256_STATUS_NULL_INPUT SHA2SW_STATUS_NULL_INPUT
void MSPCrypto_sha256_init(void);
void MSPCrypto_sha256_drop(void);
int MSPCrypto_sha256_update(const void *data, uint32_t data_len);
int MSPCrypto_sha256_finish(uint8_t *output);
void MSPCrypto_ecdsa_p256_init(void);
void MSPCrypto_ecdsa_p256_drop(void);
int MSPCrypto_ecdsa_p256_verify(
const uint8_t *pk, const uint8_t *hash, const uint8_t *sig);
#endif /* __MSP_CRYPTO_H__ */
+18
View File
@@ -0,0 +1,18 @@
/***************************************************************************//**
* \file os.h
* \version 1.0
*
* \brief
* Objective:
* Heap init prototype
*
********************************************************************************
* \copyright
* Copyright 2017-2018, Cypress Semiconductor Corporation. All rights reserved.
* You may use this file only in accordance with the license, terms, conditions,
* disclaimers, and limitations in the end user license agreement accompanying
* the software package with which this file was provided.
*******************************************************************************/
#define os_heap_init();
+37
View File
@@ -0,0 +1,37 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#ifndef H_OS_HEAP_
#define H_OS_HEAP_
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
void *malloc(size_t size);
void free(void *mem);
void *realloc(void *ptr, size_t size);
#ifdef __cplusplus
}
#endif
#endif
+25
View File
@@ -0,0 +1,25 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#ifndef H_OS_MALLOC_
#define H_OS_MALLOC_
#include "os/os_heap.h"
#endif
+5
View File
@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIPCK5E8Y1bkZMWyEFktrFIaIt3A5BQPMDNCzEAXiGDBqoAoGCCqGSM49
AwEHoUQDQgAEQcxmxiiipZVOYMID4DuBoQmmKzciU0bt0Ap2bgZ5OjXYqn8Reaiw
uk1EyEULSEgjZJda3es8W13usnOAgMW78Q==
-----END EC PRIVATE KEY-----
+5
View File
@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEINeY1S+DASQ701QrflXtTHRhGQCw+VBagk/h6OwGO8/xoAoGCCqGSM49
AwEHoUQDQgAEKstAPOj+7VukSZWhqR2u6Nu+GTfNFPsvJFc35ZU5iNmUudZa69fN
1TCK1v5IskpqgQ7l8H2LaDTMOmr8U476wQ==
-----END EC PRIVATE KEY-----
+148
View File
@@ -0,0 +1,148 @@
#! /usr/bin/env python3
#
# Copyright 2017 Linaro Limited
#
# SPDX-License-Identifier: Apache-2.0
#
# 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.
"""
Assemble multiple images into a single image that can be flashed on the device.
"""
import argparse
import errno
import io
import re
import os
import os.path
import sys
def same_keys(a, b):
"""Determine if the dicts a and b have the same keys in them"""
for ak in a.keys():
if ak not in b:
return False
for bk in b.keys():
if bk not in a:
return False
return True
offset_re = re.compile(r"^#define DT_FLASH_AREA_([0-9A-Z_]+)_OFFSET(_0)?\s+(0x[0-9a-fA-F]+|[0-9]+)$")
size_re = re.compile(r"^#define DT_FLASH_AREA_([0-9A-Z_]+)_SIZE(_0)?\s+(0x[0-9a-fA-F]+|[0-9]+)$")
class Assembly():
def __init__(self, output, bootdir, edt):
self.find_slots(edt)
try:
os.unlink(output)
except OSError as e:
if e.errno != errno.ENOENT:
raise
self.output = output
def find_slots(self, edt):
offsets = {}
sizes = {}
part_nodes = edt.compat2nodes["fixed-partitions"]
for node in part_nodes:
for child in node.children.values():
if "label" in child.props:
label = child.props["label"].val
offsets[label] = child.regs[0].addr
sizes[label] = child.regs[0].size
if not same_keys(offsets, sizes):
raise Exception("Inconsistent data in devicetree.h")
# We care about the mcuboot, image-0, and image-1 partitions.
if 'mcuboot' not in offsets:
raise Exception("Board partition table does not have mcuboot partition")
if 'image-0' not in offsets:
raise Exception("Board partition table does not have image-0 partition")
if 'image-1' not in offsets:
raise Exception("Board partition table does not have image-1 partition")
self.offsets = offsets
self.sizes = sizes
def add_image(self, source, partition):
with open(self.output, 'ab') as ofd:
pos = ofd.tell()
print("partition {}, pos={}, offset={}".format(partition, pos, self.offsets[partition]))
if pos > self.offsets[partition]:
raise Exception("Partitions not in order, unsupported")
if pos < self.offsets[partition]:
buf = b'\xFF' * (self.offsets[partition] - pos)
ofd.write(buf)
with open(source, 'rb') as rfd:
ibuf = rfd.read()
if len(ibuf) > self.sizes[partition]:
raise Exception("Image {} is too large for partition".format(source))
ofd.write(ibuf)
def find_board_name(bootdir):
suffix = ".dts.pre.tmp"
for _, _, files in os.walk(os.path.join(bootdir, "zephyr")):
for filename in files:
if filename.endswith(suffix):
return filename[:-len(suffix)]
def main():
parser = argparse.ArgumentParser()
parser.add_argument('-b', '--bootdir', required=True,
help='Directory of built bootloader')
parser.add_argument('-p', '--primary', required=True,
help='Signed image file for primary image')
parser.add_argument('-s', '--secondary',
help='Signed image file for secondary image')
parser.add_argument('-o', '--output', required=True,
help='Filename to write full image to')
parser.add_argument('-z', '--zephyr-base',
help='Zephyr base containing the Zephyr repository')
args = parser.parse_args()
zephyr_base = args.zephyr_base
if zephyr_base is None:
try:
zephyr_base = os.environ['ZEPHYR_BASE']
except KeyError:
print('Need to either have ZEPHYR_BASE in environment or pass in -z')
sys.exit(1)
sys.path.insert(0, os.path.join(zephyr_base, "scripts", "dts", "python-devicetree", "src"))
import devicetree.edtlib
board = find_board_name(args.bootdir)
dts_path = os.path.join(args.bootdir, "zephyr", board + ".dts.pre.tmp")
edt = devicetree.edtlib.EDT(dts_path, [os.path.join(zephyr_base, "dts", "bindings")],
warn_reg_unit_address_mismatch=False)
output = Assembly(args.output, args.bootdir, edt)
output.add_image(os.path.join(args.bootdir, 'zephyr', 'zephyr.bin'), 'mcuboot')
output.add_image(args.primary, "image-0")
if args.secondary is not None:
output.add_image(args.secondary, "image-1")
if __name__ == '__main__':
main()
@@ -0,0 +1,114 @@
# Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the
# distribution.
#
# Neither the name of Texas Instruments Incorporated nor the names of
# its contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import click
import string
from encryptImage import Encryptor
@click.command()
@click.option('-f','--binfile',help="input binary file")
@click.option('-o','--outfile', default="image.txt", help="output file")
@click.option('--encrypt/--no-encrypt', default=False)
@click.option('-c','--cipherfile', default="image_encrypted.txt", help="ciphertext output file")
@click.option('-s','--startaddr',help="start Address")
def bin_to_titxt_encrypt(binfile, outfile, encrypt, cipherfile, startaddr):
print("converting {} to {}".format(binfile, outfile))
f = open(binfile,'rb')
o = open(outfile, 'w')
if encrypt:
c = open('ctxt_temp.txt', 'w')
cipher = Encryptor(cipherfile)
o.write("@{}\n".format(startaddr))
if encrypt:
c.write("@{}\n".format(startaddr))
x = f.read(1)
i = 0
len = 0
while x:
len += 1
a = int.from_bytes(x, "little")
o.write("{:02x}".format(a).upper())
if encrypt:
y = cipher.encrypt(x)
b = int.from_bytes(y, "little")
c.write("{:02x}".format(b).upper())
if i < 15:
space_char = " "
else :
space_char = "\n"
o.write(space_char)
if encrypt:
c.write(space_char)
i = (i + 1) % 16
x = f.read(1)
# if not a full aligned row, change the data length
if (i != 0):
o.write("\n")
if encrypt:
while i < 15:
c.write("00 ")
i += 1
c.write("00\n")
o.write('q')
if encrypt:
c.write('q')
c.close()
cipher.set_image_length(len)
print("Generating Encrypted Image: {}.".format(cipherfile))
cipher.generate_header()
# create one file, the cipherfile by appending temporary ciphertext
c1 = open(cipherfile, 'a+')
c2 = open('ctxt_temp.txt', 'r')
c1.write(c2.read())
c1.close()
c2.close()
f.close()
o.close()
if __name__ == "__main__":
bin_to_titxt_encrypt()
@@ -0,0 +1,127 @@
# Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the
# distribution.
#
# Neither the name of Texas Instruments Incorporated nor the names of
# its contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from Crypto.Cipher import AES
from enum import Enum
import hashlib
class cipherMode(Enum):
MODE_GCM = 0x0040
MODE_CTR = 0x0030
def hex_string_to_txt(filename, hex_string):
o = open(filename, 'w')
o.write("@00000010\n")
i = 0
for x in range(0, len(hex_string), 2):
o.write(hex_string[x] + hex_string[x+1])
if(i < 15):
o.write(" ")
else :
o.write("\n")
i = (i + 1) % 16
if(i != 0):
# pad out header to nearest 128-bit buffer such that
# UniFlash doesn't complain
while i < 15:
o.write("00 ")
i += 1
o.write("00\n")
# o.write('q')
o.close()
def old_gcm_header():
#get key from private key-type file
key = bytes.fromhex("feffe992 8665731c 6d6a8f94 67308308")
nonce = bytes.fromhex("cafebabe facedbad decaf888")
aad = bytes.fromhex("feedface deadbeef feedface deadbeef abaddad2")
plaintext = bytes.fromhex("d9313225 f88406e5 a55909c5 aff5269a \
86a7a953 1534f7da 2e4c303d 8a318a72 \
1c3c0c95 95680953 2fcf0e24 49a6b525 \
b16aedf5 aa0de657 ba637b39")
#calculate the key hash
key_hash = hashlib.sha256(key).hexdigest()
cipher = AES.new(key, AES.MODE_GCM, nonce)
cipher.update(aad)
(ciphertext, tag) = cipher.encrypt_and_digest(plaintext)
#numbers are given in 16-bit little endian
first_type = "9901004000"
second_key = "55002000" + key_hash
third_tag = "50001000" + tag.hex()
fourth_iv = "51000C00" + nonce.hex()
fifth_aad = "52001400" + aad.hex()
hex_string_to_txt(first_type + second_key + third_tag + fourth_iv + fifth_aad)
class Encryptor:
mode = AES.MODE_GCM
key = bytes.fromhex("feffe992 8665731c 6d6a8f94 67308308")
nonce = bytes.fromhex("cafebabe facedbad decaf888")
aad = bytes.fromhex("feedface deadbeef feedface deadbeef abaddad2")
def __init__(self, cipherfile):
self.cipherfile = cipherfile
self.cipher = AES.new(Encryptor.key, Encryptor.mode, Encryptor.nonce)
self.cipher.update(Encryptor.aad)
self.length = b'\x00\x00\x00\x00'
def update(self, aad):
self.cipher.update(aad)
def encrypt(self, plaintext):
return self.cipher.encrypt(plaintext)
def digest(self):
return self.cipher.digest()
def set_image_length(self, length):
self.length = length.to_bytes(4, byteorder='little')
def generate_header(self):
tag = self.cipher.digest()
key_hash = hashlib.sha256(Encryptor.key).hexdigest()
first_type = "99994000"
second_key = "55002000" + key_hash
third_tag = "50001000" + tag.hex()
fourth_iv = "51000C00" + Encryptor.nonce.hex()
fifth_length = "52000400" + self.length.hex()
sixth_aad = "53001400" + Encryptor.aad.hex()
end_of_header = "AAAA"
hex_string_to_txt(self.cipherfile, first_type + second_key + third_tag + fourth_iv +
fifth_length + sixth_aad + end_of_header)
+20
View File
@@ -0,0 +1,20 @@
#! /bin/bash
#
# SPDX-License-Identifier: Apache-2.0
source $(dirname $0)/../target.sh
lscript=/tmp/flash$$.jlink
cat >$lscript <<EOF
h
r
loadfile outdir/$BOARD/zephyr.bin $BASE_BOOT
loadfile hello.signed.bin $BASE_PRIMARY_SLOT
loadfile shell.signed.bin $BASE_SECONDARY_SLOT
q
EOF
JLinkExe -device $SOC -si SWD -speed auto \
-CommanderScript $lscript
rm $lscript
+29
View File
@@ -0,0 +1,29 @@
#! /bin/bash
#
# SPDX-License-Identifier: Apache-2.0
source $(dirname $0)/../target.sh
gscript=/tmp/init$$.gdb
cat > $gscript <<EOF
target remote localhost:2331
symbol-file outdir/$BOARD/zephyr.elf
# symbol-file ../zephyr/samples/shell/outdir/$BOARD/zephyr.elf
# dir apps/boot/src
# dir libs/bootutil/src
# dir hw/mcu/stm/stm32f4xx/src
b main
# b __reset
# b bootutil_img_validate
# b cmp_rsasig
# b bootutil_verify_sig
# b mbedtls_rsa_public
# b boot_calloc
mon reset 2
layout src
focus cmd
EOF
$gdbexe -x $gscript
rm $gscript
+31
View File
@@ -0,0 +1,31 @@
# SPDX-License-Identifier: Apache-2.0
#
# Nix environment for imgtool
#
# To install the environment
#
# $ nix-env --file imgtool.nix --install env-imgtool
#
# To load the environment
#
# $ load-env-imgtool
#
with import <nixpkgs> {};
let
# Nixpkgs has fairly recent versions of the dependencies, so we can
# rely on them without having to build our own derivations.
imgtoolPythonEnv = python37.withPackages (
_: [
python37.pkgs.click
python37.pkgs.cryptography
python37.pkgs.intelhex
python37.pkgs.setuptools
python37.pkgs.cbor
]
);
in
myEnvFun {
name = "imgtool";
buildInputs = [ imgtoolPythonEnv ];
}
+22
View File
@@ -0,0 +1,22 @@
#! /usr/bin/env python3
#
# Copyright 2017 Linaro Limited
#
# SPDX-License-Identifier: Apache-2.0
#
# 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.
from imgtool import main
if __name__ == '__main__':
main.imgtool()
@@ -0,0 +1,17 @@
# Copyright 2017-2020 Linaro Limited
#
# SPDX-License-Identifier: Apache-2.0
#
# 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.
imgtool_version = "1.8.0"
@@ -0,0 +1,49 @@
# Copyright (c) 2019, Arm Limited.
# Copyright (c) 2020, Linaro Limited
#
# SPDX-License-Identifier: Apache-2.0
#
# 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.
from enum import Enum
import cbor
class SwComponent(int, Enum):
"""
Software component property IDs specified by
Arm's PSA Attestation API 1.0 document.
"""
TYPE = 1
MEASUREMENT_VALUE = 2
VERSION = 4
SIGNER_ID = 5
MEASUREMENT_DESCRIPTION = 6
def create_sw_component_data(sw_type, sw_version, sw_measurement_description,
sw_measurement_value, sw_signer_id):
# List of software component properties (Key ID + value)
properties = {
SwComponent.TYPE: sw_type,
SwComponent.VERSION: sw_version,
SwComponent.SIGNER_ID: sw_signer_id,
SwComponent.MEASUREMENT_DESCRIPTION: sw_measurement_description,
}
# Note: The measurement value must be the last item of the property
# list because later it will be modified by the bootloader.
properties[SwComponent.MEASUREMENT_VALUE] = sw_measurement_value
return cbor.dumps(properties)
@@ -0,0 +1,605 @@
# Copyright 2018 Nordic Semiconductor ASA
# Copyright 2017-2020 Linaro Limited
# Copyright 2019-2021 Arm Limited
#
# SPDX-License-Identifier: Apache-2.0
#
# 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.
"""
Image signing and management.
"""
from . import version as versmod
from .boot_record import create_sw_component_data
import click
from enum import Enum
from intelhex import IntelHex
import hashlib
import struct
import os.path
from .keys import rsa, ecdsa, x25519
from cryptography.hazmat.primitives.asymmetric import ec, padding
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, hmac
from cryptography.exceptions import InvalidSignature
IMAGE_MAGIC = 0x96f3b83d
IMAGE_HEADER_SIZE = 32
BIN_EXT = "bin"
INTEL_HEX_EXT = "hex"
DEFAULT_MAX_SECTORS = 128
MAX_ALIGN = 8
DEP_IMAGES_KEY = "images"
DEP_VERSIONS_KEY = "versions"
MAX_SW_TYPE_LENGTH = 12 # Bytes
# Image header flags.
IMAGE_F = {
'PIC': 0x0000001,
'ENCRYPTED_AES128': 0x0000004,
'ENCRYPTED_AES256': 0x0000008,
'NON_BOOTABLE': 0x0000010,
'RAM_LOAD': 0x0000020,
'ROM_FIXED': 0x0000100,
}
TLV_VALUES = {
'KEYHASH': 0x01,
'PUBKEY': 0x02,
'SHA256': 0x10,
'RSA2048': 0x20,
'ECDSA224': 0x21,
'ECDSA256': 0x22,
'RSA3072': 0x23,
'ED25519': 0x24,
'ENCRSA2048': 0x30,
'ENCKW': 0x31,
'ENCEC256': 0x32,
'ENCX25519': 0x33,
'DEPENDENCY': 0x40,
'SEC_CNT': 0x50,
'BOOT_RECORD': 0x60,
}
TLV_SIZE = 4
TLV_INFO_SIZE = 4
TLV_INFO_MAGIC = 0x6907
TLV_PROT_INFO_MAGIC = 0x6908
boot_magic = bytes([
0x77, 0xc2, 0x95, 0xf3,
0x60, 0xd2, 0xef, 0x7f,
0x35, 0x52, 0x50, 0x0f,
0x2c, 0xb6, 0x79, 0x80, ])
STRUCT_ENDIAN_DICT = {
'little': '<',
'big': '>'
}
VerifyResult = Enum('VerifyResult',
"""
OK INVALID_MAGIC INVALID_TLV_INFO_MAGIC INVALID_HASH
INVALID_SIGNATURE
""")
class TLV():
def __init__(self, endian, magic=TLV_INFO_MAGIC):
self.magic = magic
self.buf = bytearray()
self.endian = endian
def __len__(self):
return TLV_INFO_SIZE + len(self.buf)
def add(self, kind, payload):
"""
Add a TLV record. Kind should be a string found in TLV_VALUES above.
"""
e = STRUCT_ENDIAN_DICT[self.endian]
if isinstance(kind, int):
buf = struct.pack(e + 'BBH', kind, 0, len(payload))
else:
buf = struct.pack(e + 'BBH', TLV_VALUES[kind], 0, len(payload))
self.buf += buf
self.buf += payload
def get(self):
if len(self.buf) == 0:
return bytes()
e = STRUCT_ENDIAN_DICT[self.endian]
header = struct.pack(e + 'HH', self.magic, len(self))
return header + bytes(self.buf)
class Image():
def __init__(self, version=None, header_size=IMAGE_HEADER_SIZE,
pad_header=False, pad=False, confirm=False, align=1,
slot_size=0, max_sectors=DEFAULT_MAX_SECTORS,
overwrite_only=False, endian="little", load_addr=0,
rom_fixed=None, erased_val=None, save_enctlv=False,
security_counter=None):
if load_addr and rom_fixed:
raise click.UsageError("Can not set rom_fixed and load_addr at the same time")
self.version = version or versmod.decode_version("0")
self.header_size = header_size
self.pad_header = pad_header
self.pad = pad
self.confirm = confirm
self.align = align
self.slot_size = slot_size
self.max_sectors = max_sectors
self.overwrite_only = overwrite_only
self.endian = endian
self.base_addr = None
self.load_addr = 0 if load_addr is None else load_addr
self.rom_fixed = rom_fixed
self.erased_val = 0xff if erased_val is None else int(erased_val, 0)
self.payload = []
self.enckey = None
self.save_enctlv = save_enctlv
self.enctlv_len = 0
if security_counter == 'auto':
# Security counter has not been explicitly provided,
# generate it from the version number
self.security_counter = ((self.version.major << 24)
+ (self.version.minor << 16)
+ self.version.revision)
else:
self.security_counter = security_counter
def __repr__(self):
return "<Image version={}, header_size={}, security_counter={}, \
base_addr={}, load_addr={}, align={}, slot_size={}, \
max_sectors={}, overwrite_only={}, endian={} format={}, \
payloadlen=0x{:x}>".format(
self.version,
self.header_size,
self.security_counter,
self.base_addr if self.base_addr is not None else "N/A",
self.load_addr,
self.align,
self.slot_size,
self.max_sectors,
self.overwrite_only,
self.endian,
self.__class__.__name__,
len(self.payload))
def load(self, path):
"""Load an image from a given file"""
ext = os.path.splitext(path)[1][1:].lower()
try:
if ext == INTEL_HEX_EXT:
ih = IntelHex(path)
self.payload = ih.tobinarray()
self.base_addr = ih.minaddr()
else:
with open(path, 'rb') as f:
self.payload = f.read()
except FileNotFoundError:
raise click.UsageError("Input file not found")
# Add the image header if needed.
if self.pad_header and self.header_size > 0:
if self.base_addr:
# Adjust base_addr for new header
self.base_addr -= self.header_size
self.payload = bytes([self.erased_val] * self.header_size) + \
self.payload
self.check_header()
def save(self, path, hex_addr=None):
"""Save an image from a given file"""
ext = os.path.splitext(path)[1][1:].lower()
if ext == INTEL_HEX_EXT:
# input was in binary format, but HEX needs to know the base addr
if self.base_addr is None and hex_addr is None:
raise click.UsageError("No address exists in input file "
"neither was it provided by user")
h = IntelHex()
if hex_addr is not None:
self.base_addr = hex_addr
h.frombytes(bytes=self.payload, offset=self.base_addr)
if self.pad:
trailer_size = self._trailer_size(self.align, self.max_sectors,
self.overwrite_only,
self.enckey,
self.save_enctlv,
self.enctlv_len)
trailer_addr = (self.base_addr + self.slot_size) - trailer_size
padding = bytearray([self.erased_val] *
(trailer_size - len(boot_magic)))
if self.confirm and not self.overwrite_only:
padding[-MAX_ALIGN] = 0x01 # image_ok = 0x01
padding += boot_magic
h.puts(trailer_addr, bytes(padding))
h.tofile(path, 'hex')
else:
if self.pad:
self.pad_to(self.slot_size)
with open(path, 'wb') as f:
f.write(self.payload)
def check_header(self):
if self.header_size > 0 and not self.pad_header:
if any(v != 0 for v in self.payload[0:self.header_size]):
raise click.UsageError("Header padding was not requested and "
"image does not start with zeros")
def check_trailer(self):
if self.slot_size > 0:
tsize = self._trailer_size(self.align, self.max_sectors,
self.overwrite_only, self.enckey,
self.save_enctlv, self.enctlv_len)
padding = self.slot_size - (len(self.payload) + tsize)
if padding < 0:
msg = "Image size (0x{:x}) + trailer (0x{:x}) exceeds " \
"requested size 0x{:x}".format(
len(self.payload), tsize, self.slot_size)
raise click.UsageError(msg)
def ecies_hkdf(self, enckey, plainkey):
if isinstance(enckey, ecdsa.ECDSA256P1Public):
newpk = ec.generate_private_key(ec.SECP256R1(), default_backend())
shared = newpk.exchange(ec.ECDH(), enckey._get_public())
else:
newpk = X25519PrivateKey.generate()
shared = newpk.exchange(enckey._get_public())
derived_key = HKDF(
algorithm=hashes.SHA256(), length=48, salt=None,
info=b'MCUBoot_ECIES_v1', backend=default_backend()).derive(shared)
encryptor = Cipher(algorithms.AES(derived_key[:16]),
modes.CTR(bytes([0] * 16)),
backend=default_backend()).encryptor()
cipherkey = encryptor.update(plainkey) + encryptor.finalize()
mac = hmac.HMAC(derived_key[16:], hashes.SHA256(),
backend=default_backend())
mac.update(cipherkey)
ciphermac = mac.finalize()
if isinstance(enckey, ecdsa.ECDSA256P1Public):
pubk = newpk.public_key().public_bytes(
encoding=Encoding.X962,
format=PublicFormat.UncompressedPoint)
else:
pubk = newpk.public_key().public_bytes(
encoding=Encoding.Raw,
format=PublicFormat.Raw)
return cipherkey, ciphermac, pubk
def create(self, key, public_key_format, enckey, dependencies=None,
sw_type=None, custom_tlvs=None, encrypt_keylen=128):
self.enckey = enckey
# Calculate the hash of the public key
if key is not None:
pub = key.get_public_bytes()
sha = hashlib.sha256()
sha.update(pub)
pubbytes = sha.digest()
else:
pubbytes = bytes(hashlib.sha256().digest_size)
protected_tlv_size = 0
if self.security_counter is not None:
# Size of the security counter TLV: header ('HH') + payload ('I')
# = 4 + 4 = 8 Bytes
protected_tlv_size += TLV_SIZE + 4
if sw_type is not None:
if len(sw_type) > MAX_SW_TYPE_LENGTH:
msg = "'{}' is too long ({} characters) for sw_type. Its " \
"maximum allowed length is 12 characters.".format(
sw_type, len(sw_type))
raise click.UsageError(msg)
image_version = (str(self.version.major) + '.'
+ str(self.version.minor) + '.'
+ str(self.version.revision))
# The image hash is computed over the image header, the image
# itself and the protected TLV area. However, the boot record TLV
# (which is part of the protected area) should contain this hash
# before it is even calculated. For this reason the script fills
# this field with zeros and the bootloader will insert the right
# value later.
digest = bytes(hashlib.sha256().digest_size)
# Create CBOR encoded boot record
boot_record = create_sw_component_data(sw_type, image_version,
"SHA256", digest,
pubbytes)
protected_tlv_size += TLV_SIZE + len(boot_record)
if dependencies is not None:
# Size of a Dependency TLV = Header ('HH') + Payload('IBBHI')
# = 4 + 12 = 16 Bytes
dependencies_num = len(dependencies[DEP_IMAGES_KEY])
protected_tlv_size += (dependencies_num * 16)
if custom_tlvs is not None:
for value in custom_tlvs.values():
protected_tlv_size += TLV_SIZE + len(value)
if protected_tlv_size != 0:
# Add the size of the TLV info header
protected_tlv_size += TLV_INFO_SIZE
# At this point the image is already on the payload
#
# This adds the padding if image is not aligned to the 16 Bytes
# in encrypted mode
if self.enckey is not None:
pad_len = len(self.payload) % 16
if pad_len > 0:
pad = bytes(16 - pad_len)
if isinstance(self.payload, bytes):
self.payload += pad
else:
self.payload.extend(pad)
# This adds the header to the payload as well
if encrypt_keylen == 256:
self.add_header(enckey, protected_tlv_size, 256)
else:
self.add_header(enckey, protected_tlv_size)
prot_tlv = TLV(self.endian, TLV_PROT_INFO_MAGIC)
# Protected TLVs must be added first, because they are also included
# in the hash calculation
protected_tlv_off = None
if protected_tlv_size != 0:
e = STRUCT_ENDIAN_DICT[self.endian]
if self.security_counter is not None:
payload = struct.pack(e + 'I', self.security_counter)
prot_tlv.add('SEC_CNT', payload)
if sw_type is not None:
prot_tlv.add('BOOT_RECORD', boot_record)
if dependencies is not None:
for i in range(dependencies_num):
payload = struct.pack(
e + 'B3x'+'BBHI',
int(dependencies[DEP_IMAGES_KEY][i]),
dependencies[DEP_VERSIONS_KEY][i].major,
dependencies[DEP_VERSIONS_KEY][i].minor,
dependencies[DEP_VERSIONS_KEY][i].revision,
dependencies[DEP_VERSIONS_KEY][i].build
)
prot_tlv.add('DEPENDENCY', payload)
if custom_tlvs is not None:
for tag, value in custom_tlvs.items():
prot_tlv.add(tag, value)
protected_tlv_off = len(self.payload)
self.payload += prot_tlv.get()
tlv = TLV(self.endian)
# Note that ecdsa wants to do the hashing itself, which means
# we get to hash it twice.
sha = hashlib.sha256()
sha.update(self.payload)
digest = sha.digest()
tlv.add('SHA256', digest)
if key is not None:
if public_key_format == 'hash':
tlv.add('KEYHASH', pubbytes)
else:
tlv.add('PUBKEY', pub)
# `sign` expects the full image payload (sha256 done internally),
# while `sign_digest` expects only the digest of the payload
if hasattr(key, 'sign'):
sig = key.sign(bytes(self.payload))
else:
sig = key.sign_digest(digest)
tlv.add(key.sig_tlv(), sig)
# At this point the image was hashed + signed, we can remove the
# protected TLVs from the payload (will be re-added later)
if protected_tlv_off is not None:
self.payload = self.payload[:protected_tlv_off]
if enckey is not None:
if encrypt_keylen == 256:
plainkey = os.urandom(32)
else:
plainkey = os.urandom(16)
if isinstance(enckey, rsa.RSAPublic):
cipherkey = enckey._get_public().encrypt(
plainkey, padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None))
self.enctlv_len = len(cipherkey)
tlv.add('ENCRSA2048', cipherkey)
elif isinstance(enckey, (ecdsa.ECDSA256P1Public,
x25519.X25519Public)):
cipherkey, mac, pubk = self.ecies_hkdf(enckey, plainkey)
enctlv = pubk + mac + cipherkey
self.enctlv_len = len(enctlv)
if isinstance(enckey, ecdsa.ECDSA256P1Public):
tlv.add('ENCEC256', enctlv)
else:
tlv.add('ENCX25519', enctlv)
nonce = bytes([0] * 16)
cipher = Cipher(algorithms.AES(plainkey), modes.CTR(nonce),
backend=default_backend())
encryptor = cipher.encryptor()
img = bytes(self.payload[self.header_size:])
self.payload[self.header_size:] = \
encryptor.update(img) + encryptor.finalize()
self.payload += prot_tlv.get()
self.payload += tlv.get()
self.check_trailer()
def add_header(self, enckey, protected_tlv_size, aes_length=128):
"""Install the image header."""
flags = 0
if enckey is not None:
if aes_length == 128:
flags |= IMAGE_F['ENCRYPTED_AES128']
else:
flags |= IMAGE_F['ENCRYPTED_AES256']
if self.load_addr != 0:
# Indicates that this image should be loaded into RAM
# instead of run directly from flash.
flags |= IMAGE_F['RAM_LOAD']
if self.rom_fixed:
flags |= IMAGE_F['ROM_FIXED']
e = STRUCT_ENDIAN_DICT[self.endian]
fmt = (e +
# type ImageHdr struct {
'I' + # Magic uint32
'I' + # LoadAddr uint32
'H' + # HdrSz uint16
'H' + # PTLVSz uint16
'I' + # ImgSz uint32
'I' + # Flags uint32
'BBHI' + # Vers ImageVersion
'I' # Pad1 uint32
) # }
assert struct.calcsize(fmt) == IMAGE_HEADER_SIZE
header = struct.pack(fmt,
IMAGE_MAGIC,
self.rom_fixed or self.load_addr,
self.header_size,
protected_tlv_size, # TLV Info header + Protected TLVs
len(self.payload) - self.header_size, # ImageSz
flags,
self.version.major,
self.version.minor or 0,
self.version.revision or 0,
self.version.build or 0,
0) # Pad1
self.payload = bytearray(self.payload)
self.payload[:len(header)] = header
def _trailer_size(self, write_size, max_sectors, overwrite_only, enckey,
save_enctlv, enctlv_len):
# NOTE: should already be checked by the argument parser
magic_size = 16
if overwrite_only:
return MAX_ALIGN * 2 + magic_size
else:
if write_size not in set([1, 2, 4, 8]):
raise click.BadParameter("Invalid alignment: {}".format(
write_size))
m = DEFAULT_MAX_SECTORS if max_sectors is None else max_sectors
trailer = m * 3 * write_size # status area
if enckey is not None:
if save_enctlv:
# TLV saved by the bootloader is aligned
keylen = (int((enctlv_len - 1) / MAX_ALIGN) + 1) * MAX_ALIGN
else:
keylen = 16
trailer += keylen * 2 # encryption keys
trailer += MAX_ALIGN * 4 # image_ok/copy_done/swap_info/swap_size
trailer += magic_size
return trailer
def pad_to(self, size):
"""Pad the image to the given size, with the given flash alignment."""
tsize = self._trailer_size(self.align, self.max_sectors,
self.overwrite_only, self.enckey,
self.save_enctlv, self.enctlv_len)
padding = size - (len(self.payload) + tsize)
pbytes = bytearray([self.erased_val] * padding)
pbytes += bytearray([self.erased_val] * (tsize - len(boot_magic)))
if self.confirm and not self.overwrite_only:
pbytes[-MAX_ALIGN] = 0x01 # image_ok = 0x01
pbytes += boot_magic
self.payload += pbytes
@staticmethod
def verify(imgfile, key):
with open(imgfile, "rb") as f:
b = f.read()
magic, _, header_size, _, img_size = struct.unpack('IIHHI', b[:16])
version = struct.unpack('BBHI', b[20:28])
if magic != IMAGE_MAGIC:
return VerifyResult.INVALID_MAGIC, None, None
tlv_off = header_size + img_size
tlv_info = b[tlv_off:tlv_off+TLV_INFO_SIZE]
magic, tlv_tot = struct.unpack('HH', tlv_info)
if magic == TLV_PROT_INFO_MAGIC:
tlv_off += tlv_tot
tlv_info = b[tlv_off:tlv_off+TLV_INFO_SIZE]
magic, tlv_tot = struct.unpack('HH', tlv_info)
if magic != TLV_INFO_MAGIC:
return VerifyResult.INVALID_TLV_INFO_MAGIC, None, None
sha = hashlib.sha256()
prot_tlv_size = tlv_off
sha.update(b[:prot_tlv_size])
digest = sha.digest()
tlv_end = tlv_off + tlv_tot
tlv_off += TLV_INFO_SIZE # skip tlv info
while tlv_off < tlv_end:
tlv = b[tlv_off:tlv_off+TLV_SIZE]
tlv_type, _, tlv_len = struct.unpack('BBH', tlv)
if tlv_type == TLV_VALUES["SHA256"]:
off = tlv_off + TLV_SIZE
if digest == b[off:off+tlv_len]:
if key is None:
return VerifyResult.OK, version, digest
else:
return VerifyResult.INVALID_HASH, None, None
elif key is not None and tlv_type == TLV_VALUES[key.sig_tlv()]:
off = tlv_off + TLV_SIZE
tlv_sig = b[off:off+tlv_len]
payload = b[:prot_tlv_size]
try:
if hasattr(key, 'verify'):
key.verify(tlv_sig, payload)
else:
key.verify_digest(tlv_sig, digest)
return VerifyResult.OK, version, digest
except InvalidSignature:
# continue to next TLV
pass
tlv_off += TLV_SIZE + tlv_len
return VerifyResult.INVALID_SIGNATURE, None, None
@@ -0,0 +1,96 @@
# Copyright 2017 Linaro Limited
#
# SPDX-License-Identifier: Apache-2.0
#
# 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.
"""
Cryptographic key management for imgtool.
"""
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.rsa import (
RSAPrivateKey, RSAPublicKey)
from cryptography.hazmat.primitives.asymmetric.ec import (
EllipticCurvePrivateKey, EllipticCurvePublicKey)
from cryptography.hazmat.primitives.asymmetric.ed25519 import (
Ed25519PrivateKey, Ed25519PublicKey)
from cryptography.hazmat.primitives.asymmetric.x25519 import (
X25519PrivateKey, X25519PublicKey)
from .rsa import RSA, RSAPublic, RSAUsageError, RSA_KEY_SIZES
from .ecdsa import ECDSA256P1, ECDSA256P1Public, ECDSAUsageError
from .ed25519 import Ed25519, Ed25519Public, Ed25519UsageError
from .x25519 import X25519, X25519Public, X25519UsageError
class PasswordRequired(Exception):
"""Raised to indicate that the key is password protected, but a
password was not specified."""
pass
def load(path, passwd=None):
"""Try loading a key from the given path. Returns None if the password wasn't specified."""
with open(path, 'rb') as f:
raw_pem = f.read()
try:
pk = serialization.load_pem_private_key(
raw_pem,
password=passwd,
backend=default_backend())
# Unfortunately, the crypto library raises unhelpful exceptions,
# so we have to look at the text.
except TypeError as e:
msg = str(e)
if "private key is encrypted" in msg:
return None
raise e
except ValueError:
# This seems to happen if the key is a public key, let's try
# loading it as a public key.
pk = serialization.load_pem_public_key(
raw_pem,
backend=default_backend())
if isinstance(pk, RSAPrivateKey):
if pk.key_size not in RSA_KEY_SIZES:
raise Exception("Unsupported RSA key size: " + pk.key_size)
return RSA(pk)
elif isinstance(pk, RSAPublicKey):
if pk.key_size not in RSA_KEY_SIZES:
raise Exception("Unsupported RSA key size: " + pk.key_size)
return RSAPublic(pk)
elif isinstance(pk, EllipticCurvePrivateKey):
if pk.curve.name != 'secp256r1':
raise Exception("Unsupported EC curve: " + pk.curve.name)
if pk.key_size != 256:
raise Exception("Unsupported EC size: " + pk.key_size)
return ECDSA256P1(pk)
elif isinstance(pk, EllipticCurvePublicKey):
if pk.curve.name != 'secp256r1':
raise Exception("Unsupported EC curve: " + pk.curve.name)
if pk.key_size != 256:
raise Exception("Unsupported EC size: " + pk.key_size)
return ECDSA256P1Public(pk)
elif isinstance(pk, Ed25519PrivateKey):
return Ed25519(pk)
elif isinstance(pk, Ed25519PublicKey):
return Ed25519Public(pk)
elif isinstance(pk, X25519PrivateKey):
return X25519(pk)
elif isinstance(pk, X25519PublicKey):
return X25519Public(pk)
else:
raise Exception("Unknown key type: " + str(type(pk)))
@@ -0,0 +1,159 @@
"""
ECDSA key management
"""
# SPDX-License-Identifier: Apache-2.0
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.hashes import SHA256
from .general import KeyClass
class ECDSAUsageError(Exception):
pass
class ECDSA256P1Public(KeyClass):
def __init__(self, key):
self.key = key
def shortname(self):
return "ecdsa"
def _unsupported(self, name):
raise ECDSAUsageError("Operation {} requires private key".format(name))
def _get_public(self):
return self.key
def get_public_bytes(self):
# The key is embedded into MBUboot in "SubjectPublicKeyInfo" format
return self._get_public().public_bytes(
encoding=serialization.Encoding.DER,
format=serialization.PublicFormat.SubjectPublicKeyInfo)
def get_private_bytes(self, minimal):
self._unsupported('get_private_bytes')
def export_private(self, path, passwd=None):
self._unsupported('export_private')
def export_public(self, path):
"""Write the public key to the given file."""
pem = self._get_public().public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo)
with open(path, 'wb') as f:
f.write(pem)
def sig_type(self):
return "ECDSA256_SHA256"
def sig_tlv(self):
return "ECDSA256"
def sig_len(self):
# Early versions of MCUboot (< v1.5.0) required ECDSA
# signatures to be padded to 72 bytes. Because the DER
# encoding is done with signed integers, the size of the
# signature will vary depending on whether the high bit is set
# in each value. This padding was done in a
# not-easily-reversible way (by just adding zeros).
#
# The signing code no longer requires this padding, and newer
# versions of MCUboot don't require it. But, continue to
# return the total length so that the padding can be done if
# requested.
return 72
def verify(self, signature, payload):
# strip possible paddings added during sign
signature = signature[:signature[1] + 2]
k = self.key
if isinstance(self.key, ec.EllipticCurvePrivateKey):
k = self.key.public_key()
return k.verify(signature=signature, data=payload,
signature_algorithm=ec.ECDSA(SHA256()))
class ECDSA256P1(ECDSA256P1Public):
"""
Wrapper around an ECDSA private key.
"""
def __init__(self, key):
"""key should be an instance of EllipticCurvePrivateKey"""
self.key = key
self.pad_sig = False
@staticmethod
def generate():
pk = ec.generate_private_key(
ec.SECP256R1(),
backend=default_backend())
return ECDSA256P1(pk)
def _get_public(self):
return self.key.public_key()
def _build_minimal_ecdsa_privkey(self, der):
'''
Builds a new DER that only includes the EC private key, removing the
public key that is added as an "optional" BITSTRING.
'''
offset_PUB = 68
EXCEPTION_TEXT = "Error parsing ecdsa key. Please submit an issue!"
if der[offset_PUB] != 0xa1:
raise ECDSAUsageError(EXCEPTION_TEXT)
len_PUB = der[offset_PUB + 1]
b = bytearray(der[:-offset_PUB])
offset_SEQ = 29
if b[offset_SEQ] != 0x30:
raise ECDSAUsageError(EXCEPTION_TEXT)
b[offset_SEQ + 1] -= len_PUB
offset_OCT_STR = 27
if b[offset_OCT_STR] != 0x04:
raise ECDSAUsageError(EXCEPTION_TEXT)
b[offset_OCT_STR + 1] -= len_PUB
if b[0] != 0x30 or b[1] != 0x81:
raise ECDSAUsageError(EXCEPTION_TEXT)
b[2] -= len_PUB
return b
def get_private_bytes(self, minimal):
priv = self.key.private_bytes(
encoding=serialization.Encoding.DER,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption())
if minimal:
priv = self._build_minimal_ecdsa_privkey(priv)
return priv
def export_private(self, path, passwd=None):
"""Write the private key to the given file, protecting it with the optional password."""
if passwd is None:
enc = serialization.NoEncryption()
else:
enc = serialization.BestAvailableEncryption(passwd)
pem = self.key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=enc)
with open(path, 'wb') as f:
f.write(pem)
def raw_sign(self, payload):
"""Return the actual signature"""
return self.key.sign(
data=payload,
signature_algorithm=ec.ECDSA(SHA256()))
def sign(self, payload):
sig = self.raw_sign(payload)
if self.pad_sig:
# To make fixed length, pad with one or two zeros.
sig += b'\000' * (self.sig_len() - len(sig))
return sig
else:
return sig
@@ -0,0 +1,101 @@
"""
Tests for ECDSA keys
"""
# SPDX-License-Identifier: Apache-2.0
import io
import os.path
import sys
import tempfile
import unittest
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.hashes import SHA256
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../..')))
from imgtool.keys import load, ECDSA256P1, ECDSAUsageError
class EcKeyGeneration(unittest.TestCase):
def setUp(self):
self.test_dir = tempfile.TemporaryDirectory()
def tname(self, base):
return os.path.join(self.test_dir.name, base)
def tearDown(self):
self.test_dir.cleanup()
def test_keygen(self):
name1 = self.tname("keygen.pem")
k = ECDSA256P1.generate()
k.export_private(name1, b'secret')
self.assertIsNone(load(name1))
k2 = load(name1, b'secret')
pubname = self.tname('keygen-pub.pem')
k2.export_public(pubname)
pk2 = load(pubname)
# We should be able to export the public key from the loaded
# public key, but not the private key.
pk2.export_public(self.tname('keygen-pub2.pem'))
self.assertRaises(ECDSAUsageError,
pk2.export_private, self.tname('keygen-priv2.pem'))
def test_emit(self):
"""Basic sanity check on the code emitters."""
k = ECDSA256P1.generate()
ccode = io.StringIO()
k.emit_c_public(ccode)
self.assertIn("ecdsa_pub_key", ccode.getvalue())
self.assertIn("ecdsa_pub_key_len", ccode.getvalue())
rustcode = io.StringIO()
k.emit_rust_public(rustcode)
self.assertIn("ECDSA_PUB_KEY", rustcode.getvalue())
def test_emit_pub(self):
"""Basic sanity check on the code emitters."""
pubname = self.tname("public.pem")
k = ECDSA256P1.generate()
k.export_public(pubname)
k2 = load(pubname)
ccode = io.StringIO()
k2.emit_c_public(ccode)
self.assertIn("ecdsa_pub_key", ccode.getvalue())
self.assertIn("ecdsa_pub_key_len", ccode.getvalue())
rustcode = io.StringIO()
k2.emit_rust_public(rustcode)
self.assertIn("ECDSA_PUB_KEY", rustcode.getvalue())
def test_sig(self):
k = ECDSA256P1.generate()
buf = b'This is the message'
sig = k.raw_sign(buf)
# The code doesn't have any verification, so verify this
# manually.
k.key.public_key().verify(
signature=sig,
data=buf,
signature_algorithm=ec.ECDSA(SHA256()))
# Modify the message to make sure the signature fails.
self.assertRaises(InvalidSignature,
k.key.public_key().verify,
signature=sig,
data=b'This is thE message',
signature_algorithm=ec.ECDSA(SHA256()))
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,107 @@
"""
ED25519 key management
"""
# SPDX-License-Identifier: Apache-2.0
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import ed25519
from .general import KeyClass
class Ed25519UsageError(Exception):
pass
class Ed25519Public(KeyClass):
def __init__(self, key):
self.key = key
def shortname(self):
return "ed25519"
def _unsupported(self, name):
raise Ed25519UsageError("Operation {} requires private key".format(name))
def _get_public(self):
return self.key
def get_public_bytes(self):
# The key is embedded into MBUboot in "SubjectPublicKeyInfo" format
return self._get_public().public_bytes(
encoding=serialization.Encoding.DER,
format=serialization.PublicFormat.SubjectPublicKeyInfo)
def get_private_bytes(self, minimal):
self._unsupported('get_private_bytes')
def export_private(self, path, passwd=None):
self._unsupported('export_private')
def export_public(self, path):
"""Write the public key to the given file."""
pem = self._get_public().public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo)
with open(path, 'wb') as f:
f.write(pem)
def sig_type(self):
return "ED25519"
def sig_tlv(self):
return "ED25519"
def sig_len(self):
return 64
class Ed25519(Ed25519Public):
"""
Wrapper around an ED25519 private key.
"""
def __init__(self, key):
"""key should be an instance of EllipticCurvePrivateKey"""
self.key = key
@staticmethod
def generate():
pk = ed25519.Ed25519PrivateKey.generate()
return Ed25519(pk)
def _get_public(self):
return self.key.public_key()
def get_private_bytes(self, minimal):
raise Ed25519UsageError("Operation not supported with {} keys".format(
self.shortname()))
def export_private(self, path, passwd=None):
"""
Write the private key to the given file, protecting it with the
optional password.
"""
if passwd is None:
enc = serialization.NoEncryption()
else:
enc = serialization.BestAvailableEncryption(passwd)
pem = self.key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=enc)
with open(path, 'wb') as f:
f.write(pem)
def sign_digest(self, digest):
"""Return the actual signature"""
return self.key.sign(data=digest)
def verify_digest(self, signature, digest):
"""Verify that signature is valid for given digest"""
k = self.key
if isinstance(self.key, ed25519.Ed25519PrivateKey):
k = self.key.public_key()
return k.verify(signature=signature, data=digest)
@@ -0,0 +1,105 @@
"""
Tests for ECDSA keys
"""
# SPDX-License-Identifier: Apache-2.0
import hashlib
import io
import os.path
import sys
import tempfile
import unittest
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives.asymmetric import ed25519
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../..')))
from imgtool.keys import load, Ed25519, Ed25519UsageError
class Ed25519KeyGeneration(unittest.TestCase):
def setUp(self):
self.test_dir = tempfile.TemporaryDirectory()
def tname(self, base):
return os.path.join(self.test_dir.name, base)
def tearDown(self):
self.test_dir.cleanup()
def test_keygen(self):
name1 = self.tname("keygen.pem")
k = Ed25519.generate()
k.export_private(name1, b'secret')
self.assertIsNone(load(name1))
k2 = load(name1, b'secret')
pubname = self.tname('keygen-pub.pem')
k2.export_public(pubname)
pk2 = load(pubname)
# We should be able to export the public key from the loaded
# public key, but not the private key.
pk2.export_public(self.tname('keygen-pub2.pem'))
self.assertRaises(Ed25519UsageError,
pk2.export_private, self.tname('keygen-priv2.pem'))
def test_emit(self):
"""Basic sanity check on the code emitters."""
k = Ed25519.generate()
ccode = io.StringIO()
k.emit_c_public(ccode)
self.assertIn("ed25519_pub_key", ccode.getvalue())
self.assertIn("ed25519_pub_key_len", ccode.getvalue())
rustcode = io.StringIO()
k.emit_rust_public(rustcode)
self.assertIn("ED25519_PUB_KEY", rustcode.getvalue())
def test_emit_pub(self):
"""Basic sanity check on the code emitters."""
pubname = self.tname("public.pem")
k = Ed25519.generate()
k.export_public(pubname)
k2 = load(pubname)
ccode = io.StringIO()
k2.emit_c_public(ccode)
self.assertIn("ed25519_pub_key", ccode.getvalue())
self.assertIn("ed25519_pub_key_len", ccode.getvalue())
rustcode = io.StringIO()
k2.emit_rust_public(rustcode)
self.assertIn("ED25519_PUB_KEY", rustcode.getvalue())
def test_sig(self):
k = Ed25519.generate()
buf = b'This is the message'
sha = hashlib.sha256()
sha.update(buf)
digest = sha.digest()
sig = k.sign_digest(digest)
# The code doesn't have any verification, so verify this
# manually.
k.key.public_key().verify(signature=sig, data=digest)
# Modify the message to make sure the signature fails.
sha = hashlib.sha256()
sha.update(b'This is thE message')
new_digest = sha.digest()
self.assertRaises(InvalidSignature,
k.key.public_key().verify,
signature=sig,
data=new_digest)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,47 @@
"""General key class."""
# SPDX-License-Identifier: Apache-2.0
import sys
AUTOGEN_MESSAGE = "/* Autogenerated by imgtool.py, do not edit. */"
class KeyClass(object):
def _emit(self, header, trailer, encoded_bytes, indent, file=sys.stdout, len_format=None):
print(AUTOGEN_MESSAGE, file=file)
print(header, end='', file=file)
for count, b in enumerate(encoded_bytes):
if count % 8 == 0:
print("\n" + indent, end='', file=file)
else:
print(" ", end='', file=file)
print("0x{:02x},".format(b), end='', file=file)
print("\n" + trailer, file=file)
if len_format is not None:
print(len_format.format(len(encoded_bytes)), file=file)
def emit_c_public(self, file=sys.stdout):
self._emit(
header="const unsigned char {}_pub_key[] = {{".format(self.shortname()),
trailer="};",
encoded_bytes=self.get_public_bytes(),
indent=" ",
len_format="const unsigned int {}_pub_key_len = {{}};".format(self.shortname()),
file=file)
def emit_rust_public(self, file=sys.stdout):
self._emit(
header="static {}_PUB_KEY: &[u8] = &[".format(self.shortname().upper()),
trailer="];",
encoded_bytes=self.get_public_bytes(),
indent=" ",
file=file)
def emit_private(self, minimal, file=sys.stdout):
self._emit(
header="const unsigned char enc_priv_key[] = {",
trailer="};",
encoded_bytes=self.get_private_bytes(minimal),
indent=" ",
len_format="const unsigned int enc_priv_key_len = {};",
file=file)
@@ -0,0 +1,165 @@
"""
RSA Key management
"""
# SPDX-License-Identifier: Apache-2.0
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives.asymmetric.padding import PSS, MGF1
from cryptography.hazmat.primitives.hashes import SHA256
from .general import KeyClass
# Sizes that bootutil will recognize
RSA_KEY_SIZES = [2048, 3072]
class RSAUsageError(Exception):
pass
class RSAPublic(KeyClass):
"""The public key can only do a few operations"""
def __init__(self, key):
self.key = key
def key_size(self):
return self.key.key_size
def shortname(self):
return "rsa"
def _unsupported(self, name):
raise RSAUsageError("Operation {} requires private key".format(name))
def _get_public(self):
return self.key
def get_public_bytes(self):
# The key embedded into MCUboot is in PKCS1 format.
return self._get_public().public_bytes(
encoding=serialization.Encoding.DER,
format=serialization.PublicFormat.PKCS1)
def get_private_bytes(self, minimal):
self._unsupported('get_private_bytes')
def export_private(self, path, passwd=None):
self._unsupported('export_private')
def export_public(self, path):
"""Write the public key to the given file."""
pem = self._get_public().public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo)
with open(path, 'wb') as f:
f.write(pem)
def sig_type(self):
return "PKCS1_PSS_RSA{}_SHA256".format(self.key_size())
def sig_tlv(self):
return"RSA{}".format(self.key_size())
def sig_len(self):
return self.key_size() / 8
def verify(self, signature, payload):
k = self.key
if isinstance(self.key, rsa.RSAPrivateKey):
k = self.key.public_key()
return k.verify(signature=signature, data=payload,
padding=PSS(mgf=MGF1(SHA256()), salt_length=32),
algorithm=SHA256())
class RSA(RSAPublic):
"""
Wrapper around an RSA key, with imgtool support.
"""
def __init__(self, key):
"""The key should be a private key from cryptography"""
self.key = key
@staticmethod
def generate(key_size=2048):
if key_size not in RSA_KEY_SIZES:
raise RSAUsageError("Key size {} is not supported by MCUboot"
.format(key_size))
pk = rsa.generate_private_key(
public_exponent=65537,
key_size=key_size,
backend=default_backend())
return RSA(pk)
def _get_public(self):
return self.key.public_key()
def _build_minimal_rsa_privkey(self, der):
'''
Builds a new DER that only includes N/E/D/P/Q RSA parameters;
standard DER private bytes provided by OpenSSL also includes
CRT params (DP/DQ/QP) which can be removed.
'''
OFFSET_N = 7 # N is always located at this offset
b = bytearray(der)
off = OFFSET_N
if b[off + 1] != 0x82:
raise RSAUsageError("Error parsing N while minimizing")
len_N = (b[off + 2] << 8) + b[off + 3] + 4
off += len_N
if b[off + 1] != 0x03:
raise RSAUsageError("Error parsing E while minimizing")
len_E = b[off + 2] + 4
off += len_E
if b[off + 1] != 0x82:
raise RSAUsageError("Error parsing D while minimizing")
len_D = (b[off + 2] << 8) + b[off + 3] + 4
off += len_D
if b[off + 1] != 0x81:
raise RSAUsageError("Error parsing P while minimizing")
len_P = b[off + 2] + 3
off += len_P
if b[off + 1] != 0x81:
raise RSAUsageError("Error parsing Q while minimizing")
len_Q = b[off + 2] + 3
off += len_Q
# adjust DER size for removed elements
b[2] = (off - 4) >> 8
b[3] = (off - 4) & 0xff
return b[:off]
def get_private_bytes(self, minimal):
priv = self.key.private_bytes(
encoding=serialization.Encoding.DER,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption())
if minimal:
priv = self._build_minimal_rsa_privkey(priv)
return priv
def export_private(self, path, passwd=None):
"""Write the private key to the given file, protecting it with the
optional password."""
if passwd is None:
enc = serialization.NoEncryption()
else:
enc = serialization.BestAvailableEncryption(passwd)
pem = self.key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=enc)
with open(path, 'wb') as f:
f.write(pem)
def sign(self, payload):
# The verification code only allows the salt length to be the
# same as the hash length, 32.
return self.key.sign(
data=payload,
padding=PSS(mgf=MGF1(SHA256()), salt_length=32),
algorithm=SHA256())
@@ -0,0 +1,117 @@
"""
Tests for RSA keys
"""
# SPDX-License-Identifier: Apache-2.0
import io
import os
import sys
import tempfile
import unittest
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives.asymmetric.padding import PSS, MGF1
from cryptography.hazmat.primitives.hashes import SHA256
# Setup sys path so 'imgtool' is in it.
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__),
'../..')))
from imgtool.keys import load, RSA, RSAUsageError
from imgtool.keys.rsa import RSA_KEY_SIZES
class KeyGeneration(unittest.TestCase):
def setUp(self):
self.test_dir = tempfile.TemporaryDirectory()
def tname(self, base):
return os.path.join(self.test_dir.name, base)
def tearDown(self):
self.test_dir.cleanup()
def test_keygen(self):
# Try generating a RSA key with non-supported size
with self.assertRaises(RSAUsageError):
RSA.generate(key_size=1024)
for key_size in RSA_KEY_SIZES:
name1 = self.tname("keygen.pem")
k = RSA.generate(key_size=key_size)
k.export_private(name1, b'secret')
# Try loading the key without a password.
self.assertIsNone(load(name1))
k2 = load(name1, b'secret')
pubname = self.tname('keygen-pub.pem')
k2.export_public(pubname)
pk2 = load(pubname)
# We should be able to export the public key from the loaded
# public key, but not the private key.
pk2.export_public(self.tname('keygen-pub2.pem'))
self.assertRaises(RSAUsageError, pk2.export_private,
self.tname('keygen-priv2.pem'))
def test_emit(self):
"""Basic sanity check on the code emitters."""
for key_size in RSA_KEY_SIZES:
k = RSA.generate(key_size=key_size)
ccode = io.StringIO()
k.emit_c_public(ccode)
self.assertIn("rsa_pub_key", ccode.getvalue())
self.assertIn("rsa_pub_key_len", ccode.getvalue())
rustcode = io.StringIO()
k.emit_rust_public(rustcode)
self.assertIn("RSA_PUB_KEY", rustcode.getvalue())
def test_emit_pub(self):
"""Basic sanity check on the code emitters, from public key."""
pubname = self.tname("public.pem")
for key_size in RSA_KEY_SIZES:
k = RSA.generate(key_size=key_size)
k.export_public(pubname)
k2 = load(pubname)
ccode = io.StringIO()
k2.emit_c_public(ccode)
self.assertIn("rsa_pub_key", ccode.getvalue())
self.assertIn("rsa_pub_key_len", ccode.getvalue())
rustcode = io.StringIO()
k2.emit_rust_public(rustcode)
self.assertIn("RSA_PUB_KEY", rustcode.getvalue())
def test_sig(self):
for key_size in RSA_KEY_SIZES:
k = RSA.generate(key_size=key_size)
buf = b'This is the message'
sig = k.sign(buf)
# The code doesn't have any verification, so verify this
# manually.
k.key.public_key().verify(
signature=sig,
data=buf,
padding=PSS(mgf=MGF1(SHA256()), salt_length=32),
algorithm=SHA256())
# Modify the message to make sure the signature fails.
self.assertRaises(InvalidSignature,
k.key.public_key().verify,
signature=sig,
data=b'This is thE message',
padding=PSS(mgf=MGF1(SHA256()), salt_length=32),
algorithm=SHA256())
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,109 @@
"""
X25519 key management
"""
# SPDX-License-Identifier: Apache-2.0
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import x25519
from .general import KeyClass
class X25519UsageError(Exception):
pass
class X25519Public(KeyClass):
def __init__(self, key):
self.key = key
def shortname(self):
return "x25519"
def _unsupported(self, name):
raise X25519UsageError("Operation {} requires private key".format(name))
def _get_public(self):
return self.key
def get_public_bytes(self):
# The key is embedded into MBUboot in "SubjectPublicKeyInfo" format
return self._get_public().public_bytes(
encoding=serialization.Encoding.DER,
format=serialization.PublicFormat.SubjectPublicKeyInfo)
def get_private_bytes(self, minimal):
self._unsupported('get_private_bytes')
def export_private(self, path, passwd=None):
self._unsupported('export_private')
def export_public(self, path):
"""Write the public key to the given file."""
pem = self._get_public().public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo)
with open(path, 'wb') as f:
f.write(pem)
def sig_type(self):
return "X25519"
def sig_tlv(self):
return "X25519"
def sig_len(self):
return 32
class X25519(X25519Public):
"""
Wrapper around an X25519 private key.
"""
def __init__(self, key):
"""key should be an instance of EllipticCurvePrivateKey"""
self.key = key
@staticmethod
def generate():
pk = x25519.X25519PrivateKey.generate()
return X25519(pk)
def _get_public(self):
return self.key.public_key()
def get_private_bytes(self, minimal):
return self.key.private_bytes(
encoding=serialization.Encoding.DER,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption())
def export_private(self, path, passwd=None):
"""
Write the private key to the given file, protecting it with the
optional password.
"""
if passwd is None:
enc = serialization.NoEncryption()
else:
enc = serialization.BestAvailableEncryption(passwd)
pem = self.key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=enc)
with open(path, 'wb') as f:
f.write(pem)
def sign_digest(self, digest):
"""Return the actual signature"""
return self.key.sign(data=digest)
def verify_digest(self, signature, digest):
"""Verify that signature is valid for given digest"""
k = self.key
if isinstance(self.key, x25519.X25519PrivateKey):
k = self.key.public_key()
return k.verify(signature=signature, data=digest)
@@ -0,0 +1,395 @@
#! /usr/bin/env python3
#
# Copyright 2017-2020 Linaro Limited
# Copyright 2019-2021 Arm Limited
#
# SPDX-License-Identifier: Apache-2.0
#
# 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.
import re
import click
import getpass
import imgtool.keys as keys
import sys
from imgtool import image, imgtool_version
from imgtool.version import decode_version
from .keys import (
RSAUsageError, ECDSAUsageError, Ed25519UsageError, X25519UsageError)
MIN_PYTHON_VERSION = (3, 6)
if sys.version_info < MIN_PYTHON_VERSION:
sys.exit("Python %s.%s or newer is required by imgtool."
% MIN_PYTHON_VERSION)
def gen_rsa2048(keyfile, passwd):
keys.RSA.generate().export_private(path=keyfile, passwd=passwd)
def gen_rsa3072(keyfile, passwd):
keys.RSA.generate(key_size=3072).export_private(path=keyfile,
passwd=passwd)
def gen_ecdsa_p256(keyfile, passwd):
keys.ECDSA256P1.generate().export_private(keyfile, passwd=passwd)
def gen_ecdsa_p224(keyfile, passwd):
print("TODO: p-224 not yet implemented")
def gen_ed25519(keyfile, passwd):
keys.Ed25519.generate().export_private(path=keyfile, passwd=passwd)
def gen_x25519(keyfile, passwd):
keys.X25519.generate().export_private(path=keyfile, passwd=passwd)
valid_langs = ['c', 'rust']
keygens = {
'rsa-2048': gen_rsa2048,
'rsa-3072': gen_rsa3072,
'ecdsa-p256': gen_ecdsa_p256,
'ecdsa-p224': gen_ecdsa_p224,
'ed25519': gen_ed25519,
'x25519': gen_x25519,
}
def load_key(keyfile):
# TODO: better handling of invalid pass-phrase
key = keys.load(keyfile)
if key is not None:
return key
passwd = getpass.getpass("Enter key passphrase: ").encode('utf-8')
return keys.load(keyfile, passwd)
def get_password():
while True:
passwd = getpass.getpass("Enter key passphrase: ")
passwd2 = getpass.getpass("Reenter passphrase: ")
if passwd == passwd2:
break
print("Passwords do not match, try again")
# Password must be bytes, always use UTF-8 for consistent
# encoding.
return passwd.encode('utf-8')
@click.option('-p', '--password', is_flag=True,
help='Prompt for password to protect key')
@click.option('-t', '--type', metavar='type', required=True,
type=click.Choice(keygens.keys()), prompt=True,
help='{}'.format('One of: {}'.format(', '.join(keygens.keys()))))
@click.option('-k', '--key', metavar='filename', required=True)
@click.command(help='Generate pub/private keypair')
def keygen(type, key, password):
password = get_password() if password else None
keygens[type](key, password)
@click.option('-l', '--lang', metavar='lang', default=valid_langs[0],
type=click.Choice(valid_langs))
@click.option('-k', '--key', metavar='filename', required=True)
@click.command(help='Dump public key from keypair')
def getpub(key, lang):
key = load_key(key)
if key is None:
print("Invalid passphrase")
elif lang == 'c':
key.emit_c_public()
elif lang == 'rust':
key.emit_rust_public()
else:
raise ValueError("BUG: should never get here!")
@click.option('--minimal', default=False, is_flag=True,
help='Reduce the size of the dumped private key to include only '
'the minimum amount of data required to decrypt. This '
'might require changes to the build config. Check the docs!'
)
@click.option('-k', '--key', metavar='filename', required=True)
@click.command(help='Dump private key from keypair')
def getpriv(key, minimal):
key = load_key(key)
if key is None:
print("Invalid passphrase")
try:
key.emit_private(minimal)
except (RSAUsageError, ECDSAUsageError, Ed25519UsageError,
X25519UsageError) as e:
raise click.UsageError(e)
@click.argument('imgfile')
@click.option('-k', '--key', metavar='filename')
@click.command(help="Check that signed image can be verified by given key")
def verify(key, imgfile):
key = load_key(key) if key else None
ret, version, digest = image.Image.verify(imgfile, key)
if ret == image.VerifyResult.OK:
print("Image was correctly validated")
print("Image version: {}.{}.{}+{}".format(*version))
print("Image digest: {}".format(digest.hex()))
return
elif ret == image.VerifyResult.INVALID_MAGIC:
print("Invalid image magic; is this an MCUboot image?")
elif ret == image.VerifyResult.INVALID_TLV_INFO_MAGIC:
print("Invalid TLV info magic; is this an MCUboot image?")
elif ret == image.VerifyResult.INVALID_HASH:
print("Image has an invalid sha256 digest")
elif ret == image.VerifyResult.INVALID_SIGNATURE:
print("No signature found for the given key")
else:
print("Unknown return code: {}".format(ret))
sys.exit(1)
def validate_version(ctx, param, value):
try:
decode_version(value)
return value
except ValueError as e:
raise click.BadParameter("{}".format(e))
def validate_security_counter(ctx, param, value):
if value is not None:
if value.lower() == 'auto':
return 'auto'
else:
try:
return int(value, 0)
except ValueError:
raise click.BadParameter(
"{} is not a valid integer. Please use code literals "
"prefixed with 0b/0B, 0o/0O, or 0x/0X as necessary."
.format(value))
def validate_header_size(ctx, param, value):
min_hdr_size = image.IMAGE_HEADER_SIZE
if value < min_hdr_size:
raise click.BadParameter(
"Minimum value for -H/--header-size is {}".format(min_hdr_size))
return value
def get_dependencies(ctx, param, value):
if value is not None:
versions = []
images = re.findall(r"\((\d+)", value)
if len(images) == 0:
raise click.BadParameter(
"Image dependency format is invalid: {}".format(value))
raw_versions = re.findall(r",\s*([0-9.+]+)\)", value)
if len(images) != len(raw_versions):
raise click.BadParameter(
'''There's a mismatch between the number of dependency images
and versions in: {}'''.format(value))
for raw_version in raw_versions:
try:
versions.append(decode_version(raw_version))
except ValueError as e:
raise click.BadParameter("{}".format(e))
dependencies = dict()
dependencies[image.DEP_IMAGES_KEY] = images
dependencies[image.DEP_VERSIONS_KEY] = versions
return dependencies
class BasedIntParamType(click.ParamType):
name = 'integer'
def convert(self, value, param, ctx):
try:
return int(value, 0)
except ValueError:
self.fail('%s is not a valid integer. Please use code literals '
'prefixed with 0b/0B, 0o/0O, or 0x/0X as necessary.'
% value, param, ctx)
@click.argument('outfile')
@click.argument('infile')
@click.option('--custom-tlv', required=False, nargs=2, default=[],
multiple=True, metavar='[tag] [value]',
help='Custom TLV that will be placed into protected area. '
'Add "0x" prefix if the value should be interpreted as an '
'integer, otherwise it will be interpreted as a string. '
'Specify the option multiple times to add multiple TLVs.')
@click.option('-R', '--erased-val', type=click.Choice(['0', '0xff']),
required=False,
help='The value that is read back from erased flash.')
@click.option('-x', '--hex-addr', type=BasedIntParamType(), required=False,
help='Adjust address in hex output file.')
@click.option('-L', '--load-addr', type=BasedIntParamType(), required=False,
help='Load address for image when it should run from RAM.')
@click.option('-F', '--rom-fixed', type=BasedIntParamType(), required=False,
help='Set flash address the image is built for.')
@click.option('--save-enctlv', default=False, is_flag=True,
help='When upgrading, save encrypted key TLVs instead of plain '
'keys. Enable when BOOT_SWAP_SAVE_ENCTLV config option '
'was set.')
@click.option('-E', '--encrypt', metavar='filename',
help='Encrypt image using the provided public key. '
'(Not supported in direct-xip or ram-load mode.)')
@click.option('--encrypt-keylen', default='128',
type=click.Choice(['128','256']),
help='When encrypting the image using AES, select a 128 bit or '
'256 bit key len.')
@click.option('-e', '--endian', type=click.Choice(['little', 'big']),
default='little', help="Select little or big endian")
@click.option('--overwrite-only', default=False, is_flag=True,
help='Use overwrite-only instead of swap upgrades')
@click.option('--boot-record', metavar='sw_type', help='Create CBOR encoded '
'boot record TLV. The sw_type represents the role of the '
'software component (e.g. CoFM for coprocessor firmware). '
'[max. 12 characters]')
@click.option('-M', '--max-sectors', type=int,
help='When padding allow for this amount of sectors (defaults '
'to 128)')
@click.option('--confirm', default=False, is_flag=True,
help='When padding the image, mark it as confirmed (implies '
'--pad)')
@click.option('--pad', default=False, is_flag=True,
help='Pad image to --slot-size bytes, adding trailer magic')
@click.option('-S', '--slot-size', type=BasedIntParamType(), required=True,
help='Size of the slot. If the slots have different sizes, use '
'the size of the secondary slot.')
@click.option('--pad-header', default=False, is_flag=True,
help='Add --header-size zeroed bytes at the beginning of the '
'image')
@click.option('-H', '--header-size', callback=validate_header_size,
type=BasedIntParamType(), required=True)
@click.option('--pad-sig', default=False, is_flag=True,
help='Add 0-2 bytes of padding to ECDSA signature '
'(for mcuboot <1.5)')
@click.option('-d', '--dependencies', callback=get_dependencies,
required=False, help='''Add dependence on another image, format:
"(<image_ID>,<image_version>), ... "''')
@click.option('-s', '--security-counter', callback=validate_security_counter,
help='Specify the value of security counter. Use the `auto` '
'keyword to automatically generate it from the image version.')
@click.option('-v', '--version', callback=validate_version, required=True)
@click.option('--align', type=click.Choice(['1', '2', '4', '8']),
required=True)
@click.option('--public-key-format', type=click.Choice(['hash', 'full']),
default='hash', help='In what format to add the public key to '
'the image manifest: full key or hash of the key.')
@click.option('-k', '--key', metavar='filename')
@click.command(help='''Create a signed or unsigned image\n
INFILE and OUTFILE are parsed as Intel HEX if the params have
.hex extension, otherwise binary format is used''')
def sign(key, public_key_format, align, version, pad_sig, header_size,
pad_header, slot_size, pad, confirm, max_sectors, overwrite_only,
endian, encrypt_keylen, encrypt, infile, outfile, dependencies,
load_addr, hex_addr, erased_val, save_enctlv, security_counter,
boot_record, custom_tlv, rom_fixed):
if confirm:
# Confirmed but non-padded images don't make much sense, because
# otherwise there's no trailer area for writing the confirmed status.
pad = True
img = image.Image(version=decode_version(version), header_size=header_size,
pad_header=pad_header, pad=pad, confirm=confirm,
align=int(align), slot_size=slot_size,
max_sectors=max_sectors, overwrite_only=overwrite_only,
endian=endian, load_addr=load_addr, rom_fixed=rom_fixed,
erased_val=erased_val, save_enctlv=save_enctlv,
security_counter=security_counter)
img.load(infile)
key = load_key(key) if key else None
enckey = load_key(encrypt) if encrypt else None
if enckey and key:
if ((isinstance(key, keys.ECDSA256P1) and
not isinstance(enckey, keys.ECDSA256P1Public))
or (isinstance(key, keys.RSA) and
not isinstance(enckey, keys.RSAPublic))):
# FIXME
raise click.UsageError("Signing and encryption must use the same "
"type of key")
if pad_sig and hasattr(key, 'pad_sig'):
key.pad_sig = True
# Get list of custom protected TLVs from the command-line
custom_tlvs = {}
for tlv in custom_tlv:
tag = int(tlv[0], 0)
if tag in custom_tlvs:
raise click.UsageError('Custom TLV %s already exists.' % hex(tag))
if tag in image.TLV_VALUES.values():
raise click.UsageError(
'Custom TLV %s conflicts with predefined TLV.' % hex(tag))
value = tlv[1]
if value.startswith('0x'):
if len(value[2:]) % 2:
raise click.UsageError('Custom TLV length is odd.')
custom_tlvs[tag] = bytes.fromhex(value[2:])
else:
custom_tlvs[tag] = value.encode('utf-8')
img.create(key, public_key_format, enckey, dependencies, boot_record,
custom_tlvs, int(encrypt_keylen))
img.save(outfile, hex_addr)
class AliasesGroup(click.Group):
_aliases = {
"create": "sign",
}
def list_commands(self, ctx):
cmds = [k for k in self.commands]
aliases = [k for k in self._aliases]
return sorted(cmds + aliases)
def get_command(self, ctx, cmd_name):
rv = click.Group.get_command(self, ctx, cmd_name)
if rv is not None:
return rv
if cmd_name in self._aliases:
return click.Group.get_command(self, ctx, self._aliases[cmd_name])
return None
@click.command(help='Print imgtool version information')
def version():
print(imgtool_version)
@click.command(cls=AliasesGroup,
context_settings=dict(help_option_names=['-h', '--help']))
def imgtool():
pass
imgtool.add_command(keygen)
imgtool.add_command(getpub)
imgtool.add_command(getpriv)
imgtool.add_command(verify)
imgtool.add_command(sign)
imgtool.add_command(version)
if __name__ == '__main__':
imgtool()
@@ -0,0 +1,55 @@
# Copyright 2017 Linaro Limited
#
# SPDX-License-Identifier: Apache-2.0
#
# 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.
"""
Semi Semantic Versioning
Implements a subset of semantic versioning that is supportable by the image
header.
"""
from collections import namedtuple
import re
SemiSemVersion = namedtuple('SemiSemVersion', ['major', 'minor', 'revision',
'build'])
version_re = re.compile(
r"""^([1-9]\d*|0)(\.([1-9]\d*|0)(\.([1-9]\d*|0)(\+([1-9]\d*|0))?)?)?$""")
def decode_version(text):
"""Decode the version string, which should be of the form maj.min.rev+build
"""
m = version_re.match(text)
if m:
result = SemiSemVersion(
int(m.group(1)) if m.group(1) else 0,
int(m.group(3)) if m.group(3) else 0,
int(m.group(5)) if m.group(5) else 0,
int(m.group(7)) if m.group(7) else 0)
return result
else:
msg = "Invalid version number, should be maj.min.rev+build with later "
msg += "parts optional"
raise ValueError(msg)
if __name__ == '__main__':
print(decode_version("1.2"))
print(decode_version("1.0"))
print(decode_version("0.0.2+75"))
print(decode_version("0.0.0+00"))
+8
View File
@@ -0,0 +1,8 @@
#! /bin/bash
#
# SPDX-License-Identifier: Apache-2.0
source $(dirname $0)/../target.sh
# Start the jlink gdb server
JLinkGDBServer -if swd -device $SOC -speed auto
+7
View File
@@ -0,0 +1,7 @@
#!/bin/bash
#
# SPDX-License-Identifier: Apache-2.0
source $(dirname $0)/../target.sh
JLinkExe -speed auto -si SWD -device $SOC
+135
View File
@@ -0,0 +1,135 @@
// Copyright (C) 2019, Linaro Ltd
//
// SPDX-License-Identifier: Apache-2.0
//
// 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.
// This file is a Binary Template file for the 010 Editor
// (http://www.sweetscape.com/010editor/) to allow it to show the
// structure of an MCUboot image.
LittleEndian();
struct ENTRY {
uint32 id;
uint32 offset;
uint32 size;
uint32 pad;
};
// The simulator writes the partition table at the beginning of the
// image, so that we can tell where the partitions are. If you are
// trying to view an image captured from a device, you can either
// construct a synthetic partition table in the file, or change code
// described below to hardcode one.
struct PTABLE {
uchar pheader[8];
if (ptable.pheader != "mcuboot\0") {
// NOTE: Put code here to hard code a partition table, and
// continue.
Warning("Invalid magic on ptable header");
return -1;
} else {
uint32 count;
struct ENTRY entries[count];
}
};
struct PTABLE ptable;
struct IMAGE_VERSION {
uchar major;
uchar minor;
uint16 revision;
uint32 build_num;
};
struct IHDR {
uint32 magic <format=hex>;
uint32 load_addr <format=hex>;
uint16 hdr_size <format=hex>;
uint16 protect_size <format=hex>;
uint32 img_size <format=hex>;
uint32 flags;
struct IMAGE_VERSION ver;
uint32 _pad1;
};
struct TLV_HDR {
uint16 magic;
uint16 tlv_tot;
};
struct TLV {
uchar type <format=hex>;
uchar pad;
uint16 len;
switch (type) {
case 0x01: // keyhash
uchar keyhash[len];
break;
case 0x40: // dependency
if (len != 12) {
Warning("Invalid dependency size");
return -1;
}
uchar image_id;
uchar pad1;
uint16 pad2;
struct IMAGE_VERSION version;
break;
default:
// Other, just consume the data.
uchar data[len];
}
};
local int i;
local int epos;
for (i = 0; i < ptable.count; i++) {
FSeek(ptable.entries[i].offset);
switch (ptable.entries[i].id) {
case 1:
case 2:
case 4:
case 5:
struct IMAGE {
struct IHDR ihdr;
if (ihdr.magic == 0x96f3b83d) {
uchar payload[ihdr.img_size];
epos = FTell();
struct TLV_HDR tlv_hdr;
if (tlv_hdr.magic == 0x6907) {
epos += tlv_hdr.tlv_tot;
while (FTell() < epos) {
struct TLV tlv;
}
}
}
// uchar block[ptable.entries[i].size];
} image;
break;
case 3:
struct SCRATCH {
uchar data[ptable.entries[i].size];
} scratch;
break;
default:
break;
}
}
@@ -0,0 +1,5 @@
cryptography>=2.6
intelhex
click
cbor>=1.0.0
pycryptodome>=3.20
+31
View File
@@ -0,0 +1,31 @@
# SPDX-License-Identifier: Apache-2.0
import setuptools
from imgtool import imgtool_version
setuptools.setup(
name="imgtool",
version=imgtool_version,
author="The MCUboot committers",
author_email="mcuboot@groups.io",
description=("MCUboot's image signing and key management"),
license="Apache Software License",
url="http://github.com/mcu-tools/mcuboot",
packages=setuptools.find_packages(),
python_requires='>=3.6',
install_requires=[
'cryptography>=2.4.2',
'intelhex>=2.2.1',
'click',
'cbor>=1.0.0',
],
entry_points={
"console_scripts": ["imgtool=imgtool.main:imgtool"]
},
classifiers=[
"Programming Language :: Python :: 3",
"Development Status :: 4 - Beta",
"Topic :: Software Development :: Build Tools",
"License :: OSI Approved :: Apache Software License",
],
)
+105
View File
@@ -0,0 +1,105 @@
# this is a wrapper function to allow additional parsing and arguments such
# as a custom TLV with a hash to be added dynamically based on a key being
# provided
import subprocess
import click
import json
import platform
@click.command()
@click.option('-s','--sdk', help='Path to the SDK to find additional scripts and tools as needed')
@click.option('-t','--toolchain',help='Path to the toolchain')
@click.option('-n','--name',help="name of project")
@click.option('-c','--color',help="color of the LED")
def make_binary(sdk,toolchain,name,color):
# Select the proper default python executable depending on OS
python_exe = "python3"
if "Window" in platform.system():
python_exe = "python"
print("sdk:", sdk)
print("toolchain:", toolchain)
print("projectName:", name)
f = open('../signingArgs.json')
config = json.load(f)
f.close()
# config = {
# "version" : "1.0.0",
# "addKey" : True
# "privateKeyPath" : "/source/third_party/mcuboot/image_signTEST.pem"
# }
subprocess.run([toolchain+'/bin/tiarmobjcopy',name+'.out',
'--output-target','binary','sample_image-unsigned.bin'],
capture_output=True)
if(type(config["version"]) is not list):
versionList = [config["version"]]
else:
versionList = config["version"]
retVal = config.get("slotSize")
if(retVal is not None):
slotSize = retVal
else:
slotSize = 0x2800
retVal = config.get("bankSize")
if(retVal is not None):
bankSize = retVal
else:
bankSize = 0x20000
retVal = config.get("offset")
if(retVal is not None):
offset = retVal
else:
offset = 0x4800
# iterate over all versions provided
for ver in versionList:
versionStr = ver.replace('.','_')
imgtool_optional_args = ['--header-size','0x100','--align','4','--slot-size', hex(slotSize),
'--pad','--version',ver,'--pad-header','--overwrite-only','--key',
sdk+config["privateKeyPath"]]
if "addKey" in config:
print("adding a key")
imgtool_optional_args.extend(["--custom-tlv", "0xCC", "0xb93c72b74bc8487d29827005f80d635918f91bc22b14d7ed05714d58f96702dd"])
keyFile = open("keyFile.bin", 'wb')
keyArray = [0x603deb10, 0x15ca71be, 0x2b73aef0, 0x857d7781,
0x1f352c07, 0x3b6108d7, 0x2d9810a3, 0x0914dff4]
keyString = ''.join(format(x, '08x') for x in keyArray)
keyFile.write(bytearray.fromhex(keyString))
keyFile.close()
if "removeKey" in config:
print("removing a key")
imgtool_optional_args.extend(["--custom-tlv", "0xCD", "0x555555555555555555555555555555"])
outFilename = 'sample_image_signed_' + hex(offset) + '_v'+versionStr+'_'+color
imgtool_args = [python_exe,sdk+'/source/third_party/mcuboot/scripts/imgtool.py',
'sign'] + imgtool_optional_args + ['sample_image-unsigned.bin',
outFilename+'.bin']
print(imgtool_args)
proc = subprocess.run(imgtool_args, capture_output=True)
print(proc)
txtConversion_args = [python_exe,sdk+'/source/third_party/mcuboot/scripts/bin-to-ti-txt.py',
'-f',outFilename+'.bin','-o',outFilename+'.txt','--encrypt','-c',
outFilename+'_encrypted.txt','-s',hex(bankSize+offset)]
proc = subprocess.run(txtConversion_args, capture_output=True)
print(proc)
if __name__ == "__main__":
make_binary()