diff --git a/crypto/controlse/Kconfig b/crypto/controlse/Kconfig new file mode 100644 index 000000000..550d09260 --- /dev/null +++ b/crypto/controlse/Kconfig @@ -0,0 +1,41 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config CRYPTO_CONTROLSE + bool "Control Secure Element device" + default n + depends on DEV_SE05X + depends on CRYPTO_MBEDTLS + depends on MBEDTLS_VERSION = "3.4.0" + select MBEDTLS_ECDSA_C + select MBEDTLS_ECP_C + select MBEDTLS_ECP_DP_SECP256R1_ENABLED + select MBEDTLS_PEM_WRITE_C + select MBEDTLS_PK_WRITE_C + select MBEDTLS_X509_CSR_PARSE_C + select MBEDTLS_X509_CSR_WRITE_C + select MBEDTLS_X509_CRT_WRITE_C + ---help--- + Enable the controlse utility. This program is used control the + secure element device + +if CRYPTO_CONTROLSE + +config CRYPTO_CONTROLSE_PROGNAME + string "Program name" + default "controlse" + ---help--- + This is the name of the program that will be used when the NSH ELF + program is installed. + +config CRYPTO_CONTROLSE_PRIORITY + int "Controlse utility task priority" + default 100 + +config CRYPTO_CONTROLSE_STACKSIZE + int "Controlse utility stack size" + default DEFAULT_TASK_STACKSIZE + +endif diff --git a/crypto/controlse/Make.defs b/crypto/controlse/Make.defs new file mode 100644 index 000000000..0e1fad585 --- /dev/null +++ b/crypto/controlse/Make.defs @@ -0,0 +1,23 @@ +############################################################################ +# apps/crypto/controlse/Make.defs +# +# 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. +# +############################################################################ + +ifneq ($(CONFIG_CRYPTO_CONTROLSE),) +CONFIGURED_APPS += $(APPDIR)/crypto/controlse +endif diff --git a/crypto/controlse/Makefile b/crypto/controlse/Makefile new file mode 100644 index 000000000..6ad484059 --- /dev/null +++ b/crypto/controlse/Makefile @@ -0,0 +1,34 @@ +############################################################################ +# apps/crypto/controlse/Makefile +# +# 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 $(APPDIR)/Make.defs + +# controlse built-in application info + +PROGNAME = $(CONFIG_CRYPTO_CONTROLSE_PROGNAME) +PRIORITY = $(CONFIG_CRYPTO_CONTROLSE_PRIORITY) +STACKSIZE = $(CONFIG_CRYPTO_CONTROLSE_STACKSIZE) + +# controlse main source + +MAINSRC = controlse_main.c +CSRCS = x509_utils.c mbedtls_extension.c + +include $(APPDIR)/Application.mk diff --git a/crypto/controlse/controlse_main.c b/crypto/controlse/controlse_main.c new file mode 100644 index 000000000..f2ed327b8 --- /dev/null +++ b/crypto/controlse/controlse_main.c @@ -0,0 +1,737 @@ +/**************************************************************************** + * apps/crypto/controlse/controlse_main.c + * + * 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. + * + ****************************************************************************/ + +/* Copyright 2023 NXP */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#define MBEDTLS_ALLOW_PRIVATE_ACCESS +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_STACK_COLORATION +#include +#include +#endif + +#include "x509_utils.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define EOT 0x04 + +#define DEFAULT_SETTINGS \ + { \ + .se05x_dev_filename = default_se05x_device, 0 \ + } + +#define TBS_HASH_BUFFER_SIZE 32 +#define SIGNATURE_BUFFER_SIZE 300 +#define SYMM_KEY_BUFFER_SIZE 300 +#define RAW_KEY_BUFFER_SIZE 600 +#define DEFAULT_BUFFER_SIZE 1000 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +typedef enum +{ + KEYSTORE_NO_ACTION = 0, + KEYSTORE_READ, + KEYSTORE_WRITE, + KEYSTORE_GENERATE, + KEYSTORE_DELETE, + KEYSTORE_DERIVE_SYMM_KEY, + KEYSTORE_CREATE_SIGNATURE, + KEYSTORE_VERIFY_SIGNATURE, + KEYSTORE_SIGN_CSR, + KEYSTORE_VERIFY_CERTIFICATE, + KEYSTORE_GET_INFO, + KEYSTORE_GET_UID, +} keystore_operation; + +struct settings_t +{ + FAR const char *se05x_dev_filename; + FAR char *input_filename; + FAR char *signature_filename; + bool skip_process; + keystore_operation operation; + bool raw_data_in_device; + bool interface_with_pem; + uint32_t key_id; + uint32_t private_key_id; + bool show_stack_used; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const char default_se05x_device[] = "/dev/se05x"; +static const char enter_key_hex[] = "enter key(hex)"; +static const char enter_data_pem[] = "enter data(pem)"; +static const char enter_data_raw[] = "enter data(raw)"; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void print_usage(FAR FILE *f, FAR char *prg) +{ + fprintf(f, "%s - Control SE05x Secure Element\n", prg); + fprintf(f, "\nUsage: %s [options] \n", prg); + fprintf(f, "Options:\n"); + fprintf(f, " -r (read item from keystore at )\n"); + fprintf(f, " -w (set item in keystore at )\n"); + fprintf(f, " -g (generate keypair at )\n"); + fprintf(f, " -d (delete key at )\n"); + fprintf(f, " -s (create signature for data\n"); + fprintf(f, " with key at )\n"); + fprintf(f, " -S (Sign CSR with key at )\n"); + fprintf(f, " -v (verify signature for data\n"); + fprintf(f, " with key at )\n"); + fprintf(f, " -V (verify CRT with key at \n"); + fprintf(f, " -a (derive symm key\n"); + fprintf(f, " from public key \n"); + fprintf(f, " and private key)\n"); + fprintf(f, " -t (interface using raw data\n"); + fprintf(f, " use with -r, -w)\n"); + fprintf(f, " -c (interface with PEM format\n"); + fprintf(f, " internally using DER\n"); + fprintf(f, " use with -r, -w)\n"); + fprintf(f, " -p (select private key\n"); + fprintf(f, " use with -a)\n"); + fprintf(f, " -n (Read input from file)\n"); + fprintf(f, " -N (Read signature from file)\n"); + fprintf(f, " -i (show generic information)\n"); + fprintf(f, " -u (show UID)\n"); + fprintf(f, " -m (show used stack memory space)\n"); + fprintf(f, " -h (show this help)\n"); + fprintf(f, "\n"); +} + +static int set_operation(FAR struct settings_t *settings, + keystore_operation operation, FAR char *key_id_text) +{ + int result = -EPERM; + if (settings->operation == KEYSTORE_NO_ACTION) + { + settings->operation = operation; + settings->key_id = 0; + if (key_id_text != NULL) + { + settings->key_id = (uint32_t)strtoul(key_id_text, NULL, 0); + } + + result = 0; + } + + return result; +} + +static int parse_arguments(int argc, FAR char *argv[], + FAR struct settings_t *settings) +{ + int result = 0; + int opt; + FAR char *prg = basename(argv[0]); + while ( + ((opt = getopt(argc, argv, "iug:w:r:d:s:v:S:V:tca:p:n:N:mh")) != -1) && + (result == 0)) + { + switch (opt) + { + case 'i': + result = set_operation(settings, KEYSTORE_GET_INFO, optarg); + break; + case 'u': + result = set_operation(settings, KEYSTORE_GET_UID, optarg); + break; + case 'g': + result = set_operation(settings, KEYSTORE_GENERATE, optarg); + break; + case 'r': + result = set_operation(settings, KEYSTORE_READ, optarg); + break; + case 'w': + result = set_operation(settings, KEYSTORE_WRITE, optarg); + break; + case 't': + settings->raw_data_in_device = TRUE; + break; + case 'c': + settings->interface_with_pem = TRUE; + settings->raw_data_in_device = TRUE; + break; + case 'd': + result = set_operation(settings, KEYSTORE_DELETE, optarg); + break; + case 's': + result = + set_operation(settings, KEYSTORE_CREATE_SIGNATURE, optarg); + break; + case 'v': + result = + set_operation(settings, KEYSTORE_VERIFY_SIGNATURE, optarg); + break; + case 'S': + result = set_operation(settings, KEYSTORE_SIGN_CSR, optarg); + break; + case 'V': + result = + set_operation(settings, KEYSTORE_VERIFY_CERTIFICATE, optarg); + break; + case 'a': + result = set_operation(settings, KEYSTORE_DERIVE_SYMM_KEY, optarg); + break; + case 'p': + settings->private_key_id = (uint32_t)strtoul(optarg, NULL, 0); + break; + case 'n': + settings->input_filename = optarg; + break; + case 'N': + settings->signature_filename = optarg; + break; + case 'm': + settings->show_stack_used = TRUE; + break; + case 'h': + print_usage(stdout, prg); + settings->skip_process = TRUE; + break; + default: + print_usage(stderr, prg); + result = -EINVAL; + break; + } + } + + if ((result == 0) && (!settings->skip_process)) + { + if (settings->operation == KEYSTORE_NO_ACTION) + { + print_usage(stderr, prg); + result = -EINVAL; + } + + /* if device is specified as positional argument */ + + if (optind != argc) + { + settings->se05x_dev_filename = argv[optind]; + } + } + + return result; +} + +static int convert_array_hex_to_bin(FAR char *hex_buffer, + size_t hex_buffer_size, + FAR uint8_t *bin_buffer, + size_t bin_buffer_size, + FAR size_t *bin_buffer_content_size) +{ + hex_buffer_size = strcspn(hex_buffer, " \r\n"); + if (hex_buffer_size & 1) + { + return -1; + } + + *bin_buffer_content_size = 0; + size_t hex_buffer_pos; + for (hex_buffer_pos = 0; (hex_buffer_pos < hex_buffer_size) && + (*bin_buffer_content_size < bin_buffer_size); + hex_buffer_pos += 2) + { + sscanf(&hex_buffer[hex_buffer_pos], "%2hhx", + &bin_buffer[*bin_buffer_content_size]); + (*bin_buffer_content_size)++; + } + + return hex_buffer_pos == hex_buffer_size ? 0 : -1; +} + +static int read_from_file(FAR const char *prompt, FAR char *filename, + FAR char *buffer, size_t buffer_size) +{ + FAR FILE *f = stdin; + if (filename != NULL) + { + f = fopen(filename, "r"); + } + else + { + puts(prompt); + } + + size_t buffer_content_size = 0; + if (f != NULL) + { + FAR char *c = buffer; + int result = fgetc(f); + while ((result != EOF) && (result != EOT) && + (buffer_content_size < buffer_size)) + { + *c = result & 0xff; + c++; + buffer_content_size++; + result = fgetc(f); + } + } + + if (filename != NULL) + { + fclose(f); + } + + return buffer_content_size; +} + +static int read_from_file_and_convert(FAR const char *prompt, + FAR char *filename, + FAR uint8_t *buffer, + size_t buffer_size, + FAR size_t *buffer_content_size) +{ + char file_buffer[DEFAULT_BUFFER_SIZE]; + size_t file_buffer_content_size; + int result; + + file_buffer_content_size = read_from_file( + prompt, filename, (FAR char *)file_buffer, sizeof(file_buffer)); + result = convert_array_hex_to_bin(file_buffer, file_buffer_content_size, + buffer, buffer_size, buffer_content_size + ); + + return result; +} + +static size_t add_zero_termination_character(char *data, size_t content_size, + size_t buf_size) +{ + size_t zero_termination_char_position = content_size - 1; + if ((content_size + 1) <= buf_size) + { + zero_termination_char_position = content_size; + content_size++; + } + + data[zero_termination_char_position] = 0; + return content_size; +} + +static int process(int se05x_fd, FAR struct settings_t *settings) +{ + int result = 0; + if (settings->operation == KEYSTORE_GET_INFO) + { + struct se05x_info_s info; + result = ioctl(se05x_fd, SEIOC_GET_INFO, &info); + + if (result == 0) + { + printf("OEF ID: %04x\n", info.oef_id); + } + } + + else if (settings->operation == KEYSTORE_GET_UID) + { + struct se05x_uid_s uid; + result = ioctl(se05x_fd, SEIOC_GET_UID, &uid); + + if (result == 0) + { + printf("UID: "); + for (size_t i = 0; i < SE05X_MODULE_UNIQUE_ID_LEN; i++) + { + printf("%02x", uid.uid[i]); + } + + printf("\n"); + } + } + else if (settings->operation == KEYSTORE_GENERATE) + { + struct se05x_generate_keypair_s args = { + .id = settings->key_id, .cipher = SE05X_ASYM_CIPHER_EC_NIST_P_256 + }; + + result = ioctl(se05x_fd, SEIOC_GENERATE_KEYPAIR, &args); + + if (result == 0) + { + printf("Keypair generated successfully\n"); + } + } + else if (settings->operation == KEYSTORE_WRITE) + { + char pem_buf[DEFAULT_BUFFER_SIZE]; + FAR const char *prompt = enter_key_hex; + if (settings->raw_data_in_device) + { + prompt = + settings->interface_with_pem ? enter_data_pem : enter_data_raw; + } + + size_t pem_content_size = read_from_file( + prompt, settings->input_filename, pem_buf, sizeof(pem_buf)); + + uint8_t rawkey[RAW_KEY_BUFFER_SIZE]; + size_t rawkey_size = sizeof(rawkey); + + FAR uint8_t *data = (FAR uint8_t *)pem_buf; + size_t data_size = pem_content_size; + if (!settings->raw_data_in_device) + { + result = convert_public_key_pem_to_raw(rawkey, rawkey_size, + &rawkey_size, pem_buf); + if (result == 0) + { + data = rawkey; + data_size = rawkey_size; + } + } + + if (settings->interface_with_pem) + { + pem_content_size = add_zero_termination_character( + pem_buf, pem_content_size, sizeof(pem_buf)); + result = convert_pem_certificate_or_csr_to_der( + rawkey, rawkey_size, &rawkey_size, pem_buf, pem_content_size); + if (result == 0) + { + data = rawkey; + data_size = rawkey_size; + } + } + + if (result == 0) + { + struct se05x_key_transmission_s args = { + .entry = {.id = settings->key_id, + .cipher = SE05X_ASYM_CIPHER_EC_NIST_P_256}, + .content = {.buffer = data, + .buffer_size = data_size, + .buffer_content_size = data_size} + }; + + result = ioctl(se05x_fd, + settings->raw_data_in_device ? SEIOC_SET_DATA + : SEIOC_SET_KEY, + &args); + } + + if (result == 0) + { + printf("Data stored successfully\n"); + } + } + else if (settings->operation == KEYSTORE_READ) + { + uint8_t buffer[DEFAULT_BUFFER_SIZE]; + struct se05x_key_transmission_s args = { + .entry = {.id = settings->key_id}, + .content = {.buffer = buffer, .buffer_size = sizeof(buffer)} + }; + + result = + ioctl(se05x_fd, + settings->raw_data_in_device ? SEIOC_GET_DATA : SEIOC_GET_KEY, + &args); + + FAR char *data = (FAR char *)args.content.buffer; + if ((result == 0) + && settings->raw_data_in_device + && !settings->interface_with_pem) + { + args.content.buffer_content_size = add_zero_termination_character( + data, args.content.buffer_content_size, + args.content.buffer_size); + } + + char pem_buf[DEFAULT_BUFFER_SIZE]; + if ((result == 0) && !settings->raw_data_in_device) + { + result = convert_public_key_raw_to_pem( + pem_buf, sizeof(pem_buf), args.content.buffer, + args.content.buffer_content_size); + + data = pem_buf; + } + + if ((result == 0) && settings->interface_with_pem) + { + size_t pem_content_size; + result = convert_der_certificate_or_csr_to_pem( + pem_buf, sizeof(pem_buf), &pem_content_size, + args.content.buffer, args.content.buffer_content_size); + + data = pem_buf; + } + + if (result == 0) + { + puts(data); + } + } + else if (settings->operation == KEYSTORE_DELETE) + { + result = ioctl(se05x_fd, SEIOC_DELETE_KEY, settings->key_id); + + if (result == 0) + { + printf("Deleted key successfully\n"); + } + } + else if (settings->operation == KEYSTORE_DERIVE_SYMM_KEY) + { + uint8_t buffer[SYMM_KEY_BUFFER_SIZE]; + struct se05x_derive_key_s args = { + .private_key_id = settings->private_key_id, + .public_key_id = settings->key_id, + .content = {.buffer = buffer, .buffer_size = sizeof(buffer)}, + }; + + result = ioctl(se05x_fd, SEIOC_DERIVE_SYMM_KEY, &args); + + if (result == 0) + { + for (size_t i = 0; i < args.content.buffer_content_size; i++) + { + printf("%02x", args.content.buffer[i]); + } + + printf("\n"); + } + } + else if (settings->operation == KEYSTORE_CREATE_SIGNATURE) + { + uint8_t tbs_buffer[TBS_HASH_BUFFER_SIZE]; + size_t tbs_content_size; + read_from_file_and_convert("Enter tbs(hex):", settings->input_filename, + tbs_buffer, sizeof(tbs_buffer), + &tbs_content_size); + uint8_t signature_buffer[SIGNATURE_BUFFER_SIZE]; + size_t signature_content_len = 0; + if (result == 0) + { + struct se05x_signature_s args = { + .key_id = settings->key_id, + .algorithm = SE05X_ALGORITHM_SHA256, + .tbs = {.buffer = tbs_buffer, + .buffer_size = tbs_content_size, + .buffer_content_size = tbs_content_size}, + .signature = {.buffer = signature_buffer, + .buffer_size = sizeof(signature_buffer)}, + }; + + result = ioctl(se05x_fd, SEIOC_CREATE_SIGNATURE, &args); + signature_content_len = args.signature.buffer_content_size; + } + + if (result == 0) + { + for (size_t i = 0; i < signature_content_len; i++) + { + printf("%02x", signature_buffer[i]); + } + + printf("\n"); + } + } + else if (settings->operation == KEYSTORE_VERIFY_SIGNATURE) + { + uint8_t tbs_buffer[TBS_HASH_BUFFER_SIZE]; + size_t tbs_content_size; + result = read_from_file_and_convert( + "Enter tbs(hex):", settings->input_filename, tbs_buffer, + sizeof(tbs_buffer), &tbs_content_size); + + uint8_t signature_buffer[SIGNATURE_BUFFER_SIZE]; + size_t signature_content_size; + if (result == 0) + { + result = read_from_file_and_convert( + "Enter signature(hex):", settings->signature_filename, + signature_buffer, sizeof(signature_buffer), + &signature_content_size); + } + + if (result == 0) + { + struct se05x_signature_s args = { + .key_id = settings->key_id, + .algorithm = SE05X_ALGORITHM_SHA256, + .tbs = {.buffer = tbs_buffer, + .buffer_size = tbs_content_size, + .buffer_content_size = tbs_content_size}, + .signature = {.buffer = signature_buffer, + .buffer_size = signature_content_size, + .buffer_content_size = signature_content_size}, + }; + + result = ioctl(se05x_fd, SEIOC_VERIFY_SIGNATURE, &args); + } + + if (result == 0) + { + printf("Signature verified successfully\n"); + } + } + else if (settings->operation == KEYSTORE_SIGN_CSR) + { + char csr_pem_buf[DEFAULT_BUFFER_SIZE]; + size_t csr_pem_buf_content_size = + read_from_file("enter csr(pem)", settings->input_filename, + csr_pem_buf, sizeof(csr_pem_buf)); + + csr_pem_buf_content_size = add_zero_termination_character(csr_pem_buf, + csr_pem_buf_content_size, sizeof(csr_pem_buf)); + + char crt_pem_buf[DEFAULT_BUFFER_SIZE]; + result = sign_csr(se05x_fd, settings->key_id, crt_pem_buf, + sizeof(crt_pem_buf), csr_pem_buf, + csr_pem_buf_content_size); + if (result == 0) + { + puts(crt_pem_buf); + } + } + else if (settings->operation == KEYSTORE_VERIFY_CERTIFICATE) + { + char pem_buf[DEFAULT_BUFFER_SIZE]; + size_t pem_content_size = + read_from_file("enter crt(pem)", settings->input_filename, pem_buf, + sizeof(pem_buf)); + + pem_content_size = add_zero_termination_character(pem_buf, + pem_content_size, sizeof(pem_buf)); + + mbedtls_x509_crt crt; + mbedtls_x509_crt_init(&crt); + result = mbedtls_x509_crt_parse(&crt, (FAR uint8_t *)pem_buf, + pem_content_size); + + uint8_t tbs_buffer[TBS_HASH_BUFFER_SIZE]; + + if (result == 0) + { + result = mbedtls_sha256(crt.tbs.p, + crt.tbs.len, tbs_buffer, 0 + ); + } + + if (result == 0) + { + struct se05x_signature_s args = { + .key_id = settings->key_id, + .algorithm = SE05X_ALGORITHM_SHA256, + .tbs = {.buffer = tbs_buffer, + .buffer_size = sizeof(tbs_buffer), + .buffer_content_size = sizeof(tbs_buffer)}, + .signature = {.buffer = crt.sig.p, + .buffer_size = crt.sig.len, + .buffer_content_size = + crt.sig.len}, + }; + + result = ioctl(se05x_fd, SEIOC_VERIFY_SIGNATURE, &args); + } + + if (result == 0) + { + printf("Signature verified successfully\n"); + } + + mbedtls_x509_crt_free(&crt); + } + + return result; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(int argc, FAR char *argv[]) +{ + struct settings_t settings = DEFAULT_SETTINGS; + int result = parse_arguments(argc, argv, &settings); + + if ((result == 0) && (!settings.skip_process)) + { + int fd = open(settings.se05x_dev_filename, O_RDONLY); + if (fd == -1) + { + result = -ENODEV; + } + else + { + result = process(fd, &settings); + close(fd); + } + } + + if (result != 0) + { + fprintf(stderr, "err %i: %s\n", -result, strerror(-result)); + } + + if (settings.show_stack_used) + { +#ifdef CONFIG_STACK_COLORATION + FAR struct tcb_s *tcb; + tcb = nxsched_get_tcb(getpid()); + fprintf(stderr, "\nStack used: %zu / %zu\n", + up_check_tcbstack(tcb), tcb->adj_stack_size); +#else + fprintf(stderr, "\nStack used: unknown" + " (STACK_COLORATION must be enabled)\n"); +#endif + } + + return result == 0 ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/crypto/controlse/mbedtls_extension.c b/crypto/controlse/mbedtls_extension.c new file mode 100644 index 000000000..3ec58ae74 --- /dev/null +++ b/crypto/controlse/mbedtls_extension.c @@ -0,0 +1,310 @@ +/**************************************************************************** + * apps/crypto/controlse/mbedtls_extension.c + * + * 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. + * + ****************************************************************************/ + +/* Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 + * + * The source code in this file is based on + * mbedtls_x509write_crt_der() method from x509write_crt.c in Mbed TLS + */ + +/* Copyright 2023 NXP */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#define MBEDTLS_ALLOW_PRIVATE_ACCESS +#include +#include +#include +#include +#include +#include +#include + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int x509_write_time(FAR unsigned char **p, FAR unsigned char *start, + FAR const char *t, size_t size) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t len = 0; + + /* write MBEDTLS_ASN1_UTC_TIME if year < 2050 (2 bytes shorter) */ + + if (t[0] == '2' && t[1] == '0' && t[2] < '5') + { + MBEDTLS_ASN1_CHK_ADD( + len, mbedtls_asn1_write_raw_buffer( + p, start, (FAR const unsigned char *)t + 2, size - 2)); + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len)); + MBEDTLS_ASN1_CHK_ADD( + len, mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_UTC_TIME)); + } + else + { + MBEDTLS_ASN1_CHK_ADD(len, + mbedtls_asn1_write_raw_buffer( + p, start, (FAR const unsigned char *)t, size)); + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len)); + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag( + p, start, MBEDTLS_ASN1_GENERALIZED_TIME)); + } + + return ((int)len); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int mbedtls_x509write_crt_der_se05x(FAR mbedtls_x509write_cert *ctx, + FAR unsigned char *buf, size_t size, + int se05x_fd, uint32_t private_key_id) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + FAR const char *sig_oid; + size_t sig_oid_len = 0; + FAR unsigned char *c; + FAR unsigned char *c2; + unsigned char hash[64]; + unsigned char sig[MBEDTLS_PK_SIGNATURE_MAX_SIZE]; + size_t sub_len = 0; + size_t pub_len = 0; + size_t sig_and_oid_len = 0; + size_t sig_len; + size_t len = 0; + mbedtls_pk_type_t pk_alg; + + /* Prepare data to be signed at the end of the target buffer */ + + c = buf + size; + + /* Signature algorithm needed in TBS, and later for actual signature */ + + /* There's no direct way of extracting a signature algorithm + * (represented as an element of mbedtls_pk_type_t) from a PK instance. + */ + + if (mbedtls_pk_can_do(ctx->issuer_key, MBEDTLS_PK_RSA)) + { + pk_alg = MBEDTLS_PK_RSA; + } + else if (mbedtls_pk_can_do(ctx->issuer_key, MBEDTLS_PK_ECDSA)) + { + pk_alg = MBEDTLS_PK_ECDSA; + } + else + { + return (MBEDTLS_ERR_X509_INVALID_ALG); + } + + if ((ret = mbedtls_oid_get_oid_by_sig_alg(pk_alg, ctx->md_alg, &sig_oid, + &sig_oid_len)) != 0) + { + return (ret); + } + + /* Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension */ + + /* Only for v3 */ + + if (ctx->version == MBEDTLS_X509_CRT_VERSION_3) + { + MBEDTLS_ASN1_CHK_ADD( + len, mbedtls_x509_write_extensions(&c, buf, ctx->extensions)); + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len)); + MBEDTLS_ASN1_CHK_ADD(len, + mbedtls_asn1_write_tag(&c, buf, + MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE)); + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len)); + MBEDTLS_ASN1_CHK_ADD( + len, mbedtls_asn1_write_tag(&c, buf, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | + MBEDTLS_ASN1_CONSTRUCTED | 3)); + } + + /* SubjectPublicKeyInfo */ + + MBEDTLS_ASN1_CHK_ADD( + pub_len, mbedtls_pk_write_pubkey_der(ctx->subject_key, buf, c - buf)); + c -= pub_len; + len += pub_len; + + /* Subject ::= Name */ + + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_x509_write_names(&c, buf, ctx->subject)); + + /* Validity ::= SEQUENCE { + * notBefore Time, + * notAfter Time } + */ + + sub_len = 0; + + MBEDTLS_ASN1_CHK_ADD(sub_len, + x509_write_time(&c, buf, ctx->not_after, + MBEDTLS_X509_RFC5280_UTC_TIME_LEN)); + + MBEDTLS_ASN1_CHK_ADD(sub_len, + x509_write_time(&c, buf, ctx->not_before, + MBEDTLS_X509_RFC5280_UTC_TIME_LEN)); + + len += sub_len; + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, sub_len)); + MBEDTLS_ASN1_CHK_ADD( + len, mbedtls_asn1_write_tag( + &c, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)); + + /* Issuer ::= Name */ + + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_x509_write_names(&c, buf, ctx->issuer)); + + /* Signature ::= AlgorithmIdentifier */ + + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_algorithm_identifier( + &c, buf, sig_oid, strlen(sig_oid), 0)); + + /* Serial ::= INTEGER + * + * Written data is: + * - "ctx->serial_len" bytes for the raw serial buffer + * - if MSb of "serial" is 1, then prepend an extra 0x00 byte + * - 1 byte for the length + * - 1 byte for the TAG + */ + + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_raw_buffer(&c, buf, + ctx->serial, ctx->serial_len)); + if (*c & 0x80) + { + if (c - buf < 1) + { + return MBEDTLS_ERR_X509_BUFFER_TOO_SMALL; + } + + *(--c) = 0x0; + len++; + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, + ctx->serial_len + 1)); + } + else + { + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, + ctx->serial_len)); + } + + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&c, buf, + MBEDTLS_ASN1_INTEGER)); + + /* Version ::= INTEGER { v1(0), v2(1), v3(2) } */ + + /* Can be omitted for v1 */ + + if (ctx->version != MBEDTLS_X509_CRT_VERSION_1) + { + sub_len = 0; + MBEDTLS_ASN1_CHK_ADD(sub_len, + mbedtls_asn1_write_int(&c, buf, ctx->version)); + len += sub_len; + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, sub_len)); + MBEDTLS_ASN1_CHK_ADD( + len, mbedtls_asn1_write_tag(&c, buf, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | + MBEDTLS_ASN1_CONSTRUCTED | 0)); + } + + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len)); + MBEDTLS_ASN1_CHK_ADD( + len, mbedtls_asn1_write_tag( + &c, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)); + + /* Make signature + */ + + /* Compute hash of CRT. */ + + if ((ret = mbedtls_md(mbedtls_md_info_from_type(ctx->md_alg), c, len, + hash)) != 0) + { + return (ret); + } + + { + struct se05x_signature_s args = { + .key_id = private_key_id, + .algorithm = SE05X_ALGORITHM_SHA256, + .tbs = { + .buffer = hash, + .buffer_size = 32, + .buffer_content_size = 32 + }, + .signature = {.buffer = sig, .buffer_size = sizeof(sig)}, + }; + + ret = ioctl(se05x_fd, SEIOC_CREATE_SIGNATURE, &args); + if (ret != 0) + { + return ret; + } + + sig_len = args.signature.buffer_content_size; + } + + /* Move CRT to the front of the buffer to have space + * for the signature. + */ + + memmove(buf, c, len); + c = buf + len; + + /* Add signature at the end of the buffer, + * making sure that it doesn't underflow + * into the CRT buffer. + */ + + c2 = buf + size; + MBEDTLS_ASN1_CHK_ADD( + sig_and_oid_len, + mbedtls_x509_write_sig(&c2, c, sig_oid, sig_oid_len, sig, sig_len)); + + /* Memory layout after this step: + * + * buf c=buf+len c2 buf+size + * [CRT0,...,CRTn, UNUSED, ..., UNUSED, SIG0, ..., SIGm] + */ + + /* Move raw CRT to just before the signature. */ + + c = c2 - len; + memmove(c, buf, len); + + len += sig_and_oid_len; + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len)); + MBEDTLS_ASN1_CHK_ADD( + len, mbedtls_asn1_write_tag( + &c, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)); + + return ((int)len); +} diff --git a/crypto/controlse/mbedtls_extension.h b/crypto/controlse/mbedtls_extension.h new file mode 100644 index 000000000..74a1c0349 --- /dev/null +++ b/crypto/controlse/mbedtls_extension.h @@ -0,0 +1,40 @@ +/**************************************************************************** + * apps/crypto/controlse/mbedtls_extension.h + * + * 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. + * + ****************************************************************************/ + +/* Copyright 2023 NXP */ + +#ifndef __INCLUDE_APPS_CRYPTO_CONTROLSE_MBEDTLS_EXTENSION_H_ +#define __INCLUDE_APPS_CRYPTO_CONTROLSE_MBEDTLS_EXTENSION_H_ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +int mbedtls_x509write_crt_der_se05x(mbedtls_x509write_cert *ctx, + unsigned char *buf, size_t size, + int se05x_fd, uint32_t private_key_id); + +#endif /* __INCLUDE_APPS_CRYPTO_CONTROLSE_MBEDTLS_EXTENSION_H_ */ diff --git a/crypto/controlse/x509_utils.c b/crypto/controlse/x509_utils.c new file mode 100644 index 000000000..873b54ec6 --- /dev/null +++ b/crypto/controlse/x509_utils.c @@ -0,0 +1,350 @@ +/**************************************************************************** + * apps/crypto/controlse/x509_utils.c + * + * 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. + * + ****************************************************************************/ + +/* Copyright 2023 NXP */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#define MBEDTLS_ALLOW_PRIVATE_ACCESS +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/ecp.h" +#include "mbedtls/entropy.h" +#include "mbedtls/pem.h" +#include "mbedtls/pk.h" +#include "mbedtls/x509_crt.h" +#include "mbedtls/x509_csr.h" +#include "mbedtls_extension.h" +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define SECONDS_IN_DAY (60 * 60 * 24) + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const char certificate_header[] = "-----BEGIN CERTIFICATE-----\n"; +static const char certificate_footer[] = "-----END CERTIFICATE-----\n"; + +static const char certificate_request_header[] = + "-----BEGIN CERTIFICATE REQUEST-----\n"; +static const char certificate_request_footer[] = + "-----END CERTIFICATE REQUEST-----\n"; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int convert_der_certificate_to_pem(FAR char *pem_buf, + size_t pem_buf_size, + FAR size_t *pem_content_size, + FAR uint8_t *der_buf, + size_t der_buf_size) +{ + int result; + + { + mbedtls_x509_crt crt; + mbedtls_x509_crt_init(&crt); + result = mbedtls_x509_crt_parse(&crt, der_buf, der_buf_size); + mbedtls_x509_crt_free(&crt); + } + + if (result == 0) + { + result = mbedtls_pem_write_buffer( + certificate_header, certificate_footer, der_buf, der_buf_size, + (FAR uint8_t *)pem_buf, pem_buf_size, pem_content_size); + } + + return result; +} + +static int convert_der_csr_to_pem(FAR char *pem_buf, size_t pem_buf_size, + FAR size_t *pem_content_size, + FAR uint8_t *der_buf, size_t der_buf_size) +{ + int result; + + { + mbedtls_x509_csr csr; + mbedtls_x509_csr_init(&csr); + result = + mbedtls_x509_csr_parse(&csr, (FAR uint8_t *)der_buf, der_buf_size); + mbedtls_x509_csr_free(&csr); + } + + if (result == 0) + { + result = mbedtls_pem_write_buffer(certificate_request_header, + certificate_request_footer, der_buf, + der_buf_size, (FAR uint8_t *)pem_buf, + pem_buf_size, pem_content_size); + } + + return result; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int convert_public_key_raw_to_pem(FAR char *pem_buf, size_t pem_buf_size, + FAR uint8_t *key_buf, size_t key_buf_size) +{ + mbedtls_pk_context key = + { + 0 + }; + + mbedtls_pk_init(&key); + FAR const mbedtls_pk_info_t *info = + mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY); + + int result = -1; + if (info != NULL) + { + result = mbedtls_pk_setup(&key, info); + } + + FAR mbedtls_ecp_keypair *keypair = (mbedtls_ecp_keypair *)key.pk_ctx; + if (result == 0) + { + result = + mbedtls_ecp_group_load(&keypair->grp, MBEDTLS_ECP_DP_SECP256R1); + } + + if (result == 0) + { + result = mbedtls_ecp_point_read_binary(&keypair->grp, &keypair->Q, + key_buf, key_buf_size); + } + + if (result == 0) + { + result = mbedtls_pk_write_pubkey_pem(&key, (FAR uint8_t *)pem_buf, + pem_buf_size); + } + + mbedtls_pk_free(&key); + return result < 0 ? -EINVAL : 0; +} + +int convert_public_key_pem_to_raw(FAR uint8_t *key_buf, size_t key_buf_size, + FAR size_t *key_size, FAR char *pem_buf) +{ + int result = -1; + mbedtls_pk_context key = + { + 0 + }; + + mbedtls_pk_init(&key); + + result = mbedtls_pk_parse_public_key(&key, (FAR uint8_t *)pem_buf, + strlen(pem_buf) + 1); + + if (result == 0) + { + result = mbedtls_pk_can_do(&key, MBEDTLS_PK_ECKEY) == 1 ? 0 : -1; + } + + if (result == 0) + { + FAR mbedtls_ecp_keypair *keypair = (mbedtls_ecp_keypair *)key.pk_ctx; + result = mbedtls_ecp_point_write_binary( + &keypair->grp, &keypair->Q, MBEDTLS_ECP_PF_UNCOMPRESSED, key_size, + key_buf, key_buf_size); + } + + mbedtls_pk_free(&key); + return result < 0 ? -EINVAL : 0; +} + +int convert_pem_certificate_or_csr_to_der(FAR uint8_t *der_buf, + size_t der_buf_size, + FAR size_t *der_content_size, + FAR char *pem_buf, + size_t pem_buf_size) +{ + int result; + + { + mbedtls_x509_crt crt; + mbedtls_x509_crt_init(&crt); + result = + mbedtls_x509_crt_parse(&crt, (FAR uint8_t *)pem_buf, pem_buf_size); + if ((result == 0) && (der_buf_size < crt.raw.len)) + { + result = -EINVAL; + } + + if (result == 0) + { + memcpy(der_buf, crt.raw.p, crt.raw.len); + *der_content_size = crt.raw.len; + } + + mbedtls_x509_crt_free(&crt); + } + + /* if bad input data then try parsing CSR */ + + if (result != 0) + { + mbedtls_x509_csr csr; + mbedtls_x509_csr_init(&csr); + result = + mbedtls_x509_csr_parse(&csr, (FAR uint8_t *)pem_buf, pem_buf_size); + if ((result == 0) && (der_buf_size < csr.raw.len)) + { + result = -EINVAL; + } + + if (result == 0) + { + memcpy(der_buf, csr.raw.p, csr.raw.len); + *der_content_size = csr.raw.len; + } + + mbedtls_x509_csr_free(&csr); + } + + return result; +} + +int convert_der_certificate_or_csr_to_pem(FAR char *pem_buf, + size_t pem_buf_size, + FAR size_t *pem_content_size, + FAR uint8_t *der_buf, + size_t der_buf_size) +{ + int result = convert_der_certificate_to_pem( + pem_buf, pem_buf_size, pem_content_size, der_buf, der_buf_size); + + if (result != 0) + { + result = convert_der_csr_to_pem(pem_buf, pem_buf_size, + pem_content_size, + der_buf, der_buf_size); + } + + return result; +} + +int sign_csr(int se05x_fd, uint32_t private_key_id, FAR char *crt_pem_buf, + size_t crt_pem_buf_size, FAR char *csr_pem_buf, + size_t csr_pem_buf_content_size) +{ + mbedtls_x509_csr csr; + mbedtls_x509_csr_init(&csr); + int result = mbedtls_x509_csr_parse(&csr, (FAR uint8_t *)csr_pem_buf, + csr_pem_buf_content_size); + + mbedtls_x509write_cert crt; + mbedtls_x509write_crt_init(&crt); + char subject_name[200]; + if (result == 0) + { + mbedtls_x509write_crt_set_version(&crt, MBEDTLS_X509_CRT_VERSION_3); + result = mbedtls_x509_dn_gets(subject_name, sizeof(subject_name), + &csr.subject); + } + + mbedtls_pk_context private_key; + mbedtls_pk_init(&private_key); + if (result >= 0) + { + mbedtls_x509write_crt_set_subject_key(&crt, &csr.pk); + result = mbedtls_pk_setup( + &private_key, + mbedtls_pk_info_from_type((mbedtls_pk_type_t)MBEDTLS_PK_ECDSA)); + } + + if (result == 0) + { + mbedtls_x509write_crt_set_issuer_key(&crt, &private_key); + result = mbedtls_x509write_crt_set_subject_name(&crt, subject_name); + } + + if (result == 0) + { + result = + mbedtls_x509write_crt_set_issuer_name(&crt, "CN=CA,O=NXP,C=NL"); + } + + mbedtls_mpi serial; + mbedtls_mpi_init(&serial); + if (result == 0) + { + mbedtls_x509write_crt_set_md_alg(&crt, MBEDTLS_MD_SHA256); + result = mbedtls_mpi_read_string(&serial, 10, "1"); + } + + if (result == 0) + { + result = mbedtls_x509write_crt_set_serial(&crt, &serial); + } + + if (result == 0) + { + time_t rawtime; + struct tm tm_info; + char from_datetime[20]; + char to_datetime[20]; + time(&rawtime); + strftime(from_datetime, sizeof(from_datetime), "%Y%m%d%H%M%S", + gmtime_r(&rawtime, &tm_info)); + rawtime += SECONDS_IN_DAY; + strftime(to_datetime, sizeof(to_datetime), "%Y%m%d%H%M%S", + gmtime_r(&rawtime, &tm_info)); + result = mbedtls_x509write_crt_set_validity(&crt, from_datetime, + to_datetime); + } + + if (result == 0) + { + result = mbedtls_x509write_crt_der_se05x( + &crt, (FAR uint8_t *)crt_pem_buf, crt_pem_buf_size, se05x_fd, + private_key_id); + } + + if (result >= 0) + { + size_t olen; + result = mbedtls_pem_write_buffer( + certificate_header, certificate_footer, + (FAR uint8_t *)(crt_pem_buf + crt_pem_buf_size - result), result, + (FAR uint8_t *)crt_pem_buf, crt_pem_buf_size, &olen); + } + + mbedtls_mpi_free(&serial); + mbedtls_pk_free(&private_key); + mbedtls_x509write_crt_free(&crt); + mbedtls_x509_csr_free(&csr); + return result; +} diff --git a/crypto/controlse/x509_utils.h b/crypto/controlse/x509_utils.h new file mode 100644 index 000000000..872136271 --- /dev/null +++ b/crypto/controlse/x509_utils.h @@ -0,0 +1,54 @@ +/**************************************************************************** + * apps/crypto/controlse/x509_utils.h + * + * 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. + * + ****************************************************************************/ + +/* Copyright 2023 NXP */ + +#ifndef __INCLUDE_APPS_CRYPTO_CONTROLSE_X509_UTILS_H_ +#define __INCLUDE_APPS_CRYPTO_CONTROLSE_X509_UTILS_H_ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +int convert_public_key_raw_to_pem(FAR char *pem_buf, size_t pem_buf_size, + FAR uint8_t *key_buf, size_t key_buf_size); +int convert_public_key_pem_to_raw(FAR uint8_t *key_buf, size_t key_buf_size, + FAR size_t *key_size, char *pem_buf); +int convert_pem_certificate_or_csr_to_der(FAR uint8_t *der_buf, + size_t der_buf_size, + FAR size_t *der_content_size, + FAR char *pem_buf, + size_t pem_buf_size); +int convert_der_certificate_or_csr_to_pem(FAR char *pem_buf, + size_t pem_buf_size, + FAR size_t *pem_content_size, + FAR uint8_t *der_buf, + size_t der_buf_size); +int sign_csr(int se05x_fd, uint32_t private_key_id, FAR char *crt_pem_buf, + size_t crt_pem_buf_size, FAR char *csr_pem_buf, + size_t csr_pem_buf_content_size); + +#endif /* __INCLUDE_APPS_CRYPTO_CONTROLSE_X509_UTILS_H_ */ diff --git a/crypto/mbedtls/Kconfig b/crypto/mbedtls/Kconfig index 8c47420ae..206ce3e9e 100644 --- a/crypto/mbedtls/Kconfig +++ b/crypto/mbedtls/Kconfig @@ -136,6 +136,44 @@ config MBEDTLS_NET_C default y if LIBC_NETDB default n if !LIBC_NETDB +config MBEDTLS_ECDSA_C + bool "Enable the elliptic curve DSA library." + default n + +config MBEDTLS_ECP_C + bool "Enable the elliptic curve over GF(p) library." + default n + +config MBEDTLS_ECP_DP_SECP256R1_ENABLED + bool "Enables specific curves within the Elliptic Curve module." + default n + +config MBEDTLS_PEM_WRITE_C + bool "Enable PEM encoding / writing." + default n + +config MBEDTLS_PK_WRITE_C + bool "Enable the generic public (asymmetric) key writer." + default n + +config MBEDTLS_X509_CREATE_C + bool "Enable X.509 core for creating certificates." + default n + +config MBEDTLS_X509_CRT_WRITE_C + bool "Enable creating X.509 certificates." + select MBEDTLS_X509_CREATE_C + default n + +config MBEDTLS_X509_CSR_WRITE_C + bool "Enable creating X.509 Certificate Signing Requests (CSR)." + select MBEDTLS_X509_CREATE_C + default n + +config MBEDTLS_X509_CSR_PARSE_C + bool "Enable X.509 Certificate Signing Request (CSR) parsing." + default n + if CRYPTO_CRYPTODEV config MBEDTLS_ALT diff --git a/testing/setest/Kconfig b/testing/setest/Kconfig new file mode 100644 index 000000000..c7f2fafa3 --- /dev/null +++ b/testing/setest/Kconfig @@ -0,0 +1,30 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config TESTING_SETEST + bool "Secure Element driver test" + default n + depends on DEV_SE05X + ---help--- + Enable the Secure Element driver test + +if TESTING_SETEST + +config TESTING_SETEST_PROGNAME + string "Program name" + default "setest" + ---help--- + This is the name of the program that will be used when the NSH ELF + program is installed. + +config TESTING_SETEST_PRIORITY + int "setest utility task priority" + default 100 + +config TESTING_SETEST_STACKSIZE + int "setest utility stack size" + default DEFAULT_TASK_STACKSIZE + +endif diff --git a/testing/setest/Make.defs b/testing/setest/Make.defs new file mode 100644 index 000000000..68eebe636 --- /dev/null +++ b/testing/setest/Make.defs @@ -0,0 +1,23 @@ +############################################################################ +# apps/testing/setest/Make.defs +# +# 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. +# +############################################################################ + +ifneq ($(CONFIG_TESTING_SETEST),) +CONFIGURED_APPS += $(APPDIR)/testing/setest +endif diff --git a/testing/setest/Makefile b/testing/setest/Makefile new file mode 100644 index 000000000..1053f0065 --- /dev/null +++ b/testing/setest/Makefile @@ -0,0 +1,33 @@ +############################################################################ +# apps/testing/setest/Makefile +# +# 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 $(APPDIR)/Make.defs + +# setest built-in application info + +PROGNAME = $(CONFIG_TESTING_SETEST_PROGNAME) +PRIORITY = $(CONFIG_TESTING_SETEST_PRIORITY) +STACKSIZE = $(CONFIG_TESTING_SETEST_STACKSIZE) + +# setest main source + +MAINSRC = setest.c + +include $(APPDIR)/Application.mk diff --git a/testing/setest/setest.c b/testing/setest/setest.c new file mode 100644 index 000000000..0a773650e --- /dev/null +++ b/testing/setest/setest.c @@ -0,0 +1,371 @@ +/**************************************************************************** + * apps/testing/setest/setest.c + * + * 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. + * + ****************************************************************************/ + +/* Copyright 2023 NXP */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define DEFAULT_SETTINGS \ + { \ + .se05x_dev = default_se05x_device, .skip_process = FALSE, \ + .base_id = 0x230000 \ + } + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct settings_t +{ + FAR char *se05x_dev; + bool skip_process; + uint32_t base_id; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static char default_se05x_device[] = "/dev/se05x"; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void print_usage(FAR FILE *f, char *prg) +{ + fprintf(f, "%s - Secure Element Test\n", prg); + fprintf(f, "\nUsage: %s [options] \n", prg); + fprintf(f, "Options:\n"); + fprintf(f, " -b (use base address \n"); + fprintf(f, " default = 0x230000)\n"); +} + +static int parse_arguments(int argc, FAR char *argv[], + FAR struct settings_t *settings) +{ + int result = 0; + int opt; + FAR char *prg = basename(argv[0]); + while (((opt = getopt(argc, argv, "b:h")) != -1) && (result == 0)) + { + switch (opt) + { + case 'b': + settings->base_id = (uint32_t)strtoul(optarg, NULL, 0); + break; + case 'h': + print_usage(stdout, prg); + settings->skip_process = TRUE; + break; + default: + print_usage(stderr, prg); + result = -EINVAL; + break; + } + } + + if ((result == 0) && (!settings->skip_process)) + { + settings->se05x_dev = default_se05x_device; + + /* if device is specified as positional argument */ + + if (optind != argc) + { + settings->se05x_dev = argv[optind]; + } + } + + return result; +} + +static uint32_t get_se05x_id(FAR struct settings_t *settings, uint32_t id) +{ + return settings->base_id + id; +} + +static void print_result(bool success) +{ + if (success) + { + puts(" SUCCESS"); + } + else + { + puts(" FAIL"); + } +} + +static int invert_result(int result) +{ + return result != 0 ? 0 : -1; +} + +static int run_tests(int fd, FAR struct settings_t *settings) +{ + int result = 0; + puts("Setup"); + for (uint32_t id = get_se05x_id(settings, 1); + id < get_se05x_id(settings, 5); id++) + { + /* result is neglected because already empty entries result with + * errors + */ + + (void)ioctl(fd, SEIOC_DELETE_KEY, id); + } + + puts("Generate 3 keypairs"); + for (uint32_t id = get_se05x_id(settings, 1); + (id < get_se05x_id(settings, 4)) && (result == 0); id++) + { + struct se05x_generate_keypair_s args = { + .id = id, .cipher = SE05X_ASYM_CIPHER_EC_NIST_P_256 + }; + + result = ioctl(fd, SEIOC_GENERATE_KEYPAIR, &args); + } + + print_result(result == 0); + + uint8_t public_key[300]; + size_t public_key_size; + if (result == 0) + { + puts("Read from pub #1"); + + struct se05x_key_transmission_s args = { + .entry = {.id = get_se05x_id(settings, 1), + .cipher = SE05X_ASYM_CIPHER_EC_NIST_P_256}, + .content = {.buffer = public_key, + .buffer_size = sizeof(public_key)} + }; + + result = ioctl(fd, SEIOC_GET_KEY, &args); + + public_key_size = args.content.buffer_content_size; + + print_result(result == 0); + } + + if (result == 0) + { + puts("Write to pub #4"); + + struct se05x_key_transmission_s args = { + .entry = {.id = get_se05x_id(settings, 4), + .cipher = SE05X_ASYM_CIPHER_EC_NIST_P_256}, + .content = {.buffer = public_key, + .buffer_size = public_key_size, + .buffer_content_size = public_key_size} + }; + + result = ioctl(fd, SEIOC_SET_KEY, &args); + + print_result(result == 0); + } + + uint8_t hash[32] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 + }; + + uint8_t signature[300]; + size_t signature_content_size; + if (result == 0) + { + puts("Create signature with priv #1"); + + struct se05x_signature_s args = { + .key_id = get_se05x_id(settings, 1), + .algorithm = SE05X_ALGORITHM_SHA256, + .tbs = {.buffer = hash, + .buffer_size = sizeof(hash), + .buffer_content_size = sizeof(hash)}, + .signature = {.buffer = signature, + .buffer_size = sizeof(signature)}, + }; + + result = ioctl(fd, SEIOC_CREATE_SIGNATURE, &args); + signature_content_size = args.signature.buffer_content_size; + print_result(result == 0); + } + + if (result == 0) + { + puts("Verify signature with pub #4"); + + struct se05x_signature_s args = { + .key_id = get_se05x_id(settings, 4), + .algorithm = SE05X_ALGORITHM_SHA256, + .tbs = {.buffer = hash, + .buffer_size = sizeof(hash), + .buffer_content_size = sizeof(hash)}, + .signature = {.buffer = signature, + .buffer_content_size = signature_content_size}, + }; + + result = ioctl(fd, SEIOC_VERIFY_SIGNATURE, &args); + + print_result(result == 0); + } + + if (result == 0) + { + puts("Verification of signature with pub #2 should be dissapproved"); + + struct se05x_signature_s args = { + .key_id = get_se05x_id(settings, 2), + .algorithm = SE05X_ALGORITHM_SHA256, + .tbs = {.buffer = hash, .buffer_size = sizeof(hash)}, + .signature = {.buffer = signature, + .buffer_content_size = signature_content_size}, + }; + + result = invert_result(ioctl(fd, SEIOC_VERIFY_SIGNATURE, &args)); + + print_result(result == 0); + } + + uint8_t symm_key_a[32]; + if (result == 0) + { + puts("Derive symm key #a from priv #1 and pub #2"); + + struct se05x_derive_key_s args = { + .private_key_id = get_se05x_id(settings, 1), + .public_key_id = get_se05x_id(settings, 2), + .content = {.buffer = symm_key_a, + .buffer_size = sizeof(symm_key_a)}, + }; + + result = ioctl(fd, SEIOC_DERIVE_SYMM_KEY, &args); + + print_result(result == 0); + } + + uint8_t symm_key_b[32]; + if (result == 0) + { + puts("Derive symm key #b from priv #2 and pub #1"); + + struct se05x_derive_key_s args = { + .private_key_id = get_se05x_id(settings, 2), + .public_key_id = get_se05x_id(settings, 1), + .content = {.buffer = symm_key_b, + .buffer_size = sizeof(symm_key_b)}, + }; + + result = ioctl(fd, SEIOC_DERIVE_SYMM_KEY, &args); + + print_result(result == 0); + } + + uint8_t symm_key_c[32]; + if (result == 0) + { + puts("Derive symm key #c from priv #1 and pub #3"); + + struct se05x_derive_key_s args = { + .private_key_id = get_se05x_id(settings, 1), + .public_key_id = get_se05x_id(settings, 3), + .content = {.buffer = symm_key_c, + .buffer_size = sizeof(symm_key_c)}, + }; + + result = ioctl(fd, SEIOC_DERIVE_SYMM_KEY, &args); + + print_result(result == 0); + } + + if (result == 0) + { + puts("Symm key #a and #b should be equal"); + + result = memcmp(symm_key_a, symm_key_b, sizeof(symm_key_a)); + + print_result(result == 0); + } + + if (result == 0) + { + puts("Symm key #a and #c should be different"); + + result = + invert_result(memcmp(symm_key_a, symm_key_c, sizeof(symm_key_a))); + + print_result(result == 0); + } + + if (result == 0) + { + puts("All tests succeeded!\n"); + } + + return result; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(int argc, FAR char *argv[]) +{ + struct settings_t settings = DEFAULT_SETTINGS; + int result = parse_arguments(argc, argv, &settings); + + int fd; + if ((result == 0) && (!settings.skip_process)) + { + fd = open(settings.se05x_dev, O_RDONLY); + if (fd == -1) + { + result = -ENODEV; + } + else + { + run_tests(fd, &settings); + close(fd); + } + } + + if (result != 0) + { + fprintf(stderr, "err %i: %s\n", -result, strerror(-result)); + } + + return result == 0 ? EXIT_SUCCESS : EXIT_FAILURE; +}