/**************************************************************************** * 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; }