From: Kevin Kane Date: Fri, 3 Mar 2017 20:59:10 +0000 (-0800) Subject: Merge branch 'master' into iot-1785 X-Git-Tag: 1.3.0~375^2^2~16 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=9215fe671a4147b71ac353e2724fd1fb45c419f6;p=platform%2Fupstream%2Fiotivity.git Merge branch 'master' into iot-1785 Build breaks fixed. occertutility.{c,h} moved back into security subtree. Change-Id: I348dbe5d2133b57a49d4cdef05ce6e747af5eea0 Signed-off-by: Kevin Kane --- 9215fe671a4147b71ac353e2724fd1fb45c419f6 diff --cc resource/csdk/connectivity/src/adapter_util/ca_adapter_net_ssl.c index 5d84865,b92b210..53b370a mode 100644,100755..100755 --- a/resource/csdk/connectivity/src/adapter_util/ca_adapter_net_ssl.c +++ b/resource/csdk/connectivity/src/adapter_util/ca_adapter_net_ssl.c diff --cc resource/csdk/security/SConscript index 24686f6,70cc82e..a36d745 --- a/resource/csdk/security/SConscript +++ b/resource/csdk/security/SConscript @@@ -123,7 -129,6 +129,7 @@@ if libocsrm_env.get('SECURED') == '1' 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'] diff --cc resource/csdk/security/include/occertutility.h index 43c5bf8,0000000..43c5bf8 mode 100644,000000..100644 --- a/resource/csdk/security/include/occertutility.h +++ b/resource/csdk/security/include/occertutility.h diff --cc resource/csdk/security/provisioning/sample/certgenerator.cpp index 7b3aa26,0000000..6db0b4f mode 100644,000000..100644 --- a/resource/csdk/security/provisioning/sample/certgenerator.cpp +++ b/resource/csdk/security/provisioning/sample/certgenerator.cpp @@@ -1,537 -1,0 +1,535 @@@ +//****************************************************************** +// +// 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 +#include +#include +#include +#include + +#include "ocstack.h" +#include "oic_malloc.h" +#include "ocrandom.h" +#include "occertutility.h" + +#ifdef HAVE_WINDOWS_H +#include +/** @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 publicKey; + std::vector privateKey; + std::vector 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; + } + } - - return 0; +} diff --cc resource/csdk/security/src/credresource.c index 4ac1ea7,f6301c9..1578551 mode 100644,100755..100755 --- a/resource/csdk/security/src/credresource.c +++ b/resource/csdk/security/src/credresource.c @@@ -945,8 -978,14 +981,6 @@@ OCStackResult CBORPayloadToCred(const u { 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 diff --cc resource/csdk/security/src/csrresource.c index 2a39e68,0000000..b1105b9 mode 100644,000000..100644 --- a/resource/csdk/security/src/csrresource.c +++ b/resource/csdk/security/src/csrresource.c @@@ -1,528 -1,0 +1,528 @@@ +//****************************************************************** +// +// 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 +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_STRINGS_H +#include +#endif +#include +#include +#include +#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(TAG, outPayload, ERROR); ++ 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; +} diff --cc resource/csdk/security/src/occertutility.c index 2ee9de4,0000000..4ced39a mode 100644,000000..100644 --- a/resource/csdk/security/src/occertutility.c +++ b/resource/csdk/security/src/occertutility.c @@@ -1,612 -1,0 +1,613 @@@ +/* ***************************************************************** + * + * 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 +#include +#include +#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 +#endif +#include + ++#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; + } + - *publicKeyLen = 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; + } + - *privateKeyLen = strlen(buf) + 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_public_key(&subjKeyCtx, subjectPublicKey, strlen(subjectPublicKey) + 1); ++ ret = mbedtls_pk_parse_public_key(&subjKeyCtx, (const uint8_t *)subjectPublicKey, strlen(subjectPublicKey) + 1); + VERIFY_SUCCESS(TAG, 0 == ret, ERROR); + - ret = mbedtls_pk_parse_key(&issKeyCtx, issuerPrivateKey, strlen(issuerPrivateKey) + 1, NULL, 0); ++ 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) + { - ret = mbedtls_x509_crt_parse(&issCertCtx, issuerCert, strlen(issuerCert) + 1); ++ 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, - &entropy, PERSONALIZATION_STRING, sizeof(PERSONALIZATION_STRING)); ++ &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); + } + - ret = mbedtls_x509write_crt_pem(&outCertCtx, buf, sizeof(buf), mbedtls_ctr_drbg_random, &ctr_drbg); ++ 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 = byteStr.bytes; ++ *certificate = (char *)byteStr.bytes; + *certificateLen = byteStr.len; + } + + return res; +} + +#endif /* defined(__WITH_TLS__) || defined(__WITH_DTLS__) */