Build breaks fixed.
occertutility.{c,h} moved back into security subtree.
Change-Id: I348dbe5d2133b57a49d4cdef05ce6e747af5eea0
Signed-off-by: Kevin Kane <kkane@microsoft.com>
libocsrm_src = libocsrm_src + [OCSRM_SRC + 'oxmpincommon.c', OCSRM_SRC + 'pbkdf2.c']
libocsrm_src = libocsrm_src + [OCSRM_SRC + 'crlresource.c', OCSRM_SRC + 'pkix_interface.c']
libocsrm_src = libocsrm_src + [OCSRM_SRC + 'oxmverifycommon.c']
- libocsrm_src = libocsrm_src + [OCSRM_SRC + 'certhelpers.c', OCSRM_SRC + 'csrresource.c']
++ libocsrm_src = libocsrm_src + [OCSRM_SRC + 'certhelpers.c', OCSRM_SRC + 'csrresource.c', OCSRM_SRC + 'occertutility.c' ]
if target_os in ['windows', 'msys_nt']:
libocsrm_src = libocsrm_src + [OCSRM_SRC + 'strptime.c']
--- /dev/null
-
- return 0;
+//******************************************************************
+//
+// Copyright 2017 Microsoft
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//******************************************************************
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <vector>
+
+#include "ocstack.h"
+#include "oic_malloc.h"
+#include "ocrandom.h"
+#include "occertutility.h"
+
+#ifdef HAVE_WINDOWS_H
+#include <windows.h>
+/** @todo stop-gap for naming issue. Windows.h does not like us to use ERROR */
+#ifdef ERROR
+#undef ERROR
+#endif //ERROR
+#endif //HAVE_WINDOWS_H
+
+static long GetFileSize(FILE *f)
+{
+ long offset, size;
+
+ offset = ftell(f);
+
+ if (offset < 0)
+ {
+ return offset;
+ }
+
+ if (fseek(f, 0, SEEK_END) < 0)
+ {
+ return -1;
+ }
+
+ size = ftell(f);
+
+ if (fseek(f, 0, SEEK_SET) < 0)
+ {
+ return -1;
+ }
+
+ return size;
+}
+
+static char *ReadLine(char *buf, size_t len)
+{
+ char *p;
+ int lenAsInt;
+
+ if (len > 0xFFFFFFFF)
+ {
+ return NULL;
+ }
+ else
+ {
+ lenAsInt = (int)len;
+ }
+
+ if (NULL == fgets(buf, lenAsInt, stdin))
+ {
+ return NULL;
+ }
+
+ /* Trim newline that fgets stores in the buffer. */
+ for (p = buf; ((p - buf) < lenAsInt) && (*p != '\r') && (*p != '\n'); p++);
+
+ *p = '\0';
+
+ return buf;
+}
+
+typedef enum {
+ CA_CERT,
+ IDENTITY_CERT,
+ ROLE_CERT
+} CertType;
+
+static void DoGenCertificate(CertType certType)
+{
+ OCStackResult res;
+ char subjKeyPairName[50];
+ char issKeyPairName[50];
+ char filename[70];
+ char subject[100];
+ char authority[100];
+ OicUuid_t subjectUuid;
+ char notValidBefore[50];
+ char notValidAfter[50];
+ char *serial = NULL;
+ size_t serialLen = 0;
+ long fileLen = 0;
+ size_t bytesProcessed = 0;
+ std::vector<char> publicKey;
+ std::vector<char> privateKey;
+ std::vector<char> issuerCert;
+ FILE *f = NULL;
+ time_t nowTimeT;
+ struct tm *now;
+ char *certificate = NULL;
+ size_t certificateLen = 0;
+
+ printf("Subject key pair name (do not include .pub or .prv): ");
+ if (NULL == ReadLine(subjKeyPairName, sizeof(subjKeyPairName)))
+ {
+ printf("Failed to get key pair name!");
+ goto exit;
+ }
+
+ /* This sample only supports self-signed CAs. Intermediates can be created with
+ * the helper functions, though, by providing a different issuer private key and
+ * certificate.
+ */
+ if (CA_CERT != certType)
+ {
+ printf("Issuer cert/key pair name (do not include .crt, .pub, or .prv): ");
+ if (NULL == ReadLine(issKeyPairName, sizeof(issKeyPairName)))
+ {
+ printf("Failed to get key pair name!");
+ goto exit;
+ }
+ }
+ else
+ {
+ strcpy(issKeyPairName, subjKeyPairName);
+ }
+
+ // -- Load public key --
+
+ sprintf(filename, "%s.pub", subjKeyPairName);
+ f = fopen(filename, "rb");
+ if (NULL == f)
+ {
+ printf("Could not open public key!\n");
+ goto exit;
+ }
+
+ fileLen = GetFileSize(f);
+ if (fileLen < 0)
+ {
+ printf("Could not get size of public key!\n");
+ goto exit;
+ }
+
+ publicKey.resize(fileLen);
+ bytesProcessed = fread(publicKey.data(), 1, publicKey.size(), f);
+ if (bytesProcessed < publicKey.size())
+ {
+ printf("Could not read public key! Got %zu, expected %zu\n", bytesProcessed, publicKey.size());
+ goto exit;
+ }
+
+ if (0 != fclose(f))
+ {
+ printf("Warning: could not fclose public key\n");
+ }
+
+ // -- Load private key --
+ sprintf(filename, "%s.prv", issKeyPairName);
+ f = fopen(filename, "rb");
+ if (NULL == f)
+ {
+ printf("Could not open private key!\n");
+ goto exit;
+ }
+
+ fileLen = GetFileSize(f);
+ if (fileLen < 0)
+ {
+ printf("Could not get size of private key!\n");
+ goto exit;
+ }
+
+ privateKey.resize(fileLen);
+ bytesProcessed = fread(privateKey.data(), 1, privateKey.size(), f);
+ if (bytesProcessed < privateKey.size())
+ {
+ printf("Could not read private key! Got %zu, expected %zu\n", bytesProcessed, privateKey.size());
+ goto exit;
+ }
+
+ if (0 != fclose(f))
+ {
+ printf("Warning: could not fclose private key\n");
+ }
+
+ f = NULL;
+
+ // -- Load issuer cert if applicable --
+ if (CA_CERT != certType)
+ {
+ sprintf(filename, "%s.crt", issKeyPairName);
+ f = fopen(filename, "rb");
+ if (NULL == f)
+ {
+ printf("Could not open issuer certificate file!\n");
+ goto exit;
+ }
+
+ fileLen = GetFileSize(f);
+ if (fileLen < 0)
+ {
+ printf("Could not get size of issuer certificate!\n");
+ goto exit;
+ }
+
+ issuerCert.resize(fileLen);
+ bytesProcessed = fread(issuerCert.data(), 1, issuerCert.size(), f);
+ if (bytesProcessed < issuerCert.size())
+ {
+ printf("Could not read issuer certificate! Got %zu, expected %zu\n", bytesProcessed, issuerCert.size());
+ goto exit;
+ }
+
+ if (0 != fclose(f))
+ {
+ printf("Warning: could not fclose issuer certificate\n");
+ }
+
+ f = NULL;
+ }
+
+ // -- Prompt user for subject name --
+
+ if (CA_CERT == certType)
+ {
+ printf("Subject name as comma-separated list of RDN types and values\n");
+ printf("e.g.: C=US, O=Open Connectivity Foundation, CN=Main CA : ");
+ if (NULL == ReadLine(subject, sizeof(subject)))
+ {
+ printf("Failed to get subject!\n");
+ goto exit;
+ }
+ }
+ else
+ {
+ printf("Subject UUID in the RFC 4122 form (XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX): ");
+ if (NULL == ReadLine(subject, sizeof(subject)))
+ {
+ printf("Failed to get subject UUID!");
+ goto exit;
+ }
+
+ if (!OCConvertStringToUuid(subject, subjectUuid.id))
+ {
+ printf("Failed to parse input UUID!\n");
+ goto exit;
+ }
+ }
+
+ // -- Compute validity to be ten years from current time --
+ nowTimeT = time(NULL);
+ now = gmtime(&nowTimeT);
+
+ if (0 == strftime(notValidBefore, sizeof(notValidBefore), "%Y%m%d%H%M%S", now))
+ {
+ printf("Failed to format notValidBefore time!");
+ goto exit;
+ }
+
+ now->tm_year += 10;
+
+ if (0 == strftime(notValidAfter, sizeof(notValidAfter), "%Y%m%d%H%M%S", now))
+ {
+ printf("Failed to format notValidAfter time!");
+ goto exit;
+ }
+
+ // -- Generate random serial number. A real CA should record serial numbers as they are used, and --
+ // -- make sure none are ever repeated! --
+
+ res = OCGenerateRandomSerialNumber(&serial, &serialLen);
+ if (OC_STACK_OK != res)
+ {
+ printf("Failed to generate a serial number!\n");
+ goto exit;
+ }
+
+ switch (certType)
+ {
+ case CA_CERT:
+ res = OCGenerateCACertificate(
+ subject,
+ publicKey.data(),
+ NULL,
+ privateKey.data(),
+ serial,
+ notValidBefore,
+ notValidAfter,
+ &certificate,
+ &certificateLen);
+ break;
+
+ case IDENTITY_CERT:
+ res = OCGenerateIdentityCertificate(
+ &subjectUuid,
+ publicKey.data(),
+ issuerCert.data(),
+ privateKey.data(),
+ serial,
+ notValidBefore,
+ notValidAfter,
+ &certificate,
+ &certificateLen);
+ break;
+
+ case ROLE_CERT:
+ printf("Role name: ");
+ /* We don't need subject's contents now, so reuse the buffer.*/
+ if (NULL == ReadLine(subject, sizeof(subject)))
+ {
+ printf("Failed to read role name!\n");
+ goto exit;
+ }
+ printf("Authority name (press ENTER for none): ");
+ if (NULL == ReadLine(authority, sizeof(authority)))
+ {
+ printf("Failed to read authority name!\n");
+ goto exit;
+ }
+ res = OCGenerateRoleCertificate(
+ &subjectUuid,
+ publicKey.data(),
+ issuerCert.data(),
+ privateKey.data(),
+ serial,
+ notValidBefore,
+ notValidAfter,
+ subject,
+ ('\0' != *authority)?authority:NULL,
+ &certificate,
+ &certificateLen);
+ break;
+ }
+
+ if (OC_STACK_OK != res)
+ {
+ printf("Failed to generate certificate!\n");
+ goto exit;
+ }
+
+ sprintf(filename, "%s.crt", subjKeyPairName);
+ f = fopen(filename, "wb");
+ if (NULL == f)
+ {
+ printf("Failed to open certificate file for writing!\n");
+ goto exit;
+ }
+
+ bytesProcessed = fwrite(certificate, 1, certificateLen, f);
+ if (bytesProcessed < certificateLen)
+ {
+ printf("Failed to write certificate! Had %zu bytes, wrote %zu\n", certificateLen, bytesProcessed);
+ goto exit;
+ }
+
+ if (0 != fclose(f))
+ {
+ printf("Warning: failed to close certificate file\n");
+ goto exit;
+ }
+
+ f = NULL;
+
+ printf("Wrote certificate file.\n");
+
+exit:
+
+ OICFree(serial);
+ OICFree(certificate);
+ if (NULL != f)
+ {
+ if (0 != fclose(f))
+ {
+ printf("Warning: failed to fclose\n");
+ }
+ }
+}
+
+static void DoGenKeyPair()
+{
+ OCStackResult res = OC_STACK_OK;
+ char nameBuf[100];
+ char *publicKey = NULL;
+ char *privateKey = NULL;
+ size_t publicKeyLen = 0;
+ size_t privateKeyLen = 0;
+ FILE *f = NULL;
+
+ printf("Name the key pair: ");
+ if (NULL == ReadLine(nameBuf, sizeof(nameBuf)))
+ {
+ printf("Failed to read name!");
+ return;
+ }
+
+ res = OCGenerateKeyPair(&publicKey, &publicKeyLen, &privateKey, &privateKeyLen);
+ if (OC_STACK_OK == res)
+ {
+ char filename[120];
+ size_t written;
+
+ sprintf(filename, "%s.pub", nameBuf);
+ f = fopen(filename, "wb");
+ if (NULL == f)
+ {
+ printf("Couldn't open %s to write public key!\n", filename);
+ goto exit;
+ }
+
+ written = fwrite(publicKey, 1, publicKeyLen, f);
+ if (written < publicKeyLen)
+ {
+ printf("Failed to write public key! Had %zu, wrote %zu\n", publicKeyLen, written);
+ goto exit;
+ }
+
+ if (0 != fclose(f))
+ {
+ printf("Warning: failed to fclose. Errno: %d\n", errno);
+ }
+
+ printf("Wrote public key.\n");
+
+ sprintf(filename, "%s.prv", nameBuf);
+ f = fopen(filename, "wb");
+ if (NULL == f)
+ {
+ printf("Couldn't open %s to write private key!\n", filename);
+ goto exit;
+ }
+ written = fwrite(privateKey, 1, privateKeyLen, f);
+ if (written < privateKeyLen)
+ {
+ printf("Failed to write private key! Had %zu, wrote %zu\n", privateKeyLen, written);
+ goto exit;
+ }
+
+ if (0 != fclose(f))
+ {
+ printf("Warning: failed to fclose. Errno: %d\n", errno);
+ }
+ f = NULL;
+
+ printf("Wrote private key.\n");
+ }
+ else
+ {
+ printf("Failed!\n");
+ }
+
+exit:
+
+ OICFree(publicKey);
+ OICClearMemory(privateKey, privateKeyLen);
+ OICFree(privateKey);
+ if (NULL != f)
+ {
+ if (0 != fclose(f))
+ {
+ printf("Warning: failed to fclose. errno: %d\n", errno);
+ }
+ }
+}
+
+int main()
+{
+ for (;;)
+ {
+ int option;
+
+ printf("-- Certificate Generator Sample Utility --\n\n");
+
+ printf(" 1. Generate a new key pair\n");
+ printf(" 2. Generate a self-signed CA certificate (requires a key pair for the CA)\n");
+ printf(" 3. Generate an identity certificate for a particular device UUID\n");
+ printf(" (requires the CA's private key and certificate, and the device's public key)\n");
+ printf(" 4. Generate a role certificate for a particular device UUID and role\n");
+ printf(" (requires the CA's private key and certificate, and the device's public key)\n");
+
+ printf("\n");
+ printf(" 0. Exit\n");
+ printf("\n");
+ printf("Select: ");
+
+ if (scanf("%d", &option) < 1)
+ {
+ printf("Failed to read the option! Exiting.\n");
+ return 0;
+ }
+
+ while ('\n' != getchar()); /* Consume the rest of the line so it doesn't get fed to the next input. */
+
+ switch (option)
+ {
+ case 1:
+ DoGenKeyPair();
+ break;
+ case 2:
+ DoGenCertificate(CA_CERT);
+ break;
+ case 3:
+ DoGenCertificate(IDENTITY_CERT);
+ break;
+ case 4:
+ DoGenCertificate(ROLE_CERT);
+ break;
+ case 0:
+ return 0;
+ default:
+ printf("Invalid option %d\n\n", option);
+ break;
+ }
+ }
+}
{
cborFindResult = DeserializeEncodingFromCbor(&credMap, &cred->privateData);
VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed to read privateData structure");
--
-- OicEncodingType_t encoding = cred->privateData.encoding;
- if (OIC_ENCODING_DER == encoding || OIC_ENCODING_PEM == encoding)
- {
- //For unit test
- cred->privateData.encoding = OIC_ENCODING_RAW;
- OIC_LOG(WARNING, TAG, "Unknown encoding type detected for private data.");
- }
}
#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
//PublicData -- Not Mandatory
--- /dev/null
- VERIFY_NOT_NULL(TAG, outPayload, ERROR);
+//******************************************************************
+//
+// Copyright 2017 Microsoft
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//******************************************************************
+
+#include "iotivity_config.h"
+#include <stdlib.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#include <stdint.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include "oic_string.h"
+#include "cainterface.h"
+#include "payload_logging.h"
+#include "ocstack.h"
+#include "ocrandom.h"
+#include "cacommon.h"
+#include "srmresourcestrings.h"
+#include "ocpayload.h"
+#include "ocpayloadcbor.h"
+#include "credresource.h"
+#include "doxmresource.h"
+#include "srmutility.h"
+#include "certhelpers.h"
+#include "csrresource.h"
+#include "resourcemanager.h"
+
+#define TAG "OIC_SRM_CSR"
+
+static OCResourceHandle gCsrHandle = NULL;
+
+/** Default cbor payload size. This value is increased in case of CborErrorOutOfMemory.
+ * The value of payload size is increased until reaching belox max cbor size.
+ */
+static const uint16_t CBOR_SIZE = 2048;
+
+static const char* EncodingValueToString(OicEncodingType_t encoding)
+{
+ switch (encoding)
+ {
+ case OIC_ENCODING_RAW: return OIC_SEC_ENCODING_RAW;
+ case OIC_ENCODING_BASE64: return OIC_SEC_ENCODING_BASE64;
+ case OIC_ENCODING_DER: return OIC_SEC_ENCODING_DER;
+ case OIC_ENCODING_PEM: return OIC_SEC_ENCODING_PEM;
+ default: return NULL;
+ }
+}
+
+
+static OCStackResult StoreKeyPair(mbedtls_pk_context *keyPair, const OicUuid_t *myUuid)
+{
+ int ret = 0;
+ OicSecCred_t *cred = NULL;
+ OicSecKey_t publicData;
+ OicSecKey_t privateData;
+ uint8_t publicBuf[1024];
+ uint8_t privateBuf[1024];
+
+ /* These DER writing APIs write at the END of the buffers, hence the pointer arithmetic. See the API
+ * documentation for mbedTLS.
+ */
+
+ ret = mbedtls_pk_write_pubkey_der(keyPair, publicBuf, sizeof(publicBuf));
+ VERIFY_SUCCESS(TAG, 0 <= ret, ERROR);
+ publicData.data = publicBuf + sizeof(publicBuf) - ret;
+ publicData.len = ret;
+ publicData.encoding = OIC_ENCODING_DER;
+
+ ret = mbedtls_pk_write_key_der(keyPair, privateBuf, sizeof(privateBuf));
+ VERIFY_SUCCESS(TAG, 0 <= ret, ERROR);
+ privateData.data = privateBuf + sizeof(privateBuf) - ret;
+ privateData.len = ret;
+ privateData.encoding = OIC_ENCODING_DER;
+
+ cred = GenerateCredential(myUuid, ASYMMETRIC_KEY, &publicData, &privateData, myUuid, NULL);
+ VERIFY_NOT_NULL(TAG, cred, ERROR);
+ cred->credUsage = OICStrdup(PRIMARY_KEY); // @todo: we may be able to use PRIMARY_CERT here too; need to investigate
+ VERIFY_NOT_NULL(TAG, cred->credUsage, ERROR);
+
+ VERIFY_SUCCESS(TAG, OC_STACK_OK == AddCredential(cred), ERROR);
+
+ return OC_STACK_OK;
+
+exit:
+
+ if (NULL != cred)
+ {
+ DeleteCredList(cred);
+ }
+
+ OICClearMemory(privateBuf, sizeof(privateBuf));
+
+ return OC_STACK_ERROR;
+}
+
+static OCStackResult CSRToCBORPayload(const uint8_t *csr, size_t csrLen, OicEncodingType_t encoding, uint8_t **cborPayload, size_t *cborSize)
+{
+ OCStackResult ret = OC_STACK_ERROR;
+
+ CborError cborEncoderResult = CborNoError;
+ uint8_t *outPayload = NULL;
+ size_t cborLen = *cborSize;
+ CborEncoder encoder;
+ CborEncoder csrRootMap;
+ const char *strEncoding = NULL;
+
+ if ((NULL == csr) || (0 == csrLen) || (NULL == cborPayload) || (NULL == cborSize))
+ {
+ return OC_STACK_INVALID_PARAM;
+ }
+
+ if ((OIC_ENCODING_DER != encoding) && (OIC_ENCODING_PEM != encoding))
+ {
+ return OC_STACK_INVALID_PARAM;
+ }
+
+ *cborSize = 0;
+ *cborPayload = NULL;
+
+ if (0 == cborLen)
+ {
+ cborLen = CBOR_SIZE;
+ }
+
+ outPayload = (uint8_t *)OICCalloc(1, cborLen);
++ VERIFY_NOT_NULL_RETURN(TAG, outPayload, ERROR, OC_STACK_NO_MEMORY);
+ cbor_encoder_init(&encoder, outPayload, cborLen, 0);
+
+ // Create CSR Root Map (csr)
+ cborEncoderResult = cbor_encoder_create_map(&encoder, &csrRootMap, 4);
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding CSR Root Map");
+
+ // Create CSR string entry
+ cborEncoderResult = cbor_encode_text_string(&csrRootMap, OIC_JSON_CSR_NAME, strlen(OIC_JSON_CSR_NAME));
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding CSR name.");
+ cborEncoderResult = cbor_encode_byte_string(&csrRootMap, csr, csrLen);
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding CSR value.");
+
+ // Create encoding entry
+ cborEncoderResult = cbor_encode_text_string(&csrRootMap, OIC_JSON_ENCODING_NAME, strlen(OIC_JSON_ENCODING_NAME));
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding encoding name.");
+ strEncoding = EncodingValueToString(encoding);
+ assert(strEncoding != NULL);
+ cborEncoderResult = cbor_encode_text_string(&csrRootMap, strEncoding, strlen(strEncoding));
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding encoding value.");
+
+ // Rownerid
+ {
+ char *rowner = NULL;
+ OicUuid_t myUuid;
+ cborEncoderResult = cbor_encode_text_string(&csrRootMap, OIC_JSON_ROWNERID_NAME,
+ strlen(OIC_JSON_ROWNERID_NAME));
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding rownerid Name.");
+ ret = GetDoxmDeviceID(&myUuid);
+ VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
+ ret = ConvertUuidToStr(&myUuid, &rowner);
+ VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
+ cborEncoderResult = cbor_encode_text_string(&csrRootMap, rowner, strlen(rowner));
+ OICFree(rowner);
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding rownerid Value.");
+ }
+
+ //RT -- Mandatory
+ CborEncoder rtArray;
+ cborEncoderResult = cbor_encode_text_string(&csrRootMap, OIC_JSON_RT_NAME,
+ strlen(OIC_JSON_RT_NAME));
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding RT Name Tag.");
+ cborEncoderResult = cbor_encoder_create_array(&csrRootMap, &rtArray, 1);
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding RT Value.");
+ for (size_t i = 0; i < 1; i++)
+ {
+ cborEncoderResult = cbor_encode_text_string(&rtArray, OIC_RSRC_TYPE_SEC_CSR,
+ strlen(OIC_RSRC_TYPE_SEC_CSR));
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding RT Value.");
+ }
+ cborEncoderResult = cbor_encoder_close_container(&csrRootMap, &rtArray);
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing RT.");
+
+ //IF-- Mandatory
+ CborEncoder ifArray;
+ cborEncoderResult = cbor_encode_text_string(&csrRootMap, OIC_JSON_IF_NAME,
+ strlen(OIC_JSON_IF_NAME));
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding IF Name Tag.");
+ cborEncoderResult = cbor_encoder_create_array(&csrRootMap, &ifArray, 1);
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding IF Value.");
+ for (size_t i = 0; i < 1; i++)
+ {
+ cborEncoderResult = cbor_encode_text_string(&ifArray, OC_RSRVD_INTERFACE_DEFAULT,
+ strlen(OC_RSRVD_INTERFACE_DEFAULT));
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding IF Value.");
+ }
+ cborEncoderResult = cbor_encoder_close_container(&csrRootMap, &ifArray);
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing IF.");
+
+ // Close CSR Map
+ cborEncoderResult = cbor_encoder_close_container(&encoder, &csrRootMap);
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing CSR root Map.");
+
+ if (CborNoError == cborEncoderResult)
+ {
+ OIC_LOG(DEBUG, TAG, "CSRToCBORPayload Succeeded");
+ *cborSize = cbor_encoder_get_buffer_size(&encoder, outPayload);
+ *cborPayload = outPayload;
+ ret = OC_STACK_OK;
+ }
+exit:
+ if (CborErrorOutOfMemory == cborEncoderResult)
+ {
+ OIC_LOG(DEBUG, TAG, "CSRToCBORPayload:CborErrorOutOfMemory : retry with more memory");
+
+ // reallocate and try again!
+ OICFree(outPayload);
+ // Since the allocated initial memory failed, double the memory.
+ cborLen += cbor_encoder_get_buffer_size(&encoder, encoder.end);
+ cborEncoderResult = CborNoError;
+ ret = CSRToCBORPayload(csr, csrLen, encoding, cborPayload, &cborLen);
+ *cborSize = cborLen;
+ }
+ else if (cborEncoderResult != CborNoError)
+ {
+ OIC_LOG(ERROR, TAG, "Failed to CSRToCBORPayload");
+ OICFree(outPayload);
+ outPayload = NULL;
+ *cborSize = 0;
+ *cborPayload = NULL;
+ ret = OC_STACK_ERROR;
+ }
+
+ return ret;
+}
+
+OCStackResult CBORPayloadToCSR(const uint8_t *cborPayload, size_t size, uint8_t **csr, size_t *csrLen, OicEncodingType_t *encoding)
+{
+ if (NULL == cborPayload || 0 == size || NULL == csr || NULL == csrLen)
+ {
+ return OC_STACK_INVALID_PARAM;
+ }
+
+ OCStackResult ret = OC_STACK_ERROR;
+ CborValue csrCbor = { .parser = NULL };
+ CborParser parser = { .end = NULL };
+ CborError cborFindResult = CborNoError;
+ uint8_t* cborCsr = NULL;
+ size_t cborCsrLen = 0;
+ char* tagName = NULL;
+ size_t len = 0;
+
+ cborFindResult = cbor_parser_init(cborPayload, size, 0, &parser, &csrCbor);
+ VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed to initialize parser.");
+
+ if (!cbor_value_is_container(&csrCbor))
+ {
+ return OC_STACK_ERROR;
+ }
+
+ // Enter CSR Root Map
+ CborValue csrRootMap = { .parser = NULL, .ptr = NULL, .remaining = 0, .extra = 0, .type = 0, .flags = 0 };
+ cborFindResult = cbor_value_enter_container(&csrCbor, &csrRootMap);
+ VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Entering CSR Root Map.");
+
+ while (cbor_value_is_valid(&csrRootMap))
+ {
+ if (NULL != tagName)
+ {
+ free(tagName);
+ tagName = NULL;
+ }
+ len = 0;
+ CborType type = cbor_value_get_type(&csrRootMap);
+ if (type == CborTextStringType && cbor_value_is_text_string(&csrRootMap))
+ {
+ cborFindResult = cbor_value_dup_text_string(&csrRootMap, &tagName, &len, NULL);
+ VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed finding name in CSR Root Map.");
+ cborFindResult = cbor_value_advance(&csrRootMap);
+ VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed advancing value in CSR Root Map.");
+ }
+ if (NULL != tagName)
+ {
+ if (strcmp(tagName, OIC_JSON_CSR_NAME) == 0 && cbor_value_is_byte_string(&csrRootMap))
+ {
+ cborFindResult = cbor_value_dup_byte_string(&csrRootMap, &cborCsr, &cborCsrLen, NULL);
+ VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed finding name in CSR Map");
+ // Use our own heap allocator and copy the result in so callers can use OICFree.
+ *csr = (uint8_t *)OICCalloc(1, cborCsrLen);
+ VERIFY_NOT_NULL(TAG, *csr, ERROR);
+ memcpy(*csr, cborCsr, cborCsrLen);
+ free(cborCsr);
+ cborCsr = NULL;
+ *csrLen = cborCsrLen;
+ cborCsrLen = 0;
+ }
+ else if (strcmp(tagName, OIC_JSON_ENCODING_NAME) == 0 && cbor_value_is_text_string(&csrRootMap))
+ {
+ char *strEncoding = NULL;
+ cborFindResult = cbor_value_dup_text_string(&csrRootMap, &strEncoding, &len, NULL);
+ VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed finding encoding type");
+
+ if (strcmp(strEncoding, OIC_SEC_ENCODING_DER) == 0)
+ {
+ *encoding = OIC_ENCODING_DER;
+ }
+ else if (strcmp(strEncoding, OIC_SEC_ENCODING_PEM) == 0)
+ {
+ *encoding = OIC_ENCODING_PEM;
+ }
+ else
+ {
+ OIC_LOG_V(ERROR, TAG, "Invalid encoding type %s", strEncoding);
+ ret = OC_STACK_ERROR;
+ free(strEncoding);
+ goto exit;
+ }
+
+ free(strEncoding);
+ }
+ else
+ {
+ // Ignore any other tag type for now.
+ OIC_LOG_V(WARNING, TAG, "Unknown tag %s", tagName);
+ }
+
+ }
+ if (cbor_value_is_valid(&csrRootMap))
+ {
+ cborFindResult = cbor_value_advance(&csrRootMap);
+ VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed advancing CSR Root Map");
+ }
+ }
+
+ ret = OC_STACK_OK;
+
+exit:
+ if (CborNoError != cborFindResult)
+ {
+ if (NULL != *csr)
+ {
+ OICFreeAndSetToNull((void **)csr);
+ }
+
+ *csrLen = 0;
+
+ ret = OC_STACK_ERROR;
+ }
+
+ // tagName and cborCsr are both allocated internally by tinycbor, which uses malloc, not OICMalloc.
+ // Therefore, they must be freed with free, not OICFree.
+ if (NULL != tagName)
+ {
+ free(tagName);
+ }
+ if (NULL != cborCsr)
+ {
+ free(cborCsr);
+ }
+
+ return ret;
+
+}
+
+static OCEntityHandlerResult HandleCsrGetRequest(OCEntityHandlerRequest * ehRequest)
+{
+ OCStackResult res = OC_STACK_OK;
+ OCEntityHandlerResult ehRet = OC_EH_OK;
+ int ret = 0;
+ mbedtls_pk_context keyPair;
+ OicUuid_t myUuid;
+ char *myUuidStr = NULL;
+ char *myDNStr = NULL;
+ size_t myDNStrLen = 0;
+ ByteArray_t keyData = { .data = NULL, .len = 0 };
+ OCByteString csr = { .bytes = NULL, .len = 0 };
+ size_t size = 0;
+ uint8_t *payload = NULL;
+
+ OIC_LOG(INFO, TAG, "HandleCsrGetRequest processing GET request");
+
+ mbedtls_pk_init(&keyPair);
+
+ // Retrieve our current certificate, if we have one, and use that key
+ GetDerKey(&keyData, PRIMARY_CERT);
+
+ if (0 == keyData.len)
+ {
+ // No cert? Get our primary key pair, or generate it if absent.
+ GetDerKey(&keyData, PRIMARY_KEY);
+ }
+
+ res = GetDoxmDeviceID(&myUuid);
+ VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);
+ res = ConvertUuidToStr(&myUuid, &myUuidStr);
+ VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);
+
+ if (0 < keyData.len)
+ {
+ ret = mbedtls_pk_parse_key(&keyPair, keyData.data, keyData.len, NULL, 0);
+ if (0 > ret)
+ {
+ res = OC_STACK_ERROR;
+ // Because we need to set res before failing out, this is a redundant check of ret, but gives better logging.
+ VERIFY_SUCCESS(TAG, 0 <= ret, ERROR);
+ }
+ }
+ else
+ {
+ ret = OCInternalGenerateKeyPair(&keyPair);
+ if (0 > ret)
+ {
+ res = OC_STACK_ERROR;
+ VERIFY_SUCCESS(TAG, 0 <= ret, ERROR);
+ }
+ VERIFY_SUCCESS(TAG, OC_STACK_OK == (res = StoreKeyPair(&keyPair, &myUuid)), ERROR);
+ }
+
+ // Generate CSR
+ myDNStrLen = strlen(myUuidStr) + sizeof(SUBJECT_PREFIX); // sizeof(SUBJECT_PREFIX) will also count the byte for terminating null.
+ myDNStr = (char *)OICMalloc(myDNStrLen);
+ VERIFY_NOT_NULL(TAG, myDNStr, ERROR);
+ ret = snprintf(myDNStr, myDNStrLen, SUBJECT_PREFIX "%s", myUuidStr);
+ VERIFY_SUCCESS(TAG, 0 <= ret, ERROR);
+ /* ret >= myDNStrLen means there was truncation; assert because this means a code bug. */
+ assert((size_t)ret < myDNStrLen);
+ ret = OCInternalCSRRequest(myDNStr, &keyPair, OIC_ENCODING_DER, &csr);
+ if (0 > ret)
+ {
+ res = OC_STACK_ERROR;
+ VERIFY_SUCCESS(TAG, 0 <= ret, ERROR);
+ }
+
+ // Convert CSR data into CBOR for transmission
+ res = CSRToCBORPayload(csr.bytes, csr.len, OIC_ENCODING_DER, &payload, &size);
+
+exit:
+
+ ehRet = (OC_STACK_OK == res) ? OC_EH_OK : OC_EH_ERROR;
+
+ //Send payload to request originator
+ ehRet = ((SendSRMResponse(ehRequest, ehRet, payload, size)) == OC_STACK_OK) ?
+ OC_EH_OK : OC_EH_ERROR;
+
+ mbedtls_pk_free(&keyPair);
+ OICFree(myDNStr);
+ OICFree(myUuidStr);
+ OICFree(keyData.data);
+ OICFree(csr.bytes);
+ OICFree(payload);
+ return ehRet;
+}
+
+static OCEntityHandlerResult CredCsrEntityHandler(OCEntityHandlerFlag flag,
+ OCEntityHandlerRequest * ehRequest,
+ void* callbackParameter)
+{
+ OC_UNUSED(callbackParameter);
+ OCEntityHandlerResult ret = OC_EH_ERROR;
+
+ if (!ehRequest)
+ {
+ return OC_EH_ERROR;
+ }
+
+ if (flag & OC_REQUEST_FLAG)
+ {
+ OIC_LOG(DEBUG, TAG, "Flag includes OC_REQUEST_FLAG");
+ if (ehRequest->method == OC_REST_GET)
+ {
+ ret = HandleCsrGetRequest(ehRequest);
+ }
+ else
+ {
+ /* Only GET supported on CSR resource. */
+ ret = OC_EH_ERROR;
+ }
+ }
+
+ return ret;
+}
+
+OCStackResult InitCSRResource()
+{
+ OCStackResult ret = OCCreateResource(&gCsrHandle,
+ OIC_RSRC_TYPE_SEC_CSR,
+ OC_RSRVD_INTERFACE_DEFAULT,
+ OIC_RSRC_CSR_URI,
+ CredCsrEntityHandler,
+ NULL,
+ OC_SECURE);
+
+ if (OC_STACK_OK != ret)
+ {
+ OIC_LOG(FATAL, TAG, "Unable to instantiate CSR resource");
+ }
+
+ return ret;
+}
+
+OCStackResult DeInitCSRResource()
+{
+ OCStackResult res = OCDeleteResource(gCsrHandle);
+
+ if (OC_STACK_OK != res)
+ {
+ OIC_LOG_V(ERROR, TAG, "Failed to delete CSR resource: %d", res);
+ }
+
+ gCsrHandle = NULL;
+
+ return res;
+}
--- /dev/null
- *publicKeyLen = strlen(buf) + 1;
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft. All Rights Reserved.
+ *
+ *
+ *
+ * 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.
+ *
+ * *****************************************************************/
+
+#if defined(__WITH_TLS__) || defined(__WITH_DTLS__)
+
+#include "iotivity_config.h"
+
+#include "logger.h"
+#include <stddef.h>
+#include <string.h>
+#include <assert.h>
+#include "oic_malloc.h"
+#include "oic_string.h"
+#include "cacommon.h"
+#include "ocrandom.h"
+#include "cacommonutil.h"
+
+#include "ocpayload.h"
+#include "payload_logging.h"
+#include "pmutility.h"
+#include "srmutility.h"
+
+// headers required for mbed TLS
+#include "mbedtls/config.h"
+#include "mbedtls/platform.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/x509_csr.h"
+#include "mbedtls/x509_crt.h"
+#include "mbedtls/oid.h"
+
+#ifndef NDEBUG
+#include "mbedtls/debug.h"
+#include "mbedtls/version.h"
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+
++#include "certhelpers.h"
+#include "occertutility.h"
+
+#define TAG "OIC_OCCERTUTILITY"
+
+/**
+ * @def PERSONALIZATION_STRING
+ * @brief Personalization string for the mbedtls RNG
+ */
+#define PERSONALIZATION_STRING "IOTIVITY_RND"
+
+#define MAX_URI_QUERY MAX_URI_LENGTH + MAX_QUERY_LENGTH
+
+#define MAX_STRING_LEN 254
+
+/* ASN.1 DER encoding of the EKU for identity certificates (1.3.6.1.4.1.44924.1.6) */
+static const unsigned char s_ekuIdentity[] = { 0x30, 0x0C, 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0xDE, 0x7C, 0x01, 0x06 };
+
+/* ASN.1 DER encoding of the EKU for role certificates (1.3.6.1.4.1.44924.1.7) */
+static const unsigned char s_ekuRole[] = { 0x30, 0x0C, 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0xDE, 0x7C, 0x01, 0x07 };
+
+/* ASN.1 DER encoding of the EKU for both identity and roles (for use by CAs) */
+static const unsigned char s_ekuCA[] = { 0x30, 0x18, 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0xDE, 0x7C, 0x01, 0x06, 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0xDE, 0x7C, 0x01, 0x07 };
+
+/**
+ * Generates elliptic curve keypair.
+ *
+ * @param[out] pk mbedtls public key container
+ *
+ * @return 0 on success or <0 on error
+ */
+static int GenerateEccKeyPair(mbedtls_pk_context *pk)
+{
+ int ret = 0;
+ mbedtls_entropy_context entropy;
+ mbedtls_ctr_drbg_context ctr_drbg;
+
+ OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
+ VERIFY_NON_NULL_RET(pk, TAG, "Param pk is NULL", -1);
+
+ // Initialize the DRBG context
+ mbedtls_ctr_drbg_init(&ctr_drbg);
+ mbedtls_entropy_init(&entropy);
+ ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
+ &entropy, (const unsigned char *)PERSONALIZATION_STRING, sizeof(PERSONALIZATION_STRING));
+
+ if (0 > ret)
+ {
+ OIC_LOG_V(ERROR, TAG, "Seed initialization failed! %d", ret);
+ OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+ goto exit;
+ }
+ mbedtls_ctr_drbg_set_prediction_resistance(&ctr_drbg, MBEDTLS_CTR_DRBG_PR_ON);
+ ret = mbedtls_pk_setup(pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY));
+ if (0 > ret)
+ {
+ OIC_LOG_V(ERROR, TAG, "mbedtls_pk_setup error %d", ret);
+ OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+ goto exit;
+ }
+ ret = mbedtls_ecp_gen_key(MBEDTLS_ECP_DP_SECP256R1, mbedtls_pk_ec(*pk), mbedtls_ctr_drbg_random, &ctr_drbg);
+ if (0 > ret)
+ {
+ OIC_LOG(ERROR, TAG, "mbedtls_ecp_gen_keypair error");
+ OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+ goto exit;
+ }
+
+exit:
+
+ mbedtls_ctr_drbg_free(&ctr_drbg);
+ mbedtls_entropy_free(&entropy);
+
+ OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+ return 0;
+}
+
+OCStackResult OCGenerateRandomSerialNumber(char **serial, size_t *serialLen)
+{
+ int ret = 0;
+ OCStackResult res = OC_STACK_ERROR;
+ unsigned char random[20]; /* Per RFC 5280, 20 octets is the maximum length of a serial number. */
+ mbedtls_mpi serialMpi;
+
+ VERIFY_NOT_NULL_RETURN(TAG, serial, ERROR, OC_STACK_INVALID_PARAM);
+ VERIFY_NOT_NULL_RETURN(TAG, serialLen, ERROR, OC_STACK_INVALID_PARAM);
+
+ mbedtls_mpi_init(&serialMpi);
+ memset(serial, 0, sizeof(*serial));
+
+ VERIFY_SUCCESS(TAG, OCGetRandomBytes(random, sizeof(random)), ERROR);
+
+ /* Per RFC 5280, 20 octets is the maximum length of a serial number. In ASN.1, if the highest-order
+ * bit is set it causes a padding octet to be written, which would be 21 and non-compliant.
+ * Therefore, always clear the highest-order bit. Integers in ASN.1 are always big-Endian.
+ */
+ random[0] &= 0x7F;
+
+ /* Import into a large integer object and then output as a string. */
+ ret = mbedtls_mpi_read_binary(&serialMpi, random, sizeof(random));
+ VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+
+ /* Get the needed string length and allocate. */
+ ret = mbedtls_mpi_write_string(&serialMpi, 10, NULL, 0, serialLen);
+ VERIFY_SUCCESS(TAG, ret == MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL, ERROR);
+ *serial = OICCalloc(1, *serialLen);
+ VERIFY_NOT_NULL(TAG, *serial, ERROR);
+
+ /* Do the write for real. */
+ ret = mbedtls_mpi_write_string(&serialMpi, 10, *serial, *serialLen, serialLen);
+ VERIFY_SUCCESS(TAG, ret == 0, ERROR);
+
+ res = OC_STACK_OK;
+
+exit:
+
+ if (OC_STACK_OK != res)
+ {
+ OICFree(*serial);
+ *serial = NULL;
+ *serialLen = 0;
+ }
+ mbedtls_mpi_free(&serialMpi);
+
+ return res;
+}
+
+OCStackResult OCGenerateKeyPair(char **publicKey, size_t *publicKeyLen,
+ char **privateKey, size_t *privateKeyLen)
+{
+ int ret = 0;
+ mbedtls_pk_context keyPair;
+ unsigned char buf[2048];
+
+ mbedtls_pk_init(&keyPair);
+
+ VERIFY_NOT_NULL_RETURN(TAG, publicKey, ERROR, OC_STACK_INVALID_PARAM);
+ VERIFY_NOT_NULL_RETURN(TAG, publicKeyLen, ERROR, OC_STACK_INVALID_PARAM);
+ VERIFY_NOT_NULL_RETURN(TAG, privateKey, ERROR, OC_STACK_INVALID_PARAM);
+ VERIFY_NOT_NULL_RETURN(TAG, privateKeyLen, ERROR, OC_STACK_INVALID_PARAM);
+
+ *publicKey = NULL;
+ *publicKeyLen = 0;
+ *privateKey = NULL;
+ *privateKeyLen = 0;
+
+ ret = OCInternalGenerateKeyPair(&keyPair);
+ if (ret != 0)
+ {
+ OIC_LOG_V(ERROR, TAG, "Failed to generate key pair: %d", ret);
+ goto exit;
+ }
+
+ ret = mbedtls_pk_write_pubkey_pem(&keyPair, buf, sizeof(buf));
+ if (ret != 0)
+ {
+ OIC_LOG_V(ERROR, TAG, "Failed to export public key as PEM: %d", ret);
+ goto exit;
+ }
+
- *privateKeyLen = strlen(buf) + 1;
++ *publicKeyLen = strlen((char *)buf) + 1;
+ *publicKey = OICCalloc(1, *publicKeyLen);
+ if (NULL == *publicKey)
+ {
+ OIC_LOG(ERROR, TAG, "Could not allocate memory for public key");
+ ret = -1;
+ goto exit;
+ }
+ memcpy(*publicKey, buf, *publicKeyLen);
+
+ ret = mbedtls_pk_write_key_pem(&keyPair, buf, sizeof(buf));
+ if (ret != 0)
+ {
+ OIC_LOG_V(ERROR, TAG, "Failed to export private key as PEM: %d", ret);
+ goto exit;
+ }
+
- ret = mbedtls_pk_parse_public_key(&subjKeyCtx, subjectPublicKey, strlen(subjectPublicKey) + 1);
++ *privateKeyLen = strlen((char *)buf) + 1;
+ *privateKey = OICCalloc(1, *privateKeyLen);
+ if (NULL == *privateKey)
+ {
+ OIC_LOG(ERROR, TAG, "Could not allocate memory for private key");
+ ret = -1;
+ goto exit;
+ }
+ memcpy(*privateKey, buf, *privateKeyLen);
+
+exit:
+
+ mbedtls_pk_free(&keyPair);
+
+ OICClearMemory(buf, sizeof(buf));
+
+ if (ret != 0)
+ {
+ OICFree(*publicKey);
+ OICClearMemory(*privateKey, *privateKeyLen);
+ OICFree(*privateKey);
+
+ *publicKey = NULL;
+ *publicKeyLen = 0;
+ *privateKey = NULL;
+ *privateKeyLen = 0;
+
+ return OC_STACK_ERROR;
+ }
+ else
+ {
+ return OC_STACK_OK;
+ }
+}
+
+typedef enum {
+ CERT_TYPE_CA,
+ CERT_TYPE_IDENTITY,
+ CERT_TYPE_ROLE
+} CertificateType_t;
+
+static OCStackResult GenerateCertificate(
+ CertificateType_t certType,
+ const char *subject,
+ const char *subjectPublicKey,
+ const char *issuerCert,
+ const char *issuerPrivateKey,
+ const char *serial,
+ const char *notValidBefore,
+ const char *notValidAfter,
+ const char *role,
+ const char *authority,
+ OCByteString *certificate)
+{
+ OCStackResult res = OC_STACK_INVALID_PARAM;
+ int ret = 0;
+ mbedtls_x509write_cert outCertCtx;
+ mbedtls_pk_context subjKeyCtx;
+ mbedtls_pk_context issKeyCtx;
+ mbedtls_x509_crt issCertCtx;
+ mbedtls_mpi serialMpi;
+ mbedtls_x509_general_names names;
+ mbedtls_entropy_context entropy;
+ mbedtls_ctr_drbg_context ctr_drbg;
+
+ char buf[2048];
+
+ if (NULL == subjectPublicKey || NULL == issuerPrivateKey || NULL == subject || NULL == serial ||
+ NULL == notValidBefore || NULL == notValidAfter)
+ {
+ return OC_STACK_INVALID_PARAM;
+ }
+
+ mbedtls_x509write_crt_init(&outCertCtx);
+ mbedtls_pk_init(&subjKeyCtx);
+ mbedtls_pk_init(&issKeyCtx);
+ mbedtls_x509_crt_init(&issCertCtx);
+ mbedtls_mpi_init(&serialMpi);
+ memset(&names, 0, sizeof(names));
+ mbedtls_ctr_drbg_init(&ctr_drbg);
+ mbedtls_entropy_init(&entropy);
+ memset(certificate, 0, sizeof(*certificate));
+
+ ret = mbedtls_mpi_read_string(&serialMpi, 10, serial);
+ VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+
- ret = mbedtls_pk_parse_key(&issKeyCtx, issuerPrivateKey, strlen(issuerPrivateKey) + 1, NULL, 0);
++ ret = mbedtls_pk_parse_public_key(&subjKeyCtx, (const uint8_t *)subjectPublicKey, strlen(subjectPublicKey) + 1);
+ VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+
- ret = mbedtls_x509_crt_parse(&issCertCtx, issuerCert, strlen(issuerCert) + 1);
++ ret = mbedtls_pk_parse_key(&issKeyCtx, (const uint8_t *)issuerPrivateKey, strlen(issuerPrivateKey) + 1, NULL, 0);
+ VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+
+ /* If issuerCert is NULL, then the cert will be self-signed. */
+ if (NULL != issuerCert)
+ {
- &entropy, PERSONALIZATION_STRING, sizeof(PERSONALIZATION_STRING));
++ ret = mbedtls_x509_crt_parse(&issCertCtx, (const uint8_t *)issuerCert, strlen(issuerCert) + 1);
+ VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+ }
+
+ ret = mbedtls_x509write_crt_set_validity(&outCertCtx, notValidBefore, notValidAfter);
+ VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+
+ mbedtls_x509write_crt_set_version(&outCertCtx, MBEDTLS_X509_CRT_VERSION_3);
+ mbedtls_x509write_crt_set_md_alg(&outCertCtx, MBEDTLS_MD_SHA256);
+
+ res = OC_STACK_ERROR;
+
+ ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
- ret = mbedtls_x509write_crt_pem(&outCertCtx, buf, sizeof(buf), mbedtls_ctr_drbg_random, &ctr_drbg);
++ &entropy, (const uint8_t *)PERSONALIZATION_STRING, sizeof(PERSONALIZATION_STRING));
+ VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+ mbedtls_ctr_drbg_set_prediction_resistance(&ctr_drbg, MBEDTLS_CTR_DRBG_PR_ON);
+
+ ret = mbedtls_x509write_crt_set_serial(&outCertCtx, &serialMpi);
+ VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+
+ ret = mbedtls_x509write_crt_set_subject_name(&outCertCtx, subject);
+ VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+
+ if (NULL != issuerCert)
+ {
+ // mbedtls_x509_dn_gets returns the number of bytes written to buf.
+ ret = mbedtls_x509_dn_gets(buf, sizeof(buf), &issCertCtx.subject);
+ VERIFY_SUCCESS(TAG, 0 < ret, ERROR);
+ ret = mbedtls_x509write_crt_set_issuer_name(&outCertCtx, buf);
+ }
+ else
+ {
+ /* If self-signed, use the same contents of subject for the issuer name. */
+ ret = mbedtls_x509write_crt_set_issuer_name(&outCertCtx, subject);
+ }
+ VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+
+ mbedtls_x509write_crt_set_subject_key(&outCertCtx, &subjKeyCtx);
+
+ mbedtls_x509write_crt_set_issuer_key(&outCertCtx, &issKeyCtx);
+
+ if (certType == CERT_TYPE_CA)
+ {
+ ret = mbedtls_x509write_crt_set_basic_constraints(&outCertCtx, 1, -1);
+ VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+ ret = mbedtls_x509write_crt_set_key_usage(&outCertCtx,
+ MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_KEY_CERT_SIGN);
+ VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+ }
+ else
+ {
+ ret = mbedtls_x509write_crt_set_basic_constraints(&outCertCtx, 0, 0);
+ VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+ ret = mbedtls_x509write_crt_set_key_usage(&outCertCtx,
+ MBEDTLS_X509_KU_DIGITAL_SIGNATURE |
+ MBEDTLS_X509_KU_KEY_ENCIPHERMENT |
+ MBEDTLS_X509_KU_DATA_ENCIPHERMENT |
+ MBEDTLS_X509_KU_KEY_AGREEMENT);
+ VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+ }
+
+ switch (certType)
+ {
+ case CERT_TYPE_ROLE:
+ ret = mbedtls_x509write_crt_set_extension(&outCertCtx,
+ MBEDTLS_OID_EXTENDED_KEY_USAGE, MBEDTLS_OID_SIZE(MBEDTLS_OID_EXTENDED_KEY_USAGE),
+ 0,
+ s_ekuRole, sizeof(s_ekuRole));
+ VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+ ret = snprintf(buf, sizeof(buf), "CN=%s%s%s", role, (NULL != authority) ? ",OU=" : "", (NULL != authority) ? authority : "");
+ VERIFY_SUCCESS(TAG, ret < sizeof(buf), ERROR);
+ names.next = NULL;
+ names.general_name.name_type = MBEDTLS_X509_GENERALNAME_DIRECTORYNAME;
+ ret = mbedtls_x509_string_to_names(&names.general_name.directory_name, buf);
+ VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+
+ ret = mbedtls_x509write_crt_set_subject_alt_names(&outCertCtx, &names);
+ VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+ break;
+
+ case CERT_TYPE_IDENTITY:
+ ret = mbedtls_x509write_crt_set_extension(&outCertCtx,
+ MBEDTLS_OID_EXTENDED_KEY_USAGE, MBEDTLS_OID_SIZE(MBEDTLS_OID_EXTENDED_KEY_USAGE),
+ 0,
+ s_ekuIdentity, sizeof(s_ekuIdentity));
+ VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+ break;
+
+ case CERT_TYPE_CA:
+ ret = mbedtls_x509write_crt_set_extension(&outCertCtx,
+ MBEDTLS_OID_EXTENDED_KEY_USAGE, MBEDTLS_OID_SIZE(MBEDTLS_OID_EXTENDED_KEY_USAGE),
+ 0,
+ s_ekuCA, sizeof(s_ekuCA));
+ VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+ break;
+
+ default:
+ assert(false);
+ VERIFY_SUCCESS(TAG, false, ERROR);
+ }
+
- *certificate = byteStr.bytes;
++ ret = mbedtls_x509write_crt_pem(&outCertCtx, (uint8_t *)buf, sizeof(buf), mbedtls_ctr_drbg_random, &ctr_drbg);
+ VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+
+ certificate->len = strlen(buf) + 1;
+ certificate->bytes = (uint8_t *)OICCalloc(1, certificate->len);
+ VERIFY_NOT_NULL(TAG, certificate->bytes, ERROR);
+ memcpy(certificate->bytes, buf, certificate->len);
+
+ res = OC_STACK_OK;
+
+exit:
+
+ if (OC_STACK_OK != res)
+ {
+ OICFree(certificate->bytes);
+ certificate->bytes = NULL;
+ certificate->len = 0;
+ }
+
+ mbedtls_ctr_drbg_free(&ctr_drbg);
+ mbedtls_entropy_free(&entropy);
+ mbedtls_asn1_free_named_data_list(&names.general_name.directory_name);
+ mbedtls_mpi_free(&serialMpi);
+ mbedtls_x509_crt_free(&issCertCtx);
+ mbedtls_pk_free(&issKeyCtx);
+ mbedtls_pk_free(&subjKeyCtx);
+ mbedtls_x509write_crt_free(&outCertCtx);
+
+ return res;
+}
+
+OCStackResult OCGenerateCACertificate(
+ const char *subject,
+ const char *subjectPublicKey,
+ const char *issuerCert,
+ const char *issuerPrivateKey,
+ const char *serial,
+ const char *notValidBefore,
+ const char *notValidAfter,
+ char **certificate,
+ size_t *certificateLen)
+{
+ OCStackResult res = OC_STACK_OK;
+ OCByteString byteStr = { 0 };
+
+ res = GenerateCertificate(
+ CERT_TYPE_CA,
+ subject,
+ subjectPublicKey,
+ issuerCert,
+ issuerPrivateKey,
+ serial,
+ notValidBefore,
+ notValidAfter,
+ NULL,
+ NULL,
+ &byteStr);
+
+ if (OC_STACK_OK == res)
+ {
- *certificate = byteStr.bytes;
++ *certificate = (char *)byteStr.bytes;
+ *certificateLen = byteStr.len;
+ }
+
+ return res;
+}
+
+OCStackResult OCGenerateIdentityCertificate(
+ const OicUuid_t *subjectUuid,
+ const char *subjectPublicKey,
+ const char *issuerCert,
+ const char *issuerPrivateKey,
+ const char *serial,
+ const char *notValidBefore,
+ const char *notValidAfter,
+ char **certificate,
+ size_t *certificateLen)
+{
+ OCStackResult res = OC_STACK_OK;
+ OCByteString byteStr = { 0 };
+ char uuidStr[UUID_STRING_SIZE] = { 0 } ;
+ char subject[sizeof(uuidStr) + sizeof(SUBJECT_PREFIX)] = { 0 } ;
+
+ if (NULL == issuerCert)
+ {
+ return OC_STACK_INVALID_PARAM;
+ }
+
+ if (!OCConvertUuidToString(subjectUuid->id, uuidStr))
+ {
+ OIC_LOG(ERROR, TAG, "Could not convert UUID");
+ return OC_STACK_INVALID_PARAM;
+ }
+
+ if (snprintf(subject, sizeof(subject), "%s%s", SUBJECT_PREFIX, uuidStr) == sizeof(subject))
+ {
+ OIC_LOG(ERROR, TAG, "Could not write subject string");
+ return OC_STACK_INVALID_PARAM;
+ }
+
+ res = GenerateCertificate(
+ CERT_TYPE_IDENTITY,
+ subject,
+ subjectPublicKey,
+ issuerCert,
+ issuerPrivateKey,
+ serial,
+ notValidBefore,
+ notValidAfter,
+ NULL,
+ NULL,
+ &byteStr);
+
+ if (OC_STACK_OK == res)
+ {
- *certificate = byteStr.bytes;
++ *certificate = (char *)byteStr.bytes;
+ *certificateLen = byteStr.len;
+ }
+
+ return res;
+}
+
+OCStackResult OCGenerateRoleCertificate(
+ const OicUuid_t *subjectUuid,
+ const char *subjectPublicKey,
+ const char *issuerCert,
+ const char *issuerPrivateKey,
+ const char *serial,
+ const char *notValidBefore,
+ const char *notValidAfter,
+ const char *role,
+ const char *authority,
+ char **certificate,
+ size_t *certificateLen)
+{
+ OCStackResult res = OC_STACK_ERROR;
+ OCByteString byteStr;
+ char uuidStr[UUID_STRING_SIZE] = { 0 };
+ char subject[sizeof(uuidStr) + sizeof(SUBJECT_PREFIX)] = { 0 };
+
+ memset(&byteStr, 0, sizeof(byteStr));
+
+ if (NULL == role || NULL == issuerCert)
+ {
+ return OC_STACK_INVALID_PARAM;
+ }
+
+ if (!OCConvertUuidToString(subjectUuid->id, uuidStr))
+ {
+ OIC_LOG(ERROR, TAG, "Could not convert UUID");
+ return OC_STACK_INVALID_PARAM;
+ }
+
+ if (snprintf(subject, sizeof(subject), "%s%s", SUBJECT_PREFIX, uuidStr) == sizeof(subject))
+ {
+ OIC_LOG(ERROR, TAG, "Could not write subject string");
+ return OC_STACK_INVALID_PARAM;
+ }
+
+ res = GenerateCertificate(
+ CERT_TYPE_ROLE,
+ subject,
+ subjectPublicKey,
+ issuerCert,
+ issuerPrivateKey,
+ serial,
+ notValidBefore,
+ notValidAfter,
+ role,
+ authority,
+ &byteStr);
+
+ if (OC_STACK_OK == res)
+ {
++ *certificate = (char *)byteStr.bytes;
+ *certificateLen = byteStr.len;
+ }
+
+ return res;
+}
+
+#endif /* defined(__WITH_TLS__) || defined(__WITH_DTLS__) */