[IOT-1785] Finish OCF 1.0 identity certificate support
authorGreg Zaverucha <gregz@microsoft.com>
Wed, 29 Mar 2017 00:23:07 +0000 (17:23 -0700)
committerNathan Heldt-Sheller <nathan.heldt-sheller@intel.com>
Wed, 29 Mar 2017 19:22:16 +0000 (19:22 +0000)
Add unit test to exercise certificate provisioning and use
(previously only provisioning was tested).  Fixed bugs in
credresource and ca_adapter_net_ssl. Configure mbedtls to use
 OCF certificate EKUs. Added more logging in many places. Exposed
 API to remove credentials locally for use by test code.

Change-Id: Ia55c7f3a7518f12c99f60280062f156954bdf4ac
Signed-off-by: Greg Zaverucha <gregz@microsoft.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/17983
Reviewed-by: Kevin Kane <kkane@microsoft.com>
Reviewed-by: Dmitriy Zhuravlev <d.zhuravlev@samsung.com>
Reviewed-by: Alex Kelley <alexke@microsoft.com>
Tested-by: jenkins-iotivity <jenkins@iotivity.org>
Reviewed-by: Dave Thaler <dthaler@microsoft.com>
Reviewed-by: Nathan Heldt-Sheller <nathan.heldt-sheller@intel.com>
18 files changed:
resource/csdk/connectivity/src/adapter_util/ca_adapter_net_ssl.c
resource/csdk/connectivity/src/camessagehandler.c
resource/csdk/connectivity/test/ssladapter_test.cpp
resource/csdk/security/include/internal/credresource.h
resource/csdk/security/provisioning/include/internal/secureresourceprovider.h
resource/csdk/security/provisioning/include/ocprovisioningmanager.h
resource/csdk/security/provisioning/sample/autoprovisioningclient.c
resource/csdk/security/provisioning/sample/provisioningTest.py
resource/csdk/security/provisioning/sample/provisioningclient.c
resource/csdk/security/provisioning/src/ocprovisioningmanager.c
resource/csdk/security/provisioning/src/secureresourceprovider.c
resource/csdk/security/src/certhelpers.c
resource/csdk/security/src/credresource.c
resource/csdk/security/src/csrresource.c
resource/csdk/security/src/pkix_interface.c
resource/csdk/security/src/policyengine.c
resource/csdk/security/src/srmresourcestrings.c
resource/csdk/stack/octbstack_product_secured.def

index 9261663..0d0e996 100755 (executable)
@@ -97,6 +97,7 @@
 /**
  * @def MMBED_TLS_DEBUG_LEVEL
  * @brief Logging level for mbedTLS library
+ * Level 1 logs errors only, level 4 is verbose logging.
  */
 #define MBED_TLS_DEBUG_LEVEL (4)
 
@@ -200,6 +201,12 @@ if (g_sslCallback)
     g_sslCallback(&(peer)->sep.endpoint, &errorInfo);                                              \
 }
 
+/* OCF-defined EKU value indicating an identity certificate, that can be used for
+ * TLS client and server authentication.  This is the DER encoding of the OID
+ * 1.3.6.1.4.1.44924.1.6.
+ */
+static const unsigned char EKU_IDENTITY[] = { 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0xDE, 0x7C, 0x01, 0x06 };
+
 /**@def CONF_SSL(clientConf, serverConf, fn, ...)
  *
  * Calls \a fn for \a clientConf and \a serverConf.
@@ -673,6 +680,22 @@ static int InitPKIX(CATransportAdapter_t adapter)
         goto required;
     }
 
+    /* If we get here, certificates could be used, so configure OCF EKUs. */
+    ret = mbedtls_ssl_conf_ekus(serverConf, (const char*)EKU_IDENTITY, sizeof(EKU_IDENTITY),
+        (const char*)EKU_IDENTITY, sizeof(EKU_IDENTITY));
+    if (0 == ret)
+    {
+        ret = mbedtls_ssl_conf_ekus(clientConf, (const char*)EKU_IDENTITY, sizeof(EKU_IDENTITY),
+            (const char*)EKU_IDENTITY, sizeof(EKU_IDENTITY));
+    }
+    if (0 != ret)
+    {
+        /* Cert-based ciphersuites will fail, but if PSK ciphersuites are in
+         * the list they might work, so don't return error.
+         */
+        OIC_LOG(WARNING, NET_SSL_TAG, "EKU configuration error");
+    }
+
     required:
     count = ParseChain(&g_caSslContext->ca, g_pkiInfo.ca.data, g_pkiInfo.ca.len, &errNum);
     if(0 >= count)
@@ -734,6 +757,9 @@ static int GetPskCredentialsCallback(void * notUsed, mbedtls_ssl_context * ssl,
         OIC_LOG(DEBUG, NET_SSL_TAG, "PSK:");
         OIC_LOG_BUFFER(DEBUG, NET_SSL_TAG, keyBuf, ret);
 
+        OIC_LOG(DEBUG, NET_SSL_TAG, "Identity:");
+        OIC_LOG_BUFFER(DEBUG, NET_SSL_TAG, desc, descLen);
+
         OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
         return(mbedtls_ssl_set_hs_psk(ssl, keyBuf, ret));
     }
@@ -2026,15 +2052,11 @@ CAResult_t CAdecryptSsl(const CASecureEndpoint_t *sep, uint8_t *data, size_t dat
                 /* Find the CN component of the subject name. */
                 for (name = &peerCert->subject; NULL != name; name = name->next)
                 {
-                    if (!name->oid.p)
-                    {
-                        continue;
-                    }
-
-                    if ((name->oid.len < MBEDTLS_OID_SIZE(MBEDTLS_OID_AT_CN) ||
-                        (0 != memcmp(MBEDTLS_OID_AT_CN, name->oid.p, name->oid.len))))
+                    if (name->oid.p &&
+                       (name->oid.len <= MBEDTLS_OID_SIZE(MBEDTLS_OID_AT_CN)) &&
+                       (0 == memcmp(MBEDTLS_OID_AT_CN, name->oid.p, name->oid.len)))
                     {
-                        continue;
+                        break;
                     }
                 }
 
index daef640..f29b3ea 100755 (executable)
@@ -178,6 +178,10 @@ static CAData_t* CAGenerateHandlerData(const CAEndpoint_t *endpoint,
         {
             info->identity = *identity;
         }
+        else
+        {
+            OIC_LOG_V(INFO, TAG, "%s: No identity information provided", __func__);
+        }
         OIC_LOG(DEBUG, TAG, "Response Info :");
         CALogPayloadInfo(info);
     }
index e00e929..e805d61 100644 (file)
@@ -85,7 +85,6 @@
 #include "platform_features.h"
 #include "logger.h"
 
-#define MBED_TLS_DEBUG_LEVEL (4) // Verbose
 
 #define SEED "PREDICTED_SEED"
 #define dummyHandler 0xF123
index 64b1830..876af2f 100644 (file)
@@ -124,11 +124,14 @@ OicSecCred_t * GenerateCredential(const OicUuid_t* subject, OicSecCredType_t cre
 OCStackResult AddCredential(OicSecCred_t * cred);
 
 /**
- * Function to remove the credential from SVR DB.
+ * Function to remove credentials from the SVR DB for the given subject UUID.
+ * If multiple credentials exist for the UUID, they will all be removed. 
  *
  * @param subject is the Credential Subject to be deleted.
  *
- * @return ::OC_STACK_OK for success, or errorcode otherwise.
+ * @return ::OC_STACK_RESOURCE_DELETED if credentials were removed, or 
+ * if there are no credentials with the given UUID.  An error is returned if
+ * removing credentials failed. 
  */
 OCStackResult RemoveCredential(const OicUuid_t *subject);
 
index f4cd241..3a140c8 100644 (file)
@@ -143,7 +143,7 @@ OCStackResult SRPProvisionTrustCertChain(void *ctx, OicSecCredType_t type, uint1
  * @param[out] credId CredId of saved trust certificate chain in Cred of SVR.
  * @return  OC_STACK_OK in case of success and other value otherwise.
  */
-OCStackResult SRPSaveTrustCertChain(uint8_t *trustCertChain, size_t chainSize,
+OCStackResult SRPSaveTrustCertChain(const uint8_t *trustCertChain, size_t chainSize,
                                         OicEncodingType_t encodingType,uint16_t *credId);
 
 /**
index 106bdc7..790a55b 100644 (file)
@@ -540,6 +540,16 @@ OCStackResult OCGetLinkedStatus(const OicUuid_t* uuidOfDevice,
                                   size_t* numOfDevices);\r
 \r
 /**\r
+ * Remove locally stored credentials with the specified subject UUID.\r
+ *\r
+ * @param[in] subjectUuid The subject UUID of the credentials to remove\r
+ *\r
+ * @return OC_STACK_RESOURCE_DELETED if credentials were removed, or
+ * OC_STACK_ERROR if no credentials were removed.\r
+ */\r
+OCStackResult OCRemoveCredential(const OicUuid_t* subjectUuid);\r
+\r
+/**\r
  * API to delete memory allocated to linked list created by OCDiscover_XXX_Devices API.\r
  *\r
  * @param[in] pList Pointer to OCProvisionDev_t which should be deleted.\r
@@ -604,8 +614,8 @@ OCStackResult OCProvisionTrustCertChain(void *ctx, OicSecCredType_t type, uint16
  * @param[out] credId CredId of saved trust certificate chain in Cred of SVR.\r
  * @return  OC_STACK_OK in case of success and other value otherwise.\r
  */\r
-OCStackResult OCSaveTrustCertChain(uint8_t *trustCertChain, size_t chainSize,\r
-                                        OicEncodingType_t encodingType, uint16_t *credId);\r
+OCStackResult OCSaveTrustCertChain(const 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
@@ -615,7 +625,7 @@ OCStackResult OCSaveTrustCertChain(uint8_t *trustCertChain, size_t chainSize,
  * @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
+OCStackResult OCSaveOwnCertChain(const char* cert, const char* key, uint16_t *credId);\r
 \r
 /**\r
  * function to register callback, for getting notification for TrustCertChain change.\r
index 4766c31..783d542 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <stdint.h>
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
 #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"
+#include "occertutility.h"
+#include "pmutility.h"
 
 #ifdef _MSC_VER
 #include <io.h>
@@ -71,6 +70,9 @@ 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";
 
+static const char* TEST_CERT_NOT_BEFORE = "20170101000000"; // Not before field for certificates, in format YYYYMMDDhhmmss
+static const 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
@@ -81,21 +83,45 @@ 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 char* g_csr;    /* Certificate signing request from device */
+static OicUuid_t g_uuidDev1;
 
 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 int saveUuid(const OCProvisionResult_t* rslt_lst, const size_t rslt_cnt);
 static FILE* fopen_prvnMng(const char*, const char*);
 static int waitCallbackRet(void);
 
+/*
+ * Test CA key and certificate created with
+ * iotivity/resource/csdk/security/scripts/test_cert_generation.sh
+ */
+static const char* g_caCertPem = "-----BEGIN CERTIFICATE-----\n"\r
+"MIIBfjCCASSgAwIBAgIJAPQXoGTceaW5MAoGCCqGSM49BAMCMBkxFzAVBgNVBAoM\n"\r
+"DklvVGl2aXR5VGVzdENBMB4XDTE3MDMxNTAwNTExOVoXDTMwMTEyMjAwNTExOVow\n"\r
+"GTEXMBUGA1UECgwOSW9UaXZpdHlUZXN0Q0EwWTATBgcqhkjOPQIBBggqhkjOPQMB\n"\r
+"BwNCAARvYPdt+LjqASlHoc2zrjo3hHGjZsI31c+bg9AwINW5TuRZsE03w/Ejotza\n"\r
+"y4VDLImMlDhGP+K/f6OmKD3FNHhKo1UwUzAhBgNVHSUEGjAYBgorBgEEAYLefAEG\n"\r
+"BgorBgEEAYLefAEHMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNw+hm69Rxb5\n"\r
+"UpclERf5r85g1nwmMAoGCCqGSM49BAMCA0gAMEUCIQDbvNLA3ZkwEzuoH6XUR6JS\n"\r
+"UzZTVgsDgnJcOqtqOg0qEAIgUJR2g8XlMxqiuXP7JdwALdtnvCQTlJQbuD1gu+Jy\n"\r
+"AdQ=\n"\r
+"-----END CERTIFICATE-----\n";
+
+static const char* g_caKeyPem = "-----BEGIN EC PRIVATE KEY-----\n"\r
+"MHcCAQEEILx9VOHDrMYuan6SXN4CQIHHXNq6SjzanaDFDgIaOaXloAoGCCqGSM49\n"\r
+"AwEHoUQDQgAEb2D3bfi46gEpR6HNs646N4Rxo2bCN9XPm4PQMCDVuU7kWbBNN8Px\n"\r
+"I6Lc2suFQyyJjJQ4Rj/iv3+jpig9xTR4Sg==\n"\r
+"-----END EC PRIVATE KEY-----\n";
+
+
 /* 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
@@ -104,10 +130,14 @@ static int waitCallbackRet(void);
 // callback function(s) for provisioning client using C-level provisioning API
 static void ownershipTransferCB(void* ctx, size_t nOfRes, OCProvisionResult_t* arr, bool hasError)
 {
+    g_successCB = false;
     if(!hasError)
     {
         OIC_LOG_V(INFO, TAG, "Ownership Transfer SUCCEEDED - ctx: %s", (char*) ctx);
-        g_successCB = true;
+        if (saveUuid((const OCProvisionResult_t*)arr, nOfRes) == 0)
+        {
+            g_successCB = true;
+        }
     }
     else
     {
@@ -155,26 +185,43 @@ static void getCsrForCertProvCB(void* ctx, size_t nOfRes, OCPMGetCsrResult_t* ar
 {
     g_successCB = false;
 
-    if(!hasError)
+    if (!hasError)
     {
-        if(nOfRes != 1)
+        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)
+        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)
         {
-            OIC_LOG_V(ERROR, TAG, "Couldn't parse CSR: %d", ret);
-            mbedtls_x509_csr_free(&g_csr);
+            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;
         }
-
-        OIC_LOG(INFO, TAG, "getCsrForCertProvCB success");
-        g_successCB = true;
     }
     else
     {
@@ -185,6 +232,48 @@ exit:
     g_doneCB = true;
 }
 
+OCStackApplicationResult getReqCB(void* ctx, OCDoHandle handle,
+    OCClientResponse* clientResponse)
+{
+    OC_UNUSED(ctx);
+    OC_UNUSED(handle);
+
+    g_doneCB = true;
+    g_successCB = false;
+
+    if (clientResponse == NULL)
+    {
+        OIC_LOG(ERROR, TAG, "getReqCB received NULL clientResponse");
+        return OC_STACK_DELETE_TRANSACTION;
+    }
+
+    if (clientResponse->result != OC_STACK_OK)
+    {
+        OIC_LOG_V(ERROR, TAG, "getReqCB response %d", clientResponse->result);
+        return OC_STACK_DELETE_TRANSACTION;
+    }
+
+    g_successCB = true;
+
+    return OC_STACK_DELETE_TRANSACTION;
+}
+
+static void provisionAclCB(void* ctx, size_t nOfRes, OCProvisionResult_t* arr, bool hasError)
+{
+    if (!hasError)
+    {
+        OIC_LOG_V(INFO, TAG, "Provision ACL SUCCEEDED - ctx: %s", (char*)ctx);
+        g_successCB = true;
+    }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "Provision ACL FAILED - ctx: %s", (char*)ctx);
+        printResultList((const OCProvisionResult_t*)arr, nOfRes);
+        g_successCB = false;
+    }
+    g_doneCB = true;
+}
+
 // function(s) for provisioning client using C-level provisioning API
 static int initProvisionClient(void)
 {
@@ -232,6 +321,27 @@ static int initProvisionClient(void)
     return 0;
 }
 
+/* In some tests we need to close existing sessions after making a change
+ * in order for the effect of the change to take effect. This function shuts
+ * down the OC stack and restarts it.
+ */
+static int closeAllSessions()
+{
+    if (OC_STACK_OK != OCStop())
+    {
+        OIC_LOG_V(ERROR, TAG, "%s: OCStack stop error", __func__);
+        return -1;
+    }
+
+    if (OC_STACK_OK != OCInit(NULL, 0, OC_CLIENT_SERVER))
+    {
+        OIC_LOG_V(ERROR, TAG, "%s: OCStack init error", __func__);
+        return -1;
+    }
+
+    return 0;
+}
+
 static int discoverAllDevices(void)
 {
     // delete un/owned device lists before updating them
@@ -263,7 +373,6 @@ static int discoverAllDevices(void)
     return 0;
 }
 
-
 static int discoverUnownedDevices(void)
 {
     // delete unowned device list before updating it
@@ -346,42 +455,12 @@ static int registerDevices(void)
 
     // 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)
     {
@@ -389,9 +468,9 @@ static int provisionTrustAnchor(int dev_num)
         return -1;
     }
 
-    // Install the CA trust anchor
+    // Install the CA trust anchor locally
     uint16_t caCredId = 0;
-    OCStackResult rst = OCSaveTrustCertChain((uint8_t*)caCertPem, strlen(caCertPem) + 1,
+    OCStackResult rst = OCSaveTrustCertChain((const uint8_t*)g_caCertPem, strlen(g_caCertPem) + 1,
         OIC_ENCODING_PEM, &caCredId);
     if (OC_STACK_OK != rst)
     {
@@ -427,25 +506,17 @@ static int provisionTrustAnchor(int dev_num)
 
 }
 
-static int getCsr(int dev_num)
+/* If csr is not null, a copy will be made, and the caller must free it with OICFree. */
+static int getCsr(int dev_num, char** csr)
 {
-    // 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;
     }
+
+    g_doneCB = false;
     OCStackResult rst = OCGetCSRResource((void*) g_ctx, dev, getCsrForCertProvCB);
     if(OC_STACK_OK != rst)
     {
@@ -463,17 +534,26 @@ static int getCsr(int dev_num)
         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)
+    rst = OCVerifyCSRSignature(g_csr);
+    if(rst != OC_STACK_OK)
     {
         OIC_LOG(ERROR, TAG, "Failed to validate CSR signature");
-        mbedtls_x509_csr_free(&g_csr);
+        OICFreeAndSetToNull(&g_csr);
         return -1;
     }
-#endif
-    mbedtls_x509_csr_free(&g_csr);
+
+    if (csr != NULL)
+    {
+        *csr = OICStrdup(g_csr);
+        if (*csr == NULL)
+        {
+            OIC_LOG(ERROR, TAG, "OICStrdup failed");
+            OICFreeAndSetToNull(&g_csr);
+            return -1;
+        }
+    }
+
+    OICFreeAndSetToNull(&g_csr);
 
     printf("   > Get CSR SUCCEEDED\n");
 
@@ -484,6 +564,532 @@ GETCSR_ERROR:
     return -1;
 }
 
+static int doGetRequest(const char* uri, int dev_num)
+{
+    OCStackResult res;
+    OCCallbackData cbData;
+    OCDoHandle handle;
+    OCProvisionDev_t *device = NULL;
+
+    device = getDevInst(g_own_list, dev_num);
+    if (!device)
+    {
+        OIC_LOG(ERROR, TAG, "Selected device does not exist");
+        return -1;
+    }
+    cbData.context = NULL;
+    cbData.cd = NULL;
+    cbData.cb = &getReqCB;
+    OIC_LOG_V(INFO, TAG, "Performing GET on %s", uri);
+    g_doneCB = false;
+
+    char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = { 0 };
+    if (!PMGenerateQuery(true,
+        device->endpoint.addr,
+        device->securePort,
+        device->connType,
+        query, sizeof(query), uri))
+    {
+        OIC_LOG_V(ERROR, TAG, "%s : Failed to generate query", __func__);
+        return -1;
+    }
+
+    res = OCDoRequest(&handle, OC_REST_GET, query, NULL, NULL,
+        device->connType, OC_HIGH_QOS, &cbData, NULL, 0);
+
+    if (res != OC_STACK_OK)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCDoRequest returned error %d with method", res);
+    }
+    if (waitCallbackRet())  // input |g_doneCB| flag implicitly
+    {
+        OIC_LOG_V(ERROR, TAG, "%s callback error", __func__);
+    }
+    if (g_successCB)
+    {
+        return 0;
+    }
+
+    return -1;
+}
+
+static int provisionCert(int dev_num, char* cert)
+{
+    OCProvisionDev_t* dev = getDevInst((const OCProvisionDev_t*)g_own_list, dev_num);
+    if (!dev)
+    {
+        OIC_LOG(ERROR, TAG, "getDevInst: device instance empty");
+        return -1;
+    }
+
+    printf("   > Provisioning certificate credential to selected device..\n");
+    g_doneCB = false;
+    OCStackResult rst = OCProvisionCertificate((void *)g_ctx, dev, cert, provisionCredCB);
+    if (OC_STACK_OK != rst)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCProvisionCertificate returned error: %d", rst);
+        return -1;
+    }
+    if (waitCallbackRet())
+    {
+        OIC_LOG_V(ERROR, TAG, "%s failed waiting for callback", __func__);
+        return -1;
+    }
+    if (!g_successCB)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s callback completed, but failed", __func__);
+        return -1;
+    }
+
+    printf("   > Provision cert SUCCEEDED\n");
+
+    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);
+
+    return (res == OC_STACK_OK) ? 0 : -1;
+}
+
+static int setupOwnCert(OicUuid_t* inputUuid)
+{
+    OCUUIdentity deviceId = { 0 };
+    uint16_t caCredId;
+    char* serial = NULL;
+    size_t serialLen = 0;
+    char* idPublicKey = NULL;
+    size_t idPublicKeyLen = 0;
+    char* idKey = NULL;
+    size_t idKeyLen = 0;
+    char* idCert = NULL;
+    size_t idCertLen = 0;
+
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
+
+    /* Set our own trust anchor so that we trust certs we've issued. */\r
+    OCStackResult res = OCSaveTrustCertChain((const uint8_t*)g_caCertPem, strlen(g_caCertPem)+1, OIC_ENCODING_PEM, &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, &idPublicKeyLen, &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;
+    }
+
+    OicUuid_t* uuidForCert = inputUuid;
+    OicUuid_t uuid = { 0 };
+    if (inputUuid == NULL)
+    {
+        res = OCGetDeviceId(&deviceId);
+        if (res != OC_STACK_OK)
+        {
+            OIC_LOG_V(ERROR, TAG, "Failed to get own UUID, error: %d", res);
+            goto exit;
+        }
+        memcpy(uuid.id, deviceId.id, sizeof(uuid.id));
+        uuidForCert = &uuid;
+    }
+
+    OIC_LOG(DEBUG, TAG, "Creating own cert with UUID:");
+    printUuid(uuidForCert);
+
+    res = OCGenerateIdentityCertificate(
+        uuidForCert,
+        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(serial);
+    OICFree(idPublicKey);
+    if (idKey != NULL)
+    {
+        OICClearMemory(idKey, idKeyLen);
+        OICFree(idKey);
+    }
+    OICFree(idCert);
+
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+
+    return (res == OC_STACK_OK) ? 0 : -1;
+}
+
+// Caller must call OCDeleteACLList(newAcl)
+static int createLedAcl(OicSecAcl_t** newAcl)
+{
+    int ret = -1;
+    OCUUIdentity ownUuid = { 0 };
+    OicSecAcl_t* acl = NULL;
+    OicSecAce_t* ace = NULL;
+    OicSecRsrc_t* rsrc = NULL;
+    const char* resource = "/a/led";
+    const char* resource_type = "core.led";
+    const char* resource_interface = "oic.if.baseline";
+    uint16_t perms = PERMISSION_FULL_CONTROL;
+
+    /* Create an ACL with one ACE */
+    acl = (OicSecAcl_t*)OICCalloc(1, sizeof(OicSecAcl_t));
+    if (!acl)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s: OICCalloc failed (acl)", __func__);
+        goto exit;
+    }
+    ace = (OicSecAce_t*)OICCalloc(1, sizeof(OicSecAce_t));
+    if (!ace)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s: OICCalloc failed (ace)", __func__);
+        goto exit;
+    }
+    LL_APPEND(acl->aces, ace);
+
+    /* Set uuid to our own */
+    OCStackResult res = OCGetDeviceId(&ownUuid);
+    if (res != OC_STACK_OK)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to get own UUID, error: %d", res);
+        goto exit;
+    }
+    ace->subjectType = OicSecAceUuidSubject;
+    memcpy(ace->subjectuuid.id, ownUuid.id, sizeof(ace->subjectuuid.id));
+
+    OicUuid_t uuid = { 0 };
+    memcpy(uuid.id, ownUuid.id, sizeof(uuid.id));
+    OIC_LOG(DEBUG, TAG, "Creating ACE with UUID:");
+    printUuid(&uuid);
+
+    /* Add a resource (e.g. '/a/led') to the ACE */
+    rsrc = (OicSecRsrc_t*)OICCalloc(1, sizeof(OicSecRsrc_t));
+    if (!rsrc)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s: OICCalloc failed (rsrc)", __func__);
+        goto exit;
+    }
+    LL_APPEND(ace->resources, rsrc);
+    rsrc->href = OICStrdup(resource);
+
+    /* Set resource type, e.g., 'core.led' */
+    rsrc->typeLen = 1;
+    rsrc->types = (char**)OICCalloc(rsrc->typeLen, sizeof(char*));
+    if (!rsrc->types)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s: OICCalloc failed (rsrc->types)", __func__);
+        goto exit;
+    }
+    rsrc->types[0] = OICStrdup(resource_type);
+
+    /* Set interface, e.g., 'oic.if.baseline' */
+    rsrc->interfaceLen = 1;
+    rsrc->interfaces = (char**)OICCalloc(rsrc->interfaceLen, sizeof(char*));
+    if (!rsrc->interfaces)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s: OICCalloc failed (rsrc->interfaces)", __func__);
+        goto exit;
+    }
+    rsrc->interfaces[0] = OICStrdup(resource_interface);
+
+    if (!rsrc->href || !rsrc->types[0] || !rsrc->interfaces[0])
+    {
+        OIC_LOG_V(ERROR, TAG, "%s: OICStrdup failed", __func__);
+        goto exit;
+    }
+
+    /* Set permission for the ACE */
+    ace->permission = perms;
+
+    ret = 0; /* success */
+    *newAcl = acl;
+
+exit:
+
+    if (ret != 0)
+    {
+        *newAcl = NULL;
+        OCDeleteACLList(acl);
+    }
+
+    return ret;
+}
+
+static int provisionAcl(int dev_num, OicSecAcl_t* acl)
+{
+    OCStackResult res = OC_STACK_ERROR;
+
+    OCProvisionDev_t* dev = getDevInst((const OCProvisionDev_t*)g_own_list, dev_num);
+    if (!dev)
+    {
+        OIC_LOG(ERROR, TAG, "getDevInst: device instance empty");
+        goto exit;
+    }
+
+    g_doneCB = false;
+    res = OCProvisionACL((void*)g_ctx, dev, acl, provisionAclCB);
+    if (OC_STACK_OK != res)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCProvisionACL API error: %d", res);
+        goto exit;
+    }
+    if (waitCallbackRet())
+    {
+        OIC_LOG(ERROR, TAG, "OCProvisionACL callback error");
+        goto exit;
+    }
+    if (!g_successCB)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s callback completed, but failed", __func__);
+        goto exit;
+    }
+
+exit:
+
+    return (res == OC_STACK_OK) ? 0 : -1;
+}
+
+
+/* Fucntion to work around IOT-1927.  The ocrandom.h include is only required for the workaround. */
+#include "ocrandom.h"
+int workAroundBug()
+{
+    /* Remove credential for 31313131-3131-3131-3131-313131313131 */
+    const char* uuidStr = "31313131-3131-3131-3131-313131313131";
+    OicUuid_t uuid = { 0 };
+    if (!OCConvertStringToUuid(uuidStr, uuid.id))
+    {
+        OIC_LOG(ERROR, TAG, "UUID conversion failed - caller bug, or the .dat file not longer contains a cred for this UUID. ");
+        return -1;
+    }
+
+    OCStackResult res = OCRemoveCredential(&uuid);
+    if (res != OC_STACK_RESOURCE_DELETED)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s failed to remove credential for subject UUID: ", __func__);
+        OIC_LOG_BUFFER(DEBUG, TAG, uuid.id, UUID_LENGTH);
+        return -1;
+    }
+
+    return 0;
+}
+
+static int testCertUse(int dev_num)
+{
+    char* csr = NULL;
+    char* deviceCert = NULL;
+    const char* uri = "/a/led";
+    OicSecAcl_t* acl = NULL;
+
+    // Make sure we own at least one device to provision
+    if (!g_own_list || g_own_cnt == 0)
+    {
+        OIC_LOG(ERROR, TAG, "Owned device list empty, must discover unowned devices first");
+        return -1;  // Error, we should have registered unowned devices already
+    }
+
+    /* Provision the device with the CA root, and issue it a cert. */
+    if (provisionTrustAnchor(dev_num) != 0)
+    {
+        return -1;
+    }
+
+    if (getCsr(dev_num, &csr) != 0)
+    {
+        return -1;
+    }
+
+    int ret = createIdentityCertFromCSR(g_caKeyPem, g_caCertPem, csr, &deviceCert);
+    if (ret != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to create identity certificate", __func__);
+        goto exit;
+    }
+
+    ret = provisionCert(dev_num, deviceCert);
+    if (ret != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to provision certificate", __func__);
+        goto exit;
+    }
+
+    /* Try a GET request, expecting success because the owner credential is used.*/
+    ret = doGetRequest(uri, dev_num);
+    if (ret != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s failed when requesting %s", __func__, uri);
+        goto exit;
+    }
+
+    ret = createLedAcl(&acl);
+    if (ret != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s failed to create ACL", __func__);
+        goto exit;
+    }
+
+    /* Provision an ACL on the server, allowing us to access '/a/led' with our cert. */
+    ret = provisionAcl(dev_num, acl);
+    if (ret != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s failed to provision ACL", __func__);
+        goto exit;
+    }
+
+    /* Remove the owner credential */
+    OCStackResult res = OCRemoveCredential(&g_uuidDev1);
+    if (res != OC_STACK_RESOURCE_DELETED)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s failed to remove owner credential for subject UUID: ", __func__);
+        OIC_LOG_BUFFER(DEBUG, TAG, g_uuidDev1.id, UUID_LENGTH);
+        ret = -1;
+        goto exit;
+    }
+
+    /*
+     * Work around bug IOT-1927
+     * When that bug is resolved, remove this call and the function workAroundBug
+     */
+    if (workAroundBug() != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s bug workaround failed: ", __func__);
+        ret = -1;
+        goto exit;
+    }
+
+    /* Close all secure sessions, so that we don't re-use a cached session */
+    if (closeAllSessions() != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s Failed to close sessions", __func__);
+        ret = -1;
+        goto exit;
+    }
+
+    /* Try a GET request, expect failure, we don't share a credential. */
+    ret = doGetRequest(uri, dev_num);
+    if (ret == 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s Get request to %s suceeded, but should have failed", __func__, uri);
+        goto exit;
+    }
+
+    /* Provision ourself a valid certificate credential */
+    ret = setupOwnCert(NULL);
+    if (ret != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s Failed to self-provision a key/certificate", __func__);
+        goto exit;
+    }
+
+    /* Close all secure sessions again */
+    if (closeAllSessions() != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s Failed to close sessions", __func__);
+        ret = -1;
+        goto exit;
+    }
+
+
+    /* Try a get request, expect success */
+    ret = doGetRequest(uri, dev_num);
+    if (ret != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s Get request to %s failed, but should have succeeded", __func__, uri);
+        goto exit;
+    }
+
+exit:
+
+    OICFree(csr);
+    OICFree(deviceCert);
+    OCDeleteACLList(acl);
+
+    return ret;
+}
+
+/* Get a specific device from the provided device list. The devices in the list
+ * are numbered starting from 1. */
 static OCProvisionDev_t* getDevInst(const OCProvisionDev_t* dev_lst, const int dev_num)
 {
     if (!dev_lst || 0 >= dev_num)
@@ -502,6 +1108,7 @@ static OCProvisionDev_t* getDevInst(const OCProvisionDev_t* dev_lst, const int d
         lst = lst->next;
     }
 
+    OIC_LOG_V(ERROR, TAG, "%s failed, requested device not found in list (does the device need to be discovered or owned first?)", __func__);
     return NULL;  // in here |lst| is always |NULL|
 }
 
@@ -569,6 +1176,19 @@ static size_t printResultList(const OCProvisionResult_t* rslt_lst, const size_t
     return lst_cnt;
 }
 
+static int saveUuid(const OCProvisionResult_t* rslt_lst, const size_t rslt_cnt)
+{
+    if (!rslt_lst || (rslt_cnt != 1))
+    {
+        OIC_LOG_V(ERROR, TAG, "%s: expected only one device", __func__);
+        return -1;
+    }
+
+    memcpy(&g_uuidDev1, &rslt_lst[0].deviceId, sizeof(OicUuid_t));
+
+    return 0;
+}
+
 static void printUuid(const OicUuid_t* uid)
 {
     for (int i = 0; i<UUID_LENGTH; )
@@ -579,6 +1199,7 @@ static void printUuid(const OicUuid_t* uid)
             printf("-");
         }
     }
+    printf("\n");
 }
 
 static FILE* fopen_prvnMng(const char* path, const char* mode)
@@ -701,9 +1322,37 @@ int TestCSRResource()
     }
 
     /* There should be one owned device with number 1. */
-    if(getCsr(1))
+    if(getCsr(1, NULL))
+    {
+        OIC_LOG(ERROR, TAG, "Failed to get CSR from device");
+        goto exit;
+    }
+
+    ret = 0;
+
+exit:
+
+    shutdownProvisionClient();
+
+    return ret;
+}
+
+int TestCertUse()
+{
+    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 (testCertUse(1))
     {
-        OIC_LOG(ERROR, TAG, "Test1: Failed to get CSR from device");
+        OIC_LOG(ERROR, TAG, "Failed to authenticate to device with certificate");
         goto exit;
     }
 
@@ -732,9 +1381,13 @@ int main(int argc, char** argv)
             return TestTrustAnchorProvisioning();
         case 2:
             return TestCSRResource();
+        case 3:
+            return TestCertUse();
         default:
             printf("%s: Invalid test number\n", argv[0]);
             return 1;
+
+        /* Note: when adding a new test, update NUM_TESTS in provisioningTest.py */
     }
 
 }
index 17a43df..b935496 100644 (file)
@@ -64,7 +64,7 @@ parser.add_argument('--build', nargs='?', choices = ['debug', 'release'], help=
 args = parser.parse_args()
 
 # Number of unit tests in autoprovisioningclient
-NUM_TESTS = 2
+NUM_TESTS = 3
 
 iotivity_base_path = os.getcwd()
 os_name = platform.system()
index acc2eac..3f2fde5 100644 (file)
@@ -875,8 +875,8 @@ static int provisionCred(void)
  *   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
+ *   
+ *   The CA's key and cert are written to g_caKeyPem and g_caCertPem (resp.). 
  */
 static int setupCA()
 {
index 3dbdd68..9dad739 100644 (file)
@@ -1367,6 +1367,11 @@ OCStackResult OCGetLinkedStatus(const OicUuid_t* uuidOfDevice, OCUuidList_t** uu
     return PDMGetLinkedDevices(uuidOfDevice, uuidList, numOfDevices);
 }
 
+OCStackResult OCRemoveCredential(const OicUuid_t* subjectUuid)
+{
+    return RemoveCredential(subjectUuid);
+}
+
 void OCDeleteUuidList(OCUuidList_t* pList)
 {
     PDMDestoryOicUuidLinkList(pList);
@@ -1469,7 +1474,7 @@ OCStackResult OCProvisionTrustCertChain(void *ctx, OicSecCredType_t type, uint16
  * @param[out] credId CredId of saved trust certificate chain in Cred of SVR.
  * @return  OC_STACK_OK in case of success and other value otherwise.
  */
-OCStackResult OCSaveTrustCertChain(uint8_t *trustCertChain, size_t chainSize,
+OCStackResult OCSaveTrustCertChain(const uint8_t *trustCertChain, size_t chainSize,
                                     OicEncodingType_t encodingType, uint16_t *credId)
 {
     return SRPSaveTrustCertChain(trustCertChain, chainSize, encodingType, credId);
@@ -1483,7 +1488,7 @@ OCStackResult OCSaveTrustCertChain(uint8_t *trustCertChain, size_t chainSize,
  * @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)
+OCStackResult OCSaveOwnCertChain(const char* cert, const char* key, uint16_t *credId)
 {
     OicSecKey_t ownCert = { 0 };
     ownCert.data = (uint8_t*) cert;
index fa98950..3ffcea4 100644 (file)
@@ -588,7 +588,7 @@ OCStackResult SRPProvisionTrustCertChain(void *ctx, OicSecCredType_t type, uint1
     return OC_STACK_OK;
 }
 
-OCStackResult SRPSaveTrustCertChain(uint8_t *trustCertChain, size_t chainSize,
+OCStackResult SRPSaveTrustCertChain(const uint8_t *trustCertChain, size_t chainSize,
                                             OicEncodingType_t encodingType, uint16_t *credId)
 {
     OIC_LOG(DEBUG, TAG, "IN SRPSaveTrustCertChain");
index fe6f996..12ab4bf 100644 (file)
@@ -444,7 +444,7 @@ OCStackResult OCInternalIsValidCertChain(const uint8_t *buf, size_t bufLen)
 
 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_PK_ECKEY),             /* Allowed key type */
     MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP256R1),     /* EC curves */
     0                                                   /* RSA minimum key length - not used because we only use EC key pairs */
 };
index 2d80cfa..af2cdc7 100644 (file)
@@ -381,7 +381,7 @@ static CborError SerializeEncodingToCborInternal(CborEncoder *map, const OicSecK
     }
     else
     {
-        OIC_LOG_V(ERROR, TAG, "Unknown encoding type: %u.", value->encoding);
+        OIC_LOG_V(ERROR, TAG, "%s: Unknown encoding type: %u.", __func__, value->encoding);
         return CborErrorUnknownType;
     }
     exit:
@@ -496,7 +496,7 @@ static CborError DeserializeEncodingFromCborInternal(CborValue *map, char *name,
         {
             //For unit test
             value->encoding = OIC_ENCODING_RAW;
-            OIC_LOG(WARNING, TAG, "Unknown encoding type detected.");
+            OIC_LOG_V(WARNING, TAG, "%s: Unknown encoding type detected.", __func__);
         }
         //Because cbor using malloc directly, it is required to use free() instead of OICFree
         free(strEncoding);
@@ -1674,7 +1674,7 @@ exit:
 
 OCStackResult RemoveCredential(const OicUuid_t *subject)
 {
-    OCStackResult ret = OC_STACK_ERROR;
+    OCStackResult ret = OC_STACK_RESOURCE_DELETED;
     OicSecCred_t *cred = NULL;
     OicSecCred_t *tempCred = NULL;
     bool deleteFlag = false;
@@ -1691,9 +1691,9 @@ OCStackResult RemoveCredential(const OicUuid_t *subject)
 
     if (deleteFlag)
     {
-        if (UpdatePersistentStorage(gCred))
+        if (!UpdatePersistentStorage(gCred))
         {
-            ret = OC_STACK_RESOURCE_DELETED;
+            ret = OC_STACK_ERROR;
         }
     }
     return ret;
@@ -2853,36 +2853,51 @@ OCStackResult GetCredRownerId(OicUuid_t *rowneruuid)
 /* 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)
+    const char* pemHeader = "-----BEGIN CERTIFICATE-----"; /* no newlines allowed here */\r
+    const char* pemFooter = "-----END CERTIFICATE-----";
+
+    mbedtls_pem_context ctx;
+    int ret;
+
+    OC_UNUSED(pemLen);
+
+    mbedtls_pem_init(&ctx);
+    size_t usedLen;
+    ret = mbedtls_pem_read_buffer(&ctx, pemHeader, pemFooter, (const uint8_t*) pem, NULL, 0, &usedLen);
+    if (ret != 0)
     {
-        OIC_LOG(ERROR, TAG, "Failed to allocate memory");
-        return -1;
+        OIC_LOG_V(ERROR, TAG, "%s: failed reading PEM cert", __func__);
+        goto exit;
     }
-    size_t outSize = 0;
-    if (B64_OK != b64Decode(pem, pemLen, buf, bufSize, &outSize))
+
+    uint8_t *buf = OICCalloc(1, ctx.buflen);
+    if (NULL == buf)
     {
-        OICFree(buf);
-        OIC_LOG(ERROR, TAG, "Failed to decode base64 data");
-        return -1;
+        OIC_LOG(ERROR, TAG, "Failed to allocate memory");
+        ret = -1;
+        goto exit;
     }
 
+    memcpy(buf, ctx.buf, ctx.buflen);
+
     *der = buf;
-    *derLen = outSize;
+    *derLen = ctx.buflen;
 
-    return 0;
+exit:
+    mbedtls_pem_free(&ctx);
+
+    return ret;
 }
 
 /* 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* pemHeader = "-----BEGIN CERTIFICATE-----\n";\r
     const char* pemFooter = "-----END CERTIFICATE-----\n";
 
     /* Get the length required for output */
     size_t pemLen;
-    int ret = mbedtls_pem_write_buffer(pemHeader, 
+    int ret = mbedtls_pem_write_buffer(pemHeader,
         pemFooter,
         der,
         derLen,
@@ -2903,7 +2918,8 @@ static int ConvertDerCertToPem(const uint8_t* der, size_t derLen, uint8_t** pem)
     }
 
     /* Try the conversion */
-    ret = mbedtls_pem_write_buffer(pemHeader, pemFooter,
+    ret = mbedtls_pem_write_buffer(pemHeader, 
+        pemFooter,
         der,
         derLen,
         *pem,
@@ -2938,7 +2954,7 @@ static OCStackResult GetCaCert(ByteArray_t * crt, const char * usage, OicEncodin
         OIC_LOG_V(ERROR, TAG, "%s: Unsupported encoding %d", __func__, desiredEncoding);
         return OC_STACK_INVALID_PARAM;
     }
-    
+
     crt->len = 0;
     OicSecCred_t* temp = NULL;
 
@@ -2948,14 +2964,23 @@ static OCStackResult GetCaCert(ByteArray_t * crt, const char * usage, OicEncodin
             (temp->credUsage != NULL) &&
             (0 == strcmp(temp->credUsage, usage)) && (false == temp->optionalData.revstat))
         {
+
+            if ((OIC_ENCODING_BASE64 != temp->optionalData.encoding) &&
+                (OIC_ENCODING_PEM != temp->optionalData.encoding) &&
+                (OIC_ENCODING_DER != temp->optionalData.encoding))
+            {
+                OIC_LOG_V(WARNING, TAG, "%s: Unknown encoding type", __func__);
+                continue;
+            }
+
             if (OIC_ENCODING_DER == desiredEncoding)
             {
                 if ((OIC_ENCODING_BASE64 == temp->optionalData.encoding) ||
                     (OIC_ENCODING_PEM == temp->optionalData.encoding))
                 {
-                    uint8_t *buf = NULL;
+                    uint8_tbuf = NULL;
                     size_t outSize = 0;
-                    int ret = ConvertPemCertToDer((const char *)temp->optionalData.data, temp->optionalData.len, &buf, &outSize);
+                    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");
@@ -3164,45 +3189,48 @@ void GetDerKey(ByteArray_t * key, const char * usage)
     LL_FOREACH(gCred, temp)
     {
         if ((SIGNED_ASYMMETRIC_KEY == temp->credType || ASYMMETRIC_KEY == temp->credType) && 
+            temp->privateData.len > 0 &&
             NULL != temp->credUsage &&
             0 == strcmp(temp->credUsage, usage))
         {
-            
+
             if (temp->privateData.encoding == OIC_ENCODING_PEM)
             {
                 /* Convert PEM to DER */
-                mbedtls_pk_context ctx;
-                mbedtls_pk_init(&ctx);
+                const char* pemHeader = "-----BEGIN EC PRIVATE KEY-----"; /* no newlines allowed here */\r
+                const char* pemFooter = "-----END EC PRIVATE KEY-----";
 
-                int ret = mbedtls_pk_parse_key(&ctx, temp->privateData.data, temp->privateData.len, NULL, 0);
-                if (ret != 0)
+                if (temp->privateData.data[temp->privateData.len - 1] != 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);
+                    OIC_LOG(ERROR, TAG, "Bad PEM private key data (not null terminated)");
                     return;
                 }
 
-                key->data = OICRealloc(key->data, key->len + temp->privateData.len);
-                if (key->data == NULL)
+                mbedtls_pem_context ctx;
+                int ret;
+                size_t usedLen;
+
+                mbedtls_pem_init(&ctx);
+                ret = mbedtls_pem_read_buffer(&ctx, pemHeader, pemFooter, (const uint8_t*)temp->privateData.data, NULL, 0, &usedLen);
+                if (ret != 0)
                 {
-                    mbedtls_pk_free(&ctx);
-                    OIC_LOG(ERROR, TAG, "Realloc failed to increase key->data length");
+                    OIC_LOG_V(ERROR, TAG, "%s: failed reading PEM key", __func__);
+                    mbedtls_pem_free(&ctx);
                     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 */
+                key->data = OICRealloc(key->data, ctx.buflen);
+                if (NULL == key->data)
                 {
-                    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);
+                    OIC_LOG(ERROR, TAG, "Failed to allocate memory");
+                    mbedtls_pem_free(&ctx);
                     return;
                 }
-                key->data = OICRealloc(key->data, ret);
-                key->len = ret;
+
+                memcpy(key->data, ctx.buf, ctx.buflen);
+                key->len = ctx.buflen;
+                mbedtls_pem_free(&ctx);
                 break;
-                
             }
             else if(temp->privateData.encoding == OIC_ENCODING_DER)
             {
@@ -3214,7 +3242,7 @@ void GetDerKey(ByteArray_t * key, const char * usage)
             }
             else
             {
-                OIC_LOG_V(WARNING, TAG, "Key for %s found, but it has an unknown encoding", usage);
+                OIC_LOG_V(WARNING, TAG, "Key for %s found, but it has an unknown encoding (%d)", usage, temp->privateData.encoding);
             }
         }
     }
index b1105b9..0bee6ea 100644 (file)
@@ -94,7 +94,7 @@ static OCStackResult StoreKeyPair(mbedtls_pk_context *keyPair, const OicUuid_t *
 
     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
+    cred->credUsage = OICStrdup(PRIMARY_CERT);
     VERIFY_NOT_NULL(TAG, cred->credUsage, ERROR);
 
     VERIFY_SUCCESS(TAG, OC_STACK_OK == AddCredential(cred), ERROR);
@@ -394,22 +394,14 @@ static OCEntityHandlerResult HandleCsrGetRequest(OCEntityHandlerRequest * ehRequ
 
     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);
 
+    // Retrieve the key from our current certificate if present, otherwise create a new key
+    GetDerKey(&keyData, PRIMARY_CERT);
+    mbedtls_pk_init(&keyPair);
     if (0 < keyData.len)
     {
         ret = mbedtls_pk_parse_key(&keyPair, keyData.data, keyData.len, NULL, 0);
index 5fffd05..5303efc 100644 (file)
@@ -35,9 +35,25 @@ void GetPkixInfo(PkiInfo_t * inf)
         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
         return;
     }
+
     GetPemOwnCert(&inf->crt, PRIMARY_CERT);
+    if (inf->crt.len == 0)
+    {
+        OIC_LOG_V(WARNING, TAG, "%s: empty certificate", __func__);
+    }
+
     GetDerKey(&inf->key, PRIMARY_CERT);
+    if (inf->key.len == 0)
+    {
+        OIC_LOG_V(WARNING, TAG, "%s: empty key", __func__);
+    }
+
     (void)GetPemCaCert(&inf->ca, TRUST_CA);
+    if (inf->ca.len == 0)
+    {
+        OIC_LOG_V(WARNING, TAG, "%s: empty CA cert", __func__);
+    }
+
     GetDerCrl(&inf->crl);
     OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
 }
index 386bb56..8e959c3 100644 (file)
@@ -115,8 +115,16 @@ static bool IsRequestFromDevOwner(SRMRequestContext_t *context)
     if (doxm)
     {
         retVal = UuidCmp(&doxm->owner, &context->subjectUuid);
-        OIC_LOG_V(DEBUG, TAG, "%s: request was %sreceived from device owner",
+        OIC_LOG_V(DEBUG, TAG, "%s: request was %s received from device owner",
             __func__, retVal ? "" : "NOT ");
+
+        if (!retVal)
+        {
+            OIC_LOG(DEBUG, TAG, "Owner UUID  :");
+            OIC_LOG_BUFFER(DEBUG, TAG, (const uint8_t *)&doxm->owner.id, sizeof(&doxm->owner.id));
+            OIC_LOG(DEBUG, TAG, "Request UUID:");
+            OIC_LOG_BUFFER(DEBUG, TAG, (const uint8_t *)&context->subjectUuid.id, sizeof(&context->subjectUuid.id));
+        }
     }
 
     return retVal;
index 799c2b3..8a07321 100644 (file)
@@ -175,7 +175,6 @@ 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 cbe056a..8bdfdea 100644 (file)
@@ -50,6 +50,7 @@ OCProvisionPairwiseDevices
 OCProvisionTrustCertChain
 OCReadTrustCertChain
 OCRegisterTrustCertChainNotifier
+OCRemoveCredential
 OCRemoveDevice
 OCRemoveDeviceWithUuid
 OCRemoveTrustCertChainNotifier
@@ -59,9 +60,9 @@ OCSaveTrustCertChain
 OCSaveOwnCertChain
 OCSelectOwnershipTransferMethod
 OCSetOwnerTransferCallbackData
-OCUnlinkDevices
 OCSetOxmAllowStatus
-OCVerifyCSRSignature 
+OCUnlinkDevices
+OCVerifyCSRSignature
 
 SetClosePinDisplayCB
 SetDisplayPinWithContextCB