*.iml
.idea
+# Ignore Project files for VS Code
+.vscode/
+
# Ignore CTags default data
tags
return; \
} \
+/**
+ * Macro to verify an expression, goto exit: if not satisfied
+ *
+ * @param log_tag log tag
+ * @param expr Expression to verify.
+ * @param msg Message to log prior to exiting
+ * @param log_level logging level
+ *
+ * @note Invoking function must define "exit:" label for goto functionality to work correctly.
+ */
+#define VERIFY_SUCCESS_OR_EXIT(log_tag, expr, msg, log_level) do{ if (!(expr)) \
+ {OIC_LOG((log_level), (log_tag), (msg)); goto exit; } }while(0)
+
+
+/**
+ * Macro to verify an expression, or return
+ *
+ * @param log_tag log tag
+ * @param expr Expression to verify.
+ * @param msg Message to log prior to exiting
+ * @param log_level logging level
+ */
+#define VERIFY_SUCCESS_OR_RETURN(log_tag, expr, msg, log_level) do{ if (!(expr)) \
+ {OIC_LOG((log_level), (log_tag), (msg)); return; } }while(0)
+
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
--- /dev/null
+//******************************************************************
+// Copyright 2018 Cable Television Laboratories, Inc.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// 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.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+/**
+ * @file
+ *
+ * This file contains common utility functions for validating OCF certificate profiles
+ */
+
+#ifndef CA_CERT_PROFILE_H_
+#define CA_CERT_PROFILE_H_
+
+#if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
+
+#include <mbedtls/x509_crt.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * Certificate Types
+ */
+
+typedef enum
+{
+ CERT_CA_ROOT = 0,
+ CERT_CA_INT,
+ CERT_EE
+} CertType;
+
+/**
+ * Cert profile return values
+ */
+typedef enum
+{
+ CP_STATUS_OK = 0, /* Success */
+ CP_NO_EE_CERT, /* No end entity cert in cert chain */
+ CP_MUL_EE_CERTS, /* Multiple end entity certs in cert chain */
+ CP_PROFILE_VIOLATION, /* Certificate(s) don't satisfy OCF profile requirements */
+ CP_INVALID_CERT_INPUT, /* Certificate input is invalid (or null) */
+ CP_DATE_ERROR, /* Problem setting or reading certificate validity dates */
+ CP_BUF_TOO_SMALL, /* Supplied buffer is not long enough for desired operation */
+ CP_STATUS_FAILED = 255 /* Failure */
+} CertProfileResult;
+
+/**
+ * Return values for cert chain functions that return a counts or -1 on failure
+ */
+#define CP_INVALID_CERT_CHAIN -1
+#define CP_INVALID_CERT_LIST -1
+
+/**
+ * Macro to log an mbedtls error
+ * For mbedtls functions that return 0 as non-error
+ *
+ * @param log_tag log tag
+ * @param ret value returned by mbedtls call
+ * @param log_level logging level
+ * @param buf char* buffer for error string processing
+ * @param buf_size size of bug
+ *
+ * NOTE: you must include "mbedtls/error.h" in order to use this
+ */
+#define CP_LOG_MBED_ERROR(log_tag, ret, buf, buf_size, log_level) do{ if (0!=(ret)) { \
+ mbedtls_strerror((ret), (buf), (buf_size)); \
+ OIC_LOG_V((log_level), (log_tag), "mbedtls error: %s", (buf)); } }while(0)
+
+/**
+ * Cert profile violation flags
+ */
+typedef unsigned long CertProfileViolations;
+
+#define CP_NO_VIOLATIONS (0)
+#define CP_PROCESSING_ERROR (1 << 1)
+#define CP_INVALID_SIG_ALGORITHM (1 << 2)
+#define CP_INVALID_VERSION (1 << 3)
+#define CP_INVALID_PUB_KEY_ALGORITHM (1 << 4)
+#define CP_INVALID_KEY_USAGE_MISSING (1 << 5)
+#define CP_INVALID_KEY_USAGE_EXTRA (1 << 6)
+#define CP_INVALID_BASIC_CONSTRAINTS_CA (1 << 7)
+#define CP_INVALID_BASIC_CONSTRAINTS_PATH_LEN (1 << 8)
+#define CP_INVALID_EKU_NO_SERVER_AUTH (1 << 9)
+#define CP_INVALID_EKU_NO_CLIENT_AUTH (1 << 10)
+#define CP_INVALID_EKU_NO_OCF_ID_OID (1 << 11)
+#define CP_INVALID_EKU_INCLUDES_ANY (1 << 12)
+#define CP_INVALID_ISSUER_SUBJ_MISMATCH (1 << 13)
+#define CP_NOT_YET_VALID (1 << 14)
+#define CP_EXPIRED (1 << 15)
+
+
+/**
+ * Validate an end-entity certificate against OCF cert profile requirements
+ *
+ * @param[in] cert end entity cert to validate
+ *
+ * @return Success: CP_NO_VIOLATIONS
+ * Errors: 1 or more violation bits set
+ */
+CertProfileViolations ValidateEndEntityCertProfile(const mbedtls_x509_crt *cert);
+
+/**
+ * Validate an intermediate-ca certificate against OCF cert profile requirements
+ *
+ * @param[in] cert end entity ca cert to validate
+ *
+ * @return Success: CP_NO_VIOLATIONS
+ * Errors: 1 or more violation bits set
+ */
+CertProfileViolations ValidateIntermediateCACertProfile(const mbedtls_x509_crt *cert);
+
+/**
+ * Validate a root-ca certificate against OCF cert profile requirements
+ *
+ * @param[in] cert intermediate ca cert to validate
+ *
+ * @return Success: CP_NO_VIOLATIONS
+ * Errors: 1 or more violation bits set
+ */
+CertProfileViolations ValidateRootCACertProfile(const mbedtls_x509_crt *cert);
+
+/**
+ * Validate a certificate's time window
+ *
+ * @param[in] cert cert to validate
+ *
+ * @return Success: CP_NO_VIOLATIONS
+ * Errors: CP_NOT_YET_VALID and/or CP_EXPIRED
+ */
+CertProfileViolations ValidateCertTimeWindow(const mbedtls_x509_crt *cert);
+
+/**
+ * Given a cert chain intended for authentication, validated that the certs
+ * within the chain conform to OCF certificate profile requirements.
+ *
+ * @param[in] certChain cert chain intended for authentication
+ *
+ * @return Number of certs in the list that did not validate.
+ * 0 = success
+ * CP_INVALID_CERT_CHAIN for invalid input chain
+ * > 0 = some number of certs did not validate
+ */
+int ValidateAuthCertChainProfiles(const mbedtls_x509_crt *certChain);
+
+/**
+ * Given a list of root CA certs, validated that the certs
+ * within the list conform to OCF certificate profile requirements.
+ *
+ * @param[in] certList Chain chain intended for authentication
+ *
+ * @return Number of certs in the list that did not validate.
+ * 0 = success
+ * CP_INVALID_CERT_LIST for invalid input cert list
+ * > 0 = some number of certs did not validate
+ */
+int ValidateRootCACertListProfiles(const mbedtls_x509_crt *certList);
+
+/**
+ * Given a list of certificates, validate that they are currently
+ * within each certificate's valid time window
+ *
+ * @param[in] certList List of certs for which to check time window
+ *
+ * @return number of certs in the list that are NOT in valid time window relative to now
+ * 0 = success
+ * CP_INVALID_CERT_LIST for invalid input cert list
+ * > 0 = some number of certs did not validate
+ */
+int CheckCertListTimeWindows(const mbedtls_x509_crt *certList);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif // (__WITH_DTLS__) || defined (__WITH_TLS__)
+
+#endif /* CA_CERT_PROFILE_H_ */
connectivity_env.SConscript(root_dir + '/util/SConscript',
exports='connectivity_env')
-src_files = [File('adapter_util/caadapterutils.c'),]
+src_files = [File(src) for src in (
+ 'adapter_util/caadapterutils.c',
+ 'adapter_util/cacertprofile.c'
+)]
if (('BLE' in ca_transport) or ('ALL' in ca_transport)):
src_files.append(File('adapter_util/cafragmentation.c'))
#include "ca_adapter_net_ssl.h"
#include "cacommon.h"
#include "caipinterface.h"
+#include "cacertprofile.h"
#include "oic_malloc.h"
#include "experimental/ocrandom.h"
#include "experimental/byte_array.h"
OIC_LOG_V(WARNING, NET_SSL_TAG, "Own certificate chain parsing error: %d certs failed to parse", errNum);
goto required;
}
+
+ ret = ValidateAuthCertChainProfiles(&g_caSslContext->crt);
+ if (CP_INVALID_CERT_CHAIN == ret)
+ {
+ OIC_LOG(ERROR, NET_SSL_TAG, "Invalid own cert chain");
+ goto required;
+ }
+ else if (0 != ret)
+ {
+ OIC_LOG_V(ERROR, NET_SSL_TAG, "%d certificate(s) in own cert chain do not satisfy OCF profile requirements", ret);
+ goto required;
+ }
+
ret = mbedtls_pk_parse_key(&g_caSslContext->pkey, pkiInfo.key.data, pkiInfo.key.len,
NULL, 0);
if (0 != ret)
{
OIC_LOG_V(WARNING, NET_SSL_TAG, "CA chain parsing warning: %d certs failed to parse", errNum);
}
+ else
+ {
+ ret = ValidateRootCACertListProfiles(&g_caSslContext->ca);
+ if (CP_INVALID_CERT_LIST == ret)
+ {
+ OIC_LOG(ERROR, NET_SSL_TAG, "Invalid own CA cert chain");
+ OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
+ DeInitPkixInfo(&pkiInfo);
+ return -1;
+ }
+ else if (0 < ret )
+ {
+ OIC_LOG_V(ERROR, NET_SSL_TAG, "%d certificate(s) in own CA cert chain violate OCF Root CA cert profile requirements", ret);
+ OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
+ DeInitPkixInfo(&pkiInfo);
+ return -1;
+ }
+ }
ret = mbedtls_x509_crl_parse_der(&g_caSslContext->crl, pkiInfo.crl.data, pkiInfo.crl.len);
if(0 != ret)
mbedtls_x509_crt *peerCert = peer->ssl.session_negotiate->peer_cert;
if (NULL != peerCert)
{
+ ret = ValidateAuthCertChainProfiles(peerCert);
+ if (CP_INVALID_CERT_CHAIN == ret)
+ {
+ oc_mutex_unlock(g_sslContextMutex);
+ OIC_LOG(ERROR, NET_SSL_TAG, "Invalid peer cert chain");
+ OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
+ return CA_STATUS_FAILED;
+ }
+ else if (0 != ret)
+ {
+ oc_mutex_unlock(g_sslContextMutex);
+ OIC_LOG_V(ERROR, NET_SSL_TAG, "%d certificate(s) in peer cert chain do not satisfy OCF profile requirements", ret);
+ OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
+ return CA_STATUS_FAILED;
+ }
+
ret = PeerCertExtractCN(peerCert);
if (CA_STATUS_OK != ret)
{
--- /dev/null
+//******************************************************************
+// Copyright 2018 Cable Television Laboratories, Inc.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// 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 lan guage governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+#include <string.h>
+#include <time.h>
+
+#include <mbedtls/error.h>
+#include <mbedtls/x509_crt.h>
+#include <mbedtls/oid.h>
+
+#include "cacommonutil.h"
+#include "cacertprofile.h"
+#include "experimental/logger.h"
+
+#define TAG "OIC_CC_CERT_PROFILE"
+
+// OCF Compliant ID Cert profiles
+static const mbedtls_x509_crt_profile s_certProfile = {
+ MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256), // MD algorithms
+ MBEDTLS_X509_ID_FLAG(MBEDTLS_PK_ECKEY) | // Allowed key types
+ MBEDTLS_X509_ID_FLAG(MBEDTLS_PK_ECDSA),
+ MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP256R1), // EC curves
+ 0 // RSA minimum key length - not used because we only use EC key pairs
+};
+
+// OID for ID certificates (1.3.6.1.4.1.44924.1.6) suitable for mbedTLS check
+static const char s_ekuIdOid[] = MBEDTLS_OID_ISO_IDENTIFIED_ORG "\x06\x01\x04\x01\x82\xDE\x7C\x01\x06";
+
+
+static const unsigned int s_eeKeyUsage = MBEDTLS_X509_KU_DIGITAL_SIGNATURE |
+ MBEDTLS_X509_KU_KEY_AGREEMENT;
+
+static const unsigned int s_eeNonKeyUsage = MBEDTLS_X509_KU_NON_REPUDIATION |
+ MBEDTLS_X509_KU_DATA_ENCIPHERMENT |
+ MBEDTLS_X509_KU_KEY_ENCIPHERMENT |
+ MBEDTLS_X509_KU_KEY_CERT_SIGN |
+ MBEDTLS_X509_KU_CRL_SIGN |
+ MBEDTLS_X509_KU_ENCIPHER_ONLY |
+ MBEDTLS_X509_KU_DECIPHER_ONLY;
+
+static const unsigned int s_caKeyUsage = MBEDTLS_X509_KU_KEY_CERT_SIGN |
+ MBEDTLS_X509_KU_CRL_SIGN;
+
+static const unsigned int s_caNonKeyUsage = MBEDTLS_X509_KU_DIGITAL_SIGNATURE |
+ MBEDTLS_X509_KU_NON_REPUDIATION |
+ MBEDTLS_X509_KU_KEY_ENCIPHERMENT |
+ MBEDTLS_X509_KU_DATA_ENCIPHERMENT |
+ MBEDTLS_X509_KU_KEY_AGREEMENT |
+ MBEDTLS_X509_KU_ENCIPHER_ONLY |
+ MBEDTLS_X509_KU_DECIPHER_ONLY;
+
+#if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
+
+static CertProfileResult FindEndEntityCert(const mbedtls_x509_crt *certChain, mbedtls_x509_crt const **eeCert)
+{
+ *eeCert = NULL;
+
+ const mbedtls_x509_crt* curCert = certChain;
+ while (NULL != curCert)
+ {
+ if (0 == curCert->ca_istrue)
+ {
+ // first EE
+ if (NULL == *eeCert)
+ {
+ *eeCert = curCert;
+ }
+ // more than 1 EE is an error condition
+ else
+ {
+ *eeCert = NULL;
+ OIC_LOG(ERROR, TAG, "More than 1 end entity cert in chain");
+ return CP_MUL_EE_CERTS;
+ }
+ }
+ curCert = curCert->next;
+ }
+
+ if (NULL == *eeCert)
+ {
+ OIC_LOG(WARNING, TAG, "No end entity cert in chain");
+ return CP_NO_EE_CERT;
+ }
+
+ return CP_STATUS_OK;
+}
+
+static CertProfileResult CheckMdAlgorithm(const mbedtls_x509_crt_profile *profile, mbedtls_md_type_t mdAlgorithm)
+{
+ if ((MBEDTLS_X509_ID_FLAG(mdAlgorithm) & profile->allowed_mds) != 0)
+ {
+ return CP_STATUS_OK;
+ }
+ return CP_STATUS_FAILED;
+}
+
+static CertProfileResult CheckPubKeyAlgorithm(const mbedtls_x509_crt_profile *profile, mbedtls_pk_type_t pkAlgorithm)
+{
+ if ((MBEDTLS_X509_ID_FLAG(pkAlgorithm) & profile->allowed_pks) != 0)
+ {
+ return CP_STATUS_OK;
+ }
+ return CP_STATUS_FAILED;
+}
+
+
+// returns CP_STATUS_OK if pathlen is valid for cert type, othewise returns CP_STATUS_FAILED
+static CertProfileResult CheckPathLen( CertType certType, int mbedMaxPathLen) {
+
+ // mbedtls max_pathlen behaviour:
+ // CA Cert: Expects RFC5280_val as encoding input
+ // Provides RFC5280_val+1 as decoding output, where 0 = not present
+ // EE Cert: Does not encode
+ // Provides 0 as decoding output
+
+ switch(certType)
+ {
+ case CERT_CA_ROOT:
+ return (0 == mbedMaxPathLen) ? CP_STATUS_OK : CP_STATUS_FAILED;
+ case CERT_CA_INT:
+ return (1 == mbedMaxPathLen) ? CP_STATUS_OK : CP_STATUS_FAILED;
+ case CERT_EE:
+ return (0 == mbedMaxPathLen) ? CP_STATUS_OK : CP_STATUS_FAILED;
+ default:
+ {
+ OIC_LOG(WARNING, TAG, "Unkown cert type for pathlen check");
+ return CP_STATUS_FAILED;
+ }
+ }
+}
+
+// Check all cert entries that are common across root-ca, intermediate-ca, and ee certs
+static CertProfileViolations ValidateCommonCertProfileEntries(const mbedtls_x509_crt *cert) {
+
+ CertProfileResult cpResult = CP_STATUS_OK;
+ CertProfileViolations profileViolations = CP_NO_VIOLATIONS;
+
+ // Start with time windows
+ // notBefore: Required
+ // notAfter: Required
+ profileViolations = ValidateCertTimeWindow(cert);
+ if (CP_NO_VIOLATIONS != profileViolations)
+ {
+ OIC_LOG(ERROR, TAG, "Cert has expired or is not yet valid");
+ }
+
+ // signatureAlgorithm
+ // ecdsa-with-SHA256 (OID: 1.2.840.10045.4.3.2)
+ cpResult = CheckMdAlgorithm(&s_certProfile, cert->sig_md);
+ if (CP_STATUS_OK != cpResult)
+ {
+ OIC_LOG(ERROR, TAG, "Cert signature algorithm must be SHA256");
+ profileViolations |= CP_INVALID_SIG_ALGORITHM;
+ }
+
+ // Version: v3
+ // mbedTLS version 3 = x509 v3
+ if (3 != cert->version)
+ {
+ OIC_LOG(ERROR, TAG, "Cert is not x509 v3");
+ profileViolations |= CP_INVALID_VERSION;
+ }
+
+ // Subject Public Key Info
+ // id-ecPublicKey (OID: 1.2.840.10045.2.1) secp256r1 (OID:1.2.840.10045.3.1.7)
+ cpResult = CheckPubKeyAlgorithm(&s_certProfile, cert->sig_pk);
+ if (CP_STATUS_OK != cpResult)
+ {
+ OIC_LOG(ERROR, TAG, "Cert public key algorithm must be ECDSA");
+ profileViolations |= CP_INVALID_PUB_KEY_ALGORITHM;
+ }
+
+ // SerialNumber: SHALL be a positive integer, unique among all certificates issued by Root CA
+ // Not possible to validate SN uniqueness
+
+ // Issuer: SHALL match the Subject field of the issuing Root CA
+ // mbedTLS will check proper chaining during DTLS handshake
+
+ return profileViolations;
+}
+
+
+CertProfileViolations ValidateEndEntityCertProfile(const mbedtls_x509_crt *cert)
+{
+
+ // OCF requirements exist for the following extensions, but w/o mbedTLS support
+ // * check for certificate policies, if present must be 1.3.6.1.4.1.51414.0.1.1
+ // * cRL Distributiojn Points
+
+ if (NULL == cert)
+ {
+ return CP_INVALID_CERT_INPUT;
+ }
+
+ int mbedRet = 0;
+ CertProfileResult cpResult = CP_STATUS_OK;
+ CertProfileViolations profileViolations = CP_NO_VIOLATIONS;
+
+ // Check all common entries first
+ profileViolations = ValidateCommonCertProfileEntries(cert);
+
+ // keyUsage (REQUIRED/Critical)
+ // digitalSignature (0) and keyAgreement(4) bits SHALL be the only bits enabled
+ mbedRet = mbedtls_x509_crt_check_key_usage(cert, s_eeKeyUsage);
+ if (0 != mbedRet)
+ {
+ OIC_LOG(ERROR, TAG, "End entity cert key usage must include digitalSignature & keyAgreement");
+ profileViolations |= CP_INVALID_KEY_USAGE_MISSING;
+ }
+
+ if (0 != (cert->key_usage & s_eeNonKeyUsage))
+ {
+ OIC_LOG(ERROR, TAG, "End entity cert key usage must not include usages other than digitalSignature & keyAgreement");
+ profileViolations |= CP_INVALID_KEY_USAGE_EXTRA;
+ }
+
+ // basicConstraints (OPTIONAL/Critical)
+ // cA = FALSE
+ if (1 == cert->ca_istrue)
+ {
+ OIC_LOG(ERROR, TAG, "End entity cert marked as CA cert");
+ profileViolations |= CP_INVALID_BASIC_CONSTRAINTS_CA;
+ }
+
+ // pathLenConstraint: not present
+ cpResult = CheckPathLen(CERT_EE, cert->max_pathlen);
+ if (CP_STATUS_OK != cpResult)
+ {
+ OIC_LOG(ERROR, TAG, "Invalid End entity max pathlen");
+ profileViolations |= CP_INVALID_BASIC_CONSTRAINTS_PATH_LEN;
+ }
+
+ // extendedKeyUsage (REQUIRED/Non-critical)
+ // Mandatory: serverAuthentication - 1.3.6.1.5.5.7.3.1
+ mbedRet = mbedtls_x509_crt_check_extended_key_usage(cert,
+ MBEDTLS_OID_SERVER_AUTH,
+ MBEDTLS_OID_SIZE(MBEDTLS_OID_SERVER_AUTH));
+ if (0 != mbedRet)
+ {
+ OIC_LOG(ERROR, TAG, "End entity cert extended key usage must include serverAuthentication");
+ profileViolations |= CP_INVALID_EKU_NO_SERVER_AUTH;
+ }
+
+ // extendedKeyUsage (REQUIRED/Non-critical)
+ // Mandatory: clientAuthentication - 1.3.6.1.5.5.7.3.2
+ mbedRet = mbedtls_x509_crt_check_extended_key_usage(cert,
+ MBEDTLS_OID_CLIENT_AUTH,
+ MBEDTLS_OID_SIZE(MBEDTLS_OID_CLIENT_AUTH));
+ if (0 != mbedRet)
+ {
+ OIC_LOG(ERROR, TAG, "End entity cert extended key usage must include clientAuthentication");
+ profileViolations |= CP_INVALID_EKU_NO_CLIENT_AUTH;
+ }
+
+ // extendedKeyUsage (REQUIRED/Non-critical)
+ // Mandatory: OCF Identity certificate - 1.3.6.1.4.1.44924.1.6
+ mbedRet = mbedtls_x509_crt_check_extended_key_usage(cert, s_ekuIdOid, MBEDTLS_OID_SIZE(s_ekuIdOid));
+ if (0 != mbedRet)
+ {
+ OIC_LOG(ERROR, TAG, "End entity cert extended key usage must include OCF ID OID (1.3.6.1.4.1.44924.1.6");
+ profileViolations |= CP_INVALID_EKU_NO_OCF_ID_OID;
+ }
+
+ // extendedKeyUsage (REQUIRED/Non-critical)
+ // CAs SHALL NOT issue certificates with the anyExtendedKeyUsage OID (2.5.29.37.0)
+ mbedRet = mbedtls_x509_crt_check_extended_key_usage(cert,
+ MBEDTLS_OID_ANY_EXTENDED_KEY_USAGE,
+ MBEDTLS_OID_SIZE(MBEDTLS_OID_ANY_EXTENDED_KEY_USAGE));
+ if (0 == mbedRet)
+ {
+ OIC_LOG(ERROR, TAG, "End entity cert extended key usage must not include anyExtendedKeyUsage");
+ profileViolations |= CP_INVALID_EKU_INCLUDES_ANY;
+ }
+
+ // subjectAlternativeName: No requirements for ID certs
+
+ return profileViolations;
+}
+
+CertProfileViolations ValidateIntermediateCACertProfile(const mbedtls_x509_crt *cert)
+{
+
+ // OCF requirements exist for the following extensions, but w/o mbedTLS support
+ // * cRL Distribution Points
+
+ if (NULL == cert)
+ {
+ return CP_INVALID_CERT_INPUT;
+ }
+
+ int mbedRet = 0;
+ CertProfileResult cpResult = CP_STATUS_OK;
+ CertProfileViolations profileViolations = CP_NO_VIOLATIONS;
+
+ // Check all common entries first
+ profileViolations = ValidateCommonCertProfileEntries(cert);
+
+ // keyUsage: REQUIRED/Critical
+ // keyCertSign (5) & cRLSign (6) bits SHALL be the only bits enabled
+ mbedRet = mbedtls_x509_crt_check_key_usage(cert, s_caKeyUsage);
+ if (0 != mbedRet)
+ {
+ OIC_LOG(ERROR, TAG, "Intermediate CA cert key usage must include keyCertSign & cRLSign");
+ profileViolations |= CP_INVALID_KEY_USAGE_MISSING;
+ }
+
+ if (0 != (cert->key_usage & s_caNonKeyUsage))
+ {
+ OIC_LOG(ERROR, TAG, "Intermediate CA cert key usage must not include usages other than keyCertSign & cRLSign");
+ profileViolations |= CP_INVALID_KEY_USAGE_EXTRA;
+ }
+
+ // basicConstraints REQUIRED/Critical
+ // cA = TRUE
+ if (1 != cert->ca_istrue)
+ {
+ OIC_LOG(ERROR, TAG, "Intermediate CA cert not marked as CA cert");
+ profileViolations |= CP_INVALID_BASIC_CONSTRAINTS_CA;
+ }
+
+ // pathLenConstraint
+ // 0 - can only sign end-entity certs
+ cpResult = CheckPathLen(CERT_CA_INT, cert->max_pathlen);
+ if (CP_STATUS_OK != cpResult)
+ {
+ OIC_LOG(ERROR, TAG, "Invalid Intermediate CA max pathlen");
+ profileViolations |= CP_INVALID_BASIC_CONSTRAINTS_PATH_LEN;
+ }
+ return profileViolations;
+}
+
+CertProfileViolations ValidateRootCACertProfile(const mbedtls_x509_crt *cert)
+{
+ if (NULL == cert)
+ {
+ return CP_INVALID_CERT_INPUT;
+ }
+
+ int mbedRet = 0;
+ CertProfileResult cpResult = CP_STATUS_OK;
+ CertProfileViolations profileViolations = CP_NO_VIOLATIONS;
+
+ // Check all common entries first
+ profileViolations = ValidateCommonCertProfileEntries(cert);
+
+ // Issuer: SHALL match the Subject field
+ // Subject: SHALL match the Issuer field
+ if ( (cert->issuer_raw.len != cert->subject_raw.len) ||
+ (0 != memcmp(cert->issuer_raw.p, cert->subject_raw.p, cert->issuer_raw.len)))
+ {
+ OIC_LOG(ERROR, TAG, "Root CA cert subject must be the same as issuer");
+ profileViolations |= CP_INVALID_ISSUER_SUBJ_MISMATCH;
+
+ }
+
+ // keyUsage: REQUIRED/Critical
+ // keyCertSign (5) & cRLSign (6) bits SHALL be the only bits enabled
+ mbedRet = mbedtls_x509_crt_check_key_usage(cert, s_caKeyUsage);
+ if (0 != mbedRet)
+ {
+ OIC_LOG(ERROR, TAG, "Root CA cert key usage must include keyCertSign & cRLSign");
+ profileViolations |= CP_INVALID_KEY_USAGE_MISSING;
+ }
+ if (0 != (cert->key_usage & s_caNonKeyUsage))
+ {
+ OIC_LOG(ERROR, TAG, "Root CA cert key usage must not include usages other than keyCertSign & cRLSign");
+ profileViolations |= CP_INVALID_KEY_USAGE_EXTRA;
+ }
+
+ // basicConstraints REQUIRED Critical cA = TRUE
+ if (1 != cert->ca_istrue)
+ {
+ OIC_LOG(ERROR, TAG, "Root CA cert not marked as CA cert");
+ profileViolations |= CP_INVALID_BASIC_CONSTRAINTS_CA;
+ }
+
+ // pathLenConstraint = not present (unlimited)
+ cpResult = CheckPathLen(CERT_CA_ROOT, cert->max_pathlen);
+ if (CP_STATUS_OK != cpResult)
+ {
+ OIC_LOG(ERROR, TAG, "Invalid Root CA max pathlen");
+ profileViolations |= CP_INVALID_BASIC_CONSTRAINTS_PATH_LEN;
+ }
+
+ return profileViolations;
+}
+
+int ValidateAuthCertChainProfiles(const mbedtls_x509_crt *certChain)
+{
+ int numViolations = 0;
+ CertProfileResult cpResult = CP_STATUS_OK;
+ CertProfileViolations profileViolations = CP_NO_VIOLATIONS;
+
+ const mbedtls_x509_crt* eeCert = NULL;
+ cpResult = FindEndEntityCert(certChain, &eeCert);
+ if ((CP_STATUS_OK != cpResult) || (NULL == eeCert))
+ {
+ return CP_INVALID_CERT_CHAIN;
+ }
+
+ const mbedtls_x509_crt* curCert = certChain;
+ while (NULL != curCert)
+ {
+ if (curCert == eeCert)
+ {
+ profileViolations = ValidateEndEntityCertProfile(curCert);
+ }
+ else
+ {
+ profileViolations = ValidateIntermediateCACertProfile(curCert);
+ }
+ if (CP_NO_VIOLATIONS != profileViolations)
+ {
+ numViolations++;
+ }
+ curCert = curCert->next;
+ }
+ return numViolations;
+}
+
+int ValidateRootCACertListProfiles(const mbedtls_x509_crt *certList)
+{
+ int numViolations = 0;
+ CertProfileViolations profileViolations = CP_NO_VIOLATIONS;
+
+ const mbedtls_x509_crt* curCert = certList;
+ while (NULL != curCert)
+ {
+ profileViolations = ValidateRootCACertProfile(curCert);
+ if (CP_NO_VIOLATIONS != profileViolations)
+ {
+ numViolations++;
+ }
+ curCert = curCert->next;
+ }
+ return numViolations;
+}
+
+CertProfileViolations ValidateCertTimeWindow(const mbedtls_x509_crt *cert)
+{
+ CertProfileViolations profileViolations = CP_NO_VIOLATIONS;
+
+ if (mbedtls_x509_time_is_future(&cert->valid_from))
+ {
+ OIC_LOG(WARNING, TAG, "Certificate is not yet valid");
+ profileViolations |= CP_NOT_YET_VALID;
+ }
+ if (mbedtls_x509_time_is_past(&cert->valid_to))
+ {
+ OIC_LOG(WARNING, TAG, "Certificate is no longer valid");
+ profileViolations |= CP_EXPIRED;
+ }
+ return profileViolations;
+}
+
+int CheckCertListTimeWindows(const mbedtls_x509_crt *certList)
+{
+ int numInvalid = 0;
+ CertProfileViolations profileViolations = CP_NO_VIOLATIONS;
+
+ const mbedtls_x509_crt* curCert = certList;
+ while (NULL != curCert)
+ {
+ profileViolations = ValidateCertTimeWindow(curCert);
+ if (CP_NO_VIOLATIONS != profileViolations)
+ {
+ numInvalid++;
+ }
+ curCert = curCert->next;
+ }
+ return numInvalid;
+}
+
+#endif // (__WITH_DTLS__) || defined (__WITH_TLS__)
'#/resource/csdk/include',
'#/resource/csdk/stack/include',
'#/resource/oc_logger/include',
+ '#/resource/csdk/security/include',
+ '#/resource/c_common/ocrandom/include/experimental',
])
catest_env.PrependUnique(LIBS=['coap'])
if catest_env.get('SECURED') == '1' and catest_env.get('WITH_TCP') == True:
tests_src.append('ssladapter_test.cpp')
+if catest_env.get('SECURED') == '1':
+ tests_src.append('cacertprofiletest.cpp')
+
catests = catest_env.Program('catests', tests_src)
Alias("test", [catests])
--- /dev/null
+//******************************************************************
+// Copyright 2018 Cable Television Laboratories, Inc.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 s(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.
+///
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+// Warning disabled globally but VS2013 ignores the /wd4200 option in C++ files.
+#if defined(_MSC_VER) && _MSC_VER < 1900
+#pragma warning(disable : 4200)
+#endif
+
+#include <gtest/gtest.h>
+
+#include <mbedtls/error.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/x509_crt.h>
+#include <mbedtls/ctr_drbg.h>
+#include <mbedtls/oid.h>
+#include <mbedtls/pem.h>
+
+#include "oic_platform.h"
+#include "oic_malloc.h"
+#include "octypes.h"
+#include "ocrandom.h"
+#include "cacommonutil.h"
+#include "cacertprofile.h"
+#include "occertutility.h"
+
+#define TAG "CA_CERT_PROFILE_UNIT_TEST"
+
+#define PERSONALIZATION_STRING "IOTIVITY_CERT_TEST"
+
+typedef char ValidityTime[50];
+
+#define ARRAY_LEN(a) (sizeof(a) / sizeof(*a))
+
+// helper functions
+static CertProfileResult GenerateTestCert(CertType certType, CertProfileViolations violations, mbedtls_x509_crt *outCert);
+static CertProfileResult GenerateInternalCert(CertType certType, mbedtls_x509_crt *issuerCert, mbedtls_x509_crt *outCert);
+static void InitTestCert(mbedtls_x509_crt *cert);
+static void FreeTestCert(mbedtls_x509_crt *cert);
+static CertProfileResult SetNotBefore(ValidityTime notBefore, bool invalid);
+static CertProfileResult SetNotAfter(ValidityTime notAfter, bool invalid);
+
+class CACertProfileTests : public testing::Test {
+ protected:
+ virtual void SetUp()
+ {
+ }
+
+ virtual void TearDown()
+ {
+ }
+};
+
+//*****************************************************************************
+// Test Data
+//*****************************************************************************
+
+static const mbedtls_x509_crt_profile s_certProfile = {
+ MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256), // MD algorithms
+ MBEDTLS_X509_ID_FLAG(MBEDTLS_PK_ECKEY) | // Allowed key types
+ MBEDTLS_X509_ID_FLAG(MBEDTLS_PK_ECDSA),
+ MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP256R1), // EC curves
+ 0 // RSA minimum key length - not used because we only use EC key pairs
+};
+ // total len of eku byte string, will need to be written into final buff
+ // |
+static uint8_t s_ekuHeaderBytes[] = { 0x30, 0x00 };
+
+// serverAuth (1.3.6.1.5.5.7.3.1) tag len 1.3. 6. 1. 5. 5. 7. 3. 1
+static uint8_t s_ekuServerAuthOidBytes[] = { 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01 };
+
+// clientAuth (1.3.6.1.5.5.7.3.2) tag len 1.3. 6. 1. 5. 5. 7. 3. 2
+static uint8_t s_ekuClientAuthOidBytes[] = { 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02 };
+
+
+// OCF ID OID (1.3.6.1.4.1.44924.1.6) tag len 1.3. 6. 1. 4. 1. 44924. 1. 6
+static uint8_t s_ekuOcfIdentityOidBytes[] = { 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0xDE, 0x7C, 0x01, 0x06 };
+
+// any (2.5.29.37.0) tag len 2.5. 29. 37. 0
+static uint8_t s_ekuAnyOidBytes[] = { 0x06, 0x04, 0x55, 0x1D, 0x25, 0x00 };
+
+static const OCByteString s_ekuHeader = { s_ekuHeaderBytes, sizeof(s_ekuHeaderBytes) };
+static const OCByteString s_ekuServerAuthOid = { s_ekuServerAuthOidBytes, sizeof(s_ekuServerAuthOidBytes) };
+static const OCByteString s_ekuClientAuthOid = { s_ekuClientAuthOidBytes, sizeof(s_ekuClientAuthOidBytes) };
+static const OCByteString s_ekuOcfIdentityOid = { s_ekuOcfIdentityOidBytes, sizeof(s_ekuOcfIdentityOidBytes) };
+static const OCByteString s_ekuAnyOid = { s_ekuAnyOidBytes, sizeof(s_ekuAnyOidBytes) };
+
+
+// The key pairs below are OCF compliant ellliptic curve key pairs
+// (RFC 5480 secp256r1 keys) generated by the IoTivity`certgenerator` utility.
+// They are used as the public and signing keys for certificates
+// that are generated for unit tests in this module.
+
+static const char* s_rootCaPubKey = "-----BEGIN PUBLIC KEY-----\n"
+"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAET0k0tJJu5fnSXa5Wik7VPxpbiWeT\n"
+"rWnvGY8Jv2/xsODb6A7SZPvpu4svwBkO2Wy0gCDwRtwi08ZLemgrtA7w7g==\n"
+"-----END PUBLIC KEY-----\n";
+
+static const char* s_rootCaPrivKey = "-----BEGIN EC PRIVATE KEY-----\n"
+"MHcCAQEEIGrNaXfihmU41VIYHdXACpy6/X9X0MB9g0vtb/ujV403oAoGCCqGSM49\n"
+"AwEHoUQDQgAET0k0tJJu5fnSXa5Wik7VPxpbiWeTrWnvGY8Jv2/xsODb6A7SZPvp\n"
+"u4svwBkO2Wy0gCDwRtwi08ZLemgrtA7w7g==\n"
+"-----END EC PRIVATE KEY-----\n";
+
+static const char* s_intCaPubKey = "-----BEGIN PUBLIC KEY-----\n"
+"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEQQ9DVoBQlnYFjBBvV1sligvG60T\n"
+"vF0O1kXWjUOOFaVHVooHOnxUv1jQFNhH0wERkIYdHGA0DrkbLiWNe0qjDg==\n"
+"-----END PUBLIC KEY-----\n";
+
+static const char* s_intCaPrivKey = "-----BEGIN EC PRIVATE KEY-----\n"
+"MHgCAQEEIQCtAr1LI2tSUGDkaANJOaII9I9RuNl/smpx61ZL1mvm1aAKBggqhkjO\n"
+"PQMBB6FEA0IABBEEPQ1aAUJZ2BYwQb1dbJYoLxutE7xdDtZF1o1DjhWlR1aKBzp8\n"
+"VL9Y0BTYR9MBEZCGHRxgNA65Gy4ljXtKow4=\n"
+"-----END EC PRIVATE KEY-----\n";
+
+static const char* s_eePubKey = "-----BEGIN PUBLIC KEY-----\n"
+"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEK+y7B9e0o7+6SeH2o7YnJKSpY5eO\n"
+"cw29uqb5kTvGj7hOoBK/Ulr492YKlxouF+j1pXUvZYRy2aMoUnm2sGNd4Q==\n"
+"-----END PUBLIC KEY-----\n";
+
+static const char* s_eePrivKey = "-----BEGIN EC PRIVATE KEY-----\n"
+"MHcCAQEEIFiqzuEt5rOCRB4D3fHW+L22vsM7mvnK+Np8vLDl3BwCoAoGCCqGSM49\n"
+"AwEHoUQDQgAEK+y7B9e0o7+6SeH2o7YnJKSpY5eOcw29uqb5kTvGj7hOoBK/Ulr4\n"
+"92YKlxouF+j1pXUvZYRy2aMoUnm2sGNd4Q==\n"
+"-----END EC PRIVATE KEY-----\n";
+
+
+// The key pair below are NON OCF compliant RSA keys generated using
+// openssl. The pair is used in negative testing to create
+// certificates that violate the OCF crypto type requirements
+
+static const char* s_nonEccPubKey = "-----BEGIN PUBLIC KEY-----\n"
+"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwwInaid7Q3LSM+rvmI0a\n"
+"46/IWxWkSbTP91W2UQ2jt5/iwZQUEaKRxnGUtW+TdigKb1XTEHLoOa2vBnO6OCzW\n"
+"TfeA4aJSCO0cc/oW6inZqnp+3aAMoE34Y1PjOM69enY1WpbQGxoYxXpHjjuQ8M7i\n"
+"xw2xnb03HRgvy/Yg8dJ2+QZTopuxqh4Z9qHBALFZW04iS2e4GPj1NQCoc/MBsX4e\n"
+"WQV1UkeuYhbj1w3KDMDV6hcfNFp/A0XEmPh+ZcXTVRT0EHHY9sLGiVkjYX4b0i1u\n"
+"3lOv2imbIu3mPnhSUaFFBENTL+MQcvnsaHS/WNZL7tlaTWCHStlJnAlKke1rmdBB\n"
+"2wIDAQAB\n"
+"-----END PUBLIC KEY-----\n";
+
+static const char* s_nonEccPrivKey = "-----BEGIN RSA PRIVATE KEY-----\n"
+"MIIEpQIBAAKCAQEAwwInaid7Q3LSM+rvmI0a46/IWxWkSbTP91W2UQ2jt5/iwZQU\n"
+"EaKRxnGUtW+TdigKb1XTEHLoOa2vBnO6OCzWTfeA4aJSCO0cc/oW6inZqnp+3aAM\n"
+"oE34Y1PjOM69enY1WpbQGxoYxXpHjjuQ8M7ixw2xnb03HRgvy/Yg8dJ2+QZTopux\n"
+"qh4Z9qHBALFZW04iS2e4GPj1NQCoc/MBsX4eWQV1UkeuYhbj1w3KDMDV6hcfNFp/\n"
+"A0XEmPh+ZcXTVRT0EHHY9sLGiVkjYX4b0i1u3lOv2imbIu3mPnhSUaFFBENTL+MQ\n"
+"cvnsaHS/WNZL7tlaTWCHStlJnAlKke1rmdBB2wIDAQABAoIBADfxeT8x3mHGIdl1\n"
+"D5EzAcDJ3++JcN0YOwUYmLn98Lav7oxcH7nDapCEawX14VbnO78e3vL8E/TgB7MR\n"
+"Jh4RdtVdKKMSPviClUQMPeClauVGSPjpflXKqHROT4QvgxoLqVi4pTDxNqQIZVi/\n"
+"a+A5acNzAT5gVtxI4QVhMahOGYVsszaTrCf/9/rKleqKOnFyNq4QNtPtdUv+RT9B\n"
+"Sk5XruOJ3hR6Piivw5uLBYahiFbafXieQv4WAgTwZY0Hx1X5nhW3xbA2LXX4PuPv\n"
+"+DPBPtS2qGVxEc487UhhMbqBGygvOPycIYyXXUPdlN8hQkvA/vk9bEDg6Koro/MQ\n"
+"GbflZxkCgYEA+fLnwwyo6Yy4t5Gss8me0F5SA3praoGUfuN2xpzYy99puLlXazSi\n"
+"FZ2PrbiufeUJ1Fuf2AVu8/SdKKuwoinYT5MMUhbCm+ywMlGhf5aACV3XQxATU+si\n"
+"/YF8KDxRV6amBxqhmZahadKWmpV/nO7Xs1E/sIUuIIRWYa+qcnG/vJUCgYEAx7q/\n"
+"Sq3nkPhbNqbUUp9/FuHP2vz241Y5j5kHbCwiUQ5Qs9ZibShWbHEXz3uV2bWvUmb0\n"
+"eO+/Ch38SVSKpClwrubX2ABJZjxXnQiGRHdZ+Z7bepTTzNEdonlVL68D5f7Mix16\n"
+"db96+ZM6cD36k8Duiekuv4LrVyDRUDHZIwNW+K8CgYEA7nQxbSCXyPAqjV6Zz4/L\n"
+"Rmilf5H8BkkHHSLufr7GCYHjv4p6ftlgxJRjrU1iktK+VOzwistsNaspf9KEGcEo\n"
+"D4pvF6WFFfJxih/cnfc7wTPYmK8ucUIDSKyOgWhCBggDnwVmJDvTVDzG10VG0LX/\n"
+"7J/XzhTQk88NBfbr+nDQhh0CgYEAmfUz+4buF2u6M/iJdl8IAkVyieWxEjCnEi/t\n"
+"7s5ebYjRYK8DFA2iANl0dzVWn4lTaft+u7Ji2pOeo5ANhtmCyO+cth4SdkJRbvTh\n"
+"Oumda7Ouj2Elmp4fb9yDc8w+/w1X8mx4t0cwri11QIwmGbsApUIgDPQIIRNlBaJH\n"
+"NJwgcHUCgYEAzjkPOMoS4idZk7e1f/ymprGT6nsbwo2yyD18yYzaNHpSnIkZpJm0\n"
+"LXOoB+APM8Y9Hl3xHUtWV8WN1CmuWFyK7SvCPeqf6xm+fAFyRvFhX7Qm9ZMJLCif\n"
+"KCYeMZY1ax+OqnwZ79+8UB2gbjQ5efbdb8jVrZDEABCRp3Ko+/tGVYg=\n"
+"-----END RSA PRIVATE KEY-----\n";
+
+static const char* s_rootCaSerial = "244240106504148688103282289603386694025638582413";
+static const char* s_intCaSerial = "398222190774066044346258430305847925228418308044";
+static const char* s_eeSerial = "611138144226495869526348350957100882548422091813";
+
+static const char* s_rootCaIssuer = "O=OCF, OU=P256 Test Infrastructure, CN=Root Test CA";
+static const char* s_rootCaSubject = "O=OCF, OU=P256 Test Infrastructure, CN=Root Test CA";
+
+static const char* s_intCaIssuer = "O=OCF, OU=P256 Test Infrastructure, CN=Root Test CA";
+static const char* s_intCaSubject = "O=OCF, OU=P256 Test Infrastructure, CN=Intermediate Test CA";
+
+static const char* s_eeIssuer = "O=OCF, OU=P256 Test Infrastructure, CN=Intermediate Test CA";
+static const char* s_eeSubject = "O=OCF, OU=P256 Test Infrastructure, CN=11111111-1111-1111-1111-111111111111";
+static const char* s_eeUuid = "11111111-1111-1111-1111-111111111111";
+
+//*****************************************************************************
+// Tests
+//*****************************************************************************
+
+
+TEST_F(CACertProfileTests, RootCAProfiles)
+{
+ CertProfileResult cpResult = CP_STATUS_OK;
+ CertProfileViolations violations = CP_NO_VIOLATIONS;
+ CertProfileViolations expectedViolations = CP_NO_VIOLATIONS;
+ mbedtls_x509_crt cert;
+
+ CertProfileViolations violationsToTest[] =
+ {
+ CP_NO_VIOLATIONS,
+ CP_NOT_YET_VALID,
+ CP_EXPIRED,
+ CP_INVALID_SIG_ALGORITHM,
+ CP_INVALID_VERSION,
+ CP_INVALID_PUB_KEY_ALGORITHM,
+ CP_INVALID_ISSUER_SUBJ_MISMATCH,
+ CP_INVALID_KEY_USAGE_MISSING,
+ CP_INVALID_KEY_USAGE_EXTRA,
+ CP_INVALID_BASIC_CONSTRAINTS_CA,
+ CP_INVALID_BASIC_CONSTRAINTS_PATH_LEN
+ };
+
+ for (unsigned int i = 0; i < ARRAY_LEN(violationsToTest); i++)
+ {
+ InitTestCert(&cert);
+
+ cpResult = GenerateTestCert(CERT_CA_ROOT, violationsToTest[i], &cert);
+ EXPECT_TRUE(CP_STATUS_OK == cpResult);
+ if (CP_STATUS_OK == cpResult)
+ {
+ expectedViolations = violationsToTest[i];
+ violations = ValidateRootCACertProfile(&cert);
+ EXPECT_TRUE(violations == expectedViolations);
+ }
+ else
+ {
+ OIC_LOG(ERROR, TAG, "Could not generate root CA test cert");
+ }
+
+ FreeTestCert(&cert);
+ }
+}
+
+TEST_F(CACertProfileTests, IntermediateCAProfiles)
+{
+ CertProfileResult cpResult = CP_STATUS_OK;
+ CertProfileViolations violations = CP_NO_VIOLATIONS;
+ CertProfileViolations expectedViolations = CP_NO_VIOLATIONS;
+ mbedtls_x509_crt cert;
+
+ CertProfileViolations violationsToTest[] =
+ {
+ CP_NO_VIOLATIONS,
+ CP_NOT_YET_VALID,
+ CP_EXPIRED,
+ CP_INVALID_SIG_ALGORITHM,
+ CP_INVALID_VERSION,
+ CP_INVALID_PUB_KEY_ALGORITHM,
+ CP_INVALID_KEY_USAGE_MISSING,
+ CP_INVALID_KEY_USAGE_EXTRA,
+ CP_INVALID_BASIC_CONSTRAINTS_CA,
+ CP_INVALID_BASIC_CONSTRAINTS_PATH_LEN
+ };
+
+ for (unsigned int i = 0; i < ARRAY_LEN(violationsToTest); i++)
+ {
+ InitTestCert(&cert);
+
+ cpResult = GenerateTestCert(CERT_CA_INT, violationsToTest[i], &cert);
+ EXPECT_TRUE(CP_STATUS_OK == cpResult);
+ if (CP_STATUS_OK == cpResult)
+ {
+ expectedViolations = violationsToTest[i];
+ if (CP_INVALID_BASIC_CONSTRAINTS_CA == violationsToTest[i])
+ {
+ // Because we are faking non-CA cert, mbed will not encode the max_pathlen
+ // and we will get a pathlen violation as well
+ expectedViolations |= CP_INVALID_BASIC_CONSTRAINTS_PATH_LEN;
+ }
+ violations = ValidateIntermediateCACertProfile(&cert);
+ EXPECT_TRUE(violations == expectedViolations);
+ }
+ else
+ {
+ OIC_LOG(ERROR, TAG, "Could not generate root CA test cert");
+ }
+
+ FreeTestCert(&cert);
+ }
+}
+
+TEST_F(CACertProfileTests, EndEntityProfiles)
+{
+ CertProfileResult cpResult = CP_STATUS_OK;
+ CertProfileViolations violations = CP_NO_VIOLATIONS;
+ CertProfileViolations expectedViolations = CP_NO_VIOLATIONS;
+ mbedtls_x509_crt cert;
+
+ CertProfileViolations violationsToTest[] =
+ {
+ CP_NO_VIOLATIONS,
+ CP_NOT_YET_VALID,
+ CP_EXPIRED,
+ CP_INVALID_SIG_ALGORITHM,
+ CP_INVALID_VERSION,
+ CP_INVALID_PUB_KEY_ALGORITHM,
+ CP_INVALID_KEY_USAGE_MISSING,
+ CP_INVALID_KEY_USAGE_EXTRA,
+ CP_INVALID_BASIC_CONSTRAINTS_CA,
+ CP_INVALID_BASIC_CONSTRAINTS_PATH_LEN,
+ CP_INVALID_EKU_NO_SERVER_AUTH,
+ CP_INVALID_EKU_NO_CLIENT_AUTH,
+ CP_INVALID_EKU_NO_OCF_ID_OID,
+ CP_INVALID_EKU_INCLUDES_ANY
+ };
+
+ for (unsigned int i = 0; i < ARRAY_LEN(violationsToTest); i++)
+ {
+ InitTestCert(&cert);
+
+ cpResult = GenerateTestCert(CERT_EE, violationsToTest[i], &cert);
+ EXPECT_TRUE(CP_STATUS_OK == cpResult);
+ if (CP_STATUS_OK == cpResult)
+ {
+ expectedViolations = violationsToTest[i];
+ if (CP_INVALID_BASIC_CONSTRAINTS_PATH_LEN == violationsToTest[i])
+ {
+ // Because mbed does not support max_pathlen for EE certs,
+ // it is returned as zero, no matter what was specified at encoding,
+ // so this test will errantly pass
+ expectedViolations = CP_NO_VIOLATIONS;
+ }
+ violations = ValidateEndEntityCertProfile(&cert);
+ EXPECT_TRUE(violations == expectedViolations);
+ }
+ else
+ {
+ OIC_LOG(ERROR, TAG, "Could not generate End Entity test cert");
+ }
+
+ FreeTestCert(&cert);
+ }
+}
+
+TEST_F(CACertProfileTests, InternalRootCACert)
+{
+ CertProfileResult cpResult = CP_STATUS_OK;
+ CertProfileViolations violations = CP_NO_VIOLATIONS;
+
+ mbedtls_x509_crt rootCert;
+
+ InitTestCert(&rootCert);
+
+ cpResult = GenerateInternalCert(CERT_CA_ROOT, NULL, &rootCert);
+ EXPECT_TRUE(CP_STATUS_OK == cpResult);
+ if (CP_STATUS_OK == cpResult)
+ {
+ violations = ValidateRootCACertProfile(&rootCert);
+ EXPECT_TRUE(violations == CP_NO_VIOLATIONS);
+ }
+ else
+ {
+ OIC_LOG(ERROR, TAG, "Could not generate internal CA test cert");
+ }
+
+ FreeTestCert(&rootCert);
+}
+
+TEST_F(CACertProfileTests, InternalIntermediateCert)
+{
+ CertProfileResult cpResult = CP_STATUS_OK;
+ CertProfileViolations violations = CP_NO_VIOLATIONS;
+
+ mbedtls_x509_crt rootCert;
+ mbedtls_x509_crt intCert;
+
+ InitTestCert(&rootCert);
+ InitTestCert(&intCert);
+
+ cpResult = GenerateInternalCert(CERT_CA_ROOT, NULL, &rootCert);
+ EXPECT_TRUE(CP_STATUS_OK == cpResult);
+ VERIFY_SUCCESS_OR_RETURN(TAG, (CP_STATUS_OK == cpResult), "Could not generate issuing Root CA cert", ERROR);
+ violations = ValidateRootCACertProfile(&rootCert);
+ EXPECT_TRUE(violations == CP_NO_VIOLATIONS);
+ VERIFY_SUCCESS_OR_RETURN(TAG, (violations == CP_NO_VIOLATIONS), "Invalid Internal Root CA cert generated ", ERROR);
+
+ cpResult = GenerateInternalCert(CERT_CA_INT , &rootCert, &intCert);
+ EXPECT_TRUE(CP_STATUS_OK == cpResult);
+ if (CP_STATUS_OK == cpResult)
+ {
+ violations = ValidateIntermediateCACertProfile(&intCert);
+ EXPECT_TRUE(violations == CP_NO_VIOLATIONS);
+ }
+ else
+ {
+ OIC_LOG(ERROR, TAG, "Could not generate internal CA test cert");
+ }
+
+ FreeTestCert(&rootCert);
+ FreeTestCert(&intCert);
+}
+
+TEST_F(CACertProfileTests, InternalEndEntityCert)
+{
+ CertProfileResult cpResult = CP_STATUS_OK;
+ CertProfileViolations violations = CP_NO_VIOLATIONS;
+
+ mbedtls_x509_crt rootCert;
+ mbedtls_x509_crt intCert;
+ mbedtls_x509_crt eeCert;
+
+ InitTestCert(&rootCert);
+ InitTestCert(&intCert);
+ InitTestCert(&eeCert);
+
+ cpResult = GenerateInternalCert(CERT_CA_ROOT, NULL, &rootCert);
+ EXPECT_TRUE(CP_STATUS_OK == cpResult);
+ VERIFY_SUCCESS_OR_RETURN(TAG, (CP_STATUS_OK == cpResult), "Could not generate issuing Root CA cert", ERROR);
+ violations = ValidateRootCACertProfile(&rootCert);
+ EXPECT_TRUE(violations == CP_NO_VIOLATIONS);
+ VERIFY_SUCCESS_OR_RETURN(TAG, (violations == CP_NO_VIOLATIONS), "Invalid Internal Root CA cert generated ", ERROR);
+
+ cpResult = GenerateInternalCert(CERT_CA_INT, &rootCert, &intCert);
+ EXPECT_TRUE(CP_STATUS_OK == cpResult);
+ VERIFY_SUCCESS_OR_RETURN(TAG, (CP_STATUS_OK == cpResult), "Could not generate issuing Intermediate CA cert", ERROR);
+ violations = ValidateIntermediateCACertProfile(&intCert);
+ EXPECT_TRUE(violations == CP_NO_VIOLATIONS);
+ VERIFY_SUCCESS_OR_RETURN(TAG, (violations == CP_NO_VIOLATIONS), "Invalid Internal Intermediate CA cert generated ", ERROR);
+
+ cpResult = GenerateInternalCert(CERT_EE, &intCert, &eeCert);
+ EXPECT_TRUE(CP_STATUS_OK == cpResult);
+ if (CP_STATUS_OK == cpResult)
+ {
+ violations = ValidateEndEntityCertProfile(&eeCert);
+ EXPECT_TRUE(violations == CP_NO_VIOLATIONS);
+ }
+ else
+ {
+ OIC_LOG(ERROR, TAG, "Could not generate internal CA test cert");
+ }
+
+ FreeTestCert(&rootCert);
+ FreeTestCert(&intCert);
+ InitTestCert(&eeCert);
+}
+
+TEST_F(CACertProfileTests, VerifyInternalCertChain)
+{
+ CertProfileResult cpResult = CP_STATUS_OK;
+ CertProfileViolations violations = CP_NO_VIOLATIONS;
+ int mbedRet = 0;
+
+ mbedtls_x509_crt rootCert;
+ mbedtls_x509_crt intCert;
+ mbedtls_x509_crt eeCert;
+ mbedtls_x509_crt *certChain;
+
+ InitTestCert(&rootCert);
+ InitTestCert(&intCert);
+ InitTestCert(&eeCert);
+
+ cpResult = GenerateInternalCert(CERT_CA_ROOT, NULL, &rootCert);
+ EXPECT_TRUE(CP_STATUS_OK == cpResult);
+ VERIFY_SUCCESS_OR_RETURN(TAG, (CP_STATUS_OK == cpResult), "Could not generate issuing Root CA cert", ERROR);
+ violations = ValidateRootCACertProfile(&rootCert);
+ EXPECT_TRUE(violations == CP_NO_VIOLATIONS);
+ VERIFY_SUCCESS_OR_RETURN(TAG, (violations == CP_NO_VIOLATIONS), "Invalid Internal Root CA cert generated ", ERROR);
+
+ cpResult = GenerateInternalCert(CERT_CA_INT, &rootCert, &intCert);
+ EXPECT_TRUE(CP_STATUS_OK == cpResult);
+ VERIFY_SUCCESS_OR_RETURN(TAG, (CP_STATUS_OK == cpResult), "Could not generate issuing Intermediate CA cert", ERROR);
+ violations = ValidateIntermediateCACertProfile(&intCert);
+ EXPECT_TRUE(violations == CP_NO_VIOLATIONS);
+ VERIFY_SUCCESS_OR_RETURN(TAG, (violations == CP_NO_VIOLATIONS), "Invalid Internal Intermediate CA cert generated ", ERROR);
+
+ cpResult = GenerateInternalCert(CERT_EE, &intCert, &eeCert);
+ EXPECT_TRUE(CP_STATUS_OK == cpResult);
+ VERIFY_SUCCESS_OR_RETURN(TAG, (CP_STATUS_OK == cpResult), "Could not generate End Entity CA cert", ERROR);
+ EXPECT_TRUE(violations == CP_NO_VIOLATIONS);
+ VERIFY_SUCCESS_OR_RETURN(TAG, (violations == CP_NO_VIOLATIONS), "Invalid Internal End Entity cert generated ", ERROR);
+
+ uint32_t flags;
+ certChain = &eeCert;
+ certChain->next = &intCert;
+ mbedRet = mbedtls_x509_crt_verify_with_profile(
+ certChain, &rootCert, NULL,
+ &s_certProfile, NULL,
+ &flags, NULL, NULL);
+ EXPECT_TRUE(0 == mbedRet);
+
+ FreeTestCert(&rootCert);
+ FreeTestCert(&intCert);
+ InitTestCert(&eeCert);
+}
+
+
+//*****************************************************************************
+// Helper fxns
+//*****************************************************************************
+
+static CertProfileResult SetNotBefore(ValidityTime notBefore, bool invalid)
+{
+ time_t nowTimeT = time(NULL);
+ struct tm *now = gmtime(&nowTimeT);
+
+ if (invalid)
+ {
+ now->tm_year += 10;
+ }
+
+ if (0 == strftime(notBefore, sizeof(ValidityTime), "%Y%m%d%H%M%S", now))
+ {
+ return CP_DATE_ERROR;
+ }
+ return CP_STATUS_OK;
+}
+
+static CertProfileResult SetNotAfter(ValidityTime notAfter, bool invalid)
+{
+ time_t nowTimeT = time(NULL);
+ struct tm *now = gmtime(&nowTimeT);
+
+ if (invalid)
+ {
+ now->tm_year -= 10;
+ }
+ else
+ {
+ now->tm_year += 10;
+ }
+
+ if (0 == strftime(notAfter, sizeof(ValidityTime), "%Y%m%d%H%M%S", now))
+ {
+ return CP_DATE_ERROR;
+ }
+ return CP_STATUS_OK;
+}
+
+// returns length of constructed byte stream, or -1 on error
+static int constructEku( unsigned int numOids, const OCByteString **oidList, unsigned char *buf, unsigned int buflen)
+{
+ size_t encodingLen = 0;
+ unsigned char *curPtr = buf;
+ unsigned char *bufEnd = buf+buflen;
+
+ // add header
+ if ( (curPtr + s_ekuHeader.len > bufEnd) ||
+ (encodingLen + s_ekuHeader.len) > 127)
+ {
+ return -1;
+ }
+ memcpy(curPtr, s_ekuHeader.bytes, s_ekuHeader.len);
+ encodingLen += s_ekuHeader.len;
+ curPtr += s_ekuHeader.len;
+
+ // add supplied OIDs
+ for ( unsigned int i = 0; i < numOids; i++ )
+ {
+ if ( (curPtr + oidList[i]->len > bufEnd) ||
+ (encodingLen + s_ekuHeader.len) > 127)
+ {
+ return -1;
+ }
+ memcpy(curPtr, oidList[i]->bytes, oidList[i]->len);
+ encodingLen += oidList[i]->len;
+ curPtr += oidList[i]->len;
+ }
+
+ // write the length into the encoding (2nd byte), only supporting short form
+ if ( encodingLen > 127 )
+ {
+ return -1;
+ }
+ *(buf+1) = (unsigned char)(encodingLen - s_ekuHeader.len);
+
+ return (int)encodingLen;
+}
+
+// must call InitTestCert before calling, and FreeTestCert when done
+static CertProfileResult GenerateTestCert(CertType certType, CertProfileViolations violations, mbedtls_x509_crt *outCert)
+{
+ OC_UNUSED(s_eePrivKey);
+
+ int mbedRet = 0;
+ CertProfileResult cpResult = CP_STATUS_OK;
+
+ char buf[2048];
+ char mbedErrBuf[256];
+
+ int isCa = 0;
+ int maxPathLen = 0;
+ unsigned int usage = 0;
+ bool makeDateInvalid = false;
+
+ mbedtls_x509write_cert outCertCtx;
+ mbedtls_pk_context subjectPubKeyCtx;
+ mbedtls_pk_context issuerPrivKeyCtx;
+ mbedtls_mpi serialMpi;
+ mbedtls_entropy_context entropy;
+ mbedtls_ctr_drbg_context ctr_drbg;
+
+ mbedtls_x509write_crt_init(&outCertCtx);
+ mbedtls_pk_init(&subjectPubKeyCtx);
+ mbedtls_pk_init(&issuerPrivKeyCtx);
+ mbedtls_mpi_init(&serialMpi);
+ mbedtls_entropy_init(&entropy);
+ mbedtls_ctr_drbg_init(&ctr_drbg);
+
+ const char *subjectPubKey = NULL;
+ const char *issuerPrivKey = NULL;
+ const char *serial = NULL;
+ const char *subject = NULL;
+ const char *issuer = NULL;
+
+ switch ( certType )
+ {
+ case CERT_CA_ROOT:
+ subjectPubKey = (violations & CP_INVALID_PUB_KEY_ALGORITHM) ? s_nonEccPubKey : s_rootCaPubKey;
+ issuerPrivKey = (violations & CP_INVALID_PUB_KEY_ALGORITHM) ? s_nonEccPrivKey : s_rootCaPrivKey;
+ serial = s_rootCaSerial;
+ subject = s_rootCaSubject;
+ issuer = (violations & CP_INVALID_ISSUER_SUBJ_MISMATCH) ? s_eeIssuer : s_rootCaIssuer;
+ break;
+ case CERT_CA_INT:
+ subjectPubKey = (violations & CP_INVALID_PUB_KEY_ALGORITHM) ? s_nonEccPubKey : s_intCaPubKey;
+ issuerPrivKey = (violations & CP_INVALID_PUB_KEY_ALGORITHM) ? s_nonEccPrivKey : s_rootCaPrivKey;
+ serial = s_intCaSerial;
+ subject = s_intCaSubject;
+ issuer = s_intCaIssuer;
+ break;
+ case CERT_EE:
+ subjectPubKey = (violations & CP_INVALID_PUB_KEY_ALGORITHM) ? s_nonEccPubKey : s_eePubKey;
+ issuerPrivKey = (violations & CP_INVALID_PUB_KEY_ALGORITHM) ? s_nonEccPrivKey : s_intCaPrivKey;
+ serial = s_eeSerial;
+ subject = s_eeSubject;
+ issuer = s_eeIssuer;
+ break;
+ default:
+ OIC_LOG(ERROR, TAG, "Unknown cert type for internal cert generation");
+ return CP_STATUS_FAILED;
+ };
+
+ // Set up
+
+ mbedRet = mbedtls_mpi_read_string(&serialMpi, 10, serial);
+ CP_LOG_MBED_ERROR(TAG, mbedRet, mbedErrBuf, sizeof(mbedErrBuf), ERROR);
+ cpResult = (0 == mbedRet) ? CP_STATUS_OK : CP_STATUS_FAILED;
+ VERIFY_SUCCESS_OR_EXIT(TAG, (0 == mbedRet), "Problem reading serial number", ERROR);
+
+ mbedRet = mbedtls_pk_parse_public_key(&subjectPubKeyCtx, (const uint8_t *)subjectPubKey, strlen(subjectPubKey) + 1);
+ CP_LOG_MBED_ERROR(TAG, mbedRet, mbedErrBuf, sizeof(mbedErrBuf), ERROR);
+ cpResult = (0 == mbedRet) ? CP_STATUS_OK : CP_STATUS_FAILED;
+ VERIFY_SUCCESS_OR_EXIT(TAG, (0 == mbedRet), "Problem parsing public key", ERROR);
+
+ mbedRet = mbedtls_pk_parse_key(&issuerPrivKeyCtx, (const uint8_t *)issuerPrivKey, strlen(issuerPrivKey) + 1, NULL, 0);
+ CP_LOG_MBED_ERROR(TAG, mbedRet, mbedErrBuf, sizeof(mbedErrBuf), ERROR);
+ cpResult = (0 == mbedRet) ? CP_STATUS_OK : CP_STATUS_FAILED;
+ VERIFY_SUCCESS_OR_EXIT(TAG, (0 == mbedRet), "Problem parsing private key", ERROR);
+
+ mbedRet = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
+ (const uint8_t *)PERSONALIZATION_STRING,
+ sizeof(PERSONALIZATION_STRING));
+ CP_LOG_MBED_ERROR(TAG, mbedRet, mbedErrBuf, sizeof(mbedErrBuf), ERROR);
+ cpResult = (0 == mbedRet) ? CP_STATUS_OK : CP_STATUS_FAILED;
+ VERIFY_SUCCESS_OR_EXIT(TAG, (0 == mbedRet), "Problem setting seed", ERROR);
+
+ mbedtls_ctr_drbg_set_prediction_resistance(&ctr_drbg, MBEDTLS_CTR_DRBG_PR_ON);
+
+ // Validity window
+
+ ValidityTime notValidBefore;
+ makeDateInvalid = (violations & CP_NOT_YET_VALID) ? true : false;
+ cpResult = SetNotBefore(notValidBefore, makeDateInvalid);
+ VERIFY_SUCCESS_OR_EXIT(TAG, (CP_STATUS_OK == cpResult), "Problem setting not before date", ERROR);
+
+ ValidityTime notValidAfter;
+ makeDateInvalid = (violations & CP_EXPIRED) ? true : false;
+ cpResult = SetNotAfter(notValidAfter, makeDateInvalid);
+ VERIFY_SUCCESS_OR_EXIT(TAG, (CP_STATUS_OK == cpResult), "Problem setting not after date", ERROR);
+
+ mbedRet = mbedtls_x509write_crt_set_validity(&outCertCtx, notValidBefore, notValidAfter);
+ CP_LOG_MBED_ERROR(TAG, mbedRet, mbedErrBuf, sizeof(mbedErrBuf), ERROR);
+ cpResult = (0 == mbedRet) ? CP_STATUS_OK : CP_STATUS_FAILED;
+ VERIFY_SUCCESS_OR_EXIT(TAG, (0 == mbedRet), "Problem setting certificate time window", ERROR);
+
+ // Version
+
+ // mbedtls only encodes V3, will fake violations below
+ mbedtls_x509write_crt_set_version(&outCertCtx, MBEDTLS_X509_CRT_VERSION_3);
+
+ // Sig Type
+
+ if (violations & CP_INVALID_SIG_ALGORITHM)
+ {
+ mbedtls_x509write_crt_set_md_alg(&outCertCtx, MBEDTLS_MD_SHA224);
+ }
+ else
+ {
+ mbedtls_x509write_crt_set_md_alg(&outCertCtx, MBEDTLS_MD_SHA256);
+ }
+
+ // Serial Number
+
+ mbedRet = mbedtls_x509write_crt_set_serial(&outCertCtx, &serialMpi);
+ CP_LOG_MBED_ERROR(TAG, mbedRet, mbedErrBuf, sizeof(mbedErrBuf), ERROR);
+ cpResult = (0 == mbedRet) ? CP_STATUS_OK : CP_STATUS_FAILED;
+ VERIFY_SUCCESS_OR_EXIT(TAG, 0 == mbedRet, "Problem writing certificate serial number", ERROR);
+
+ // Subject
+
+ mbedRet = mbedtls_x509write_crt_set_subject_name(&outCertCtx, subject);
+ CP_LOG_MBED_ERROR(TAG, mbedRet, mbedErrBuf, sizeof(mbedErrBuf), ERROR);
+ cpResult = (0 == mbedRet) ? CP_STATUS_OK : CP_STATUS_FAILED;
+ VERIFY_SUCCESS_OR_EXIT(TAG, 0 == mbedRet, "Problem writing certificate subject", ERROR);
+
+ // Issuer
+
+ mbedRet = mbedtls_x509write_crt_set_issuer_name(&outCertCtx, issuer);
+ CP_LOG_MBED_ERROR(TAG, mbedRet, mbedErrBuf, sizeof(mbedErrBuf), ERROR);
+ cpResult = (0 == mbedRet) ? CP_STATUS_OK : CP_STATUS_FAILED;
+ VERIFY_SUCCESS_OR_EXIT(TAG, 0 == mbedRet, "Problem writing certificate issuer", ERROR);
+
+ // Keys
+
+ mbedtls_x509write_crt_set_subject_key(&outCertCtx, &subjectPubKeyCtx);
+ mbedtls_x509write_crt_set_issuer_key(&outCertCtx, &issuerPrivKeyCtx);
+
+ // Basic Constraints
+
+ // mbedtls max_pathlen behaviour:
+ // CA Cert: Expects RFC5280_val as encoding input
+ // Provides RFC5280_val+1 as decoding output, where 0 = not present
+ // EE Cert: Does not encode
+ // Provides 0 as decoding output
+
+ switch (certType)
+ {
+ case CERT_CA_ROOT:
+ isCa = (violations & CP_INVALID_BASIC_CONSTRAINTS_CA) ? 0 : 1;
+ maxPathLen = (violations & CP_INVALID_BASIC_CONSTRAINTS_PATH_LEN) ? 2 :-1;
+ break;
+ case CERT_CA_INT:
+ isCa = (violations & CP_INVALID_BASIC_CONSTRAINTS_CA) ? 0 : 1;
+ maxPathLen = (violations & CP_INVALID_BASIC_CONSTRAINTS_PATH_LEN) ? -1 : 0;
+ break;
+ case CERT_EE:
+ isCa = (violations & CP_INVALID_BASIC_CONSTRAINTS_CA) ? 1 : 0;
+ maxPathLen = (violations & CP_INVALID_BASIC_CONSTRAINTS_PATH_LEN) ? 10 : -1;
+ break;
+ };
+
+ mbedRet = mbedtls_x509write_crt_set_basic_constraints(&outCertCtx, isCa, maxPathLen);
+ CP_LOG_MBED_ERROR(TAG, mbedRet, mbedErrBuf, sizeof(mbedErrBuf), ERROR);
+ cpResult = (0 == mbedRet) ? CP_STATUS_OK : CP_STATUS_FAILED;
+ VERIFY_SUCCESS_OR_EXIT(TAG, 0 == mbedRet, "Problem writing basic constraints", ERROR);
+
+ // Key Usage
+
+ switch (certType)
+ {
+ case CERT_CA_ROOT:
+ usage = MBEDTLS_X509_KU_KEY_CERT_SIGN | MBEDTLS_X509_KU_CRL_SIGN;
+ if (violations & CP_INVALID_KEY_USAGE_MISSING) {
+ usage &= ~MBEDTLS_X509_KU_CRL_SIGN;
+ }
+ if (violations & CP_INVALID_KEY_USAGE_EXTRA) {
+ usage |= MBEDTLS_X509_KU_DIGITAL_SIGNATURE;
+ }
+ break;
+ case CERT_CA_INT:
+ usage = MBEDTLS_X509_KU_KEY_CERT_SIGN | MBEDTLS_X509_KU_CRL_SIGN;
+ if (violations & CP_INVALID_KEY_USAGE_MISSING) {
+ usage &= ~MBEDTLS_X509_KU_KEY_CERT_SIGN;
+ }
+ if (violations & CP_INVALID_KEY_USAGE_EXTRA) {
+ usage |= MBEDTLS_X509_KU_KEY_ENCIPHERMENT;
+ }
+ break;
+ case CERT_EE:
+ usage = MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_KEY_AGREEMENT;
+ if ( violations & CP_INVALID_KEY_USAGE_MISSING ) {
+ usage &= ~MBEDTLS_X509_KU_KEY_AGREEMENT;
+ }
+ if (violations & CP_INVALID_KEY_USAGE_EXTRA) {
+ usage |= MBEDTLS_X509_KU_NON_REPUDIATION;
+ }
+ break;
+ };
+
+ mbedRet = mbedtls_x509write_crt_set_key_usage(&outCertCtx, usage);
+ cpResult = (0 == mbedRet) ? CP_STATUS_OK : CP_STATUS_FAILED;
+ CP_LOG_MBED_ERROR(TAG, mbedRet, mbedErrBuf, sizeof(mbedErrBuf), ERROR);
+ VERIFY_SUCCESS_OR_EXIT(TAG, (0 == mbedRet), "Problem writing key usages", ERROR);
+
+ // Extended Key Usage
+
+ if (CERT_EE == certType)
+ {
+ const OCByteString *oidList[4];
+
+ unsigned int numOids = 0;
+ if (!(violations & CP_INVALID_EKU_NO_SERVER_AUTH))
+ {
+ oidList[numOids] = &s_ekuServerAuthOid;
+ numOids++;
+ }
+
+ if (!(violations & CP_INVALID_EKU_NO_CLIENT_AUTH))
+ {
+ oidList[numOids] = &s_ekuClientAuthOid;
+ numOids++;
+ }
+
+ if (!(violations & CP_INVALID_EKU_NO_OCF_ID_OID))
+ {
+ oidList[numOids] = &s_ekuOcfIdentityOid;
+ numOids++;
+ }
+
+ if (violations & CP_INVALID_EKU_INCLUDES_ANY)
+ {
+ oidList[numOids] = &s_ekuAnyOid;
+ numOids++;
+ }
+
+ int encodingLen = constructEku(numOids, oidList, (unsigned char*)buf, sizeof(buf));
+ cpResult = (0 < encodingLen) ? CP_STATUS_OK : CP_STATUS_FAILED;
+ VERIFY_SUCCESS_OR_EXIT(TAG, (0 < encodingLen), "Insufficient buffer size for EKU encoding", ERROR);
+
+
+ mbedRet = mbedtls_x509write_crt_set_extension(
+ &outCertCtx,
+ MBEDTLS_OID_EXTENDED_KEY_USAGE,
+ MBEDTLS_OID_SIZE(MBEDTLS_OID_EXTENDED_KEY_USAGE), 0,
+ (const unsigned char*)buf, encodingLen);
+ CP_LOG_MBED_ERROR(TAG, mbedRet, mbedErrBuf, sizeof(mbedErrBuf), ERROR);
+ cpResult = (0 == mbedRet) ? CP_STATUS_OK : CP_STATUS_FAILED;
+ VERIFY_SUCCESS_OR_EXIT(TAG, (0 == mbedRet), "Problem writing eku OCF OID", ERROR);
+ }
+
+ // Create the cert
+
+ mbedRet = mbedtls_x509write_crt_pem(&outCertCtx, (uint8_t *)buf, sizeof(buf), mbedtls_ctr_drbg_random, &ctr_drbg);
+ CP_LOG_MBED_ERROR(TAG, mbedRet, mbedErrBuf, sizeof(mbedErrBuf), ERROR);
+ cpResult = (0 == mbedRet) ? CP_STATUS_OK : CP_STATUS_FAILED;
+ VERIFY_SUCCESS_OR_EXIT(TAG, (0 == mbedRet), "Problem writing certificate", ERROR);
+
+ mbedRet = mbedtls_x509_crt_parse(outCert, (const unsigned char*)buf, sizeof(buf));
+ CP_LOG_MBED_ERROR(TAG, mbedRet, mbedErrBuf, sizeof(mbedErrBuf), ERROR);
+ cpResult = (0 == mbedRet) ? CP_STATUS_OK : CP_STATUS_FAILED;
+ VERIFY_SUCCESS_OR_EXIT(TAG, (0 == mbedRet), "Problem parsing cert buffer", ERROR);
+
+ if (violations & CP_INVALID_VERSION )
+ {
+ outCert->version = 1;
+ }
+
+exit:
+ mbedtls_pk_free(&subjectPubKeyCtx);
+ mbedtls_pk_free(&issuerPrivKeyCtx);
+ mbedtls_x509write_crt_free(&outCertCtx);
+ mbedtls_entropy_free(&entropy);
+ mbedtls_ctr_drbg_free(&ctr_drbg);
+
+ return cpResult;
+}
+
+// must call InitTestCert before calling, and FreeTestCert when done
+// pass issuerCert as NULL for root CA
+static CertProfileResult GenerateInternalCert(CertType certType, mbedtls_x509_crt *issuerCert, mbedtls_x509_crt *outCert)
+{
+ char pemBuf[1024];
+ char mbedErrBuf[256];
+
+ CertProfileResult cpResult = CP_STATUS_OK;
+ OCStackResult stackResult = OC_STACK_OK;
+ int mbedRet = 0;
+
+ char *certificate = NULL;
+ size_t certificateLen = 0;
+
+ const char *subjectPubKey = NULL;
+ const char *issuerPrivKey = NULL;
+ const char *serial = NULL;
+ const char *subject = NULL;
+ const char *issuerCertPem = NULL;
+ OicUuid_t subjectUuid;
+
+ switch ( certType )
+ {
+ case CERT_CA_ROOT:
+ subjectPubKey = s_rootCaPubKey;
+ issuerPrivKey = s_rootCaPrivKey;
+ serial = s_rootCaSerial;
+ subject = s_rootCaSubject;
+ break;
+ case CERT_CA_INT:
+ subjectPubKey = s_intCaPubKey;
+ issuerPrivKey = s_rootCaPrivKey;
+ serial = s_intCaSerial;
+ subject = s_intCaSubject;
+ break;
+ case CERT_EE:
+ subjectPubKey = s_eePubKey;
+ issuerPrivKey = s_intCaPrivKey;
+ serial = s_eeSerial;
+ if (!OCConvertStringToUuid(s_eeUuid, subjectUuid.id))
+ {
+ OIC_LOG(ERROR, TAG, "Could not generate end entity cert UUID");
+ cpResult = CP_STATUS_FAILED;
+ goto exit;
+ }
+ break;
+ default:
+ OIC_LOG(ERROR, TAG, "Unknown cert type for internal cert generation");
+ cpResult = CP_STATUS_FAILED;
+ goto exit;
+ };
+
+ ValidityTime notValidBefore;
+ cpResult = SetNotBefore(notValidBefore, false);
+ VERIFY_SUCCESS_OR_EXIT(TAG, (CP_STATUS_OK == cpResult), "Problem setting not before date", ERROR);
+
+ ValidityTime notValidAfter;
+ cpResult = SetNotAfter(notValidAfter, false);
+ VERIFY_SUCCESS_OR_EXIT(TAG, (CP_STATUS_OK == cpResult), "Problem setting not after date", ERROR);
+
+ // need to convert issuer cert to PEM
+ if ( (CERT_CA_ROOT != certType) && (NULL != issuerCert) )
+ {
+ size_t pemLen = 0;
+ mbedRet = mbedtls_pem_write_buffer( "-----BEGIN CERTIFICATE-----\n",
+ "-----END CERTIFICATE-----\n",
+ issuerCert->raw.p, issuerCert->raw.len,
+ (unsigned char*)pemBuf, sizeof(pemBuf), &pemLen );
+ CP_LOG_MBED_ERROR(TAG, mbedRet, mbedErrBuf, sizeof(mbedErrBuf), ERROR);
+ cpResult = (0 == mbedRet) ? CP_STATUS_OK : CP_STATUS_FAILED;
+ VERIFY_SUCCESS_OR_EXIT(TAG, 0 == mbedRet, "Problem generating PEM from issuer cert", ERROR);
+ issuerCertPem = pemBuf;
+ }
+
+ switch ( certType )
+ {
+ case CERT_CA_ROOT:
+ stackResult = OCGenerateRootCACertificate(
+ subject, subjectPubKey,
+ issuerCertPem, issuerPrivKey,
+ serial,
+ notValidBefore, notValidAfter,
+ &certificate, &certificateLen);
+ break;
+ case CERT_CA_INT:
+ stackResult = OCGenerateIntermediateCACertificate(
+ subject, subjectPubKey,
+ issuerCertPem, issuerPrivKey,
+ serial,
+ notValidBefore, notValidAfter,
+ &certificate, &certificateLen);
+ break;
+ case CERT_EE:
+ stackResult = OCGenerateIdentityCertificate(
+ &subjectUuid, subjectPubKey,
+ issuerCertPem, issuerPrivKey,
+ serial,
+ notValidBefore, notValidAfter,
+ &certificate, &certificateLen);
+ break;
+ default:
+ OIC_LOG(ERROR, TAG, "Unknown cert type for internal cert generation");
+ cpResult = CP_STATUS_FAILED;
+ goto exit;
+ };
+ VERIFY_SUCCESS_OR_EXIT(TAG, (OC_STACK_OK == stackResult), "Problem generating internal certificate", ERROR);
+
+ mbedRet = mbedtls_x509_crt_parse(outCert, (const unsigned char*)certificate, certificateLen);
+ CP_LOG_MBED_ERROR(TAG, mbedRet, mbedErrBuf, sizeof(mbedErrBuf), ERROR);
+ cpResult = (0 == mbedRet) ? CP_STATUS_OK : CP_STATUS_FAILED;
+ VERIFY_SUCCESS_OR_EXIT(TAG, (0 == mbedRet), "Problem converting internal cert to mbed format", ERROR);
+
+exit:
+ OICFree(certificate);
+ return cpResult;
+ };
+
+static void InitTestCert(mbedtls_x509_crt *cert)
+{
+ mbedtls_x509_crt_init(cert);
+}
+
+
+static void FreeTestCert(mbedtls_x509_crt *cert)
+{
+ mbedtls_x509_crt_free(cert);
+}
+
char **privateKey, size_t *privateKeyLen);
/**
- * Generate a certificate to act as a Certificate Authority (CA).
+ * Generate a certificate to act as a Root Certificate Authority (CA).
*
* @param subject Comma-separated list of RDN types and values:
* e.g. "C=US, O=Open Connectivity Foundation, CN=Main CA"
*
* @return OC_STACK_OK if successful, error code otherwise
*/
-OCStackResult OC_CALL OCGenerateCACertificate(
+OCStackResult OC_CALL OCGenerateRootCACertificate(
+ 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);
+
+/**
+ * Generate a certificate to act as an Intermediate Certificate Authority (CA).
+ *
+ * @param subject Comma-separated list of RDN types and values:
+ * e.g. "C=US, O=Open Connectivity Foundation, CN=Main CA"
+ * @param subjectPublicKey Subject's public key in PEM format
+ * @param issuerCert Issuer's certificate in PEM format
+ * If this certificate will be self-signed, pass in NULL.
+ * @param issuerPrivateKey Issuer's private key in PEM format
+ * If self-signing (issuerCert is NULL), this must be the private
+ * key corresponding to subjectPublicKey.
+ * @param serial String containing the serial number in ASCII numerals:
+ * e.g., "12345". Caller must ensure each certificate issued by a
+ * CA has a unique serial number, and it is recommended to generate
+ * them randomly by producing 19 random bytes and converting them to
+ * a numerical value. See GenerateRandomSerialNumber().
+ * @param notValidBefore The notValidBefore date in UTC for the certificate in the form YYYYMMDDhhmmss
+ * e.g., "20131231235959" for December 31st 2013 at 23:59:59
+ * @param notValidAfter The notValidAfter date in UTC for the certificate in the form YYYYMMDDhhmmss
+ * e.g., "20140101010203" for January 1st 2014 at 01:02:03
+ * @param[OUT] certificate Pointer to a buffer that will receive the PEM-encoded certificate. Memory will be
+ * allocated internally; caller must call OICFree on certificate when finished to free
+ * its memory.
+ * @param[OUT] certificateLen Variable to receive the size of certificate, which will include the terminating NULL.
+ *
+ * @return OC_STACK_OK if successful, error code otherwise
+ */
+OCStackResult OC_CALL OCGenerateIntermediateCACertificate(
const char *subject,
const char *subjectPublicKey,
const char *issuerCert,
#define VERIFY_SUCCESS(tag, op, logLevel) do{ if (!(op)) \
{OIC_LOG((logLevel), tag, #op " failed!!"); goto exit; } }while(0)
+/**
+ * Macro to verify a conditional, if fails, log supplied message and goto exit
+ * eg: VERIFY_SUCCESS_OR_LOG_AND_EXIT(TAG, OC_STACK_OK == foo(), ERROR);
+ * @note Invoking function must define "exit:" label for goto functionality to work correctly.
+ */
+#define VERIFY_OR_LOG_AND_EXIT(tag, op, msg, logLevel) do{ if (!(op)) \
+ {OIC_LOG((logLevel), tag, msg); goto exit; } }while(0)
+
/**
* Macro to verify expression evaluates to bool true.
* eg: VERIFY_TRUE_OR_EXIT(TAG, OC_STACK_OK == foo(), ERROR);
#define VERIFY_NOT_NULL_RETURN(tag, arg, logLevel, retValue) do { if (NULL == (arg)) \
{ OIC_LOG((logLevel), tag, #arg " is NULL"); return retValue; } } while(0)
+/**
+ * Macro to log an mbedtls error
+ * For mbedtls functions that return 0 as non-error
+ * @note Invoker must provide message buffer, and must include "mbedtls/error.h"
+ */
+#define LOG_MBED_ERROR(tag, ret, buf, bufSize, logLevel) do{ if (0!=(ret)) { \
+ mbedtls_strerror((ret), (buf), (bufSize)); \
+ OIC_LOG_V((logLevel), (tag), "mbedtls error: %s", (buf)); } }while(0)
+
/**
* This method initializes the @ref OicParseQueryIter_t struct.
*
}
typedef enum {
- CA_CERT,
+ ROOT_CA_CERT,
+ INT_CA_CERT,
IDENTITY_CERT,
ROLE_CERT
} CertType;
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)
+ if (ROOT_CA_CERT != certType)
{
printf("Issuer cert/key pair name (do not include .crt, .pub, or .prv): ");
if (NULL == ReadLine(issKeyPairName, sizeof(issKeyPairName)))
f = NULL;
// -- Load issuer cert if applicable --
- if (CA_CERT != certType)
+ if (ROOT_CA_CERT != certType)
{
snprintf(filename, sizeof(filename), "%s.crt", issKeyPairName);
f = fopen(filename, "rb");
// -- Prompt user for subject name --
- if (CA_CERT == certType)
+ if (IDENTITY_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 : ");
switch (certType)
{
- case CA_CERT:
- res = OCGenerateCACertificate(
+ case ROOT_CA_CERT:
+ res = OCGenerateRootCACertificate(
subject,
publicKey.data(),
NULL,
&certificateLen);
break;
+ case INT_CA_CERT:
+ res = OCGenerateIntermediateCACertificate(
+ subject,
+ publicKey.data(),
+ issuerCert.data(),
+ privateKey.data(),
+ serial,
+ notValidBefore,
+ notValidAfter,
+ &certificate,
+ &certificateLen);
+ break;
+
case IDENTITY_CERT:
res = OCGenerateIdentityCertificate(
&subjectUuid,
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(" 2. Generate a self-signed Root CA certificate (requires a key pair for the CA)\n");
+ printf(" 3. Generate an Intermediate CA certificate, signed by a Root CA\n");
+ printf(" (requires the Root CA's private key and certificate\n");
+ printf(" 4. Generate an identity certificate for a particular device UUID\n");
+ printf(" (requires the Root/Intermediate CA's private key and certificate, and the device's public key)\n");
+ printf(" 5. 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");
DoGenKeyPair();
break;
case 2:
- DoGenCertificate(CA_CERT);
+ DoGenCertificate(ROOT_CA_CERT);
break;
case 3:
- DoGenCertificate(IDENTITY_CERT);
+ DoGenCertificate(INT_CA_CERT);
break;
case 4:
+ DoGenCertificate(IDENTITY_CERT);
+ break;
+ case 5:
DoGenCertificate(ROLE_CERT);
break;
case 0:
"creds": [\r
{\r
"credid": 1,\r
- "subjectuuid": "61646d69-6e44-6576-6963-655575696430",\r
+ "subjectuuid": "11111111-1111-1111-1111-111111111111",\r
"credtype": 8,\r
"publicdata": {\r
- "encoding": "oic.sec.encoding.der",\r
- "data": "308201FA3082019FA003020102020105300A06082A8648CE3D04030230683132303006035504030C29757569643A33313331333133312D333133312D333133312D333133312D333133313331333133313331310B3009060355040613024B523110300E060355040A0C0753616D73756E6731133011060355040B0C0A4F434620537562204341301E170D3136313130343134353535335A170D3336313130343134353535335A3068310B3009060355040613024B523110300E060355040A130753616D73756E6731133011060355040B130A4F4346204465766963653132303006035504031329757569643A36313634366436392D366534342D363537362D363936332D3635353537353639363433303059301306072A8648CE3D020106082A8648CE3D030107034200044310BC484A3B33F03B9BC66021B93A2BEA388D49398791C8E10E70437A40548DDA5F389FC16DA44E1A4DDC739D30C1CFD6AC82D141897129D8C162601D804323A33A303830360603551D11042F302D822B7573657269643A38646561366332642D653064392D346536342D383035632D333230316638376336633934300A06082A8648CE3D0403020349003046022100C34554A93FCF4EA1A9CC9783A7F29B6CC2B86FEBCB15495DEECD8548EAB3414B02210090CDD6731FE3BE7E2BE5F13F178B9A59E8DAC8EFBEFBFE4D9F456F629E73AA55"\r
+ "encoding": "oic.sec.encoding.der",\r
+ "data": "308201c230820166a0030201020214189cfc9c5e03a00e787cd8f72c05f02bad9ca6c9300c06082a8648ce3d04030205003040310b3009060355040613025553310c300a060355040a13034f4346312330210603550403131a44455620496e7420434120466f722050726f7620436c69656e74301e170d3138303232323231303935395a170d3238303232323231303935395a30343132303006035504031329757569643a31313131313131312d313131312d313131312d313131312d3131313131313131313131313059301306072a8648ce3d020106082a8648ce3d03010703420004330c7dd98deab941369ca64bfb15399829eefc7676028fd3e434dc940b9f469dd418e1d731f8f588b713a9b5670ae2cbc42257bfa8c126c44021fb3ff87ddf26a348304630090603551d1304023000300e0603551d0f0101ff04040302018830290603551d250422302006082b0601050507030106082b06010505070302060a2b0601040182de7c0106300c06082a8648ce3d04030205000348003045022100bacad2ab82a4b9ffe8e0f83c2182f1977f7f1445d966e4cb76a898abee9de447022065f9c8bcf6d85aa57170cfd0a7e460e0f1e238ed6e17cfaa9c859ab764fa416f"\r
},\r
"credusage": "oic.sec.cred.mfgcert",\r
"privatedata": {\r
- "encoding": "oic.sec.encoding.raw",\r
- "data": "3077020101042074A0348F8CB40E58FABAFAC494C4472CA04BECFEA6340276DFB4BA2F609F1A6FA00A06082A8648CE3D030107A144034200044310BC484A3B33F03B9BC66021B93A2BEA388D49398791C8E10E70437A40548DDA5F389FC16DA44E1A4DDC739D30C1CFD6AC82D141897129D8C162601D804323"\r
+ "encoding": "oic.sec.encoding.raw",\r
+ "data": "30770201010420a7327fd4cab3939e1dac3af863e79d36cc745260240330aca768d573f7aeb39ca00a06082a8648ce3d030107a14403420004330c7dd98deab941369ca64bfb15399829eefc7676028fd3e434dc940b9f469dd418e1d731f8f588b713a9b5670ae2cbc42257bfa8c126c44021fb3ff87ddf26"\r
}\r
- },\r
- {\r
+ },\r
+ {\r
"credid": 2,\r
+ "subjectuuid": "11111111-1111-1111-1111-111111111111",\r
+ "credtype": 8,\r
+ "publicdata": {\r
+ "encoding": "oic.sec.encoding.der",\r
+ "data": "308201cc30820171a00302010202143eb82f1a2ea07f120da3747b359d01dac141cc8b300c06082a8648ce3d04030205003041310b3009060355040613025553310c300a060355040a13034f4346312430220603550403131b44455620526f6f7420434120466f722050726f7620436c69656e74301e170d3138303232323231303932325a170d3238303232323231303932325a3040310b3009060355040613025553310c300a060355040a13034f4346312330210603550403131a44455620496e7420434120466f722050726f7620436c69656e743059301306072a8648ce3d020106082a8648ce3d03010703420004a80432e8346caffcc4c7de41f723bb04a566ac20d610e8df2e40605dd0fd2fbb173c4e6615e03219e8487f4249b046e74175621db8e2ee79242af2e59a8d7c7ca3463044300f0603551d13040830060101ff020100300e0603551d0f0101ff04040302010630210603551d25041a3018060a2b0601040182de7c0106060a2b0601040182de7c0107300c06082a8648ce3d04030205000347003044022001c91215ffb31949eef14f1b5f4529c4414d05b8d4f1bd059d4e96bdaf0f7e5702200b229045fa11bcd546cc0bbcf28ebb5f0a97aa41b0ff3fd2bb7543a88dfde0fe"\r
+ },\r
+ "credusage": "oic.sec.cred.mfgcert"\r
+ },\r
+ {\r
+ "credid": 3,\r
"subjectuuid": "*",\r
"credtype": 8,\r
"publicdata": {\r
- "encoding": "oic.sec.encoding.der",\r
- "data": "308201CF30820175A003020102020101300A06082A8648CE3D04030230683132303006035504030C29757569643A33313331333133312D333133312D333133312D333133312D333133313331333133313331310B3009060355040613024B523110300E060355040A0C0753616D73756E6731133011060355040B0C0A4F434620537562204341301E170D3136313130343132343933325A170D3336313130343132343933325A30683132303006035504030C29757569643A33313331333133312D333133312D333133312D333133312D333133313331333133313331310B3009060355040613024B523110300E060355040A0C0753616D73756E6731133011060355040B0C0A4F4346205375622043413059301306072A8648CE3D020106082A8648CE3D03010703420004A334EF1F497964DF840DF2F5BA2BFD6A0241FAD9C0D8E88A71821A46FD5CF800F5099627BD5473AE495678EB2D6F62474CFAC6C1C8B9DB47FA86373AB8330EBCA310300E300C0603551D13040530030101FF300A06082A8648CE3D0403020348003045022100AF5E06A44002579F13F47B19F299078A7B35FB6B2C707F7CC926319F744F2BB40220533AC74FA77F42AAFEAA2EED7E1BA2A440DEA6A99C7C3377D86AC4231B1D6D3B",\r
- "revstat": false\r
+ "encoding": "oic.sec.encoding.der",\r
+ "data": "308201ca3082016da00302010202147b9f928b0cf7012243be983c5c892eb7a5f3d8b5300c06082a8648ce3d04030205003040310b3009060355040613025553310c300a060355040a13034f4346312330210603550403131a44455620526f6f7420434120466f72204d666720536572766572301e170d3138303232323231313133375a170d3238303232323231313133375a3040310b3009060355040613025553310c300a060355040a13034f4346312330210603550403131a44455620526f6f7420434120466f72204d6667205365727665723059301306072a8648ce3d020106082a8648ce3d03010703420004e6fb0e47db7e1f2b2eed26261e1bd21e5db666519c9376e5d0e026469d56fa6eaac5199ca201f82fd49ac694e072699b9be749e39bd18ca9be70dfb14c82288ea3433041300c0603551d13040530030101ff300e0603551d0f0101ff04040302010630210603551d25041a3018060a2b0601040182de7c0106060a2b0601040182de7c0107300c06082a8648ce3d04030205000349003046022100a3d697f9cfe04483e29aae7bfd5f61b2bfe322ee838ecb75eb2975485275d491022100abc33276d6c6df073b868470959d6b2a0fc53a35bb7726625a7ce28b3e68f390",\r
+ "revstat": false\r
},\r
"credusage": "oic.sec.cred.mfgtrustca"\r
- }\r
+ }\r
],\r
- "rowneruuid": "00000000-0000-0000-0000-000000000000",\r
+ "rowneruuid": "11111111-1111-1111-1111-111111111111",\r
"rt": ["oic.r.cred"],\r
"if": ["oic.if.baseline"]\r
- },\r
+ },\r
"acl": {\r
- "aclist2": [\r
+ "aclist2": [\r
{\r
"aceid": 1,\r
"subject": { "conntype": "anon-clear" },\r
"permission": 14\r
}\r
],\r
- "rowneruuid": "61646d69-6e44-6576-6963-655575696430",\r
- "rt": ["oic.r.acl"],\r
- "if": ["oic.if.baseline"]\r
- },\r
- "pstat": {\r
- "dos": {\r
- "s": 3,\r
- "p": false\r
- },\r
- "isop": true,\r
- "cm": 0,\r
- "tm": 0,\r
- "om": 4,\r
- "sm": 4,\r
- "rowneruuid": "61646d69-6e44-6576-6963-655575696430",\r
- "rt": ["oic.r.pstat"],\r
- "if": ["oic.if.baseline"]\r
- },\r
- "doxm": {\r
- "oxms": [0],\r
- "oxmsel": 0,\r
- "sct": 9,\r
- "owned": true,\r
- "deviceuuid": "61646D69-6E44-6576-6963-655575696430",\r
- "devowneruuid": "61646D69-6E44-6576-6963-655575696430",\r
- "rowneruuid": "61646D69-6E44-6576-6963-655575696430",\r
- "rt": ["oic.r.doxm"],\r
- "if": ["oic.if.baseline"]\r
- }\r
+ "rowneruuid": "11111111-1111-1111-1111-111111111111",\r
+ "rt": ["oic.r.acl"],\r
+ "if": ["oic.if.baseline"]\r
+ },\r
+ "pstat": {\r
+ "dos": {\r
+ "s": 1,\r
+ "p": false\r
+ },\r
+ "isop": false,\r
+ "cm": 2,\r
+ "tm": 0,\r
+ "om": 4,\r
+ "sm": 4,\r
+ "rowneruuid": "11111111-1111-1111-1111-111111111111",\r
+ "rt": ["oic.r.pstat"],\r
+ "if": ["oic.if.baseline"]\r
+ },\r
+ "doxm": {\r
+ "oxms": [2],\r
+ "oxmsel": 2,\r
+ "sct": 9,\r
+ "owned": false,\r
+ "deviceuuid": "11111111-1111-1111-1111-111111111111",\r
+ "devowneruuid": "11111111-1111-1111-1111-111111111111",\r
+ "rowneruuid": "11111111-1111-1111-1111-111111111111",\r
+ "x.org.iotivity.dpc": true,\r
+ "rt": ["oic.r.doxm"],\r
+ "if": ["oic.if.baseline"]\r
+ }\r
}\r
{
- "cred": {
- "creds": [
- {
- "credid": 1,
- "subjectuuid": "4d617566-6163-7475-7265-724365727430",
- "credtype": 8,
- "publicdata": {
- "encoding": "oic.sec.encoding.der",
- "data": "308201F93082019FA003020102020107300A06082A8648CE3D04030230683132303006035504030C29757569643A33313331333133312D333133312D333133312D333133312D333133313331333133313331310B3009060355040613024B523110300E060355040A0C0753616D73756E6731133011060355040B0C0A4F434620537562204341301E170D3136313130343135303830395A170D3336313130343135303830395A3068310B3009060355040613024B523110300E060355040A130753616D73756E6731133011060355040B130A4F4346204465766963653132303006035504031329757569643A36613735373337342D373736662D373236622D343436352D3736353537353639363433303059301306072A8648CE3D020106082A8648CE3D03010703420004A86446F9A4B5A424922F4FB16730C80B21BEF558F792517D7737FDC49FD8CF982910F617805698DD4EE4DDA6C3B30918246B4D3540C74B836B1ECAC1A122B1BAA33A303830360603551D11042F302D822B7573657269643A36373434363731642D323936332D346339322D613862622D333831313762343836353865300A06082A8648CE3D0403020348003045022100D75F26C5D486782C9C8CDAAF3CB60562298E873EDD1C297C64A4112989CF8C65022060625A591EEA2E1B58E1A52B1AD9F086C5F1F265BE8FB8C024CB6C9FC69C9FCC"
- },
- "credusage": "oic.sec.cred.mfgcert",
- "privatedata": {
- "encoding": "oic.sec.encoding.raw",
- "data": "3078020101042100E00D6E162B33F56D50B40E57288DF284F76D5CE7F1F800F7559882AB126B5813A00A06082A8648CE3D030107A14403420004A86446F9A4B5A424922F4FB16730C80B21BEF558F792517D7737FDC49FD8CF982910F617805698DD4EE4DDA6C3B30918246B4D3540C74B836B1ECAC1A122B1BA"
- }
- },
- {
- "credid": 2,
- "subjectuuid": "*",
- "credtype": 8,
- "publicdata": {
- "encoding": "oic.sec.encoding.der",
- "data": "308201CF30820175A003020102020101300A06082A8648CE3D04030230683132303006035504030C29757569643A33313331333133312D333133312D333133312D333133312D333133313331333133313331310B3009060355040613024B523110300E060355040A0C0753616D73756E6731133011060355040B0C0A4F434620537562204341301E170D3136313130343132343933325A170D3336313130343132343933325A30683132303006035504030C29757569643A33313331333133312D333133312D333133312D333133312D333133313331333133313331310B3009060355040613024B523110300E060355040A0C0753616D73756E6731133011060355040B0C0A4F4346205375622043413059301306072A8648CE3D020106082A8648CE3D03010703420004A334EF1F497964DF840DF2F5BA2BFD6A0241FAD9C0D8E88A71821A46FD5CF800F5099627BD5473AE495678EB2D6F62474CFAC6C1C8B9DB47FA86373AB8330EBCA310300E300C0603551D13040530030101FF300A06082A8648CE3D0403020348003045022100AF5E06A44002579F13F47B19F299078A7B35FB6B2C707F7CC926319F744F2BB40220533AC74FA77F42AAFEAA2EED7E1BA2A440DEA6A99C7C3377D86AC4231B1D6D3B",
- "revstat": false
- },
- "credusage": "oic.sec.cred.mfgtrustca"
- }
- ],
- "rowneruuid": "4d617566-6163-7475-7265-724365727430",
- "rt": ["oic.r.cred"],
- "if": ["oic.if.baseline"]
- },
- "acl": {
+ "cred": {
+ "creds": [
+ {
+ "credid": 1,
+ "subjectuuid": "22222222-2222-2222-2222-222222222222",
+ "credtype": 8,
+ "publicdata": {
+ "encoding": "oic.sec.encoding.der",
+ "data": "308201c030820165a003020102021447efad722789c14dd7432c8ad8d107254322981f300c06082a8648ce3d0403020500303f310b3009060355040613025553310c300a060355040a13034f4346312230200603550403131944657620496e7420434120466f72204d666720536572766572301e170d3138303232323231313235345a170d3238303232323231313235345a30343132303006035504031329757569643a32323232323232322d323232322d323232322d323232322d3232323232323232323232323059301306072a8648ce3d020106082a8648ce3d03010703420004e8bc72ef357e44b2cb4c5ecee53d4b5887a7e49189a11de194891a248d78bff123591b969f4e5458fd81adbcbf3d2a456d6c343f850cc588f8d9c29c8777519da348304630090603551d1304023000300e0603551d0f0101ff04040302018830290603551d250422302006082b0601050507030106082b06010505070302060a2b0601040182de7c0106300c06082a8648ce3d0403020500034700304402205ef55c6c7afc4f5ec2ed8a1cb15690c3e366349ad54efd6c0636bd944f20dafa02207c51bc360fc4d343a0de66094dc67d00377b93b6e760be170ba7dc7d33bda3c7"
+ },
+ "credusage": "oic.sec.cred.mfgcert",
+ "privatedata": {
+ "encoding": "oic.sec.encoding.raw",
+ "data": "307702010104205aa7ccc369023bf3594a7048a7a0902c5628852d39efa3a5b21a49be8e7b490aa00a06082a8648ce3d030107a14403420004e8bc72ef357e44b2cb4c5ecee53d4b5887a7e49189a11de194891a248d78bff123591b969f4e5458fd81adbcbf3d2a456d6c343f850cc588f8d9c29c8777519d"
+ }
+ },
+ {
+ "credid": 2,
+ "subjectuuid": "22222222-2222-2222-2222-222222222222",
+ "credtype": 8,
+ "publicdata": {
+ "encoding": "oic.sec.encoding.der",
+ "data": "308201cc3082016fa00302010202143c63b103218a700a32848897865164d9799a6c13300c06082a8648ce3d04030205003040310b3009060355040613025553310c300a060355040a13034f4346312330210603550403131a44455620526f6f7420434120466f72204d666720536572766572301e170d3138303232323231313230305a170d3238303232323231313230305a303f310b3009060355040613025553310c300a060355040a13034f4346312230200603550403131944657620496e7420434120466f72204d6667205365727665723059301306072a8648ce3d020106082a8648ce3d030107034200043b8c398c16c68fce8c0a7dbc9cbb54413ac8ef3198de013a9b33c8b3f420b2206aad8d44033aee18266e23f3211995a7a4b29e0e8bf44aeca47a58ca00972089a3463044300f0603551d13040830060101ff020100300e0603551d0f0101ff04040302010630210603551d25041a3018060a2b0601040182de7c0106060a2b0601040182de7c0107300c06082a8648ce3d0403020500034900304602210095813d2af81116ab69576fd3d9103d29849246700aeb80611cb787059223c369022100fdb4e83be362b40efd202f34107de9920b4ef8ec1f1f57db8ece3acd0e923bed"
+ },
+ "credusage": "oic.sec.cred.mfgcert"
+ },
+ {
+ "credid": 3,
+ "subjectuuid": "*",
+ "credtype": 8,
+ "publicdata": {
+ "encoding": "oic.sec.encoding.der",
+ "data": "308201cc3082016fa003020102021467944d2fdb52be342eacbe332990f229771b0695300c06082a8648ce3d04030205003041310b3009060355040613025553310c300a060355040a13034f4346312430220603550403131b44455620526f6f7420434120466f722050726f7620436c69656e74301e170d3138303232323231303835325a170d3238303232323231303835325a3041310b3009060355040613025553310c300a060355040a13034f4346312430220603550403131b44455620526f6f7420434120466f722050726f7620436c69656e743059301306072a8648ce3d020106082a8648ce3d030107034200041e75544d42938a72c375b73d436ed4600824eee28295a253ff4fdd15a7c41ae96c07be2a3599fae987e039882ebf9ddb7bad000c66dd6145db05a00569643bb4a3433041300c0603551d13040530030101ff300e0603551d0f0101ff04040302010630210603551d25041a3018060a2b0601040182de7c0106060a2b0601040182de7c0107300c06082a8648ce3d04030205000349003046022100a9959d87f3ba6b9846c62804e83e209829de67349cbc1e4434132d677eeb94f2022100a01144a0e0b3f02f329025253c49c7f504763fb3351a6438fca1d2a3339ed321",
+ "revstat": false
+ },
+ "credusage": "oic.sec.cred.mfgtrustca"
+ }
+ ],
+ "rowneruuid": "00000000-0000-0000-0000-000000000000",
+ "rt": ["oic.r.cred"],
+ "if": ["oic.if.baseline"]
+ },
+ "acl": {
"aclist2": [
{
"aceid": 1,
"permission": 14
}
],
- "rowneruuid": "4d617566-6163-7475-7265-724365727430",
+ "rowneruuid": "00000000-0000-0000-0000-000000000000",
"rt": ["oic.r.acl"],
"if": ["oic.if.baseline"]
},
"tm": 0,
"om": 4,
"sm": 4,
- "rowneruuid": "4d617566-6163-7475-7265-724365727430",
+ "rowneruuid": "00000000-0000-0000-0000-000000000000",
"rt": ["oic.r.pstat"],
"if": ["oic.if.baseline"]
},
"oxmsel": 2,
"sct": 9,
"owned": false,
- "deviceuuid": "4d617566-6163-7475-7265-724365727430",
- "devowneruuid": "4d617566-6163-7475-7265-724365727430",
- "rowneruuid": "4d617566-6163-7475-7265-724365727430",
+ "deviceuuid": "22222222-2222-2222-2222-222222222222",
+ "devowneruuid": "00000000-0000-0000-0000-000000000000",
+ "rowneruuid": "00000000-0000-0000-0000-000000000000",
"x.org.iotivity.dpc": true,
"rt": ["oic.r.doxm"],
"if": ["oic.if.baseline"]
}
/* Create a CA certificate */
- res = OCGenerateCACertificate(
+ res = OCGenerateRootCACertificate(
"C=US, O=Open Connectivity Foundation, CN=IoTivity test code CA", // subject
publicKey,
NULL, // Issuer private key is null
&caCertLen);
if (res != OC_STACK_OK)
{
- OIC_LOG_V(ERROR, TAG, "OCGenerateCACertificate failed, error: %d", res);
+ OIC_LOG_V(ERROR, TAG, "OCGenerateRootCACertificate failed, error: %d", res);
goto exit;
}
// headers required for mbed TLS
#include "mbedtls/config.h"
#include "mbedtls/platform.h"
+#include "mbedtls/error.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/x509_csr.h"
#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 identity certificates */
+static const unsigned char s_ekuIdentity[] = {
+ 0x30, 0x20,
+ 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, // serverAuth (1.3.6.1.5.5.7.3.1)
+ 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, // clientAuth (1.3.6.1.5.5.7.3.2)
+ 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0xDE, 0x7C, 0x01, 0x06 // OCF ID OID (1.3.6.1.4.1.44924.1.6)
+};
/* 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 };
}
typedef enum {
- CERT_TYPE_CA,
+ CERT_TYPE_ROOT_CA,
+ CERT_TYPE_INTERMEDIATE_CA,
CERT_TYPE_IDENTITY,
CERT_TYPE_ROLE
} CertificateType_t;
mbedtls_ctr_drbg_context ctr_drbg;
char buf[2048];
+ char mbedErrorBuf[256];
+
if (NULL == subjectPublicKey || NULL == issuerPrivateKey || NULL == subject || NULL == serial ||
NULL == notValidBefore || NULL == notValidAfter)
memset(certificate, 0, sizeof(*certificate));
ret = mbedtls_mpi_read_string(&serialMpi, 10, serial);
- VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+ LOG_MBED_ERROR(TAG, ret, mbedErrorBuf, sizeof(mbedErrorBuf), ERROR);
+ VERIFY_OR_LOG_AND_EXIT(TAG, 0 == ret, "Could not parse serial number for internal cert generation", ERROR);
ret = mbedtls_pk_parse_public_key(&subjKeyCtx, (const uint8_t *)subjectPublicKey, strlen(subjectPublicKey) + 1);
- VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+ LOG_MBED_ERROR(TAG, ret, mbedErrorBuf, sizeof(mbedErrorBuf), ERROR);
+ VERIFY_OR_LOG_AND_EXIT(TAG, 0 == ret, "Could not parse public key for internal cert generation", ERROR);
ret = mbedtls_pk_parse_key(&issKeyCtx, (const uint8_t *)issuerPrivateKey, strlen(issuerPrivateKey) + 1, NULL, 0);
- VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+ LOG_MBED_ERROR(TAG, ret, mbedErrorBuf, sizeof(mbedErrorBuf), ERROR);
+ VERIFY_OR_LOG_AND_EXIT(TAG, 0 == ret, "Could not parse private key for internal cert generation", ERROR);
/* If issuerCert is NULL, then the cert will be self-signed. */
if (NULL != issuerCert)
{
ret = mbedtls_x509_crt_parse(&issCertCtx, (const uint8_t *)issuerCert, strlen(issuerCert) + 1);
- VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+ LOG_MBED_ERROR(TAG, ret, mbedErrorBuf, sizeof(mbedErrorBuf), ERROR);
+ VERIFY_OR_LOG_AND_EXIT(TAG, 0 == ret, "Could not parse issuer cert for internal cert generation", ERROR);
}
ret = mbedtls_x509write_crt_set_validity(&outCertCtx, notValidBefore, notValidAfter);
- VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+ LOG_MBED_ERROR(TAG, ret, mbedErrorBuf, sizeof(mbedErrorBuf), ERROR);
+ VERIFY_OR_LOG_AND_EXIT(TAG, 0 == ret, "Could not write validity time for internal cert generation", ERROR);
mbedtls_x509write_crt_set_version(&outCertCtx, MBEDTLS_X509_CRT_VERSION_3);
mbedtls_x509write_crt_set_md_alg(&outCertCtx, MBEDTLS_MD_SHA256);
ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
&entropy, (const uint8_t *)PERSONALIZATION_STRING, sizeof(PERSONALIZATION_STRING));
- VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+ LOG_MBED_ERROR(TAG, ret, mbedErrorBuf, sizeof(mbedErrorBuf), ERROR);
+ VERIFY_OR_LOG_AND_EXIT(TAG, 0 == ret, "Could not generate seed for internal cert generation", 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);
+ LOG_MBED_ERROR(TAG, ret, mbedErrorBuf, sizeof(mbedErrorBuf), ERROR);
+ VERIFY_OR_LOG_AND_EXIT(TAG, 0 == ret, "Could not write serial number for internal cert generation", ERROR);
ret = mbedtls_x509write_crt_set_subject_name(&outCertCtx, subject);
- VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+ LOG_MBED_ERROR(TAG, ret, mbedErrorBuf, sizeof(mbedErrorBuf), ERROR);
+ VERIFY_OR_LOG_AND_EXIT(TAG, 0 == ret, "Could not write subject name for internal cert generation", 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);
+ VERIFY_OR_LOG_AND_EXIT(TAG, 0 < ret, "Could not parse subject name from issuer for internal cert generation", 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);
+ LOG_MBED_ERROR(TAG, ret, mbedErrorBuf, sizeof(mbedErrorBuf), ERROR);
+ VERIFY_OR_LOG_AND_EXIT(TAG, 0 == ret, "Could not write issuer name for internal cert generation", ERROR);
mbedtls_x509write_crt_set_subject_key(&outCertCtx, &subjKeyCtx);
mbedtls_x509write_crt_set_issuer_key(&outCertCtx, &issKeyCtx);
- if (certType == CERT_TYPE_CA)
+ /*
+ * mbedtls max_pathlen behaviour
+ * CA Cert: Expects RFC5280_val as encoding input
+ * Provides RFC5280_val+1 as decoding output, where 0 = not present
+ * EE Cert: Does not encode
+ * Provides 0 as decoding output
+ */
+
+ if (CERT_TYPE_ROOT_CA == certType)
{
ret = mbedtls_x509write_crt_set_basic_constraints(&outCertCtx, 1, -1);
- VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+ LOG_MBED_ERROR(TAG, ret, mbedErrorBuf, sizeof(mbedErrorBuf), ERROR);
+ VERIFY_OR_LOG_AND_EXIT(TAG, 0 == ret, "Could not write basic constraints for internal root ca cert generation", ERROR);
+ ret = mbedtls_x509write_crt_set_key_usage(&outCertCtx,
+ MBEDTLS_X509_KU_KEY_CERT_SIGN | MBEDTLS_X509_KU_CRL_SIGN);
+ LOG_MBED_ERROR(TAG, ret, mbedErrorBuf, sizeof(mbedErrorBuf), ERROR);
+ VERIFY_OR_LOG_AND_EXIT(TAG, 0 == ret, "Could not write key usage for internal root ca cert generation", ERROR);
+ }
+ else if (CERT_TYPE_INTERMEDIATE_CA == certType)
+ {
+ ret = mbedtls_x509write_crt_set_basic_constraints(&outCertCtx, 1, 0);
+ LOG_MBED_ERROR(TAG, ret, mbedErrorBuf, sizeof(mbedErrorBuf), ERROR);
+ VERIFY_OR_LOG_AND_EXIT(TAG, 0 == ret, "Could not write basic constraints for internal intermediate ca cert generation", 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);
+ MBEDTLS_X509_KU_KEY_CERT_SIGN | MBEDTLS_X509_KU_CRL_SIGN);
+ LOG_MBED_ERROR(TAG, ret, mbedErrorBuf, sizeof(mbedErrorBuf), ERROR);
+ VERIFY_OR_LOG_AND_EXIT(TAG, 0 == ret, "Could not write key usage for internal intermediate ca cert generation", ERROR);
}
else
{
- ret = mbedtls_x509write_crt_set_basic_constraints(&outCertCtx, 0, 0);
- VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+ ret = mbedtls_x509write_crt_set_basic_constraints(&outCertCtx, 0, -1);
+ LOG_MBED_ERROR(TAG, ret, mbedErrorBuf, sizeof(mbedErrorBuf), ERROR);
+ VERIFY_OR_LOG_AND_EXIT(TAG, 0 == ret, "Could not write basic constraints for internal root ee cert generation", 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);
+ MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_KEY_AGREEMENT);
+ LOG_MBED_ERROR(TAG, ret, mbedErrorBuf, sizeof(mbedErrorBuf), ERROR);
+ VERIFY_OR_LOG_AND_EXIT(TAG, 0 == ret, "Could not write key usage for internal ee cert generation", ERROR);
}
switch (certType)
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);
+ LOG_MBED_ERROR(TAG, ret, mbedErrorBuf, sizeof(mbedErrorBuf), ERROR);
+ VERIFY_OR_LOG_AND_EXIT(TAG, 0 == ret, "Could not write eku for internal role cert generation", ERROR);
ret = snprintf(buf, sizeof(buf), "CN=%s%s%s", role, (NULL != authority) ? ",OU=" : "", (NULL != authority) ? authority : "");
// To prevent sign-compare warning sizeof(buf) is cast to int. This is safe because the max size of buf fits into int.
// Note ret value from snprintf may be negative if there was an error so it should not be cast to size_t.
- VERIFY_SUCCESS(TAG, ret < (int)sizeof(buf), ERROR);
+ VERIFY_OR_LOG_AND_EXIT(TAG, ret < (int)sizeof(buf), "snprintf error during internal cert generation", 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);
+ LOG_MBED_ERROR(TAG, ret, mbedErrorBuf, sizeof(mbedErrorBuf), ERROR);
+ VERIFY_OR_LOG_AND_EXIT(TAG, 0 == ret, "Could not parse direcotry name for internal role cert generation", ERROR);
ret = mbedtls_x509write_crt_set_subject_alt_names(&outCertCtx, &names);
- VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+ LOG_MBED_ERROR(TAG, ret, mbedErrorBuf, sizeof(mbedErrorBuf), ERROR);
+ VERIFY_OR_LOG_AND_EXIT(TAG, 0 == ret, "Could not write subject alt names for internal role cert generation", ERROR);
break;
case CERT_TYPE_IDENTITY:
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);
+ LOG_MBED_ERROR(TAG, ret, mbedErrorBuf, sizeof(mbedErrorBuf), ERROR);
+ VERIFY_OR_LOG_AND_EXIT(TAG, 0 == ret, "Could not write eku for internal ee cert generation", ERROR);
break;
- case CERT_TYPE_CA:
+ case CERT_TYPE_ROOT_CA:
+ case CERT_TYPE_INTERMEDIATE_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);
+ LOG_MBED_ERROR(TAG, ret, mbedErrorBuf, sizeof(mbedErrorBuf), ERROR);
+ VERIFY_OR_LOG_AND_EXIT(TAG, 0 == ret, "Could not write eku for internal root/int ca cert generation", ERROR);
break;
default:
assert(false);
- VERIFY_SUCCESS(TAG, false, ERROR);
+ VERIFY_OR_LOG_AND_EXIT(TAG, false, "Unkown cert type during internal cert generation", ERROR);
}
ret = mbedtls_x509write_crt_pem(&outCertCtx, (uint8_t *)buf, sizeof(buf), mbedtls_ctr_drbg_random, &ctr_drbg);
- VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+ LOG_MBED_ERROR(TAG, ret, mbedErrorBuf, sizeof(mbedErrorBuf), ERROR);
+ VERIFY_OR_LOG_AND_EXIT(TAG, 0 == ret, "Could not generate pem buffer for internal cert generation", ERROR);
certificate->len = strlen(buf) + 1;
certificate->bytes = (uint8_t *)OICCalloc(1, certificate->len);
return res;
}
-OCStackResult OC_CALL OCGenerateCACertificate(
+OCStackResult OC_CALL OCGenerateRootCACertificate(
+ 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_ROOT_CA,
+ subject,
+ subjectPublicKey,
+ issuerCert,
+ issuerPrivateKey,
+ serial,
+ notValidBefore,
+ notValidAfter,
+ NULL,
+ NULL,
+ &byteStr);
+
+ if (OC_STACK_OK == res)
+ {
+ *certificate = (char *)byteStr.bytes;
+ *certificateLen = byteStr.len;
+ }
+
+ return res;
+}
+
+OCStackResult OC_CALL OCGenerateIntermediateCACertificate(
const char *subject,
const char *subjectPublicKey,
const char *issuerCert,
OCByteString byteStr = { 0 };
res = GenerateCertificate(
- CERT_TYPE_CA,
+ CERT_TYPE_INTERMEDIATE_CA,
subject,
subjectPublicKey,
issuerCert,
OCDiscoverSingleDeviceInUnicast
OCDiscoverUnownedDevices
OCDoOwnershipTransfer
-OCGenerateCACertificate
OCGenerateIdentityCertificate
+OCGenerateIntermediateCACertificate
OCGenerateKeyPair
OCGenerateRandomSerialNumber
OCGenerateRoleCertificate
+OCGenerateRootCACertificate
OCGetACLResource
OCGetACL2Resource
OCGetCredResource