فهرست منبع

MbedTLS files added, CMake update: cip security files added

micsat 2 سال پیش
والد
کامیت
f2bd678163

+ 3 - 0
.gitignore

@@ -23,3 +23,6 @@ source/cip_objects/
 
 
 build/
+*.crt
+*.req
+*.key

+ 31 - 3
source/src/cip/cip_security/CMakeLists.txt

@@ -1,5 +1,5 @@
 #######################################
-# CIP Security library                         #
+# CIP Security library                #
 #######################################
 
 #######################################
@@ -12,7 +12,35 @@ opener_common_includes()
 #######################################
 opener_platform_support("INCLUDES")
 
-set( CIP_SECURITY_SRC cipsecurity.c certificatemanagement.c ethernetipsecurity.c)
+set( CIP_SECURITY_SRC cipsecurity.c certificatemanagement.c ethernetipsecurity.c gen_key.c cert_req.c cert_write.c)
 
 add_library( CIP_SECURITY ${CIP_SECURITY_SRC})
-target_link_libraries(CIP_SECURITY CIP_FILE_OBJECT)
+# target_link_libraries(CIP_SECURITY  CIP_FILE_OBJECT)
+target_link_libraries(CIP_SECURITY PUBLIC CIP_FILE_OBJECT 
+MbedTLS::mbedtls
+MbedTLS::mbedcrypto
+MbedTLS::mbedx509)
+
+###############################################################
+# RSA key file for generated private-public key pair          #
+###############################################################
+set(OPENER_DATA_FOLDER "${OpENer_SOURCE_DIR}/../data")
+if(EXISTS "${OPENER_DATA_FOLDER}/keyfile.key")
+    find_file( RSA_KEY_FILE_LOCATION NAMES keyfile.key PATHS ${OPENER_DATA_FOLDER} NO_DEFAULT_PATH  DOC "RSA key file" )
+else()
+    file(WRITE ${OPENER_DATA_FOLDER}/keyfile.key "") # create empty file if not exists
+    set( RSA_KEY_FILE_LOCATION ${OPENER_DATA_FOLDER}/keyfile.key)
+endif()
+add_compile_definitions(RSA_KEY_FILE_LOCATION=\"${RSA_KEY_FILE_LOCATION}\")
+
+###############################################################
+# Certificate file for default device certificate             #
+###############################################################
+find_file( FILE_OBJECT_CERTIFICATE_FILE_LOCATION NAMES cert.crt PATHS ${OPENER_DATA_FOLDER} NO_DEFAULT_PATH  DOC "Default Device Certificate File" )
+add_compile_definitions(FILE_OBJECT_CERTIFICATE_FILE_LOCATION=\"${FILE_OBJECT_CERTIFICATE_FILE_LOCATION}\")
+
+###############################################################
+# CSR file for static File Object Instance                    # 
+###############################################################
+find_file( FILE_OBJECT_CSR_FILE_LOCATION NAMES csr.req PATHS ${OPENER_DATA_FOLDER} NO_DEFAULT_PATH  DOC "CSR File" )
+add_compile_definitions(FILE_OBJECT_CSR_FILE_LOCATION=\"${FILE_OBJECT_CSR_FILE_LOCATION}\")

+ 202 - 0
source/src/cip/cip_security/LICENSE

@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.

+ 285 - 0
source/src/cip/cip_security/cert_req.c

@@ -0,0 +1,285 @@
+/*
+ *  Certificate request generation
+ *
+ *  Copyright The Mbed TLS Contributors
+ *  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.
+ * 
+ ******************************************************************************
+ *  Modifications copyright (C) 2023, Rockwell Automation, Inc.
+ *  All rights reserved.
+ ******************************************************************************/
+
+/** @file
+ * @brief Certificate signing request (CSR) generation
+ *
+ * ********************************************************************
+ * include files
+ */
+#include "mbedtls/build_info.h"
+#include "mbedtls/platform.h"
+/* md.h is included this early since MD_CAN_XXX macros are defined there. */
+#include "mbedtls/md.h"
+
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/error.h"
+#include "mbedtls/x509_csr.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cert_req.h"
+#include "ciptypes.h"
+#include "trace.h"
+
+#define DFL_FILENAME RSA_KEY_FILE_LOCATION  // config in CMakeLists.txt
+#define DFL_PASSWORD NULL
+#define DFL_DEBUG_LEVEL 0
+#define DFL_OUTPUT_FILENAME FILE_OBJECT_CSR_FILE_LOCATION  // config in CMakeLists.txt
+#define SUBJECT_NAME_TEMPLATE "CN=%s,O=%s,OU=%s,L=%s,ST=%s,C=%s,R=%s"
+#define DFL_KEY_USAGE 0
+#define DFL_FORCE_KEY_USAGE 0
+#define DFL_NS_CERT_TYPE 0
+#define DFL_FORCE_NS_CERT_TYPE 0
+#define DFL_MD_ALG MBEDTLS_MD_SHA256
+
+/*
+ * global options
+ */
+struct options {
+  const char *filename;     /* filename of the key file             */
+  const char *password;     /* password for the key file            */
+  int debug_level;          /* level of debugging                   */
+  const char *output_file;  /* where to store the constructed key file  */
+  const char *subject_name; /* subject name for certificate request   */
+  mbedtls_x509_san_list *san_list; /* subjectAltName for certificate request */
+  unsigned char key_usage;         /* key usage flags                      */
+  int force_key_usage;             /* Force adding the KeyUsage extension  */
+  unsigned char ns_cert_type;      /* NS cert type                         */
+  int force_ns_cert_type;          /* Force adding NsCertType extension    */
+  mbedtls_md_type_t md_alg;        /* Hash algorithm used for signature.   */
+} options;
+
+/** @brief  Write certificate request
+ * 
+ *  @param req structure containing CSR Parameters
+ *  @param output_file  where to store the constructed key file
+ *  @param f_rng random number generator function
+ *  @param p_rng random number generator param
+ *  @return status
+ */
+int write_certificate_request(mbedtls_x509write_csr *req,
+                              const char *output_file,
+                              int (*f_rng)(void *, unsigned char *, size_t),
+                              void *p_rng) {
+
+  int ret; //return value
+  unsigned char output_buf[4096];
+
+  memset(output_buf, 0, 4096);
+  if ((ret = mbedtls_x509write_csr_pem(req, output_buf, 4096, f_rng, p_rng)) <
+      0) {
+    return ret;
+  }
+
+  size_t len = strlen((char *)output_buf);
+  FILE *file;
+
+  if ((file = fopen(output_file, "w")) == NULL) {
+    return -1;
+  }
+
+  if (fwrite(output_buf, 1, len, file) != len) {
+    fclose(file);
+    return -1;
+  }
+
+  fclose(file);
+
+  return 0;
+}
+
+/* function called in OpENer certificatemanagement */
+int MbedtlsWriteCSR(CipShortString *short_strings) { 
+  int ret = 1;
+  int exit_code = MBEDTLS_EXIT_FAILURE;
+  mbedtls_pk_context key;
+  char buf[1024];
+
+  mbedtls_x509write_csr req;
+  mbedtls_entropy_context entropy;
+  mbedtls_ctr_drbg_context ctr_drbg; //ctr_drbg - Counter Mode Deterministic Random Bit Generator
+  mbedtls_x509_san_list *cur, *prev; //Subject Alternative Name List
+
+  /*
+   * Set to sane values
+   */
+  mbedtls_x509write_csr_init(&req);
+  mbedtls_pk_init(&key);
+  mbedtls_ctr_drbg_init(&ctr_drbg);
+  memset(buf, 0, sizeof(buf));
+  mbedtls_entropy_init(&entropy);
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+  psa_status_t status = psa_crypto_init();
+  if (status != PSA_SUCCESS) {
+    mbedtls_fprintf(stderr,
+                    "Failed to initialize PSA Crypto implementation: %d\n",
+                    (int)status);
+    goto exit;
+  }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+  /* create subjectName string from input params */
+  char subjectName[500];
+  snprintf(subjectName, sizeof(subjectName), SUBJECT_NAME_TEMPLATE, short_strings[0].string,
+                                                                    short_strings[1].string,
+                                                                    short_strings[2].string,
+                                                                    short_strings[3].string,
+                                                                    short_strings[4].string,
+                                                                    short_strings[5].string,
+                                                                    short_strings[6].string);
+
+  options.filename = DFL_FILENAME;
+  options.password = DFL_PASSWORD;
+  options.debug_level = DFL_DEBUG_LEVEL;
+  options.output_file = DFL_OUTPUT_FILENAME;
+  options.subject_name = subjectName;
+  options.key_usage = DFL_KEY_USAGE;
+  options.force_key_usage = DFL_FORCE_KEY_USAGE;
+  options.ns_cert_type = DFL_NS_CERT_TYPE;
+  options.force_ns_cert_type = DFL_FORCE_NS_CERT_TYPE;
+  options.md_alg = DFL_MD_ALG;
+  options.san_list = NULL;
+
+  /* Set the MD algorithm to use for the signature in the CSR */
+  mbedtls_x509write_csr_set_md_alg(&req, options.md_alg);
+
+  /* Set the Key Usage Extension flags in the CSR */
+  if (options.key_usage || options.force_key_usage == 1) {
+    ret = mbedtls_x509write_csr_set_key_usage(&req, options.key_usage);
+
+    if (ret != 0) {
+      OPENER_TRACE_INFO(
+          " failed\n  !  mbedtls_x509write_csr_set_key_usage returned %d", ret);
+      goto exit;
+    }
+  }
+
+  /* Set the Cert Type flags in the CSR */
+  if (options.ns_cert_type || options.force_ns_cert_type == 1) {
+    ret = mbedtls_x509write_csr_set_ns_cert_type(&req, options.ns_cert_type);
+
+    if (ret != 0) {
+      OPENER_TRACE_INFO(
+          " failed\n  !  mbedtls_x509write_csr_set_ns_cert_type returned %d", ret);
+      goto exit;
+    }
+  }
+
+  /*
+   * 0. Seed the PRNG (Pseudorandom number generator)
+   */
+  OPENER_TRACE_INFO("  . Seeding the random number generator...");
+  fflush(stdout);
+
+  if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
+                                   NULL,
+                                   0)) != 0) {
+    OPENER_TRACE_INFO(" failed\n  !  mbedtls_ctr_drbg_seed returned %d", ret);
+    goto exit;
+  }
+
+  OPENER_TRACE_INFO(" ok\n");
+
+  /*
+   * 1.0. Check the subject name for validity
+   */
+  OPENER_TRACE_INFO("  . Checking subject name...");
+  fflush(stdout);
+
+  if ((ret = mbedtls_x509write_csr_set_subject_name(&req, options.subject_name)) !=
+      0) {
+    OPENER_TRACE_INFO(
+        " failed\n  !  mbedtls_x509write_csr_set_subject_name returned %d",
+        ret);
+    goto exit;
+  }
+
+  OPENER_TRACE_INFO(" ok\n");
+
+  /*
+   * 1.1. Load the key
+   */
+  OPENER_TRACE_INFO("  . Loading the private key ...");
+  fflush(stdout);
+
+  ret = mbedtls_pk_parse_keyfile(&key, options.filename, options.password,
+                                 mbedtls_ctr_drbg_random, &ctr_drbg);
+
+  if (ret != 0) {
+    OPENER_TRACE_INFO(" failed\n  !  mbedtls_pk_parse_keyfile returned %d", ret);
+    goto exit;
+  }
+
+  mbedtls_x509write_csr_set_key(&req, &key);
+
+  OPENER_TRACE_INFO(" ok\n");
+
+  /*
+   * 1.2. Writing the request
+   */
+  OPENER_TRACE_INFO("  . Writing the certificate request ...");
+  fflush(stdout);
+
+  if ((ret = write_certificate_request(
+           &req, options.output_file, mbedtls_ctr_drbg_random, &ctr_drbg)) != 0) {
+    OPENER_TRACE_INFO(" failed\n  !  write_certificate_request %d", ret);
+    goto exit;
+  }
+
+  OPENER_TRACE_INFO(" ok\n\n");
+
+  exit_code = MBEDTLS_EXIT_SUCCESS;
+
+exit:
+
+  if (exit_code != MBEDTLS_EXIT_SUCCESS) {
+#ifdef MBEDTLS_ERROR_C
+    mbedtls_strerror(ret, buf, sizeof(buf));
+    OPENER_TRACE_INFO(" - %s\n", buf);
+#else
+    OPENER_TRACE_INFO("\n");
+#endif
+  }
+
+  mbedtls_x509write_csr_free(&req);
+  mbedtls_pk_free(&key);
+  mbedtls_ctr_drbg_free(&ctr_drbg);
+  mbedtls_entropy_free(&entropy);
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+  mbedtls_psa_crypto_free();
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+  cur = options.san_list;
+  while (cur != NULL) {
+    prev = cur;
+    cur = cur->next;
+    mbedtls_free(prev);
+  }
+
+  return exit_code;
+}

+ 24 - 0
source/src/cip/cip_security/cert_req.h

@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2023, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#ifndef OPENER_CERT_REQ_H
+#define OPENER_CERT_REQ_H
+
+#include "typedefs.h"
+#include "ciptypes.h"
+
+
+/* ********************************************************************
+ * public functions
+ */
+/** @brief  Certificate signing request generation
+ * 
+ *  @param short_strings structure containing CSR Parameters
+ *  @return status
+ */
+int MbedtlsWriteCSR(CipShortString *short_strings);
+
+#endif  // OPENER_CERT_REQ_H

+ 642 - 0
source/src/cip/cip_security/cert_write.c

@@ -0,0 +1,642 @@
+/*
+ *  Certificate generation and signing
+ *
+ *  Copyright The Mbed TLS Contributors
+ *  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.
+ * 
+ ******************************************************************************
+ *  Modifications copyright (C) 2023, Rockwell Automation, Inc.
+ *  All rights reserved.
+ ******************************************************************************/
+
+/** @file
+ * @brief Certificate generation and signing
+ *
+ * ********************************************************************
+ * include files
+ */
+#include "mbedtls/build_info.h"
+
+#include "mbedtls/platform.h"
+/* md.h is included this early since MD_CAN_XXX macros are defined there. */
+#include "mbedtls/md.h"
+
+#include "mbedtls/x509_crt.h"
+#include "mbedtls/x509_csr.h"
+#include "mbedtls/oid.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/error.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "cert_write.h"
+#include "trace.h"
+
+// oid - object identifier 
+#define SET_OID(x, oid) \
+    do { x.len = MBEDTLS_OID_SIZE(oid); x.p = (unsigned char *) oid; } while (0)
+
+#if defined(MBEDTLS_X509_CSR_PARSE_C)
+#define USAGE_CSR                                                           \
+    "    request_file=%%s         default: (empty)\n"                           \
+    "                            If request_file is specified, subject_key,\n"  \
+    "                            subject_pwd and subject_name are ignored!\n"
+#else
+#define USAGE_CSR ""
+#endif /* MBEDTLS_X509_CSR_PARSE_C */
+
+#define FORMAT_PEM              0
+#define FORMAT_DER              1
+
+#define DFL_ISSUER_CRT          ""
+#define DFL_REQUEST_FILE        ""
+#define DFL_SUBJECT_KEY         RSA_KEY_FILE_LOCATION // "subject.key"
+#define DFL_ISSUER_KEY          RSA_KEY_FILE_LOCATION // "ca.key"
+#define DFL_SUBJECT_PWD         ""
+#define DFL_ISSUER_PWD          ""
+#define DFL_OUTPUT_FILENAME     FILE_OBJECT_CERTIFICATE_FILE_LOCATION // "cert.crt"
+#define SUBJECT_NAME_TEMPLATE   "CN=%s,O=%s,OU=%s,L=%s,ST=%s,C=%s,R=%s"
+//#define DFL_SUBJECT_NAME      "CN=CA,O=mbed TLS,C=UK"
+#define DFL_ISSUER_NAME         SUBJECT_NAME_TEMPLATE//"CN=CA,O=mbed TLS,C=UK"
+#define DFL_NOT_BEFORE          "20010101000000"
+#define DFL_NOT_AFTER           "20301231235959"
+#define DFL_SERIAL              "1"
+#define DFL_SERIAL_HEX          "1"
+#define DFL_SELFSIGN            1 // 1: self-signed
+#define DFL_IS_CA               0
+#define DFL_MAX_PATHLEN         -1
+#define DFL_SIG_ALG             MBEDTLS_MD_SHA256
+#define DFL_KEY_USAGE           0
+#define DFL_EXT_KEY_USAGE       NULL
+#define DFL_NS_CERT_TYPE        0
+#define DFL_VERSION             3
+#define DFL_AUTH_IDENT          1
+#define DFL_SUBJ_IDENT          1
+#define DFL_CONSTRAINTS         1
+#define DFL_DIGEST              MBEDTLS_MD_SHA256
+#define DFL_FORMAT              FORMAT_PEM
+
+typedef enum {
+    SERIAL_FRMT_UNSPEC,
+    SERIAL_FRMT_DEC,
+    SERIAL_FRMT_HEX
+} serial_format_t;
+
+/*
+ * global options
+ */
+struct options {
+    const char *issuer_crt;     /* filename of the issuer certificate   */
+    const char *request_file;   /* filename of the certificate request  */
+    const char *subject_key;    /* filename of the subject key file     */
+    const char *issuer_key;     /* filename of the issuer key file      */
+    const char *subject_pwd;    /* password for the subject key file    */
+    const char *issuer_pwd;     /* password for the issuer key file     */
+    const char *output_file;    /* where to store the constructed CRT   */
+    const char *subject_name;   /* subject name for certificate         */
+    const char *issuer_name;    /* issuer name for certificate          */
+    const char *not_before;     /* validity period not before           */
+    const char *not_after;      /* validity period not after            */
+    const char *serial;         /* serial number string (decimal)       */
+    const char *serial_hex;     /* serial number string (hex)           */
+    int selfsign;               /* selfsign the certificate             */
+    int is_ca;                  /* is a CA certificate                  */
+    int max_pathlen;            /* maximum CA path length               */
+    int authority_identifier;   /* add authority identifier to CRT      */
+    int subject_identifier;     /* add subject identifier to CRT        */
+    int basic_constraints;      /* add basic constraints ext to CRT     */
+    int version;                /* CRT version                          */
+    mbedtls_md_type_t md;       /* Hash used for signing                */
+    unsigned char key_usage;    /* key usage flags                      */
+    mbedtls_asn1_sequence *ext_key_usage; /* extended key usages        */
+    unsigned char ns_cert_type; /* NS cert type                         */
+    int format;                 /* format                               */
+} options;
+
+
+/** @brief  write an X.509 certificate to a PEM or DER file format
+ * 
+ *  @param crt certificate structure
+ *  @param output_file  output file pointer
+ *  @param f_rng random number generator function
+ *  @param p_rng random number generator param
+ *  @return status
+ */
+int write_certificate(mbedtls_x509write_cert *crt, const char *output_file,
+                      int (*f_rng)(void *, unsigned char *, size_t),
+                      void *p_rng)
+{
+    int ret;
+    FILE *file;
+    unsigned char output_buf[4096];
+    unsigned char *output_start;
+    size_t len = 0;
+
+    memset(output_buf, 0, 4096);
+    if (options.format == FORMAT_DER) {
+        ret = mbedtls_x509write_crt_der(crt, output_buf, 4096,
+                                        f_rng, p_rng);
+        if (ret < 0) {
+            return ret;
+        }
+
+        len = (size_t)ret;
+        output_start = output_buf + 4096 - len;
+    } else {
+        ret = mbedtls_x509write_crt_pem(crt, output_buf, 4096,
+                                        f_rng, p_rng);
+        if (ret < 0) {
+            return ret;
+        }
+
+        len = strlen((char *) output_buf);
+        output_start = output_buf;
+    }
+
+    if ((file = fopen(output_file, "w")) == NULL) {
+        return -1;
+    }
+
+    if (fwrite(output_start, 1, len, file) != len) {
+        fclose(file);
+        return -1;
+    }
+
+    fclose(file);
+
+    return 0;
+}
+
+/** @brief  parse and convert a decimal string format to its equivalent binary representation
+ * 
+ *  @param obuf  output buffer
+ *  @param obufmax 
+ *  @param ibuf  input buffer
+ *  @param len  
+ *  @return status
+ */
+int parse_serial_decimal_format(unsigned char *obuf, size_t obufmax,
+                                const char *ibuf, size_t *len)
+{
+    unsigned long long int dec;
+    unsigned int remaining_bytes = sizeof(dec);
+    unsigned char *p = obuf;
+    unsigned char val;
+    char *end_ptr = NULL;
+
+    errno = 0;
+    dec = strtoull(ibuf, &end_ptr, 10);
+
+    if ((errno != 0) || (end_ptr == ibuf)) {
+        return -1;
+    }
+
+    *len = 0;
+
+    while (remaining_bytes > 0) {
+        if (obufmax < (*len + 1)) {
+            return -1;
+        }
+
+        val = (dec >> ((remaining_bytes - 1) * 8)) & 0xFF;
+
+        /* Skip leading zeros */
+        if ((val != 0) || (*len != 0)) {
+            *p = val;
+            (*len)++;
+            p++;
+        }
+
+        remaining_bytes--;
+    }
+
+    return 0;
+}
+
+/* function called in OpENer certificatemanagement */
+int MbedtlsGenerateCertificate(char *subject_name_input[], char *serial_number_input)
+{
+    int ret = 1;
+    int exit_code = MBEDTLS_EXIT_FAILURE;
+    mbedtls_x509_crt issuer_crt;
+    mbedtls_pk_context loaded_issuer_key;
+    mbedtls_pk_context loaded_subject_key;
+    mbedtls_pk_context *issuer_key = &loaded_issuer_key;
+    mbedtls_pk_context *subject_key = &loaded_subject_key;
+    char buf[1024];
+    char issuer_name[256];
+
+#if defined(MBEDTLS_X509_CSR_PARSE_C)
+    char subject_name[256]; 
+    mbedtls_x509_csr csr;
+#endif
+    mbedtls_x509write_cert crt;
+    //serial_format_t serial_frmt = SERIAL_FRMT_UNSPEC;
+    unsigned char serial[MBEDTLS_X509_RFC5280_MAX_SERIAL_LEN];
+    size_t serial_len;
+    //mbedtls_asn1_sequence *ext_key_usage;
+    mbedtls_entropy_context entropy;
+    mbedtls_ctr_drbg_context ctr_drbg; //ctr_drbg - Counter Mode Deterministic Random Bit Generator
+
+    /*
+     * Set to sane values
+     */
+    mbedtls_x509write_crt_init(&crt);
+    mbedtls_pk_init(&loaded_issuer_key);
+    mbedtls_pk_init(&loaded_subject_key);
+    mbedtls_ctr_drbg_init(&ctr_drbg);
+    mbedtls_entropy_init(&entropy);
+#if defined(MBEDTLS_X509_CSR_PARSE_C)
+    mbedtls_x509_csr_init(&csr);
+#endif
+    mbedtls_x509_crt_init(&issuer_crt);
+    memset(buf, 0, sizeof(buf));
+    memset(serial, 0, sizeof(serial));
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+    psa_status_t status = psa_crypto_init();
+    if (status != PSA_SUCCESS) {
+        mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n",
+                        (int) status);
+        goto exit;
+    }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+/* create issuerName string from input params */
+    char issuerName[500];
+    snprintf(issuerName, sizeof(issuerName), SUBJECT_NAME_TEMPLATE, subject_name_input[0],
+                                                                      subject_name_input[1],
+                                                                      subject_name_input[2],
+                                                                      subject_name_input[3],
+                                                                      subject_name_input[4],
+                                                                      subject_name_input[5],
+                                                                      subject_name_input[6]);
+
+    options.issuer_crt          = DFL_ISSUER_CRT;
+    options.request_file        = DFL_REQUEST_FILE;
+    options.subject_key         = DFL_SUBJECT_KEY;
+    options.issuer_key          = DFL_ISSUER_KEY;
+    options.subject_pwd         = DFL_SUBJECT_PWD;
+    options.issuer_pwd          = DFL_ISSUER_PWD;
+    options.output_file         = DFL_OUTPUT_FILENAME;
+    options.subject_name        = SUBJECT_NAME_TEMPLATE;  // same as issuer_name for self-signed certificate
+    options.issuer_name         = issuerName;
+    options.not_before          = DFL_NOT_BEFORE;
+    options.not_after           = DFL_NOT_AFTER;
+    options.serial              = serial_number_input;
+    options.serial_hex          = DFL_SERIAL_HEX;
+    options.selfsign            = DFL_SELFSIGN;
+    options.is_ca               = DFL_IS_CA;
+    options.max_pathlen         = DFL_MAX_PATHLEN;
+    options.key_usage           = DFL_KEY_USAGE;
+    options.ext_key_usage       = DFL_EXT_KEY_USAGE;
+    options.ns_cert_type        = DFL_NS_CERT_TYPE;
+    options.version             = DFL_VERSION - 1;
+    options.md                  = DFL_DIGEST;
+    options.subject_identifier   = DFL_SUBJ_IDENT;
+    options.authority_identifier = DFL_AUTH_IDENT;
+    options.basic_constraints    = DFL_CONSTRAINTS;
+    options.format              = DFL_FORMAT;
+
+    OPENER_TRACE_INFO("\n");
+
+    /*
+     * 0. Seed the PRNG
+     */
+    OPENER_TRACE_INFO("  . Seeding the random number generator...");
+    fflush(stdout);
+
+    if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
+                                     NULL,
+                                     0)) != 0) {
+        mbedtls_strerror(ret, buf, sizeof(buf));
+        OPENER_TRACE_INFO(" failed\n  !  mbedtls_ctr_drbg_seed returned %d - %s\n",
+                       ret, buf);
+        goto exit;
+    }
+
+    OPENER_TRACE_INFO(" ok\n");
+
+    // Parse serial to MPI
+    OPENER_TRACE_INFO("  . Reading serial number...");
+    fflush(stdout);
+
+    ret = parse_serial_decimal_format(serial, sizeof(serial), options.serial,
+                                      &serial_len);
+
+    if (ret != 0) {
+        OPENER_TRACE_INFO(" failed\n  !  Unable to parse serial\n");
+        goto exit;
+    }
+
+    OPENER_TRACE_INFO(" ok\n");
+
+    // Parse issuer certificate if present
+    //
+    if (!options.selfsign && strlen(options.issuer_crt)) {
+        /*
+         * 1.0.a. Load the certificates
+         */
+        OPENER_TRACE_INFO("  . Loading the issuer certificate ...");
+        fflush(stdout);
+
+        if ((ret = mbedtls_x509_crt_parse_file(&issuer_crt, options.issuer_crt)) != 0) {
+            mbedtls_strerror(ret, buf, sizeof(buf));
+            OPENER_TRACE_INFO(" failed\n  !  mbedtls_x509_crt_parse_file "
+                           "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf);
+            goto exit;
+        }
+
+        ret = mbedtls_x509_dn_gets(issuer_name, sizeof(issuer_name),
+                                   &issuer_crt.subject);
+        if (ret < 0) {
+            mbedtls_strerror(ret, buf, sizeof(buf));
+            OPENER_TRACE_INFO(" failed\n  !  mbedtls_x509_dn_gets "
+                           "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf);
+            goto exit;
+        }
+
+        options.issuer_name = issuer_name;
+
+        OPENER_TRACE_INFO(" ok\n");
+    }
+
+#if defined(MBEDTLS_X509_CSR_PARSE_C)
+    // Parse certificate request if present
+    //
+    if (!options.selfsign && strlen(options.request_file)) {
+        /*
+         * 1.0.b. Load the CSR
+         */
+        OPENER_TRACE_INFO("  . Loading the certificate request ...");
+        fflush(stdout);
+
+        if ((ret = mbedtls_x509_csr_parse_file(&csr, options.request_file)) != 0) {
+            mbedtls_strerror(ret, buf, sizeof(buf));
+            OPENER_TRACE_INFO(" failed\n  !  mbedtls_x509_csr_parse_file "
+                           "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf);
+            goto exit;
+        }
+
+        ret = mbedtls_x509_dn_gets(subject_name, sizeof(subject_name),
+                                   &csr.subject);
+        if (ret < 0) {
+            mbedtls_strerror(ret, buf, sizeof(buf));
+            OPENER_TRACE_INFO(" failed\n  !  mbedtls_x509_dn_gets "
+                           "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf);
+            goto exit;
+        }
+
+        options.subject_name = subject_name;
+        subject_key = &csr.pk;
+
+        OPENER_TRACE_INFO(" ok\n");
+    }
+#endif /* MBEDTLS_X509_CSR_PARSE_C */
+
+    /*
+     * 1.1. Load the keys
+     */
+    if (!options.selfsign && !strlen(options.request_file)) {
+        OPENER_TRACE_INFO("  . Loading the subject key ...");
+        fflush(stdout);
+
+        ret = mbedtls_pk_parse_keyfile(&loaded_subject_key, options.subject_key,
+                                       options.subject_pwd, mbedtls_ctr_drbg_random, &ctr_drbg);
+        if (ret != 0) {
+            mbedtls_strerror(ret, buf, sizeof(buf));
+            OPENER_TRACE_INFO(" failed\n  !  mbedtls_pk_parse_keyfile "
+                           "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf);
+            goto exit;
+        }
+
+        OPENER_TRACE_INFO(" ok\n");
+    }
+
+    OPENER_TRACE_INFO("  . Loading the issuer key ...");
+    fflush(stdout);
+
+    ret = mbedtls_pk_parse_keyfile(&loaded_issuer_key, options.issuer_key,
+                                   options.issuer_pwd, mbedtls_ctr_drbg_random, &ctr_drbg);
+    if (ret != 0) {
+        mbedtls_strerror(ret, buf, sizeof(buf));
+        OPENER_TRACE_INFO(" failed\n  !  mbedtls_pk_parse_keyfile "
+                       "returned -x%02x - %s\n\n", (unsigned int) -ret, buf);
+        goto exit;
+    }
+
+    // Check if key and issuer certificate match
+    //
+    if (strlen(options.issuer_crt)) {
+        if (mbedtls_pk_check_pair(&issuer_crt.pk, issuer_key,
+                                  mbedtls_ctr_drbg_random, &ctr_drbg) != 0) {
+            OPENER_TRACE_INFO(" failed\n  !  issuer_key does not match "
+                           "issuer certificate\n\n");
+            goto exit;
+        }
+    }
+
+    OPENER_TRACE_INFO(" ok\n");
+
+    if (options.selfsign) {
+        options.subject_name = options.issuer_name;
+        subject_key = issuer_key;
+    }
+
+    mbedtls_x509write_crt_set_subject_key(&crt, subject_key);
+    mbedtls_x509write_crt_set_issuer_key(&crt, issuer_key);
+
+    /*
+     * 1.0. Check the names for validity
+     */
+    if ((ret = mbedtls_x509write_crt_set_subject_name(&crt, options.subject_name)) != 0) {
+        mbedtls_strerror(ret, buf, sizeof(buf));
+        OPENER_TRACE_INFO(" failed\n  !  mbedtls_x509write_crt_set_subject_name "
+                       "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf);
+        goto exit;
+    }
+
+    if ((ret = mbedtls_x509write_crt_set_issuer_name(&crt, options.issuer_name)) != 0) {
+        mbedtls_strerror(ret, buf, sizeof(buf));
+        OPENER_TRACE_INFO(" failed\n  !  mbedtls_x509write_crt_set_issuer_name "
+                       "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf);
+        goto exit;
+    }
+
+    OPENER_TRACE_INFO("  . Setting certificate values ...");
+    fflush(stdout);
+
+    mbedtls_x509write_crt_set_version(&crt, options.version);
+    mbedtls_x509write_crt_set_md_alg(&crt, options.md);
+
+    ret = mbedtls_x509write_crt_set_serial_raw(&crt, serial, serial_len);
+    if (ret != 0) {
+        mbedtls_strerror(ret, buf, sizeof(buf));
+        OPENER_TRACE_INFO(" failed\n  !  mbedtls_x509write_crt_set_serial_raw "
+                       "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf);
+        goto exit;
+    }
+
+    ret = mbedtls_x509write_crt_set_validity(&crt, options.not_before, options.not_after);
+    if (ret != 0) {
+        mbedtls_strerror(ret, buf, sizeof(buf));
+        OPENER_TRACE_INFO(" failed\n  !  mbedtls_x509write_crt_set_validity "
+                       "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf);
+        goto exit;
+    }
+
+    OPENER_TRACE_INFO(" ok\n");
+
+    if (options.version == MBEDTLS_X509_CRT_VERSION_3 &&
+        options.basic_constraints != 0) {
+        OPENER_TRACE_INFO("  . Adding the Basic Constraints extension ...");
+        fflush(stdout);
+
+        ret = mbedtls_x509write_crt_set_basic_constraints(&crt, options.is_ca,
+                                                          options.max_pathlen);
+        if (ret != 0) {
+            mbedtls_strerror(ret, buf, sizeof(buf));
+            OPENER_TRACE_INFO(" failed\n  !  x509write_crt_set_basic_constraints "
+                           "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf);
+            goto exit;
+        }
+
+        OPENER_TRACE_INFO(" ok\n");
+    }
+
+#if defined(MBEDTLS_MD_CAN_SHA1)
+    if (options.version == MBEDTLS_X509_CRT_VERSION_3 &&
+        options.subject_identifier != 0) {
+        OPENER_TRACE_INFO("  . Adding the Subject Key Identifier ...");
+        fflush(stdout);
+
+        ret = mbedtls_x509write_crt_set_subject_key_identifier(&crt);
+        if (ret != 0) {
+            mbedtls_strerror(ret, buf, sizeof(buf));
+            OPENER_TRACE_INFO(" failed\n  !  mbedtls_x509write_crt_set_subject"
+                           "_key_identifier returned -0x%04x - %s\n\n",
+                           (unsigned int) -ret, buf);
+            goto exit;
+        }
+
+        OPENER_TRACE_INFO(" ok\n");
+    }
+
+    if (options.version == MBEDTLS_X509_CRT_VERSION_3 &&
+        options.authority_identifier != 0) {
+        OPENER_TRACE_INFO("  . Adding the Authority Key Identifier ...");
+        fflush(stdout);
+
+        ret = mbedtls_x509write_crt_set_authority_key_identifier(&crt);
+        if (ret != 0) {
+            mbedtls_strerror(ret, buf, sizeof(buf));
+            OPENER_TRACE_INFO(" failed\n  !  mbedtls_x509write_crt_set_authority_"
+                           "key_identifier returned -0x%04x - %s\n\n",
+                           (unsigned int) -ret, buf);
+            goto exit;
+        }
+
+        OPENER_TRACE_INFO(" ok\n");
+    }
+#endif /* MBEDTLS_MD_CAN_SHA1 */
+
+    if (options.version == MBEDTLS_X509_CRT_VERSION_3 &&
+        options.key_usage != 0) {
+        OPENER_TRACE_INFO("  . Adding the Key Usage extension ...");
+        fflush(stdout);
+
+        ret = mbedtls_x509write_crt_set_key_usage(&crt, options.key_usage);
+        if (ret != 0) {
+            mbedtls_strerror(ret, buf, sizeof(buf));
+            OPENER_TRACE_INFO(" failed\n  !  mbedtls_x509write_crt_set_key_usage "
+                           "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf);
+            goto exit;
+        }
+
+        OPENER_TRACE_INFO(" ok\n");
+    }
+
+    if (options.ext_key_usage) {
+        OPENER_TRACE_INFO("  . Adding the Extended Key Usage extension ...");
+        fflush(stdout);
+
+        ret = mbedtls_x509write_crt_set_ext_key_usage(&crt, options.ext_key_usage);
+        if (ret != 0) {
+            mbedtls_strerror(ret, buf, sizeof(buf));
+            OPENER_TRACE_INFO(
+                " failed\n  !  mbedtls_x509write_crt_set_ext_key_usage returned -0x%02x - %s\n\n",
+                (unsigned int) -ret,
+                buf);
+            goto exit;
+        }
+
+        OPENER_TRACE_INFO(" ok\n");
+    }
+
+    if (options.version == MBEDTLS_X509_CRT_VERSION_3 &&
+        options.ns_cert_type != 0) {
+        OPENER_TRACE_INFO("  . Adding the NS Cert Type extension ...");
+        fflush(stdout);
+
+        ret = mbedtls_x509write_crt_set_ns_cert_type(&crt, options.ns_cert_type);
+        if (ret != 0) {
+            mbedtls_strerror(ret, buf, sizeof(buf));
+            OPENER_TRACE_INFO(" failed\n  !  mbedtls_x509write_crt_set_ns_cert_type "
+                           "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf);
+            goto exit;
+        }
+
+        OPENER_TRACE_INFO(" ok\n");
+    }
+
+    /*
+     * 1.2. Writing the certificate
+     */
+    OPENER_TRACE_INFO("  . Writing the certificate...");
+    fflush(stdout);
+
+    if ((ret = write_certificate(&crt, options.output_file,
+                                 mbedtls_ctr_drbg_random, &ctr_drbg)) != 0) {
+        mbedtls_strerror(ret, buf, sizeof(buf));
+        OPENER_TRACE_INFO(" failed\n  !  write_certificate -0x%04x - %s\n\n",
+                       (unsigned int) -ret, buf);
+        goto exit;
+    }
+
+    OPENER_TRACE_INFO(" ok\n\n");
+
+    exit_code = MBEDTLS_EXIT_SUCCESS;
+
+exit:
+#if defined(MBEDTLS_X509_CSR_PARSE_C)
+    mbedtls_x509_csr_free(&csr);
+#endif /* MBEDTLS_X509_CSR_PARSE_C */
+    mbedtls_x509_crt_free(&issuer_crt);
+    mbedtls_x509write_crt_free(&crt);
+    mbedtls_pk_free(&loaded_subject_key);
+    mbedtls_pk_free(&loaded_issuer_key);
+    mbedtls_ctr_drbg_free(&ctr_drbg);
+    mbedtls_entropy_free(&entropy);
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+    mbedtls_psa_crypto_free();
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+    //mbedtls_exit(exit_code);
+    return exit_code;
+}

+ 25 - 0
source/src/cip/cip_security/cert_write.h

@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2023, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#ifndef OPENER_CERT_WRITE_H
+#define OPENER_CERT_WRITE_H
+
+#include "typedefs.h"
+#include "ciptypes.h"
+
+
+/* ********************************************************************
+ * public functions
+ */
+/** @brief Certificate generation
+ *
+ *  @param subject_name_input  subject name
+ *  @param serial_number_input  serial number in subject name
+ *  @return status
+ */
+int MbedtlsGenerateCertificate(char *subject_name_input[], char *serial_number_input);
+
+#endif  // OPENER_CERT_WRITE_H

+ 91 - 16
source/src/cip/cip_security/certificatemanagement.c

@@ -52,19 +52,27 @@
 #include "certificatemanagement.h"
 #include "cipsecurity.h"
 
-#include "OpENerFileObject/cipfile.h" //TODO: check
+#include "OpENerFileObject/cipfile.h"
 #include "cipepath.h"
 #include "cipstring.h"
 
+// MbedTLS files
+#include "cert_req.h"
+#include "gen_key.h"
+#include "cert_write.h"
+
+/** @brief The device's configuration data */
+#include "devicedata.h"
+
 /* ********************************************************************
  * defines
  */
 /** The implemented class revision is 1 */
-#define CERTIFICATE_MANAGEMENT_OBJECT_REVISION 1
+#define CERTIFICATE_MANAGEMENT_OBJECT_REVISION 2
 #define DEFAULT_DEVICE_CERTIFICATE_INSTANCE_NUMBER 1
 
 /**
- * declaration of (static) Certificate Management object instance 1 data
+ * declaration of (static) Certificate Management object class data
  */
 CertificateManagementObjectClassAttributes cmo_class_attr = {
   .capability_flags = kCertificateManagementObjectCapabilityFlagPushModel,
@@ -82,6 +90,17 @@ const CipShortString default_name = {
   .string = (EipByte *)(&instance_1_name),
 };
 
+char *default_device_certificate_subject_name[] = {
+                                          "OpENer", // 1: Common Name
+                                          "EIP Stack Group", // 2: Organization
+                                          "EIP Stack Group", // 3: Organizational Unit
+                                          "Vienna", // 4: City / Locality
+                                          "Vienna", // 5: State / County / Region
+                                          "AT", // 6: Country
+                                          "mail@example.com"}; // 7: Email address //TODO: add email
+
+CipUlint default_device_certificate_serial_number = OPENER_SERIAL_NUMBER; 
+
 Certificate default_device_certificate;
 
 Certificate default_ca_certificate;
@@ -361,7 +380,7 @@ EipStatus CertificateManagementObjectCreateCSR(
     message_router_response->general_status = kCipErrorObjectStateConflict;
   }
   else{
-    const size_t number_of_strings = 8; //number of Create_CSR Request Parameters
+    const size_t number_of_strings = 9; //number of Create_CSR Request Parameters
     CipShortString short_strings[number_of_strings];
     memset( short_strings, 0, sizeof(short_strings) );
     // 1: Common Name
@@ -372,6 +391,7 @@ EipStatus CertificateManagementObjectCreateCSR(
     // 6: Country
     // 7: Email address
     // 8: Serial number
+    // 9: Subject alternative name
 
     for(size_t i = 0; i < number_of_strings; i++) {
       DecodeCipShortString(&short_strings[i],
@@ -385,20 +405,34 @@ EipStatus CertificateManagementObjectCreateCSR(
       // The CMO state does not change after this service call with invalid parameters
       return kEipStatusOk;
     }
-
-    // use values from Default Device certificate if items are null
-    for(size_t i = 0; i < number_of_strings; i++) {
+ 
+    // use values from Default Device Certificate if items are null
+    for(size_t i = 0; i < number_of_strings-2; i++) {
       if(0 == short_strings[i].length) {
-        //TODO: use value from Default Device certificate
+        SetCipShortStringByCstr(&short_strings[i], default_device_certificate_subject_name[i]);
       }
     }
+    if(0 == short_strings[7].length){ //serial number
+      char serial_number[20];
+      sprintf(serial_number, "%lu", default_device_certificate_serial_number);
+      SetCipShortStringByCstr(&short_strings[7], serial_number);
+    }
+    if(0 == short_strings[8].length){ //Subject alternative name
+      //TODO: 
+      /* use the IP Address and/or DNS Name as defined in the TCP IP Interface 
+      Object in Volume 2 Section 5-4 TCP/IP Interface Object */
+    }
 
-    /* create file object for device certificate */
-    CipInstance CSR_file_object = CipFileCreateInstance(""); //no name TODO: check
+    /* create file object for certificate signing request */
+    CipInstance CSR_file_object = CipFileCreateInstance("Certificate Signing Request");
 
-    /* add data to file object */ //TODO: provide CSR file - mbedTLS, use values in short_strings
+    /* add data to file object */
     CipFileCreateCSRFileInstance(&CSR_file_object);
 
+    /* create CSR file (MbedTLS) with received data */
+    OPENER_TRACE_INFO("\nCreating CSR file:\n");
+    MbedtlsWriteCSR(short_strings);
+
     CipEpath CSR_file_object_path = CipEpathCreate(2,
                                                    kCipFileObjectClassCode,
                                                    CSR_file_object.instance_number,
@@ -543,7 +577,7 @@ EipStatus CertificateManagementObjectInit(void) {
 
   certificate_management_object_class = CreateCipClass(
     kCertificateManagementObjectClassCode,
-    3,    /* # class attributes */
+    10,   /* # class attributes */
     10,   /* # highest class attribute number */
     3,    /* # class services */
     5,    /* # instance attributes */
@@ -637,8 +671,49 @@ EipStatus CertificateManagementObjectInit(void) {
   g_certificate_management.device_certificate = default_device_certificate;          /*Attribute 3*/
   g_certificate_management.ca_certificate = default_ca_certificate;                  /*Attribute 4*/
   g_certificate_management.certificate_encoding =
-    kCertificateManagementObjectCertificateEncodingPEM;                                                 /*Attribute 5*/
-
+    kCertificateManagementObjectCertificateEncodingPEM;                              /*Attribute 5*/
+  
+  /* Create RSA key file (MbedTLS) */
+  OPENER_TRACE_INFO("\nCreating RSA key file: \n"); 
+  // check if key file exist already
+  FILE *key_file;
+  if ((key_file = fopen(RSA_KEY_FILE_LOCATION, "r")) != NULL) {
+    // check if file is empty
+    fseek (key_file, 0, SEEK_END);
+    long size = ftell(key_file);
+    if (0 != size) {
+        OPENER_TRACE_INFO(" Key EXISTS already!\n");
+        fclose(key_file);
+    }
+    else{ // empty file - create
+      MbedtlsGenerateKey();
+    }
+  }
+  else{ // file not found - create
+    MbedtlsGenerateKey();
+  } 
+    
+  /* Create Default device certificate (MbedTLS) */
+  char serial_number[20];
+  sprintf(serial_number, "%lu", default_device_certificate_serial_number);
+  OPENER_TRACE_INFO("\nGenerating default device certificate: \n");
+  // check if certificate file exist already
+  FILE *cert_file;
+  if ((cert_file = fopen(FILE_OBJECT_CERTIFICATE_FILE_LOCATION, "r")) != NULL) {
+    // check if file is empty
+    fseek (cert_file, 0, SEEK_END);
+    long size = ftell(cert_file);
+    if (0 != size) {
+        OPENER_TRACE_INFO(" Certificate EXISTS already!\n\n");
+        fclose(cert_file);
+    }
+    else{ // empty file - create
+      MbedtlsGenerateCertificate(default_device_certificate_subject_name, serial_number);
+    }
+  }
+  else{ // file not found - create
+    MbedtlsGenerateCertificate(default_device_certificate_subject_name, serial_number);
+  }
+  
   return kEipStatusOk;
-
-}
+}

+ 382 - 0
source/src/cip/cip_security/gen_key.c

@@ -0,0 +1,382 @@
+/*
+ *  Key generation application
+ *
+ *  Copyright The Mbed TLS Contributors
+ *  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.
+ *
+ *******************************************************************************
+ *  Modifications copyright (C) 2023, Rockwell Automation, Inc.
+ *  All rights reserved.
+ ******************************************************************************/
+
+/** @file
+ * @brief Key generation application
+ *
+ * ********************************************************************
+ * include files
+ */
+#include "mbedtls/build_info.h"
+
+#include "mbedtls/platform.h"
+
+#if defined(MBEDTLS_PK_WRITE_C) && defined(MBEDTLS_FS_IO) && \
+    defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_CTR_DRBG_C)
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/ecdsa.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/error.h"
+#include "mbedtls/pk.h"
+#include "mbedtls/rsa.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gen_key.h"
+#include "trace.h"
+
+#if !defined(_WIN32)
+#include <unistd.h>
+
+#define DEV_RANDOM_THRESHOLD 32
+
+#define PRINT_KEY 0 // print key in the terminal
+
+/** @brief gather additional randomness
+ * 
+ *  @param data user-specific context
+ *  @param output  buffer for random data
+ *  @param len length of buffer
+ *  @param olen length of output buffer - number of random bytes
+ *  @return status
+ */
+int dev_random_entropy_poll(void *data, unsigned char *output, size_t len,
+                            size_t *olen) {
+  FILE *file;
+  size_t ret = len;
+  size_t left = len;
+  unsigned char *p = output;
+  ((void)data);
+
+  *olen = 0;
+
+  file = fopen("/dev/random", "rb");
+  if (file == NULL) {
+    return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
+  }
+
+  while (left > 0) {
+    /* /dev/random can return much less than requested. If so, try again */
+    ret = fread(p, 1, left, file);
+    if (ret == 0 && ferror(file)) { 
+      fclose(file);
+      return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
+    } 
+
+    p += ret;
+    left -= ret;
+    sleep(1);
+  }
+  fclose(file);
+  *olen = len;
+
+  return 0;
+}
+#endif /* !_WIN32 */
+#endif
+
+#if defined(MBEDTLS_ECP_C)
+#define DFL_EC_CURVE mbedtls_ecp_curve_list()->grp_id // list of supported elliptic curves
+#else
+#define DFL_EC_CURVE 0
+#endif
+
+#if !defined(_WIN32) && defined(MBEDTLS_FS_IO)
+#define USAGE_DEV_RANDOM "    use_dev_random=0|1    default: 0\n"
+#else
+#define USAGE_DEV_RANDOM ""
+#endif /* !_WIN32 && MBEDTLS_FS_IO */
+
+#define FORMAT_PEM 0
+#define FORMAT_DER 1
+
+#define DFL_TYPE            MBEDTLS_PK_RSA
+#define DFL_RSA_KEYSIZE     2048
+#define DFL_FILENAME        RSA_KEY_FILE_LOCATION  // "keyfile.key"
+#define DFL_FORMAT          FORMAT_PEM
+#define DFL_USE_DEV_RANDOM  0
+
+/*
+ * global options
+ */
+struct options {
+  int type;             /* the type of key to generate          */
+  unsigned int rsa_keysize;    /* length of key in bits         */
+  int ec_curve;         /* curve identifier for EC keys         */
+  const char *filename; /* filename of the key file             */
+  int format;           /* the output format to use             */
+  int use_dev_random;   /* use /dev/random as entropy source    */
+} options;
+
+/** @brief  write a private key to a file in a particular format
+ * 
+ *  @param key private key
+ *  @param output_file  output file pointer
+ *  @return status
+ */
+static int write_private_key(mbedtls_pk_context *key, const char *output_file) {
+  int ret;
+  FILE *file;
+  unsigned char output_buf[16000];
+  unsigned char *c = output_buf;
+  size_t len = 0;
+
+  memset(output_buf, 0, 16000);
+  if (options.format == FORMAT_PEM) {
+    if ((ret = mbedtls_pk_write_key_pem(key, output_buf, 16000)) != 0) {
+      return ret;
+    }
+
+    len = strlen((char *)output_buf);
+  } else {
+    if ((ret = mbedtls_pk_write_key_der(key, output_buf, 16000)) < 0) {
+      return ret;
+    }
+
+    len = (size_t)ret;
+    c = output_buf + sizeof(output_buf) - len;
+  }
+
+  if ((file = fopen(output_file, "wb")) == NULL) {
+    return -1;
+  }
+
+  if (fwrite(c, 1, len, file) != len) {
+    fclose(file);
+    return -1;
+  }
+
+  fclose(file);
+
+  return 0;
+}
+
+/* function called in OpENer certificatemanagement */
+int MbedtlsGenerateKey(void)
+{
+  int ret = 1;
+  int exit_code = MBEDTLS_EXIT_FAILURE;
+  mbedtls_pk_context key;
+  char buf[1024];
+
+  mbedtls_mpi N, P, Q, D, E, DP, DQ, QP; //multi precision integer structure
+  mbedtls_entropy_context entropy;
+  mbedtls_ctr_drbg_context ctr_drbg; //ctr_drbg - Counter Mode Deterministic Random Bit Generator
+  const char *personalization = "gen_key"; // The personalization string is a small protection against a lack of startup entropy and ensures each application has at least a different starting point.
+
+  /*
+   * Set to sane values
+   */
+
+  mbedtls_mpi_init(&N); //multi precision integer structure
+  mbedtls_mpi_init(&P);
+  mbedtls_mpi_init(&Q);
+  mbedtls_mpi_init(&D);
+  mbedtls_mpi_init(&E);
+  mbedtls_mpi_init(&DP);
+  mbedtls_mpi_init(&DQ);
+  mbedtls_mpi_init(&QP);
+
+  mbedtls_pk_init(&key); //pk - public key
+  mbedtls_ctr_drbg_init(&ctr_drbg);
+  memset(buf, 0, sizeof(buf));
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+  psa_status_t status = psa_crypto_init();
+  if (status != PSA_SUCCESS) {
+    OPENER_TRACE_INFO(stderr,
+                    "Failed to initialize PSA Crypto implementation: %d\n",
+                    (int)status);
+    goto exit;
+  }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+  options.type = DFL_TYPE;
+  options.rsa_keysize = DFL_RSA_KEYSIZE;
+  options.ec_curve = DFL_EC_CURVE;
+  options.filename = DFL_FILENAME;
+  options.format = DFL_FORMAT;
+  options.use_dev_random = DFL_USE_DEV_RANDOM;
+
+  OPENER_TRACE_INFO("\n  . Seeding the random number generator...");
+  fflush(stdout);
+
+  mbedtls_entropy_init(&entropy);
+#if !defined(_WIN32) && defined(MBEDTLS_FS_IO)
+  if (options.use_dev_random) {
+    if ((ret = mbedtls_entropy_add_source(
+             &entropy, dev_random_entropy_poll, NULL, DEV_RANDOM_THRESHOLD,
+             MBEDTLS_ENTROPY_SOURCE_STRONG)) != 0) {
+      OPENER_TRACE_INFO(
+          " failed\n  ! mbedtls_entropy_add_source returned -0x%04x\n",
+          (unsigned int)-ret);
+      goto exit;
+    }
+
+    OPENER_TRACE_INFO("\n    Using /dev/random, so can take a long time! ");
+    fflush(stdout);
+  }
+#endif /* !_WIN32 && MBEDTLS_FS_IO */
+
+  if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
+                                   (const unsigned char *)personalization,
+                                   strlen(personalization))) != 0) {
+    OPENER_TRACE_INFO(" failed\n  ! mbedtls_ctr_drbg_seed returned -0x%04x\n",
+                   (unsigned int)-ret);
+    goto exit;
+  }
+
+  OPENER_TRACE_INFO(" ok");
+
+  /*
+   * 1.1. Generate the key
+   */
+  OPENER_TRACE_INFO("\n  . Generating the private key ...");
+  fflush(stdout);
+
+  if ((ret = mbedtls_pk_setup(&key, mbedtls_pk_info_from_type(
+                                        (mbedtls_pk_type_t)options.type))) != 0) {
+    OPENER_TRACE_INFO(" failed\n  !  mbedtls_pk_setup returned -0x%04x",
+                   (unsigned int)-ret);
+    goto exit;
+  }
+
+#if defined(MBEDTLS_RSA_C) && defined(MBEDTLS_GENPRIME)
+  if (options.type == MBEDTLS_PK_RSA) {
+    ret = mbedtls_rsa_gen_key(mbedtls_pk_rsa(key), mbedtls_ctr_drbg_random,
+                              &ctr_drbg, options.rsa_keysize, 65537);
+    if (ret != 0) {
+      OPENER_TRACE_INFO(" failed\n  !  mbedtls_rsa_gen_key returned -0x%04x",
+                     (unsigned int)-ret);
+      goto exit;
+    }
+  } else
+#endif /* MBEDTLS_RSA_C */
+#if defined(MBEDTLS_ECP_C)
+      if (options.type == MBEDTLS_PK_ECKEY) {
+    ret = mbedtls_ecp_gen_key((mbedtls_ecp_group_id)options.ec_curve,
+                              mbedtls_pk_ec(key), mbedtls_ctr_drbg_random,
+                              &ctr_drbg);
+    if (ret != 0) {
+      OPENER_TRACE_INFO(" failed\n  !  mbedtls_ecp_gen_key returned -0x%04x",
+                     (unsigned int)-ret);
+      goto exit;
+    }
+  } else
+#endif /* MBEDTLS_ECP_C */
+  {
+    OPENER_TRACE_INFO(" failed\n  !  key type not supported\n");
+    goto exit;
+  }
+
+   OPENER_TRACE_INFO(" ok");
+
+#if(PRINT_KEY)
+  /*
+   * 1.2 Print the key - OPTIONAL
+   */
+  OPENER_TRACE_INFO("\n  . Key information:\n");
+
+#if defined(MBEDTLS_RSA_C)
+  if (mbedtls_pk_get_type(&key) == MBEDTLS_PK_RSA) {
+    mbedtls_rsa_context *rsa = mbedtls_pk_rsa(key);
+
+    if ((ret = mbedtls_rsa_export(rsa, &N, &P, &Q, &D, &E)) != 0 ||
+        (ret = mbedtls_rsa_export_crt(rsa, &DP, &DQ, &QP)) != 0) {
+      OPENER_TRACE_INFO(" failed\n  ! could not export RSA parameters\n\n");
+      goto exit;
+    }
+
+    mbedtls_mpi_write_file("N:  ", &N, 16, NULL); // mpi - multi precision integer structure
+    mbedtls_mpi_write_file("E:  ", &E, 16, NULL);
+    mbedtls_mpi_write_file("D:  ", &D, 16, NULL);
+    mbedtls_mpi_write_file("P:  ", &P, 16, NULL);
+    mbedtls_mpi_write_file("Q:  ", &Q, 16, NULL);
+    mbedtls_mpi_write_file("DP: ", &DP, 16, NULL);
+    mbedtls_mpi_write_file("DQ:  ", &DQ, 16, NULL);
+    mbedtls_mpi_write_file("QP:  ", &QP, 16, NULL);
+  } else
+#endif
+#if defined(MBEDTLS_ECP_C)
+      if (mbedtls_pk_get_type(&key) == MBEDTLS_PK_ECKEY) {
+    mbedtls_ecp_keypair *ecp = mbedtls_pk_ec(key);
+    OPENER_TRACE_INFO(
+        "curve: %s\n",
+        mbedtls_ecp_curve_info_from_grp_id(ecp->MBEDTLS_PRIVATE(grp).id)->name);
+    mbedtls_mpi_write_file(
+        "X_Q:   ", &ecp->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X), 16, NULL);
+    mbedtls_mpi_write_file(
+        "Y_Q:   ", &ecp->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y), 16, NULL);
+    mbedtls_mpi_write_file("D:     ", &ecp->MBEDTLS_PRIVATE(d), 16, NULL);
+  } else
+#endif
+    OPENER_TRACE_INFO("  ! key type not supported\n");
+
+#endif /* PRINT_KEY */  
+
+  /*
+   * 1.3 Export key
+   */
+  OPENER_TRACE_INFO("\n  . Writing key to file... ");
+
+  if ((ret = write_private_key(&key, options.filename)) != 0) {
+    OPENER_TRACE_INFO(" failed\n");
+    goto exit;
+  }
+
+  OPENER_TRACE_INFO(" ok\n");
+
+  exit_code = MBEDTLS_EXIT_SUCCESS;
+
+exit:
+
+  if (exit_code != MBEDTLS_EXIT_SUCCESS) {
+#ifdef MBEDTLS_ERROR_C
+    mbedtls_strerror(ret, buf, sizeof(buf));
+    OPENER_TRACE_INFO(" - %s\n", buf);
+#else
+    OPENER_TRACE_INFO("\n");
+#endif
+  }
+
+  mbedtls_mpi_free(&N);  // mpi - multi precision integer structure
+  mbedtls_mpi_free(&P);
+  mbedtls_mpi_free(&Q);
+  mbedtls_mpi_free(&D);
+  mbedtls_mpi_free(&E);
+  mbedtls_mpi_free(&DP);
+  mbedtls_mpi_free(&DQ);
+  mbedtls_mpi_free(&QP);
+
+  mbedtls_pk_free(&key);
+  mbedtls_ctr_drbg_free(&ctr_drbg);
+  mbedtls_entropy_free(&entropy);
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+  mbedtls_psa_crypto_free();
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+  // mbedtls_exit(exit_code)
+  return exit_code;
+}

+ 22 - 0
source/src/cip/cip_security/gen_key.h

@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2023, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#ifndef OPENER_GEN_KEY_H
+#define OPENER_GEN_KEY_H
+
+#include "typedefs.h"
+#include "ciptypes.h"
+
+/* ********************************************************************
+ * public functions
+ */
+/** @brief Key generation
+ *
+ *  @return Status
+ */
+int MbedtlsGenerateKey(void);
+
+#endif  // OPENER_GEN_KEY_H