init:初始框架
This commit is contained in:
@@ -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__ */
|
||||
+73
@@ -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__ */
|
||||
+150
@@ -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
|
||||
+53
@@ -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
|
||||
+184
@@ -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
|
||||
+35
@@ -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
|
||||
+122
@@ -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_ */
|
||||
+141
@@ -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_ */
|
||||
+63
@@ -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_ */
|
||||
+57
@@ -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_ */
|
||||
+131
@@ -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_ */
|
||||
+83
@@ -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_ */
|
||||
+205
@@ -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 */
|
||||
Vendored
+377
@@ -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__ */
|
||||
+30
@@ -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
|
||||
+103
@@ -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, ¶m)) != 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, ¶m) != 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 */
|
||||
+78
@@ -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 */
|
||||
Vendored
+48
@@ -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, ¶m)) {
|
||||
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, ¶m)) {
|
||||
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, ¶m)) {
|
||||
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 */
|
||||
+693
@@ -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 */
|
||||
+367
@@ -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 */
|
||||
+103
@@ -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 */
|
||||
+122
@@ -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, ¶ms->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( ¶ms, 0, sizeof(mbedtls_asn1_buf) );
|
||||
|
||||
if( ( ret = mbedtls_asn1_get_alg( p, end, alg, ¶ms ) ) != 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
@@ -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();
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,5 @@
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEIPCK5E8Y1bkZMWyEFktrFIaIt3A5BQPMDNCzEAXiGDBqoAoGCCqGSM49
|
||||
AwEHoUQDQgAEQcxmxiiipZVOYMID4DuBoQmmKzciU0bt0Ap2bgZ5OjXYqn8Reaiw
|
||||
uk1EyEULSEgjZJda3es8W13usnOAgMW78Q==
|
||||
-----END EC PRIVATE KEY-----
|
||||
@@ -0,0 +1,5 @@
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEINeY1S+DASQ701QrflXtTHRhGQCw+VBagk/h6OwGO8/xoAoGCCqGSM49
|
||||
AwEHoUQDQgAEKstAPOj+7VukSZWhqR2u6Nu+GTfNFPsvJFc35ZU5iNmUudZa69fN
|
||||
1TCK1v5IskpqgQ7l8H2LaDTMOmr8U476wQ==
|
||||
-----END EC PRIVATE KEY-----
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 ];
|
||||
}
|
||||
@@ -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"))
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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",
|
||||
],
|
||||
)
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user