Merge branch 'master' into iot-1785
authorKevin Kane <kkane@microsoft.com>
Wed, 22 Mar 2017 02:26:26 +0000 (19:26 -0700)
committerKevin Kane <kkane@microsoft.com>
Wed, 22 Mar 2017 02:26:30 +0000 (19:26 -0700)
Change-Id: If30ba205d4fcb0b5dc969f83d464509a8059ef3f
Signed-off-by: Kevin Kane <kkane@microsoft.com>
47 files changed:
extlibs/mbedtls/config-iotivity.h
resource/csdk/connectivity/api/cacommon.h
resource/csdk/connectivity/api/casecurityinterface.h
resource/csdk/connectivity/inc/ca_adapter_net_ssl.h
resource/csdk/connectivity/src/adapter_util/ca_adapter_net_ssl.c
resource/csdk/connectivity/src/caconnectivitymanager.c
resource/csdk/connectivity/test/ca_api_unittest.cpp
resource/csdk/connectivity/test/ssladapter_test.cpp
resource/csdk/security/SConscript
resource/csdk/security/include/internal/aclresource.h
resource/csdk/security/include/internal/certhelpers.h [new file with mode: 0644]
resource/csdk/security/include/internal/credresource.h
resource/csdk/security/include/internal/csrresource.h [new file with mode: 0644]
resource/csdk/security/include/internal/rolesresource.h [new file with mode: 0644]
resource/csdk/security/include/internal/srmresourcestrings.h
resource/csdk/security/include/occertutility.h [new file with mode: 0644]
resource/csdk/security/include/securevirtualresourcetypes.h
resource/csdk/security/provisioning/include/internal/secureresourceprovider.h
resource/csdk/security/provisioning/include/ocprovisioningmanager.h
resource/csdk/security/provisioning/include/pmtypes.h
resource/csdk/security/provisioning/sample/SConscript
resource/csdk/security/provisioning/sample/autoprovisioningclient.c [new file with mode: 0644]
resource/csdk/security/provisioning/sample/certgenerator.cpp [new file with mode: 0644]
resource/csdk/security/provisioning/sample/provisioningTest.py [new file with mode: 0644]
resource/csdk/security/provisioning/sample/provisioningclient.c
resource/csdk/security/provisioning/sample/subownerclient.c
resource/csdk/security/provisioning/src/cloud/aclid.c
resource/csdk/security/provisioning/src/ocprovisioningmanager.c
resource/csdk/security/provisioning/src/ownershiptransfermanager.c
resource/csdk/security/provisioning/src/secureresourceprovider.c
resource/csdk/security/provisioning/unittest/secureresourceprovider.cpp
resource/csdk/security/src/aclresource.c
resource/csdk/security/src/certhelpers.c [new file with mode: 0644]
resource/csdk/security/src/credresource.c
resource/csdk/security/src/csrresource.c [new file with mode: 0644]
resource/csdk/security/src/doxmresource.c
resource/csdk/security/src/dpairingresource.c
resource/csdk/security/src/occertutility.c [new file with mode: 0644]
resource/csdk/security/src/policyengine.c
resource/csdk/security/src/resourcemanager.c
resource/csdk/security/src/rolesresource.c [new file with mode: 0644]
resource/csdk/security/src/secureresourcemanager.c
resource/csdk/security/src/srmresourcestrings.c
resource/csdk/security/tool/json2cbor.c
resource/csdk/security/unittest/aclresourcetest.cpp
resource/csdk/security/unittest/credentialresource.cpp
resource/csdk/stack/octbstack_product_secured.def

index 8f2082c..38ebdc5 100644 (file)
 #define MBEDTLS_X509_RSASSA_PSS_SUPPORT
 
 /**
+ * \def MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT
+ *
+ * Enable parsing of all supported subtypes of the Subject Alternative Name
+ * extension. When enabled, the subject_alt_names field of mbedtls_x509_crt
+ * is defined as an mbedtls_x509_subject_alt_name_sequence, each element of
+ * which can describe a different subtype of the GeneralName choice as defined
+ * by the standard.
+ *
+ * Comment this macro to only support dNSName subtypes, and to define the
+ * subject_alt_names field as an mbedtls_x509_sequence. Any other subtypes will
+ * be ignored. This was the behavior in earlier versions.
+ */
+#define MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT
+
+/**
  * \def MBEDTLS_ZLIB_SUPPORT
  *
  * If set, the SSL/TLS module uses ZLIB to support compression and
index 340a8a0..867beee 100644 (file)
@@ -128,6 +128,18 @@ extern "C"
 #define CA_OPTION_URI_QUERY 15
 #define CA_OPTION_ACCEPT 17
 #define CA_OPTION_LOCATION_QUERY 20
+        
+/**
+ * @def UUID_PREFIX
+ * @brief uuid prefix in certificate subject field
+ */
+#define UUID_PREFIX "uuid:"
+
+/**
+ * @def SUBJECT_PREFIX
+ * @brief prefix for specifying part of a cert's subject for a particular uuid
+ */
+#define SUBJECT_PREFIX "CN=" UUID_PREFIX
 
 /**
 * TODO: Move these COAP defines to CoAP lib once approved.
@@ -316,6 +328,8 @@ typedef struct
 #endif
 } CAEndpoint_t;
 
+#define CA_SECURE_ENDPOINT_PUBLIC_KEY_MAX_LENGTH    (128)
+
 /**
  * Endpoint information for secure messages.
  */
@@ -326,6 +340,8 @@ typedef struct
     CARemoteId_t identity;      /**< endpoint device uuid */
     CARemoteId_t userId;        /**< endpoint user uuid */
     uint32_t attributes;
+    uint8_t publicKey[CA_SECURE_ENDPOINT_PUBLIC_KEY_MAX_LENGTH]; /**< Peer's DER-encoded public key (if using certificate) */
+    size_t publicKeyLength;     /**< Length of publicKey; zero if not using certificate */
 } CASecureEndpoint_t;
 
 /**
index 1318d2d..1238a48 100644 (file)
@@ -72,10 +72,11 @@ typedef int (*CAgetPskCredentialsHandler)(CADtlsPskCredType_t type,
  * API to get a secure connected peer information
  *
  * @param[in] peer peer information includs IP address and port.
+ * @param[out] sep copy of secure endpoint info
  *
- * @return  secure connected peer information on success, otherwise NULL
+ * @return  CA_STATUS_OK on success; other error otherwise
  */
-const CASecureEndpoint_t *CAGetSecureEndpointData(const CAEndpoint_t *peer);
+CAResult_t CAGetSecureEndpointData(const CAEndpoint_t *peer, CASecureEndpoint_t *sep);
 #endif //MULTIPLE_OWNER
 
 /**
index 12cde83..464341e 100644 (file)
@@ -179,16 +179,15 @@ CAResult_t CAsslGenerateOwnerPsk(const CAEndpoint_t *endpoint,
                     const uint8_t* provServerDeviceId, const size_t provServerDeviceIdLen,
                     uint8_t* ownerPsk, const size_t ownerPskSize);
 
-#ifdef MULTIPLE_OWNER
 /**
- * Gets CA secure endpoint info corresponding for endpoint.
+ * Gets a copy of CA secure endpoint info corresponding for endpoint.
  *
  * @param[in]  peer    remote address
+ * @param[out] sep     copy of secure endpoint data
  *
- * @return  CASecureEndpoint or NULL
+ * @return  CA_STATUS_OK on success; other error code on failure
  */
-const CASecureEndpoint_t *GetCASecureEndpointData(const CAEndpoint_t* peer);
-#endif
+CAResult_t GetCASecureEndpointData(const CAEndpoint_t* peer, CASecureEndpoint_t *sep);
 
 /**
  * Adds a bit to the attributes field of a secure endpoint.
index ece2431..dd28412 100755 (executable)
@@ -25,6 +25,7 @@
 
 #include <stddef.h>
 #include <stdbool.h>
+#include <assert.h>
 #include "ca_adapter_net_ssl.h"
 #include "cacommon.h"
 #include "caipinterface.h"
@@ -42,6 +43,7 @@
 #include "mbedtls/pkcs12.h"
 #include "mbedtls/ssl_internal.h"
 #include "mbedtls/net_sockets.h"
+#include "mbedtls/oid.h"
 #ifdef __WITH_DTLS__
 #include "mbedtls/timing.h"
 #include "mbedtls/ssl_cookie.h"
  */
 #define PERSONALIZATION_STRING "IOTIVITY_RND"
 /**
- * @def UUID_PREFIX
- * @brief uuid prefix in certificate subject field
- */
-#define UUID_PREFIX "uuid:"
-/**
  * @def USERID_PREFIX
  * @brief userid prefix in certificate alternative subject name field
  */
@@ -850,15 +847,15 @@ static SslEndPoint_t *GetSslPeer(const CAEndpoint_t *peer)
     return NULL;
 }
 
-#ifdef MULTIPLE_OWNER
 /**
- * Gets CA secure endpoint info corresponding for endpoint.
+ * Gets a copy of CA secure endpoint info corresponding for endpoint.
  *
  * @param[in]  peer    remote address
+ * @param[out] sep     copy of secure endpoint data
  *
- * @return  CASecureEndpoint or NULL
+ * @return  CA_STATUS_OK on success; other error code on failure
  */
-const CASecureEndpoint_t *GetCASecureEndpointData(const CAEndpoint_t* peer)
+CAResult_t GetCASecureEndpointData(const CAEndpoint_t* peer, CASecureEndpoint_t* sep)
 {
     OIC_LOG_V(DEBUG, NET_SSL_TAG, "In %s", __func__);
 
@@ -867,23 +864,23 @@ const CASecureEndpoint_t *GetCASecureEndpointData(const CAEndpoint_t* peer)
     {
         OIC_LOG(ERROR, NET_SSL_TAG, "Context is NULL");
         oc_mutex_unlock(g_sslContextMutex);
-        return NULL;
+        return CA_STATUS_NOT_INITIALIZED;
     }
 
     SslEndPoint_t* sslPeer = GetSslPeer(peer);
     if(sslPeer)
     {
         OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
+        memcpy(sep, &sslPeer->sep, sizeof(sslPeer->sep));
         oc_mutex_unlock(g_sslContextMutex);
-        return &sslPeer->sep;
+        return CA_STATUS_OK;
     }
 
     OIC_LOG(DEBUG, NET_SSL_TAG, "Return NULL");
     OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
     oc_mutex_unlock(g_sslContextMutex);
-    return NULL;
+    return CA_STATUS_INVALID_PARAM;
 }
-#endif
 
 /**
  * Adds a bit to the attributes field of a secure endpoint.
@@ -1338,7 +1335,7 @@ static void SetupCipher(mbedtls_ssl_config * config, CATransportAdapter_t adapte
 
     g_getCredentialTypesCallback(g_caSslContext->cipherFlag);
     // Retrieve the PSK credential from SRM
-    if (0 != InitPskIdentity(config))
+    if (true == g_caSslContext->cipherFlag[0] && 0 != InitPskIdentity(config))
     {
         OIC_LOG(ERROR, NET_SSL_TAG, "PSK identity initialization failed!");
     }
@@ -2053,10 +2050,9 @@ CAResult_t CAdecryptSsl(const CASecureEndpoint_t *sep, uint8_t *data, size_t dat
             if (MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 != selectedCipher &&
                 MBEDTLS_TLS_ECDH_ANON_WITH_AES_128_CBC_SHA256 != selectedCipher)
             {
-                char uuid[UUID_LENGTH * 2 + 5] = {0};
-                void * uuidPos = NULL;
-                void * userIdPos = NULL;
                 const mbedtls_x509_crt * peerCert = mbedtls_ssl_get_peer_cert(&peer->ssl);
+                const mbedtls_x509_name * name = NULL;
+                uint8_t pubKeyBuf[CA_SECURE_ENDPOINT_PUBLIC_KEY_MAX_LENGTH] = { 0 };
                 ret = (NULL == peerCert ? -1 : 0);
                 if (!checkSslOperation(peer,
                                        ret,
@@ -2067,50 +2063,116 @@ CAResult_t CAdecryptSsl(const CASecureEndpoint_t *sep, uint8_t *data, size_t dat
                     OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
                     return CA_STATUS_FAILED;
                 }
-                uuidPos = memmem(peerCert->subject_raw.p, peerCert->subject_raw.len,
-                                                 UUID_PREFIX, sizeof(UUID_PREFIX) - 1);
 
-                if (NULL != uuidPos)
+                /* mbedtls_pk_write_pubkey_der takes a non-const mbedtls_pk_context, but inspection
+                 * shows that every place it's used internally treats it as const, so casting its
+                 * constness away is safe.
+                 */
+                ret = mbedtls_pk_write_pubkey_der((mbedtls_pk_context *)&peerCert->pk, pubKeyBuf, sizeof(pubKeyBuf));
+                if (ret <= 0)
                 {
-                    memcpy(uuid, (char*) uuidPos + sizeof(UUID_PREFIX) - 1, UUID_LENGTH * 2 + 4);
-                    OIC_LOG_V(DEBUG, NET_SSL_TAG, "certificate uuid string: %s" , uuid);
-                    ret = (OCConvertStringToUuid(uuid, peer->sep.identity.id)) ? 0 : -1;
-                    if (!checkSslOperation(peer,
-                                           ret,
-                                           "Failed to convert subject",
-                                           MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT))
-                    {
-                        oc_mutex_unlock(g_sslContextMutex);
-                        OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
-                        return CA_STATUS_FAILED;
-                    }
+                    OIC_LOG_V(ERROR, NET_SSL_TAG, "Failed to copy public key of remote peer: -0x%x", ret);
+                    oc_mutex_unlock(g_sslContextMutex);
+                    OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
+                    return CA_STATUS_FAILED;
                 }
-                else
+                else if (ret > sizeof(peer->sep.publicKey))
                 {
-                    OIC_LOG(WARNING, NET_SSL_TAG, "uuid not found");
+                    assert(!"publicKey field of CASecureEndpoint_t is too small for the public key!");
+                    OIC_LOG(ERROR, NET_SSL_TAG, "Public key of remote peer was too large");
+                    oc_mutex_unlock(g_sslContextMutex);
+                    OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
+                    return CA_STATUS_FAILED;
                 }
+                /* DER data is written to the end of the buffer, so we have to skip ahead in it. */
+                memcpy(peer->sep.publicKey, (pubKeyBuf + sizeof(pubKeyBuf) - ret), ret);
+                peer->sep.publicKeyLength = ret;
 
-                userIdPos = memmem(peerCert->subject_raw.p, peerCert->subject_raw.len,
-                                             USERID_PREFIX, sizeof(USERID_PREFIX) - 1);
-                if (NULL != userIdPos)
+                /* Find the CN component of the subject name. */
+                for (name = &peerCert->subject; NULL != name; name = name->next)
                 {
-                    memcpy(uuid, (char*) userIdPos + sizeof(USERID_PREFIX) - 1, UUID_LENGTH * 2 + 4);
-                    ret = (OCConvertStringToUuid(uuid, peer->sep.userId.id)) ? 0 : -1;
-                    if (!checkSslOperation(peer,
-                                           ret,
-                                           "Failed to convert subject alt name",
-                                           MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT))
+                    if (!name->oid.p)
                     {
-                        oc_mutex_unlock(g_sslContextMutex);
-                        OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
-                        return CA_STATUS_FAILED;
+                        continue;
                     }
+
+                    if ((name->oid.len < MBEDTLS_OID_SIZE(MBEDTLS_OID_AT_CN) ||
+                        (0 != memcmp(MBEDTLS_OID_AT_CN, name->oid.p, name->oid.len))))
+                    {
+                        continue;
+                    }
+                }
+
+                if (NULL == name)
+                {
+                    OIC_LOG(WARNING, NET_SSL_TAG, "no CN RDN found in subject name");
                 }
                 else
                 {
-                    OIC_LOG(WARNING, NET_SSL_TAG, "Subject alternative name not found");
+                    const size_t uuidBufLen = UUID_STRING_SIZE - 1;
+                    char uuid[UUID_STRING_SIZE] = { 0 };
+                    const unsigned char * uuidPos = NULL;
+                    const unsigned char * userIdPos = NULL;
+
+                    uuidPos = (const unsigned char*)memmem(name->val.p, name->val.len,
+                                                           UUID_PREFIX, sizeof(UUID_PREFIX) - 1);
+
+                    /* If UUID_PREFIX is present, ensure there's enough data for the prefix plus an entire
+                     * UUID, to make sure we don't read past the end of the buffer.
+                     */
+                    if ((NULL != uuidPos) && 
+                        (name->val.len >= ((uuidPos - name->val.p) + (sizeof(UUID_PREFIX) - 1) + uuidBufLen)))
+                    {
+                        memcpy(uuid, uuidPos + sizeof(UUID_PREFIX) - 1, uuidBufLen);
+                        OIC_LOG_V(DEBUG, NET_SSL_TAG, "certificate uuid string: %s", uuid);
+                        ret = (OCConvertStringToUuid(uuid, peer->sep.identity.id)) ? 0 : -1;
+                        if (!checkSslOperation(peer,
+                                               ret,
+                                               "Failed to convert subject",
+                                               MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT))
+                        {
+                            oc_mutex_unlock(g_sslContextMutex);
+                            OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
+                            return CA_STATUS_FAILED;
+                        }
+                    }
+                    else
+                    {
+                        OIC_LOG(WARNING, NET_SSL_TAG, "uuid not found");
+                    }
+
+                    /* If USERID_PREFIX is present, ensure there's enough data for the prefix plus an entire
+                     * UUID, to make sure we don't read past the end of the buffer.
+                     */
+                    userIdPos = (const unsigned char*)memmem(name->val.p, name->val.len,
+                                                             USERID_PREFIX, sizeof(USERID_PREFIX) - 1);
+                    if ((NULL != userIdPos) &&
+                        (name->val.len >= ((userIdPos - name->val.p) + (sizeof(USERID_PREFIX) - 1) + uuidBufLen)))
+                    {
+                        memcpy(uuid, userIdPos + sizeof(USERID_PREFIX) - 1, uuidBufLen);
+                        ret = (OCConvertStringToUuid(uuid, peer->sep.userId.id)) ? 0 : -1;
+                        if (!checkSslOperation(peer,
+                                               ret,
+                                               "Failed to convert subject alt name",
+                                               MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT))
+                        {
+                            oc_mutex_unlock(g_sslContextMutex);
+                            OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
+                            return CA_STATUS_FAILED;
+                        }
+                    }
+                    else
+                    {
+                        OIC_LOG(WARNING, NET_SSL_TAG, "Subject alternative name not found");
+                    }
                 }
             }
+            else
+            {
+                /* No public key information for non-certificate-using ciphersuites. */
+                memset(&peer->sep.publicKey, 0, sizeof(peer->sep.publicKey));
+                peer->sep.publicKeyLength = 0;
+            }
 
             oc_mutex_unlock(g_sslContextMutex);
             OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
index b37f163..a7b95d5 100644 (file)
@@ -139,18 +139,18 @@ void CARegisterHandler(CARequestCallback ReqHandler, CAResponseCallback RespHand
 
 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
 #ifdef MULTIPLE_OWNER
-const CASecureEndpoint_t *CAGetSecureEndpointData(const CAEndpoint_t *peer)
+CAResult_t CAGetSecureEndpointData(const CAEndpoint_t *peer, CASecureEndpoint_t *sep)
 {
     OIC_LOG(DEBUG, TAG, "IN CAGetSecurePeerInfo");
 
     if (!g_isInitialized)
     {
         OIC_LOG(DEBUG, TAG, "CA is not initialized");
-        return NULL;
+        return CA_STATUS_NOT_INITIALIZED;
     }
 
     OIC_LOG(DEBUG, TAG, "OUT CAGetSecurePeerInfo");
-    return GetCASecureEndpointData(peer);
+    return GetCASecureEndpointData(peer, sep);
 }
 #endif //MULTIPLE_OWNER
 
index e234da0..2b3850a 100755 (executable)
@@ -100,7 +100,6 @@ static const uint16_t PORT = 4545;
 static const char NORMAL_INFO_DATA[] =
                                     "{\"oc\":[{\"href\":\"%s\",\"prop\":{\"rt\":[\"core.led\"],"
                                      "\"if\":[\"oc.mi.def\"],\"obs\":1}}]}";
-
 #ifdef __WITH_DTLS__
 
 // Iotivity Device Identity.
@@ -164,6 +163,74 @@ int32_t CAGetDtlsPskCredentials( CADtlsPskCredType_t type,
     printf("CAGetDtlsPskCredentials OUT\n");
     return ret;
 }
+
+const char* our_cert = "-----BEGIN CERTIFICATE-----\n"
+"MIIBhTCCASugAwIBAgIJAPZ5mB94RwYHMAoGCCqGSM49BAMCMCUxIzAhBgNVBAoM\n"
+"GklvVGl2aXR5VGVzdFNlbGZTaWduZWROYW1lMB4XDTE2MTIxNjIxMjcyMVoXDTMw\n"
+"MDgyNTIxMjcyMVowITEfMB0GA1UECgwWSW9UaXZpdHlUZXN0Q2xpZW50TmFtZTBZ\n"
+"MBMGByqGSM49AgEGCCqGSM49AwEHA0IABF8OxpJNe01ZPEFpXUUhjUV5uwJM1TF3\n"
+"ZSt0tJ71lQiRZ9cbl5z31acRpsZM+fXiR+wkR4xoP7iIyDdTHHVHtkSjSDBGMBUG\n"
+"A1UdJQQOMAwGCisGAQQBgt58AQYwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBQH\n"
+"EWLwaDfA+o6U4wmQKVoK9I3B/DAKBggqhkjOPQQDAgNIADBFAiAbDHQHzSjNiDeQ\n"
+"OaJYRMLIW2dIlabiQ5pxkW/jEaRszAIhAPzuoNdrQTRbnqCy0hmS9hFt8MxDrrBh\n"
+"7jHARQm/5pko\n"
+"-----END CERTIFICATE-----\n";
+
+const char* our_key = "-----BEGIN EC PRIVATE KEY-----\n"
+"MHcCAQEEIOV0iG5CndNK6JhB8nDcqQjNjgRWe/LQWPNPua3w7nHToAoGCCqGSM49\n"
+"AwEHoUQDQgAEXw7Gkk17TVk8QWldRSGNRXm7AkzVMXdlK3S0nvWVCJFn1xuXnPfV\n"
+"pxGmxkz59eJH7CRHjGg/uIjIN1McdUe2RA==\n"
+"-----END EC PRIVATE KEY-----\n";
+
+const char* our_ca = "-----BEGIN CERTIFICATE-----\n"
+"MIIBlzCCATygAwIBAgIJALxGf3YRERn1MAoGCCqGSM49BAMCMCUxIzAhBgNVBAoM\n"
+"GklvVGl2aXR5VGVzdFNlbGZTaWduZWROYW1lMB4XDTE2MTIxNjIxMjcyMVoXDTMw\n"
+"MDgyNTIxMjcyMVowJTEjMCEGA1UECgwaSW9UaXZpdHlUZXN0U2VsZlNpZ25lZE5h\n"
+"bWUwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATo/zp8PXaA/drJQKSG3TlerO0F\n"
+"eHkpRkmXMeLFLrImqo1w9OyLfVmrpBrCDjf83BkwLYp19bkYizL2Yk9zIQ4Do1Uw\n"
+"UzAhBgNVHSUEGjAYBgorBgEEAYLefAEGBgorBgEEAYLefAEHMA8GA1UdEwEB/wQF\n"
+"MAMBAf8wHQYDVR0OBBYEFAcRYvBoN8D6jpTjCZApWgr0jcH8MAoGCCqGSM49BAMC\n"
+"A0kAMEYCIQCuZb1LMTthWy9rPgy2FQgoFHB2LXUJlgRLJeO/gTFqgQIhANRvr1Py\n"
+"5Bp6asye5FK4VUj6tARxmRNeNLvwonLrqp2w\n"
+"-----END CERTIFICATE-----\n";
+
+// Invoked by the CA stack to retrieve credentials from this module
+void provide_x509_cert_and_key(PkiInfo_t* inf)
+{
+    /* PEM data must end in newline and be null terminated for IoTivity */
+
+    inf->crt.data = (uint8_t*) our_cert;
+    inf->crt.len = strlen(our_cert) + 1;
+    inf->key.data = (uint8_t*) our_key;
+    inf->key.len = strlen(our_key) + 1;
+    inf->ca.data = (uint8_t*) our_ca;
+    inf->ca.len = strlen(our_ca) + 1;
+
+    // CRL not provided
+    inf->crl.data = NULL;
+    inf->crl.len = 0;
+
+    return;
+}
+// Empty version, for testing.
+void badPkixInfoHandler(PkiInfo_t* inf)
+{
+    return;
+}
+
+void provide_supported_credential_types(bool* list)
+{
+    list[1] = true;
+    /*
+     * Note: there is a default implementation of this in credresource.c, exposed by 
+     * pkix_interface.h, called InitManufacturerCipherSuiteList.  If the cred resource 
+     * has a credential of the required type, it updates list accordingly. 
+     *
+     * In a separate test, we could use the cred resource and APIs (credresource.h). 
+     */
+    return;
+}
+
 #endif  //__WITH_DTLS__
 
 // CAInitialize TC
@@ -293,6 +360,43 @@ TEST_F(CATests, SendRequestTestWithInvalidAddress)
     tempRep = NULL;
 }
 
+#if defined(__WITH_DTLS__)
+TEST_F(CATests, DISABLED_PkiTest)
+{
+    // @todo: this test is disabled for now, it crashes with an invalid write. Cert data
+    // provided by the provide_x509_cert_and_key is stored as const char, but ParseChain()
+    // (in ca_adapter_net_ssl.c) writes to it while reading.  We could change the test to 
+    // provide data on the heap, but the CA stack should not be changing data provided to it
+    // by callbacks. 
+
+    char* local_addr = "127.0.0.1";
+    uint16_t local_port = 5503;
+    CAEndpoint_t* serverAddr = NULL;
+
+    CARegisterHandler(request_handler, response_handler, error_handler);
+
+    EXPECT_EQ(CA_STATUS_OK, CASelectNetwork(CA_ADAPTER_IP));
+    CACreateEndpoint(CA_DEFAULT_FLAGS, CA_ADAPTER_IP, local_addr, local_port, &serverAddr);
+    ASSERT_TRUE(serverAddr != NULL);
+
+    // Register a credential types handler (tells the CA layer which creds are supported)
+    EXPECT_EQ(CA_STATUS_OK, CAregisterGetCredentialTypesHandler(provide_supported_credential_types));
+
+    // Limit ourselves to 0xC0AE : TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 since it's non-PSK
+    EXPECT_EQ(CA_STATUS_OK, CASelectCipherSuite(0xC0AE, serverAddr->adapter));
+
+    // Register an empty callback to provide the keys, expect failure when initializing the handshake.
+    EXPECT_EQ(CA_STATUS_OK, CAregisterPkixInfoHandler(badPkixInfoHandler));
+    EXPECT_EQ(CA_STATUS_FAILED, CAInitiateHandshake(serverAddr));
+
+    // Register a working callback to provide the keys, expect success.
+    EXPECT_EQ(CA_STATUS_OK, CAregisterPkixInfoHandler(provide_x509_cert_and_key));
+    EXPECT_EQ(CA_STATUS_OK, CAInitiateHandshake(serverAddr)); 
+
+    CADestroyEndpoint(serverAddr);
+}
+#endif /* defined(__WITH_DTLS__) */
+
 // CASendRequest TC
 // check return value when a NULL is passed instead of a valid CARequestInfo_t address
 TEST_F(CATests, SendRequestTestWithNullAddr)
@@ -481,6 +585,8 @@ TEST_F(CATests, RegisterDTLSCredentialsHandlerTest)
 {
 #ifdef __WITH_DTLS__
     EXPECT_EQ(CA_STATUS_OK, CAregisterPskCredentialsHandler(CAGetDtlsPskCredentials));
+    EXPECT_EQ(CA_STATUS_OK, CAregisterPkixInfoHandler(provide_x509_cert_and_key));
+    EXPECT_EQ(CA_STATUS_OK, CAregisterGetCredentialTypesHandler(provide_supported_credential_types));
 #endif
 }
 
index f18dfaf..a6188ce 100644 (file)
@@ -44,9 +44,7 @@
 #define CAsetTlsCipherSuite CAsetTlsCipherSuiteTest
 #define CAsslGenerateOwnerPsk CAsslGenerateOwnerPskTest
 #define CAcloseSslConnectionAll CAcloseSslConnectionAllTest
-#ifdef MULTIPLE_OWNER
 #define GetCASecureEndpointData GetCASecureEndpointDataTest
-#endif
 #define SetCASecureEndpointAttribute SetCASecureEndpointAttributeTest
 #define GetCASecureEndpointAttributes GetCASecureEndpointAttributesTest
 
index 45372e4..8a8e1b3 100644 (file)
@@ -59,7 +59,10 @@ libocsrm_env.PrependUnique(CPPPATH = [
 
 if target_os in ['windows', 'msys_nt']:
        libocsrm_env.AppendUnique(LIBPATH = [os.path.join(libocsrm_env.get('BUILD_DIR'), 'resource', 'oc_logger')])
-       libocsrm_env.AppendUnique(CCFLAGS=['/W4', '/WX'])
+    #  - warning C4200: nonstandard extension used: zero-sized array in struct/union
+    #  - warning C4214: nonstandard extension used: bit field types other than int
+    #    - warnings inherited from a header included from libcoap
+       libocsrm_env.AppendUnique(CCFLAGS=['/wd4200', '/wd4214', '/W4', '/WX'])
 
 if target_os in ['linux', 'android', 'tizen', 'msys_nt', 'windows'] and libocsrm_env.get('SECURED') == '1':
        SConscript('provisioning/SConscript', 'libocsrm_env')
@@ -123,6 +126,9 @@ if libocsrm_env.get('SECURED') == '1':
        libocsrm_src = libocsrm_src + [OCSRM_SRC + 'oxmpincommon.c', OCSRM_SRC + 'pbkdf2.c']
        libocsrm_src = libocsrm_src + [OCSRM_SRC + 'crlresource.c', OCSRM_SRC + 'pkix_interface.c']
        libocsrm_src = libocsrm_src + [OCSRM_SRC + 'oxmverifycommon.c']
+       libocsrm_src = libocsrm_src + [OCSRM_SRC + 'certhelpers.c', OCSRM_SRC + 'occertutility.c']
+       libocsrm_src = libocsrm_src + [OCSRM_SRC + 'csrresource.c']
+       libocsrm_src = libocsrm_src + [OCSRM_SRC + 'rolesresource.c']
 
 if target_os in ['windows', 'msys_nt']:
        libocsrm_src  = libocsrm_src + [OCSRM_SRC + 'strptime.c']
index dec810a..ea173ec 100644 (file)
@@ -52,15 +52,30 @@ OCStackResult DeInitACLResource();
 const OicSecAce_t* GetACLResourceData(const OicUuid_t* subjectId, OicSecAce_t **savePtr);
 
 /**
+ * This method is used by PolicyEngine to retrieve ACLs for a set of roles.
+ *
+ * @param[in] roles Array of roles to check for.
+ * @param[in] roleCount Length of roles array.
+ * @param[out] savePtr is used internally by @ref GetACLResourceDataByRoles to maintain index between
+ *                     successive calls for the same roles list.
+ *
+ * @note On the first call to @ref GETAclResourceDataByRoles, savePtr should point to NULL.
+ * 
+ * @return reference to @ref OicSecAce_t if ACE is found, else NULL.
+ */
+const OicSecAce_t* GetACLResourceDataByRoles(const OicSecRole_t *roles, size_t roleCount, OicSecAce_t **savePtr);
+
+/**
  * This function converts ACL data into CBOR format.
  *
  * @param acl instance of @ref OicSecAcl_t structure.
+ * @param aclVersion Version of ACL resource to produce; can be OIC_SEC_ACL_V1 or OIC_SEC_ACL_V2
  * @param outPayload is the pointer to allocated memory for cbor payload.
  * @param size of the cbor payload.
  *
  * @return ::OC_STACK_OK for Success, otherwise some error value.
  */
-OCStackResult AclToCBORPayload(const OicSecAcl_t * acl, uint8_t **outPayload, size_t *size);
+OCStackResult AclToCBORPayload(const OicSecAcl_t *acl, OicSecAclVersion_t aclVersion, uint8_t **outPayload, size_t *size);
 
 #ifdef MULTIPLE_OWNER
 /**
@@ -138,7 +153,7 @@ OCStackResult AppendACL(const uint8_t* payload, const size_t size);
  *
  * @return ::OC_STACK_OK for Success, otherwise some error value
  */
-OCStackResult AppendACL2(const OicSecAcl_t* acl);
+OCStackResult AppendACLObject(const OicSecAcl_t* acl);
 
 /**
  * This function updates default ACE which is required for ownership transfer.
@@ -174,7 +189,7 @@ OCStackResult GetAclRownerId(OicUuid_t *rowneruuid);
  *
  * @return instance of @ref OicSecAcl_t structure or NULL if error occurs
  */
-OicSecAcl_t* CBORPayloadToAcl2(const uint8_t *cborPayload, const size_t size);
+OicSecAcl_t* CBORPayloadToCloudAcl(const uint8_t *cborPayload, const size_t size);
 
 /**
  * This function prints ACL to stdin
diff --git a/resource/csdk/security/include/internal/certhelpers.h b/resource/csdk/security/include/internal/certhelpers.h
new file mode 100644 (file)
index 0000000..32e97c6
--- /dev/null
@@ -0,0 +1,129 @@
+//******************************************************************
+//
+// Copyright 2017 Microsoft
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//******************************************************************
+
+#ifndef IOTVT_SRM_CERTHELPERS_H_
+#define IOTVT_SRM_CERTHELPERS_H_
+
+#if defined(__WITH_TLS__) || defined(__WITH_DTLS__)
+
+#include "mbedtls/pk.h"
+#include <time.h>
+
+/**
+ * Internal certificate request function; used by CSR resource handler
+ *
+ * @param[in]  subject  Subject to put into the CSR
+ * @param[in]  keyPair  Key pair for which to generate the CSR
+ * @param[in]  encoding Encoding to use; valid values are OIC_ENCODING_PEM and OIC_ENCODING_DER
+ * @param[out] csr      OCByteString containing the CSR in PEM. Caller takes ownership
+ *                      of allocated memory and must call OICFree on csr->bytes when finished.
+ *                      If encoding is OIC_ENCODING_DER, csr->len is the length of the encoded CSR.
+ *                      If encoding is OIC_ENCODING_PEM, csr->len is the length of the PEM string including the
+ *                      terminating NULL.
+ *
+ * @return 0 on success, <0 on failure
+ */
+int OCInternalCSRRequest(const char *subject, mbedtls_pk_context *keyPair, 
+                         OicEncodingType_t encoding, OCByteString *csr);
+
+/**
+ * Internal key pair generation function; used by CSR resource handler
+ *
+ * @param[in,out] keyPair Key object to generate; caller should already have called mbedtls_pk_init on it.
+ *
+ * @return 0 on success, <0 on failure
+ */
+int OCInternalGenerateKeyPair(mbedtls_pk_context *keyPair);
+
+#endif
+
+/**
+ * Determine if a buffer contains a role certificate, and optionally, return
+ * a DER encoding of the public key. This is intended as a simple check when the
+ * certificate is presented to reject obviously invalid certificates.
+ *
+ * The following properties are checked:
+ * 1. The certificate is a valid X.509 certificate.
+ * 2. It contains the role certificate Extended Key Usage.
+ * 3. It contains at least one Subject Alternative Name extension that validly encodes a role.
+ *
+ * It does NOT validate the cryptographic signature nor check its time validity.
+ * These checks should be done when the certificate is being used as part of an access control check, 
+ * as that is when the time validity check should be made, and when trusted CAs are known.
+ *
+ * @param[in] buf           Buffer containing certificate as a PEM string
+ * @param[in] bufLen        Length of buffer including terminating NULL
+ * @param[out] pubKey       Optional pointer to receive buffer containing binary DER encoding of public key.
+ *                          Caller must free with OICFree when finished. Pass NULL in to not retrieve the
+ *                          public key.
+ * @param[out] pubKeyLen    Pointer to variable to receive size of pubKey. Ignored if pubKey is NULL.
+ *
+ * @return OC_STACK_OK if certificate satisfies the properties above, and the public key is
+ *                     successfully extracted (if requested).
+ *         OC_STACK_INVALID_PARAM if the certificate does not meet the properties above.
+ *         OC_STACK_NO_MEMORY or OC_STACK_ERROR if some other error arose during the check.
+ */
+OCStackResult OCInternalIsValidRoleCertificate(const uint8_t *buf, size_t bufLen,
+                                               uint8_t **pubKey, size_t *pubKeyLen);
+
+/**
+ * Determine if a buffer contains a valid chain of certificates. This is intended to verify
+ * one or more intermediate CA certificates are valid.
+ * 
+ * This only checks that they are valid X.509 structures; no verification of the cryptographic
+ * signature of time-validity is performed. These should be done at point of use.
+ *
+ * @param[in] buf           Buffer containing certificates as a PEM string
+ * @param[in] bufLen        Length of buffer including terminating NULL
+ *
+ * @return OC_STACK_OK if buf contains a valid chain of certificates
+ *         OC_STACK_INVALID_PARAM if buf cannot be parsed as a chain of certificates
+ *         OC_STACK_ERROR if some other error arose during the check
+ */
+OCStackResult OCInternalIsValidCertChain(const uint8_t *buf, size_t bufLen);
+
+/**
+ * Verify the validity of a role certificate chain against a set of trusted certificate
+ * authorities. If successful, a list of roles authorized by this certificate is returned.
+ *
+ * The certificate's validity is also verified against the current time.
+ *
+ * The GetPemCaCert function from credresource.h can be used to retrieve the set of trusted CAs
+ * from the /oic/sec/cred resource in a form suitable for the trustedCaCerts and trustedCaCertsLength
+ * parameters.
+ *
+ * @param[in] certificate           OicSecKey_t containing the leaf certificate
+ * @param[in] optData               Optional OicSecOpt_t containing intermediate CAs and revocation status
+ * @param[in] trustedCaCerts        PEM string containing the trusted CAs certificates
+ * @param[in] trustedCaCertsLength  Length of trustedCaCerts (including terminating NULL)
+ * @param[out] roles                Pointer to receive array of OicSecRole_t objects listing roles
+ *                                  Caller must call OICFree to release this memory when finished
+ * @param[out] rolesLength          Length of returned roles array
+ * @param[out] notValidAfter        struct tm to receive notValidAfter time of the certificate
+ *
+ * @return OC_STACK_OK if the certificate is valid.
+ *         OC_STACK_INVALID_PARAM if the certificate is not valid.
+ *         OC_STACK_NO_MEMORY or OC_STACK_ERROR if some other error arose during validation.
+ */
+OCStackResult OCInternalVerifyRoleCertificate(const OicSecKey_t *certificate, const OicSecOpt_t *optData,
+                                              const uint8_t *trustedCaCerts, size_t trustedCaCertsLength,
+                                              OicSecRole_t **roles, size_t *rolesLength,
+                                              struct tm *notValidAfter);
+#endif
index 8299eff..9f71dad 100644 (file)
@@ -24,6 +24,7 @@
 #include "cainterface.h"
 #include "securevirtualresourcetypes.h"
 #include "octypes.h"
+#include <cbor.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -211,7 +212,14 @@ OCStackResult GetCredRownerId(OicUuid_t *rowneruuid);
 
 #if defined(__WITH_TLS__) || defined(__WITH_DTLS__)
 /**
- * Used by mbedTLS to retrieve trusted CA certificates
+ * Used by role certificate validator to get CA certificates as PEM
+ *
+ * @param[out] crt certificates to be filled.
+ * @param[in] usage credential usage string.
+ */
+OCStackResult GetPemCaCert(ByteArray_t * crt, const char * usage);
+/**
+ * Used by mbedTLS to retrieve trusted CA certificates as DER
  *
  * @param[out] crt certificates to be filled.
  * @param[in] usage credential usage string.
@@ -239,6 +247,13 @@ void GetDerKey(ByteArray_t * key, const char * usage);
  */
 void InitCipherSuiteListInternal(bool *list, const char * usage);
 #endif // __WITH_TLS__
+
+// Helpers shared by cred and roles resources
+CborError SerializeEncodingToCbor(CborEncoder *rootMap, const char *tag, const OicSecKey_t *value);
+CborError SerializeSecOptToCbor(CborEncoder *rootMap, const char *tag, const OicSecOpt_t *value);
+CborError DeserializeEncodingFromCbor(CborValue *rootMap, OicSecKey_t *value);
+CborError DeserializeSecOptFromCbor(CborValue *rootMap, OicSecOpt_t *value);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/resource/csdk/security/include/internal/csrresource.h b/resource/csdk/security/include/internal/csrresource.h
new file mode 100644 (file)
index 0000000..5522066
--- /dev/null
@@ -0,0 +1,64 @@
+//******************************************************************
+//
+// Copyright 2017 Microsoft
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//******************************************************************
+
+#ifndef IOTVT_SRM_CSRR_H
+#define IOTVT_SRM_CSRR_H
+
+#include "cainterface.h"
+#include "securevirtualresourcetypes.h"
+#include "octypes.h"
+
+#if defined(__WITH_TLS__) || defined(__WITH_DTLS__)
+#ifdef __cplusplus
+extern "C" {
+#endif
+/**
+ * Initialize the CSR resource.
+ *
+ * @return OC_STACK_OK if successful; error otherwise.
+ */
+OCStackResult InitCSRResource();
+
+/**
+ * De-initialize the CSR resource.
+ *
+ * @return OC_STACK_OK if successful; error otherwise.
+ */
+OCStackResult DeInitCSRResource();
+
+/**
+ * This function converts a CBOR payload into a CSR.
+ * Caller needs to call 'OICFree' on *csr after use.
+ *
+ * @param[in] cborPayload Received CBOR payload to extract the CSR from
+ * @param[in] size Size of cborPayload
+ * @param[out] csr Buffer containing the CSR
+ * @param[out] csrLen Length of csr
+ * @param[out] encoding Encoding of CSR (OIC_ENCODING_PEM or OIC_ENCODING_DER)
+ */
+OCStackResult CBORPayloadToCSR(const uint8_t *cborPayload, size_t size, 
+                               uint8_t **csr, size_t *csrLen, 
+                               OicEncodingType_t *encoding);
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+#endif
diff --git a/resource/csdk/security/include/internal/rolesresource.h b/resource/csdk/security/include/internal/rolesresource.h
new file mode 100644 (file)
index 0000000..9a7149a
--- /dev/null
@@ -0,0 +1,96 @@
+//******************************************************************
+//
+// Copyright 2017 Microsoft
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//******************************************************************
+
+#ifndef IOTVT_SRM_ROLESR_H
+#define IOTVT_SRM_ROLESR_H
+
+#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
+
+#include "cainterface.h"
+#include "securevirtualresourcetypes.h"
+#include "octypes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct RoleCertChain {
+    uint32_t                credId;             /**< locally assigned ID number for use with DELETE */
+    OicSecKey_t             certificate;        /**< leaf certificate data */
+    OicSecOpt_t             optData;            /**< intermediate CA certificates */
+
+    struct RoleCertChain    *next;              /**< next chain in list */
+} RoleCertChain_t;
+
+/**
+ * Initialize the roles resource.
+ *
+ * @return OC_STACK_OK if successful; error otherwise
+ */
+OCStackResult InitRolesResource();
+
+/**
+ * De-initialize the roles resource.
+ *
+ * @return OC_STACK_OK if successful; error otherwise
+ */
+OCStackResult DeInitRolesResource();
+
+/**
+ * Retrieve the roles asserted by a given endpoint with certificates.
+ *
+ * @param[in] endpoint      Endpoint to retrieve roles for
+ * @param[out] roles        Pointer to receive array of OicSecRole_t objects containing roles for this endpoint
+ *                          On success, caller must free the received array with OICFree when finished
+ * @param[out] roleCount    Variable to receive length of roles array.
+ *
+ * @note If the endpoint is found but has not asserted any roles with certificates, 
+ *       OC_STACK_OK will be returned, but NULL will be returned in roles and 0 in roleCount.
+ *
+ * @return OC_STACK_OK if list of roles is successfully populated; error otherwise.
+ */
+OCStackResult GetEndpointRoles(const CAEndpoint_t *endpoint, OicSecRole_t **roles, size_t *roleCount);
+
+/**
+ * This function converts a CBOR payload into a list of role certificates.
+ * Caller needs to call 'OICFree' on *roleCertList after use.
+ *
+ * @param[in] cborPayload Received CBOR payload to extract the role cert list from
+ * @param[in] size Size of cborPayload
+ * @param[out] roleCertList Pointer to receive linked list of RoleCertChain_t objects
+ *             On success, caller must call FreeRoleCertChainList on *roleCertList when finished
+ * @return OC_STACK_OK if payload is successfully converted; error code otherwise
+ */
+OCStackResult CBORPayloadToRoles(const uint8_t *cborPayload, size_t size, RoleCertChain_t **roleCertList);
+
+/**
+ * Free the memory used by a list of RoleCertChain_t objects created by CBORPayloadToRoles.
+ *
+ * @param[in] roleCertList List received from CBORPayloadToRoles
+ */
+void FreeRoleCertChainList(RoleCertChain_t *roleCertList);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* defined(__WITH_DTLS__) || defined(__WITH_TLS__) */
+
+#endif /* IOTVT_SRM_ROLESR_H */
index 85ba6e8..f1a0ea1 100644 (file)
@@ -42,6 +42,10 @@ extern const char * OIC_JSON_ACL_NAME;
 extern const char * OIC_JSON_ACLIST_NAME;
 extern const char * OIC_JSON_ACES_NAME;
 
+extern const char * OIC_RSRC_TYPE_SEC_ACL2;
+extern const char * OIC_RSRC_ACL2_URI;
+extern const char * OIC_JSON_ACL2_NAME;
+
 //PSTAT
 extern const char * OIC_RSRC_TYPE_SEC_PSTAT;
 extern const char * OIC_RSRC_PSTAT_URI;
@@ -59,6 +63,16 @@ extern const char * OIC_RSRC_CRED_URI;
 extern const char * OIC_JSON_CRED_NAME;
 extern const char * OIC_JSON_CREDS_NAME;
 
+//csr
+extern const char * OIC_RSRC_TYPE_SEC_CSR;
+extern const char * OIC_RSRC_CSR_URI;
+extern const char * OIC_JSON_CSR_NAME;
+
+//roles
+extern const char * OIC_RSRC_TYPE_SEC_ROLES;
+extern const char * OIC_RSRC_ROLES_URI;
+extern const char * OIC_JSON_ROLES_NAME;
+
 //CRL
 extern const char * OIC_RSRC_TYPE_SEC_CRL;
 extern const char * OIC_RSRC_CRL_URI;
@@ -91,7 +105,6 @@ extern const char * OIC_JSON_VER_NAME;
 
 //reset profile
 extern const char * OIC_JSON_RESET_PF_NAME;
-
 extern const char * OIC_JSON_SUBJECTID_NAME;
 extern const char * OIC_JSON_RESOURCES_NAME;
 extern const char * OIC_JSON_AMSS_NAME;
@@ -114,6 +127,7 @@ extern const char * OIC_JSON_OXM_SEL_NAME;
 extern const char * OIC_JSON_DEVICE_ID_FORMAT_NAME;
 extern const char * OIC_JSON_CREDID_NAME;
 extern const char * OIC_JSON_ROLEIDS_NAME;
+extern const char * OIC_JSON_AUTHORITY_NAME;
 extern const char * OIC_JSON_CREDTYPE_NAME;
 extern const char * OIC_JSON_PUBLICDATA_NAME;
 extern const char * OIC_JSON_PRIVATEDATA_NAME;
@@ -160,9 +174,10 @@ extern const char * OIC_JSON_SEC_V_NAME;
 
 extern const char * OIC_JSON_EMPTY_STRING;
 
-// Certificates provided by Cloud
+// Certificates provided by Cloud or OBT/CMS
 extern const char * TRUST_CA;
 extern const char * PRIMARY_CERT;
+extern const char * PRIMARY_KEY;
 
 // Certificates provided by manufacturer
 extern const char * MF_TRUST_CA;
diff --git a/resource/csdk/security/include/occertutility.h b/resource/csdk/security/include/occertutility.h
new file mode 100644 (file)
index 0000000..7962cd0
--- /dev/null
@@ -0,0 +1,223 @@
+//******************************************************************
+//
+// Copyright 2017 Microsoft
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//******************************************************************
+
+#if defined(__WITH_TLS__) || defined(__WITH_DTLS__)
+
+#ifndef OCCERTUTILITY_H_
+#define OCCERTUTILITY_H_
+
+#include "securevirtualresourcetypes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Generate a random serial number suitable for use with a certificate.
+ * Callers must record used serial numbers and ensure serial numbers do not
+ * get repeated!
+ *
+ * @param[OUT] serial      Pointer to a string that will be set to the location of the ASCII serial number.
+ *                         Memory for this buffer will be allocated internally; caller must call OICFree on serial
+ *                         when finished to free its memory.
+ * @param[OUT] serialLen   Variable to receive size of serial, which will include the terminating NULL.
+ *
+ * @return OC_STACK_OK if generated successfully; error otherwise.
+ */
+OCStackResult OCGenerateRandomSerialNumber(char **serial, size_t *serialLen);
+
+/**
+ * Generate a new NIST P-256 elliptic curve key pair and return the public and private
+ * keys as PEM encoded strings.
+ *
+ * @param[OUT] publicKey     Pointer to receive PEM encoded public key. Memory is allocated internally
+ *                           and must be freed by caller with OICFree.
+ * @param[OUT] publicKeyLen  Variable to receive length of publicKey, which will include terminating NULL.
+ * @param[OUT] privateKey    Pointer to receive PEM encoded private key. Memory is allocated internally
+ *                           and, when finished, caller should first call OICClearMemory to securely erase
+ *                           its contents and then freed with OICFree. Caller is responsible for ensuring
+ *                           this key remains protected and secret!
+ * @param[OUT] privateKeyLen Variable to receive length of privateKey, which will include terminating NULL.
+ */
+OCStackResult OCGenerateKeyPair(char **publicKey, size_t *publicKeyLen,
+                                char **privateKey, size_t *privateKeyLen);
+
+/**
+ * Generate a certificate to act as a 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 OCGenerateCACertificate(
+    const char *subject,
+    const char *subjectPublicKey,
+    const char *issuerCert,
+    const char *issuerPrivateKey,
+    const char *serial,
+    const char *notValidBefore,
+    const char *notValidAfter,
+    char **certificate,
+    size_t *certificateLen);
+
+/**
+ * Generate a certificate for a device's identity.
+ *
+ * @param subjectUuid           UUID for the device to use the certificate.
+ * @param subjectPublicKey      Subject's public key in PEM format
+ * @param issuerCert            Issuer's certificate in PEM format
+ * @param issuerPrivateKey      Issuer's private key in PEM format
+ * @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 OCGenerateIdentityCertificate(
+    const OicUuid_t *subjectUuid,
+    const char *subjectPublicKey,
+    const char *issuerCert,
+    const char *issuerPrivateKey,
+    const char *serial,
+    const char *notValidBefore,
+    const char *notValidAfter,
+    char **certificate,
+    size_t *certificateLen);
+
+/**
+ * Generate a certificate for a device's role.
+ *
+ * @param subjectUuid           UUID for the device to use the certificate.
+ * @param subjectPublicKey      Subject's public key in PEM format
+ * @param issuerCert            Issuer's certificate in PEM format
+ * @param issuerPrivateKey      Issuer's private key in PEM format
+ * @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 role                  The role to encode in the certificate.
+ * @param authority             The role authority to encode in the certificate. This field is optional;
+ *                              to omit, use NULL, and authority is construed to be the certificate issuer.
+ * @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 OCGenerateRoleCertificate(
+    const OicUuid_t *subjectUuid,
+    const char *subjectPublicKey,
+    const char *issuerCert,
+    const char *issuerPrivateKey,
+    const char *serial,
+    const char *notValidBefore,
+    const char *notValidAfter,
+    const char *role,
+    const char *authority,
+    char **certificate,
+    size_t *certificateLen);
+
+/**
+ * Extract a UUID from a CSR.
+ *
+ * @param[in]  csr  The CSR containing the UUID as null-terminated PEM.
+ * @param[out] uuid The UUID in the CSR
+ *
+ * @return 0 on success, nonzero otherwise
+ */
+OCStackResult OCGetUuidFromCSR(const char* csr, OicUuid_t* uuid);
+
+/**
+ * Extract a public key from a CSR.
+ *
+ * @param[in]  csr       The CSR containing the public key, as null-terminated PEM.
+ * @param[out] publicKey The public key is output here as null-terminated PEM.
+ *                       Callers must call OICFree when finished.
+ *
+ * @return 0 on success, nonzero otherwise
+ */
+OCStackResult OCGetPublicKeyFromCSR(const char* csr, char** publicKey);
+
+/**
+ * Verify the signature in a CSR is valid.
+ *
+ * @param[in] csr The CSR to check, as null-terminated PEM.
+ *
+ * @returns 0 on success, nonzero otherwise
+ *
+ * @remark Requires that ECDSA with SHA-256 be used for the signature.
+ */
+OCStackResult OCVerifyCSRSignature(const char* csr);
+
+/**
+ * Convert a CSR from DER encoding to PEM encoding.
+ *
+ * @param[in] derCSR The CSR to convert, encoded as DER
+ * @param[in] derCSRLen Then number of bytes in derCSR
+ * @param[out] pemCSR The output, PEM encoded, null-terminated CSR. Callers 
+ *                    call OICFree when finished. 
+ *
+ * @returns 0 on success, nonzero otherwise
+*/
+OCStackResult OCConvertDerCSRToPem(const char* derCSR, size_t derCSRLen, char** pemCSR);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* OCCERTUTILITY_H_ */
+
+#endif /* defined(__WITH_TLS__) || defined(__WITH_DTLS__) */
\ No newline at end of file
index 7fdd5f3..62e4825 100644 (file)
@@ -278,10 +278,12 @@ enum
     OIC_R_AMACL_TYPE,
     OIC_R_CRED_TYPE,
     OIC_R_CRL_TYPE,
+    OIC_R_CSR_TYPE,
     OIC_R_DOXM_TYPE,
     OIC_R_DPAIRING_TYPE,
     OIC_R_PCONF_TYPE,
     OIC_R_PSTAT_TYPE,
+    OIC_R_ROLES_TYPE,
     OIC_R_SACL_TYPE,
     OIC_R_SVC_TYPE,
     OIC_SEC_SVR_TYPE_COUNT, //define the value to number of SVR
@@ -379,7 +381,8 @@ typedef void OicSecCert_t;
  */
 #define UUID_LENGTH 128/8 // 128-bit GUID length
 //TODO: Confirm the length and type of ROLEID.
-#define ROLEID_LENGTH 128/8 // 128-bit ROLEID length
+#define ROLEID_LENGTH 64 // 64-byte authority max length
+#define ROLEAUTHORITY_LENGTH 64 // 64-byte authority max length
 #define OWNER_PSK_LENGTH_128 128/8 //byte size of 128-bit key size
 #define OWNER_PSK_LENGTH_256 256/8 //byte size of 256-bit key size
 
@@ -433,10 +436,41 @@ struct OicSecValidity
     OicSecValidity_t *next;
 };
 
+typedef enum
+{
+    OIC_SEC_ACL_UNKNOWN = 0,
+    OIC_SEC_ACL_V1 = 1,
+    OIC_SEC_ACL_V2 = 2
+} OicSecAclVersion_t;
+
+#define OIC_SEC_ACL_LATEST OIC_SEC_ACL_V2
+
+typedef enum
+{
+    OicSecAceUuidSubject = 0, /* Default to this type. */
+    OicSecAceRoleSubject
+} OicSecAceSubjectType;
+
+/**
+ * /oic/sec/role (Role) data type.
+ * Derived from OIC Security Spec; see Spec for details.
+ */
+struct OicSecRole
+{
+    // <Attribute ID>:<Read/Write>:<Multiple/Single>:<Mandatory?>:<Type>
+    char id[ROLEID_LENGTH];                 // 0:R:S:Y:String
+    char authority[ROLEAUTHORITY_LENGTH];   // 1:R:S:N:String
+};
+
 struct OicSecAce
 {
     // <Attribute ID>:<Read/Write>:<Multiple/Single>:<Mandatory?>:<Type>
-    OicUuid_t subjectuuid;              // 0:R:S:Y:uuid
+    OicSecAceSubjectType subjectType;
+    union                               // 0:R:S:Y:{roletype|didtype|"*"}
+    {
+        OicUuid_t subjectuuid;          // Only valid for subjectType == OicSecAceUuidSubject
+        OicSecRole_t subjectRole;       // Only valid for subjectType == OicSecAceRoleSubject
+    };
     OicSecRsrc_t *resources;            // 1:R:M:Y:Resource
     uint16_t permission;                // 2:R:S:Y:UINT16
     OicSecValidity_t *validities;       // 3:R:M:N:Time-interval
@@ -552,17 +586,6 @@ struct OicSecPstat
 };
 
 /**
- * /oic/sec/role (Role) data type.
- * Derived from OIC Security Spec; see Spec for details.
- */
-struct OicSecRole
-{
-    // <Attribute ID>:<Read/Write>:<Multiple/Single>:<Mandatory?>:<Type>
-    //TODO fill in with Role definition
-    uint8_t             id[ROLEID_LENGTH];
-};
-
-/**
  * /oic/sec/sacl (Signed Access Control List) data type.
  * Derived from OIC Security Spec; see Spec for details.
  */
index 605835d..f4cd241 100644 (file)
@@ -35,15 +35,16 @@ extern "C"
 /**
  * API to send ACL information to resource.
  *
- * @param[in] ctx Application context would be returned in result callback.
+ * @param[in] ctx Application context to be returned in result callback.
  * @param[in] selectedDeviceInfo Selected target device.
+ * @param[in] aclVersion Version of the ACL resource to access
  * @param[in] acl ACL to provision.
  * @param[in] resultCallback callback provided by API user, callback will be called when
  *            provisioning request recieves a response from resource server.
  * @return OC_STACK_OK in case of success and other value otherwise.
  */
 OCStackResult SRPProvisionACL(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
-                                        OicSecAcl_t *acl, OCProvisionResultCB resultCallback);
+                                        OicSecAcl_t *acl, OicSecAclVersion_t aclVersion, OCProvisionResultCB resultCallback);
 
 /**
  * API to save ACL which has several ACE into Acl of SVR.
@@ -56,7 +57,7 @@ OCStackResult SRPSaveACL(const OicSecAcl_t *acl);
 /**
  * API to request CRED information to resource.
  *
- * @param[in] ctx Application context would be returned in result callback.
+ * @param[in] ctx Application context to be returned in result callback.
  * @param[in] selectedDeviceInfo Selected target device.
  * @param[in] resultCallback callback provided by API user, callback will be called when
  *            provisioning request recieves a response from resource server.
@@ -68,21 +69,60 @@ OCStackResult SRPGetCredResource(void *ctx, const OCProvisionDev_t *selectedDevi
 /**
  * API to request ACL information to resource.
  *
- * @param[in] ctx Application context would be returned in result callback.
+ * @param[in] ctx Application context to be returned in result callback.
  * @param[in] selectedDeviceInfo Selected target device.
+ * @param[in] aclVersion Version of ACL resource to query
  * @param[in] resultCallback callback provided by API user, callback will be called when
  *            provisioning request recieves a response from resource server.
  * @return OC_STACK_OK in case of success and other value otherwise.
  */
 OCStackResult SRPGetACLResource(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
-        OCProvisionResultCB resultCallback);
+        OicSecAclVersion_t aclVersion, OCProvisionResultCB resultCallback);
+
+/**
+ * API to request the Certificate Signing Request (CSR) resource.
+ *
+ * @param[in] ctx Application context to be returned in result callback.
+ * @param[in] selectedDeviceInfo Selected target device.
+ * @param[in] resultCallback callback provided by API user, callback will be called when
+ *            provisioning request recieves a response from resource server.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult SRPGetCSRResource(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
+                                OCGetCSRResultCB resultCallback);
+
+/**
+ * API to request the Roles resource.
+ *
+ * @param[in] ctx Application context to be returned in result callback.
+ * @param[in] selectedDeviceInfo Selected target device.
+ * @param[in] resultCallback Callback provided by API user. Callback will be called when
+ *            provisioning request receives a response from resource server.
+ * @return OC_STACK_OK in case of success or error value otherwise.
+ */
+OCStackResult SRPGetRolesResource(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
+                                  OCGetRolesResultCB resultCallback);
+
+/**
+ * This function requests the device delete a particular role certificate by credId.
+ *
+ * @param[in] ctx Application context that is returned in the result callback.
+ * @param[in] selectedDeviceInfo Selected target device.
+ * @param[in] resultCallback callback provided by the API user. Callback will be called when request receives
+ *            a response from the resource server.
+ * @param[in] credId credId to request be deleted.
+ *
+ * @return OC_STACK_OK in case of success, and error value otherwise.
+ */
+OCStackResult SRPDeleteRoleCertificateByCredId(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
+                                               OCProvisionResultCB resultCallback, uint32_t credId);
 
 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
 
 /**
  * function to provision Trust certificate chain to devices.
  *
- * @param[in] ctx Application context would be returned in result callback.
+ * @param[in] ctx Application context to be returned in result callback.
  * @param[in] type Type of credentials to be provisioned to the device.
  * @param[in] credId CredId of trust certificate chain to be provisioned to the device.
  * @param[in] selectedDeviceInfo Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.
@@ -134,7 +174,7 @@ void SRPRemoveTrustCertChainNotifier(void);
 /**
  * API to send Direct-Pairing Configuration to a device.
  *
- * @param[in] ctx Application context would be returned in result callback.
+ * @param[in] ctx Application context to be returned in result callback.
  * @param[in] selectedDeviceInfo Selected target device.
  * @param[in] pconf PCONF pointer.
  * @param[in] resultCallback callback provided by API user, callback will be called when
@@ -159,11 +199,13 @@ OCStackResult SRPProvisionDirectPairing(void *ctx, const OCProvisionDev_t *selec
 /**
  * API to provision credential to devices.
  *
- * @param[in] ctx Application context would be returned in result callback.
+ * @param[in] ctx Application context to be returned in result callback.
  * @param[in] type Type of credentials to be provisioned to the device.
  * @param[in] keySize size of key
- * @param[in] pDev1 Pointer to PMOwnedDeviceInfo_t instance,respresenting resource to be provsioned.
-   @param[in] pDev2 Pointer to PMOwnedDeviceInfo_t instance,respresenting resource to be provsioned.
+ * @param[in] pDev1 Pointer to PMOwnedDeviceInfo_t instance, respresenting resource to be provsioned.
+ * @param[in] pDev2 Pointer to PMOwnedDeviceInfo_t instance, respresenting resource to be provsioned.
+ * @param[in] pemCert When provisioning a certificate (type is SIGNED_ASYMMETRIC_KEY), this is the 
+ *                    certificate, encoded as PEM. 
  * @param[in] resultCallback callback provided by API user, callback will be called when
  *            provisioning request recieves a response from first resource server.
  * @return OC_STACK_OK in case of success and other value otherwise.
@@ -171,13 +213,14 @@ OCStackResult SRPProvisionDirectPairing(void *ctx, const OCProvisionDev_t *selec
 OCStackResult SRPProvisionCredentials(void *ctx,OicSecCredType_t type, size_t keySize,
                                       const OCProvisionDev_t *pDev1,
                                       const OCProvisionDev_t *pDev2,
+                                      const char* pemCert,
                                       OCProvisionResultCB resultCallback);
 
 /**
  * Function to unlink devices.
  * This function will remove the credential & relationship between the two devices.
  *
- * @param[in] ctx Application context would be returned in result callback
+ * @param[in] ctx Application context to be returned in result callback
  * @param[in] pTargetDev1 first device information to be unlinked.
  * @param[in] pTargetDev2 second device information to be unlinked.
  * @param[in] resultCallback callback provided by API user, callback will be called when
@@ -194,7 +237,7 @@ OCStackResult SRPUnlinkDevices(void* ctx,
  * Function to device revocation.
  * This function will remove credential of target device from all devices in subnet.
  *
- * @param[in] ctx Application context would be returned in result callback
+ * @param[in] ctx Application context to be returned in result callback
  * @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds)
  * @param[in] pTargetDev Device information to be revoked.
  * @param[in] resultCallback callback provided by API user, callback will be called when
@@ -210,18 +253,18 @@ OCStackResult SRPRemoveDevice(void* ctx,
                               OCProvisionResultCB resultCallback);
 
 /**
-* Function to device revocation
-* This function will remove credential of target device from all devices in subnet.
-*
-* @param[in] ctx Application context would be returned in result callback
-* @param[in] pOwnedDevList List of owned devices
-* @param[in] pTargetDev Device information to be revoked.
-* @param[in] resultCallback callback provided by API user, callback will be called when
-*            credential revocation is finished.
-* @return  OC_STACK_OK in case of success and other value otherwise.
-*          If OC_STACK_OK is returned, the caller of this API should wait for callback.
-*          OC_STACK_CONTINUE means operation is success but no request is need to be initiated.
-*/
+ * Function to device revocation
+ * This function will remove credential of target device from all devices in subnet.
+ *
+ * @param[in] ctx Application context to be returned in result callback
+ * @param[in] pOwnedDevList List of owned devices
+ * @param[in] pTargetDev Device information to be revoked.
+ * @param[in] resultCallback callback provided by API user, callback will be called when
+ *            credential revocation is finished.
+ * @return  OC_STACK_OK in case of success and other value otherwise.
+ *          If OC_STACK_OK is returned, the caller of this API should wait for callback.
+ *          OC_STACK_CONTINUE means operation is success but no request is need to be initiated.
+ */
 OCStackResult SRPRemoveDeviceWithoutDiscovery(void* ctx, const OCProvisionDev_t* pOwnedDevList,
                              const OCProvisionDev_t* pTargetDev, OCProvisionResultCB resultCallback);
 
@@ -229,7 +272,7 @@ OCStackResult SRPRemoveDeviceWithoutDiscovery(void* ctx, const OCProvisionDev_t*
  * Function to sync-up credential and ACL of the target device.
  * This function will remove credential and ACL of target device from all devices in subnet.
  *
- * @param[in] ctx Application context would be returned in result callback
+ * @param[in] ctx Application context to be returned in result callback
  * @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds)
  * @param[in] pTargetDev Device information to be revoked.
  * @param[in] resultCallback callback provided by API user, callback will be called when
index 1421f39..106bdc7 100644 (file)
@@ -200,7 +200,7 @@ OCStackResult OCIsSubownerOfDevice(OCProvisionDev_t *device, bool *isSubowner);
 /**\r
  * API to provision credentials between two devices and ACLs for the devices who act as a server.\r
  *\r
- * @param[in] ctx Application context would be returned in result callback.\r
+ * @param[in] ctx Application context returned in the result callback.\r
  * @param[in] type Type of credentials to be provisioned to the device.\r
  * @param[in] keySize size of key
  * @param[in] pDev1 Pointer to OCProvisionDev_t instance,respresenting device to be provisioned.\r
@@ -217,9 +217,9 @@ OCStackResult OCProvisionPairwiseDevices(void* ctx, OicSecCredType_t type, size_
                                          OCProvisionResultCB resultCallback);\r
 \r
 /**\r
- * API to send ACL information to device.\r
+ * API to send version 1 ACL information to device.\r
  *\r
- * @param[in] ctx Application context would be returned in result callback.\r
+ * @param[in] ctx Application context returned in the result callback.\r
  * @param[in] selectedDeviceInfo Selected target device.\r
  * @param[in] acl ACL to provision.\r
  * @param[in] resultCallback callback provided by API user, callback will be called when provisioning\r
@@ -230,6 +230,19 @@ OCStackResult OCProvisionACL(void *ctx, const OCProvisionDev_t *selectedDeviceIn
                              OCProvisionResultCB resultCallback);\r
 \r
 /**\r
+ * API to send version 2 ACL information to device.\r
+ *\r
+ * @param[in] ctx Application context returned in the result callback.\r
+ * @param[in] selectedDeviceInfo Selected target device.\r
+ * @param[in] acl ACL to provision.\r
+ * @param[in] resultCallback callback provided by API user, callback will be called when provisioning\r
+              request recieves a response from resource server.\r
+ * @return OC_STACK_OK in case of success and other value otherwise.\r
+ */\r
+OCStackResult OCProvisionACL2(void *ctx, const OCProvisionDev_t *selectedDeviceInfo, OicSecAcl_t *acl,
+                              OCProvisionResultCB resultCallback);\r
+\r
+/**\r
  * function to save ACL which has several ACE into Acl of SVR.\r
  *\r
  * @param acl ACL to be saved in Acl of SVR.\r
@@ -240,7 +253,7 @@ OCStackResult OCSaveACL(const OicSecAcl_t* acl);
 /**\r
  * this function requests CRED information to resource.\r
  *\r
- * @param[in] ctx Application context would be returned in result callback.\r
+ * @param[in] ctx Application context returned in the result callback.\r
  * @param[in] selectedDeviceInfo Selected target device.\r
  * @param[in] resultCallback callback provided by API user, callback will be called when provisioning\r
               request recieves a response from resource server.\r
@@ -250,9 +263,9 @@ OCStackResult OCGetCredResource(void* ctx, const OCProvisionDev_t *selectedDevic
                              OCProvisionResultCB resultCallback);\r
 \r
 /**\r
- * this function requests ACL information to resource.\r
+ * this function requests version 1 ACL information to resource.\r
  *\r
- * @param[in] ctx Application context would be returned in result callback.\r
+ * @param[in] ctx Application context returned in the result callback.\r
  * @param[in] selectedDeviceInfo Selected target device.\r
  * @param[in] resultCallback callback provided by API user, callback will be called when provisioning\r
               request recieves a response from resource server.\r
@@ -262,9 +275,60 @@ OCStackResult OCGetACLResource(void* ctx, const OCProvisionDev_t *selectedDevice
                              OCProvisionResultCB resultCallback);\r
 \r
 /**\r
+ * this function requests version 2 ACL information to resource.\r
+ *\r
+ * @param[in] ctx Application context returned in the result callback.\r
+ * @param[in] selectedDeviceInfo Selected target device.\r
+ * @param[in] resultCallback callback provided by API user, callback will be called when provisioning\r
+              request recieves a response from resource server.\r
+ * @return  OC_STACK_OK in case of success and other value otherwise.\r
+ */\r
+OCStackResult OCGetACL2Resource(void* ctx, const OCProvisionDev_t *selectedDeviceInfo,\r
+                               OCProvisionResultCB resultCallback);\r
+\r
+/**\r
+ * This function requests the device provide its Certificate Signing Request (CSR).\r
+ *\r
+ * @param[in] ctx Application context returned in the result callback.\r
+ * @param[in] selectedDeviceInfo Selected target device.\r
+ * @param[in] resultCallback callback provided by API user, callback will be called when provisioning\r
+              request recieves a response from resource server.\r
+ * @return  OC_STACK_OK in case of success and other value otherwise.\r
+ */\r
+OCStackResult OCGetCSRResource(void* ctx, const OCProvisionDev_t *selectedDeviceInfo,\r
+                               OCGetCSRResultCB resultCallback);\r
+\r
+/**\r
+ * This function requests the device provide its roles resource, listing the role certificates\r
+ * it has for the local requestor.\r
+ *\r
+ * @param[in] ctx Application context that is returned in the result callback.\r
+ * @param[in] selectedDeviceInfo Selected target device.\r
+ * @param[in] resultCallback callback provided by the API user. Callback will be called when provisioning\r
+ *                           request receives a response from the resource server.\r
+ * @return OC_STACK_OK in case of success, and error value otherwise.\r
+ */\r
+OCStackResult OCGetRolesResource(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,\r
+                                 OCGetRolesResultCB resultCallback);\r
+\r
+/**\r
+ * This function requests the device delete a particular role certificate by credId.\r
+ *\r
+ * @param[in] ctx Application context that is returned in the result callback.\r
+ * @param[in] selectedDeviceInfo Selected target device.\r
+ * @param[in] resultCallback callback provided by the API user. Callback will be called when request receives\r
+ *            a response from the resource server.\r
+ * @param[in] credId credId to request be deleted. If 0, delete all role certificates for this peer.\r
+ *\r
+ * @return OC_STACK_OK in case of success, and error value otherwise.\r
+ */\r
+OCStackResult OCDeleteRoleCertificateByCredId(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,\r
+                                              OCProvisionResultCB resultCallback, uint32_t credId);\r
+\r
+/**\r
  * this function sends Direct-Pairing Configuration to a device.\r
  *\r
- * @param[in] ctx Application context would be returned in result callback.\r
+ * @param[in] ctx Application context returned in the result callback.\r
  * @param[in] selectedDeviceInfo Selected target device.\r
  * @param[in] pconf PCONF pointer.\r
  * @param[in] resultCallback callback provided by API user, callback will be called when provisioning\r
@@ -277,7 +341,7 @@ OCStackResult OCProvisionDirectPairing(void* ctx, const OCProvisionDev_t *select
 /**\r
  * API to provision credential to devices.\r
  *\r
- * @param[in] ctx Application context would be returned in result callback.\r
+ * @param[in] ctx Application context returned in the result callback.\r
  * @param[in] type Type of credentials to be provisioned to the device.\r
  * @param[in] keySize size of key
  * @param[in] pDev1 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.\r
@@ -291,6 +355,21 @@ OCStackResult OCProvisionCredentials(void *ctx, OicSecCredType_t type, size_t ke
                                       const OCProvisionDev_t *pDev2,\r
                                       OCProvisionResultCB resultCallback);\r
 \r
+/**\r
+ * API to provision a certificate to a device.\r
+ *\r
+ * @param[in] ctx Application context returned in result callback.\r
+ * @param[in] pDev Pointer to OCProvisionDev_t instance, respresenting the device to be provsioned.\r
+ * @param[in] pemCert Certificate to provision, encoded as PEM\r
+ * @param[in] resultCallback callback provided by API user, callback will be called when\r
+ *            provisioning request receives a response from first resource server.\r
+ * @return OC_STACK_OK in case of success and other value otherwise.\r
+ */\r
+OCStackResult OCProvisionCertificate(void *ctx,\r
+                                     const OCProvisionDev_t *pDev,\r
+                                     const char* pemCert,\r
+                                     OCProvisionResultCB resultCallback);\r
+\r
 #ifdef MULTIPLE_OWNER\r
 /**\r
  * API to provision preconfigured PIN to device(NOT LIST).\r
@@ -298,7 +377,7 @@ OCStackResult OCProvisionCredentials(void *ctx, OicSecCredType_t type, size_t ke
  * OCProvisionPreconfigPin API will update the device's Doxm\r
  * and then try preconfigured PIN provisioning once again.\r
  *\r
- * @param[in] ctx Application context would be returned in result callback.\r
+ * @param[in] ctx Application context returned in the result callback.\r
  * @param[in] targetDeviceInfo Selected target device.\r
  * @param[in] preconfigPin string of preconfigured PIN.\r
  * @param[in] preconfigPinLen string length of 'preconfigPin'.\r
@@ -384,16 +463,16 @@ OCStackResult OCRemoveDevice(void* ctx,
                              OCProvisionResultCB resultCallback);\r
 \r
 /**\r
-* Function to device revocation\r
-* This function will remove credential of target device from all devices in subnet.\r
-*\r
-* @param[in] ctx Application context would be returned in result callback\r
-* @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds)\r
-* @param[in] pTargetUuid Device information to be revoked.\r
-* @param[in] resultCallback callback provided by API user, callback will be called when\r
-*            credential revocation is finished.\r
+ * Function to device revocation\r
+ * This function will remove credential of target device from all devices in subnet.\r
+ *\r
+ * @param[in] ctx Application context would be returned in result callback\r
+ * @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds)\r
+ * @param[in] pTargetUuid Device information to be revoked.\r
+ * @param[in] resultCallback callback provided by API user, callback will be called when\r
+ *            credential revocation is finished.\r
  * @return  OC_STACK_OK in case of success and other value otherwise.\r
-*/\r
+ */\r
 OCStackResult OCRemoveDeviceWithUuid(void* ctx,\r
                                      unsigned short waitTimeForOwnedDeviceDiscovery,\r
                                      const OicUuid_t* pTargetUuid,\r
@@ -492,7 +571,7 @@ void OCDeletePdAclList(OicSecPdAcl_t* pPdAcl);
 /**\r
  * this function sends CRL information to resource.\r
  *\r
- * @param[in] ctx Application context would be returned in result callback.\r
+ * @param[in] ctx Application context returned in the result callback.\r
  * @param[in] selectedDeviceInfo Selected target device.\r
  * @param[in] crl CRL to provision.\r
  * @param[in] resultCallback callback provided by API user, callback will be called when provisioning\r
@@ -505,7 +584,7 @@ OCStackResult OCProvisionCRL(void* ctx, const OCProvisionDev_t *selectedDeviceIn
 /**\r
  * function to provision Trust certificate chain to devices.\r
  *\r
- * @param[in] ctx Application context would be returned in result callback.\r
+ * @param[in] ctx Application context returned in the result callback.\r
  * @param[in] type Type of credentials to be provisioned to the device.\r
  * @param[in] credId CredId of trust certificate chain to be provisioned to the device.\r
  * @param[in] selectedDeviceInfo Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.\r
@@ -527,6 +606,17 @@ OCStackResult OCProvisionTrustCertChain(void *ctx, OicSecCredType_t type, uint16
  */\r
 OCStackResult OCSaveTrustCertChain(uint8_t *trustCertChain, size_t chainSize,\r
                                         OicEncodingType_t encodingType, uint16_t *credId);\r
+\r
+/**\r
+ * Function to save an identity certificate chain into Cred of SVR.\r
+ *\r
+ * @param[in] cert Certificate chain to be saved in Cred of SVR, PEM encoded, null terminated\r
+ * @param[in] key private key corresponding to the certificate, PEM encoded, null terminated\r
+ * @param[out] credId CredId of saved certificate chain in Cred of SVR.\r
+ * @return  OC_STACK_OK in case of success and other value otherwise.\r
+ */\r
+OCStackResult OCSaveOwnCertChain(char* cert, char* key, uint16_t *credId);\r
+\r
 /**\r
  * function to register callback, for getting notification for TrustCertChain change.\r
  *\r
index a1f8fb6..60e0255 100644 (file)
@@ -101,6 +101,30 @@ typedef struct OCPMResult{
     OCStackResult  res;
 }OCProvisionResult_t;
 
+typedef struct OCPMGetCsrResult
+{
+    OicUuid_t           deviceId;
+    OCStackResult       res;
+    uint8_t             *csr;
+    size_t              csrLen;
+    OicEncodingType_t   encoding; /* Determines contents of csr; either OIC_ENCODING_DER or OIC_ENCODING_PEM */
+} OCPMGetCsrResult_t;
+
+typedef struct OCPMRoleCertChain
+{
+    uint64_t            credId;         /**< credential ID */
+    OicSecKey_t         certificate;    /**< leaf certificate */
+    OicSecOpt_t         optData;        /**< intermediate CA certificates (if any) */
+} OCPMRoleCertChain_t;
+
+typedef struct OCPMGetRolesResult
+{
+    OicUuid_t           deviceId;       /**< responding device ID */
+    OCStackResult       res;            /**< result for this device */
+    OCPMRoleCertChain_t *chains;        /**< cert chains (if res is OC_STACK_OK) */
+    size_t              chainsLength;   /**< length of chains array (if res is OC_STACK_OK */
+} OCPMGetRolesResult_t;
+
 /**
  * Owner device type
  */
@@ -137,6 +161,33 @@ typedef enum OxmAllowTableIdx {
  */
 typedef void (*OCProvisionResultCB)(void* ctx, size_t nOfRes, OCProvisionResult_t *arr, bool hasError);
 
+/**
+ * Callback function definition of CSR retrieve API
+ *
+ * @param[OUT] ctx - If user set a context, it will be returned here.
+ * @param[OUT] nOfRes - total number of results
+ * @param[OUT] arr - Array of OCPMGetCsrResult_t, containing one entry for each target device. If an entry's res
+ *                   member is OC_STACK_OK, then csr and csrLen are valid; otherwise they should not be used.
+ *                   This memory is only valid while the callback is executing; callers must make copies if the data
+ *                   needs to be kept longer.
+ * @param[OUT] hasError - If all calls succeded, this will be false. One or more errors, and this will
+ *                        be true. Examine the elements of arr to discover which failed.
+ */
+typedef void (*OCGetCSRResultCB)(void* ctx, size_t nOfRes, OCPMGetCsrResult_t *arr, bool hasError);
+
+/**
+ * Callback function definition of roles retrieve API
+ *
+ * @param[OUT] ctx - If user set a context, it will be returned here.
+ * @param[OUT] nOfRes - total number of results
+ * @param[OUT] arr - Array of OCPMGetRolesResult_t, containing one entry for each target device. If an entry's res
+ *                   member is OC_STACK_OK, then chains and chainsLength are valid; otherwise they should not be used.
+ *                   This memory is only valid while the callback is executing; callers must make copies if the data
+ *                   needs to be kept longer.
+ * @param[OUT] hasError - If all calls succeeded, this will be false. One or more errors, and this will
+ *                        be true. Examine the elements of arr to discover which failed.
+ */
+typedef void (*OCGetRolesResultCB)(void* ctx, size_t nOfRes, OCPMGetRolesResult_t *arr, bool hasError);
 
 /**
  * Callback function definition of direct-pairing
index b8eb2cb..960f510 100644 (file)
@@ -79,10 +79,12 @@ else:
 ######################################################################
 
 provisioningclient = provisioning_sample_env.Program('provisioningclient', 'provisioningclient.c')
+autoprovisioningclient = provisioning_sample_env.Program('autoprovisioningclient', 'autoprovisioningclient.c')
 sampleserver_justworks = provisioning_sample_env.Program('sampleserver_justworks', 'sampleserver_justworks.cpp')
 sampleserver_randompin = provisioning_sample_env.Program('sampleserver_randompin', 'sampleserver_randompin.cpp')
 sampleserver_mfg = provisioning_sample_env.Program('sampleserver_mfg', 'sampleserver_mfg.cpp')
 sampleserver_mvjustworks = provisioning_sample_env.Program('sampleserver_mvjustworks', 'sampleserver_mvjustworks.cpp')
+certgenerator = provisioning_sample_env.Program('certgenerator', 'certgenerator.cpp')
 
 if provisioning_sample_env.get('MULTIPLE_OWNER') == '1':
        subownerclient = provisioning_sample_env.Program('subownerclient', 'subownerclient.c')
@@ -131,7 +133,7 @@ if provisioning_sample_env.get('WITH_TCP') == True:
 
 if provisioning_sample_env.get('MULTIPLE_OWNER') == '1':
        Alias("samples", [
-                                       provisioningclient, subownerclient,
+                                       provisioningclient, subownerclient, autoprovisioningclient,
                                        sampleserver_justworks, sampleserver_randompin, sampleserver_mfg,
                                        sampleserver_preconfpin,
                                        clientdat, subownerclientdat, preconfserverdat,
@@ -140,7 +142,7 @@ if provisioning_sample_env.get('MULTIPLE_OWNER') == '1':
                                ])
 else:
        Alias("samples", [
-                                       provisioningclient,
+                                       provisioningclient, autoprovisioningclient,
                                        sampleserver_justworks, sampleserver_randompin, sampleserver_mfg,
                                        clientdat,
                                        justworksdat, randompindat, mfgdat, randompin_with_emptyuuid_dat,
diff --git a/resource/csdk/security/provisioning/sample/autoprovisioningclient.c b/resource/csdk/security/provisioning/sample/autoprovisioningclient.c
new file mode 100644 (file)
index 0000000..4766c31
--- /dev/null
@@ -0,0 +1,744 @@
+/******************************************************************
+ *
+ * Copyright 2017 Microsoft. All Rights Reserved.
+ *
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *****************************************************************/
+
+/*
+ * This file is derived from iotivity\resource\csdk\security\provisioning\sample\provisioningclient.c
+ * That program is interactive, and requires user input to perform provisioning
+ * steps, while this version takes input on the command line and executes a
+ * sequence of provisioning operations automatically, then exists, reporting
+ * whether the sequence succeeded.  This is so that we can script provisioning
+ * for testing.
+ */
+
+#include "iotivity_config.h"
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include "payload_logging.h"
+#include "utlist.h"
+#include "logger.h"
+#include "oic_malloc.h"
+#include "oic_string.h"
+#include "ocprovisioningmanager.h"
+#include "oxmjustworks.h"
+#include "oxmrandompin.h"
+#include "securevirtualresourcetypes.h"
+#include "srmutility.h"
+#include "pmtypes.h"
+#include "oxmverifycommon.h"
+#include "mbedtls/config.h"
+#include "mbedtls/pem.h"
+#include "mbedtls/x509_csr.h"
+#include "certhelpers.h"
+
+#ifdef _MSC_VER
+#include <io.h>
+
+#define F_OK 0
+#define access _access_s
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif //__cplusplus
+
+#define DISCOVERY_TIMEOUT   3  // 3 sec
+#define CALLBACK_TIMEOUT    60  // 1 min
+#define TAG "provisioningclient"
+
+static const char* SVR_DB_FILE_NAME = "oic_svr_db_client.dat";
+        // '_' for separaing from the same constant variable in |srmresourcestrings.c|
+static const char* PRVN_DB_FILE_NAME = "oic_autoprvn_mng.db";
+
+// |g_ctx| means provision manager application context and
+// the following, includes |un/own_list|, could be variables, which |g_ctx| has,
+// for accessing all function(s) for these, they are declared on global domain
+static char* g_ctx = "Provision Manager Client Application Context";
+static char* g_svr_fname;
+static char* g_prvn_fname;
+static OCProvisionDev_t* g_own_list;
+static OCProvisionDev_t* g_unown_list;
+static int g_own_cnt;
+static int g_unown_cnt;
+mbedtls_x509_csr g_csr;
+
+static volatile bool g_doneCB;    /* Set to true by the callback to indicate it completed. */
+static bool g_successCB; /* Set to true by the callback to indicate success. */
+
+// function declaration(s) for calling them before implementing
+
+static OCProvisionDev_t* getDevInst(const OCProvisionDev_t*, const int);
+static int printDevList(const OCProvisionDev_t*);
+static size_t printUuidList(const OCUuidList_t*);
+static size_t printResultList(const OCProvisionResult_t*, const size_t);
+static void printUuid(const OicUuid_t*);
+static FILE* fopen_prvnMng(const char*, const char*);
+static int waitCallbackRet(void);
+
+/* At a few places in this file, warning 4028 is incorrectly produced, disable it for the whole file. */\r
+#ifdef _MSC_VER\r
+#pragma warning( disable : 4028)\r
+#endif
+
+// callback function(s) for provisioning client using C-level provisioning API
+static void ownershipTransferCB(void* ctx, size_t nOfRes, OCProvisionResult_t* arr, bool hasError)
+{
+    if(!hasError)
+    {
+        OIC_LOG_V(INFO, TAG, "Ownership Transfer SUCCEEDED - ctx: %s", (char*) ctx);
+        g_successCB = true;
+    }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "Ownership Transfer FAILED - ctx: %s", (char*) ctx);
+        printResultList((const OCProvisionResult_t*) arr, nOfRes);
+        g_successCB = false;
+    }
+    g_doneCB = true;
+}
+
+static void provisionCredCB(void* ctx, size_t nOfRes, OCProvisionResult_t* arr, bool hasError)
+{
+    if(!hasError)
+    {
+        OIC_LOG_V(INFO, TAG, "Provision Credential SUCCEEDED - ctx: %s", (char*) ctx);
+        g_successCB = true;
+    }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "Provision Credential FAILED - ctx: %s", (char*) ctx);
+        printResultList((const OCProvisionResult_t*) arr, nOfRes);
+        g_successCB = false;
+    }
+    g_doneCB = true;
+}
+
+/* Function of type OCProvisionResultCB from \resource\csdk\security\provisioning\include\pmtypes.h */
+void provisionTrustChainCB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError)
+{
+    if(!hasError)
+    {
+        OIC_LOG_V(INFO, TAG, "Provision Credential SUCCEEDED - ctx: %s", (char*)ctx);
+        g_successCB = true;
+    }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "Provision Credential FAILED - ctx: %s", (char*)ctx);
+        printResultList((const OCProvisionResult_t*)arr, nOfRes);
+        g_successCB = false;
+    }
+    g_doneCB = true;
+}
+
+static void getCsrForCertProvCB(void* ctx, size_t nOfRes, OCPMGetCsrResult_t* arr, bool hasError)
+{
+    g_successCB = false;
+
+    if(!hasError)
+    {
+        if(nOfRes != 1)
+        {
+            OIC_LOG_V(ERROR, TAG, "getCsrForCertProvCB FAILED - ctx: %s", (char*)ctx);
+            goto exit;
+        }
+
+        mbedtls_x509_csr_init(&g_csr);
+        int ret = mbedtls_x509_csr_parse(&g_csr, arr[0].csr, arr[0].csrLen);
+        if(ret < 0)
+        {
+            OIC_LOG_V(ERROR, TAG, "Couldn't parse CSR: %d", ret);
+            mbedtls_x509_csr_free(&g_csr);
+
+            goto exit;
+        }
+
+        OIC_LOG(INFO, TAG, "getCsrForCertProvCB success");
+        g_successCB = true;
+    }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "getCsrForCertProvCB FAILED - ctx: %s", (char*)ctx);
+    }
+
+exit:
+    g_doneCB = true;
+}
+
+// function(s) for provisioning client using C-level provisioning API
+static int initProvisionClient(void)
+{
+    // initialize persistent storage for SVR DB
+    static OCPersistentStorage pstStr =
+    {
+        .open = fopen_prvnMng,
+        .read = fread,
+        .write = fwrite,
+        .close = fclose,
+        .unlink = remove
+    };
+    if (OC_STACK_OK != OCRegisterPersistentStorageHandler(&pstStr))
+    {
+        OIC_LOG(ERROR, TAG, "OCRegisterPersistentStorageHandler error");
+        return -1;
+    }
+
+    // initialize OC stack and provisioning manager
+    if (OC_STACK_OK != OCInit(NULL, 0, OC_CLIENT_SERVER))
+    {
+        OIC_LOG(ERROR, TAG, "OCStack init error");
+        return -1;
+    }
+
+    if (access(PRVN_DB_FILE_NAME, F_OK) == 0)
+    {
+        printf("************************************************************\n");
+        printf("************Provisioning DB file already exists.************\n");
+        printf("************************************************************\n");
+    }
+    else
+    {
+        printf("*************************************************************\n");
+        printf("************No provisioning DB file, creating new************\n");
+        printf("*************************************************************\n");
+    }
+
+    if (OC_STACK_OK != OCInitPM(PRVN_DB_FILE_NAME))
+    {
+        OIC_LOG(ERROR, TAG, "OC_PM init error");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int discoverAllDevices(void)
+{
+    // delete un/owned device lists before updating them
+    if(g_own_list)
+    {
+        OCDeleteDiscoveredDevices(g_own_list);
+        g_own_list = NULL;
+    }
+    if(g_unown_list)
+    {
+        OCDeleteDiscoveredDevices(g_unown_list);
+        g_unown_list = NULL;
+    }
+
+    // call |OCGetDevInfoFromNetwork| API
+    printf("   Discovering All Un/Owned Devices on Network..\n");
+    if(OC_STACK_OK != OCGetDevInfoFromNetwork(DISCOVERY_TIMEOUT, &g_own_list, &g_unown_list))
+    {
+        OIC_LOG(ERROR, TAG, "OCGetDevInfoFromNetwork API error");
+        return -1;
+    }
+
+    // display the discovered un/owned lists
+    printf("   > Discovered Owned Devices\n");
+    g_own_cnt = printDevList(g_own_list);
+    printf("   > Discovered Unowned Devices\n");
+    g_unown_cnt = printDevList(g_unown_list);
+
+    return 0;
+}
+
+
+static int discoverUnownedDevices(void)
+{
+    // delete unowned device list before updating it
+    if(g_unown_list)
+    {
+        OCDeleteDiscoveredDevices(g_unown_list);
+        g_unown_list = NULL;
+    }
+
+    // call |OCDiscoverUnownedDevices| API
+    printf("   Discovering Only Unowned Devices on Network..\n");
+    if(OC_STACK_OK != OCDiscoverUnownedDevices(DISCOVERY_TIMEOUT, &g_unown_list))
+    {
+        OIC_LOG(ERROR, TAG, "OCDiscoverUnownedDevices API error");
+        return -1;
+    }
+
+    // display the discovered unowned list
+    printf("   > Discovered Unowned Devices\n");
+    g_unown_cnt = printDevList(g_unown_list);
+
+    return 0;
+}
+
+static int discoverOwnedDevices(void)
+{
+    // delete owned device list before updating it
+    if(g_own_list)
+    {
+        OCDeleteDiscoveredDevices(g_own_list);
+        g_own_list = NULL;
+    }
+
+    // call |OCDiscoverOwnedDevices| API
+    printf("   Discovering Only Owned Devices on Network..\n");
+    if(OC_STACK_OK != OCDiscoverOwnedDevices(DISCOVERY_TIMEOUT, &g_own_list))
+    {
+        OIC_LOG(ERROR, TAG, "OCDiscoverOwnedDevices API error");
+        return -1;
+    }
+
+    // display the discovered owned list
+    printf("   > Discovered Owned Devices\n");
+    g_own_cnt = printDevList(g_own_list);
+
+    return 0;
+}
+
+static int registerDevices(void)
+{
+    // check |unown_list| for registering devices
+    if(!g_unown_list || 0>=g_unown_cnt)
+    {
+        OIC_LOG(ERROR, TAG, "Unowned device list empty, must discover unowned devices first");
+        return -1;  // Error, we should have registered unowned devices already
+    }
+
+    // call |OCDoOwnershipTransfer| API
+    // calling this API with callback actually acts like blocking
+    // for error checking, the return value saved and printed
+    g_doneCB = false;
+    printf("   Registering All Discovered Unowned Devices..\n");
+    OCStackResult rst = OCDoOwnershipTransfer((void*) g_ctx, g_unown_list, ownershipTransferCB);
+    if(OC_STACK_OK != rst)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCDoOwnershipTransfer API error: %d", rst);
+        return -1;
+    }
+    if(waitCallbackRet())  // input |g_doneCB| flag implicitly
+    {
+        OIC_LOG(ERROR, TAG, "OCDoOwnershipTransfer callback error");
+        return -1;
+    }
+
+    if(!g_successCB)
+    {
+        OIC_LOG(ERROR, TAG, "OCDoOwnershipTransfer callback failed");
+        return -1;
+    }
+
+    // display the registered result
+    printf("   > Registered Discovered Unowned Devices\n");
+    printf("   > Please Discover Owned Devices for the Registered Result, with [10|12] Menu\n");
+
+    return 0;
+}
+
+/*
+* Test CA key and certificate created with
+* iotivity/resource/csdk/security/scripts/test_cert_generation.sh
+*/
+const char* caCertPem = "-----BEGIN CERTIFICATE-----\n"
+"MIIBfzCCASSgAwIBAgIJAOMHgsOiVyXpMAoGCCqGSM49BAMCMBkxFzAVBgNVBAoM\n"
+"DklvVGl2aXR5VGVzdENBMB4XDTE3MDEwNjAwNDA1M1oXDTMwMDkxNTAwNDA1M1ow\n"
+"GTEXMBUGA1UECgwOSW9UaXZpdHlUZXN0Q0EwWTATBgcqhkjOPQIBBggqhkjOPQMB\n"
+"BwNCAAQMaZlQqz2C2DFRh3xcATSAyEIp9RIjYMU8/x6cZ0OTKA0ihZCDXmMksLk8\n"
+"zWhYI/Sr7wpYxBaQh5yvaiP5zFl2o1UwUzAhBgNVHSUEGjAYBgorBgEEAYLefAEG\n"
+"BgorBgEEAYLefAEHMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHnMVojc5HNr\n"
+"fuLOz3iNV3u3vG3kMAoGCCqGSM49BAMCA0kAMEYCIQC7+/pCT8hEupk3nhStU3pF\n"
+"QmJg6VCbcFKMY8MmqyBx2QIhAIwM63/OPXh9hpbRoVp5Z90KxUvbjZ/XstqULmYl\n"
+"LzEE\n"
+"-----END CERTIFICATE-----\n";
+
+const char* caKeyPem = "-----BEGIN EC PRIVATE KEY-----\n"
+"MHcCAQEEID8CoB1N6UCnGYZPAKWu376GtJxW7KlI2BXzS3ISQrEnoAoGCCqGSM49\n"
+"AwEHoUQDQgAEUjKmL4wS485e3FIl3s07qvN+Auw0ra6+/y2phVu/qA/D92rd+HJK\n"
+"Tnzf9FpTBRvWkiUh8rAWVuwoQxVkLmr9WA==\n"
+"-----END EC PRIVATE KEY-----\n";
+
+static int provisionTrustAnchor(int dev_num)
+{
+    // make sure we own at least one device to provision
+    if(!g_own_list || g_own_cnt == 0)
+    {
+        OIC_LOG(ERROR, TAG, "Unowned device list empty, must discover unowned devices first");
+        return -1;  // Error, we should have registered unowned devices already
+    }
+
+    OCProvisionDev_t* targetDevice = getDevInst((const OCProvisionDev_t*)g_own_list, dev_num);
+    if(targetDevice == NULL)
+    {
+        OIC_LOG(ERROR, TAG, "Error, invalid device %d");
+        return -1;
+    }
+
+    // Install the CA trust anchor
+    uint16_t caCredId = 0;
+    OCStackResult rst = OCSaveTrustCertChain((uint8_t*)caCertPem, strlen(caCertPem) + 1,
+        OIC_ENCODING_PEM, &caCredId);
+    if (OC_STACK_OK != rst)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCSaveTrustCertChain error: %d", rst);
+        return -1;
+    }
+
+    // Provision the CA root cert to the target device
+    printf("   > Saving root certificate (trust anchor) to selected device..\n");
+    g_doneCB = false;
+    OicSecCredType_t type = SIGNED_ASYMMETRIC_KEY;
+
+    rst = OCProvisionTrustCertChain((void*)g_ctx, type, caCredId, targetDevice, &provisionTrustChainCB);
+    if(OC_STACK_OK != rst)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCProvisionTrustCertChain returned error: %d", rst);
+        return -1;
+    }
+
+    if(waitCallbackRet())  // input |g_doneCB| flag implicitly
+    {
+        OIC_LOG(ERROR, TAG, "OCProvisionTrustCertChain callback error");
+        return -1;
+    }
+    if(!g_successCB)
+    {
+        return -1;
+    }
+
+    printf("   > Provisioned certificate trust anchor\n");
+
+    return 0;
+
+}
+
+static int getCsr(int dev_num)
+{
+    // check |own_list| for retrieving CSR
+    if(!g_own_list || 1 > g_own_cnt)
+    {
+        OIC_LOG(ERROR, TAG, "Unowned device list empty, must discover unowned devices first");
+        return -1;  // Error, we should have registered unowned devices already
+    }
+
+    // call |getDevInst| API
+    // calling this API with callback actually acts like blocking
+    // for error checking, the return value saved and printed
+    g_doneCB = false;
+    OCProvisionDev_t* dev = getDevInst((const OCProvisionDev_t*) g_own_list, dev_num);
+    if(!dev)
+    {
+        OIC_LOG(ERROR, TAG, "getDevInst: device instance empty");
+        goto GETCSR_ERROR;
+    }
+    OCStackResult rst = OCGetCSRResource((void*) g_ctx, dev, getCsrForCertProvCB);
+    if(OC_STACK_OK != rst)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCGetCSRResource API error: %d", rst);
+
+        goto GETCSR_ERROR;
+    }
+    if(waitCallbackRet())  // input |g_doneCB| flag implicitly
+    {
+        OIC_LOG(ERROR, TAG, "OCGetCSRResource callback error");
+        goto GETCSR_ERROR;
+    }
+    if(!g_successCB)
+    {
+        return -1;
+    }
+
+    /* @todo: once change https://gerrit.iotivity.org/gerrit/#/c/17509 merges, we'll have this function */
+#if 0
+    int ret = OCInternalVerifyCSRSignature(&g_csr);
+    if(ret != 0)
+    {
+        OIC_LOG(ERROR, TAG, "Failed to validate CSR signature");
+        mbedtls_x509_csr_free(&g_csr);
+        return -1;
+    }
+#endif
+    mbedtls_x509_csr_free(&g_csr);
+
+    printf("   > Get CSR SUCCEEDED\n");
+
+    return 0;
+
+GETCSR_ERROR:
+    printf("   > Get CSR FAILED\n");
+    return -1;
+}
+
+static OCProvisionDev_t* getDevInst(const OCProvisionDev_t* dev_lst, const int dev_num)
+{
+    if (!dev_lst || 0 >= dev_num)
+    {
+        printf("     Device List is Empty..\n");
+        return NULL;
+    }
+
+    OCProvisionDev_t* lst = (OCProvisionDev_t*)dev_lst;
+    for (int i = 0; lst; )
+    {
+        if (dev_num == ++i)
+        {
+            return lst;
+        }
+        lst = lst->next;
+    }
+
+    return NULL;  // in here |lst| is always |NULL|
+}
+
+static int printDevList(const OCProvisionDev_t* dev_lst)
+{
+    if (!dev_lst)
+    {
+        printf("     Device List is Empty..\n\n");
+        return 0;
+    }
+
+    OCProvisionDev_t* lst = (OCProvisionDev_t*)dev_lst;
+    int lst_cnt = 0;
+    for (; lst; )
+    {
+        printf("     [%d] ", ++lst_cnt);
+        printUuid((const OicUuid_t*)&lst->doxm->deviceID);
+        printf("\n");
+        lst = lst->next;
+    }
+    printf("\n");
+
+    return lst_cnt;
+}
+
+static size_t printUuidList(const OCUuidList_t* uid_lst)
+{
+    if (!uid_lst)
+    {
+        printf("     Device List is Empty..\n\n");
+        return 0;
+    }
+
+    OCUuidList_t* lst = (OCUuidList_t*)uid_lst;
+    size_t lst_cnt = 0;
+    for (; lst; )
+    {
+        printf("     [%zu] ", ++lst_cnt);
+        printUuid((const OicUuid_t*)&lst->dev);
+        printf("\n");
+        lst = lst->next;
+    }
+    printf("\n");
+
+    return lst_cnt;
+}
+
+static size_t printResultList(const OCProvisionResult_t* rslt_lst, const size_t rslt_cnt)
+{
+    if (!rslt_lst || (0 == rslt_cnt))
+    {
+        printf("     Device List is Empty..\n\n");
+        return 0;
+    }
+
+    size_t lst_cnt = 0;
+    for (; rslt_cnt > lst_cnt; ++lst_cnt)
+    {
+        printf("     [%" PRIuPTR "] ", lst_cnt + 1);
+        printUuid((const OicUuid_t*)&rslt_lst[lst_cnt].deviceId);
+        printf(" - result: %d\n", rslt_lst[lst_cnt].res);
+    }
+    printf("\n");
+
+    return lst_cnt;
+}
+
+static void printUuid(const OicUuid_t* uid)
+{
+    for (int i = 0; i<UUID_LENGTH; )
+    {
+        printf("%02X", (*uid).id[i++]);
+        if (i == 4 || i == 6 || i == 8 || i == 10)  // canonical format for UUID has '8-4-4-4-12'
+        {
+            printf("-");
+        }
+    }
+}
+
+static FILE* fopen_prvnMng(const char* path, const char* mode)
+{
+    if (0 == strncmp(path, OC_SECURITY_DB_DAT_FILE_NAME, strlen(OC_SECURITY_DB_DAT_FILE_NAME)))
+    {
+        // input |g_svr_db_fname| internally by force, not using |path| parameter
+        // because |OCPersistentStorage::open| is called |OCPersistentStorage| internally
+        // with its own |SVR_DB_FILE_NAME|
+        return fopen(SVR_DB_FILE_NAME, mode);
+    }
+    else
+    {
+        return fopen(path, mode);
+    }
+}
+
+static int waitCallbackRet(void)
+{
+    for(int i = 0; !g_doneCB; ++i)
+    {
+        if(OC_STACK_OK != OCProcess())
+        {
+            OIC_LOG(ERROR, TAG, "OCStack process error");
+            return -1;
+        }
+
+        if (i == CALLBACK_TIMEOUT)
+        {
+            return -1;
+        }
+
+        sleep(1);
+    }
+
+    return 0;
+}
+
+void shutdownProvisionClient()
+{
+    if(OC_STACK_OK != OCStop())
+    {
+        OIC_LOG(ERROR, TAG, "OCStack stop error");
+    }
+    OCDeleteDiscoveredDevices(g_own_list);  // after here |g_own_list| points to nothing
+    OCDeleteDiscoveredDevices(g_unown_list);  // after here |g_unown_list| points to nothing
+
+    OICFreeAndSetToNull(&g_svr_fname);
+    OICFreeAndSetToNull(&g_prvn_fname);
+}
+
+static int initDiscoverRegisterAllDevices()
+{
+    if(initProvisionClient())
+    {
+        OIC_LOG_V(ERROR, TAG, "%s: ProvisionClient init error", __func__);
+        return -1;
+    }
+
+    if(discoverAllDevices())
+    {
+        OIC_LOG_V(ERROR, TAG, "%s: Discovery failed", __func__);
+        return -1;
+    }
+
+    if(registerDevices())
+    {
+        OIC_LOG_V(ERROR, TAG, "%s: Failed to onboard devices", __func__);
+        return -1;
+    }
+
+    if(discoverAllDevices())
+    {
+        OIC_LOG_V(ERROR, TAG, "%s: Re-discovery failed after registerDevices", __func__);
+        return -1;
+    }
+
+    return 0;
+
+}
+
+int TestTrustAnchorProvisioning()
+{
+    int ret = -1;
+
+    OIC_LOG_V(ERROR, TAG, "Running %s", __func__);
+
+    if(initDiscoverRegisterAllDevices())
+    {
+        OIC_LOG_V(ERROR, TAG, "%s: Failed discover and provision devices", __func__);
+        goto exit;
+    }
+
+    /* There should be one owned device with number 1. */
+    if(provisionTrustAnchor(1))
+    {
+        OIC_LOG_V(ERROR, TAG, "%s: Failed to provision trust anchor to device", __func__);
+        goto exit;
+    }
+
+    ret = 0;
+
+exit:
+
+    shutdownProvisionClient();
+
+    return ret;
+}
+
+int TestCSRResource()
+{
+    int ret = -1;
+
+    OIC_LOG_V(ERROR, TAG, "Running %s", __func__);
+
+    if(initDiscoverRegisterAllDevices())
+    {
+        OIC_LOG_V(ERROR, TAG, "%s: Failed discover and provision devices", __func__);
+        goto exit;
+    }
+
+    /* There should be one owned device with number 1. */
+    if(getCsr(1))
+    {
+        OIC_LOG(ERROR, TAG, "Test1: Failed to get CSR from device");
+        goto exit;
+    }
+
+    ret = 0;
+
+exit:
+
+    shutdownProvisionClient();
+
+    return ret;
+}
+
+// main function for provisioning client using C-level provisioning API
+int main(int argc, char** argv)
+{
+    if(argc != 2)
+    {
+        printf("%s: No test number provided (argc = %d)\n", argv[0], argc);
+        return 1;
+    }
+
+    unsigned int testNumber = strtoul(argv[1], NULL, 10);
+    switch (testNumber)
+    {
+        case 1:
+            return TestTrustAnchorProvisioning();
+        case 2:
+            return TestCSRResource();
+        default:
+            printf("%s: Invalid test number\n", argv[0]);
+            return 1;
+    }
+
+}
+
+#ifdef __cplusplus
+}
+#endif //__cplusplus
diff --git a/resource/csdk/security/provisioning/sample/certgenerator.cpp b/resource/csdk/security/provisioning/sample/certgenerator.cpp
new file mode 100644 (file)
index 0000000..6db0b4f
--- /dev/null
@@ -0,0 +1,535 @@
+//******************************************************************
+//
+// Copyright 2017 Microsoft
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//******************************************************************
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <vector>
+
+#include "ocstack.h"
+#include "oic_malloc.h"
+#include "ocrandom.h"
+#include "occertutility.h"
+
+#ifdef HAVE_WINDOWS_H
+#include <windows.h>
+/** @todo stop-gap for naming issue. Windows.h does not like us to use ERROR */
+#ifdef ERROR
+#undef ERROR
+#endif //ERROR
+#endif //HAVE_WINDOWS_H
+
+static long GetFileSize(FILE *f)
+{
+    long offset, size;
+
+    offset = ftell(f);
+
+    if (offset < 0)
+    {
+        return offset;
+    }
+
+    if (fseek(f, 0, SEEK_END) < 0)
+    {
+        return -1;
+    }
+
+    size = ftell(f);
+
+    if (fseek(f, 0, SEEK_SET) < 0)
+    {
+        return -1;
+    }
+
+    return size;
+}
+
+static char *ReadLine(char *buf, size_t len)
+{
+    char *p;
+    int lenAsInt;
+
+    if (len > 0xFFFFFFFF)
+    {
+        return NULL;
+    }
+    else
+    {
+        lenAsInt = (int)len;
+    }
+
+    if (NULL == fgets(buf, lenAsInt, stdin))
+    {
+        return NULL;
+    }
+
+    /* Trim newline that fgets stores in the buffer. */
+    for (p = buf; ((p - buf) < lenAsInt) && (*p != '\r') && (*p != '\n'); p++);
+
+    *p = '\0';
+
+    return buf;
+}
+
+typedef enum {
+    CA_CERT,
+    IDENTITY_CERT,
+    ROLE_CERT
+} CertType;
+
+static void DoGenCertificate(CertType certType)
+{
+    OCStackResult res;
+    char subjKeyPairName[50];
+    char issKeyPairName[50];
+    char filename[70];
+    char subject[100];
+    char authority[100];
+    OicUuid_t subjectUuid;
+    char notValidBefore[50];
+    char notValidAfter[50];
+    char *serial = NULL;
+    size_t serialLen = 0;
+    long fileLen = 0;
+    size_t bytesProcessed = 0;
+    std::vector<char> publicKey;
+    std::vector<char> privateKey;
+    std::vector<char> issuerCert;
+    FILE *f = NULL;
+    time_t nowTimeT;
+    struct tm *now;
+    char *certificate = NULL;
+    size_t certificateLen = 0;
+
+    printf("Subject key pair name (do not include .pub or .prv): ");
+    if (NULL == ReadLine(subjKeyPairName, sizeof(subjKeyPairName)))
+    {
+        printf("Failed to get key pair name!");
+        goto exit;
+    }
+
+    /* This sample only supports self-signed CAs. Intermediates can be created with
+     * the helper functions, though, by providing a different issuer private key and
+     * certificate.
+     */
+    if (CA_CERT != certType)
+    {
+        printf("Issuer cert/key pair name (do not include .crt, .pub, or .prv): ");
+        if (NULL == ReadLine(issKeyPairName, sizeof(issKeyPairName)))
+        {
+            printf("Failed to get key pair name!");
+            goto exit;
+        }
+    }
+    else
+    {
+        strcpy(issKeyPairName, subjKeyPairName);
+    }
+
+    // -- Load public key --
+
+    sprintf(filename, "%s.pub", subjKeyPairName);
+    f = fopen(filename, "rb");
+    if (NULL == f)
+    {
+        printf("Could not open public key!\n");
+        goto exit;
+    }
+
+    fileLen = GetFileSize(f);
+    if (fileLen < 0)
+    {
+        printf("Could not get size of public key!\n");
+        goto exit;
+    }
+
+    publicKey.resize(fileLen);
+    bytesProcessed = fread(publicKey.data(), 1, publicKey.size(), f);
+    if (bytesProcessed < publicKey.size())
+    {
+        printf("Could not read public key! Got %zu, expected %zu\n", bytesProcessed, publicKey.size());
+        goto exit;
+    }
+
+    if (0 != fclose(f))
+    {
+        printf("Warning: could not fclose public key\n");
+    }
+
+    // -- Load private key --
+    sprintf(filename, "%s.prv", issKeyPairName);
+    f = fopen(filename, "rb");
+    if (NULL == f)
+    {
+        printf("Could not open private key!\n");
+        goto exit;
+    }
+
+    fileLen = GetFileSize(f);
+    if (fileLen < 0)
+    {
+        printf("Could not get size of private key!\n");
+        goto exit;
+    }
+
+    privateKey.resize(fileLen);
+    bytesProcessed = fread(privateKey.data(), 1, privateKey.size(), f);
+    if (bytesProcessed < privateKey.size())
+    {
+        printf("Could not read private key! Got %zu, expected %zu\n", bytesProcessed, privateKey.size());
+        goto exit;
+    }
+
+    if (0 != fclose(f))
+    {
+        printf("Warning: could not fclose private key\n");
+    }
+
+    f = NULL;
+
+    // -- Load issuer cert if applicable --
+    if (CA_CERT != certType)
+    {
+        sprintf(filename, "%s.crt", issKeyPairName);
+        f = fopen(filename, "rb");
+        if (NULL == f)
+        {
+            printf("Could not open issuer certificate file!\n");
+            goto exit;
+        }
+
+        fileLen = GetFileSize(f);
+        if (fileLen < 0)
+        {
+            printf("Could not get size of issuer certificate!\n");
+            goto exit;
+        }
+
+        issuerCert.resize(fileLen);
+        bytesProcessed = fread(issuerCert.data(), 1, issuerCert.size(), f);
+        if (bytesProcessed < issuerCert.size())
+        {
+            printf("Could not read issuer certificate! Got %zu, expected %zu\n", bytesProcessed, issuerCert.size());
+            goto exit;
+        }
+
+        if (0 != fclose(f))
+        {
+            printf("Warning: could not fclose issuer certificate\n");
+        }
+
+        f = NULL;
+    }
+
+    // -- Prompt user for subject name --
+
+    if (CA_CERT == certType)
+    {
+        printf("Subject name as comma-separated list of RDN types and values\n");
+        printf("e.g.: C=US, O=Open Connectivity Foundation, CN=Main CA : ");
+        if (NULL == ReadLine(subject, sizeof(subject)))
+        {
+            printf("Failed to get subject!\n");
+            goto exit;
+        }
+    }
+    else
+    {
+        printf("Subject UUID in the RFC 4122 form (XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX): ");
+        if (NULL == ReadLine(subject, sizeof(subject)))
+        {
+            printf("Failed to get subject UUID!");
+            goto exit;
+        }
+
+        if (!OCConvertStringToUuid(subject, subjectUuid.id))
+        {
+            printf("Failed to parse input UUID!\n");
+            goto exit;
+        }
+    }
+
+    // -- Compute validity to be ten years from current time --
+    nowTimeT = time(NULL);
+    now = gmtime(&nowTimeT);
+
+    if (0 == strftime(notValidBefore, sizeof(notValidBefore), "%Y%m%d%H%M%S", now))
+    {
+        printf("Failed to format notValidBefore time!");
+        goto exit;
+    }
+
+    now->tm_year += 10;
+
+    if (0 == strftime(notValidAfter, sizeof(notValidAfter), "%Y%m%d%H%M%S", now))
+    {
+        printf("Failed to format notValidAfter time!");
+        goto exit;
+    }
+
+    // -- Generate random serial number. A real CA should record serial numbers as they are used, and --
+    // -- make sure none are ever repeated!                                                           --
+
+    res = OCGenerateRandomSerialNumber(&serial, &serialLen);
+    if (OC_STACK_OK != res)
+    {
+        printf("Failed to generate a serial number!\n");
+        goto exit;
+    }
+
+    switch (certType)
+    {
+    case CA_CERT:
+        res = OCGenerateCACertificate(
+            subject,
+            publicKey.data(),
+            NULL,
+            privateKey.data(),
+            serial,
+            notValidBefore,
+            notValidAfter,
+            &certificate,
+            &certificateLen);
+        break;
+
+    case IDENTITY_CERT:
+        res = OCGenerateIdentityCertificate(
+            &subjectUuid,
+            publicKey.data(),
+            issuerCert.data(),
+            privateKey.data(),
+            serial,
+            notValidBefore,
+            notValidAfter,
+            &certificate,
+            &certificateLen);
+        break;
+
+    case ROLE_CERT:
+        printf("Role name: ");
+        /* We don't need subject's contents now, so reuse the buffer.*/
+        if (NULL == ReadLine(subject, sizeof(subject)))
+        {
+            printf("Failed to read role name!\n");
+            goto exit;
+        }
+        printf("Authority name (press ENTER for none): ");
+        if (NULL == ReadLine(authority, sizeof(authority)))
+        {
+            printf("Failed to read authority name!\n");
+            goto exit;
+        }
+        res = OCGenerateRoleCertificate(
+            &subjectUuid,
+            publicKey.data(),
+            issuerCert.data(),
+            privateKey.data(),
+            serial,
+            notValidBefore,
+            notValidAfter,
+            subject,
+            ('\0' != *authority)?authority:NULL,
+            &certificate,
+            &certificateLen);
+        break;
+    }
+
+    if (OC_STACK_OK != res)
+    {
+        printf("Failed to generate certificate!\n");
+        goto exit;
+    }
+
+    sprintf(filename, "%s.crt", subjKeyPairName);
+    f = fopen(filename, "wb");
+    if (NULL == f)
+    {
+        printf("Failed to open certificate file for writing!\n");
+        goto exit;
+    }
+    
+    bytesProcessed = fwrite(certificate, 1, certificateLen, f);
+    if (bytesProcessed < certificateLen)
+    {
+        printf("Failed to write certificate! Had %zu bytes, wrote %zu\n", certificateLen, bytesProcessed);
+        goto exit;
+    }
+
+    if (0 != fclose(f))
+    {
+        printf("Warning: failed to close certificate file\n");
+        goto exit;
+    }
+
+    f = NULL;
+
+    printf("Wrote certificate file.\n");
+
+exit:
+
+    OICFree(serial);
+    OICFree(certificate);
+    if (NULL != f)
+    {
+        if (0 != fclose(f))
+        {
+            printf("Warning: failed to fclose\n");
+        }
+    }
+}
+
+static void DoGenKeyPair()
+{
+    OCStackResult res = OC_STACK_OK;
+    char nameBuf[100];
+    char *publicKey = NULL;
+    char *privateKey = NULL;
+    size_t publicKeyLen = 0;
+    size_t privateKeyLen = 0;
+    FILE *f = NULL;
+
+    printf("Name the key pair: ");
+    if (NULL == ReadLine(nameBuf, sizeof(nameBuf)))
+    {
+        printf("Failed to read name!");
+        return;
+    }
+
+    res = OCGenerateKeyPair(&publicKey, &publicKeyLen, &privateKey, &privateKeyLen);
+    if (OC_STACK_OK == res)
+    {
+        char filename[120];
+        size_t written;
+
+        sprintf(filename, "%s.pub", nameBuf);
+        f = fopen(filename, "wb");
+        if (NULL == f)
+        {
+            printf("Couldn't open %s to write public key!\n", filename);
+            goto exit;
+        }
+
+        written = fwrite(publicKey, 1, publicKeyLen, f);
+        if (written < publicKeyLen)
+        {
+            printf("Failed to write public key! Had %zu, wrote %zu\n", publicKeyLen, written);
+            goto exit;
+        }
+
+        if (0 != fclose(f))
+        {
+            printf("Warning: failed to fclose. Errno: %d\n", errno);
+        }
+
+        printf("Wrote public key.\n");
+
+        sprintf(filename, "%s.prv", nameBuf);
+        f = fopen(filename, "wb");
+        if (NULL == f)
+        {
+            printf("Couldn't open %s to write private key!\n", filename);
+            goto exit;
+        }
+        written = fwrite(privateKey, 1, privateKeyLen, f);
+        if (written < privateKeyLen)
+        {
+            printf("Failed to write private key! Had %zu, wrote %zu\n", privateKeyLen, written);
+            goto exit;
+        }
+
+        if (0 != fclose(f))
+        {
+            printf("Warning: failed to fclose. Errno: %d\n", errno);
+        }
+        f = NULL;
+
+        printf("Wrote private key.\n");
+    }
+    else
+    {
+        printf("Failed!\n");
+    }
+
+exit:
+
+    OICFree(publicKey);
+    OICClearMemory(privateKey, privateKeyLen);
+    OICFree(privateKey);
+    if (NULL != f)
+    {
+        if (0 != fclose(f))
+        {
+            printf("Warning: failed to fclose. errno: %d\n", errno);
+        }
+    }
+}
+
+int main()
+{
+    for (;;)
+    {
+        int option;
+
+        printf("-- Certificate Generator Sample Utility --\n\n");
+
+        printf(" 1. Generate a new key pair\n");
+        printf(" 2. Generate a self-signed CA certificate (requires a key pair for the CA)\n");
+        printf(" 3. Generate an identity certificate for a particular device UUID\n");
+        printf("       (requires the CA's private key and certificate, and the device's public key)\n");
+        printf(" 4. Generate a role certificate for a particular device UUID and role\n");
+        printf("       (requires the CA's private key and certificate, and the device's public key)\n");
+
+        printf("\n");
+        printf(" 0. Exit\n");
+        printf("\n");
+        printf("Select: ");
+
+        if (scanf("%d", &option) < 1)
+        {
+            printf("Failed to read the option! Exiting.\n");
+            return 0;
+        }
+
+        while ('\n' != getchar()); /* Consume the rest of the line so it doesn't get fed to the next input. */
+
+        switch (option)
+        {
+        case 1:
+            DoGenKeyPair();
+            break;
+        case 2:
+            DoGenCertificate(CA_CERT);
+            break;
+        case 3:
+            DoGenCertificate(IDENTITY_CERT);
+            break;
+        case 4:
+            DoGenCertificate(ROLE_CERT);
+            break;
+        case 0:
+            return 0;
+        default:
+            printf("Invalid option %d\n\n", option);
+            break;
+        }
+    }
+}
\ No newline at end of file
diff --git a/resource/csdk/security/provisioning/sample/provisioningTest.py b/resource/csdk/security/provisioning/sample/provisioningTest.py
new file mode 100644 (file)
index 0000000..17a43df
--- /dev/null
@@ -0,0 +1,122 @@
+#!/usr/bin/python -W
+
+import subprocess
+import os
+import time
+import sys
+import shutil
+import platform
+import argparse
+import textwrap
+
+# Note: to see the return value of a process
+#       - in Windows type: echo %errorlevel%
+#       - in Linux type: echo $?
+
+# Resets the state of sampleserver_justworks and autoprovisioningclient so that
+# state from one test is not present during subsequent tests
+def cleanup(iotivity_base_path, exe_path):
+
+    # Copy fresh oic_svr_db_server_justworks.dat
+    dat_file_src = os.path.join(iotivity_base_path, 'resource', 'csdk', 'security', 'provisioning', 'sample', 'oic_svr_db_server_justworks.dat' )
+    dat_file_dest = exe_path
+    shutil.copy(dat_file_src, dat_file_dest)
+\r
+    # Copy fresh oic_svr_db_client.dat \r
+    dat_file_src = os.path.join(iotivity_base_path, 'resource', 'examples', 'oic_svr_db_client.dat' )\r
+    dat_file_dest = exe_path\r
+    shutil.copy(dat_file_src, dat_file_dest)\r
+\r
+    #Delete provisioning DB file\r
+    db_file = os.path.join(exe_path, 'oic_autoprvn_mng.db')\r
+    if os.path.isfile(db_file):\r
+        os.unlink(db_file)\r
+\r
+# Print the environment variables (useful for debugging)
+def print_environment():
+    for key in os.environ.keys():\r
+        print "%30s %s \n" % (key,os.environ[key])\r
+    print 'current PATH is %s' % sys.path
+
+
+### main ###
+
+usage = '''
+ Run end-to-end certificate tests between autoprovisioningclient and sampleserver_justworks
+ Usage Notes
+   - script assumes it's being run from the root of iotivity, e.g.:
+         t:\\iotivity\\resource\\csdk\\security\\provisioning\\sample\\provisioningTest.py
+   - I have added
+        t:\\iotivity\\out\\windows\\amd64\\debug\\resource\\csdk
+        t:\\iotivity\\out\\windows\\amd64\\debug
+     to my PATH
+   - The discovery timeout in autoprovisioning client may be a bit agressive, 3 seconds
+'''
+
+parser = argparse.ArgumentParser(
+    formatter_class=argparse.RawDescriptionHelpFormatter,
+    description=usage
+)
+
+parser.add_argument('--arch', nargs='?', choices = ['amd64', 'x86', 'arm'], help= 'Architecture, one of x86, amd64 or arm. Defaults to amd64', default='amd64')
+parser.add_argument('--build', nargs='?', choices = ['debug', 'release'], help= 'Build type, one of debug or release. Defaults to debug', default='debug')
+
+args = parser.parse_args()
+
+# Number of unit tests in autoprovisioningclient
+NUM_TESTS = 2
+
+iotivity_base_path = os.getcwd()
+os_name = platform.system()
+if os_name == 'Windows':
+    os_name = 'windows'
+elif os_name == 'Linux':
+    os_name = 'linux'
+
+exe_path = os.path.join(iotivity_base_path, 'out', os_name, args.arch, args.build, 'resource', 'csdk', 'security', 'provisioning', 'sample')
+
+# Set PATH so octbstack.dll is found
+cwd = os.getcwd()
+sys.path.append(os.path.join(cwd, exe_path))
+sys.path.append(os.path.join(cwd, 'out', os_name, args.arch, args.build))
+
+# Work in the output dir with the test binaries
+os.chdir(exe_path)
+
+output_text = ""
+num_failures = 0
+for i in range(1, NUM_TESTS + 1):\r
+    print '\nRunning test %d...\n' % i\r
+\r
+    # Clear state from previous test\r
+    cleanup(iotivity_base_path, exe_path)\r
+\r
+    # Start the device/server with a non-blocking call\r
+    #note: Popen can take file descriptors to redirect the processes stdin, stdout, stderr\r
+    try:\r
+        server_process = subprocess.Popen('sampleserver_justworks')\r
+    except:\r
+        print 'Failed to start sampleserver_justworks', sys.exc_info()[0]\r
+        sys.exit(-1)\r
+\r
+    # Run the auto provisioning client with the test number as argument, block until it returns\r
+    return_code = subprocess.call(["autoprovisioningclient", str(i)])\r
+\r
+    if return_code != 0:\r
+        num_failures += 1\r
+        print "Test %d failed" % i\r
+        output_text  += "Test %d failed\n" % i\r
+    else:\r
+        print "Test %d passed" % i\r
+\r
+\r
+    server_process.kill()\r
+
+
+print "\n------------------------------------"
+print " Test Results: %d of %d tests passed" % (NUM_TESTS - num_failures, NUM_TESTS)
+print "------------------------------------"
+print output_text
+print '\n'
+
+
index 58fa2be..c1ac02c 100644 (file)
 #include "srmutility.h"
 #include "pmtypes.h"
 #include "oxmverifycommon.h"
+#include "mbedtls/config.h"
+#include "mbedtls/pem.h"
+#include "mbedtls/x509_csr.h"
+#include "occertutility.h"
 
 #ifdef _MSC_VER
 #include <io.h>
@@ -66,6 +70,7 @@ extern "C"
 #define _33_PROVIS_DP_              33
 #define _34_CHECK_LINK_STATUS_      34
 #define _35_SAVE_ACL_               35
+#define _36_PROVIS_CERT_            36
 #define _40_UNLINK_PAIR_DEVS_       40
 #define _50_REMOVE_SELEC_DEV_       50
 #define _51_REMOVE_DEV_WITH_UUID_   51
@@ -73,6 +78,7 @@ extern "C"
 #define _53_RESET_SVR_DB_           53
 #define _60_GET_CRED_               60
 #define _61_GET_ACL_                61
+#define _62_GET_CSR_                62
 #ifdef MULTIPLE_OWNER
 #define _70_MOT_CHANGE_MOM_         70
 #define _71_MOT_PROV_PRECONF_PIN_   71
@@ -101,6 +107,9 @@ static const OicSecPrm_t  SUPPORTED_PRMS[1] =
     PRM_PRE_CONFIGURED,
 };
 
+static char* TEST_CERT_NOT_BEFORE = "20170101000000"; // Not before field for certificates, in format YYYYMMDDhhmmss
+static char* TEST_CERT_NOT_AFTER = "20270101000000";  // + ten years
+
 // |g_ctx| means provision manager application context and
 // the following, includes |un/own_list|, could be variables, which |g_ctx| has,
 // for accessing all function(s) for these, they are declared on global domain
@@ -115,8 +124,13 @@ static int g_unown_cnt;
 static OCProvisionDev_t* g_mot_enable_list;
 static int g_mot_enable_cnt;
 #endif //MULTIPLE_OWNER
+char* g_caKeyPem;   /* Test CA private key */
+char* g_caCertPem;  /* Test CA certificate */
+uint16_t g_caCredId = 0;   /* ID of CA's OCF identity cert */
+char* g_csr;    /* Certificate signing request from device */
 
-static bool g_doneCB;
+static bool g_doneCB;    /* Set to true by the callback to indicate it completed. */
+static bool g_successCB; /* Set to true by the callback to indicate success. */
 #ifdef __WITH_TLS__
 static int secure_protocol = 1;
 static void setDevProtocol(OCProvisionDev_t* dev_lst);
@@ -134,6 +148,11 @@ static FILE* fopen_prvnMng(const char*, const char*);
 static int waitCallbackRet(void);
 static int selectTwoDiffNum(int*, int*, const int, const char*);
 
+/* At a few places in this file, warning 4028 is incorrectly produced, disable it for the whole file. */
+#ifdef _MSC_VER
+#pragma warning( disable : 4028)
+#endif
+
 // callback function(s) for provisioning client using C-level provisioning API
 static void ownershipTransferCB(void* ctx, size_t nOfRes, OCProvisionResult_t* arr, bool hasError)
 {
@@ -168,11 +187,30 @@ static void provisionCredCB(void* ctx, size_t nOfRes, OCProvisionResult_t* arr,
     if(!hasError)
     {
         OIC_LOG_V(INFO, TAG, "Provision Credential SUCCEEDED - ctx: %s", (char*) ctx);
+        g_successCB = true;
     }
     else
     {
         OIC_LOG_V(ERROR, TAG, "Provision Credential FAILED - ctx: %s", (char*) ctx);
         printResultList((const OCProvisionResult_t*) arr, nOfRes);
+        g_successCB = false;
+    }
+    g_doneCB = true;
+}
+
+/* Function of type OCProvisionResultCB from \resource\csdk\security\provisioning\include\pmtypes.h */
+void provisionTrustChainCB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError)
+{
+    if (!hasError)
+    {
+        OIC_LOG_V(INFO, TAG, "Provision Credential SUCCEEDED - ctx: %s", (char*)ctx);
+        g_successCB = true;
+    }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "Provision Credential FAILED - ctx: %s", (char*)ctx);
+        printResultList((const OCProvisionResult_t*)arr, nOfRes);
+        g_successCB = false;
     }
     g_doneCB = true;
 }
@@ -219,7 +257,139 @@ static void getAclCB(void* ctx, size_t nOfRes, OCProvisionResult_t* arr, bool ha
     g_doneCB = true;
 }
 
-static void provisionDPCB(void* ctx, size_t nOfRes, OCProvisionResult_t* arr, bool hasError)
+static void getCsrCB(void* ctx, size_t nOfRes, OCPMGetCsrResult_t* arr, bool hasError)
+{
+    if (!hasError)
+    {
+        size_t i;
+        mbedtls_x509_csr csr;
+        OIC_LOG_V(INFO, TAG, "getCsrCB SUCCEEDED - ctx: %s", (char*)ctx);
+        for (i = 0; i < nOfRes; i++)
+        {
+            char pemBuffer[2048] = { 0 };
+            char infoBuffer[2048] = { 0 };
+            size_t olen;
+            int ret;
+
+            if (arr[i].encoding == OIC_ENCODING_DER)
+            {
+                ret = mbedtls_pem_write_buffer("-----BEGIN CERTIFICATE REQUEST-----",
+                    "-----END CERTIFICATE REQUEST-----",
+                    arr[i].csr,
+                    arr[i].csrLen,
+                    (unsigned char *)pemBuffer,
+                    sizeof(pemBuffer),
+                    &olen);
+                if (ret < 0)
+                {
+                    OIC_LOG_V(ERROR, TAG, "Couldn't convert CSR into PEM: %d", ret);
+                    pemBuffer[0] = '\0';
+                }
+            }
+            else
+            {
+                OICStrcpyPartial(pemBuffer, sizeof(pemBuffer), (const char *)arr[i].csr, arr[i].csrLen);
+            }
+
+            mbedtls_x509_csr_init(&csr);
+            ret = mbedtls_x509_csr_parse_der(&csr, arr[i].csr, arr[i].csrLen);
+            if (ret < 0)
+            {
+                OIC_LOG_V(ERROR, TAG, "Couldn't parse CSR: %d", ret);
+                infoBuffer[0] = '\0';
+            }
+            else
+            {
+                ret = mbedtls_x509_csr_info(infoBuffer, sizeof(infoBuffer), "", &csr);
+                if (ret < 0)
+                {
+                    OIC_LOG_V(ERROR, TAG, "Couldn't get CSR info buffer: %d", ret);
+                    infoBuffer[0] = '\0';
+                }
+            }
+            mbedtls_x509_csr_free(&csr);
+
+            OIC_LOG(INFO, TAG, "getCsrCB success");
+            // OIC_LOG_V truncates strings, and the entirety of the CSR PEM gets cut off if we use it
+            printf("getCsrCB: csr[%" PRIuPTR "]:\n%s\n", i, pemBuffer);
+            printf("getCsrCB: csr info[%" PRIuPTR "]:\n%s\n", i, infoBuffer);
+        }
+    }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "getCsrCB FAILED - ctx: %s", (char*)ctx);
+
+        if (!arr || (0 == nOfRes))
+        {
+            printf("     Device List is Empty..\n\n");
+        }
+        else
+        {
+            size_t lst_cnt;\r
+            for (lst_cnt = 0; nOfRes > lst_cnt; ++lst_cnt)
+            {
+                printf("     [%" PRIuPTR "] ", lst_cnt + 1);
+                printUuid((const OicUuid_t*)&arr[lst_cnt].deviceId);
+                printf(" - result: %d\n", arr[lst_cnt].res);
+            }
+            printf("\n");
+        }
+    }
+    g_doneCB = true;
+}
+
+static void getCsrForCertProvCB(void* ctx, size_t nOfRes, OCPMGetCsrResult_t* arr, bool hasError)
+{
+    g_successCB = false;
+
+    if (!hasError)
+    {
+        if (nOfRes != 1)
+        {
+            OIC_LOG_V(ERROR, TAG, "getCsrForCertProvCB FAILED - ctx: %s", (char*)ctx);
+            goto exit;
+        }
+
+        if (arr[0].encoding == OIC_ENCODING_DER)
+        {
+            OCStackResult res = OCConvertDerCSRToPem((char*)arr[0].csr, arr[0].csrLen, &g_csr);
+            if (res != OC_STACK_OK)
+            {
+                OIC_LOG_V(ERROR, TAG, "getCsrForCertProvCB FAILED (CSR re-encoding failed) - error: %d, ctx: %s", res, (char*)ctx);
+                goto exit;
+            }
+            g_successCB = true;
+        }
+        else if(arr[0].encoding == OIC_ENCODING_PEM)
+        {
+            g_csr = (char*)OICCalloc(1, arr[0].csrLen);
+            if (g_csr == NULL)
+            {
+                OIC_LOG_V(ERROR, TAG, "getCsrForCertProvCB FAILED (memory allocation) - ctx: %s", (char*)ctx);
+                goto exit;
+            }
+
+            memcpy(g_csr, arr[0].csr, arr[0].csrLen);
+
+            OIC_LOG(INFO, TAG, "getCsrForCertProvCB success");
+            g_successCB = true;
+        }
+        else
+        {
+            OIC_LOG_V(ERROR, TAG, "getCsrForCertProvCB FAILED (unknown encoding) - ctx: %s", (char*)ctx);
+            goto exit;
+        }
+    }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "getCsrForCertProvCB FAILED - ctx: %s", (char*)ctx);
+    }
+
+exit:
+    g_doneCB = true;
+}
+
+static void provisionDPCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
 {
     if(!hasError)
     {
@@ -336,7 +506,7 @@ static int initProvisionClient(void)
         return -1;
     }
 
-    if (access(PRVN_DB_FILE_NAME, F_OK) != -1)
+    if (access(PRVN_DB_FILE_NAME, F_OK) == 0)
     {
         printf("************************************************************\n");
         printf("************Provisioning DB file already exists.************\n");
@@ -697,6 +867,345 @@ static int provisionCred(void)
     return 0;
 }
 
+/*
+ *   Initialize the provisioning client for certificate provisioning.
+ *   This function:
+ *   1. Generates a root key pair for a CA.
+ *   2. Generates a self-signed root certificate for the CA public key.
+ *   3. Saves this root as a trust anchor locally.
+ *   4. Generate and store an IoTivity key and cert (issued from the CA root cert).
+ *      This is an EE cert the CA/OBT will use in DTLS.
+ *
+ *   @param[out] credid parameter for the ID of the CA credential
+ */
+static int setupCA()
+{
+    char* publicKey = NULL;
+    size_t publicKeyLen = 0;
+    size_t caKeyLen = 0;
+    char* serial = NULL;
+    size_t serialLen = 0;
+    size_t caCertLen = 0;
+    char* idPublicKey = NULL;
+    char* idKey = NULL;
+    char* idCert = NULL;
+    size_t idCertLen = 0;
+    size_t idKeyLen = 0;
+
+    if (g_caCredId == 0)
+    {
+        printf("Setting up CA for certificate provisioning\n");
+    }
+    else
+    {
+        printf("Skipping CA setup, already done\n");
+        return 0;
+    }
+
+    /* Create CA keypair, serial number */
+    OCStackResult res = OCGenerateKeyPair(&publicKey, &publicKeyLen, &g_caKeyPem, &caKeyLen);
+    if (res != OC_STACK_OK)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCGenerateKeyPair failed, error: %d", res);
+        goto exit;
+    }
+
+    res = OCGenerateRandomSerialNumber(&serial, &serialLen);
+    if (res != OC_STACK_OK)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCGenerateRandomSerialNumber failed, error: %d", res);
+        goto exit;
+    }
+
+    /* Create a CA certificate */
+    res = OCGenerateCACertificate(
+        "C=US, O=Open Connectivity Foundation, CN=IoTivity test code CA",  // subject
+        publicKey,
+        NULL,               // Issuer private key is null
+        g_caKeyPem,         // use CA's own key to create self-signed cert
+        serial,
+        TEST_CERT_NOT_BEFORE,
+        TEST_CERT_NOT_AFTER,
+        &g_caCertPem,
+        &caCertLen);
+    if (res != OC_STACK_OK)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCGenerateCACertificate failed, error: %d", res);
+        goto exit;
+    }
+
+    /* Set our own trust anchor so that we trust certs we've issued. */\r
+    res = OCSaveTrustCertChain((uint8_t*) g_caCertPem, caCertLen, OIC_ENCODING_PEM, &g_caCredId);
+    if (OC_STACK_OK != res)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCSaveTrustCertChain error: %d", res);
+        goto exit;
+    }
+
+    /* Create identity certificate for use by the CA. */
+    res = OCGenerateKeyPair(&idPublicKey, &publicKeyLen, &idKey, &idKeyLen);
+    if (res != OC_STACK_OK)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCGenerateKeyPair failed, error: %d", res);
+        goto exit;
+    }
+
+    res = OCGenerateRandomSerialNumber(&serial, &serialLen);
+    if (res != OC_STACK_OK)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCGenerateRandomSerialNumber failed, error: %d", res);
+        goto exit;
+    }
+
+    OCUUIdentity deviceId = { 0 };
+    res = OCGetDeviceId(&deviceId);
+    if (res != OC_STACK_OK)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to get own UUID, error: %d", res);
+        goto exit;
+    }
+
+    OicUuid_t uuid = { 0 };
+    memcpy(uuid.id, deviceId.id, sizeof(uuid.id));
+
+    res = OCGenerateIdentityCertificate(
+        &uuid,
+        idPublicKey,
+        g_caCertPem,
+        g_caKeyPem,
+        serial,
+        TEST_CERT_NOT_BEFORE,
+        TEST_CERT_NOT_AFTER,
+        &idCert,
+        &idCertLen);
+    if (res != OC_STACK_OK)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to create identity cert for CA, error: %d", res);
+        goto exit;
+    }
+
+    uint16_t idCertCredId = 0;
+    res = OCSaveOwnCertChain(idCert, idKey, &idCertCredId);
+    if (res != OC_STACK_OK)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to save CA's identity cert & key, error: %d", res);
+        goto exit;
+    }
+
+exit:
+    OICFree(publicKey);
+    OICFree(serial);
+    OICFree(idPublicKey);
+    if (idKey != NULL)
+    {
+        OICClearMemory(idKey, idKeyLen);
+        OICFree(idKey);
+    }
+    OICFree(idCert);
+
+    if (res != OC_STACK_OK)
+    {
+        return -1;
+    }
+
+    return 0;
+}
+
+/*
+ * Create an identity certificate for a device, based on the information in its CSR. 
+ * Assumes the csr has already been validated wtih OCVerifyCSRSignature.
+ */
+static int createIdentityCertFromCSR(const char* caKeyPem, const char* caCertPem, char* csr, 
+    char** deviceCert)
+{
+    char* publicKey = NULL;
+    char* serial = NULL;
+    size_t serialLen;
+    OicUuid_t uuid = { 0 };
+    OCStackResult res = OC_STACK_ERROR;
+
+    res = OCGetUuidFromCSR(csr, &uuid);
+    if (res != OC_STACK_OK)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to get UUID from CSR, error: %d", res);
+        goto exit;
+    }
+    /* Note: a real OBT must make sure the UUID isn't already in use on the network. */
+
+    res = OCGetPublicKeyFromCSR(csr, &publicKey);
+    if (res != OC_STACK_OK)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to get public key from CSR, error: %d", res);
+        goto exit;
+    }
+
+    res = OCGenerateRandomSerialNumber(&serial, &serialLen);
+    if (res != OC_STACK_OK)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCGenerateRandomSerialNumber failed, error: %d", res);
+        goto exit;
+    }
+
+    size_t deviceCertLen;
+    res = OCGenerateIdentityCertificate(
+            &uuid,
+            publicKey,
+            caCertPem,
+            caKeyPem,
+            serial,
+            TEST_CERT_NOT_BEFORE,
+            TEST_CERT_NOT_AFTER,
+            deviceCert,
+            &deviceCertLen);
+
+    if(res != OC_STACK_OK)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCGenerateIdentityCertificate failed, error: %d", res);
+        goto exit;
+    }
+
+exit:
+    OICFree(publicKey);
+    OICFree(serial);
+
+    if (res != OC_STACK_OK)
+    {
+        return -1;
+    }
+
+    return 0;
+}
+
+static int provisionCert(void)
+{
+    // make sure we own at least one device to provision
+    if (!g_own_list || g_own_cnt == 0)
+    {
+        printf("   > Owned Device List, to Provision Credentials, is Empty\n");
+        printf("   > Please Register Unowned Devices first, with [20] Menu\n");
+        return 0;  // normal case
+    }
+
+    // select device for provisioning certificate
+    int dev_num = 0;
+    for (; ; )
+    {
+        printf("   > Enter Device Number, for certificate provisioning: ");
+        for (int ret = 0; 1 != ret; )
+        {
+            ret = scanf("%d", &dev_num);
+            for (; 0x20 <= getchar(); );  // for removing overflow garbages
+                                          // '0x20<=code' is character region
+        }
+        if (0<dev_num && g_own_cnt >= dev_num)
+        {
+            break;
+        }
+        printf("     Entered Wrong Number. Please Enter Again\n");
+    }
+
+    OCProvisionDev_t* targetDevice = getDevInst((const OCProvisionDev_t*)g_own_list, dev_num);
+    if (targetDevice == NULL)
+    {
+        OIC_LOG(ERROR, TAG, "Error, invalid device %d");
+        return -1;
+    }
+
+    // Install the CA trust anchor
+    if (setupCA() != 0)
+    {
+        printf("     Failed to setup CA\n");
+        return -1;
+    }
+
+    // Provision the CA root cert to the target device
+    printf("   > Saving root certificate (trust anchor) to selected device..\n");
+    g_doneCB = false;
+    OicSecCredType_t type = SIGNED_ASYMMETRIC_KEY;
+
+    OCStackResult rst = OCProvisionTrustCertChain((void*)g_ctx, type, g_caCredId, targetDevice, &provisionTrustChainCB);
+    if (OC_STACK_OK != rst)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCProvisionTrustCertChain returned error: %d", rst);
+        return -1;
+    }
+
+    if (waitCallbackRet())  // input |g_doneCB| flag implicitly
+    {
+        OIC_LOG(ERROR, TAG, "OCProvisionTrustCertChain callback error");
+        return -1;
+    }
+    if (!g_successCB)
+    {
+        return -1;
+    }
+
+    // Request a CSR from the device, check the CSR signature
+    printf("   > Getting CSR from device..\n");
+    g_doneCB = false;
+    rst = OCGetCSRResource((void*)g_ctx, targetDevice, getCsrForCertProvCB);
+    if (OC_STACK_OK != rst)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCGetCSRResource API error: %d", rst);
+        return -1;
+    }
+    if (waitCallbackRet())  // input |g_doneCB| flag implicitly
+    {
+        OIC_LOG(ERROR, TAG, "OCGetCSRResource callback error");
+        return -1;
+    }
+    if (!g_successCB)
+    {
+        return -1;
+    }
+
+    rst = OCVerifyCSRSignature(g_csr);
+    if (OC_STACK_OK != rst)
+    {
+        OIC_LOG(ERROR, TAG, "Failed to validate CSR signature");
+        OICFreeAndSetToNull(&g_csr);
+        return -1;
+    }
+
+    printf("   > Creating a certificate for the device..\n");
+    char* deviceCert;
+    int ret = createIdentityCertFromCSR(g_caKeyPem, g_caCertPem, g_csr, &deviceCert);
+    OICFreeAndSetToNull(&g_csr);
+    if (ret != 0)
+    {
+        OIC_LOG(ERROR, TAG, "Failed to generate certificate");
+        OICFree(deviceCert);
+        return -1;
+    }
+
+    //Provision the new cert
+    printf("   > Provisioning certificate credential to selected device..\n");
+    g_doneCB = false;
+    rst = OCProvisionCertificate((void *)g_ctx, targetDevice, deviceCert, provisionCredCB);
+    if (OC_STACK_OK != rst)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCProvisionCertificate returned error: %d", rst);
+        OICFree(deviceCert);
+        return -1;
+    }
+    if (waitCallbackRet())  // input |g_doneCB| flag implicitly
+    {
+        OIC_LOG(ERROR, TAG, "OCProvisionCertificate callback error");
+        OICFree(deviceCert);
+        return -1;
+    }
+    if (!g_successCB)
+    {
+        OICFree(deviceCert);
+        return -1;
+    }
+
+    printf("   > Provisioned certificate crendentials\n");
+    OICFree(deviceCert);
+
+    return 0;
+}
+
 static int provisionAcl(void)
 {
     // check |own_list| for provisioning access control list
@@ -1127,6 +1636,66 @@ PVACL_ERROR:
     return -1;
 }
 
+static int getCsr(void)
+{
+    // check |own_list| for retrieving CSR
+    if(!g_own_list || 1>g_own_cnt)
+    {
+        printf("   > Owned Device List, to retrieve CSR, is Empty\n");
+        printf("   > Please Register Unowned Devices first, with [20] Menu\n");
+        return 0;  // normal case
+    }
+
+    // select device for retrieving CSR
+    int dev_num = 0;
+    for( ; ; )
+    {
+        printf("   > Enter Device Number, for retrieving CSR: ");
+        for(int ret=0; 1!=ret; )
+        {
+            ret = scanf("%d", &dev_num);
+            for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                        // '0x20<=code' is character region
+        }
+        if(0<dev_num && g_own_cnt>=dev_num)
+        {
+            break;
+        }
+        printf("     Entered Wrong Number. Please Enter Again\n");
+    }
+
+    // call |getDevInst| API
+    // calling this API with callback actually acts like blocking
+    // for error checking, the return value saved and printed
+    g_doneCB = false;
+    OCProvisionDev_t* dev = getDevInst((const OCProvisionDev_t*) g_own_list, dev_num);
+    if(!dev)
+    {
+        OIC_LOG(ERROR, TAG, "getDevInst: device instance empty");
+        goto GETCSR_ERROR;
+    }
+    OCStackResult rst = OCGetCSRResource((void*) g_ctx, dev, getCsrCB);
+    if(OC_STACK_OK != rst)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCGetCSRResource API error: %d", rst);
+
+        goto GETCSR_ERROR;
+    }
+    if(waitCallbackRet())  // input |g_doneCB| flag implicitly
+    {
+        OIC_LOG(ERROR, TAG, "OCGetCSRResource callback error");
+        goto GETCSR_ERROR;
+    }
+
+    // display the result of get credential
+    printf("   > Get CSR SUCCEEDED\n");
+
+    return 0;
+
+GETCSR_ERROR:
+    return -1;
+}
+
 static int unlinkPairwise(void)
 {
     // check |own_list| for unlinking pairwise devices
@@ -1624,6 +2193,7 @@ static OicSecAcl_t* createAcl(const int dev_num)
         OIC_LOG(ERROR, TAG, "createAcl: device instance empty");
         goto CRACL_ERROR;
     }
+    ace->subjectType = OicSecAceUuidSubject;
     memcpy(&ace->subjectuuid, &dev->doxm->deviceID, UUID_LENGTH);
 
     // enter number of |resources| in 'accessed' device
@@ -2402,7 +2972,9 @@ static void printMenu(void)
     printf("** 32. Provision the Selected Access Control List(ACL)\n");
     printf("** 33. Provision Direct-Pairing Configuration\n");
     printf("** 34. Check Linked Status of the Selected Device on PRVN DB\n");
-    printf("** 35. Save the Selected Access Control List(ACL) into local SVR DB\n\n");
+    printf("** 35. Save the Selected Access Control List(ACL) into local SVR DB\n");
+    printf("** 36. Provision certificate credential\n\n");
+
 
     printf("** [D] UNLINK PAIRWISE THINGS\n");
     printf("** 40. Unlink Pairwise Things\n\n");
@@ -2415,7 +2987,8 @@ static void printMenu(void)
 
     printf("** [F] GET SECURITY RESOURCE FOR DEBUGGING ONLY\n");
     printf("** 60. Get the Credential resources of the Selected Device\n");
-    printf("** 61. Get the ACL resources of the Selected Device\n\n");
+    printf("** 61. Get the ACL resources of the Selected Device\n");
+    printf("** 62. Get the CSR of the Selected Device\n\n");
 
 #ifdef MULTIPLE_OWNER
     printf("** [G] UPDATE THE MULTIPLE OWNERSHIP TRANSFER RELATED VALUE\n");
@@ -2577,6 +3150,12 @@ int main()
                 OIC_LOG(ERROR, TAG, "_35_SAVE_ACL_: error");
             }
             break;
+        case _36_PROVIS_CERT_:
+            if (provisionCert())
+            {
+                OIC_LOG(ERROR, TAG, "_36_PROVIS_CERT_: error");
+            }
+            break;
         case _40_UNLINK_PAIR_DEVS_:
             if(unlinkPairwise())
             {
@@ -2619,6 +3198,12 @@ int main()
                 OIC_LOG(ERROR, TAG, "_61_GET_ACL_: error");
             }
             break;
+        case _62_GET_CSR_:
+            if(getCsr())
+            {
+                OIC_LOG(ERROR, TAG, "_62_GET_CSR_: error");
+            }
+            break;
 #ifdef MULTIPLE_OWNER
         case _70_MOT_CHANGE_MOM_:
             if(changeMultipleOwnershipTrnasferMode())
index e3e0a66..68ceb45 100644 (file)
@@ -507,6 +507,7 @@ static OicSecAcl_t* createAclForLEDAccess(const OicUuid_t* subject)
         return NULL;  // not need to 'goto' |ERROR| before allocating |acl|
     }
     LL_APPEND(acl->aces, ace);
+    ace->subjectType = OicSecAceUuidSubject;
     memcpy(ace->subjectuuid.id, subject->id, sizeof(subject->id));
 
     // fill the href
index 6ce5ec3..2098373 100644 (file)
@@ -184,7 +184,7 @@ static OCStackResult handleAclGetInfoResponse(void *ctx, void **data, OCClientRe
         goto exit;
     }
 
-    OicSecAcl_t* acl = CBORPayloadToAcl2(cbor, size);
+    OicSecAcl_t* acl = CBORPayloadToCloudAcl(cbor, size);
     if (NULL == acl)
     {
         OIC_LOG(ERROR, TAG, "Can't parse CBOR payload");
index 4adc3f6..3dbdd68 100644 (file)
@@ -352,7 +352,23 @@ void OCDeleteDiscoveredDevices(OCProvisionDev_t *pList)
 OCStackResult OCProvisionACL(void* ctx, const OCProvisionDev_t *selectedDeviceInfo, OicSecAcl_t *acl,
                              OCProvisionResultCB resultCallback)
 {
-    return SRPProvisionACL(ctx, selectedDeviceInfo, acl, resultCallback);
+    return SRPProvisionACL(ctx, selectedDeviceInfo, acl, OIC_SEC_ACL_V1, resultCallback);
+}
+
+/**
+ * this function sends ACL information to resource.
+ *
+ * @param[in] ctx Application context would be returned in result callback.
+ * @param[in] selectedDeviceInfo Selected target device.
+ * @param[in] acl ACL to provision.
+ * @param[in] resultCallback callback provided by API user, callback will be called when provisioning
+              request recieves a response from resource server.
+ * @return  OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCProvisionACL2(void* ctx, const OCProvisionDev_t *selectedDeviceInfo, OicSecAcl_t *acl,
+                              OCProvisionResultCB resultCallback)
+{
+    return SRPProvisionACL(ctx, selectedDeviceInfo, acl, OIC_SEC_ACL_V2, resultCallback);
 }
 
 /**
@@ -393,9 +409,32 @@ OCStackResult OCGetCredResource(void* ctx, const OCProvisionDev_t *selectedDevic
 OCStackResult OCGetACLResource(void* ctx, const OCProvisionDev_t *selectedDeviceInfo,
                              OCProvisionResultCB resultCallback)
 {
-    return SRPGetACLResource(ctx, selectedDeviceInfo, resultCallback);
+    return SRPGetACLResource(ctx, selectedDeviceInfo, OIC_SEC_ACL_V1, resultCallback);
+}
+
+OCStackResult OCGetACL2Resource(void* ctx, const OCProvisionDev_t *selectedDeviceInfo,\r
+                               OCProvisionResultCB resultCallback)
+{
+    return SRPGetACLResource(ctx, selectedDeviceInfo, OIC_SEC_ACL_V2, resultCallback);
+}
+
+OCStackResult OCGetCSRResource(void* ctx, const OCProvisionDev_t *selectedDeviceInfo,
+                             OCGetCSRResultCB resultCallback)
+{
+    return SRPGetCSRResource(ctx, selectedDeviceInfo, resultCallback);
+}
+
+OCStackResult OCGetRolesResource(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
+                              OCGetRolesResultCB resultCallback)
+{
+    return SRPGetRolesResource(ctx, selectedDeviceInfo, resultCallback);
 }
 
+OCStackResult OCDeleteRoleCertificateByCredId(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
+                                              OCProvisionResultCB resultCallback, uint32_t credId)
+{
+    return SRPDeleteRoleCertificateByCredId(ctx, selectedDeviceInfo, resultCallback, credId);
+}
 
 OCStackResult OCReadTrustCertChain(uint16_t credId, uint8_t **trustCertChain,
                                      size_t *chainSize)
@@ -419,10 +458,31 @@ OCStackResult OCProvisionCredentials(void *ctx, OicSecCredType_t type, size_t ke
                                       OCProvisionResultCB resultCallback)
 {
     return SRPProvisionCredentials(ctx, type, keySize,
-                                      pDev1, pDev2, resultCallback);
+                                      pDev1, pDev2, NULL, resultCallback);
 
 }
 
+#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
+/**
+* API to provision a certificate to a device.
+*
+* @param[in] ctx Application context returned in result callback.
+* @param[in] pDev Pointer to OCProvisionDev_t instance, respresenting the device to be provsioned.
+* @param[in] pemCert Certificate to provision, encoded as PEM
+* @param[in] resultCallback callback provided by API user, callback will be called when
+*            provisioning request receives a response from first resource server.
+* @return OC_STACK_OK in case of success and other value otherwise.
+*/
+OCStackResult OCProvisionCertificate(void *ctx,
+    const OCProvisionDev_t *pDev,
+    const char* pemCert,
+    OCProvisionResultCB resultCallback)
+{
+    return SRPProvisionCredentials(ctx, SIGNED_ASYMMETRIC_KEY, 0,
+        pDev, NULL, pemCert, resultCallback);
+}
+#endif
+
 /**
  * this function sends Direct-Pairing Configuration to a device.
  *
@@ -994,7 +1054,7 @@ static void AclProv1CB(void* ctx, size_t nOfRes, OCProvisionResult_t *arr, bool
     UpdateLinkResults(link, 1, arr[0].res);
     if (NULL != link->pDev2Acl)
     {
-        OCStackResult res =  SRPProvisionACL(ctx, link->pDev2, link->pDev2Acl, &AclProv2CB);
+        OCStackResult res =  SRPProvisionACL(ctx, link->pDev2, link->pDev2Acl, OIC_SEC_ACL_V1, &AclProv2CB);
         if (OC_STACK_OK!=res)
         {
              UpdateLinkResults(link, 2, res);
@@ -1044,7 +1104,7 @@ static void ProvisionCredsCB(void* ctx, size_t nOfRes, OCProvisionResult_t *arr,
     if (NULL != link->pDev1Acl)
     {
 
-        OCStackResult res =  SRPProvisionACL(ctx, link->pDev1, link->pDev1Acl, &AclProv1CB);
+        OCStackResult res =  SRPProvisionACL(ctx, link->pDev1, link->pDev1Acl, OIC_SEC_ACL_V1, &AclProv1CB);
         if (OC_STACK_OK!=res)
         {
              OIC_LOG(ERROR, TAG, "Error while provisioning ACL for device 1");
@@ -1059,7 +1119,7 @@ static void ProvisionCredsCB(void* ctx, size_t nOfRes, OCProvisionResult_t *arr,
     else if (NULL!=link->pDev2Acl)
     {
         OIC_LOG(ERROR, TAG, "ACL for device 1 is NULL");
-        OCStackResult res =  SRPProvisionACL(ctx, link->pDev2, link->pDev2Acl, &AclProv2CB);
+        OCStackResult res =  SRPProvisionACL(ctx, link->pDev2, link->pDev2Acl, OIC_SEC_ACL_V1, &AclProv2CB);
         if (OC_STACK_OK!=res)
         {
              OIC_LOG(ERROR, TAG, "Error while provisioning ACL for device 2");
@@ -1165,7 +1225,7 @@ OCStackResult OCProvisionPairwiseDevices(void* ctx, OicSecCredType_t type, size_
     link->currentCountResults = 0;
     link->resArr = (OCProvisionResult_t*) OICMalloc(sizeof(OCProvisionResult_t)*noOfResults);
     res = SRPProvisionCredentials(link, type, keySize,
-                                     pDev1, pDev2, &ProvisionCredsCB);
+                                     pDev1, pDev2, NULL, &ProvisionCredsCB);
     if (res != OC_STACK_OK)
     {
         OICFree(link->resArr);
@@ -1416,6 +1476,29 @@ OCStackResult OCSaveTrustCertChain(uint8_t *trustCertChain, size_t chainSize,
 }
 
 /**
+ * Function to save an identity certificate chain into Cred of SVR.
+ *
+ * @param[in] cert Certificate chain to be saved in Cred of SVR, PEM encoded, null terminated
+ * @param[in] key key corresponding to the certificate, PEM encoded, null terminated
+ * @param[out] credId CredId of saved certificate chain in Cred of SVR.
+ * @return  OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCSaveOwnCertChain(char* cert, char* key, uint16_t *credId)
+{
+    OicSecKey_t ownCert = { 0 };
+    ownCert.data = (uint8_t*) cert;
+    ownCert.len = strlen(cert) + 1;
+    ownCert.encoding = OIC_ENCODING_PEM;
+
+    OicSecKey_t ownKey = { 0 };
+    ownKey.data = (uint8_t*) key;
+    ownKey.len = strlen(key) + 1;
+    ownKey.encoding = OIC_ENCODING_PEM;
+
+    return SRPSaveOwnCertChain(&ownCert, &ownKey, credId);
+}
+
+/**
  * function to register notifier for Trustcertchain change.
  *
  * @param[in] ctx user context.
index 9c27e04..09ffbb6 100644 (file)
@@ -1667,6 +1667,7 @@ static OicSecAcl_t* GenerateOwnerAcl(const OicUuid_t* owner)
     ownerAce->permission = PERMISSION_FULL_CONTROL;
 
     //Set subject as PT's UUID
+    ownerAce->subjectType = OicSecAceUuidSubject;
     memcpy(ownerAce->subjectuuid.id, owner->id, sizeof(owner->id));
 
     wildcardRsrc->href = OICStrdup(WILDCARD_RESOURCE_URI);
@@ -1774,7 +1775,7 @@ static OCStackResult PostOwnerAcl(OTMContext_t* otmCtx)
         goto error;
     }
 
-    res = AclToCBORPayload(ownerAcl, &secPayload->securityData, &secPayload->payloadSize);
+    res = AclToCBORPayload(ownerAcl, OIC_SEC_ACL_V1, &secPayload->securityData, &secPayload->payloadSize);
     if (OC_STACK_OK != res)
     {
         OICFree(secPayload);
index 2646f3a..7f072ad 100644 (file)
@@ -34,6 +34,8 @@
 #include "pstatresource.h"
 #include "srmresourcestrings.h"
 #include "credresource.h"
+#include "csrresource.h"
+#include "rolesresource.h"
 #include "doxmresource.h"
 #include "pconfresource.h"
 #include "credentialgenerator.h"
@@ -95,6 +97,24 @@ struct GetSecData {
     int numOfResults;                        /**< Number of results in result array.**/
 };
 
+typedef struct GetCsrData GetCsrData_t;
+struct GetCsrData {
+    void *ctx;
+    const OCProvisionDev_t *deviceInfo;         /**< Pointer to PMDevInfo_t.**/
+    OCGetCSRResultCB resultCallback;            /**< Pointer to result callback.**/
+    OCPMGetCsrResult_t *resArr;                 /**< Result array.**/
+    size_t numOfResults;                        /**< Number of results in result array.**/
+};
+
+typedef struct GetRolesData GetRolesData_t;
+struct GetRolesData {
+    void *ctx;                                  /**< User-provided context **/
+    const OCProvisionDev_t *deviceInfo;         /**< Pointer to PMDevInfo_t.**/
+    OCGetRolesResultCB resultCallback;          /**< Pointer to result callback.**/
+    OCPMGetRolesResult_t *resArr;               /**< Result array.**/
+    size_t numOfResults;                        /**< Number of results in result array.**/
+};
+
 /**
  * Structure to carry PCONF provision API data to callback.
  */
@@ -287,7 +307,6 @@ static OCStackApplicationResult provisionCredentialCB1(void *ctx, OCDoHandle UNU
     return OC_STACK_DELETE_TRANSACTION;
 }
 
-
 /**
  * Internal function for handling credential generation and sending credential to resource server.
  *
@@ -441,10 +460,41 @@ static OCStackApplicationResult provisionCertCB(void *ctx, OCDoHandle UNUSED,
     return OC_STACK_DELETE_TRANSACTION;
 }
 
+static OCStackApplicationResult provisionIdentityCertCB(void *ctx, OCDoHandle UNUSED,
+    OCClientResponse *clientResponse)
+{
+    // Just call the callback provided to SRProvisionCredentials
+    VERIFY_NOT_NULL_RETURN(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
+    CredentialData_t* credData = (CredentialData_t *)ctx;
+    (void)UNUSED;
+    bool hasError;
+
+    // We expect OC_STACK_RESOURCE_CHANGED, anything else is an error
+    if (clientResponse && (OC_STACK_RESOURCE_CHANGED == clientResponse->result))
+    {
+        hasError = false;
+    }
+    else
+    {
+        hasError = true;
+    }
+
+    OCProvisionResultCB resultCallback = credData->resultCallback;
+    VERIFY_NOT_NULL_RETURN(TAG, resultCallback, ERROR, OC_STACK_DELETE_TRANSACTION);
+
+    ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
+        credData->resArr, hasError);
+
+    OICFree(credData);
+
+    return OC_STACK_DELETE_TRANSACTION;
+
+}
+
 OCStackResult SRPProvisionTrustCertChain(void *ctx, OicSecCredType_t type, uint16_t credId,
         const OCProvisionDev_t *selectedDeviceInfo, OCProvisionResultCB resultCallback)
 {
-    OIC_LOG(INFO, TAG, "In SRPProvisionTrustCertChain");
+    OIC_LOG(INFO, TAG, "IN SRPProvisionTrustCertChain");
     VERIFY_NOT_NULL_RETURN(TAG, selectedDeviceInfo, ERROR,  OC_STACK_INVALID_PARAM);
     VERIFY_NOT_NULL_RETURN(TAG, resultCallback, ERROR,  OC_STACK_INVALID_CALLBACK);
     if (SIGNED_ASYMMETRIC_KEY != type)
@@ -468,7 +518,7 @@ OCStackResult SRPProvisionTrustCertChain(void *ctx, OicSecCredType_t type, uint1
         return OC_STACK_NO_MEMORY;
     }
     secPayload->base.type = PAYLOAD_TYPE_SECURITY;
-    int secureFlag = 0;
+    int secureFlag = 1; /* Don't send the private key to the device, if it happens to be present */
     if(OC_STACK_OK != CredToCBORPayload(trustCertChainCred, &secPayload->securityData, &secPayload->payloadSize, secureFlag))
     {
         DeleteCredList(trustCertChainCred);
@@ -532,6 +582,9 @@ OCStackResult SRPProvisionTrustCertChain(void *ctx, OicSecCredType_t type, uint1
     }
 
     VERIFY_SUCCESS_RETURN(TAG, (OC_STACK_OK == ret), ERROR, OC_STACK_ERROR);
+
+    OIC_LOG(INFO, TAG, "OUT SRPProvisionTrustCertChain");
+
     return OC_STACK_OK;
 }
 
@@ -550,12 +603,12 @@ OCStackResult SRPSaveTrustCertChain(uint8_t *trustCertChain, size_t chainSize,
     res = GetDoxmDeviceID(&cred->subject);
     if (OC_STACK_OK != res)
     {
-        OIC_LOG(ERROR, TAG, "Cann't get the device id(GetDoxmDeviceID)");
+        OIC_LOG(ERROR, TAG, "Can't get the device id(GetDoxmDeviceID)");
         DeleteCredList(cred);
         return res;
     }
 
-    cred->credUsage= (char *)OICCalloc(1, strlen(TRUST_CA)+1 );
+    cred->credUsage= (char *)OICCalloc(1, strlen(TRUST_CA) + 1);
     VERIFY_NOT_NULL_RETURN(TAG, cred->credUsage, ERROR, OC_STACK_NO_MEMORY);
     OICStrcpy(cred->credUsage, strlen(TRUST_CA) + 1, TRUST_CA);
 
@@ -567,12 +620,18 @@ OCStackResult SRPSaveTrustCertChain(uint8_t *trustCertChain, size_t chainSize,
         VERIFY_NOT_NULL_RETURN(TAG, cred->optionalData.data, ERROR, OC_STACK_NO_MEMORY);
         cred->optionalData.len = chainSize + 1;
     }
-    else
+    else if (encodingType == OIC_ENCODING_DER)
     {
         cred->optionalData.data = (uint8_t *)OICCalloc(1, chainSize);
         VERIFY_NOT_NULL_RETURN(TAG, cred->optionalData.data, ERROR, OC_STACK_NO_MEMORY);
         cred->optionalData.len = chainSize;
     }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "Unknown encoding in %s", __func__);
+        DeleteCredList(cred);
+        return OC_STACK_INVALID_PARAM;
+    }
     memcpy(cred->optionalData.data, trustCertChain, chainSize);
     cred->optionalData.encoding = encodingType;
     cred->optionalData.revstat = false;
@@ -600,14 +659,15 @@ OCStackResult SRPSaveTrustCertChain(uint8_t *trustCertChain, size_t chainSize,
     return res;
 }
 
-OCStackResult SRPSaveOwnCertChain(OicSecKey_t * cert, OicSecKey_t * key, uint16_t *credId)
+static OCStackResult saveCertChain(OicSecKey_t * cert, OicSecKey_t * key, uint16_t *credId, const char* usage)
 {
-    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
+    OIC_LOG_V(DEBUG, TAG, "IN %s", __func__);
     VERIFY_NOT_NULL_RETURN(TAG, cert, ERROR,  OC_STACK_INVALID_PARAM);
     VERIFY_NOT_NULL_RETURN(TAG, cert->data, ERROR,  OC_STACK_INVALID_PARAM);
     VERIFY_NOT_NULL_RETURN(TAG, key, ERROR,  OC_STACK_INVALID_PARAM);
     VERIFY_NOT_NULL_RETURN(TAG, key->data, ERROR,  OC_STACK_INVALID_PARAM);
     VERIFY_NOT_NULL_RETURN(TAG, credId, ERROR,  OC_STACK_INVALID_PARAM);
+    VERIFY_NOT_NULL_RETURN(TAG, usage, ERROR, OC_STACK_INVALID_PARAM);
 
     OCStackResult res = OC_STACK_ERROR;
 
@@ -624,9 +684,9 @@ OCStackResult SRPSaveOwnCertChain(OicSecKey_t * cert, OicSecKey_t * key, uint16_
         return res;
     }
 
-    cred->credUsage= (char *)OICCalloc(1, strlen(PRIMARY_CERT)+1 );
+    cred->credUsage= (char *)OICCalloc(1, strlen(usage) + 1);
     VERIFY_NOT_NULL_RETURN(TAG, cred->credUsage, ERROR, OC_STACK_NO_MEMORY);
-    OICStrcpy(cred->credUsage, strlen(PRIMARY_CERT) + 1, PRIMARY_CERT) ;
+    OICStrcpy(cred->credUsage, strlen(usage) + 1, usage);
 
     cred->credType = SIGNED_ASYMMETRIC_KEY;
 
@@ -652,15 +712,22 @@ OCStackResult SRPSaveOwnCertChain(OicSecKey_t * cert, OicSecKey_t * key, uint16_
     }
     *credId = cred->credId;
 
-    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+    OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__);
 
     return res;
 }
+
+OCStackResult SRPSaveOwnCertChain(OicSecKey_t * cert, OicSecKey_t * key, uint16_t *credId)
+{
+    return saveCertChain(cert, key, credId, PRIMARY_CERT);
+}
+
 #endif // __WITH_DTLS__ || __WITH_TLS__
 
 OCStackResult SRPProvisionCredentials(void *ctx, OicSecCredType_t type, size_t keySize,
                                       const OCProvisionDev_t *pDev1,
                                       const OCProvisionDev_t *pDev2,
+                                      const char* pemCert,
                                       OCProvisionResultCB resultCallback)
 {
     VERIFY_NOT_NULL_RETURN(TAG, pDev1, ERROR,  OC_STACK_INVALID_PARAM);
@@ -670,13 +737,13 @@ OCStackResult SRPProvisionCredentials(void *ctx, OicSecCredType_t type, size_t k
     }
     if (!resultCallback)
     {
-        OIC_LOG(INFO, TAG, "SRPUnlinkDevices : NULL Callback");
+        OIC_LOG(INFO, TAG, "SRPProvisionCredentials: NULL Callback");
         return OC_STACK_INVALID_CALLBACK;
     }
     if (SYMMETRIC_PAIR_WISE_KEY == type &&
         0 == memcmp(&pDev1->doxm->deviceID, &pDev2->doxm->deviceID, sizeof(OicUuid_t)))
     {
-        OIC_LOG(INFO, TAG, "SRPUnlinkDevices : Same device ID");
+        OIC_LOG(INFO, TAG, "SRPProvisionCredentials : Same device ID");
         return OC_STACK_INVALID_PARAM;
     }
 
@@ -768,6 +835,55 @@ OCStackResult SRPProvisionCredentials(void *ctx, OicSecCredType_t type, size_t k
             VERIFY_SUCCESS_RETURN(TAG, (res==OC_STACK_OK), ERROR, OC_STACK_ERROR);
             return res;
         }
+        case SIGNED_ASYMMETRIC_KEY:
+        {
+            /* pDev1 is the device to be provisioned, checked non-null above */
+            /* pDev2 is not used, should be NULL */
+            /* size param is not used. */
+            /* pemCert is the cerficiate to be provisioned */
+            VERIFY_NOT_NULL_RETURN(TAG, pemCert, ERROR, OC_STACK_INVALID_PARAM);
+
+            OicSecKey_t deviceCert = { 0 };
+            deviceCert.data = (uint8_t*) pemCert; /* Casting away const is OK here */
+            deviceCert.len = strlen(pemCert) + 1;
+            deviceCert.encoding = OIC_ENCODING_PEM;
+
+            /* Create a credential object */
+            OicSecCred_t* cred =  GenerateCredential(&pDev1->doxm->deviceID, SIGNED_ASYMMETRIC_KEY,
+                    &deviceCert, NULL, // oic.sec.cred.publicdata = deviceCert, .privatedata = NULL
+                    &provTooldeviceID, NULL); // rowner is the provisioning tool and no eowner
+            VERIFY_NOT_NULL_RETURN(TAG, cred, ERROR, OC_STACK_ERROR);
+
+            cred->publicData.encoding = OIC_ENCODING_PEM;
+            cred->credUsage = OICStrdup(PRIMARY_CERT);
+
+            /* Create credential data (used by the response handler provisionIdentityCertCB and freed there) */
+            CredentialData_t *credData = (CredentialData_t *)OICCalloc(1, sizeof(CredentialData_t)); 
+            if (NULL == credData)
+            {
+                DeleteCredList(cred);
+                OIC_LOG(ERROR, TAG, "Memory allocation problem");
+                return OC_STACK_NO_MEMORY;
+            }
+            credData->deviceInfo1 = pDev1;
+            credData->deviceInfo2 = NULL;
+            credData->credInfo = cred;
+            credData->ctx = ctx;
+            credData->credInfoFirst = cred;
+            credData->numOfResults = 0;
+            credData->resultCallback = resultCallback;
+            credData->resArr = NULL;
+
+            /* Note: the callback of type OCClientResponseHandler, thin wrapper that calls resultCallback */
+            OCStackResult res = provisionCredentials(cred, pDev1, credData, &provisionIdentityCertCB); 
+            if (res != OC_STACK_OK)
+            {
+                OICFree(credData);
+            }
+
+            DeleteCredList(cred);
+            return OC_STACK_OK;
+        }
         default:
         {
             OIC_LOG(ERROR, TAG, "Invalid option.");
@@ -832,12 +948,26 @@ static OCStackApplicationResult SRPProvisionACLCB(void *ctx, OCDoHandle UNUSED,
 }
 
 OCStackResult SRPProvisionACL(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
-        OicSecAcl_t *acl, OCProvisionResultCB resultCallback)
+        OicSecAcl_t *acl, OicSecAclVersion_t aclVersion, OCProvisionResultCB resultCallback)
 {
     VERIFY_NOT_NULL_RETURN(TAG, selectedDeviceInfo, ERROR,  OC_STACK_INVALID_PARAM);
     VERIFY_NOT_NULL_RETURN(TAG, acl, ERROR,  OC_STACK_INVALID_PARAM);
     VERIFY_NOT_NULL_RETURN(TAG, resultCallback, ERROR,  OC_STACK_INVALID_CALLBACK);
 
+    const char *uri = NULL;
+
+    switch (aclVersion)
+    {
+    case OIC_SEC_ACL_V1:
+        uri = OIC_RSRC_ACL_URI;
+        break;
+    case OIC_SEC_ACL_V2:
+        uri = OIC_RSRC_ACL2_URI;
+        break;
+    default:
+        return OC_STACK_INVALID_PARAM;
+    }
+
     // if rowneruuid is empty, set it to device ID
     OicUuid_t emptyOwner = {.id = {0} };
     if (memcmp(&(acl->rownerID.id), &emptyOwner, UUID_IDENTITY_SIZE) == 0)
@@ -864,7 +994,7 @@ OCStackResult SRPProvisionACL(void *ctx, const OCProvisionDev_t *selectedDeviceI
         return OC_STACK_NO_MEMORY;
     }
     secPayload->base.type = PAYLOAD_TYPE_SECURITY;
-    if(OC_STACK_OK != AclToCBORPayload(acl, &secPayload->securityData, &secPayload->payloadSize))
+    if(OC_STACK_OK != AclToCBORPayload(acl, aclVersion, &secPayload->securityData, &secPayload->payloadSize))
     {
         OCPayloadDestroy((OCPayload *)secPayload);
         OIC_LOG(ERROR, TAG, "Failed to AclToCBORPayload");
@@ -878,7 +1008,7 @@ OCStackResult SRPProvisionACL(void *ctx, const OCProvisionDev_t *selectedDeviceI
                         selectedDeviceInfo->endpoint.addr,
                         selectedDeviceInfo->securePort,
                         selectedDeviceInfo->connType,
-                        query, sizeof(query), OIC_RSRC_ACL_URI))
+                        query, sizeof(query), uri))
     {
         OIC_LOG(ERROR, TAG, "DeviceDiscoveryHandler : Failed to generate query");
         return OC_STACK_ERROR;
@@ -2607,17 +2737,31 @@ static OCStackApplicationResult SRPGetACLResourceCB(void *ctx, OCDoHandle UNUSED
 }
 
 OCStackResult SRPGetACLResource(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
-        OCProvisionResultCB resultCallback)
+        OicSecAclVersion_t aclVersion, OCProvisionResultCB resultCallback)
 {
     VERIFY_NOT_NULL_RETURN(TAG, selectedDeviceInfo, ERROR,  OC_STACK_INVALID_PARAM);
     VERIFY_NOT_NULL_RETURN(TAG, resultCallback, ERROR,  OC_STACK_INVALID_CALLBACK);
 
+    const char *uri = NULL;
+
+    switch (aclVersion)
+    {
+    case OIC_SEC_ACL_V1:
+        uri = OIC_RSRC_ACL_URI;
+        break;
+    case OIC_SEC_ACL_V2:
+        uri = OIC_RSRC_ACL2_URI;
+        break;
+    default:
+        return OC_STACK_INVALID_PARAM;
+    }
+
     char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
     if(!PMGenerateQuery(true,
                         selectedDeviceInfo->endpoint.addr,
                         selectedDeviceInfo->securePort,
                         selectedDeviceInfo->connType,
-                        query, sizeof(query), OIC_RSRC_ACL_URI))
+                        query, sizeof(query), uri))
     {
         OIC_LOG(ERROR, TAG, "SRPGetACLResource : Failed to generate query");
         return OC_STACK_ERROR;
@@ -2664,6 +2808,429 @@ OCStackResult SRPGetACLResource(void *ctx, const OCProvisionDev_t *selectedDevic
     return OC_STACK_OK;
 }
 
+/**
+ * Internal Function to store results in result array during GetCSRResourceCB.
+ */
+static void registerResultForGetCSRResourceCB(GetCsrData_t *getCsrData,
+                                             OCStackResult stackresult,
+                                             const uint8_t *payload,
+                                             size_t payloadSize)
+{
+    /* SRPGetCSRResource allocates the memory for getCsrData. When it calls this callback,
+     * numOfResults points to the current entry we're filling out. Later when this structure
+     * gets returned to the caller, that's when it actually reflects the number of
+     * results returned.
+     */
+    OCPMGetCsrResult_t* currentEntry = &getCsrData->resArr[getCsrData->numOfResults];
+    OIC_LOG_V(INFO, TAG, "Inside registerResultForGetCSRResourceCB "
+        "getCsrData->numOfResults is %d\n", getCsrData->numOfResults);
+    memcpy(currentEntry->deviceId.id,
+        getCsrData->deviceInfo->doxm->deviceID.id, UUID_LENGTH);
+    currentEntry->res = stackresult;
+
+    if (OC_STACK_OK == stackresult)
+    {
+        OCStackResult res = CBORPayloadToCSR(payload, payloadSize,
+            &currentEntry->csr,
+            &currentEntry->csrLen,
+            &currentEntry->encoding);
+        if (OC_STACK_OK != res)
+        {
+            currentEntry->res = res;
+            currentEntry->csr = NULL;
+            currentEntry->csrLen = 0;
+            currentEntry->encoding = OIC_ENCODING_UNKNOW;
+        }
+    }
+
+    ++(getCsrData->numOfResults);
+}
+
+/**
+ * Callback handler of SRPGetCSRResource.
+ *
+ * @param[in] ctx             ctx value passed to callback from calling function.
+ * @param[in] UNUSED          handle to an invocation
+ * @param[in] clientResponse  Response from queries to remote servers.
+ * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
+ *          and  OC_STACK_KEEP_TRANSACTION to keep it.
+ */
+static OCStackApplicationResult SRPGetCSRResourceCB(void *ctx, OCDoHandle UNUSED,
+    OCClientResponse *clientResponse)
+{
+    size_t i = 0;
+    OIC_LOG_V(INFO, TAG, "IN %s", __func__);
+    OC_UNUSED(UNUSED);
+    VERIFY_NOT_NULL_RETURN(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
+    GetCsrData_t *getCsrData = (GetCsrData_t*)ctx;
+    OCGetCSRResultCB resultCallback = getCsrData->resultCallback;
+
+    if (clientResponse)
+    {
+        if (OC_STACK_OK == clientResponse->result)
+        {
+            uint8_t *payload = ((OCSecurityPayload*)clientResponse->payload)->securityData;
+            size_t size = ((OCSecurityPayload*)clientResponse->payload)->payloadSize;
+
+            OIC_LOG_BUFFER(DEBUG, TAG, payload, size);
+
+            registerResultForGetCSRResourceCB(getCsrData, OC_STACK_OK, payload, size);
+        }
+    }
+    else
+    {
+        registerResultForGetCSRResourceCB(getCsrData, OC_STACK_ERROR, NULL, 0);
+    }
+
+    ((OCGetCSRResultCB)(resultCallback))(getCsrData->ctx, getCsrData->numOfResults,
+        getCsrData->resArr,
+        false);
+    OIC_LOG_V(ERROR, TAG, "%s: received Null clientResponse", __func__);
+    for (i = 0; i < getCsrData->numOfResults; i++)
+    {
+        OICFree(getCsrData->resArr[i].csr);
+    }
+    OICFree(getCsrData->resArr);
+    OICFree(getCsrData);
+    OIC_LOG_V(INFO, TAG, "OUT %s", __func__);
+
+    return OC_STACK_DELETE_TRANSACTION;
+}
+
+OCStackResult SRPGetCSRResource(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
+        OCGetCSRResultCB resultCallback)
+{
+    VERIFY_NOT_NULL_RETURN(TAG, selectedDeviceInfo, ERROR,  OC_STACK_INVALID_PARAM);
+    VERIFY_NOT_NULL_RETURN(TAG, resultCallback, ERROR,  OC_STACK_INVALID_CALLBACK);
+
+    char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
+    if (!PMGenerateQuery(true,
+                        selectedDeviceInfo->endpoint.addr,
+                        selectedDeviceInfo->securePort,
+                        selectedDeviceInfo->connType,
+                        query, sizeof(query), OIC_RSRC_CSR_URI))
+    {
+        OIC_LOG(ERROR, TAG, "SRPGetCSRResource : Failed to generate query");
+        return OC_STACK_ERROR;
+    }
+    OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
+
+    OCCallbackData cbData =  {.context=NULL, .cb=NULL, .cd=NULL};
+    cbData.cb = &SRPGetCSRResourceCB;
+    GetCsrData_t* getCsrData = (GetCsrData_t*)OICCalloc(1, sizeof(GetCsrData_t));
+    if (NULL == getCsrData)
+    {
+        OIC_LOG(ERROR, TAG, "Unable to allocate memory");
+        return OC_STACK_NO_MEMORY;
+    }
+    getCsrData->deviceInfo = selectedDeviceInfo;
+    getCsrData->resultCallback = resultCallback;
+    getCsrData->numOfResults=0;
+    getCsrData->ctx = ctx;
+
+    int noOfRiCalls = 1;
+    getCsrData->resArr = (OCPMGetCsrResult_t*)OICCalloc(noOfRiCalls, sizeof(OCPMGetCsrResult_t));
+    if (NULL == getCsrData->resArr)
+    {
+        OICFree(getCsrData);
+        OIC_LOG(ERROR, TAG, "Unable to allocate memory");
+        return OC_STACK_NO_MEMORY;
+    }
+    cbData.context = (void *)getCsrData;
+    OCMethod method = OC_REST_GET;
+    OCDoHandle handle = NULL;
+    OIC_LOG(DEBUG, TAG, "Sending Get CSR to resource server");
+    OCStackResult ret = OCDoResource(&handle, method, query, NULL, NULL,
+            selectedDeviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
+    if (OC_STACK_OK != ret)
+    {
+        OIC_LOG(ERROR, TAG, "OCStack resource error");
+        OICFree(getCsrData->resArr);
+        OICFree(getCsrData);
+    }
+    OIC_LOG(DEBUG, TAG, "OUT SRPGetCSRResource");
+
+    return ret;
+}
+
+/**
+ * Internal Function to store results in result array during GetRolesResourceCB.
+ */
+static void registerResultForGetRolesResourceCB(GetRolesData_t *getRolesData,
+                                                OCStackResult stackresult,
+                                                const uint8_t *payload,
+                                                size_t payloadSize)
+{
+    /* SRPGetRolesResource allocates the memory for getRolesData. When it calls this callback,
+     * numOfResults points to the current entry we're filling out. Later when this structure
+     * gets returned to the caller, that's when it actually reflects the number of
+     * results returned.
+     */
+    OCPMGetRolesResult_t* currentEntry = &getRolesData->resArr[getRolesData->numOfResults];
+    OIC_LOG_V(INFO, TAG, "Inside registerResultForGetCSRResourceCB "
+        "getRolesData->numOfResults is %d\n", getRolesData->numOfResults);
+    memcpy(currentEntry->deviceId.id,
+        getRolesData->deviceInfo->doxm->deviceID.id, UUID_LENGTH);
+    currentEntry->res = stackresult;
+    currentEntry->chainsLength = 0;
+
+    if (OC_STACK_OK == stackresult)
+    {
+        RoleCertChain_t *chains = NULL;
+        OCStackResult res = CBORPayloadToRoles(payload, payloadSize, &chains);
+        if (OC_STACK_OK != res)
+        {
+            currentEntry->res = res;
+            currentEntry->chains = NULL;
+        }
+        else
+        {
+            RoleCertChain_t *curr = NULL;
+            for (curr = chains; NULL != curr; curr = curr->next)
+            {
+                currentEntry->chainsLength++;
+            }
+            currentEntry->chains = (OCPMRoleCertChain_t *)OICCalloc(currentEntry->chainsLength, sizeof(OCPMRoleCertChain_t));
+            if (NULL == currentEntry->chains)
+            {
+                OIC_LOG(ERROR, TAG, "No memory allocating role chains");
+                currentEntry->chainsLength = 0;
+                currentEntry->res = OC_STACK_NO_MEMORY;
+            }
+            else
+            {
+                size_t i;
+                for (i = 0, curr = chains; NULL != curr; curr = curr->next, i++)
+                {
+                    currentEntry->chains[i].credId = curr->credId;
+                    /* Take ownership of the buffers from certificate and optData, rather than copy. */
+                    currentEntry->chains[i].certificate = curr->certificate;
+                    currentEntry->chains[i].optData = curr->optData;
+                    
+                    curr->certificate.data = NULL;
+                    curr->certificate.len = 0;
+                    curr->optData.data = NULL;
+                    curr->optData.len = 0;
+                }
+            }
+            FreeRoleCertChainList(chains);
+        }
+    }
+
+    ++(getRolesData->numOfResults);
+}
+
+/**
+ * Callback handler of SRPGetRolesResource.
+ *
+ * @param[in] ctx             ctx value passed to callback from calling function.
+ * @param[in] UNUSED          handle to an invocation
+ * @param[in] clientResponse  Response from queries to remote servers.
+ * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
+ *          and  OC_STACK_KEEP_TRANSACTION to keep it.
+ */
+static OCStackApplicationResult SRPGetRolesResourceCB(void *ctx, OCDoHandle handle,
+                                                      OCClientResponse *clientResponse)
+{
+    OIC_LOG(INFO, TAG, "Inside SRPGetRolesResourceCB.");
+    OC_UNUSED(handle);
+    VERIFY_NOT_NULL_RETURN(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
+    GetRolesData_t *getRolesData = (GetRolesData_t*)ctx;
+    OCGetRolesResultCB resultCallback = getRolesData->resultCallback;
+
+    if (clientResponse)
+    {
+        if (OC_STACK_OK == clientResponse->result)
+        {
+            uint8_t *payload = ((OCSecurityPayload*)clientResponse->payload)->securityData;
+            size_t size = ((OCSecurityPayload*)clientResponse->payload)->payloadSize;
+
+            OIC_LOG_BUFFER(DEBUG, TAG, payload, size);
+
+            registerResultForGetRolesResourceCB(getRolesData, OC_STACK_OK, payload, size);
+        }
+    }
+    else
+    {
+        OIC_LOG(ERROR, TAG, "SRPGetRolesResourceCB received Null clientResponse");
+        registerResultForGetRolesResourceCB(getRolesData, OC_STACK_ERROR, NULL, 0);
+    }
+
+    resultCallback(getRolesData->ctx, getRolesData->numOfResults,
+                   getRolesData->resArr,
+                   false);
+    for (size_t i = 0; i < getRolesData->numOfResults; i++)
+    {
+        /* We took ownership of certificate.data and optData.data, so we must free them.
+         * These are allocated internally by tinycbor, which uses malloc and free, so we call
+         * free directly for those.
+         */
+        for (size_t j = 0; j < getRolesData->resArr[i].chainsLength; j++)
+        {
+            free(getRolesData->resArr[i].chains[j].certificate.data);
+            free(getRolesData->resArr[i].chains[j].optData.data);
+        }
+        OICFree(getRolesData->resArr[i].chains);
+    }
+    OICFree(getRolesData->resArr);
+    OICFree(getRolesData);
+
+    return OC_STACK_DELETE_TRANSACTION;
+}
+
+OCStackResult SRPGetRolesResource(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
+        OCGetRolesResultCB resultCallback)
+{
+    VERIFY_NOT_NULL_RETURN(TAG, selectedDeviceInfo, ERROR,  OC_STACK_INVALID_PARAM);
+    VERIFY_NOT_NULL_RETURN(TAG, resultCallback, ERROR,  OC_STACK_INVALID_CALLBACK);
+
+    char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
+    if (!PMGenerateQuery(true,
+                        selectedDeviceInfo->endpoint.addr,
+                        selectedDeviceInfo->securePort,
+                        selectedDeviceInfo->connType,
+                        query, sizeof(query), OIC_RSRC_ROLES_URI))
+    {
+        OIC_LOG(ERROR, TAG, "SRPGetRolesResource : Failed to generate query");
+        return OC_STACK_ERROR;
+    }
+    OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
+
+    OCCallbackData cbData =  {.context=NULL, .cb=NULL, .cd=NULL};
+    cbData.cb = &SRPGetRolesResourceCB;
+    GetRolesData_t *getRolesData = (GetRolesData_t*)OICCalloc(1, sizeof(GetRolesData_t));
+    if (NULL == getRolesData)
+    {
+        OIC_LOG(ERROR, TAG, "Unable to allocate memory");
+        return OC_STACK_NO_MEMORY;
+    }
+    getRolesData->deviceInfo = selectedDeviceInfo;
+    getRolesData->resultCallback = resultCallback;
+    getRolesData->numOfResults = 0;
+    getRolesData->ctx = ctx;
+
+    getRolesData->resArr = (OCPMGetRolesResult_t*)OICCalloc(1, sizeof(OCPMGetRolesResult_t));
+    if (NULL == getRolesData->resArr)
+    {
+        OICFree(getRolesData);
+        OIC_LOG(ERROR, TAG, "Unable to allocate memory");
+        return OC_STACK_NO_MEMORY;
+    }
+    cbData.context = (void *)getRolesData;
+    OCDoHandle handle = NULL;
+    OIC_LOG(DEBUG, TAG, "Sending Get Roles to resource server");
+    OCStackResult ret = OCDoResource(&handle, OC_REST_GET, query, NULL, NULL,
+            selectedDeviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
+    if (OC_STACK_OK != ret)
+    {
+        OIC_LOG(ERROR, TAG, "OCStack resource error");
+        OICFree(getRolesData->resArr);
+        OICFree(getRolesData);
+    }
+    OIC_LOG(DEBUG, TAG, "OUT SRPGetRolesResource");
+
+    return ret;
+}
+
+/**
+ * Callback handler of SRPDeleteRoleCertificateByCredId.
+ *
+ * @param[in] ctx             ctx value passed to callback from calling function.
+ * @param[in] UNUSED          handle to an invocation
+ * @param[in] clientResponse  Response from queries to remote servers.
+ * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
+ *          and  OC_STACK_KEEP_TRANSACTION to keep it.
+ */
+static OCStackApplicationResult SRPDeleteRoleCertificateCB(void *ctx, OCDoHandle UNUSED,
+                                                           OCClientResponse *clientResponse)
+{
+    OC_UNUSED(UNUSED);
+    GetSecData_t *getSecData = (GetSecData_t *)ctx;
+
+    OIC_LOG(DEBUG, TAG, "SRPDeleteRoleCertificateCB IN");
+
+    if (NULL != clientResponse)
+    {
+        memcpy(getSecData->resArr[(getSecData->numOfResults)].deviceId.id,
+            getSecData->deviceInfo->doxm->deviceID.id, UUID_LENGTH);
+        getSecData->resArr[(getSecData->numOfResults)].res = clientResponse->result;
+        ++(getSecData->numOfResults);
+    }
+
+    OIC_LOG(DEBUG, TAG, "SRPDeleteRoleCertificateCB OUT");
+
+    return OC_STACK_DELETE_TRANSACTION;
+}
+
+OCStackResult SRPDeleteRoleCertificateByCredId(void* ctx, const OCProvisionDev_t *selectedDeviceInfo,
+                                               OCProvisionResultCB resultCallback, uint32_t credId)
+{
+    VERIFY_NOT_NULL_RETURN(TAG, selectedDeviceInfo, ERROR,  OC_STACK_INVALID_PARAM);
+    VERIFY_NOT_NULL_RETURN(TAG, resultCallback, ERROR,  OC_STACK_INVALID_CALLBACK);
+
+    char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
+    if (!PMGenerateQuery(true,
+                        selectedDeviceInfo->endpoint.addr,
+                        selectedDeviceInfo->securePort,
+                        selectedDeviceInfo->connType,
+                        query, sizeof(query), OIC_RSRC_ROLES_URI))
+    {
+        OIC_LOG(ERROR, TAG, "SRPDeleteRoleCertificateByCredId : Failed to generate query");
+        return OC_STACK_ERROR;
+    }
+    size_t queryLen = strlen(query);
+    int snRet = snprintf(query + queryLen, sizeof(query) - queryLen, "?credId=%u", credId);
+
+    if (0 > snRet)
+    {
+        OIC_LOG_V(ERROR, TAG, "snprintf returned error: %d", snRet);
+        return OC_STACK_ERROR;
+    }
+    else if ((size_t)snRet >= (sizeof(query) - queryLen))
+    {
+        OIC_LOG_V(ERROR, TAG, "snprintf truncated");
+        return OC_STACK_ERROR;
+    }
+
+    OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
+
+    OCCallbackData cbData =  {.context=NULL, .cb=NULL, .cd=NULL};
+    cbData.cb = &SRPDeleteRoleCertificateCB;
+    GetSecData_t *getSecData = (GetSecData_t*)OICCalloc(1, sizeof(GetSecData_t));
+    if (NULL == getSecData)
+    {
+        OIC_LOG(ERROR, TAG, "Unable to allocate memory");
+        return OC_STACK_NO_MEMORY;
+    }
+    getSecData->deviceInfo = selectedDeviceInfo;
+    getSecData->resultCallback = resultCallback;
+    getSecData->numOfResults = 0;
+    getSecData->ctx = ctx;
+
+    getSecData->resArr = (OCProvisionResult_t*)OICCalloc(1, sizeof(OCProvisionResult_t));
+    if (NULL == getSecData->resArr)
+    {
+        OICFree(getSecData);
+        OIC_LOG(ERROR, TAG, "Unable to allocate memory");
+        return OC_STACK_NO_MEMORY;
+    }
+    cbData.context = (void *)getSecData;
+    OCMethod method = OC_REST_DELETE;
+    OCDoHandle handle = NULL;
+    OIC_LOG(DEBUG, TAG, "Sending Delete Roles to resource server");
+    OCStackResult ret = OCDoResource(&handle, method, query, NULL, NULL,
+            selectedDeviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
+    if (OC_STACK_OK != ret)
+    {
+        OIC_LOG(ERROR, TAG, "OCStack resource error");
+        OICFree(getSecData->resArr);
+        OICFree(getSecData);
+    }
+    OIC_LOG(DEBUG, TAG, "OUT SRPGetRolesResource");
+
+    return ret;
+}
+
 OCStackResult SRPReadTrustCertChain(uint16_t credId, uint8_t **trustCertChain,
                                      size_t *chainSize)
 {
index 81b38e8..a438504 100644 (file)
@@ -76,44 +76,49 @@ TEST(SRPProvisionACLTest, NullDeviceInfo)
     uint8_t deviceId2[] = {0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x63};
     memcpy(pDev2.doxm->deviceID.id, deviceId2, sizeof(deviceId2));
 
-    EXPECT_EQ(OC_STACK_INVALID_PARAM, SRPProvisionACL(NULL, NULL, &acl, &provisioningCB));
+    EXPECT_EQ(OC_STACK_INVALID_PARAM, SRPProvisionACL(NULL, NULL, &acl, OIC_SEC_ACL_V2, &provisioningCB));
 }
 
 TEST(SRPProvisionACLTest, NullCallback)
 {
-    EXPECT_EQ(OC_STACK_INVALID_CALLBACK, SRPProvisionACL(NULL, &pDev1, &acl, NULL));
+    EXPECT_EQ(OC_STACK_INVALID_CALLBACK, SRPProvisionACL(NULL, &pDev1, &acl, OIC_SEC_ACL_V2, NULL));
 }
 
 TEST(SRPProvisionACLTest, NullACL)
 {
-    EXPECT_EQ(OC_STACK_INVALID_PARAM, SRPProvisionACL(NULL, &pDev1, NULL, &provisioningCB));
+    EXPECT_EQ(OC_STACK_INVALID_PARAM, SRPProvisionACL(NULL, &pDev1, NULL, OIC_SEC_ACL_V2, &provisioningCB));
+}
+
+TEST(SRPProvisionACLTest, InvalidVersion)
+{
+    EXPECT_EQ(OC_STACK_INVALID_PARAM, SRPProvisionACL(NULL, &pDev1, &acl, OIC_SEC_ACL_UNKNOWN, &provisioningCB));
 }
 
 TEST(SRPProvisionCredentialsTest, NullDevice1)
 {
     EXPECT_EQ(OC_STACK_INVALID_PARAM, SRPProvisionCredentials(NULL, credType,
                                                               OWNER_PSK_LENGTH_128, NULL,
-                                                              &pDev2, &provisioningCB));
+                                                              &pDev2, NULL, &provisioningCB));
 }
 
 TEST(SRPProvisionCredentialsTest, SamelDeviceId)
 {
     EXPECT_EQ(OC_STACK_INVALID_PARAM, SRPProvisionCredentials(NULL, credType,
                                                               OWNER_PSK_LENGTH_128, &pDev1,
-                                                              &pDev1, &provisioningCB));
+                                                              &pDev1, NULL, &provisioningCB));
 }
 
 TEST(SRPProvisionCredentialsTest, NullCallback)
 {
     EXPECT_EQ(OC_STACK_INVALID_CALLBACK, SRPProvisionCredentials(NULL, credType,
                                                                  OWNER_PSK_LENGTH_128,
-                                                                 &pDev1, &pDev2, NULL));
+                                                                 &pDev1, &pDev2, NULL, NULL));
 }
 
 TEST(SRPProvisionCredentialsTest, InvalidKeySize)
 {
     EXPECT_EQ(OC_STACK_INVALID_PARAM, SRPProvisionCredentials(NULL, credType,
-                                                                0, &pDev1, &pDev2,
+                                                                0, &pDev1, &pDev2, NULL,
                                                                 &provisioningCB));
 }
 
@@ -452,12 +457,12 @@ TEST_F(SRPTest, SRPProvisionTrustCertChainNoResource)
 
 TEST(SRPProvisionTrustCertChainTest, SRPGetACLResourceNoCallback)
 {
-    EXPECT_EQ(OC_STACK_INVALID_CALLBACK, SRPGetACLResource(NULL, &pDev1, NULL));
+    EXPECT_EQ(OC_STACK_INVALID_CALLBACK, SRPGetACLResource(NULL, &pDev1, OIC_SEC_ACL_V2, NULL));
 }
 
 TEST(SRPProvisionTrustCertChainTest, SRPGetACLResourceNoDevice)
 {
-    EXPECT_EQ(OC_STACK_INVALID_PARAM, SRPGetACLResource(NULL, NULL, provisioningCB));
+    EXPECT_EQ(OC_STACK_INVALID_PARAM, SRPGetACLResource(NULL, NULL, OIC_SEC_ACL_V2, provisioningCB));
 }
 
 TEST(SRPProvisionTrustCertChainTest, SRPGetCredResourceNoCallback)
index 369c33e..019e445 100644 (file)
@@ -55,6 +55,7 @@ static const uint8_t ACL_MAP_SIZE = 4;
 static const uint8_t ACL_ACLIST_MAP_SIZE = 1;
 static const uint8_t ACL_ACES_MAP_SIZE = 3;
 static const uint8_t ACL_RESOURCE_MAP_SIZE = 3;
+static const uint8_t ACE_ROLE_MAP_SIZE = 2;
 
 
 // CborSize is the default cbor payload size being used.
@@ -62,6 +63,7 @@ static const uint16_t CBOR_SIZE = 2048*8;
 
 static OicSecAcl_t *gAcl = NULL;
 static OCResourceHandle gAclHandle = NULL;
+static OCResourceHandle gAcl2Handle = NULL;
 
 void FreeRsrc(OicSecRsrc_t *rsrc)
 {
@@ -166,8 +168,21 @@ OicSecAce_t* DuplicateACE(const OicSecAce_t* ace)
         newAce = (OicSecAce_t*)OICCalloc(1, sizeof(OicSecAce_t));
         VERIFY_NOT_NULL(TAG, newAce, ERROR);
 
-        //Subject uuid
-        memcpy(&newAce->subjectuuid, &ace->subjectuuid, sizeof(OicUuid_t));
+        //Subject
+        newAce->subjectType = ace->subjectType;
+        switch (newAce->subjectType)
+        {
+        case OicSecAceUuidSubject:
+            memcpy(&newAce->subjectuuid, &ace->subjectuuid, sizeof(OicUuid_t));
+            break;
+        case OicSecAceRoleSubject:
+            memcpy(&newAce->subjectRole, &ace->subjectRole, sizeof(ace->subjectRole));
+            break;
+        default:
+            assert(!"Unsupported ACE type");
+            OICFree(newAce);
+            return NULL;
+        }
 
         OicSecRsrc_t* rsrc = NULL;
         LL_FOREACH(ace->resources, rsrc)
@@ -285,10 +300,20 @@ static size_t OicSecAclSize(const OicSecAcl_t *secAcl)
     return size;
 }
 
-OCStackResult AclToCBORPayload(const OicSecAcl_t *secAcl, uint8_t **payload, size_t *size)
+OCStackResult AclToCBORPayload(const OicSecAcl_t *secAcl, OicSecAclVersion_t aclVersion, uint8_t **payload, size_t *size)
 {
-     if (NULL == secAcl || NULL == payload || NULL != *payload || NULL == size)
+    if (NULL == secAcl || NULL == payload || NULL != *payload || NULL == size)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    /* aclVersion parameter validation. */
+    switch (aclVersion)
     {
+    case OIC_SEC_ACL_V1:
+    case OIC_SEC_ACL_V2:
+        break;
+    default:
         return OC_STACK_INVALID_PARAM;
     }
 
@@ -343,6 +368,13 @@ OCStackResult AclToCBORPayload(const OicSecAcl_t *secAcl, uint8_t **payload, siz
         uint8_t aclMapSize = ACL_ACES_MAP_SIZE;
         size_t inLen = 0;
 
+        // Version 1 doesn't support role subjects. If we have any, we can't comply with the request.
+        if ((OIC_SEC_ACL_V2 > aclVersion) && (OicSecAceRoleSubject == ace->subjectType))
+        {
+            cborEncoderResult = CborUnknownError;
+            VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "ACE has a role subject; can't create a V1 ACL payload for this ACL.");
+        }
+
         OicSecValidity_t* validityElts = ace->validities;
         while(validityElts)
         {
@@ -370,22 +402,54 @@ OCStackResult AclToCBORPayload(const OicSecAcl_t *secAcl, uint8_t **payload, siz
         cborEncoderResult = cbor_encode_text_string(&oicSecAclMap, OIC_JSON_SUBJECTID_NAME,
             strlen(OIC_JSON_SUBJECTID_NAME));
         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Subject Name Tag.");
-        inLen = (memcmp(&(ace->subjectuuid), &WILDCARD_SUBJECT_ID, sizeof(OicUuid_t)) == 0) ?
-            WILDCARD_SUBJECT_ID_LEN : sizeof(OicUuid_t);
-        if(inLen == WILDCARD_SUBJECT_ID_LEN)
+        if (OicSecAceUuidSubject == ace->subjectType)
         {
-            cborEncoderResult = cbor_encode_text_string(&oicSecAclMap, WILDCARD_RESOURCE_URI,
-                strlen(WILDCARD_RESOURCE_URI));
-            VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding Subject Id wildcard Value.");
+            inLen = (memcmp(&(ace->subjectuuid), &WILDCARD_SUBJECT_ID, sizeof(OicUuid_t)) == 0) ?
+                WILDCARD_SUBJECT_ID_LEN : sizeof(OicUuid_t);
+            if (inLen == WILDCARD_SUBJECT_ID_LEN)
+            {
+                cborEncoderResult = cbor_encode_text_string(&oicSecAclMap, WILDCARD_RESOURCE_URI,
+                    strlen(WILDCARD_RESOURCE_URI));
+                VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding Subject Id wildcard Value.");
+            }
+            else
+            {
+                char *subject = NULL;
+                ret = ConvertUuidToStr(&ace->subjectuuid, &subject);
+                cborEncoderResult = (OC_STACK_OK == ret) ? CborNoError : CborUnknownError;
+                VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed to convert subject UUID to string");
+                cborEncoderResult = cbor_encode_text_string(&oicSecAclMap, subject, strlen(subject));
+                OICFree(subject);
+                VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding Subject UUID Value");
+            }
+        }
+        else if (OicSecAceRoleSubject == ace->subjectType)
+        {
+            assert(OIC_SEC_ACL_V2 <= aclVersion);
+            CborEncoder roleMap;
+            cborEncoderResult = cbor_encoder_create_map(&oicSecAclMap, &roleMap, ACE_ROLE_MAP_SIZE);
+            VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed creating role map");
+
+            cborEncoderResult = cbor_encode_text_string(&roleMap, OIC_JSON_ROLEIDS_NAME, strlen(OIC_JSON_ROLEIDS_NAME));
+            VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding roleid tag");
+
+            cborEncoderResult = cbor_encode_text_string(&roleMap, ace->subjectRole.id, strlen(ace->subjectRole.id));
+            VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding roleid value");
+
+            cborEncoderResult = cbor_encode_text_string(&roleMap, OIC_JSON_AUTHORITY_NAME, strlen(OIC_JSON_AUTHORITY_NAME));
+            VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding authority tag");
+
+            cborEncoderResult = cbor_encode_text_string(&roleMap, ace->subjectRole.authority, strlen(ace->subjectRole.authority));
+            VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding authority value");
+
+            cborEncoderResult = cbor_encoder_close_container(&oicSecAclMap, &roleMap);
+            VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed closing role map");
         }
         else
         {
-            char *subject = NULL;
-            ret = ConvertUuidToStr(&ace->subjectuuid, &subject);
-            VERIFY_SUCCESS(TAG, ret == OC_STACK_OK, ERROR);
-            cborEncoderResult = cbor_encode_text_string(&oicSecAclMap, subject, strlen(subject));
-            VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding Subject UUID Value.");
-            OICFree(subject);
+            assert(!"Unknown ACE subject type");
+            cborEncoderResult = CborUnknownError;
+            VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Unknown ACE subject type");
         }
 
         // Resources
@@ -647,7 +711,7 @@ exit:
         // Since the allocated initial memory failed, double the memory.
         cborLen += cbor_encoder_get_buffer_size(&encoder, encoder.end);
         cborEncoderResult = CborNoError;
-        ret = AclToCBORPayload(secAcl, payload, &cborLen);
+        ret = AclToCBORPayload(secAcl, aclVersion, payload, &cborLen);
         *size = cborLen;
     }
     else if (cborEncoderResult != CborNoError)
@@ -666,7 +730,7 @@ exit:
 // This function converts CBOR format to ACL data.
 // Caller needs to invoke 'free' when done using
 // It parses { "aclist" : [ { ... } ] } instead of { "aclist" : { "aces" : [ ] } }
-OicSecAcl_t* CBORPayloadToAcl2(const uint8_t *cborPayload, const size_t size)
+OicSecAcl_t* CBORPayloadToCloudAcl(const uint8_t *cborPayload, const size_t size)
 {
     if (NULL == cborPayload || 0 == size)
     {
@@ -744,14 +808,15 @@ OicSecAcl_t* CBORPayloadToAcl2(const uint8_t *cborPayload, const size_t size)
                                 if(strcmp(subject, WILDCARD_RESOURCE_URI) == 0)
                                 {
                                     ace->subjectuuid.id[0] = '*';
+                                    free(subject);
                                 }
                                 else
                                 {
                                     OIC_LOG_V(DEBUG, TAG, "Converting subjectuuid = %s to uuid...", subject);
                                     ret = ConvertStrToUuid(subject, &ace->subjectuuid);
+                                    free(subject);
                                     VERIFY_SUCCESS(TAG, ret == OC_STACK_OK, ERROR);
                                 }
-                                OICFree(subject);
                             }
 
                             // Resources -- Mandatory
@@ -946,10 +1011,12 @@ OicSecAcl_t* CBORPayloadToAcl2(const uint8_t *cborPayload, const size_t size)
                 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Rownerid Value.");
                 OIC_LOG_V(DEBUG, TAG, "Converting rownerid = %s to uuid...", stRowner);
                 ret = ConvertStrToUuid(stRowner, &acl->rownerID);
+                free(stRowner);
                 VERIFY_SUCCESS(TAG, ret == OC_STACK_OK, ERROR);
-                OICFree(stRowner);
             }
-            OICFree(tagName);
+            // Strings allocated with cbor_value_dup_text_string must be freed with free, not OICFree.
+            free(tagName);
+            tagName = NULL;
         }
         if (cbor_value_is_valid(&aclMap))
         {
@@ -970,7 +1037,7 @@ exit:
 }
 
 // This function converts CBOR format to ACL data.
-// Caller needs to invoke 'free' when done using
+// Caller needs to invoke 'OICFree' on returned value when done using
 // note: This function is used in unit test hence not declared static,
 OicSecAcl_t* CBORPayloadToAcl(const uint8_t *cborPayload, const size_t size)
 {
@@ -983,6 +1050,8 @@ OicSecAcl_t* CBORPayloadToAcl(const uint8_t *cborPayload, const size_t size)
     CborValue aclCbor = { .parser = NULL };
     CborParser parser = { .end = NULL };
     CborError cborFindResult = CborNoError;
+    char *tagName = NULL;
+    char *roleTagName = NULL;
 
     cbor_parser_init(cborPayload, size, 0, &parser, &aclCbor);
 
@@ -995,7 +1064,6 @@ OicSecAcl_t* CBORPayloadToAcl(const uint8_t *cborPayload, const size_t size)
 
     while (cbor_value_is_valid(&aclMap))
     {
-        char* tagName = NULL;
         size_t len = 0;
         CborType type = cbor_value_get_type(&aclMap);
         if (type == CborTextStringType)
@@ -1064,21 +1132,108 @@ OicSecAcl_t* CBORPayloadToAcl(const uint8_t *cborPayload, const size_t size)
                                     if (name)
                                     {
                                         // Subject -- Mandatory
-                                        if (strcmp(name, OIC_JSON_SUBJECTID_NAME)  == 0)
+                                        if (strcmp(name, OIC_JSON_SUBJECTID_NAME) == 0)
                                         {
-                                            char *subject = NULL;
-                                            cborFindResult = cbor_value_dup_text_string(&aceMap, &subject, &tempLen, NULL);
-                                            VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding subject Value.");
-                                            if(strcmp(subject, WILDCARD_RESOURCE_URI) == 0)
+                                            if (cbor_value_is_text_string(&aceMap))
                                             {
-                                                ace->subjectuuid.id[0] = '*';
+                                                /* UUID-type subject */
+                                                char *subject = NULL;
+                                                cborFindResult = cbor_value_dup_text_string(&aceMap, &subject, &tempLen, NULL);
+                                                VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding subject Value.");
+                                                if (strcmp(subject, WILDCARD_RESOURCE_URI) == 0)
+                                                {
+                                                    ace->subjectuuid.id[0] = '*';
+                                                    ace->subjectType = OicSecAceUuidSubject;
+                                                }
+                                                else
+                                                {
+                                                    ret = ConvertStrToUuid(subject, &ace->subjectuuid);
+                                                    if (OC_STACK_OK != ret)
+                                                    {
+                                                        cborFindResult = CborUnknownError;
+                                                        free(subject);
+                                                        VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed converting subject UUID");
+                                                    }
+                                                    ace->subjectType = OicSecAceUuidSubject;
+                                                }
+                                                free(subject);
+                                            }
+                                            else if (cbor_value_is_container(&aceMap))
+                                            {
+                                                /* Role subject */
+                                                size_t unusedLen = 0;
+                                                CborValue roleMap;
+                                                memset(&roleMap, 0, sizeof(roleMap));
+
+                                                cborFindResult = cbor_value_enter_container(&aceMap, &roleMap);
+                                                VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed entering role map");
+
+                                                while (cbor_value_is_valid(&roleMap) && cbor_value_is_text_string(&roleMap))
+                                                {
+                                                    cborFindResult = cbor_value_dup_text_string(&roleMap, &roleTagName, &unusedLen, NULL);
+                                                    VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed getting role map tag name");
+                                                    cborFindResult = cbor_value_advance(&roleMap);
+                                                    VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed advancing role map");
+
+                                                    if (NULL != roleTagName)
+                                                    {
+                                                        if (strcmp(roleTagName, OIC_JSON_ROLEIDS_NAME) == 0)
+                                                        {
+                                                            char *roleId = NULL;
+                                                            cborFindResult = cbor_value_dup_text_string(&roleMap, &roleId, &unusedLen, NULL);
+                                                            VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed getting role id value");
+                                                            if (strlen(roleId) >= sizeof(ace->subjectRole.id))
+                                                            {
+                                                                cborFindResult = CborUnknownError;
+                                                                VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Role ID is too long");
+                                                            }
+                                                            OICStrcpy(ace->subjectRole.id, sizeof(ace->subjectRole.id), roleId);
+                                                            free(roleId);
+                                                        }
+                                                        else if (strcmp(roleTagName, OIC_JSON_AUTHORITY_NAME) == 0)
+                                                        {
+                                                            char *authorityName = NULL;
+                                                            cborFindResult = cbor_value_dup_text_string(&roleMap, &authorityName, &unusedLen, NULL);
+                                                            VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed getting role authority value");
+                                                            if (strlen(authorityName) >= sizeof(ace->subjectRole.authority))
+                                                            {
+                                                                cborFindResult = CborUnknownError;
+                                                                VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Authority name is too long");
+                                                            }
+                                                            OICStrcpy(ace->subjectRole.authority, sizeof(ace->subjectRole.authority), authorityName);
+                                                            free(authorityName);
+                                                        }
+                                                        else
+                                                        {
+                                                            OIC_LOG_V(WARNING, TAG, "Unknown tag name in role map: %s", roleTagName);
+                                                        }
+
+                                                        free(roleTagName);
+                                                        roleTagName = NULL;
+                                                    }
+
+                                                    if (cbor_value_is_valid(&roleMap))
+                                                    {
+                                                        cborFindResult = cbor_value_advance(&roleMap);
+                                                        VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed advancing role map");
+                                                    }
+                                                }
+
+                                                /* Make sure at least the id is present. */
+                                                if ('\0' == ace->subjectRole.id[0])
+                                                {
+                                                    cborFindResult = CborUnknownError;
+                                                    VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "ID for role was not present in role map");
+                                                }
+
+                                                ace->subjectType = OicSecAceRoleSubject;
                                             }
                                             else
                                             {
-                                                ret = ConvertStrToUuid(subject, &ace->subjectuuid);
-                                                VERIFY_SUCCESS(TAG, ret == OC_STACK_OK, ERROR);
+                                                cborFindResult = CborUnknownError;
+                                                OIC_LOG_V(ERROR, TAG, "Unknown subject value type: %d", cbor_value_get_type(&aceMap));
+                                                VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Type of subject value was not expected");
                                             }
-                                            OICFree(subject);
                                         }
 
                                         // Resources -- Mandatory
@@ -1298,14 +1453,15 @@ OicSecAcl_t* CBORPayloadToAcl(const uint8_t *cborPayload, const size_t size)
                 cborFindResult = cbor_value_dup_text_string(&aclMap, &stRowner, &len, NULL);
                 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Rownerid Value.");
                 ret = ConvertStrToUuid(stRowner, &acl->rownerID);
+                free(stRowner);
                 VERIFY_SUCCESS(TAG, ret == OC_STACK_OK, ERROR);
-                OICFree(stRowner);
             }
             else if (NULL != gAcl)
             {
                 memcpy(&(acl->rownerID), &(gAcl->rownerID), sizeof(OicUuid_t));
             }
-            OICFree(tagName);
+            free(tagName);
+            tagName = NULL;
         }
         if (cbor_value_is_valid(&aclMap))
         {
@@ -1322,6 +1478,9 @@ exit:
         acl = NULL;
     }
 
+    free(tagName);
+    free(roleTagName);
+
     return acl;
 }
 
@@ -1450,7 +1609,7 @@ OCStackResult RemoveACE(const OicUuid_t *subject, const char *resource)
         {
             uint8_t *payload = NULL;
             size_t size = 0;
-            if (OC_STACK_OK == AclToCBORPayload(gAcl, &payload, &size))
+            if (OC_STACK_OK == AclToCBORPayload(gAcl, OIC_SEC_ACL_V2, &payload, &size))
             {
                 if (OC_STACK_OK == UpdateSecureResourceInPS(OIC_JSON_ACL_NAME, payload, size))
                 {
@@ -1861,7 +2020,7 @@ static OCStackResult RemoveAllAce(void)
     OIC_LOG(INFO, TAG, "IN RemoveAllAce");
 
     //Backup the current ACL
-    ret = AclToCBORPayload(gAcl, &aclBackup, &backupSize);
+    ret = AclToCBORPayload(gAcl, OIC_SEC_ACL_LATEST, &aclBackup, &backupSize);
     if(OC_STACK_OK == ret)
     {
         // Remove all ACE from ACL
@@ -1872,7 +2031,7 @@ static OCStackResult RemoveAllAce(void)
         }
 
         //Generate empty ACL payload
-        ret = AclToCBORPayload(gAcl, &payload, &size);
+        ret = AclToCBORPayload(gAcl, OIC_SEC_ACL_LATEST, &payload, &size);
         if (OC_STACK_OK == ret )
         {
             //Update the PS.
@@ -1918,7 +2077,7 @@ static OCStackResult RemoveAllAce(void)
     return (OC_STACK_OK == ret ? OC_STACK_RESOURCE_DELETED : ret);
 }
 
-static OCEntityHandlerResult HandleACLGetRequest(const OCEntityHandlerRequest *ehRequest)
+static OCEntityHandlerResult HandleACLGetRequest(const OCEntityHandlerRequest *ehRequest, OicSecAclVersion_t aclVersion)
 {
     OIC_LOG(INFO, TAG, "HandleACLGetRequest processing the request");
     uint8_t* payload = NULL;
@@ -1969,7 +2128,7 @@ static OCEntityHandlerResult HandleACLGetRequest(const OCEntityHandlerRequest *e
                         0 == strcmp(WILDCARD_RESOURCE_URI, rsrc->href))
                     {
                         // Convert ACL data into CBOR format for transmission
-                        if (OC_STACK_OK != AclToCBORPayload(&targetAcl, &payload, &size))
+                        if (OC_STACK_OK != AclToCBORPayload(&targetAcl, aclVersion, &payload, &size))
                         {
                             ehRet = OC_EH_ERROR;
                         }
@@ -1980,7 +2139,7 @@ static OCEntityHandlerResult HandleACLGetRequest(const OCEntityHandlerRequest *e
             else
             {
                 // Convert ACL data into CBOR format for transmission
-                if (OC_STACK_OK != AclToCBORPayload(&targetAcl, &payload, &size))
+                if (OC_STACK_OK != AclToCBORPayload(&targetAcl, aclVersion, &payload, &size))
                 {
                     ehRet = OC_EH_ERROR;
                 }
@@ -1993,7 +2152,7 @@ static OCEntityHandlerResult HandleACLGetRequest(const OCEntityHandlerRequest *e
     {
         OIC_LOG(DEBUG,TAG,"'subject' field is not inculded in REST request.");
         // Convert ACL data into CBOR format for transmission.
-        if (OC_STACK_OK != AclToCBORPayload(gAcl, &payload, &size))
+        if (OC_STACK_OK != AclToCBORPayload(gAcl, aclVersion, &payload, &size))
         {
             ehRet = OC_EH_ERROR;
         }
@@ -2074,7 +2233,7 @@ static OCEntityHandlerResult HandleACLPostRequest(const OCEntityHandlerRequest *
                 size_t cborSize = 0;
                 uint8_t *cborPayload = NULL;
 
-                if (OC_STACK_OK == AclToCBORPayload(gAcl, &cborPayload, &cborSize))
+                if (OC_STACK_OK == AclToCBORPayload(gAcl, OIC_SEC_ACL_LATEST, &cborPayload, &cborSize))
                 {
                     if (UpdateSecureResourceInPS(OIC_JSON_ACL_NAME, cborPayload, cborSize) == OC_STACK_OK)
                     {
@@ -2156,7 +2315,46 @@ OCEntityHandlerResult ACLEntityHandler(OCEntityHandlerFlag flag, OCEntityHandler
         switch (ehRequest->method)
         {
             case OC_REST_GET:
-                ehRet = HandleACLGetRequest(ehRequest);
+                ehRet = HandleACLGetRequest(ehRequest, OIC_SEC_ACL_V1);
+                break;
+
+            case OC_REST_POST:
+                ehRet = HandleACLPostRequest(ehRequest);
+                break;
+
+            case OC_REST_DELETE:
+                ehRet = HandleACLDeleteRequest(ehRequest);
+                break;
+
+            default:
+                ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
+                               OC_EH_OK : OC_EH_ERROR;
+        }
+    }
+
+    return ehRet;
+}
+
+OCEntityHandlerResult ACL2EntityHandler(OCEntityHandlerFlag flag, OCEntityHandlerRequest * ehRequest,
+        void* callbackParameter)
+{
+    OIC_LOG(DEBUG, TAG, "Received request ACL2EntityHandler");
+    OC_UNUSED(callbackParameter);
+    OCEntityHandlerResult ehRet = OC_EH_ERROR;
+
+    if (!ehRequest)
+    {
+        return ehRet;
+    }
+
+    if (flag & OC_REQUEST_FLAG)
+    {
+        // TODO :  Handle PUT method
+        OIC_LOG(DEBUG, TAG, "Flag includes OC_REQUEST_FLAG");
+        switch (ehRequest->method)
+        {
+            case OC_REST_GET:
+                ehRet = HandleACLGetRequest(ehRequest, OIC_SEC_ACL_V2);
                 break;
 
             case OC_REST_POST:
@@ -2177,7 +2375,7 @@ OCEntityHandlerResult ACLEntityHandler(OCEntityHandlerFlag flag, OCEntityHandler
 }
 
 /**
- * This internal method is used to create '/oic/sec/acl' resource.
+ * This internal method is used to create the '/oic/sec/acl' and '/oic/sec/acl2' resources.
  */
 static OCStackResult CreateACLResource()
 {
@@ -2196,6 +2394,21 @@ static OCStackResult CreateACLResource()
         OIC_LOG(FATAL, TAG, "Unable to instantiate ACL resource");
         DeInitACLResource();
     }
+
+    ret = OCCreateResource(&gAcl2Handle,
+                           OIC_RSRC_TYPE_SEC_ACL2,
+                           OC_RSRVD_INTERFACE_DEFAULT,
+                           OIC_RSRC_ACL2_URI,
+                           ACL2EntityHandler,
+                           NULL,
+                           OC_SECURE);
+
+    if (OC_STACK_OK != ret)
+    {
+        OIC_LOG(FATAL, TAG, "Unable to instantiate ACL2 resource");
+        DeInitACLResource();
+    }
+
     return ret;
 }
 
@@ -2239,6 +2452,7 @@ OCStackResult GetDefaultACL(OicSecAcl_t** defaultAcl)
     VERIFY_NOT_NULL(TAG, readOnlyAce, ERROR);
 
     // Subject -- Mandatory
+    readOnlyAce->subjectType = OicSecAceUuidSubject;
     memcpy(&readOnlyAce->subjectuuid, &WILDCARD_SUBJECT_ID, sizeof(readOnlyAce->subjectuuid));
 
     // Resources -- Mandatory
@@ -2311,6 +2525,7 @@ OCStackResult GetDefaultACL(OicSecAcl_t** defaultAcl)
     VERIFY_NOT_NULL(TAG, readWriteAce, ERROR);
 
     // Subject -- Mandatory
+    readWriteAce->subjectType = OicSecAceUuidSubject;
     memcpy(&readWriteAce->subjectuuid, &WILDCARD_SUBJECT_ID, sizeof(readWriteAce->subjectuuid));
 
     // Resources -- Mandatory
@@ -2459,13 +2674,15 @@ OCStackResult DeInitACLResource()
 {
     OCStackResult ret =  OCDeleteResource(gAclHandle);
     gAclHandle = NULL;
+    OCStackResult ret2 = OCDeleteResource(gAcl2Handle);
+    gAcl2Handle = NULL;
 
     if (gAcl)
     {
         DeleteACLList(gAcl);
         gAcl = NULL;
     }
-    return ret;
+    return (OC_STACK_OK != ret) ? ret : ret2;
 }
 
 const OicSecAce_t* GetACLResourceData(const OicUuid_t* subjectId, OicSecAce_t **savePtr)
@@ -2508,7 +2725,8 @@ const OicSecAce_t* GetACLResourceData(const OicUuid_t* subjectId, OicSecAce_t **
     // Find the next ACL corresponding to the 'subjectID' and return it.
     LL_FOREACH(begin, ace)
     {
-        if (memcmp(&(ace->subjectuuid), subjectId, sizeof(OicUuid_t)) == 0)
+        if ((OicSecAceUuidSubject == ace->subjectType) && 
+            (0 == memcmp(&(ace->subjectuuid), subjectId, sizeof(OicUuid_t))))
         {
             OIC_LOG(DEBUG, TAG, "GetACLResourceData: found matching ACE:");
             printACE(ace);
@@ -2522,7 +2740,70 @@ const OicSecAce_t* GetACLResourceData(const OicUuid_t* subjectId, OicSecAce_t **
     return NULL;
 }
 
-OCStackResult AppendACL2(const OicSecAcl_t* acl)
+const OicSecAce_t* GetACLResourceDataByRoles(const OicSecRole_t *roles, size_t roleCount, OicSecAce_t **savePtr)
+{
+    OicSecAce_t *ace = NULL;
+    OicSecAce_t *begin = NULL;
+
+    if ((NULL == savePtr) || (NULL == gAcl))
+    {
+        OIC_LOG(ERROR, TAG, "Invalid parameters to GetACLResourceDataByRoles");
+        return NULL;
+    }
+
+    if ((NULL == roles) || (0 == roleCount))
+    {
+        /* Not an error; just nothing to do. */
+        return NULL;
+    }
+
+    /*
+     * savePtr MUST point to NULL if this is the 'first' call to retrieve ACL for
+     * subjectID.
+     */
+    if (NULL == *savePtr)
+    {
+        begin = gAcl->aces;
+    }
+    else
+    {
+        /*
+         * If this is a 'successive' call, search for location pointed by
+         * savePtr and assign 'begin' to the next ACL after it in the linked
+         * list and start searching from there.
+         */
+        LL_FOREACH(gAcl->aces, ace)
+        {
+            if (ace == *savePtr)
+            {
+                begin = ace->next;
+            }
+        }
+    }
+
+    // Find the next ACL corresponding to the 'roleID' and return it.
+    LL_FOREACH(begin, ace)
+    {
+        if (OicSecAceRoleSubject == ace->subjectType)
+        {
+            for (size_t i = 0; i < roleCount; i++)
+            {
+                if ((0 == strcmp(ace->subjectRole.id, roles[i].id) &&
+                    (0 == strcmp(ace->subjectRole.authority, roles[i].authority))))
+                {
+                    *savePtr = ace;
+                    return ace;
+                }
+            }
+        }
+    }
+
+    // Cleanup in case no ACL is found
+    *savePtr = NULL;
+    return NULL;
+}
+
+OCStackResult AppendACLObject(const OicSecAcl_t* acl)
 {
     OCStackResult ret = OC_STACK_ERROR;
 
@@ -2551,7 +2832,7 @@ OCStackResult AppendACL2(const OicSecAcl_t* acl)
 
     size_t size = 0;
     uint8_t *payload = NULL;
-    ret = AclToCBORPayload(gAcl, &payload, &size);
+    ret = AclToCBORPayload(gAcl, OIC_SEC_ACL_LATEST, &payload, &size);
     if (OC_STACK_OK == ret)
     {
         ret = UpdateSecureResourceInPS(OIC_JSON_ACL_NAME, payload, size);
@@ -2566,7 +2847,7 @@ OCStackResult AppendACL(const uint8_t *cborPayload, const size_t size)
     // Convert CBOR format to ACL data. This will also validate the ACL data received.
     OicSecAcl_t* newAcl = CBORPayloadToAcl(cborPayload, size);
 
-    return AppendACL2(newAcl);
+    return AppendACLObject(newAcl);
 }
 
 OCStackResult InstallACL(const OicSecAcl_t* acl)
@@ -2630,7 +2911,7 @@ OCStackResult InstallACL(const OicSecAcl_t* acl)
 
     if (newInstallAcl)
     {
-        ret = AppendACL2(newInstallAcl);
+        ret = AppendACLObject(newInstallAcl);
         if (OC_STACK_OK != ret)
         {
             OIC_LOG(ERROR, TAG, "Failed to append ACL");
@@ -2676,6 +2957,7 @@ static OicSecAce_t* GetSecDefaultACE()
     VERIFY_NOT_NULL(TAG, newAce, ERROR);
 
     // Subject -- Mandatory
+    newAce->subjectType = OicSecAceUuidSubject;
     memcpy(&newAce->subjectuuid, &WILDCARD_SUBJECT_ID, WILDCARD_SUBJECT_ID_LEN);
 
     //Resources -- Mandatory
@@ -2758,7 +3040,8 @@ OCStackResult UpdateDefaultSecProvACE()
         LL_FOREACH_SAFE(gAcl->aces, ace, tempAce)
         {
             //Find default security resource ACL
-            if(memcmp(&ace->subjectuuid, &WILDCARD_SUBJECT_ID, sizeof(OicUuid_t)) == 0 &&
+            if(OicSecAceUuidSubject == ace->subjectType &&
+                memcmp(&ace->subjectuuid, &WILDCARD_SUBJECT_ID, sizeof(OicUuid_t)) == 0 &&
                 ((PERMISSION_READ | PERMISSION_WRITE) == ace->permission))
             {
                 matchedRsrc = 0;
@@ -2802,7 +3085,7 @@ OCStackResult UpdateDefaultSecProvACE()
 
                 size_t size = 0;
                 uint8_t *payload = NULL;
-                if (OC_STACK_OK == AclToCBORPayload(gAcl, &payload, &size))
+                if (OC_STACK_OK == AclToCBORPayload(gAcl, OIC_SEC_ACL_LATEST, &payload, &size))
                 {
                     if (UpdateSecureResourceInPS(OIC_JSON_ACL_NAME, payload, size) == OC_STACK_OK)
                     {
@@ -2838,7 +3121,7 @@ OCStackResult SetAclRownerId(const OicUuid_t* newROwner)
         memcpy(prevId.id, gAcl->rownerID.id, sizeof(prevId.id));
         memcpy(gAcl->rownerID.id, newROwner->id, sizeof(newROwner->id));
 
-        ret = AclToCBORPayload(gAcl, &cborPayload, &size);
+        ret = AclToCBORPayload(gAcl, OIC_SEC_ACL_LATEST, &cborPayload, &size);
         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
 
         ret = UpdateSecureResourceInPS(OIC_JSON_ACL_NAME, cborPayload, size);
diff --git a/resource/csdk/security/src/certhelpers.c b/resource/csdk/security/src/certhelpers.c
new file mode 100644 (file)
index 0000000..fe6f996
--- /dev/null
@@ -0,0 +1,614 @@
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft. All Rights Reserved.
+ *
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * *****************************************************************/
+
+#include "iotivity_config.h"
+
+#include "logger.h"
+#include <stddef.h>
+#include <string.h>
+#include <assert.h>
+#include "oic_malloc.h"
+#include "oic_string.h"
+#include "cacommon.h"
+#include "ocrandom.h"
+#include "cacommonutil.h"
+
+#include "ocpayload.h"
+#include "payload_logging.h"
+#include "pmutility.h"
+#include "srmutility.h"
+
+// headers required for mbed TLS
+#include "mbedtls/config.h"
+#include "mbedtls/platform.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/x509_csr.h"
+#include "mbedtls/x509_crt.h"
+#include "mbedtls/oid.h"
+
+#ifndef NDEBUG
+#include "mbedtls/debug.h"
+#include "mbedtls/version.h"
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+
+#include "certhelpers.h"
+
+#define TAG "OIC_CERTHELPERS"
+
+/**
+ * @def PERSONALIZATION_STRING
+ * @brief Personalization string for the mbedtls RNG
+ */
+#define PERSONALIZATION_STRING "IOTIVITY_RND"
+
+#define MAX_URI_QUERY MAX_URI_LENGTH + MAX_QUERY_LENGTH
+
+#define MAX_STRING_LEN 254
+
+#define MAX_ROLES_PER_CERT 10
+
+/* OID for role certificates (1.3.6.1.4.1.44924.1.7) suitable for mbedTLS check */
+static const char s_ekuRoleOid[] = MBEDTLS_OID_ISO_IDENTIFIED_ORG "\x06\x01\x04\x01\x82\xDE\x7C\x01\x07";
+
+/**
+ * Generates elliptic curve keypair.
+ *
+ * @param[out]  pk    mbedtls public key container
+ *
+ * @return  0 on success or <0 on error
+ */
+static int GenerateEccKeyPair(mbedtls_pk_context *pk)
+{
+    int ret = 0;
+    mbedtls_entropy_context entropy;
+    mbedtls_ctr_drbg_context ctr_drbg;
+
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
+    VERIFY_NON_NULL_RET(pk, TAG, "Param pk is NULL", -1);
+
+    // Initialize the DRBG context
+    mbedtls_ctr_drbg_init(&ctr_drbg);
+    mbedtls_entropy_init(&entropy);
+    ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
+                                &entropy, (const unsigned char *)PERSONALIZATION_STRING, sizeof(PERSONALIZATION_STRING));
+
+    if (0 > ret)
+    {
+        OIC_LOG_V(ERROR, TAG, "Seed initialization failed! %d", ret);
+        OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+        goto exit;
+    }
+    mbedtls_ctr_drbg_set_prediction_resistance(&ctr_drbg, MBEDTLS_CTR_DRBG_PR_ON);
+    ret = mbedtls_pk_setup(pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY));
+    if (0 > ret)
+    {
+        OIC_LOG_V(ERROR, TAG, "mbedtls_pk_setup error %d", ret);
+        OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+        goto exit;
+    }
+    ret = mbedtls_ecp_gen_key(MBEDTLS_ECP_DP_SECP256R1, mbedtls_pk_ec(*pk), mbedtls_ctr_drbg_random, &ctr_drbg);
+    if (0 > ret)
+    {
+        OIC_LOG(ERROR, TAG, "mbedtls_ecp_gen_keypair error");
+        OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+        goto exit;
+    }
+
+exit:
+
+    mbedtls_ctr_drbg_free(&ctr_drbg);
+    mbedtls_entropy_free(&entropy);
+
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+    return 0;
+}
+
+/**
+ * Generates certificate signing request for given key pair.
+ *
+ * @param[in]  subject        CSR Subject names should contain a comma-separated list of OID types and values:
+ *                            e.g. "C=UA,O=ABC,CN=uuid:32323232-3232-3232-3232-323232323232"
+ * @param[in]  key            Public/private key pair to generate for.
+ * @param[in]  encoding       Encoding to use; valid values are OIC_ENCODING_PEM and OIC_ENCODING_DER
+ * @param[out] csr            certificate signing request in the requested encoding
+ *
+ * @return  0 on success or <0 on error
+ */
+static int GenerateCSRForKey(const char *subject, mbedtls_pk_context* key, OicEncodingType_t encoding, OCByteString *csr)
+{
+    int ret = 0;
+    unsigned char buf[2048];
+    mbedtls_entropy_context entropy;
+    mbedtls_ctr_drbg_context ctr_drbg;
+    mbedtls_x509write_csr req;
+
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
+    VERIFY_NON_NULL_RET(subject, TAG, "Param subject is NULL", -1);
+    VERIFY_NON_NULL_RET(csr, TAG, "Param csr is NULL", -1);
+
+    if ((OIC_ENCODING_PEM != encoding) && (OIC_ENCODING_DER != encoding))
+    {
+        OIC_LOG(ERROR, TAG, "Unsupported encoding requested");
+        return -1;
+    }
+
+    // Initialize all data structures up front so the error path can always free them safely, no
+    // matter where the error exit point.
+    mbedtls_x509write_csr_init(&req);
+    mbedtls_ctr_drbg_init(&ctr_drbg);
+    mbedtls_entropy_init(&entropy);
+    csr->bytes = NULL;
+
+    // Initialize CSR context
+    // Set up MD algorithm, key and subject to CSR
+    mbedtls_x509write_csr_set_md_alg(&req, MBEDTLS_MD_SHA256);
+    mbedtls_x509write_csr_set_key(&req, key);
+    ret = mbedtls_x509write_csr_set_subject_name(&req, subject);
+    if (0 > ret)
+    {
+        OIC_LOG_V(ERROR, TAG, "mbedtls_x509write_csr_set_subject_name error %d", ret);
+        goto exit;
+    }
+
+    // Initialize the DRBG context
+    ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
+                                &entropy, (const unsigned char *)PERSONALIZATION_STRING, sizeof(PERSONALIZATION_STRING));
+    if (0 > ret)
+    {
+        OIC_LOG_V(ERROR, TAG, "Seed initialization failed! %d", ret);
+        goto exit;
+    }
+    mbedtls_ctr_drbg_set_prediction_resistance(&ctr_drbg, MBEDTLS_CTR_DRBG_PR_ON);
+
+    // Create CSR
+    if (OIC_ENCODING_PEM == encoding)
+    {
+        ret = mbedtls_x509write_csr_pem(&req, buf, sizeof(buf),
+                                        mbedtls_ctr_drbg_random, &ctr_drbg);
+
+        // In the PEM case, success is always denoted by a zero return. We have to compute the length.
+        if (0 != ret)
+        {
+            OIC_LOG_V(ERROR, TAG, "mbedtls_x509write_csr_pem error %d", ret);
+            goto exit;
+        }
+        else
+        {
+            csr->len = strlen((const char *)buf) + 1;
+            csr->bytes = (uint8_t *)OICMalloc(csr->len);
+            if (NULL == csr->bytes)
+            {
+                OIC_LOG(ERROR, TAG, "OICMalloc returned NULL on csr allocation");
+                ret = MBEDTLS_ERR_X509_ALLOC_FAILED;
+                goto exit;
+            }
+            memcpy(csr->bytes, buf, csr->len);
+        }
+    }
+    else // encoding == OIC_ENCODING_DER
+    {
+        ret = mbedtls_x509write_csr_der(&req, buf, sizeof(buf),
+                                        mbedtls_ctr_drbg_random, &ctr_drbg);
+
+        // In the DER case, ret is the number of bytes written.
+        if (0 > ret)
+        {
+            OIC_LOG_V(ERROR, TAG, "mbedtls_x509write_csr_der error %d", ret);
+            goto exit;
+        }
+        else
+        {
+            csr->len = ret;
+            csr->bytes = (uint8_t *)OICMalloc(csr->len);
+            if (NULL == csr->bytes)
+            {
+                OIC_LOG(ERROR, TAG, "OICMalloc returned NULL on csr allocation");
+                ret = MBEDTLS_ERR_X509_ALLOC_FAILED;
+                goto exit;
+            }
+            // DER data gets written to the end of the buffer.
+            memcpy(csr->bytes, buf + sizeof(buf) - csr->len, csr->len);
+            ret = 0;
+        }
+    }
+
+
+
+exit:
+
+    if (0 > ret)
+    {
+        OICFree(csr->bytes);
+        csr->bytes = NULL;
+        csr->len = 0;
+    }
+
+    mbedtls_entropy_free(&entropy);
+    mbedtls_ctr_drbg_free(&ctr_drbg);
+    mbedtls_x509write_csr_free(&req);
+
+    OICClearMemory(buf, sizeof(buf));
+
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+    return ret;
+}
+
+int OCInternalCSRRequest(const char *subject, mbedtls_pk_context *keyPair, OicEncodingType_t encoding, OCByteString *csr)
+{
+    return GenerateCSRForKey(subject, keyPair, encoding, csr);
+}
+
+int OCInternalGenerateKeyPair(mbedtls_pk_context *keyPair)
+{
+    return GenerateEccKeyPair(keyPair);
+}
+
+OCStackResult OCInternalIsValidRoleCertificate(const uint8_t *buf, size_t bufLen,
+                                               uint8_t **pubKey, size_t *pubKeyLen)
+{
+    OCStackResult res = OC_STACK_ERROR;
+    mbedtls_x509_crt parsedCert;
+
+    OIC_LOG(DEBUG, TAG, "OCInternalIsValidRoleCertificate IN");
+
+    mbedtls_x509_crt_init(&parsedCert);
+    int mbedRet = mbedtls_x509_crt_parse(&parsedCert, buf, bufLen);
+
+    if (0 > mbedRet)
+    {
+        OIC_LOG(ERROR, TAG, "Could not parse cert chain");
+        goto exit;
+    }
+
+    bool valid = false;
+    /* There should only be one certificate. */
+    if (NULL != parsedCert.next)
+    {
+        OIC_LOG(ERROR, TAG, "Expected only one certificate, but buffer contained more than one.");
+        res = OC_STACK_INVALID_PARAM;
+        goto exit;
+    }
+
+    /* We opt to require an EKU extension to be present; all-purposes certs are not allowed.
+     * mbedtls_x509_crt_check_extended_key_usage will return success if the EKU extension is absent,
+     * so we check this separately first.
+     */
+    if ((parsedCert.ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE) == 0)
+    {
+        OIC_LOG(ERROR, TAG, "EKU extension is absent. We require it to be present.");
+        res = OC_STACK_INVALID_PARAM;
+        goto exit;
+    }
+
+    /* The subject alternative name extension must also be present. */
+    if ((parsedCert.ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME) == 0)
+    {
+        OIC_LOG(ERROR, TAG, "Subject alternative name is absent, and is required in a role certificate.");
+        res = OC_STACK_INVALID_PARAM;
+        goto exit;
+    }
+
+    mbedRet = mbedtls_x509_crt_check_extended_key_usage(&parsedCert, s_ekuRoleOid, MBEDTLS_OID_SIZE(s_ekuRoleOid));
+    if (0 > mbedRet)
+    {
+        OIC_LOG_V(ERROR, TAG, "Role EKU is absent: %d", mbedRet);
+        res = OC_STACK_INVALID_PARAM;
+        goto exit;
+    }
+
+    valid = false;
+    /* Check for at least one subjAltName with a role in it. */
+    for (const mbedtls_x509_general_names *nameCur = &parsedCert.subject_alt_names; 
+            NULL != nameCur; 
+            nameCur = nameCur->next)
+    {
+        if (MBEDTLS_X509_GENERALNAME_DIRECTORYNAME == nameCur->general_name.name_type)
+        {
+            /* Name must contain a CN component. OU is optional. Anything else is ignored
+             * but not grounds for rejection.
+             */
+            for (const mbedtls_x509_name *dirName = nameCur->general_name.directory_name;
+                    NULL != dirName;
+                    dirName = dirName->next)
+            {
+                if ((MBEDTLS_OID_SIZE(MBEDTLS_OID_AT_CN) == dirName->oid.len) &&
+                    (0 == memcmp(MBEDTLS_OID_AT_CN, dirName->oid.p, MBEDTLS_OID_SIZE(MBEDTLS_OID_AT_CN))))
+                {
+                    if (dirName->val.len >= ROLEID_LENGTH)
+                    {
+                        OIC_LOG_V(ERROR, TAG, "Certificate has role id that is too long: %" PRIuPTR, dirName->val.len);
+                        res = OC_STACK_INVALID_PARAM;
+                        goto exit;
+                    }
+
+                    valid = true;
+                }
+                else if ((MBEDTLS_OID_SIZE(MBEDTLS_OID_AT_ORG_UNIT) == dirName->oid.len) &&
+                            (0 == memcmp(MBEDTLS_OID_AT_ORG_UNIT, dirName->oid.p, MBEDTLS_OID_SIZE(MBEDTLS_OID_AT_ORG_UNIT))))
+                {
+                    if (dirName->val.len >= ROLEAUTHORITY_LENGTH)
+                    {
+                        OIC_LOG_V(ERROR, TAG, "Certificate has role authority that is too long: %" PRIuPTR, dirName->val.len);
+                        res = OC_STACK_INVALID_PARAM;
+                        goto exit;
+                    }
+                    /* Presence of OU does not affect validity, so don't set valid flag. */
+                }
+                else
+                {
+                    OIC_LOG(WARNING, TAG, "Directory name has attribute that isn't CN or OU; ignoring");
+                }
+            }
+        }
+
+        if (valid)
+        {
+            break;
+        }
+    }
+
+    if (!valid)
+    {
+        OIC_LOG(ERROR, TAG, "Could not find valid role encoded in a subject alternative name");
+        res = OC_STACK_INVALID_PARAM;
+        goto exit;
+    }
+
+    /* If the public key is requested, extract it. */
+    if (NULL != pubKey)
+    {
+        unsigned char tmp[1024] = { 0 };
+        mbedRet = mbedtls_pk_write_pubkey_der(&parsedCert.pk, tmp, sizeof(tmp));
+        if (0 > mbedRet)
+        {
+            OIC_LOG_V(ERROR, TAG, "Could not write public key as DER: %d", mbedRet);
+            res = OC_STACK_ERROR;
+            goto exit;
+        }
+
+        /* mbedRet is the amount of data written, and it's written at the END of the buffer. */
+        *pubKey = (uint8_t *)OICCalloc(1, mbedRet);
+        if (NULL == *pubKey)
+        {
+            OIC_LOG(ERROR, TAG, "No memory allocating pubKey");
+            res = OC_STACK_NO_MEMORY;
+            goto exit;
+        }
+        memcpy(*pubKey, tmp + sizeof(tmp) - mbedRet, mbedRet);
+        *pubKeyLen = mbedRet;
+    }
+
+    res = OC_STACK_OK;
+
+exit:
+
+    mbedtls_x509_crt_free(&parsedCert);
+
+    OIC_LOG_V(DEBUG, TAG, "OCInternalIsValidRoleCertificate OUT; returning %d", res);
+    return res;
+}
+
+OCStackResult OCInternalIsValidCertChain(const uint8_t *buf, size_t bufLen)
+{
+    OCStackResult res = OC_STACK_ERROR;
+    int mbedRet;
+    mbedtls_x509_crt parsedCert;
+
+    OIC_LOG(DEBUG, TAG, "OCInternalIsValidCertChain IN");
+
+    mbedtls_x509_crt_init(&parsedCert);
+    mbedRet = mbedtls_x509_crt_parse(&parsedCert, buf, bufLen);
+    if (0 > mbedRet)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to parse certificate chain: %d", mbedRet);
+        res = OC_STACK_INVALID_PARAM;
+    }
+    else
+    {
+        res = OC_STACK_OK;
+        if (0 < mbedRet)
+        {
+            OIC_LOG_V(WARNING, TAG, "Partly successful: mbedTLS returned %d", mbedRet);
+        }
+    }
+
+    mbedtls_x509_crt_free(&parsedCert);
+
+    OIC_LOG_V(DEBUG, TAG, "OCInternalIsValidCertChain OUT; returning %d", res);
+
+    return res;
+}
+
+static const mbedtls_x509_crt_profile s_certProfile = {
+    MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256),            /* MD algorithms */
+    MBEDTLS_X509_ID_FLAG(MBEDTLS_PK_ECDSA),             /* Signature algorithms */
+    MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP256R1),     /* EC curves */
+    0                                                   /* RSA minimum key length - not used because we only use EC key pairs */
+};
+
+OCStackResult OCInternalVerifyRoleCertificate(const OicSecKey_t *certificate, const OicSecOpt_t *optData,
+                                              const uint8_t *trustedCaCerts, size_t trustedCaCertsLength,
+                                              OicSecRole_t **roles, size_t *rolesLength,
+                                              struct tm *notValidAfter)
+{
+    VERIFY_NOT_NULL_RETURN(TAG, certificate, ERROR, OC_STACK_INVALID_PARAM);
+    VERIFY_NOT_NULL_RETURN(TAG, trustedCaCerts, ERROR, OC_STACK_INVALID_PARAM);
+    VERIFY_NOT_NULL_RETURN(TAG, roles, ERROR, OC_STACK_INVALID_PARAM);
+    VERIFY_NOT_NULL_RETURN(TAG, rolesLength, ERROR, OC_STACK_INVALID_PARAM);
+    VERIFY_NOT_NULL_RETURN(TAG, notValidAfter, ERROR, OC_STACK_INVALID_PARAM);
+
+    OCStackResult res = OC_STACK_ERROR;
+    int mbedRet;
+    uint32_t flags = 0;
+    mbedtls_x509_crt certChain, trustedCas;
+
+    OicSecRole_t rolesTmp[MAX_ROLES_PER_CERT];
+    memset(rolesTmp, 0, sizeof(rolesTmp));
+    size_t rolesTmpCount = 0;
+
+    OIC_LOG(DEBUG, TAG, "OCInternalVerifyRoleCertificate IN");
+
+    mbedtls_x509_crt_init(&certChain);
+    mbedtls_x509_crt_init(&trustedCas);
+
+    res = OCInternalIsValidRoleCertificate(certificate->data, certificate->len, NULL, NULL);
+    if (OC_STACK_OK != res)
+    {
+        OIC_LOG_V(ERROR, TAG, "Certificate is not valid as a role certificate: %d", res);
+        goto exit;
+    }
+
+    mbedRet = mbedtls_x509_crt_parse(&certChain, certificate->data, certificate->len);
+    if (0 > mbedRet)
+    {
+        OIC_LOG_V(ERROR, TAG, "Could not parse certificate: %d", mbedRet);
+        res = OC_STACK_ERROR;
+        goto exit;
+    }
+
+    if (NULL != optData)
+    {
+        mbedRet = mbedtls_x509_crt_parse(&certChain, optData->data, optData->len);
+        if (0 > mbedRet)
+        {
+            OIC_LOG_V(ERROR, TAG, "Could not parse optional data: %d", mbedRet);
+            res = OC_STACK_ERROR;
+            goto exit;
+        }
+    }
+
+    mbedRet = mbedtls_x509_crt_parse(&trustedCas, trustedCaCerts, trustedCaCertsLength);
+    if (0 > mbedRet)
+    {
+        OIC_LOG_V(ERROR, TAG, "Could not parse trusted CA certs: %d", mbedRet);
+        res = OC_STACK_ERROR;
+        goto exit;
+    }
+
+    mbedRet = mbedtls_x509_crt_verify_with_profile(
+        &certChain,
+        &trustedCas,
+        NULL,
+        &s_certProfile,
+        NULL,
+        &flags,
+        NULL,
+        NULL);
+    if (0 > mbedRet)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to verify certificate: ret = %d, flags = %u", mbedRet, flags);
+        res = OC_STACK_INVALID_PARAM;
+        goto exit;
+    }
+
+    /* Certificate is verified. If requested, extract the list of roles and return.
+     * The first certificate in the certChain list is the leaf, since we parsed it first.
+     */
+    if (NULL != roles)
+    {
+        for (const mbedtls_x509_general_names *nameCur = &certChain.subject_alt_names;
+             (NULL != nameCur) && (rolesTmpCount < MAX_ROLES_PER_CERT);
+             nameCur = nameCur->next)
+        {
+            if (MBEDTLS_X509_GENERALNAME_DIRECTORYNAME == nameCur->general_name.name_type)
+            {
+                bool advanceCount = false;
+                for (const mbedtls_x509_name *dirName = nameCur->general_name.directory_name;
+                     NULL != dirName;
+                     dirName = dirName->next)
+                {
+                    if ((MBEDTLS_OID_SIZE(MBEDTLS_OID_AT_CN) == dirName->oid.len) &&
+                        (0 == memcmp(MBEDTLS_OID_AT_CN, dirName->oid.p, MBEDTLS_OID_SIZE(MBEDTLS_OID_AT_CN))))
+                    {
+                        /* When checking validity above, we made sure the role ID and authority were not too
+                         * long to fit in an OicSecRole_t. Here we only assert, but don't check again in release code.
+                         * id was also initialized as all zeroes, so string will automatically be null-terminated.
+                         */
+                        assert(dirName->val.len < ROLEID_LENGTH); 
+                        memcpy(rolesTmp[rolesTmpCount].id, dirName->val.p, dirName->val.len);
+                        advanceCount = true;
+                    }
+                    else if ((MBEDTLS_OID_SIZE(MBEDTLS_OID_AT_ORG_UNIT) == dirName->oid.len) &&
+                             (0 == memcmp(MBEDTLS_OID_AT_ORG_UNIT, dirName->oid.p, MBEDTLS_OID_SIZE(MBEDTLS_OID_AT_ORG_UNIT))))
+                    {
+                        assert(dirName->val.len < ROLEID_LENGTH); 
+                        memcpy(rolesTmp[rolesTmpCount].authority, dirName->val.p, dirName->val.len);
+                    }
+
+                }
+
+                if (advanceCount)
+                {
+                    rolesTmpCount++;
+                }
+            }
+        }
+
+        if (MAX_ROLES_PER_CERT <= rolesTmpCount)
+        {
+            OIC_LOG(ERROR, TAG, "More roles than supported in a single certificate");
+            res = OC_STACK_ERROR;
+            goto exit;
+        }
+        else if (0 == rolesTmpCount)
+        {
+            OIC_LOG(ERROR, TAG, "No roles in the certificate");
+            res = OC_STACK_ERROR;
+            goto exit;
+        }
+
+        *roles = (OicSecRole_t *)OICCalloc(1, sizeof(OicSecRole_t) * rolesTmpCount);
+        if (NULL == *roles)
+        {
+            OIC_LOG(ERROR, TAG, "No memory allocating roles array");
+            res = OC_STACK_NO_MEMORY;
+            goto exit;
+        }
+
+        memcpy(*roles, rolesTmp, sizeof(rolesTmp[0]) * rolesTmpCount);
+        *rolesLength = rolesTmpCount;
+    }
+
+    memset(notValidAfter, 0, sizeof(*notValidAfter));
+
+    notValidAfter->tm_year = certChain.valid_to.year - 1900;
+    notValidAfter->tm_mon = certChain.valid_to.mon - 1;
+    notValidAfter->tm_mday = certChain.valid_to.day;
+    notValidAfter->tm_hour = certChain.valid_to.hour;
+    notValidAfter->tm_min = certChain.valid_to.min;
+    notValidAfter->tm_sec = certChain.valid_to.sec;
+
+    res = OC_STACK_OK;
+
+exit:
+
+    mbedtls_x509_crt_free(&trustedCas);
+    mbedtls_x509_crt_free(&certChain);
+
+    OIC_LOG_V(DEBUG, TAG, "OCInternalVerifyRoleCertificate out: %d", res);
+
+    return res;
+}
\ No newline at end of file
index 81a4c42..c9ba13e 100755 (executable)
@@ -53,6 +53,8 @@
 #include "srmutility.h"
 #include "psinterface.h"
 #include "pinoxmcommon.h"
+#include "certhelpers.h"
+#include "cacommon.h"
 
 #ifdef __unix__
 #include <sys/types.h>
@@ -63,6 +65,9 @@
 
 #if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
 #include <mbedtls/ssl_ciphersuites.h>
+#include "mbedtls/pk.h"
+#include "mbedtls/base64.h"
+#include "mbedtls/pem.h"
 #endif
 
 #define TAG  "OIC_SRM_CREDL"
@@ -72,7 +77,6 @@
 #include <intsafe.h>
 #endif
 
-
 /** Max credential types number used for TLS */
 #define MAX_TYPE 2
 /** Default cbor payload size. This value is increased in case of CborErrorOutOfMemory.
@@ -384,7 +388,7 @@ static CborError SerializeEncodingToCborInternal(CborEncoder *map, const OicSecK
     return cborEncoderResult;
 }
 
-static CborError SerializeEncodingToCbor(CborEncoder *rootMap, const char* tag, const OicSecKey_t *value)
+CborError SerializeEncodingToCbor(CborEncoder *rootMap, const char* tag, const OicSecKey_t *value)
 {
     CborError cborEncoderResult = CborNoError;
     CborEncoder map;
@@ -406,7 +410,7 @@ static CborError SerializeEncodingToCbor(CborEncoder *rootMap, const char* tag,
     return cborEncoderResult;
 }
 
-static CborError SerializeSecOptToCbor(CborEncoder *rootMap, const char* tag, const OicSecOpt_t *value)
+CborError SerializeSecOptToCbor(CborEncoder *rootMap, const char* tag, const OicSecOpt_t *value)
 {
     CborError cborEncoderResult = CborNoError;
     CborEncoder map;
@@ -501,7 +505,7 @@ static CborError DeserializeEncodingFromCborInternal(CborValue *map, char *name,
     return cborFindResult;
 }
 
-static CborError DeserializeEncodingFromCbor(CborValue *rootMap, OicSecKey_t *value)
+CborError DeserializeEncodingFromCbor(CborValue *rootMap, OicSecKey_t *value)
 {
     CborValue map = { .parser = NULL };
     CborError cborFindResult = cbor_value_enter_container(rootMap, &map);
@@ -535,7 +539,7 @@ static CborError DeserializeEncodingFromCbor(CborValue *rootMap, OicSecKey_t *va
     return cborFindResult;
 }
 
-static CborError DeserializeSecOptFromCbor(CborValue *rootMap, OicSecOpt_t *value)
+CborError DeserializeSecOptFromCbor(CborValue *rootMap, OicSecOpt_t *value)
 {
     CborValue map = { .parser = NULL };
     CborError cborFindResult = cbor_value_enter_container(rootMap, &map);
@@ -581,9 +585,57 @@ static CborError DeserializeSecOptFromCbor(CborValue *rootMap, OicSecOpt_t *valu
     return cborFindResult;
 }
 
+/* Produce debugging output for all credentials, output metadata. */
+static void logCredMetadata()
+{
+#if defined(TB_LOG)
+    OicSecCred_t * temp = NULL;
+    size_t count = 0;
+    char uuidString[UUID_STRING_SIZE];
+    OicUuid_t ownUuid;
+
+    OIC_LOG_V(DEBUG, TAG, "IN %s:", __func__);
+
+    if (GetDoxmDeviceID(&ownUuid) == OC_STACK_OK && OCConvertUuidToString(ownUuid.id, uuidString))
+    {
+        OIC_LOG_V(DEBUG, TAG, "Own UUID: %s", uuidString);
+    }
+
+    LL_FOREACH(gCred, temp)
+    {
+        count++;
+        OIC_LOG(DEBUG, TAG, " ");
+        OIC_LOG_V(DEBUG, TAG, "Cred ID: %d", temp->credId);
+        if (OCConvertUuidToString(temp->subject.id, uuidString))
+        {
+            OIC_LOG_V(DEBUG, TAG, "Subject UUID: %s", uuidString);
+        }
+        OIC_LOG_V(DEBUG, TAG, "Cred Type: %d", temp->credType);
+        OIC_LOG_V(DEBUG, TAG, "privateData length: %d, encoding: %d", temp->privateData.len, temp->privateData.encoding);
+
+#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
+        OIC_LOG_V(DEBUG, TAG, "publicData length: %d, encoding: %d", temp->publicData.len, temp->publicData.encoding);           
+        if (temp->credUsage)
+        {
+            OIC_LOG_V(DEBUG, TAG, "credUsage: %s", temp->credUsage);
+        }
+
+        OIC_LOG_V(DEBUG, TAG, "optionalData length: %d, encoding: %d", temp->optionalData.len, temp->optionalData.encoding);
+#endif
+
+    }
+
+    OIC_LOG_V(DEBUG, TAG, "Found %d credentials.", count);
+
+    OIC_LOG_V(DEBUG, TAG, "OUT %s:", __func__);
+#endif
+}
+
+
 OCStackResult CredToCBORPayload(const OicSecCred_t *credS, uint8_t **cborPayload,
                                 size_t *cborSize, int secureFlag)
 {
+    OIC_LOG_V(DEBUG, TAG, "IN %s:", __func__);
     if (NULL == credS || NULL == cborPayload || NULL != *cborPayload || NULL == cborSize)
     {
         return OC_STACK_INVALID_PARAM;
@@ -642,7 +694,8 @@ OCStackResult CredToCBORPayload(const OicSecCred_t *credS, uint8_t **cborPayload
         }
 #endif //MULTIPLE_OWNER
 
-        if (SIGNED_ASYMMETRIC_KEY == cred->credType && cred->publicData.data)
+        if ((SIGNED_ASYMMETRIC_KEY == cred->credType || ASYMMETRIC_KEY == cred->credType) 
+            && cred->publicData.data)
         {
             mapSize++;
         }
@@ -700,7 +753,8 @@ OCStackResult CredToCBORPayload(const OicSecCred_t *credS, uint8_t **cborPayload
 
 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
         //PublicData -- Not Mandatory
-        if (SIGNED_ASYMMETRIC_KEY == cred->credType && cred->publicData.data)
+        if ((SIGNED_ASYMMETRIC_KEY == cred->credType || ASYMMETRIC_KEY == cred->credType) 
+            && cred->publicData.data)
         {
             cborEncoderResult = SerializeEncodingToCbor(&credMap,
                                          OIC_JSON_PUBLICDATA_NAME, &cred->publicData);
@@ -850,6 +904,8 @@ exit:
         ret = OC_STACK_ERROR;
     }
 
+    OIC_LOG_V(DEBUG, TAG, "OUT %s:", __func__);
+
     return ret;
 }
 
@@ -983,14 +1039,6 @@ OCStackResult CBORPayloadToCred(const uint8_t *cborPayload, size_t size,
                             {
                                 cborFindResult = DeserializeEncodingFromCbor(&credMap, &cred->privateData);
                                 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed to read privateData structure");
-
-                                OicEncodingType_t encoding = cred->privateData.encoding;
-                                if (OIC_ENCODING_DER == encoding || OIC_ENCODING_PEM == encoding)
-                                {
-                                    //For unit test
-                                    cred->privateData.encoding = OIC_ENCODING_RAW;
-                                    OIC_LOG(WARNING, TAG, "Unknown encoding type detected for private data.");
-                                }
                             }
 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
                             //PublicData -- Not Mandatory
@@ -1157,6 +1205,7 @@ OicSecCred_t * GenerateCredential(const OicUuid_t * subject, OicSecCredType_t cr
         VERIFY_NOT_NULL(TAG, cred->publicData.data, ERROR);
         memcpy(cred->publicData.data, publicData->data, publicData->len);
         cred->publicData.len = publicData->len;
+        cred->publicData.encoding = publicData->encoding;
     }
 #endif // __WITH_DTLS__
 
@@ -1166,7 +1215,7 @@ OicSecCred_t * GenerateCredential(const OicUuid_t * subject, OicSecCredType_t cr
         VERIFY_NOT_NULL(TAG, cred->privateData.data, ERROR);
         memcpy(cred->privateData.data, privateData->data, privateData->len);
         cred->privateData.len = privateData->len;
-        cred->privateData.encoding = OIC_ENCODING_RAW;
+        cred->privateData.encoding = privateData->encoding;
     }
 
     VERIFY_NOT_NULL(TAG, rownerID, ERROR);
@@ -1346,6 +1395,9 @@ static bool UpdatePersistentStorage(const OicSecCred_t *cred)
     }
 
     OIC_LOG(DEBUG, TAG, "OUT Cred UpdatePersistentStorage");
+
+    logCredMetadata();
+
     return ret;
 }
 
@@ -2110,7 +2162,7 @@ static OCEntityHandlerResult HandlePostRequest(OCEntityHandlerRequest * ehReques
 #endif//__WITH_DTLS__
     }
 
-    if (OC_EH_CHANGED != ret)
+    if (OC_EH_CHANGED != ret && cred != NULL)
     {
         if(OC_STACK_OK != RemoveCredential(&cred->subject))
         {
@@ -2452,15 +2504,16 @@ OicSecCred_t* GetCredEntryByCredId(const uint16_t credId)
                 cred->privateData.encoding = tmpCred->privateData.encoding;
             }
 #if defined(__WITH_X509__) || defined(__WITH_TLS__)
-            else if (tmpCred->publicData.data)
+            if (tmpCred->publicData.data)
             {
                 cred->publicData.data = (uint8_t *)OICCalloc(1, tmpCred->publicData.len);
                 VERIFY_NOT_NULL(TAG, cred->publicData.data, ERROR);
 
                 memcpy(cred->publicData.data, tmpCred->publicData.data, tmpCred->publicData.len);
                 cred->publicData.len = tmpCred->publicData.len;
+                cred->publicData.encoding = tmpCred->publicData.encoding;
             }
-            else if (tmpCred->optionalData.data)
+            if (tmpCred->optionalData.data)
             {
                 cred->optionalData.data = (uint8_t *)OICCalloc(1, tmpCred->optionalData.len);
                 VERIFY_NOT_NULL(TAG, cred->optionalData.data, ERROR);
@@ -2470,7 +2523,6 @@ OicSecCred_t* GetCredEntryByCredId(const uint16_t credId)
                 cred->optionalData.encoding = tmpCred->optionalData.encoding;
                 cred->optionalData.revstat= tmpCred->optionalData.revstat;
             }
-
             if (tmpCred->credUsage)
             {
                 cred->credUsage = OICStrdup(tmpCred->credUsage);
@@ -2798,59 +2850,198 @@ OCStackResult GetCredRownerId(OicUuid_t *rowneruuid)
 }
 
 #if defined (__WITH_TLS__) || defined(__WITH_DTLS__)
-void GetDerCaCert(ByteArray_t * crt, const char * usage)
+/* Caller must call OICFree on *der when finished. */
+static int ConvertPemCertToDer(const char *pem, size_t pemLen, uint8_t** der, size_t* derLen)
+{
+    size_t bufSize = B64DECODE_OUT_SAFESIZE(pemLen + 1);
+    uint8_t *buf = OICCalloc(1, bufSize);
+    if (NULL == buf)
+    {
+        OIC_LOG(ERROR, TAG, "Failed to allocate memory");
+        return -1;
+    }
+    size_t outSize = 0;
+    if (B64_OK != b64Decode(pem, pemLen, buf, bufSize, &outSize))
+    {
+        OICFree(buf);
+        OIC_LOG(ERROR, TAG, "Failed to decode base64 data");
+        return -1;
+    }
+
+    *der = buf;
+    *derLen = outSize;
+
+    return 0;
+}
+
+/* Caller must call OICFree on *pem when finished. */
+static int ConvertDerCertToPem(const uint8_t* der, size_t derLen, uint8_t** pem)
+{
+    const char* pemHeader = "-----BEGIN CERTIFICATE-----\n";
+    const char* pemFooter = "-----END CERTIFICATE-----\n";
+
+    /* Get the length required for output*/
+    size_t pemLen;
+    int ret = mbedtls_pem_write_buffer(pemHeader, 
+        pemFooter,
+        der,
+        derLen,
+        NULL,
+        0,
+        &pemLen);
+    if (ret != MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL)
+    {
+        OIC_LOG_V(ERROR, TAG, "Couldn't convert cert into PEM, failed getting required length: %d", ret);
+        return ret;
+    }
+
+    *pem = OICCalloc(1, pemLen + 1);
+    if (*pem == NULL)
+    {
+        OIC_LOG(ERROR, TAG, "Failed to allocate memory for PEM cert");
+        return ret;
+    }
+
+    /* Try the conversion */
+    ret = mbedtls_pem_write_buffer(pemHeader, pemFooter,
+        der,
+        derLen,
+        *pem,
+        pemLen,
+        &pemLen);
+    if (ret < 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "Couldn't convert cert into PEM, failed getting required length: %d", ret);
+        OICFreeAndSetToNull(pem);
+        return ret;
+    }
+
+    return 0;
+}
+
+static OCStackResult GetCaCert(ByteArray_t * crt, const char * usage, OicEncodingType_t desiredEncoding)
 {
     OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
     if (NULL == crt || NULL == usage)
     {
         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
-        return;
+        return OC_STACK_INVALID_PARAM;
+    }
+    
+    switch (desiredEncoding)
+    {
+    case OIC_ENCODING_PEM:
+    case OIC_ENCODING_DER:
+    case OIC_ENCODING_BASE64:
+        break;
+    default:
+        OIC_LOG_V(ERROR, TAG, "%s: Unsupported encoding %d", __func__, desiredEncoding);
+        return OC_STACK_INVALID_PARAM;
     }
+    
     crt->len = 0;
     OicSecCred_t* temp = NULL;
 
     LL_FOREACH(gCred, temp)
     {
         if ((SIGNED_ASYMMETRIC_KEY == temp->credType) &&
+            (temp->credUsage != NULL) &&
             (0 == strcmp(temp->credUsage, usage)) && (false == temp->optionalData.revstat))
         {
-            if(OIC_ENCODING_BASE64 == temp->optionalData.encoding)
+            if (OIC_ENCODING_DER == desiredEncoding)
             {
-                size_t bufSize = B64DECODE_OUT_SAFESIZE((temp->optionalData.len + 1));
-                uint8_t * buf = OICCalloc(1, bufSize);
-                if(NULL == buf)
+                if ((OIC_ENCODING_BASE64 == temp->optionalData.encoding) ||
+                    (OIC_ENCODING_PEM == temp->optionalData.encoding))
                 {
-                    OIC_LOG(ERROR, TAG, "Failed to allocate memory");
-                    return;
+                    uint8_t *buf = NULL;
+                    size_t outSize = 0;
+                    int ret = ConvertPemCertToDer((const char *)temp->optionalData.data, temp->optionalData.len, &buf, &outSize);
+                    if (0 > ret)
+                    {
+                        OIC_LOG(ERROR, TAG, "Could not convert PEM cert to DER");
+                        return OC_STACK_ERROR;
+                    }
+
+                    uint8_t *savePtr = crt->data;
+                    crt->data = OICRealloc(crt->data, crt->len + outSize);
+                    if (NULL == crt->data)
+                    {
+                        OIC_LOG(ERROR, TAG, "No memory reallocating crt->data");
+                        OICFree(savePtr);
+                        OICFree(buf);
+                        return OC_STACK_NO_MEMORY;
+                    }
+                    memcpy(crt->data + crt->len, buf, outSize);
+                    crt->len += outSize;
+                    OICFree(buf);
                 }
-                size_t outSize;
-                if(B64_OK != b64Decode((char*)(temp->optionalData.data),
-                                       temp->optionalData.len, buf, bufSize, &outSize))
+                else
                 {
-                    OICFree(buf);
-                    OIC_LOG(ERROR, TAG, "Failed to decode base64 data");
-                    return;
+                    uint8_t *savePtr = crt->data;
+                    crt->data = OICRealloc(crt->data, crt->len + temp->optionalData.len);
+                    if (NULL == crt->data)
+                    {
+                        OIC_LOG(ERROR, TAG, "No memory reallocating crt->data");
+                        OICFree(savePtr);
+                        return OC_STACK_NO_MEMORY;
+                    }
+                    memcpy(crt->data + crt->len, temp->optionalData.data, temp->optionalData.len);
+                    crt->len += temp->optionalData.len;
                 }
-                crt->data = OICRealloc(crt->data, crt->len + outSize);
-                memcpy(crt->data + crt->len, buf, outSize);
-                crt->len += outSize;
-                OICFree(buf);
+                OIC_LOG_V(DEBUG, TAG, "%s found", usage);
             }
             else
             {
+                /* PEM/Base64 */
+                uint8_t *pem = NULL;
+                size_t pemLen = 0;
+                if ((OIC_ENCODING_BASE64 == temp->optionalData.encoding) ||
+                    (OIC_ENCODING_PEM == temp->optionalData.encoding))
+                {
+                    pem = temp->optionalData.data;
+                    pemLen = temp->optionalData.len;
+                }
+                else
+                {
+                    int ret = ConvertDerCertToPem(temp->optionalData.data, temp->optionalData.len, &pem);
+                    if (0 > ret)
+                    {
+                        OIC_LOG_V(ERROR, TAG, "Failed converting DER cert to PEM: %d", ret);
+                        return OC_STACK_ERROR;
+                    }
+                    pemLen = strlen((char *)pem) + 1;
+                }
+
+                uint8_t *oldData = crt->data;
                 crt->data = OICRealloc(crt->data, crt->len + temp->optionalData.len);
+                if (NULL == crt->data)
+                {
+                    OIC_LOG(ERROR, TAG, "No memory reallocating crt->data");
+                    OICFree(oldData);
+                    return OC_STACK_NO_MEMORY;
+                }
                 memcpy(crt->data + crt->len, temp->optionalData.data, temp->optionalData.len);
                 crt->len += temp->optionalData.len;
             }
-            OIC_LOG_V(DEBUG, TAG, "%s found", usage);
         }
     }
     if(0 == crt->len)
     {
         OIC_LOG_V(WARNING, TAG, "%s not found", usage);
+        return OC_STACK_NO_RESOURCE;
     }
     OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
-    return;
+    return OC_STACK_OK;
+}
+
+void GetDerCaCert(ByteArray_t * crt, const char * usage)
+{
+    (void)GetCaCert(crt, usage, OIC_ENCODING_DER);
+}
+
+OCStackResult GetPemCaCert(ByteArray_t * crt, const char * usage)
+{
+    return GetCaCert(crt, usage, OIC_ENCODING_PEM);
 }
 
 void GetDerOwnCert(ByteArray_t * crt, const char * usage)
@@ -2866,6 +3057,7 @@ void GetDerOwnCert(ByteArray_t * crt, const char * usage)
     LL_FOREACH(gCred, temp)
     {
         if (SIGNED_ASYMMETRIC_KEY == temp->credType &&
+            temp->credUsage != NULL &&
             0 == strcmp(temp->credUsage, usage))
         {
             crt->data = OICRealloc(crt->data, crt->len + temp->publicData.len);
@@ -2895,13 +3087,59 @@ void GetDerKey(ByteArray_t * key, const char * usage)
     key->len = 0;
     LL_FOREACH(gCred, temp)
     {
-        if (SIGNED_ASYMMETRIC_KEY == temp->credType &&
+        if ((SIGNED_ASYMMETRIC_KEY == temp->credType || ASYMMETRIC_KEY == temp->credType) && 
+            NULL != temp->credUsage &&
             0 == strcmp(temp->credUsage, usage))
         {
-            key->data = OICRealloc(key->data, key->len + temp->privateData.len);
-            memcpy(key->data + key->len, temp->privateData.data, temp->privateData.len);
-            key->len += temp->privateData.len;
-            OIC_LOG_V(DEBUG, TAG, "Key for %s found", usage);
+            
+            if (temp->privateData.encoding == OIC_ENCODING_PEM)
+            {
+                /* Convert PEM to DER */
+                mbedtls_pk_context ctx;
+                mbedtls_pk_init(&ctx);
+
+                int ret = mbedtls_pk_parse_key(&ctx, temp->privateData.data, temp->privateData.len, NULL, 0);
+                if (ret != 0)
+                {
+                    mbedtls_pk_free(&ctx);
+                    OIC_LOG_V(ERROR, TAG, "Key for %s found, but failed to convert from PEM to DER (while reading PEM)", usage);
+                    return;
+                }
+
+                key->data = OICRealloc(key->data, key->len + temp->privateData.len);
+                if (key->data == NULL)
+                {
+                    mbedtls_pk_free(&ctx);
+                    OIC_LOG(ERROR, TAG, "Realloc failed to increase key->data length");
+                    return;
+                }
+
+                key->len += temp->privateData.len;
+                ret = mbedtls_pk_write_key_der(&ctx, key->data, key->len);
+                if (ret < 1) /* return value is the number of bytes written, or error */
+                {
+                    mbedtls_pk_free(&ctx);
+                    key->len = 0;
+                    OIC_LOG_V(ERROR, TAG, "Key for %s found, but failed to convert from PEM to DER (while writing DER)", usage);
+                    return;
+                }
+                key->data = OICRealloc(key->data, ret);
+                key->len = ret;
+                break;
+                
+            }
+            else if(temp->privateData.encoding == OIC_ENCODING_DER)
+            {
+                key->data = OICRealloc(key->data, key->len + temp->privateData.len);
+                memcpy(key->data + key->len, temp->privateData.data, temp->privateData.len);
+                key->len += temp->privateData.len;
+                OIC_LOG_V(DEBUG, TAG, "Key for %s found", usage);
+                break;
+            }
+            else
+            {
+                OIC_LOG_V(WARNING, TAG, "Key for %s found, but it has an unknown encoding", usage);
+            }
         }
     }
     if(0 == key->len)
@@ -2939,7 +3177,7 @@ void InitCipherSuiteListInternal(bool * list, const char * usage)
             }
             case SIGNED_ASYMMETRIC_KEY:
             {
-                if (0 == strcmp(temp->credUsage, usage))
+                if (NULL != temp->credUsage && 0 == strcmp(temp->credUsage, usage))
                 {
                     list[1] = true;
                     OIC_LOG_V(DEBUG, TAG, "SIGNED_ASYMMETRIC_KEY found for %s", usage);
diff --git a/resource/csdk/security/src/csrresource.c b/resource/csdk/security/src/csrresource.c
new file mode 100644 (file)
index 0000000..b1105b9
--- /dev/null
@@ -0,0 +1,528 @@
+//******************************************************************
+//
+// Copyright 2017 Microsoft
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//******************************************************************
+
+#include "iotivity_config.h"
+#include <stdlib.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#include <stdint.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include "oic_string.h"
+#include "cainterface.h"
+#include "payload_logging.h"
+#include "ocstack.h"
+#include "ocrandom.h"
+#include "cacommon.h"
+#include "srmresourcestrings.h"
+#include "ocpayload.h"
+#include "ocpayloadcbor.h"
+#include "credresource.h"
+#include "doxmresource.h"
+#include "srmutility.h"
+#include "certhelpers.h"
+#include "csrresource.h"
+#include "resourcemanager.h"
+
+#define TAG  "OIC_SRM_CSR"
+
+static OCResourceHandle    gCsrHandle = NULL;
+
+/** Default cbor payload size. This value is increased in case of CborErrorOutOfMemory.
+ * The value of payload size is increased until reaching belox max cbor size.
+ */
+static const uint16_t CBOR_SIZE = 2048;
+
+static const char* EncodingValueToString(OicEncodingType_t encoding)
+{
+    switch (encoding)
+    {
+    case OIC_ENCODING_RAW:    return OIC_SEC_ENCODING_RAW;
+    case OIC_ENCODING_BASE64: return OIC_SEC_ENCODING_BASE64;
+    case OIC_ENCODING_DER:    return OIC_SEC_ENCODING_DER;
+    case OIC_ENCODING_PEM:    return OIC_SEC_ENCODING_PEM;
+    default:                  return NULL;
+    }
+}
+
+
+static OCStackResult StoreKeyPair(mbedtls_pk_context *keyPair, const OicUuid_t *myUuid)
+{
+    int ret = 0;
+    OicSecCred_t *cred = NULL;
+    OicSecKey_t publicData;
+    OicSecKey_t privateData;
+    uint8_t publicBuf[1024];
+    uint8_t privateBuf[1024];
+
+    /* These DER writing APIs write at the END of the buffers, hence the pointer arithmetic. See the API
+     * documentation for mbedTLS.
+     */
+
+    ret = mbedtls_pk_write_pubkey_der(keyPair, publicBuf, sizeof(publicBuf));
+    VERIFY_SUCCESS(TAG, 0 <= ret, ERROR);
+    publicData.data = publicBuf + sizeof(publicBuf) - ret;
+    publicData.len = ret;
+    publicData.encoding = OIC_ENCODING_DER;
+
+    ret = mbedtls_pk_write_key_der(keyPair, privateBuf, sizeof(privateBuf));
+    VERIFY_SUCCESS(TAG, 0 <= ret, ERROR);
+    privateData.data = privateBuf + sizeof(privateBuf) - ret;
+    privateData.len = ret;
+    privateData.encoding = OIC_ENCODING_DER;
+
+    cred = GenerateCredential(myUuid, ASYMMETRIC_KEY, &publicData, &privateData, myUuid, NULL);
+    VERIFY_NOT_NULL(TAG, cred, ERROR);
+    cred->credUsage = OICStrdup(PRIMARY_KEY); // @todo: we may be able to use PRIMARY_CERT here too; need to investigate
+    VERIFY_NOT_NULL(TAG, cred->credUsage, ERROR);
+
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == AddCredential(cred), ERROR);
+
+    return OC_STACK_OK;
+
+exit:
+
+    if (NULL != cred)
+    {
+        DeleteCredList(cred);
+    }
+
+    OICClearMemory(privateBuf, sizeof(privateBuf));
+
+    return OC_STACK_ERROR;
+}
+
+static OCStackResult CSRToCBORPayload(const uint8_t *csr, size_t csrLen, OicEncodingType_t encoding, uint8_t **cborPayload, size_t *cborSize)
+{
+    OCStackResult ret = OC_STACK_ERROR;
+
+    CborError cborEncoderResult = CborNoError;
+    uint8_t *outPayload = NULL;
+    size_t cborLen = *cborSize;
+    CborEncoder encoder;
+    CborEncoder csrRootMap;
+    const char *strEncoding = NULL;
+
+    if ((NULL == csr) || (0 == csrLen) || (NULL == cborPayload) || (NULL == cborSize))
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    if ((OIC_ENCODING_DER != encoding) && (OIC_ENCODING_PEM != encoding))
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    *cborSize = 0;
+    *cborPayload = NULL;
+
+    if (0 == cborLen)
+    {
+        cborLen = CBOR_SIZE;
+    }
+
+    outPayload = (uint8_t *)OICCalloc(1, cborLen);
+    VERIFY_NOT_NULL_RETURN(TAG, outPayload, ERROR, OC_STACK_NO_MEMORY);
+    cbor_encoder_init(&encoder, outPayload, cborLen, 0);
+
+    // Create CSR Root Map (csr)
+    cborEncoderResult = cbor_encoder_create_map(&encoder, &csrRootMap, 4);
+    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding CSR Root Map");
+
+    // Create CSR string entry
+    cborEncoderResult = cbor_encode_text_string(&csrRootMap, OIC_JSON_CSR_NAME, strlen(OIC_JSON_CSR_NAME));
+    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding CSR name.");
+    cborEncoderResult = cbor_encode_byte_string(&csrRootMap, csr, csrLen);
+    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding CSR value.");
+
+    // Create encoding entry
+    cborEncoderResult = cbor_encode_text_string(&csrRootMap, OIC_JSON_ENCODING_NAME, strlen(OIC_JSON_ENCODING_NAME));
+    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding encoding name.");
+    strEncoding = EncodingValueToString(encoding);
+    assert(strEncoding != NULL);
+    cborEncoderResult = cbor_encode_text_string(&csrRootMap, strEncoding, strlen(strEncoding));
+    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding encoding value.");
+
+    // Rownerid
+    {
+        char *rowner = NULL;
+        OicUuid_t myUuid;
+        cborEncoderResult = cbor_encode_text_string(&csrRootMap, OIC_JSON_ROWNERID_NAME,
+            strlen(OIC_JSON_ROWNERID_NAME));
+        VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding rownerid Name.");
+        ret = GetDoxmDeviceID(&myUuid);
+        VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
+        ret = ConvertUuidToStr(&myUuid, &rowner);
+        VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
+        cborEncoderResult = cbor_encode_text_string(&csrRootMap, rowner, strlen(rowner));
+        OICFree(rowner);
+        VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding rownerid Value.");
+    }
+
+    //RT -- Mandatory
+    CborEncoder rtArray;
+    cborEncoderResult = cbor_encode_text_string(&csrRootMap, OIC_JSON_RT_NAME,
+        strlen(OIC_JSON_RT_NAME));
+    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding RT Name Tag.");
+    cborEncoderResult = cbor_encoder_create_array(&csrRootMap, &rtArray, 1);
+    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding RT Value.");
+    for (size_t i = 0; i < 1; i++)
+    {
+        cborEncoderResult = cbor_encode_text_string(&rtArray, OIC_RSRC_TYPE_SEC_CSR,
+            strlen(OIC_RSRC_TYPE_SEC_CSR));
+        VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding RT Value.");
+    }
+    cborEncoderResult = cbor_encoder_close_container(&csrRootMap, &rtArray);
+    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing RT.");
+
+    //IF-- Mandatory
+    CborEncoder ifArray;
+    cborEncoderResult = cbor_encode_text_string(&csrRootMap, OIC_JSON_IF_NAME,
+        strlen(OIC_JSON_IF_NAME));
+    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding IF Name Tag.");
+    cborEncoderResult = cbor_encoder_create_array(&csrRootMap, &ifArray, 1);
+    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding IF Value.");
+    for (size_t i = 0; i < 1; i++)
+    {
+        cborEncoderResult = cbor_encode_text_string(&ifArray, OC_RSRVD_INTERFACE_DEFAULT,
+            strlen(OC_RSRVD_INTERFACE_DEFAULT));
+        VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding IF Value.");
+    }
+    cborEncoderResult = cbor_encoder_close_container(&csrRootMap, &ifArray);
+    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing IF.");
+
+    // Close CSR Map
+    cborEncoderResult = cbor_encoder_close_container(&encoder, &csrRootMap);
+    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing CSR root Map.");
+
+    if (CborNoError == cborEncoderResult)
+    {
+        OIC_LOG(DEBUG, TAG, "CSRToCBORPayload Succeeded");
+        *cborSize = cbor_encoder_get_buffer_size(&encoder, outPayload);
+        *cborPayload = outPayload;
+        ret = OC_STACK_OK;
+    }
+exit:
+    if (CborErrorOutOfMemory == cborEncoderResult)
+    {
+        OIC_LOG(DEBUG, TAG, "CSRToCBORPayload:CborErrorOutOfMemory : retry with more memory");
+
+        // reallocate and try again!
+        OICFree(outPayload);
+        // Since the allocated initial memory failed, double the memory.
+        cborLen += cbor_encoder_get_buffer_size(&encoder, encoder.end);
+        cborEncoderResult = CborNoError;
+        ret = CSRToCBORPayload(csr, csrLen, encoding, cborPayload, &cborLen);
+        *cborSize = cborLen;
+    }
+    else if (cborEncoderResult != CborNoError)
+    {
+        OIC_LOG(ERROR, TAG, "Failed to CSRToCBORPayload");
+        OICFree(outPayload);
+        outPayload = NULL;
+        *cborSize = 0;
+        *cborPayload = NULL;
+        ret = OC_STACK_ERROR;
+    }
+
+    return ret;
+}
+
+OCStackResult CBORPayloadToCSR(const uint8_t *cborPayload, size_t size, uint8_t **csr, size_t *csrLen, OicEncodingType_t *encoding)
+{
+    if (NULL == cborPayload || 0 == size || NULL == csr || NULL == csrLen)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    OCStackResult ret = OC_STACK_ERROR;
+    CborValue csrCbor = { .parser = NULL };
+    CborParser parser = { .end = NULL };
+    CborError cborFindResult = CborNoError;
+    uint8_t* cborCsr = NULL;
+    size_t cborCsrLen = 0;
+    char* tagName = NULL;
+    size_t len = 0;
+
+    cborFindResult = cbor_parser_init(cborPayload, size, 0, &parser, &csrCbor);
+    VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed to initialize parser.");
+
+    if (!cbor_value_is_container(&csrCbor))
+    {
+        return OC_STACK_ERROR;
+    }
+
+    // Enter CSR Root Map
+    CborValue csrRootMap = { .parser = NULL, .ptr = NULL, .remaining = 0, .extra = 0, .type = 0, .flags = 0 };
+    cborFindResult = cbor_value_enter_container(&csrCbor, &csrRootMap);
+    VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Entering CSR Root Map.");
+
+    while (cbor_value_is_valid(&csrRootMap))
+    {
+        if (NULL != tagName)
+        {
+            free(tagName);
+            tagName = NULL;
+        }
+        len = 0;
+        CborType type = cbor_value_get_type(&csrRootMap);
+        if (type == CborTextStringType && cbor_value_is_text_string(&csrRootMap))
+        {
+            cborFindResult = cbor_value_dup_text_string(&csrRootMap, &tagName, &len, NULL);
+            VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed finding name in CSR Root Map.");
+            cborFindResult = cbor_value_advance(&csrRootMap);
+            VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed advancing value in CSR Root Map.");
+        }
+        if (NULL != tagName)
+        {
+            if (strcmp(tagName, OIC_JSON_CSR_NAME) == 0 && cbor_value_is_byte_string(&csrRootMap))
+            {
+                cborFindResult = cbor_value_dup_byte_string(&csrRootMap, &cborCsr, &cborCsrLen, NULL);
+                VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed finding name in CSR Map");
+                // Use our own heap allocator and copy the result in so callers can use OICFree.
+                *csr = (uint8_t *)OICCalloc(1, cborCsrLen);
+                VERIFY_NOT_NULL(TAG, *csr, ERROR);
+                memcpy(*csr, cborCsr, cborCsrLen);
+                free(cborCsr);
+                cborCsr = NULL;
+                *csrLen = cborCsrLen;
+                cborCsrLen = 0;
+            }
+            else if (strcmp(tagName, OIC_JSON_ENCODING_NAME) == 0 && cbor_value_is_text_string(&csrRootMap))
+            {
+                char *strEncoding = NULL;
+                cborFindResult = cbor_value_dup_text_string(&csrRootMap, &strEncoding, &len, NULL);
+                VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed finding encoding type");
+
+                if (strcmp(strEncoding, OIC_SEC_ENCODING_DER) == 0)
+                {
+                    *encoding = OIC_ENCODING_DER;
+                }
+                else if (strcmp(strEncoding, OIC_SEC_ENCODING_PEM) == 0)
+                {
+                    *encoding = OIC_ENCODING_PEM;
+                }
+                else
+                {
+                    OIC_LOG_V(ERROR, TAG, "Invalid encoding type %s", strEncoding);
+                    ret = OC_STACK_ERROR;
+                    free(strEncoding);
+                    goto exit;
+                }
+
+                free(strEncoding);
+            }
+            else
+            {
+                // Ignore any other tag type for now.
+                OIC_LOG_V(WARNING, TAG, "Unknown tag %s", tagName);
+            }
+
+        }
+        if (cbor_value_is_valid(&csrRootMap))
+        {
+            cborFindResult = cbor_value_advance(&csrRootMap);
+            VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed advancing CSR Root Map");
+        }
+    }
+
+    ret = OC_STACK_OK;
+
+exit:
+    if (CborNoError != cborFindResult)
+    {
+        if (NULL != *csr)
+        {
+            OICFreeAndSetToNull((void **)csr);
+        }
+
+        *csrLen = 0;
+
+        ret = OC_STACK_ERROR;
+    }
+
+    // tagName and cborCsr are both allocated internally by tinycbor, which uses malloc, not OICMalloc.
+    // Therefore, they must be freed with free, not OICFree.
+    if (NULL != tagName)
+    {
+        free(tagName);
+    }
+    if (NULL != cborCsr)
+    {
+        free(cborCsr);
+    }
+
+    return ret;
+
+}
+
+static OCEntityHandlerResult HandleCsrGetRequest(OCEntityHandlerRequest * ehRequest)
+{
+    OCStackResult res = OC_STACK_OK;
+    OCEntityHandlerResult ehRet = OC_EH_OK;
+    int ret = 0;
+    mbedtls_pk_context keyPair;
+    OicUuid_t myUuid;
+    char *myUuidStr = NULL;
+    char *myDNStr = NULL;
+    size_t myDNStrLen = 0;
+    ByteArray_t keyData = { .data = NULL, .len = 0 };
+    OCByteString csr = { .bytes = NULL, .len = 0 };
+    size_t size = 0;
+    uint8_t *payload = NULL;
+
+    OIC_LOG(INFO, TAG, "HandleCsrGetRequest  processing GET request");
+
+    mbedtls_pk_init(&keyPair);
+
+    // Retrieve our current certificate, if we have one, and use that key
+    GetDerKey(&keyData, PRIMARY_CERT);
+
+    if (0 == keyData.len)
+    {
+        // No cert? Get our primary key pair, or generate it if absent.
+        GetDerKey(&keyData, PRIMARY_KEY);
+    }
+
+    res = GetDoxmDeviceID(&myUuid);
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);
+    res = ConvertUuidToStr(&myUuid, &myUuidStr);
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);
+
+    if (0 < keyData.len)
+    {
+        ret = mbedtls_pk_parse_key(&keyPair, keyData.data, keyData.len, NULL, 0);
+        if (0 > ret)
+        {
+            res = OC_STACK_ERROR;
+            // Because we need to set res before failing out, this is a redundant check of ret, but gives better logging.
+            VERIFY_SUCCESS(TAG, 0 <= ret, ERROR);
+        }
+    }
+    else
+    {
+        ret = OCInternalGenerateKeyPair(&keyPair);
+        if (0 > ret)
+        {
+            res = OC_STACK_ERROR;
+            VERIFY_SUCCESS(TAG, 0 <= ret, ERROR);
+        }
+        VERIFY_SUCCESS(TAG, OC_STACK_OK == (res = StoreKeyPair(&keyPair, &myUuid)), ERROR);
+    }
+
+    // Generate CSR
+    myDNStrLen = strlen(myUuidStr) + sizeof(SUBJECT_PREFIX); // sizeof(SUBJECT_PREFIX) will also count the byte for terminating null.
+    myDNStr = (char *)OICMalloc(myDNStrLen);
+    VERIFY_NOT_NULL(TAG, myDNStr, ERROR);
+    ret = snprintf(myDNStr, myDNStrLen, SUBJECT_PREFIX "%s", myUuidStr);
+    VERIFY_SUCCESS(TAG, 0 <= ret, ERROR);
+    /* ret >= myDNStrLen means there was truncation; assert because this means a code bug. */
+    assert((size_t)ret < myDNStrLen);
+    ret = OCInternalCSRRequest(myDNStr, &keyPair, OIC_ENCODING_DER, &csr);
+    if (0 > ret)
+    {
+        res = OC_STACK_ERROR;
+        VERIFY_SUCCESS(TAG, 0 <= ret, ERROR);
+    }
+
+    // Convert CSR data into CBOR for transmission
+    res = CSRToCBORPayload(csr.bytes, csr.len, OIC_ENCODING_DER, &payload, &size);
+
+exit:
+
+    ehRet = (OC_STACK_OK == res) ? OC_EH_OK : OC_EH_ERROR;
+
+    //Send payload to request originator
+    ehRet = ((SendSRMResponse(ehRequest, ehRet, payload, size)) == OC_STACK_OK) ?
+                       OC_EH_OK : OC_EH_ERROR;
+
+    mbedtls_pk_free(&keyPair);
+    OICFree(myDNStr);
+    OICFree(myUuidStr);
+    OICFree(keyData.data);
+    OICFree(csr.bytes);
+    OICFree(payload);
+    return ehRet;
+}
+
+static OCEntityHandlerResult CredCsrEntityHandler(OCEntityHandlerFlag flag,
+                                                  OCEntityHandlerRequest * ehRequest,
+                                                  void* callbackParameter)
+{
+    OC_UNUSED(callbackParameter);
+    OCEntityHandlerResult ret = OC_EH_ERROR;
+
+    if (!ehRequest)
+    {
+        return OC_EH_ERROR;
+    }
+
+    if (flag & OC_REQUEST_FLAG)
+    {
+        OIC_LOG(DEBUG, TAG, "Flag includes OC_REQUEST_FLAG");
+        if (ehRequest->method == OC_REST_GET)
+        {
+            ret = HandleCsrGetRequest(ehRequest);
+        }
+        else
+        {
+            /* Only GET supported on CSR resource. */
+            ret = OC_EH_ERROR;
+        }
+    }
+
+    return ret;
+}
+
+OCStackResult InitCSRResource()
+{
+    OCStackResult ret = OCCreateResource(&gCsrHandle,
+        OIC_RSRC_TYPE_SEC_CSR,
+        OC_RSRVD_INTERFACE_DEFAULT,
+        OIC_RSRC_CSR_URI,
+        CredCsrEntityHandler,
+        NULL,
+        OC_SECURE);
+
+    if (OC_STACK_OK != ret)
+    {
+        OIC_LOG(FATAL, TAG, "Unable to instantiate CSR resource");
+    }
+
+    return ret;
+}
+
+OCStackResult DeInitCSRResource()
+{
+    OCStackResult res = OCDeleteResource(gCsrHandle);
+
+    if (OC_STACK_OK != res)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to delete CSR resource: %d", res);
+    }
+
+    gCsrHandle = NULL;
+
+    return res;
+}
\ No newline at end of file
index 92d9fe3..7d6495c 100644 (file)
@@ -897,11 +897,12 @@ void MultipleOwnerDTLSHandshakeCB(const CAEndpoint_t *object,
 
     if(CA_STATUS_OK == errorInfo->result)
     {
-        const CASecureEndpoint_t* authenticatedSubOwnerInfo = CAGetSecureEndpointData(object);
-        if(authenticatedSubOwnerInfo)
+        CASecureEndpoint_t authenticationSubOwnerInfo;
+        CAResult_t caRes = CAGetSecureEndpointData(object, &authenticationSubOwnerInfo);
+        if (CA_STATUS_OK == caRes)
         {
-            if (0 == memcmp(authenticatedSubOwnerInfo->identity.id, gDoxm->owner.id,
-                            authenticatedSubOwnerInfo->identity.id_length))
+            if (0 == memcmp(authenticationSubOwnerInfo.identity.id, gDoxm->owner.id,
+                            authenticationSubOwnerInfo.identity.id_length))
             {
                 OIC_LOG(WARNING, TAG, "Super owner tried MOT, this request will be ignored.");
                 return;
@@ -911,8 +912,8 @@ void MultipleOwnerDTLSHandshakeCB(const CAEndpoint_t *object,
             LL_FOREACH(gDoxm->subOwners, subOwnerInst)
             {
                 if(0 == memcmp(subOwnerInst->uuid.id,
-                               authenticatedSubOwnerInfo->identity.id,
-                               authenticatedSubOwnerInfo->identity.id_length))
+                               authenticationSubOwnerInfo.identity.id,
+                               authenticationSubOwnerInfo.identity.id_length))
                 {
                     break;
                 }
@@ -924,8 +925,8 @@ void MultipleOwnerDTLSHandshakeCB(const CAEndpoint_t *object,
                 if(subOwnerInst)
                 {
                     char* strUuid = NULL;
-                    memcpy(subOwnerInst->uuid.id, authenticatedSubOwnerInfo->identity.id,
-                           authenticatedSubOwnerInfo->identity.id_length);
+                    memcpy(subOwnerInst->uuid.id, authenticationSubOwnerInfo.identity.id,
+                           authenticationSubOwnerInfo.identity.id_length);
                     if(OC_STACK_OK != ConvertUuidToStr(&subOwnerInst->uuid, &strUuid))
                     {
                         OIC_LOG(ERROR, TAG, "Failed to allocate memory.");
@@ -941,6 +942,10 @@ void MultipleOwnerDTLSHandshakeCB(const CAEndpoint_t *object,
                 }
             }
         }
+        else
+        {
+            OIC_LOG_V(ERROR, TAG, "Could not CAGetSecureEndpointData: %d", caRes);
+        }
     }
 
     if(CA_STATUS_OK != CAregisterPskCredentialsHandler(GetDtlsPskCredentials))
index 631fa63..1de78f5 100644 (file)
@@ -573,6 +573,7 @@ static OCEntityHandlerResult HandleDpairingPutRequest (const OCEntityHandlerRequ
 
             LL_APPEND(acl->aces, ace);
 
+            ace->subjectType = OicSecAceUuidSubject;
             memcpy(&ace->subjectuuid, &gDpair->pdeviceID, sizeof(OicUuid_t));
 
             for(size_t i = 0; i < pdAcl->resourcesLen; i++)
@@ -632,7 +633,7 @@ static OCEntityHandlerResult HandleDpairingPutRequest (const OCEntityHandlerRequ
 
             size_t size = 0;
             uint8_t *payload = NULL;
-            if (OC_STACK_OK == AclToCBORPayload(acl, &payload, &size))
+            if (OC_STACK_OK == AclToCBORPayload(acl, OIC_SEC_ACL_V1, &payload, &size))
             {
                 AppendACL(payload, size);
                 OICFree(payload);
diff --git a/resource/csdk/security/src/occertutility.c b/resource/csdk/security/src/occertutility.c
new file mode 100644 (file)
index 0000000..2f8665a
--- /dev/null
@@ -0,0 +1,828 @@
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft. All Rights Reserved.
+ *
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * *****************************************************************/
+
+#if defined(__WITH_TLS__) || defined(__WITH_DTLS__)
+
+#include "iotivity_config.h"
+
+#include "logger.h"
+#include <stddef.h>
+#include <string.h>
+#include <assert.h>
+#include "oic_malloc.h"
+#include "oic_string.h"
+#include "cacommon.h"
+#include "ocrandom.h"
+#include "cacommonutil.h"
+
+#include "ocpayload.h"
+#include "payload_logging.h"
+#include "pmutility.h"
+#include "srmutility.h"
+
+// headers required for mbed TLS
+#include "mbedtls/config.h"
+#include "mbedtls/platform.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/x509_csr.h"
+#include "mbedtls/oid.h"
+#include "mbedtls/x509_crt.h"
+#include "mbedtls/oid.h"
+#include "mbedtls/pem.h"
+#include "mbedtls/base64.h"
+
+#ifndef NDEBUG
+#include "mbedtls/debug.h"
+#include "mbedtls/version.h"
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+
+#include "certhelpers.h"
+#include "occertutility.h"
+
+#define TAG "OIC_OCCERTUTILITY"
+
+/**
+ * @def PERSONALIZATION_STRING
+ * @brief Personalization string for the mbedtls RNG
+ */
+#define PERSONALIZATION_STRING "IOTIVITY_RND"
+
+#define MAX_URI_QUERY MAX_URI_LENGTH + MAX_QUERY_LENGTH
+
+#define MAX_STRING_LEN 254
+
+/* ASN.1 DER encoding of the EKU for identity certificates (1.3.6.1.4.1.44924.1.6) */
+static const unsigned char s_ekuIdentity[] = { 0x30, 0x0C, 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0xDE, 0x7C, 0x01, 0x06 };
+
+/* ASN.1 DER encoding of the EKU for role certificates (1.3.6.1.4.1.44924.1.7) */
+static const unsigned char s_ekuRole[] = { 0x30, 0x0C, 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0xDE, 0x7C, 0x01, 0x07 };
+
+/* ASN.1 DER encoding of the EKU for both identity and roles (for use by CAs) */
+static const unsigned char s_ekuCA[] = { 0x30, 0x18, 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0xDE, 0x7C, 0x01, 0x06, 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0xDE, 0x7C, 0x01, 0x07 };
+
+/**
+ * Generates elliptic curve keypair.
+ *
+ * @param[out]  pk    mbedtls public key container
+ *
+ * @return  0 on success or <0 on error
+ */
+static int GenerateEccKeyPair(mbedtls_pk_context *pk)
+{
+    int ret = 0;
+    mbedtls_entropy_context entropy;
+    mbedtls_ctr_drbg_context ctr_drbg;
+
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
+    VERIFY_NON_NULL_RET(pk, TAG, "Param pk is NULL", -1);
+
+    // Initialize the DRBG context
+    mbedtls_ctr_drbg_init(&ctr_drbg);
+    mbedtls_entropy_init(&entropy);
+    ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
+                                &entropy, (const unsigned char *)PERSONALIZATION_STRING, sizeof(PERSONALIZATION_STRING));
+
+    if (0 > ret)
+    {
+        OIC_LOG_V(ERROR, TAG, "Seed initialization failed! %d", ret);
+        OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+        goto exit;
+    }
+    mbedtls_ctr_drbg_set_prediction_resistance(&ctr_drbg, MBEDTLS_CTR_DRBG_PR_ON);
+    ret = mbedtls_pk_setup(pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY));
+    if (0 > ret)
+    {
+        OIC_LOG_V(ERROR, TAG, "mbedtls_pk_setup error %d", ret);
+        OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+        goto exit;
+    }
+    ret = mbedtls_ecp_gen_key(MBEDTLS_ECP_DP_SECP256R1, mbedtls_pk_ec(*pk), mbedtls_ctr_drbg_random, &ctr_drbg);
+    if (0 > ret)
+    {
+        OIC_LOG(ERROR, TAG, "mbedtls_ecp_gen_keypair error");
+        OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+        goto exit;
+    }
+
+exit:
+
+    mbedtls_ctr_drbg_free(&ctr_drbg);
+    mbedtls_entropy_free(&entropy);
+
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+    return 0;
+}
+
+OCStackResult OCGenerateRandomSerialNumber(char **serial, size_t *serialLen)
+{
+    int ret = 0;
+    OCStackResult res = OC_STACK_ERROR;
+    unsigned char random[20]; /* Per RFC 5280, 20 octets is the maximum length of a serial number. */
+    mbedtls_mpi serialMpi;
+
+    VERIFY_NOT_NULL_RETURN(TAG, serial, ERROR, OC_STACK_INVALID_PARAM);
+    VERIFY_NOT_NULL_RETURN(TAG, serialLen, ERROR, OC_STACK_INVALID_PARAM);
+
+    mbedtls_mpi_init(&serialMpi);
+    memset(serial, 0, sizeof(*serial));
+
+    VERIFY_SUCCESS(TAG, OCGetRandomBytes(random, sizeof(random)), ERROR);
+
+    /* Per RFC 5280, 20 octets is the maximum length of a serial number. In ASN.1, if the highest-order
+     * bit is set it causes a padding octet to be written, which would be 21 and non-compliant. 
+     * Therefore, always clear the highest-order bit. Integers in ASN.1 are always big-Endian.
+     */
+    random[0] &= 0x7F;
+
+    /* Import into a large integer object and then output as a string. */
+    ret = mbedtls_mpi_read_binary(&serialMpi, random, sizeof(random));
+    VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+
+    /* Get the needed string length and allocate. */
+    ret = mbedtls_mpi_write_string(&serialMpi, 10, NULL, 0, serialLen);
+    VERIFY_SUCCESS(TAG, ret == MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL, ERROR);
+    *serial = OICCalloc(1, *serialLen);
+    VERIFY_NOT_NULL(TAG, *serial, ERROR);
+
+    /* Do the write for real. */
+    ret = mbedtls_mpi_write_string(&serialMpi, 10, *serial, *serialLen, serialLen);
+    VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+
+    res = OC_STACK_OK;
+
+exit:
+
+    if (OC_STACK_OK != res)
+    {
+        OICFree(*serial);
+        *serial = NULL;
+        *serialLen = 0;
+    }
+    mbedtls_mpi_free(&serialMpi);
+
+    return res;
+}
+
+OCStackResult OCGenerateKeyPair(char **publicKey, size_t *publicKeyLen,
+                                char **privateKey, size_t *privateKeyLen)
+{
+    int ret = 0;
+    mbedtls_pk_context keyPair;
+    unsigned char buf[2048];
+
+    mbedtls_pk_init(&keyPair);
+
+    VERIFY_NOT_NULL_RETURN(TAG, publicKey, ERROR, OC_STACK_INVALID_PARAM);
+    VERIFY_NOT_NULL_RETURN(TAG, publicKeyLen, ERROR, OC_STACK_INVALID_PARAM);
+    VERIFY_NOT_NULL_RETURN(TAG, privateKey, ERROR, OC_STACK_INVALID_PARAM);
+    VERIFY_NOT_NULL_RETURN(TAG, privateKeyLen, ERROR, OC_STACK_INVALID_PARAM);
+
+    *publicKey = NULL;
+    *publicKeyLen = 0;
+    *privateKey = NULL;
+    *privateKeyLen = 0;
+
+    ret = OCInternalGenerateKeyPair(&keyPair);
+    if (ret != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to generate key pair: %d", ret);
+        goto exit;
+    }
+
+    ret = mbedtls_pk_write_pubkey_pem(&keyPair, buf, sizeof(buf));
+    if (ret != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to export public key as PEM: %d", ret);
+        goto exit;
+    }
+
+    *publicKeyLen = strlen((char *)buf) + 1;
+    *publicKey = OICCalloc(1, *publicKeyLen);
+    if (NULL == *publicKey)
+    {
+        OIC_LOG(ERROR, TAG, "Could not allocate memory for public key");
+        ret = -1;
+        goto exit;
+    }
+    memcpy(*publicKey, buf, *publicKeyLen);
+
+    ret = mbedtls_pk_write_key_pem(&keyPair, buf, sizeof(buf));
+    if (ret != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to export private key as PEM: %d", ret);
+        goto exit;
+    }
+
+    *privateKeyLen = strlen((char *)buf) + 1;
+    *privateKey = OICCalloc(1, *privateKeyLen);
+    if (NULL == *privateKey)
+    {
+        OIC_LOG(ERROR, TAG, "Could not allocate memory for private key");
+        ret = -1;
+        goto exit;
+    }
+    memcpy(*privateKey, buf, *privateKeyLen);
+
+exit:
+
+    mbedtls_pk_free(&keyPair);
+
+    OICClearMemory(buf, sizeof(buf));
+
+    if (ret != 0)
+    {
+        OICFree(*publicKey);
+        OICClearMemory(*privateKey, *privateKeyLen);
+        OICFree(*privateKey);
+
+        *publicKey = NULL;
+        *publicKeyLen = 0;
+        *privateKey = NULL;
+        *privateKeyLen = 0;
+
+        return OC_STACK_ERROR;
+    }
+    else
+    {
+        return OC_STACK_OK;
+    }
+}
+
+typedef enum {
+    CERT_TYPE_CA,
+    CERT_TYPE_IDENTITY,
+    CERT_TYPE_ROLE
+} CertificateType_t;
+
+static OCStackResult GenerateCertificate(
+    CertificateType_t certType,
+    const char *subject,
+    const char *subjectPublicKey,
+    const char *issuerCert,
+    const char *issuerPrivateKey,
+    const char *serial,
+    const char *notValidBefore,
+    const char *notValidAfter,
+    const char *role,
+    const char *authority,
+    OCByteString *certificate)
+{
+    OCStackResult res = OC_STACK_INVALID_PARAM;
+    int ret = 0;
+    mbedtls_x509write_cert outCertCtx;
+    mbedtls_pk_context subjKeyCtx;
+    mbedtls_pk_context issKeyCtx;
+    mbedtls_x509_crt issCertCtx;
+    mbedtls_mpi serialMpi;
+    mbedtls_x509_general_names names;
+    mbedtls_entropy_context entropy;
+    mbedtls_ctr_drbg_context ctr_drbg;
+
+    char buf[2048];
+
+    if (NULL == subjectPublicKey || NULL == issuerPrivateKey || NULL == subject || NULL == serial ||
+        NULL == notValidBefore || NULL == notValidAfter)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    mbedtls_x509write_crt_init(&outCertCtx);
+    mbedtls_pk_init(&subjKeyCtx);
+    mbedtls_pk_init(&issKeyCtx);
+    mbedtls_x509_crt_init(&issCertCtx);
+    mbedtls_mpi_init(&serialMpi);
+    memset(&names, 0, sizeof(names));
+    mbedtls_ctr_drbg_init(&ctr_drbg);
+    mbedtls_entropy_init(&entropy);
+    memset(certificate, 0, sizeof(*certificate));
+
+    ret = mbedtls_mpi_read_string(&serialMpi, 10, serial);
+    VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+
+    ret = mbedtls_pk_parse_public_key(&subjKeyCtx, (const uint8_t *)subjectPublicKey, strlen(subjectPublicKey) + 1);
+    VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+
+    ret = mbedtls_pk_parse_key(&issKeyCtx, (const uint8_t *)issuerPrivateKey, strlen(issuerPrivateKey) + 1, NULL, 0);
+    VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+
+    /* If issuerCert is NULL, then the cert will be self-signed. */
+    if (NULL != issuerCert)
+    {
+        ret = mbedtls_x509_crt_parse(&issCertCtx, (const uint8_t *)issuerCert, strlen(issuerCert) + 1);
+        VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+    }
+
+    ret = mbedtls_x509write_crt_set_validity(&outCertCtx, notValidBefore, notValidAfter);
+    VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+
+    mbedtls_x509write_crt_set_version(&outCertCtx, MBEDTLS_X509_CRT_VERSION_3);
+    mbedtls_x509write_crt_set_md_alg(&outCertCtx, MBEDTLS_MD_SHA256);
+
+    res = OC_STACK_ERROR;
+
+    ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
+        &entropy, (const uint8_t *)PERSONALIZATION_STRING, sizeof(PERSONALIZATION_STRING));
+    VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+    mbedtls_ctr_drbg_set_prediction_resistance(&ctr_drbg, MBEDTLS_CTR_DRBG_PR_ON);
+
+    ret = mbedtls_x509write_crt_set_serial(&outCertCtx, &serialMpi);
+    VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+
+    ret = mbedtls_x509write_crt_set_subject_name(&outCertCtx, subject);
+    VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+
+    if (NULL != issuerCert)
+    {
+        // mbedtls_x509_dn_gets returns the number of bytes written to buf.
+        ret = mbedtls_x509_dn_gets(buf, sizeof(buf), &issCertCtx.subject);
+        VERIFY_SUCCESS(TAG, 0 < ret, ERROR);
+        ret = mbedtls_x509write_crt_set_issuer_name(&outCertCtx, buf);
+    }
+    else
+    {
+        /* If self-signed, use the same contents of subject for the issuer name. */
+        ret = mbedtls_x509write_crt_set_issuer_name(&outCertCtx, subject);
+    }
+    VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+
+    mbedtls_x509write_crt_set_subject_key(&outCertCtx, &subjKeyCtx);
+
+    mbedtls_x509write_crt_set_issuer_key(&outCertCtx, &issKeyCtx);
+
+    if (certType == CERT_TYPE_CA)
+    {
+        ret = mbedtls_x509write_crt_set_basic_constraints(&outCertCtx, 1, -1);
+        VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+        ret = mbedtls_x509write_crt_set_key_usage(&outCertCtx, 
+            MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_KEY_CERT_SIGN);
+        VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+    }
+    else
+    {
+        ret = mbedtls_x509write_crt_set_basic_constraints(&outCertCtx, 0, 0);
+        VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+        ret = mbedtls_x509write_crt_set_key_usage(&outCertCtx,
+            MBEDTLS_X509_KU_DIGITAL_SIGNATURE |
+            MBEDTLS_X509_KU_KEY_ENCIPHERMENT |
+            MBEDTLS_X509_KU_DATA_ENCIPHERMENT |
+            MBEDTLS_X509_KU_KEY_AGREEMENT);
+        VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+    }
+    
+    switch (certType)
+    {
+    case CERT_TYPE_ROLE:
+        ret = mbedtls_x509write_crt_set_extension(&outCertCtx,
+            MBEDTLS_OID_EXTENDED_KEY_USAGE, MBEDTLS_OID_SIZE(MBEDTLS_OID_EXTENDED_KEY_USAGE),
+            0,
+            s_ekuRole, sizeof(s_ekuRole));
+        VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+        ret = snprintf(buf, sizeof(buf), "CN=%s%s%s", role, (NULL != authority) ? ",OU=" : "", (NULL != authority) ? authority : "");
+        VERIFY_SUCCESS(TAG, ret < sizeof(buf), ERROR);
+        names.next = NULL;
+        names.general_name.name_type = MBEDTLS_X509_GENERALNAME_DIRECTORYNAME;
+        ret = mbedtls_x509_string_to_names(&names.general_name.directory_name, buf);
+        VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+
+        ret = mbedtls_x509write_crt_set_subject_alt_names(&outCertCtx, &names);
+        VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+        break;
+
+    case CERT_TYPE_IDENTITY:
+        ret = mbedtls_x509write_crt_set_extension(&outCertCtx,
+            MBEDTLS_OID_EXTENDED_KEY_USAGE, MBEDTLS_OID_SIZE(MBEDTLS_OID_EXTENDED_KEY_USAGE),
+            0,
+            s_ekuIdentity, sizeof(s_ekuIdentity));
+        VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+        break;
+
+    case CERT_TYPE_CA:
+        ret = mbedtls_x509write_crt_set_extension(&outCertCtx,
+            MBEDTLS_OID_EXTENDED_KEY_USAGE, MBEDTLS_OID_SIZE(MBEDTLS_OID_EXTENDED_KEY_USAGE),
+            0,
+            s_ekuCA, sizeof(s_ekuCA));
+        VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+        break;
+
+    default:
+        assert(false);
+        VERIFY_SUCCESS(TAG, false, ERROR);
+    }
+
+    ret = mbedtls_x509write_crt_pem(&outCertCtx, (uint8_t *)buf, sizeof(buf), mbedtls_ctr_drbg_random, &ctr_drbg);
+    VERIFY_SUCCESS(TAG, 0 == ret, ERROR);
+
+    certificate->len = strlen(buf) + 1;
+    certificate->bytes = (uint8_t *)OICCalloc(1, certificate->len);
+    VERIFY_NOT_NULL(TAG, certificate->bytes, ERROR);
+    memcpy(certificate->bytes, buf, certificate->len);
+
+    res = OC_STACK_OK;
+
+exit:
+
+    if (OC_STACK_OK != res)
+    {
+        OICFree(certificate->bytes);
+        certificate->bytes = NULL;
+        certificate->len = 0;
+    }
+
+    mbedtls_ctr_drbg_free(&ctr_drbg);
+    mbedtls_entropy_free(&entropy);
+    mbedtls_asn1_free_named_data_list(&names.general_name.directory_name);
+    mbedtls_mpi_free(&serialMpi);
+    mbedtls_x509_crt_free(&issCertCtx);
+    mbedtls_pk_free(&issKeyCtx);
+    mbedtls_pk_free(&subjKeyCtx);
+    mbedtls_x509write_crt_free(&outCertCtx);
+
+    return res;
+}
+
+OCStackResult OCGenerateCACertificate(
+    const char *subject,
+    const char *subjectPublicKey,
+    const char *issuerCert,
+    const char *issuerPrivateKey,
+    const char *serial,
+    const char *notValidBefore,
+    const char *notValidAfter,
+    char **certificate,
+    size_t *certificateLen)
+{
+    OCStackResult res = OC_STACK_OK;
+    OCByteString byteStr = { 0 };
+    
+    res = GenerateCertificate(
+        CERT_TYPE_CA,
+        subject,
+        subjectPublicKey,
+        issuerCert,
+        issuerPrivateKey,
+        serial,
+        notValidBefore,
+        notValidAfter,
+        NULL,
+        NULL,
+        &byteStr);
+
+    if (OC_STACK_OK == res)
+    {
+        *certificate = (char *)byteStr.bytes;
+        *certificateLen = byteStr.len;
+    }
+
+    return res;
+}
+
+OCStackResult OCGenerateIdentityCertificate(
+    const OicUuid_t *subjectUuid,
+    const char *subjectPublicKey,
+    const char *issuerCert,
+    const char *issuerPrivateKey,
+    const char *serial,
+    const char *notValidBefore,
+    const char *notValidAfter,
+    char **certificate,
+    size_t *certificateLen)
+{
+    OCStackResult res = OC_STACK_OK;
+    OCByteString byteStr = { 0 };
+    char uuidStr[UUID_STRING_SIZE] = { 0 } ;
+    char subject[sizeof(uuidStr) + sizeof(SUBJECT_PREFIX)] = { 0 } ;
+
+    if (NULL == issuerCert)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    if (!OCConvertUuidToString(subjectUuid->id, uuidStr))
+    {
+        OIC_LOG(ERROR, TAG, "Could not convert UUID");
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    if (snprintf(subject, sizeof(subject), "%s%s", SUBJECT_PREFIX, uuidStr) == sizeof(subject))
+    {
+        OIC_LOG(ERROR, TAG, "Could not write subject string");
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    res = GenerateCertificate(
+        CERT_TYPE_IDENTITY,
+        subject,
+        subjectPublicKey,
+        issuerCert,
+        issuerPrivateKey,
+        serial,
+        notValidBefore,
+        notValidAfter,
+        NULL,
+        NULL,
+        &byteStr);
+
+    if (OC_STACK_OK == res)
+    {
+        *certificate = (char *)byteStr.bytes;
+        *certificateLen = byteStr.len;
+    }
+
+    return res;
+}
+
+OCStackResult OCGenerateRoleCertificate(
+    const OicUuid_t *subjectUuid,
+    const char *subjectPublicKey,
+    const char *issuerCert,
+    const char *issuerPrivateKey,
+    const char *serial,
+    const char *notValidBefore,
+    const char *notValidAfter,
+    const char *role,
+    const char *authority,
+    char **certificate,
+    size_t *certificateLen)
+{
+    OCStackResult res = OC_STACK_ERROR;
+    OCByteString byteStr;
+    char uuidStr[UUID_STRING_SIZE] = { 0 };
+    char subject[sizeof(uuidStr) + sizeof(SUBJECT_PREFIX)] = { 0 };
+
+    memset(&byteStr, 0, sizeof(byteStr));
+
+    if (NULL == role || NULL == issuerCert)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    if (!OCConvertUuidToString(subjectUuid->id, uuidStr))
+    {
+        OIC_LOG(ERROR, TAG, "Could not convert UUID");
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    if (snprintf(subject, sizeof(subject), "%s%s", SUBJECT_PREFIX, uuidStr) == sizeof(subject))
+    {
+        OIC_LOG(ERROR, TAG, "Could not write subject string");
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    res = GenerateCertificate(
+        CERT_TYPE_ROLE,
+        subject,
+        subjectPublicKey,
+        issuerCert,
+        issuerPrivateKey,
+        serial,
+        notValidBefore,
+        notValidAfter,
+        role,
+        authority,
+        &byteStr);
+
+    if (OC_STACK_OK == res)
+    {
+        *certificate = (char *)byteStr.bytes;
+        *certificateLen = byteStr.len;
+    }
+
+    return res;
+}
+
+
+/* Verify the signature in a CSR is valid. */
+static int VerifyCSRSignature(mbedtls_x509_csr* csr)
+{
+    unsigned char hash[MBEDTLS_MD_MAX_SIZE];
+
+    if (csr->sig_md != MBEDTLS_MD_SHA256)
+    {
+        OIC_LOG(ERROR, TAG, "Unexpected digest used in CSR\n");
+        return -1;
+    }
+
+    if ((csr->cri.len == 0) || (csr->cri.p == NULL))
+    {
+        OIC_LOG(ERROR, TAG, "Missing CertificateRequestInfo field in CSR\n");
+        return -1;
+    }
+
+    if ((csr->sig.len == 0) || (csr->sig.p == NULL))
+    {
+        OIC_LOG(ERROR, TAG, "Missing signature field in CSR\n");
+        return -1;
+    }
+
+    if (MBEDTLS_OID_CMP(MBEDTLS_OID_ECDSA_SHA256, &csr->sig_oid) != 0)
+    {
+        char buf[256];
+        if (mbedtls_oid_get_numeric_string(buf, sizeof(buf), &csr->sig_oid) > 0)
+        {
+            OIC_LOG_V(ERROR, TAG, "Unexpected signature OID in CSR (got %s)\n", buf);
+        }
+        else
+        {
+            OIC_LOG(ERROR, TAG, "Unexpected signature OID in CSR\n");
+        }
+        return -1;
+    }
+
+    if (mbedtls_pk_get_type(&csr->pk) != MBEDTLS_PK_ECKEY)
+    {
+        OIC_LOG(ERROR, TAG, "Unexpected public key type in CSR\n");
+        return -1;
+    }
+
+    /* mbedtls_pk_get_bitlen returns the bit length of the curve */
+    if (mbedtls_pk_get_bitlen(&csr->pk) != 256)
+    {
+        OIC_LOG(ERROR, TAG, "Unexpected public length in CSR\n");
+        return -1;
+    }
+
+    mbedtls_ecp_keypair* ecKey = mbedtls_pk_ec(csr->pk);
+    if ((ecKey != NULL) && (ecKey->grp.id != MBEDTLS_ECP_DP_SECP256R1))
+    {
+        OIC_LOG(ERROR, TAG, "Unexpected curve parameters in CSR\n");
+        return -1;
+    }
+
+    /* Hash the CertificateRequestInfoField (https://tools.ietf.org/html/rfc2986#section-3) */
+    int ret = mbedtls_md(mbedtls_md_info_from_type(csr->sig_md), csr->cri.p, csr->cri.len, hash);
+    if (ret != 0)
+    {
+        OIC_LOG(ERROR, TAG, "Failed to hash CertificateRequestInfoField\n");
+        return ret;
+    }
+
+    /* the length of hash is determined from csr->sig_md*/
+    ret = mbedtls_pk_verify(&csr->pk, csr->sig_md, hash, 0, csr->sig.p, csr->sig.len);
+
+    return ret;
+}
+
+OCStackResult OCVerifyCSRSignature(const char* csr)
+{
+    mbedtls_x509_csr csrObj;
+
+    mbedtls_x509_csr_init(&csrObj);
+    int ret = mbedtls_x509_csr_parse(&csrObj, (const unsigned char*)csr, strlen(csr) + 1);
+    if (ret < 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "Couldn't parse CSR: %d", ret);
+        mbedtls_x509_csr_free(&csrObj);
+        return OC_STACK_ERROR;
+    }
+
+    ret = VerifyCSRSignature(&csrObj);
+
+    mbedtls_x509_csr_free(&csrObj);
+
+    if (ret != 0)
+    {
+        return OC_STACK_ERROR;
+    }
+
+    return OC_STACK_OK;
+}
+
+OCStackResult OCGetUuidFromCSR(const char* csr, OicUuid_t* uuid)
+{
+    mbedtls_x509_csr csrObj;
+
+    mbedtls_x509_csr_init(&csrObj);
+    int ret = mbedtls_x509_csr_parse(&csrObj, (const unsigned char*)csr, strlen(csr) + 1);
+    if (ret < 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "Couldn't parse CSR: %d", ret);
+        mbedtls_x509_csr_free(&csrObj);
+        return OC_STACK_ERROR;
+    }
+
+    char uuidStr[UUID_STRING_SIZE + sizeof(SUBJECT_PREFIX) - 1] = { 0 };   // Both constants count NULL, subtract one
+    ret = mbedtls_x509_dn_gets(uuidStr, sizeof(uuidStr), &csrObj.subject);
+    if (ret != (sizeof(uuidStr) - 1))
+    {
+        OIC_LOG_V(ERROR, TAG, "mbedtls_x509_dn_gets returned length or error: %d, expected %d", ret, sizeof(uuidStr) - 1);
+        mbedtls_x509_csr_free(&csrObj);
+        return OC_STACK_ERROR;
+    }
+
+    if (!OCConvertStringToUuid(uuidStr + sizeof(SUBJECT_PREFIX) - 1, uuid->id))
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to convert UUID: '%s'", uuidStr);
+        mbedtls_x509_csr_free(&csrObj);
+        return OC_STACK_ERROR;
+    }
+
+    mbedtls_x509_csr_free(&csrObj);
+    return OC_STACK_OK;
+}
+
+OCStackResult OCGetPublicKeyFromCSR(const char* csr, char** publicKey)
+{
+    mbedtls_x509_csr csrObj;
+
+    mbedtls_x509_csr_init(&csrObj);
+    int ret = mbedtls_x509_csr_parse(&csrObj, (const unsigned char*)csr, strlen(csr) + 1);
+    if (ret < 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "Couldn't parse CSR: %d", ret);
+        mbedtls_x509_csr_free(&csrObj);
+        return OC_STACK_ERROR;
+    }
+
+    char subjectPublicKey[500] = { 0 };
+    ret = mbedtls_pk_write_pubkey_pem(&csrObj.pk, (unsigned char*)subjectPublicKey, sizeof(subjectPublicKey));
+    if (ret != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to write subject public key as PEM: %d", ret);
+        mbedtls_x509_csr_free(&csrObj);
+        return OC_STACK_ERROR;
+    }
+
+    size_t pkLen = strlen(subjectPublicKey) + 1;
+    *publicKey = (char*) OICCalloc(1, pkLen);
+    if (*publicKey == NULL)
+    {
+        OIC_LOG(ERROR, TAG, "Failed to allocate memory for public key");
+        mbedtls_x509_csr_free(&csrObj);
+        return OC_STACK_ERROR;
+    }
+
+    memcpy(*publicKey, subjectPublicKey, pkLen);
+    mbedtls_x509_csr_free(&csrObj);
+
+    return OC_STACK_OK;
+}
+
+OCStackResult OCConvertDerCSRToPem(const char* derCSR, size_t derCSRLen, char** pemCSR)
+{
+    const char* pemHeader = "-----BEGIN CERTIFICATE REQUEST-----\n";
+    const char* pemFooter = "-----END CERTIFICATE REQUEST-----\n";
+
+    /* Get the length required for output*/
+    size_t pemCSRLen;
+    int ret = mbedtls_pem_write_buffer(pemHeader,
+        pemFooter,
+        (const unsigned char*)derCSR,
+        derCSRLen,
+        NULL,
+        0,
+        &pemCSRLen);
+    if (ret != MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL)
+    {
+        OIC_LOG_V(ERROR, TAG, "Couldn't convert CSR into PEM, failed getting required length: %d", ret);
+        return OC_STACK_ERROR;
+    }
+
+    *pemCSR = OICCalloc(1, pemCSRLen + 1);
+    if (*pemCSR == NULL)
+    {
+        OIC_LOG(ERROR, TAG, "Failed to allocate memory for PEM CSR");
+        return OC_STACK_ERROR;
+    }
+
+    /* Try the conversion */
+    ret = mbedtls_pem_write_buffer(pemHeader, pemFooter,
+        (const unsigned char *)derCSR,
+        derCSRLen,
+        (unsigned char*) *pemCSR,
+        pemCSRLen,
+        &pemCSRLen);
+    if (ret < 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "Couldn't convert CSR into PEM, failed getting required length: %d", ret);
+        OICFree(*pemCSR);
+        *pemCSR = NULL;
+        return OC_STACK_ERROR;
+    }
+
+    return OC_STACK_OK;
+}
+
+#endif /* defined(__WITH_TLS__) || defined(__WITH_DTLS__) */
\ No newline at end of file
index 3c7ce13..386bb56 100644 (file)
@@ -36,6 +36,7 @@
 #include "pconfresource.h"
 #include "amaclresource.h"
 #include "credresource.h"
+#include "rolesresource.h"
 
 #define TAG "OIC_SRM_PE"
 
@@ -377,6 +378,31 @@ static bool IsResourceInAce(const char *resource, const OicSecAce_t *ace)
     return false;
 }
 
+static void ProcessMatchingACE(SRMRequestContext_t *context, const OicSecAce_t *currentAce)
+{
+    // Found the subject, so how about resource?
+    OIC_LOG_V(DEBUG, TAG, "%s:found ACE matching subject", __func__);
+
+    // Subject was found, so err changes to Rsrc not found for now.
+    context->responseVal = ACCESS_DENIED_RESOURCE_NOT_FOUND;
+    OIC_LOG_V(DEBUG, TAG, "%s:Searching for resource...", __func__);
+    if (IsResourceInAce(context->resourceUri, currentAce))
+    {
+        OIC_LOG_V(INFO, TAG, "%s:found matching resource in ACE", __func__);
+
+        // Found the resource, so it's down to valid period & permission.
+        context->responseVal = ACCESS_DENIED_INVALID_PERIOD;
+        if (IsAccessWithinValidTime(currentAce))
+        {
+            context->responseVal = ACCESS_DENIED_INSUFFICIENT_PERMISSION;
+            if (IsPermissionAllowingRequest(currentAce->permission,
+                context->requestedPermission))
+            {
+                context->responseVal = ACCESS_GRANTED;
+            }
+        }
+    }
+}
 
 /**
  * Find ACLs containing context->subject.
@@ -414,36 +440,48 @@ static void ProcessAccessRequest(SRMRequestContext_t *context)
 
         if (NULL != currentAce)
         {
-            // Found the subject, so how about resource?
-            OIC_LOG_V(DEBUG, TAG, "%s:found ACE matching subject" ,__func__);
+            ProcessMatchingACE(context, currentAce);
+        }
+        else
+        {
+            OIC_LOG_V(INFO, TAG, "%s:no ACL found matching subject for resource %s",
+                __func__, context->resourceUri);
+        }
+    } while ((NULL != currentAce) && !IsAccessGranted(context->responseVal));
 
-            // Subject was found, so err changes to Rsrc not found for now.
-            context->responseVal = ACCESS_DENIED_RESOURCE_NOT_FOUND;
-            OIC_LOG_V(DEBUG, TAG, "%s:Searching for resource..." ,__func__);
-            if (IsResourceInAce(context->resourceUri, currentAce))
+#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
+        // If no subject ACE granted access, try role ACEs.
+        if (!IsAccessGranted(context->responseVal))
+        {
+            currentAce = NULL;
+            aceSavePtr = NULL;
+            OicSecRole_t *roles = NULL;
+            size_t roleCount = 0;
+            OCStackResult res = GetEndpointRoles(context->endPoint, &roles, &roleCount);
+            if (OC_STACK_OK != res)
             {
-                OIC_LOG_V(INFO, TAG, "%s:found matching resource in ACE" ,__func__);
-
-                // Found the resource, so it's down to valid period & permission.
-                context->responseVal = ACCESS_DENIED_INVALID_PERIOD;
-                if (IsAccessWithinValidTime(currentAce))
+                OIC_LOG_V(ERROR, TAG, "Could not locate any roles for endpoint: %d", res);
+            }
+            else
+            {
+                do
                 {
-                    context->responseVal = ACCESS_DENIED_INSUFFICIENT_PERMISSION;
-                    if (IsPermissionAllowingRequest(currentAce->permission,
-                        context->requestedPermission))
+                    currentAce = GetACLResourceDataByRoles(roles, roleCount, &aceSavePtr);
+                    if (NULL != currentAce)
                     {
-                        context->responseVal = ACCESS_GRANTED;
+                        ProcessMatchingACE(context, currentAce);
                     }
-                }
+                    else
+                    {
+                        OIC_LOG_V(INFO, TAG, "%s:no ACL found matching roles for resource %s",
+                            __func__, context->resourceUri);
+                    }
+                } while ((NULL != currentAce) && !IsAccessGranted(context->responseVal));
+
+                OICFree(roles);
             }
         }
-        else
-        {
-            OIC_LOG_V(INFO, TAG, "%s:no ACE found matching subject for resource %s",
-                __func__, context->resourceUri);
-        }
-    } while ((NULL != currentAce)
-        && (false == IsAccessGranted(context->responseVal)));
+#endif /* defined(__WITH_DTLS__) || defined(__WITH_TLS__) */
 
     OIC_LOG_V(INFO, TAG, "%s:Leaving with responseVal = %s", __func__,
         IsAccessGranted(context->responseVal) ? "ACCESS_GRANTED" : "ACCESS_DENIED");
index 323a0bf..a6d09b7 100644 (file)
@@ -41,6 +41,8 @@
 
 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
 #include "crlresource.h"
+#include "csrresource.h"
+#include "rolesresource.h"
 #endif // __WITH_DTLS__ || __WITH_TLS__
 
 OCStackResult SendSRMResponse(const OCEntityHandlerRequest *ehRequest,
@@ -96,6 +98,14 @@ OCStackResult InitSecureResources( )
     {
         ret = InitCRLResource();
     }
+    if(OC_STACK_OK == ret)
+    {
+        ret = InitCSRResource();
+    }
+    if(OC_STACK_OK == ret)
+    {
+        ret = InitRolesResource();
+    }
 #endif // __WITH_DTLS__ || __WITH_TLS__
     if(OC_STACK_OK == ret)
     {
@@ -131,6 +141,8 @@ OCStackResult DestroySecureResources( )
     DeInitPstatResource();
 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
     DeInitCRLResource();
+    DeInitCSRResource();
+    DeInitRolesResource();
 #endif // __WITH_DTLS__ || __WITH_TLS__
     DeInitAmaclResource();
 //#ifdef DIRECT_PAIRING
diff --git a/resource/csdk/security/src/rolesresource.c b/resource/csdk/security/src/rolesresource.c
new file mode 100644 (file)
index 0000000..97a872f
--- /dev/null
@@ -0,0 +1,1210 @@
+//******************************************************************
+//
+// Copyright 2017 Microsoft
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//******************************************************************
+
+#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
+#include "iotivity_config.h"
+#include <stdlib.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#include <stdint.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include "oic_string.h"
+#include "cainterface.h"
+#include "payload_logging.h"
+#include "ocstack.h"
+#include "ocrandom.h"
+#include "cacommon.h"
+#include "srmresourcestrings.h"
+#include "ocpayload.h"
+#include "ocpayloadcbor.h"
+#include "credresource.h"
+#include "doxmresource.h"
+#include "srmutility.h"
+#include "certhelpers.h"
+#include "resourcemanager.h"
+#include "utlist.h"
+#include "ca_adapter_net_ssl.h"
+#include "ocstackinternal.h"
+#include "rolesresource.h"
+
+#define TAG  "OIC_SRM_ROLES"
+
+typedef struct RolesEntry {
+    uint8_t                 *publicKey;         /**< DER-encoded public key */
+    size_t                  publicKeyLength;    /**< length of publicKey */
+    RoleCertChain_t         *chains;            /**< stored certificates */
+
+    struct tm               cacheValidUntil;    /**< Cache valid until time; use 0 if cache is not yet set */
+    OicSecRole_t            *cachedRoles;       /**< Cached roles; must free with OICFree */
+    size_t                  cachedRolesLength;  /**< Length of cachedRoles array */
+
+    struct RolesEntry       *next;
+} RolesEntry_t;
+
+static OCResourceHandle gRolesHandle        = NULL;
+static RolesEntry_t     *gRoles             = NULL;
+static uint32_t         gIdCounter          = 1;
+
+/** 
+ * Default cbor payload size. This value is increased in case of CborErrorOutOfMemory.
+ * The value of payload size is increased until reaching max cbor size. 
+ */
+static const uint16_t CBOR_SIZE = 2048;
+
+/**
+ * Zero subject UUID.
+ */
+static const char EMPTY_UUID[] = "00000000-0000-0000-0000-000000000000";
+
+/**
+ * Mandatory parts of a role map cred entry: 4 key/value pairs: credId, subject, publicData, and credType.
+ */
+static const uint8_t ROLE_MAP_SIZE = 4;
+
+static void InvalidateRoleCache(RolesEntry_t *entry)
+{
+    memset(&entry->cacheValidUntil, 0, sizeof(entry->cacheValidUntil));
+    OICFree(entry->cachedRoles);
+    entry->cachedRoles = NULL;
+    entry->cachedRolesLength = 0;
+}
+
+/* Caller must call OICFree on publicKey when finished. */
+static OCStackResult GetPeerPublicKeyFromEndpoint(const CAEndpoint_t *endpoint,
+                                                  uint8_t **publicKey, 
+                                                  size_t *publicKeyLength)
+{
+    CASecureEndpoint_t sep;
+    CAResult_t res = GetCASecureEndpointData(endpoint, &sep);
+    if (CA_STATUS_OK != res)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s: Failed to GetCASecureEndpointData: %d", __func__, res);
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    if ((NULL == sep.publicKey) || (0 == sep.publicKeyLength))
+    {
+        OIC_LOG_V(ERROR, TAG, "%s: Peer did not have a public key", __func__);
+        return OC_STACK_ERROR;
+    }
+
+    *publicKey = OICCalloc(1, sep.publicKeyLength);
+    if (NULL == *publicKey)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s: No memory for publicKey", __func__);
+        return OC_STACK_NO_MEMORY;
+    }
+
+    memcpy(*publicKey, sep.publicKey, sep.publicKeyLength);
+    *publicKeyLength = sep.publicKeyLength;
+
+    return OC_STACK_OK;
+}
+
+/* Caller must call OICFree on publicKey when finished. */
+static OCStackResult GetPeerPublicKey(const OCDevAddr *peer, uint8_t **publicKey, size_t *publicKeyLength)
+{
+    CAEndpoint_t endpoint;
+    CopyDevAddrToEndpoint(peer, &endpoint);
+
+    return GetPeerPublicKeyFromEndpoint(&endpoint, publicKey, publicKeyLength);
+}
+
+static void FreeRoleCertChain(RoleCertChain_t *roleCert)
+{
+    if (NULL == roleCert)
+    {
+        return;
+    }
+
+    OICFree(roleCert->optData.data);
+    OICFree(roleCert->certificate.data);
+    OICFree(roleCert);
+}
+
+void FreeRoleCertChainList(RoleCertChain_t *roleCertList)
+{
+    if (NULL == roleCertList)
+    {
+        return;
+    }
+
+    RoleCertChain_t *certTmp1 = NULL;
+    RoleCertChain_t *certTmp2 = NULL;
+    LL_FOREACH_SAFE(roleCertList, certTmp1, certTmp2)
+    {
+        LL_DELETE(roleCertList, certTmp1);
+        FreeRoleCertChain(certTmp1);
+    }
+}
+
+static void FreeRolesEntry(RolesEntry_t *rolesEntry)
+{
+    if (NULL == rolesEntry)
+    {
+        return;
+    }
+
+    FreeRoleCertChainList(rolesEntry->chains);
+    OICFree(rolesEntry->chains);
+    OICFree(rolesEntry->publicKey);
+    OICFree(rolesEntry->cachedRoles);
+    OICFree(rolesEntry);
+}
+
+static void FreeRolesList(RolesEntry_t *roles)
+{
+    if (NULL != roles)
+    {
+        RolesEntry_t *entryTmp1 = NULL;
+        RolesEntry_t *entryTmp2 = NULL;
+        LL_FOREACH_SAFE(roles, entryTmp1, entryTmp2)
+        {
+            LL_DELETE(roles, entryTmp1);
+            FreeRolesEntry(entryTmp1);
+        }
+    }
+}
+
+static OCStackResult DuplicateRoleCertChain(const RoleCertChain_t *roleCert, RoleCertChain_t **duplicate)
+{
+    OIC_LOG(DEBUG, TAG, "DuplicateRoleCertChain IN");
+
+    OCStackResult res = OC_STACK_ERROR;
+    RoleCertChain_t *tmp = NULL;
+
+    if ((NULL == roleCert) || (NULL == duplicate))
+    {
+        res = OC_STACK_INVALID_PARAM;
+        goto exit;
+    }
+
+    tmp = (RoleCertChain_t *)OICCalloc(1, sizeof(RoleCertChain_t));
+    if (NULL == tmp)
+    {
+        OIC_LOG(ERROR, TAG, "No memory for tmp");
+        res = OC_STACK_NO_MEMORY;
+        goto exit;
+    }
+
+    tmp->certificate.data = (uint8_t *)OICCalloc(1, roleCert->certificate.len);
+    if (NULL == tmp->certificate.data)
+    {
+        OIC_LOG(ERROR, TAG, "No memory for certificate data");
+        res = OC_STACK_NO_MEMORY;
+        goto exit;
+    }
+    tmp->credId = roleCert->credId;
+    tmp->certificate.len = roleCert->certificate.len;
+    tmp->certificate.encoding = roleCert->certificate.encoding;
+    memcpy(tmp->certificate.data, roleCert->certificate.data, roleCert->certificate.len);
+
+    if (NULL != roleCert->optData.data)
+    {
+        tmp->optData.data = (uint8_t *)OICCalloc(1, roleCert->optData.len);
+        if (NULL == tmp->optData.data)
+        {
+            OIC_LOG(ERROR, TAG, "No memory for optional data");
+            res = OC_STACK_NO_MEMORY;
+            goto exit;
+        }
+        tmp->optData.len = roleCert->optData.len;
+        tmp->optData.encoding = roleCert->optData.encoding;
+        tmp->optData.revstat = roleCert->optData.revstat;
+        memcpy(tmp->optData.data, roleCert->optData.data, roleCert->optData.len);
+    }
+
+    *duplicate = tmp;
+    res = OC_STACK_OK;
+
+exit:
+
+    OIC_LOG_V(DEBUG, TAG, "DuplicateRoleCertChain OUT: %d", res);
+
+    if (OC_STACK_OK != res)
+    {
+        FreeRoleCertChain(tmp);
+    }
+
+    return res;
+}
+
+static OCStackResult AddRoleCertificate(const RoleCertChain_t *roleCert, const uint8_t *pubKey, size_t pubKeyLength)
+{
+    OCStackResult res = OC_STACK_ERROR;
+    RolesEntry_t *targetEntry = NULL;
+    RoleCertChain_t *copy = NULL;
+
+    OIC_LOG(DEBUG, TAG, "AddRoleCertificate IN");
+
+    if ((NULL == pubKey) || (0 == pubKeyLength))
+    {
+        assert(!"AddRoleCertificate called with no public key");
+        res = OC_STACK_INVALID_PARAM;
+        goto exit;
+    }
+
+    for (targetEntry = gRoles; NULL != targetEntry; targetEntry = targetEntry->next)
+    {
+        if ((targetEntry->publicKeyLength == pubKeyLength) &&
+            (0 == memcmp(targetEntry->publicKey, pubKey, pubKeyLength)))
+        {
+            break;
+        }
+    }
+
+    if (NULL != targetEntry)
+    {
+        InvalidateRoleCache(targetEntry);
+    }
+    else
+    {
+        /* We haven't seen this public key before and need a new entry. */
+        targetEntry = (RolesEntry_t *)OICCalloc(1, sizeof(RolesEntry_t *));
+        if (NULL == targetEntry)
+        {
+            OIC_LOG(ERROR, TAG, "No memory for new targetEntry");
+            res = OC_STACK_NO_MEMORY;
+            goto exit;
+        }
+        targetEntry->publicKey = (uint8_t *)OICCalloc(1, pubKeyLength);
+        if (NULL == targetEntry->publicKey)
+        {
+            OIC_LOG(ERROR, TAG, "No memory for new targetEntry public key");
+            OICFree(targetEntry);
+            res = OC_STACK_NO_MEMORY;
+            goto exit;
+        }
+        targetEntry->publicKeyLength = pubKeyLength;
+        memcpy(targetEntry->publicKey, pubKey, pubKeyLength);
+
+        LL_PREPEND(gRoles, targetEntry);
+    }
+
+    // @todo: Detect duplicates and don't add them again
+    res = DuplicateRoleCertChain(roleCert, &copy);
+    if (OC_STACK_OK != res)
+    {
+        OIC_LOG_V(ERROR, TAG, "Could not duplicate role cert chain: %d", res);
+        goto exit;
+    }
+
+    // Assign our own credId.
+    copy->credId = gIdCounter++;
+
+    LL_APPEND(targetEntry->chains, copy);
+
+    res = OC_STACK_OK;
+
+exit:
+
+    if (OC_STACK_OK != res)
+    {
+        FreeRoleCertChain(copy);
+    }
+
+    OIC_LOG_V(DEBUG, TAG, "AddRoleCertificate IN: %d", res);
+
+    return res;
+}
+
+static OCStackResult RolesToCBORPayload(const RoleCertChain_t *roles, uint8_t **cborPayload,
+                                        size_t *cborSize)
+{
+    OCStackResult ret = OC_STACK_OK;
+
+    CborError cborEncoderResult = CborNoError;
+    uint8_t *outPayload = NULL;
+    CborEncoder encoder;
+    CborEncoder rolesRootMap;
+    CborEncoder rolesArray;
+    size_t roleCount = 0;
+    const RoleCertChain_t *currChain = NULL;
+
+    VERIFY_NOT_NULL_RETURN(TAG, roles, ERROR, OC_STACK_INVALID_PARAM);
+    VERIFY_NOT_NULL_RETURN(TAG, cborPayload, ERROR, OC_STACK_INVALID_PARAM);
+    VERIFY_NOT_NULL_RETURN(TAG, cborSize, ERROR, OC_STACK_INVALID_PARAM);
+
+    size_t cborLen = *cborSize;
+    *cborSize = 0;
+    *cborPayload = NULL;
+
+    if (0 == cborLen)
+    {
+        cborLen = CBOR_SIZE;
+    }
+
+    outPayload = (uint8_t *)OICCalloc(1, cborLen);
+    VERIFY_NOT_NULL_RETURN(TAG, outPayload, ERROR, OC_STACK_NO_MEMORY);
+    cbor_encoder_init(&encoder, outPayload, cborLen, 0);
+
+    // Create roles root map (roles, rt, if)
+    cborEncoderResult = cbor_encoder_create_map(&encoder, &rolesRootMap, 3);
+    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding roles root map");
+
+    // Roles array
+    cborEncoderResult = cbor_encode_text_string(&rolesRootMap, OIC_JSON_ROLES_NAME, strlen(OIC_JSON_ROLES_NAME));
+    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding roles name tag");
+
+    for (currChain = roles; NULL != currChain; currChain = currChain->next)
+    {
+        roleCount++;
+    }
+
+    cborEncoderResult = cbor_encoder_create_array(&rolesRootMap, &rolesArray, roleCount);
+    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding roles array");
+
+    for (currChain = roles; NULL != currChain; currChain = currChain->next)
+    {
+        CborEncoder roleMap;
+        size_t mapSize = ROLE_MAP_SIZE;
+
+        if (NULL != currChain->optData.data)
+        {
+            mapSize++;
+        }
+
+        cborEncoderResult = cbor_encoder_create_map(&rolesArray, &roleMap, mapSize);
+        VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding role map");
+
+        // credId - mandatory
+        cborEncoderResult = cbor_encode_text_string(&roleMap, OIC_JSON_CREDID_NAME, strlen(OIC_JSON_CREDID_NAME));
+        VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding credId tag");
+        cborEncoderResult = cbor_encode_int(&roleMap, currChain->credId);
+        VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding credId value");
+
+        // subjectuuid - mandatory - always zero for role certificates
+        cborEncoderResult = cbor_encode_text_string(&roleMap, OIC_JSON_SUBJECTID_NAME, strlen(OIC_JSON_SUBJECTID_NAME));
+        VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding subject tag");
+        cborEncoderResult = cbor_encode_text_string(&roleMap, EMPTY_UUID, sizeof(EMPTY_UUID) - 1);
+        VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding subject value");
+        
+        // publicData - mandatory
+        cborEncoderResult = SerializeEncodingToCbor(&roleMap, OIC_JSON_PUBLICDATA_NAME, &currChain->certificate);
+        VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding publicData");
+
+        // optionalData
+        if (NULL != currChain->optData.data)
+        {
+            cborEncoderResult = SerializeSecOptToCbor(&roleMap, OIC_JSON_OPTDATA_NAME, &currChain->optData);
+            VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding optional data");
+        }
+
+        // credType - mandatory
+        cborEncoderResult = cbor_encode_text_string(&roleMap, OIC_JSON_CREDTYPE_NAME, strlen(OIC_JSON_CREDTYPE_NAME));
+        VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding credType tag");
+        // Per security spec, only SIGNED_ASYMMETRIC_KEY is supported here.
+        cborEncoderResult = cbor_encode_int(&roleMap, SIGNED_ASYMMETRIC_KEY);
+        VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding credType value");
+
+        cborEncoderResult = cbor_encoder_close_container(&rolesArray, &roleMap);
+        VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed closing role map");
+    }
+
+    cborEncoderResult = cbor_encoder_close_container(&rolesRootMap, &rolesArray);
+    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed closing roles array");
+
+    // RT -- Mandatory
+    CborEncoder rtArray;
+    cborEncoderResult = cbor_encode_text_string(&rolesRootMap, OIC_JSON_RT_NAME,
+        strlen(OIC_JSON_RT_NAME));
+    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding RT Name Tag.");
+    cborEncoderResult = cbor_encoder_create_array(&rolesRootMap, &rtArray, 1);
+    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding RT Value.");
+    for (size_t i = 0; i < 1; i++)
+    {
+        cborEncoderResult = cbor_encode_text_string(&rtArray, OIC_RSRC_TYPE_SEC_ROLES,
+            strlen(OIC_RSRC_TYPE_SEC_ROLES));
+        VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding RT Value.");
+    }
+    cborEncoderResult = cbor_encoder_close_container(&rolesRootMap, &rtArray);
+    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing RT.");
+
+    // IF-- Mandatory
+    CborEncoder ifArray;
+    cborEncoderResult = cbor_encode_text_string(&rolesRootMap, OIC_JSON_IF_NAME,
+        strlen(OIC_JSON_IF_NAME));
+    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding IF Name Tag.");
+    cborEncoderResult = cbor_encoder_create_array(&rolesRootMap, &ifArray, 1);
+    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding IF Value.");
+    for (size_t i = 0; i < 1; i++)
+    {
+        cborEncoderResult = cbor_encode_text_string(&ifArray, OC_RSRVD_INTERFACE_DEFAULT,
+            strlen(OC_RSRVD_INTERFACE_DEFAULT));
+        VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding IF Value.");
+    }
+    cborEncoderResult = cbor_encoder_close_container(&rolesRootMap, &ifArray);
+    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing IF.");
+
+    // Close roles root map
+    cborEncoderResult = cbor_encoder_close_container(&encoder, &rolesRootMap);
+    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed closing roles root map");
+
+    *cborSize = cbor_encoder_get_buffer_size(&encoder, outPayload);
+    *cborPayload = outPayload;
+
+exit:
+    if (CborErrorOutOfMemory == cborEncoderResult)
+    {
+        OIC_LOG(DEBUG, TAG, "RolesToCBORPayload:CborErrorOutOfMemory : retry with more memory");
+
+        // reallocate and try again!
+        OICFree(outPayload);
+        // Since the initially-allocated memory failed, double the memory.
+        cborLen += cbor_encoder_get_buffer_size(&encoder, encoder.end);
+        ret = RolesToCBORPayload(roles, cborPayload, cborSize);
+        *cborSize = cborLen;
+    }
+    else if (cborEncoderResult != CborNoError)
+    {
+        OIC_LOG(ERROR, TAG, "Failed to RolesToCBORPayload");
+        OICFree(outPayload);
+        *cborSize = 0;
+        *cborPayload = NULL;
+        ret = OC_STACK_ERROR;
+    }
+
+    return ret;
+}
+
+/* Caller must call DeleteRoleCredentials on roleEntries when finished. */
+OCStackResult CBORPayloadToRoles(const uint8_t *cborPayload, size_t size, RoleCertChain_t **roleEntries)
+{
+    if (NULL == cborPayload || 0 == size || NULL == roleEntries)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    CborValue rolesCbor = { .parser = NULL };
+    CborParser parser = { .end = NULL };
+    CborError cborFindResult = CborNoError;
+    RoleCertChain_t *headRoleCertChain = NULL;
+    char* tagName = NULL;
+    size_t len = 0;
+
+    cborFindResult = cbor_parser_init(cborPayload, size, 0, &parser, &rolesCbor);
+    VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed to initialize parser.");
+
+    if (!cbor_value_is_container(&rolesCbor))
+    {
+        return OC_STACK_ERROR;
+    }
+
+    // Enter roles Root Map
+    CborValue rolesRootMap;
+    memset(&rolesRootMap, 0, sizeof(rolesRootMap));
+    cborFindResult = cbor_value_enter_container(&rolesCbor, &rolesRootMap);
+    VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Entering roles Root Map.");
+
+    while (cbor_value_is_valid(&rolesRootMap))
+    {
+        if (NULL != tagName)
+        {
+            free(tagName);
+            tagName = NULL;
+        }
+        len = 0;
+        CborType type = cbor_value_get_type(&rolesRootMap);
+        if (type == CborTextStringType && cbor_value_is_text_string(&rolesRootMap))
+        {
+            cborFindResult = cbor_value_dup_text_string(&rolesRootMap, &tagName, &len, NULL);
+            VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed finding name in roles Root Map.");
+            cborFindResult = cbor_value_advance(&rolesRootMap);
+            VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed advancing value in roles Root Map.");
+        }
+        else
+        {
+            OIC_LOG_V(WARNING, TAG, "Value is not of type string, but of type %x", type);
+        }
+
+        if (NULL != tagName)
+        {
+            if (strcmp(tagName, OIC_JSON_ROLES_NAME) == 0)
+            {
+                // Enter role array
+                int roleCount = 0;
+                RoleCertChain_t *currEntry = NULL;
+                CborValue roleArray;
+                memset(&roleArray, 0, sizeof(roleArray));
+
+                cborFindResult = cbor_value_enter_container(&rolesRootMap, &roleArray);
+                VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed entering role array.");
+
+                while (cbor_value_is_valid(&roleArray))
+                {
+                    roleCount++;
+                    CborValue roleMap;
+                    memset(&roleMap, 0, sizeof(roleMap));
+                    cborFindResult = cbor_value_enter_container(&roleArray, &roleMap);
+                    VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed entering role map.");
+
+                    if (NULL == currEntry)
+                    {
+                        assert(NULL == headRoleCertChain);
+                        headRoleCertChain = currEntry = (RoleCertChain_t *)OICCalloc(1, sizeof(RoleCertChain_t));
+                        VERIFY_NOT_NULL(TAG, currEntry, ERROR);
+                    }
+                    else
+                    {
+                        assert(NULL != headRoleCertChain);
+                        currEntry->next = (RoleCertChain_t *)OICCalloc(1, sizeof(RoleCertChain_t));
+                        VERIFY_NOT_NULL(TAG, currEntry->next, ERROR);
+                        currEntry = currEntry->next;
+                    }
+
+                    while (cbor_value_is_valid(&roleMap))
+                    {
+                        free(tagName);
+                        tagName = NULL;
+                        CborType innerType = cbor_value_get_type(&roleMap);
+                        if (innerType == CborTextStringType)
+                        {
+                            cborFindResult = cbor_value_dup_text_string(&roleMap, &tagName, &len, NULL);
+                            VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed finding name in role map.");
+                            cborFindResult = cbor_value_advance(&roleMap);
+                            VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed advancing value in role map.");
+                        }
+                        if (NULL != tagName)
+                        {
+                            //credid
+                            if (strcmp(tagName, OIC_JSON_CREDID_NAME) == 0)
+                            {
+                                uint64_t credId64 = 0;
+                                cborFindResult = cbor_value_get_uint64(&roleMap, &credId64);
+                                VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed retrieving credId.");
+                                if (UINT32_MAX < credId64)
+                                {
+                                    cborFindResult = CborUnknownError;
+                                    VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "credId was too large.");
+                                }
+                                currEntry->credId = (uint32_t)credId64;
+                            }
+                            else if (strcmp(tagName, OIC_JSON_PUBLICDATA_NAME) == 0)
+                            {
+                                cborFindResult = DeserializeEncodingFromCbor(&roleMap, &currEntry->certificate);
+                                VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed to read publicData");
+                            }
+                            else if (strcmp(tagName, OIC_JSON_OPTDATA_NAME) == 0)
+                            {
+                                cborFindResult = DeserializeSecOptFromCbor(&roleMap, &currEntry->optData);
+                                VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed to read optionalData");
+                            }
+                            else if (strcmp(tagName, OIC_JSON_CREDTYPE_NAME) == 0)
+                            {
+                                uint64_t credType = 0;
+                                cborFindResult = cbor_value_get_uint64(&roleMap, &credType);
+                                VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed retrieving credType.");
+                                /* Only SIGNED_ASYMMETRIC_KEY is supported. */
+                                if (SIGNED_ASYMMETRIC_KEY != (OicSecCredType_t)credType)
+                                {
+                                    OIC_LOG_V(ERROR, TAG, "Unsupported role credential type: %llu", credType);
+                                    goto exit;
+                                }
+                            }
+                            // Silently ignore subject field; log anything else.
+                            else if (strcmp(tagName, OIC_JSON_SUBJECTID_NAME) != 0)
+                            {
+                                OIC_LOG_V(WARNING, TAG, "Unknown role map tag: %s", tagName);
+                            }
+                        }
+
+                        if (cbor_value_is_valid(&roleMap))
+                        {
+                            cborFindResult = cbor_value_advance(&roleMap);
+                            VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed advancing role map.");
+                        }
+                    }
+
+                    if (NULL == currEntry->certificate.data)
+                    {
+                        OIC_LOG(ERROR, TAG, "Role credential did not have publicData");
+                        goto exit;
+                    }
+
+                    if (cbor_value_is_valid(&roleArray))
+                    {
+                        cborFindResult = cbor_value_advance(&roleArray);
+                        VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed advancing role array.");
+                    }
+                }
+            }
+            else
+            {
+                // Ignore any other tag type for now.
+                OIC_LOG_V(WARNING, TAG, "Unknown role root map tag %s", tagName);
+            }
+
+        }
+        if (cbor_value_is_valid(&rolesRootMap))
+        {
+            cborFindResult = cbor_value_advance(&rolesRootMap);
+            VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed advancing CSR Root Map");
+        }
+    }
+
+    *roleEntries = headRoleCertChain;
+
+exit:
+    if (NULL != tagName)
+    {
+        free(tagName);
+    }
+
+    if (CborNoError != cborFindResult)
+    {
+        if (NULL != headRoleCertChain)
+        {
+            FreeRoleCertChainList(headRoleCertChain);
+        }
+        return OC_STACK_ERROR;
+    }
+    else
+    {
+        return OC_STACK_OK;
+    }
+}
+
+static OCEntityHandlerResult HandleGetRequest(OCEntityHandlerRequest *ehRequest)
+{
+    OIC_LOG(DEBUG, TAG, "Roles HandleGetRequest IN");
+
+    OCStackResult res = OC_STACK_ERROR;
+    OCEntityHandlerResult ehRet = OC_EH_ERROR;
+    size_t size = 0;
+    uint8_t *payload = NULL;
+    const RoleCertChain_t *roles = NULL;
+    uint8_t *publicKey = NULL;
+    size_t publicKeyLength = 0;
+
+    res = GetPeerPublicKey(&ehRequest->devAddr, &publicKey, &publicKeyLength);
+    if (OC_STACK_OK != res)
+    {
+        OIC_LOG_V(ERROR, TAG, "Could not get remote peer's public key: %d", res);
+        ehRet = OC_EH_ERROR;
+        goto exit;
+    }
+
+    for (const RolesEntry_t *entry = gRoles; NULL != entry; entry = entry->next)
+    {
+        if ((entry->publicKeyLength == publicKeyLength) &&
+            (0 == memcmp(entry->publicKey, publicKey, publicKeyLength)))
+        {
+            roles = entry->chains;
+            break;
+        }
+    }
+
+    if (NULL == roles)
+    {
+        OIC_LOG(ERROR, TAG, "Could not find a roles list for this peer");
+        ehRet = OC_EH_ERROR;
+        goto exit;
+    }
+
+    res = RolesToCBORPayload(roles, &payload, &size);
+    ehRet = (OC_STACK_OK == res) ? OC_EH_OK : OC_EH_ERROR;
+
+exit:
+    
+    ehRet = ((SendSRMResponse(ehRequest, ehRet, payload, size)) == OC_STACK_OK) ? OC_EH_OK : OC_EH_ERROR;
+
+    OICFree(payload);
+    OICFree(publicKey);
+
+    OIC_LOG(DEBUG, TAG, "Roles HandleGetRequest OUT");
+    return ehRet;
+}
+
+static OCEntityHandlerResult HandlePostRequest(OCEntityHandlerRequest *ehRequest)
+{
+    OCEntityHandlerResult ehRet = OC_EH_ERROR;
+    uint8_t *pubKey = NULL;
+    size_t pubKeyLength = 0;
+    uint8_t *peerPubKey = NULL;
+    size_t peerPubKeyLen = 0;
+
+    OIC_LOG(DEBUG, TAG, "Roles HandlePostRequest IN");
+
+    RoleCertChain_t *chains = NULL;
+    uint8_t *payload = (((OCSecurityPayload*)ehRequest->payload)->securityData);
+    size_t size = (((OCSecurityPayload*)ehRequest->payload)->payloadSize);
+
+    OCStackResult res = GetPeerPublicKey(&ehRequest->devAddr, &peerPubKey, &peerPubKeyLen);
+    if (OC_STACK_OK != res)
+    {
+        OIC_LOG_V(ERROR, TAG, "Could not get peer's public key: %d", res);
+        ehRet = OC_EH_ERROR; 
+        goto exit;
+    }
+
+    res = CBORPayloadToRoles(payload, size, &chains);
+    if (OC_STACK_OK == res)
+    {
+        RoleCertChain_t *curr;
+
+        for (curr = chains; NULL != curr; curr = curr->next)
+        {
+            if (NULL != curr->optData.data)
+            {
+                if (OC_STACK_OK != OCInternalIsValidCertChain(curr->optData.data, curr->optData.len))
+                {
+                    OIC_LOG(ERROR, TAG, "Optional data is not a valid cert chain");
+                    ehRet = OC_EH_ERROR;
+                    goto exit;
+                }
+            }
+
+            if (OC_STACK_OK != OCInternalIsValidRoleCertificate(curr->certificate.data, curr->certificate.len,
+                &pubKey, &pubKeyLength))
+            {
+                OIC_LOG(ERROR, TAG, "Could not verify certificate is a valid role certificate");
+                ehRet = OC_EH_ERROR;
+                goto exit;
+            }
+
+            if ((pubKeyLength != peerPubKeyLen) ||
+                (0 != memcmp(pubKey, peerPubKey, pubKeyLength)))
+            {
+                OIC_LOG(ERROR, TAG, "Peer sent us certificate not for its public key");
+                continue;
+            }
+
+            if (OC_STACK_OK != AddRoleCertificate(curr, pubKey, pubKeyLength))
+            {
+                OIC_LOG(ERROR, TAG, "Could not AddRoleCertificate");
+                ehRet = OC_EH_ERROR;
+                goto exit;
+            }
+        }
+
+        ehRet = OC_EH_OK;
+    }
+
+exit:
+
+    ehRet = (SendSRMResponse(ehRequest, ehRet, NULL, 0) == OC_STACK_OK) ? OC_EH_OK : OC_EH_ERROR;
+
+    FreeRoleCertChainList(chains);
+    OICFree(pubKey);
+    OICFree(peerPubKey);
+
+    OIC_LOG(DEBUG, TAG, "Roles HandlePostRequest OUT");
+
+    return ehRet;
+}
+
+static OCEntityHandlerResult HandleDeleteRequest(OCEntityHandlerRequest *ehRequest)
+{
+    OIC_LOG(DEBUG, TAG, "Roles HandleDeleteRequest IN");
+
+    OCEntityHandlerResult ehRet = OC_EH_ERROR;
+    uint8_t *peerPubKey = NULL;
+    size_t peerPubKeyLen = 0;
+    OicParseQueryIter_t parseIter = { .attrPos = NULL };
+    uint32_t credId = 0;
+
+    if (NULL == ehRequest->query)
+    {
+        return ehRet;
+    }
+    
+    // Parsing REST query to get the credId
+    ParseQueryIterInit((unsigned char *)ehRequest->query, &parseIter);
+    while (GetNextQuery(&parseIter))
+    {
+        if (strncasecmp((const char *)parseIter.attrPos, OIC_JSON_CREDID_NAME,
+            parseIter.attrLen) == 0)
+        {
+            int ret = sscanf((const char *)parseIter.valPos, "%lu", &credId);
+            if (1 > ret)
+            {
+                OIC_LOG_V(ERROR, TAG, "credId was not valid: %s", parseIter.valPos);
+                ehRet = OC_EH_ERROR;
+                goto exit;
+            }
+        }
+        else
+        {
+            OIC_LOG_V(DEBUG, TAG, "Unexpected in query string: %s=%s", parseIter.attrPos, parseIter.valPos);
+        }
+    }
+
+    OCStackResult res = GetPeerPublicKey(&ehRequest->devAddr, &peerPubKey, &peerPubKeyLen);
+    if (OC_STACK_OK != res)
+    {
+        OIC_LOG_V(ERROR, TAG, "Could not get peer's public key: %d", res);
+        ehRet = OC_EH_ERROR;
+        goto exit;
+    }
+
+    RolesEntry_t *entry = NULL;
+    for (entry = gRoles; NULL != entry; entry = entry->next)
+    {
+        assert((0 < entry->publicKeyLength) && (NULL != entry->publicKey));
+        if ((entry->publicKeyLength == peerPubKeyLen) &&
+            (0 == memcmp(entry->publicKey, peerPubKey, peerPubKeyLen)))
+        {
+            break;
+        }
+    }
+
+    if (NULL == entry)
+    {
+        /* No entry for this peer. */
+        OIC_LOG(ERROR, TAG, "No entry for this peer's public key");
+        ehRet = OC_EH_ERROR;
+        goto exit;
+    }
+
+    InvalidateRoleCache(entry);
+
+    RoleCertChain_t *curr1 = NULL;
+    RoleCertChain_t *curr2 = NULL;
+    LL_FOREACH_SAFE(entry->chains, curr1, curr2)
+    {
+        // credId of zero means all creds; we never assign zero as a credId.
+        if ((0 == credId) || (curr1->credId == credId))
+        {
+            LL_DELETE(entry->chains, curr1);
+            FreeRoleCertChain(curr1);
+            ehRet = OC_EH_OK;
+            break;
+        }
+    }
+
+exit:
+
+    ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ? OC_EH_OK : OC_EH_ERROR;
+
+    OIC_LOG(DEBUG, TAG, "Roles HandleDeleteRequest OUT");
+    OICFree(peerPubKey);
+
+    return ehRet;
+}
+
+static OCEntityHandlerResult RolesEntityHandler(OCEntityHandlerFlag flag,
+                                                OCEntityHandlerRequest * ehRequest,
+                                                void* callbackParameter)
+{
+    OCEntityHandlerResult ehRet = OC_EH_ERROR;
+
+    OC_UNUSED(callbackParameter);
+
+    if (!ehRequest)
+    {
+        return OC_EH_ERROR;
+    }
+
+    if (flag & OC_REQUEST_FLAG)
+    {
+        OIC_LOG(DEBUG, TAG, "Flag includes OC_REQUEST_FLAG");
+        switch (ehRequest->method)
+        {
+        case OC_REST_GET:
+            ehRet = HandleGetRequest(ehRequest);
+            break;
+        case OC_REST_PUT:
+        case OC_REST_POST:
+            ehRet = HandlePostRequest(ehRequest);
+            break;
+        case OC_REST_DELETE:
+            ehRet = HandleDeleteRequest(ehRequest);
+            break;
+        default:
+            ehRet = ((SendSRMResponse(ehRequest, OC_EH_ERROR, NULL, 0)) == OC_STACK_OK) ?
+                OC_EH_OK : OC_EH_ERROR;
+            break;
+        }
+    }
+
+    return ehRet;
+}
+
+OCStackResult InitRolesResource()
+{
+    OCStackResult res = OCCreateResource(&gRolesHandle,
+        OIC_RSRC_TYPE_SEC_ROLES,
+        OC_RSRVD_INTERFACE_DEFAULT,
+        OIC_RSRC_ROLES_URI,
+        RolesEntityHandler,
+        NULL,
+        OC_SECURE);
+
+    if (OC_STACK_OK != res)
+    {
+        OIC_LOG_V(FATAL, TAG, "Unable to instantiate roles resource: %d", res);
+    }
+
+    return res;
+}
+
+OCStackResult DeInitRolesResource()
+{
+    OCStackResult res = OCDeleteResource(gRolesHandle);
+
+    if (OC_STACK_OK != res)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to delete roles resource: %d", res);
+    }
+
+    gRolesHandle = NULL;
+
+    FreeRolesList(gRoles);
+    
+    gRoles = NULL;
+
+    return res;
+}
+
+/*
+ * true if before < after, false if before >= after
+ */
+static bool IsBefore(const struct tm *before, const struct tm *after)
+{
+    if (before->tm_year > after->tm_year)
+    {
+        return false;
+    }
+
+    if (before->tm_year == after->tm_year)
+    {
+        if (before->tm_mon > after->tm_mon)
+        {
+            return false;
+        }
+
+        if (before->tm_mon == after->tm_mon)
+        {
+            if (before->tm_mday > after->tm_mday)
+            {
+                return false;
+            }
+
+            if (before->tm_mday == after->tm_mday)
+            {
+                if (before->tm_hour > after->tm_hour)
+                {
+                    return false;
+                }
+
+                if (before->tm_hour == after->tm_hour)
+                {
+                    if (before->tm_min > after->tm_min)
+                    {
+                        return false;
+                    }
+
+                    if (before->tm_min == after->tm_min)
+                    {
+                        return (before->tm_sec < after->tm_sec);
+                    }
+                }
+            }
+        }
+    }
+
+    return true;
+}
+
+OCStackResult GetEndpointRoles(const CAEndpoint_t *endpoint, OicSecRole_t **roles, size_t *roleCount)
+{
+    VERIFY_NOT_NULL_RETURN(TAG, endpoint, ERROR, OC_STACK_INVALID_PARAM);
+    VERIFY_NOT_NULL_RETURN(TAG, roles, ERROR, OC_STACK_INVALID_PARAM);
+    VERIFY_NOT_NULL_RETURN(TAG, roleCount, ERROR, OC_STACK_INVALID_PARAM);
+
+    uint8_t *publicKey = NULL;
+    size_t publicKeyLength = 0;
+    RolesEntry_t *targetEntry = NULL;
+    OicSecRole_t *rolesToReturn = NULL;
+    size_t rolesToReturnCount = 0;
+    ByteArray_t trustedCaCerts;
+    memset(&trustedCaCerts, 0, sizeof(trustedCaCerts));
+
+    OCStackResult res = GetPeerPublicKeyFromEndpoint(endpoint, &publicKey, &publicKeyLength);
+    if (OC_STACK_INVALID_PARAM == res)
+    {
+        /*
+         * OC_STACK_INVALID_PARAM means the endpoint didn't authenticate with a certificate.
+         * Succeed and return no roles.
+         */
+        *roles = NULL;
+        *roleCount = 0;
+        return OC_STACK_OK;
+    }
+    else if (OC_STACK_OK != res)
+    {
+        /* Any other error is a fatal error. */
+        OIC_LOG_V(ERROR, TAG, "Could not GetPeerPublicKeyFromEndpoint: %d", res);
+        return res;
+    }
+
+    for (targetEntry = gRoles; NULL != targetEntry; targetEntry = targetEntry->next)
+    {
+        if ((targetEntry->publicKeyLength == publicKeyLength) &&
+            (0 == memcmp(targetEntry->publicKey, publicKey, publicKeyLength)))
+        {
+            break;
+        }
+    }
+
+    if (NULL == targetEntry)
+    {
+        /* No roles for this peer. */
+        *roles = NULL;
+        *roleCount = 0;
+        OICFree(publicKey);
+        return OC_STACK_OK;
+    }
+
+    /* Is the cache still valid? */
+    struct tm now;
+    memset(&now, 0, sizeof(now));
+#ifndef WITH_ARDUINO /* No reliable time on Arduino, so assume the cache is valid if present. */
+    time_t nowTimeT = 0;
+    nowTimeT = time(NULL);
+    /* If we failed to get the current time, assume the cache is valid if present. */
+    if ((time_t)-1 != nowTimeT)
+    {
+        /* gmtime_{s,r} should not ever fail. */
+#ifdef HAVE_WINDOWS_H
+        if (0 != gmtime_s(&now, &nowTimeT))
+        {
+            assert(!"gmtime_s failed");
+            OIC_LOG(WARNING, TAG, "gmtime_s failed; assuming role cache is valid");
+            memset(&now, 0, sizeof(now));
+        }
+#else
+        if (NULL == gmtime_r(&nowTimeT, &now))
+        {
+            assert(!"gmtime_r failed");
+            OIC_LOG(WARNING, TAG, "gmtime_r failed; assuming role cache is valid");
+            memset(&now, 0, sizeof(now));
+        }
+#endif
+    }
+#endif /* WITH_ARDUINO */
+
+    if (IsBefore(&now, &targetEntry->cacheValidUntil))
+    {
+        /* now < cacheValidUntil: provide caller with a copy of the cached roles */
+        *roles = (OicSecRole_t *)OICCalloc(targetEntry->cachedRolesLength, sizeof(OicSecRole_t));
+        if (NULL == *roles)
+        {
+            OICFree(publicKey);
+            return OC_STACK_NO_MEMORY;
+        }
+        memcpy(*roles, targetEntry->cachedRoles, (targetEntry->cachedRolesLength * sizeof(OicSecRole_t)));
+        *roleCount = targetEntry->cachedRolesLength;
+
+        OICFree(publicKey);
+        return OC_STACK_OK;
+    }
+
+    InvalidateRoleCache(targetEntry);
+
+    /* Retrieve the current set of trusted CAs from the cred resource. */
+    res = GetPemCaCert(&trustedCaCerts, TRUST_CA);
+    if (OC_STACK_OK != res)
+    {
+        OIC_LOG_V(ERROR, TAG, "Could not get CA certs: %d", res);
+        OICFree(publicKey);
+        return res;
+    }
+
+    for (const RoleCertChain_t *chain = targetEntry->chains; NULL != chain; chain = chain->next)
+    {
+        OicSecRole_t *currCertRoles = NULL;
+        size_t currCertRolesCount = 0;
+        struct tm notValidAfter;
+        memset(&notValidAfter, 0, sizeof(notValidAfter));
+
+        res = OCInternalVerifyRoleCertificate(&chain->certificate, &chain->optData,
+                                              trustedCaCerts.data, trustedCaCerts.len,
+                                              &currCertRoles, &currCertRolesCount,
+                                              &notValidAfter);
+
+        if (OC_STACK_OK != res)
+        {
+            OIC_LOG_V(ERROR, TAG, "Failed to verify a role certificate: %d", res);
+            /* Don't exit; try all certificates presented. */
+        }
+        else
+        {
+            /* Add returned roles to current list. */
+            OicSecRole_t *savePtr = rolesToReturn;
+            rolesToReturn = (OicSecRole_t *)OICRealloc(rolesToReturn,
+                sizeof(rolesToReturn[0]) * (rolesToReturnCount + currCertRolesCount));
+            if (NULL == rolesToReturn)
+            {
+                OIC_LOG(ERROR, TAG, "No memory reallocating rolesToReturn");
+                memset(&targetEntry->cacheValidUntil, 0, sizeof(targetEntry->cacheValidUntil));
+                OICFree(trustedCaCerts.data);
+                OICFree(savePtr);
+                OICFree(currCertRoles);
+                OICFree(publicKey);
+                return OC_STACK_NO_MEMORY;
+            }
+            memcpy(rolesToReturn + (rolesToReturnCount * sizeof(rolesToReturn[0])), 
+                currCertRoles, 
+                currCertRolesCount * sizeof(currCertRoles[0]));
+            rolesToReturnCount += currCertRolesCount;
+            OICFree(currCertRoles);
+        }
+
+        /* 
+         * Set the cacheValidUntil value to be the earliest notValidUntil date amongst
+         * all the certificates.
+         *
+         * Assumption is that if tm_year is zero, the cacheValidUntil is all zero, and so the
+         * cacheValidUntil value hasn't yet been set. tm_year of 0 means the year 1900, and we
+         * should never see this value in a certificate.
+         */
+        if ((0 == targetEntry->cacheValidUntil.tm_year) ||
+            IsBefore(&notValidAfter, &targetEntry->cacheValidUntil))
+        {
+            memcpy(&targetEntry->cacheValidUntil, &notValidAfter, sizeof(targetEntry->cacheValidUntil));
+        }
+    }
+
+    targetEntry->cachedRoles = rolesToReturn;
+    targetEntry->cachedRolesLength = rolesToReturnCount;
+
+    /* Make a copy for the caller. */
+    *roles = (OicSecRole_t *)OICCalloc(targetEntry->cachedRolesLength, sizeof(OicSecRole_t));
+    if (NULL == *roles)
+    {
+        OICFree(publicKey);
+        OICFree(trustedCaCerts.data);
+        return OC_STACK_NO_MEMORY;
+    }
+    memcpy(*roles, targetEntry->cachedRoles, (targetEntry->cachedRolesLength * sizeof(OicSecRole_t)));
+    *roleCount = targetEntry->cachedRolesLength;
+
+    OICFree(publicKey);
+    OICFree(trustedCaCerts.data);
+    return OC_STACK_OK;
+}
+
+#endif /* defined(__WITH_DTLS__) || defined(__WITH_TLS__) */
\ No newline at end of file
index f725a6f..a4424a2 100644 (file)
@@ -481,12 +481,14 @@ bool SRMIsSecurityResourceURI(const char* uri)
         OIC_RSRC_AMACL_URI,
         OIC_RSRC_CRL_URI,
         OIC_RSRC_CRED_URI,
+        OIC_RSRC_CSR_URI,
         OIC_RSRC_ACL_URI,
         OIC_RSRC_DOXM_URI,
         OIC_RSRC_PSTAT_URI,
         OIC_RSRC_PCONF_URI,
         OIC_RSRC_DPAIRING_URI,
         OIC_RSRC_VER_URI,
+        OIC_RSRC_ROLES_URI,
         OC_RSRVD_PROV_CRL_URL
     };
 
@@ -576,6 +578,15 @@ OicSecSvrType_t GetSvrTypeFromUri(const char* uri)
         }
     }
 
+    svrLen = strlen(OIC_RSRC_CSR_URI);
+    if (uriLen == svrLen)
+    {
+        if (0 == strncmp(uri, OIC_RSRC_CSR_URI, svrLen))
+        {
+            return OIC_R_CSR_TYPE;
+        }
+    }
+
     svrLen = strlen(OIC_RSRC_DOXM_URI);
     if (uriLen == svrLen)
     {
@@ -612,6 +623,15 @@ OicSecSvrType_t GetSvrTypeFromUri(const char* uri)
         }
     }
 
+    svrLen = strlen(OIC_RSRC_ROLES_URI);
+    if (uriLen == svrLen)
+    {
+        if (0 == strncmp(uri, OIC_RSRC_ROLES_URI, svrLen))
+        {
+            return OIC_R_ROLES_TYPE;
+        }
+    }
+
     svrLen = strlen(OIC_RSRC_SVC_URI);
     if (uriLen == svrLen)
     {
index 3d4b913..becb1be 100644 (file)
@@ -37,6 +37,10 @@ const char * OIC_JSON_ACL_NAME = "acl";
 const char * OIC_JSON_ACLIST_NAME = "aclist";
 const char * OIC_JSON_ACES_NAME = "aces";
 
+const char * OIC_RSRC_TYPE_SEC_ACL2 = "oic.r.acl2";
+const char * OIC_RSRC_ACL2_URI = "/oic/sec/acl2";
+const char * OIC_JSON_ACL2_NAME = "acl2";
+
 //Pstat
 const char * OIC_RSRC_TYPE_SEC_PSTAT = "oic.r.pstat";
 const char * OIC_RSRC_PSTAT_URI =  "/oic/sec/pstat";
@@ -53,6 +57,16 @@ const char * OIC_RSRC_CRED_URI =  "/oic/sec/cred";
 const char * OIC_JSON_CRED_NAME = "cred";
 const char * OIC_JSON_CREDS_NAME = "creds";
 
+//CSR
+const char * OIC_RSRC_TYPE_SEC_CSR = "oic.r.csr";
+const char * OIC_RSRC_CSR_URI = "/oic/sec/csr";
+const char * OIC_JSON_CSR_NAME = "csr";
+
+//roles
+const char * OIC_RSRC_TYPE_SEC_ROLES = "oic.r.roles";
+const char * OIC_RSRC_ROLES_URI = "/oic/sec/roles";
+const char * OIC_JSON_ROLES_NAME = "roles";
+
 //CRL
 const char * OIC_RSRC_TYPE_SEC_CRL = "oic.r.crl";
 const char * OIC_RSRC_CRL_URI =  "/oic/sec/crl";
@@ -115,6 +129,7 @@ const char * OIC_JSON_SM_NAME = "sm";
 const char * OIC_JSON_CREDID_NAME = "credid";
 const char * OIC_JSON_SUBJECTID_NAME = "subjectuuid";
 const char * OIC_JSON_ROLEIDS_NAME = "roleid";
+const char * OIC_JSON_AUTHORITY_NAME = "authority";
 const char * OIC_JSON_CREDTYPE_NAME = "credtype";
 const char * OIC_JSON_PUBLICDATA_NAME = "publicdata";
 const char * OIC_JSON_PRIVATEDATA_NAME = "privatedata";
@@ -157,6 +172,7 @@ const char * OIC_JSON_EMPTY_STRING = "";
 // Certificates provided by Cloud
 const char * TRUST_CA = "oic.sec.cred.trustca";
 const char * PRIMARY_CERT = "oic.sec.cred.cert";
+const char * PRIMARY_KEY = "primary_key";
 
 // Certificates provided by manufacturer
 const char * MF_TRUST_CA = "oic.sec.cred.mfgtrustca";
index da650f0..4fe67c8 100644 (file)
@@ -128,7 +128,7 @@ static void ConvertJsonToCBOR(const char *jsonFileName, const char *cborFileName
     {
         OicSecAcl_t *acl = JSONToAclBin(jsonStr);
         VERIFY_NOT_NULL(TAG, acl, FATAL);
-        ret = AclToCBORPayload(acl, &aclCbor, &aclCborSize);
+        ret = AclToCBORPayload(acl, OIC_SEC_ACL_V2, &aclCbor, &aclCborSize);
         if(OC_STACK_OK != ret)
         {
             OIC_LOG (ERROR, TAG, "Failed converting Acl to Cbor Payload");
@@ -364,6 +364,7 @@ OicSecAcl_t* JSONToAclBin(const char * jsonStr)
                 ret = ConvertStrToUuid(jsonObj->valuestring, &ace->subjectuuid);
                 VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
             }
+            ace->subjectType = OicSecAceUuidSubject;
             // Resources -- Mandatory
             jsonObj = cJSON_GetObjectItem(jsonAcl, OIC_JSON_RESOURCES_NAME);
             VERIFY_NOT_NULL(TAG, jsonObj, ERROR);
index 3ecb643..823cd8e 100644 (file)
@@ -134,7 +134,7 @@ TEST(ACLResourceTest, CBORDefaultACLConversion)
 
     size_t defaultAclSize = 0;
     uint8_t *defaultPsStorage = NULL;
-    OCStackResult convRet = AclToCBORPayload(defaultAcl, &defaultPsStorage, &defaultAclSize);
+    OCStackResult convRet = AclToCBORPayload(defaultAcl, OIC_SEC_ACL_LATEST, &defaultPsStorage, &defaultAclSize);
     EXPECT_EQ(OC_STACK_OK, convRet);
     ASSERT_TRUE(NULL != defaultPsStorage);
     EXPECT_NE(static_cast<size_t>(0), defaultAclSize);
@@ -207,7 +207,7 @@ TEST(ACLResourceTest, CBORACLConversion)
 
     size_t size = 0;
     uint8_t *psStorage = NULL;
-    EXPECT_EQ(OC_STACK_OK, AclToCBORPayload(secAcl, &psStorage, &size));
+    EXPECT_EQ(OC_STACK_OK, AclToCBORPayload(secAcl, OIC_SEC_ACL_V1, &psStorage, &size));
     ASSERT_TRUE(NULL != psStorage);
     OicSecAcl_t *acl = CBORPayloadToAcl(psStorage, size);
     ASSERT_TRUE(NULL != acl);
@@ -419,7 +419,7 @@ TEST(ACLResourceTest, ACLDeleteWithSingleResourceTest)
     //GET CBOR POST payload
     size_t size = 0;
     uint8_t  *payload = NULL;
-    EXPECT_EQ(OC_STACK_OK, AclToCBORPayload(&acl, &payload, &size));
+    EXPECT_EQ(OC_STACK_OK, AclToCBORPayload(&acl, OIC_SEC_ACL_LATEST, &payload, &size));
     ASSERT_TRUE(NULL != payload);
 
     // Security Payload
@@ -474,7 +474,7 @@ TEST(ACLResourceTest, ACLDeleteWithMultiResourceTest)
     //GET CBOR POST payload
     size_t size = 0;
     uint8_t *payload = NULL;
-    EXPECT_EQ(OC_STACK_OK, AclToCBORPayload(&acl, &payload, &size));
+    EXPECT_EQ(OC_STACK_OK, AclToCBORPayload(&acl, OIC_SEC_ACL_LATEST, &payload, &size));
     ASSERT_TRUE(NULL != payload);
 
     // Security Payload
@@ -541,7 +541,7 @@ TEST(ACLResourceTest, ACLGetWithQueryTest)
     //GET CBOR POST payload
     size_t size = 0;
     uint8_t *payload = NULL;
-    EXPECT_EQ(OC_STACK_OK, AclToCBORPayload(&acl, &payload, &size));
+    EXPECT_EQ(OC_STACK_OK, AclToCBORPayload(&acl, OIC_SEC_ACL_LATEST, &payload, &size));
     ASSERT_TRUE(NULL != payload);
 
     // Security Payload
index 0a38f72..1981fdb 100644 (file)
@@ -355,7 +355,7 @@ TEST(CredResourceTest, GenerateAndAddCredentialValidInput)
     OICStrcpy((char *)subject.id, sizeof(subject.id), "subject11");
 
     uint8_t privateKey[] = "My private Key11";
-    OicSecKey_t key = {privateKey, sizeof(privateKey)};
+    OicSecKey_t key = {privateKey, sizeof(privateKey), OIC_ENCODING_RAW};
 
     OicSecCred_t *cred1  = NULL;
     OicSecCred_t *headCred = NULL;
index aa4f1a7..2a43031 100644 (file)
@@ -15,22 +15,34 @@ InputPinCodeCallback
 LoadSecretJustWorksCallback
 
 OCConfigSelfOwnership
+OCConvertDerCSRToPem
 OCDeleteACLList
 OCDeleteDiscoveredDevices
 OCDeletePdAclList
+OCDeleteRoleCertificateByCredId
 OCDeleteUuidList
 OCDiscoverOwnedDevices
 OCDiscoverSingleDevice
 OCDiscoverUnownedDevices
 OCDoOwnershipTransfer
+OCGenerateCACertificate
+OCGenerateIdentityCertificate
+OCGenerateKeyPair
+OCGenerateRandomSerialNumber
+OCGenerateRoleCertificate
 OCGetACLResource
 OCGetCredResource
+OCGetCSRResource
 OCGetDevInfoFromNetwork
 OCGetLinkedStatus
+OCGetPublicKeyFromCSR
+OCGetRolesResource
+OCGetUuidFromCSR
 OCInitPM
 OCPDMCleanupForTimeout
 OCProvisionACL
 OCSaveACL
+OCProvisionCertificate
 OCProvisionCredentials
 OCProvisionDirectPairing
 OCProvisionPairwiseDevices
@@ -43,9 +55,11 @@ OCRemoveTrustCertChainNotifier
 OCResetDevice
 OCResetSVRDB
 OCSaveTrustCertChain
+OCSaveOwnCertChain
 OCSetOwnerTransferCallbackData
 OCUnlinkDevices
 OCSetOxmAllowStatus
+OCVerifyCSRSignature 
 
 SetClosePinDisplayCB
 SetDisplayPinWithContextCB