Add PKIX provisioning
authorDmytro Zhuravlev <d.zhuravlev@samsung.com>
Thu, 10 Sep 2015 17:29:30 +0000 (20:29 +0300)
committerSachin Agrawal <sachin.agrawal@intel.com>
Fri, 18 Sep 2015 15:59:46 +0000 (15:59 +0000)
Implementation for certificate, crl resources generation and provisioning

Change-Id: Ib8bd72186da5a0d8314b00f28dbe05cb60d9b344
Signed-off-by: Dmytro Zhuravlev <d.zhuravlev@samsung.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/2453
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: dongik Lee <dongik.lee@samsung.com>
Reviewed-by: Randeep Singh <randeep.s@samsung.com>
Reviewed-by: Sachin Agrawal <sachin.agrawal@intel.com>
resource/csdk/security/provisioning/include/internal/credentialgenerator.h
resource/csdk/security/provisioning/include/ocprovisioningmanager.h
resource/csdk/security/provisioning/src/credentialgenerator.c
resource/csdk/security/provisioning/src/ocprovisioningmanager.c
resource/csdk/security/provisioning/src/secureresourceprovider.c

index 470e820..99fb37d 100644 (file)
@@ -43,6 +43,17 @@ OCStackResult PMGeneratePairWiseCredentials(OicSecCredType_t type, size_t keySiz
                                        OicSecCred_t **firstCred,
                                        OicSecCred_t **secondCred);
 
+/**
+ * Function to generate certificate credentials.
+ *
+ * @param[in]  ptDeviceId     Device ID of provisioning tool.
+ * @param[in]  deviceId       DeviceID of the device.
+ * @param[out] cred           Generated credential for device.
+ * @return  OC_STACK_OK on success
+ */
+OCStackResult PMGenerateCertificateCredentials(const OicUuid_t *ptDeviceId,
+                                          const OicUuid_t *deviceId, OicSecCred_t **cred);
+
 #ifdef __cplusplus
 }
 #endif
index f7169c1..1ec311d 100644 (file)
-/* *****************************************************************\r
- *\r
- * Copyright 2015 Samsung Electronics All Rights Reserved.\r
- *\r
- *\r
- *\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- *     http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- *\r
- * *****************************************************************/\r
-\r
-#ifndef OCPROVISIONINGMANAGER_H_\r
-#define OCPROVISIONINGMANAGER_H_\r
-\r
-#include "octypes.h"\r
-#include "pmtypes.h"\r
-#include "ownershiptransfermanager.h"\r
-\r
-#ifdef __cplusplus\r
-extern "C" {\r
-#endif // __cplusplus\r
-\r
-/**\r
- * The function is responsible for initializaton of the provisioning manager. It will load\r
- * provisioning database which have owned device's list and their linked status.\r
- * In addition, if there is a device(s) which has not up-to-date credentials, this function will\r
- * automatically try to update the deivce(s).\r
- *\r
- * @param[in] dbPath file path of the sqlite3 db\r
- *\r
- * @return OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCProvisionInit(const char* dbPath);\r
-\r
-/**\r
- * The function is responsible for discovery of device is current subnet. It will list\r
- * all the device in subnet which are not yet owned. Please call OCInit with OC_CLIENT_SERVER as\r
- * OCMode.\r
- *\r
- * @param[in] timeout Timeout in seconds, value till which function will listen to responses from\r
- *                    client before returning the list of devices.\r
- * @param[out] ppList List of candidate devices to be provisioned\r
- * @return OTM_SUCCESS in case of success and other value otherwise.\r
- */\r
-OCStackResult OCDiscoverUnownedDevices(unsigned short waittime, OCProvisionDev_t **ppList);\r
-\r
-/**\r
- * Do ownership transfer for un-owned device.\r
- *\r
- * @param[in] ctx Application context would be returned in result callback\r
- * @param[in] targetDevices List of devices to perform ownership transfer.\r
- * @param[in] resultCallback Result callback function to be invoked when ownership transfer finished.\r
- * @return OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCDoOwnershipTransfer(void* ctx,\r
-                                    OCProvisionDev_t *targetDevices,\r
-                                    OCProvisionResultCB resultCallback);\r
-\r
-/**\r
- * API to register for particular OxM.\r
- *\r
- * @param[in] Ownership transfer method.\r
- * @param[in] Implementation of callback functions for owership transfer.\r
- * @return  OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCSetOwnerTransferCallbackData(OicSecOxm_t oxm, OTMCallbackData_t* callbackData);\r
-\r
-/**\r
- * The function is responsible for discovery of owned device is current subnet. It will list\r
- * all the device in subnet which are owned by calling provisioning client.\r
- *\r
- * @param[in] timeout Timeout in seconds, value till which function will listen to responses from\r
- *                    client before returning the list of devices.\r
- * @param[out] ppList List of device owned by provisioning tool.\r
- * @return OTM_SUCCESS in case of success and other value otherwise.\r
- */\r
-OCStackResult OCDiscoverOwnedDevices(unsigned short timeout, OCProvisionDev_t **ppList);\r
-\r
-/**\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] type Type of credentials to be provisioned to the device.\r
- * @param[in] pDev1 Pointer to OCProvisionDev_t instance,respresenting device to be provisioned.\r
- * @param[in] acl ACL for device 1. If this is not required set NULL.\r
- * @param[in] pDev2 Pointer to OCProvisionDev_t instance,respresenting device to be provisioned.\r
- * @param[in] acl ACL for device 2. If this is not required set NULL.\r
- * @param[in] resultCallback callback provided by API user, callback will be called when\r
- *            provisioning request recieves a response from first resource server.\r
- * @return  OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCProvisionPairwiseDevices(void* ctx, OicSecCredType_t type, size_t keySize,\r
-                                         const OCProvisionDev_t *pDev1, OicSecAcl_t *pDev1Acl,\r
-                                         const OCProvisionDev_t *pDev2, OicSecAcl_t *pDev2Acl,\r
-                                         OCProvisionResultCB resultCallback);\r
-\r
-/**\r
- * API to send ACL information to device.\r
- *\r
- * @param[in] ctx Application context would be returned in 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 OCProvisionACL(void *ctx, const OCProvisionDev_t *selectedDeviceInfo, OicSecAcl_t *acl,\r
-                             OCProvisionResultCB resultCallback);\r
-\r
-/**\r
- * API to provision credential to devices.\r
- *\r
- * @param[in] ctx Application context would be returned in result callback.\r
- * @param[in] type Type of credentials to be provisioned to the device.\r
- * @param[in] pDev1 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.\r
-   @param[in] pDev2 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.\r
- * @param[in] resultCallback callback provided by API user, callback will be called when\r
- *            provisioning request recieves a response from first resource server.\r
- * @return  OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCProvisionCredentials(void *ctx, OicSecCredType_t type, size_t keySize,\r
-                                      const OCProvisionDev_t *pDev1,\r
-                                      const OCProvisionDev_t *pDev2,\r
-                                      OCProvisionResultCB resultCallback);\r
-\r
-/**\r
- * API to delete memory allocated to linked list created by OCDiscover_XXX_Devices API.\r
- *\r
- * @param[in] ppList Pointer to OCProvisionDev_t which should be deleted.\r
- */\r
-void OCDeleteDiscoveredDevices(OCProvisionDev_t **ppList);\r
-\r
-/**\r
- * API to delete memory allocated to OCProvisionResult_t list in callback function.\r
- *\r
- * @note: This function must be called in the callback implementation after checking results.\r
- *\r
- * @param[in] pList Pointer to OCProvisionResult_t list which should be deleted.\r
- */\r
-void OCDeleteProvisionResults(OCProvisionResult_t *pList);\r
-\r
-#ifdef __cplusplus\r
-}\r
-#endif // __cplusplus\r
-\r
-#endif /* OCPROVISIONINGMANAGER_H_ */\r
+/* *****************************************************************
+ *
+ * Copyright 2015 Samsung Electronics 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.
+ *
+ * *****************************************************************/
+
+#ifndef OCPROVISIONINGMANAGER_H_
+#define OCPROVISIONINGMANAGER_H_
+
+#include "octypes.h"
+#include "pmtypes.h"
+#include "ownershiptransfermanager.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+/**
+ * The function is responsible for initializaton of the provisioning manager. It will load
+ * provisioning database which have owned device's list and their linked status.
+ * In addition, if there is a device(s) which has not up-to-date credentials, this function will
+ * automatically try to update the deivce(s).
+ *
+ * @param[in] dbPath file path of the sqlite3 db
+ *
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCProvisionInit(const char* dbPath);
+
+/**
+ * The function is responsible for discovery of device is current subnet. It will list
+ * all the device in subnet which are not yet owned. Please call OCInit with OC_CLIENT_SERVER as
+ * OCMode.
+ *
+ * @param[in] timeout Timeout in seconds, value till which function will listen to responses from
+ *                    client before returning the list of devices.
+ * @param[out] ppList List of candidate devices to be provisioned
+ * @return OTM_SUCCESS in case of success and other value otherwise.
+ */
+OCStackResult OCDiscoverUnownedDevices(unsigned short waittime, OCProvisionDev_t **ppList);
+
+/**
+ * Do ownership transfer for un-owned device.
+ *
+ * @param[in] ctx Application context would be returned in result callback
+ * @param[in] targetDevices List of devices to perform ownership transfer.
+ * @param[in] resultCallback Result callback function to be invoked when ownership transfer finished.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCDoOwnershipTransfer(void* ctx,
+                                    OCProvisionDev_t *targetDevices,
+                                    OCProvisionResultCB resultCallback);
+
+/**
+ * API to register for particular OxM.
+ *
+ * @param[in] Ownership transfer method.
+ * @param[in] Implementation of callback functions for owership transfer.
+ * @return  OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCSetOwnerTransferCallbackData(OicSecOxm_t oxm, OTMCallbackData_t* callbackData);
+
+/**
+ * The function is responsible for discovery of owned device is current subnet. It will list
+ * all the device in subnet which are owned by calling provisioning client.
+ *
+ * @param[in] timeout Timeout in seconds, value till which function will listen to responses from
+ *                    client before returning the list of devices.
+ * @param[out] ppList List of device owned by provisioning tool.
+ * @return OTM_SUCCESS in case of success and other value otherwise.
+ */
+OCStackResult OCDiscoverOwnedDevices(unsigned short timeout, OCProvisionDev_t **ppList);
+
+/**
+ * API to provision credentials between two devices and ACLs for the devices who act as a server.
+ *
+ * @param[in] ctx Application context would be returned in result callback.
+ * @param[in] type Type of credentials to be provisioned to the device.
+ * @param[in] pDev1 Pointer to OCProvisionDev_t instance,respresenting device to be provisioned.
+ * @param[in] acl ACL for device 1. If this is not required set NULL.
+ * @param[in] pDev2 Pointer to OCProvisionDev_t instance,respresenting device to be provisioned.
+ * @param[in] acl ACL for device 2. If this is not required set NULL.
+ * @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.
+ */
+OCStackResult OCProvisionPairwiseDevices(void* ctx, OicSecCredType_t type, size_t keySize,
+                                         const OCProvisionDev_t *pDev1, OicSecAcl_t *pDev1Acl,
+                                         const OCProvisionDev_t *pDev2, OicSecAcl_t *pDev2Acl,
+                                         OCProvisionResultCB resultCallback);
+
+/**
+ * API to send ACL information to device.
+ *
+ * @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 OCProvisionACL(void *ctx, const OCProvisionDev_t *selectedDeviceInfo, OicSecAcl_t *acl,
+                             OCProvisionResultCB resultCallback);
+
+/**
+ * API to provision credential to devices.
+ *
+ * @param[in] ctx Application context would be returned in result callback.
+ * @param[in] type Type of credentials to be provisioned to the device.
+ * @param[in] pDev1 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.
+   @param[in] pDev2 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.
+ * @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.
+ */
+OCStackResult OCProvisionCredentials(void *ctx, OicSecCredType_t type, size_t keySize,
+                                      const OCProvisionDev_t *pDev1,
+                                      const OCProvisionDev_t *pDev2,
+                                      OCProvisionResultCB resultCallback);
+
+/**
+ * API to delete memory allocated to linked list created by OCDiscover_XXX_Devices API.
+ *
+ * @param[in] ppList Pointer to OCProvisionDev_t which should be deleted.
+ */
+void OCDeleteDiscoveredDevices(OCProvisionDev_t **ppList);
+
+/**
+ * API to delete memory allocated to OCProvisionResult_t list in callback function.
+ *
+ * @note: This function must be called in the callback implementation after checking results.
+ *
+ * @param[in] pList Pointer to OCProvisionResult_t list which should be deleted.
+ */
+void OCDeleteProvisionResults(OCProvisionResult_t *pList);
+
+#ifdef __WITH_X509__
+/**
+ * this function sends CRL information to resource.
+ *
+ * @param[in] ctx Application context would be returned in result callback.
+ * @param[in] selectedDeviceInfo Selected target device.
+ * @param[in] crl CRL 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 OCProvisionCRL(void* ctx, const OCProvisionDev_t *selectedDeviceInfo, OicSecCrl_t *crl,
+                             OCProvisionResultCB resultCallback);
+#endif // __WITH_X509__
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif /* OCPROVISIONINGMANAGER_H_ */
index 0343627..a5f452b 100644 (file)
 #include <string.h>
 #include "credentialgenerator.h"
 #include "oic_malloc.h"
+#include "oic_string.h"
 #include "logger.h"
 #include "credresource.h"
 #include "ocrandom.h"
 #include "base64.h"
 #include "stdbool.h"
 #include "securevirtualresourcetypes.h"
+#ifdef __WITH_X509__
+#include "ck_manager.h"
+
+#define CHAIN_LEN (2) //TODO: replace by external define or a runtime value
+#endif  //__WITH_X509__
 
 #define TAG "SRPAPI-CG"
 
@@ -112,3 +118,271 @@ bail:
 
     return res;
 }
+
+#ifdef __WITH_X509__
+/**
+ * Function to compose JSON Web Key (JWK) string from a certificate and a public key.
+ *
+ * @param[in]  certificateChain    Array of Base64 encoded certificate strings.
+ * @param[in]  chainLength         Number of the certificates in certificateChain.
+ * @return     Valid JWK string on success, or NULL on fail.
+ */
+static char *CreateCertificatePublicJWK(const char *const *certificateChain,
+                                        const size_t chainLength)
+{
+    if (NULL == certificateChain || chainLength == 0)
+    {
+        OC_LOG(ERROR, TAG, "Error CreateCertificatePublicJWK: Invalid params");
+        return NULL;
+    }
+
+    size_t certChainSize = 0;
+    for (size_t i = 0; i < chainLength; ++i)
+    {
+        if (NULL != certificateChain[i])
+        {
+            certChainSize += strlen(certificateChain[i]);
+        }
+        else
+        {
+            OC_LOG(ERROR, TAG, "Error CreateCertificatePublicJWK: Invalid params");
+            return NULL;
+        }
+
+    }
+    /* certificates in the json array taken in quotes and separated by a comma
+     * so we have to count the number of characters (number of commas and quotes) required
+     * for embedding certificates in the array depending on the number of certificates in chain
+     * each certificate except last embeded in  "\"%s\"," */
+    const int numCommasAndQuotes = chainLength * 3 - 1;
+    const char firstPart[] = "{\"kty\":\"EC\",\"crv\":\"P-256\",\"x5c\":[";
+    const char secondPart[] = "]}";
+    /* to calculate the size of JWK public part we need to add the value of first and  second parts,
+     * size of certificate chain, number of additional commas and quotes and 1 for string termination symbol */
+    size_t certPubJWKLen = strlen(firstPart) + strlen(secondPart)
+                                             + certChainSize + numCommasAndQuotes + 1;
+    char *certPubJWK = (char *)OICMalloc(certPubJWKLen);
+
+    if (NULL != certPubJWK)
+    {
+        OICStrcpy(certPubJWK, certPubJWKLen, firstPart);
+        size_t offset = strlen(firstPart);
+        for (size_t i = 0; i < chainLength; ++i)
+        {
+            offset += sprintf(certPubJWK + offset, "\"%s\",", certificateChain[i]);
+        }
+        sprintf(certPubJWK + offset - 1, secondPart);
+    }
+    else
+    {
+        OC_LOG(ERROR, TAG, "Error while memory allocation");
+    }
+    return certPubJWK;
+}
+
+/**
+ * Function to compose JWK string from a private key.
+ *
+ * @param[in]  privateKey    Base64 encoded private key.
+ * @return     Valid JWK string on success, or NULL on fail.
+ */
+static char *CreateCertificatePrivateJWK(const char *privateKey)
+{
+    if (NULL == privateKey)
+    {
+        OC_LOG(ERROR, TAG, "Error privateKey is NULL");
+        return NULL;
+    }
+    const char firstPart[] = "{\"kty\":\"EC\",\"crv\":\"P-256\",\"d\":\"";
+    const char secondPart[] = "\"}";
+    char *certPrivJWK = (char *)OICMalloc(strlen(firstPart) + strlen(secondPart) + strlen(
+            privateKey) + 1);
+
+    if (NULL != certPrivJWK)
+    {
+        sprintf(certPrivJWK, "%s%s%s", firstPart, privateKey, secondPart);
+    }
+    else
+    {
+        OC_LOG(ERROR, TAG, "Error while memory allocation");
+    }
+    return certPrivJWK;
+}
+
+
+/**
+ * Function to generate Base64 encoded credential data for device.
+ *
+ * @param[in]   subject             Device id.
+ * @param[out]  certificateChain    Pointer to Array of Base64 encoded certificate strings.
+ * @param[out]  chainLength         Pointer to number of the certificates in certificateChain.
+ * @param[out]  privKey             Pointer to Base64 encoded private key.
+ * @return  OC_STACK_OK on success
+ */
+static OCStackResult GenerateCertificateAndKeys(const OicUuid_t * subject, char *** const certificateChain,
+        size_t * const chainLength, char ** const privKey)
+{
+    if (NULL == subject || NULL == certificateChain || NULL == chainLength || NULL == privKey)
+    {
+        return  OC_STACK_INVALID_PARAM;
+    }
+    *certificateChain = NULL;
+    *privKey     = NULL;
+
+    ByteArray pubKeyBA  = BYTE_ARRAY_INITIALIZER;
+    ByteArray privKeyBA = BYTE_ARRAY_INITIALIZER;
+    ByteArray cert[CHAIN_LEN];
+
+    uint8_t pubKeyData[PUBLIC_KEY_SIZE] = {0};
+    uint8_t privKeyData[PRIVATE_KEY_SIZE] = {0};
+    uint8_t certData[ISSUER_MAX_CERT_SIZE * CHAIN_LEN] = {0};
+    uint8_t subjName[UUID_LENGTH + 1] = {0};
+
+    pubKeyBA.data  = pubKeyData;
+    pubKeyBA.len   = PUBLIC_KEY_SIZE;
+    privKeyBA.data = privKeyData;
+    privKeyBA.len  = PRIVATE_KEY_SIZE;
+    for (size_t i = 0; i < CHAIN_LEN; ++i)
+    {
+        cert[i].data      = certData + ISSUER_MAX_CERT_SIZE * i;
+        cert[i].len       = ISSUER_MAX_CERT_SIZE;
+    }
+
+    memcpy(subjName, subject->id, UUID_LENGTH);
+    subjName[UUID_LENGTH] = '\0';
+
+    if (PKI_SUCCESS != GenerateKeyPair(&privKeyBA, &pubKeyBA))
+    {
+        OC_LOG(ERROR, TAG, "Error generating keys.");
+        return OC_STACK_ERROR;
+    }
+    if (PKI_SUCCESS != CKMIssueDeviceCertificate(subjName, NULL, NULL, pubKeyBA.data, cert))
+    {
+        OC_LOG(ERROR, TAG, "Error generating certificate.");
+        return OC_STACK_ERROR;
+    }
+
+    char privB64buf[B64ENCODE_OUT_SAFESIZE(PRIVATE_KEY_SIZE) + 1] = {0};
+    uint32_t privB64len = 0;
+    if (B64_OK != b64Encode(privKeyBA.data,  privKeyBA.len, privB64buf,
+                             B64ENCODE_OUT_SAFESIZE(PRIVATE_KEY_SIZE) + 1, &privB64len))
+    {
+        OC_LOG(ERROR, TAG, "Error while encoding key");
+        return OC_STACK_ERROR;
+    }
+
+    if (PKI_SUCCESS != GetCAChain(chainLength , cert + 1))
+    {
+        OC_LOG(ERROR, TAG, "Error getting CA certificate chain.");
+        return OC_STACK_ERROR;
+    }
+
+    ++(*chainLength);
+    *certificateChain = (char **)OICMalloc(sizeof(char *) * (*chainLength));
+
+    OCStackResult ret = OC_STACK_NO_MEMORY;
+    if (NULL == *certificateChain)
+    {
+        goto memclean;
+    }
+
+
+    for (size_t i = 0; i < *chainLength; ++i)
+    {
+        (*certificateChain)[i] = NULL;
+
+        char certB64buf[B64ENCODE_OUT_SAFESIZE(ISSUER_MAX_CERT_SIZE) + 1] = {0};
+        uint32_t certB64len = 0;
+        if (B64_OK != b64Encode(cert[i].data, cert[i].len, certB64buf,
+                                B64ENCODE_OUT_SAFESIZE(ISSUER_MAX_CERT_SIZE) + 1, &certB64len))
+        {
+            OC_LOG(ERROR, TAG, "Error while encoding certificate");
+            ret = OC_STACK_ERROR;
+            goto memclean;
+        }
+
+        (*certificateChain)[i] = (char *) OICMalloc(certB64len + 1);
+        if (NULL == (*certificateChain)[i])
+        {
+            goto memclean;
+        }
+
+        memcpy((*certificateChain)[i], certB64buf, certB64len + 1);
+    }
+
+
+    *privKey     = (char *)OICMalloc(privB64len + 1);
+
+    if (NULL == *privKey)
+    {
+memclean:
+        if (NULL != *certificateChain)
+        {
+            for (size_t i = 0; i < *chainLength; ++i)
+            {
+                OICFree((*certificateChain)[i]);
+            }
+        }
+        OICFree(*certificateChain);
+        *certificateChain = NULL;
+        *privKey     = NULL;
+        *chainLength = 0;
+        if (OC_STACK_NO_MEMORY == ret)
+        {
+            OC_LOG(ERROR, TAG, "Error while memory allocation");
+        }
+        return ret;
+    }
+
+    memcpy(*privKey, privB64buf, privB64len + 1);
+
+    return OC_STACK_OK;
+}
+
+
+OCStackResult PMGenerateCertificateCredentials(const OicUuid_t *ptDeviceId,
+        const OicUuid_t *deviceId, OicSecCred_t **const cred)
+{
+    if (NULL == ptDeviceId || NULL == deviceId || NULL == cred)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+    char **certificateChain = NULL;
+    char *privKey = NULL;
+    size_t certChainLen = 0;
+    if (OC_STACK_OK != GenerateCertificateAndKeys(deviceId, &certificateChain,
+            &certChainLen, &privKey))
+    {
+        OC_LOG(ERROR, TAG, "Error while generating credential data.");
+        return OC_STACK_ERROR;
+    }
+
+    char *publicJWK = CreateCertificatePublicJWK(certificateChain, certChainLen);
+    char *privateJWK = CreateCertificatePrivateJWK(privKey);
+    for (size_t i = 0; i < certChainLen; ++i)
+    {
+        OICFree(certificateChain[i]);
+    }
+    OICFree(certificateChain);
+    OICFree(privKey);
+    if (NULL == publicJWK || NULL == privateJWK)
+    {
+        OICFree(publicJWK);
+        OICFree(privateJWK);
+        OC_LOG(ERROR, TAG, "Error while converting keys to JWK format.");
+        return OC_STACK_ERROR;
+    }
+
+    OicSecCred_t *tempCred =  GenerateCredential(deviceId, SIGNED_ASYMMETRIC_KEY, publicJWK,
+                              privateJWK, 1, ptDeviceId);
+    OICFree(publicJWK);
+    OICFree(privateJWK);
+    if (NULL == tempCred)
+    {
+        OC_LOG(ERROR, TAG, "Error while generating credential.");
+        return OC_STACK_ERROR;
+    }
+    *cred = tempCred;
+    return OC_STACK_OK;
+}
+#endif // __WITH_X509__
index cdef12d..98b8233 100644 (file)
@@ -400,3 +400,20 @@ OCStackResult OCProvisionPairwiseDevices(void* ctx, OicSecCredType_t type, size_
     return res;
 
 }
+#ifdef __WITH_X509__
+/**
+ * this function sends CRL information to resource.
+ *
+ * @param[in] ctx Application context would be returned in result callback.
+ * @param[in] selectedDeviceInfo Selected target device.
+ * @param[in] crl CRL 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 OCProvisionCRL(void* ctx, const OCProvisionDev_t *selectedDeviceInfo, OicSecCrl_t *crl,
+                             OCProvisionResultCB resultCallback)
+{
+    return SRPProvisionCRL(ctx, selectedDeviceInfo, crl, resultCallback);
+}
+#endif // __WITH_X509__
index f7ebcea..84e15b3 100644 (file)
 #include "pmtypes.h"
 #include "pmutility.h"
 
+#ifdef __WITH_X509__
+#include "crlresource.h"
+#endif // WITH_X509__
+
 #define SRP_MAX_URI_LENGTH 512
 #define TAG "SRPAPI"
 
@@ -280,16 +284,302 @@ static OCStackResult provisionCredentials(const OicSecCred_t *cred,
     return OC_STACK_OK;
 }
 
+#ifdef __WITH_X509__
+/**
+ * Structure to carry certificate data to callback.
+ */
+typedef struct CertificateData CertData_t;
+struct CertificateData
+{
+    void *ctx;                                  /**< Pointer to user context.**/
+    const OCProvisionDev_t *deviceInfo;        /**< Pointer to OCProvisionDev_t.**/
+    OicSecCred_t *credInfo;                     /**< Pointer to OicSecCred_t.**/
+    OCProvisionResultCB resultCallback;         /**< Pointer to result callback.**/
+    OCProvisionResult_t *resArr;                /**< Result array.**/
+    int numOfResults;                           /**< Number of results in result array.**/
+};
+
+/**
+ * Structure to carry CRL provision API data to callback.
+ */
+typedef struct CRLData CRLData_t;
+struct CRLData
+{
+    void *ctx;                                  /**< Pointer to user context.**/
+    const OCProvisionDev_t *deviceInfo;         /**< Pointer to PMDevInfo_t.**/
+    OCProvisionResultCB resultCallback;         /**< Pointer to result callback.**/
+    OCProvisionResult_t *resArr;                /**< Result array.**/
+    int numOfResults;                           /**< Number of results in result array.**/
+};
+
+/**
+ * Internal function to update result in result array.
+ */
+static void registerResultForCertProvisioning(CertData_t *certData,
+                                              OCStackResult stackresult)
+{
+
+   OC_LOG_V(INFO,TAG,"value of credData->numOfResults is %d",certData->numOfResults);
+   memcpy(certData->resArr[(certData->numOfResults)].deviceId.id,
+          certData->deviceInfo->doxm->deviceID.id,UUID_LENGTH);
+   certData->resArr[(certData->numOfResults)].res = stackresult;
+   ++(certData->numOfResults);
+}
+
+/**
+ * Internal Function to store results in result array during ACL provisioning.
+ */
+static void registerResultForCRLProvisioning(CRLData_t *crlData,
+                                             OCStackResult stackresult)
+{
+   OC_LOG_V(INFO, TAG, "Inside registerResultForCRLProvisioning crlData->numOfResults is %d\n",
+                       crlData->numOfResults);
+   memcpy(crlData->resArr[(crlData->numOfResults)].deviceId.id,
+          crlData->deviceInfo->doxm->deviceID.id, UUID_LENGTH);
+   crlData->resArr[(crlData->numOfResults)].res = stackresult;
+   ++(crlData->numOfResults);
+}
+
+
+/**
+ * Callback handler of SRPProvisionCRL.
+ *
+ * @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 SRPProvisionCRLCB(void *ctx, OCDoHandle UNUSED,
+                                                  OCClientResponse *clientResponse)
+{
+    OC_LOG_V(INFO, TAG, "Inside SRPProvisionCRLCB.");
+    (void)UNUSED;
+    VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
+    CRLData_t *crlData = (CRLData_t*)ctx;
+    OCProvisionResultCB resultCallback = crlData->resultCallback;
+
+    if (clientResponse)
+    {
+        if(OC_STACK_RESOURCE_CREATED == clientResponse->result)
+        {
+            registerResultForCRLProvisioning(crlData, OC_STACK_RESOURCE_CREATED);
+            ((OCProvisionResultCB)(resultCallback))(crlData->ctx, crlData->numOfResults,
+                                                    crlData->resArr,
+                                                    false);
+             OICFree(crlData->resArr);
+             OICFree(crlData);
+             return OC_STACK_DELETE_TRANSACTION;
+        }
+    }
+    registerResultForCRLProvisioning(crlData, OC_STACK_ERROR);
+    ((OCProvisionResultCB)(resultCallback))(crlData->ctx, crlData->numOfResults,
+                                            crlData->resArr,
+                                            true);
+    OC_LOG_V(ERROR, TAG, "SRPProvisionCRLCB received Null clientResponse");
+    OICFree(crlData->resArr);
+    OICFree(crlData);
+    return OC_STACK_DELETE_TRANSACTION;
+}
+
+OCStackResult SRPProvisionCRL(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
+        OicSecCrl_t *crl, OCProvisionResultCB resultCallback)
+{
+    VERIFY_NON_NULL(TAG, selectedDeviceInfo, ERROR,  OC_STACK_INVALID_PARAM);
+    VERIFY_NON_NULL(TAG, crl, ERROR,  OC_STACK_INVALID_PARAM);
+    VERIFY_NON_NULL(TAG, resultCallback, ERROR,  OC_STACK_INVALID_CALLBACK);
+
+    OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
+    if (!secPayload)
+    {
+        OC_LOG(ERROR, TAG, "Failed to memory allocation");
+        return OC_STACK_NO_MEMORY;
+    }
+
+    secPayload->base.type = PAYLOAD_TYPE_SECURITY;
+    secPayload->securityData = BinToCrlJSON(crl);
+    if (NULL == secPayload->securityData)
+    {
+        OICFree(secPayload);
+        OC_LOG(ERROR, TAG, "Failed to BinToCrlJSON");
+        return OC_STACK_NO_MEMORY;
+    }
+    OC_LOG_V(INFO, TAG, "CRL : %s", secPayload->securityData);
+
+    char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
+    if(!PMGenerateQuery(true,
+                        selectedDeviceInfo->endpoint.addr,
+                        selectedDeviceInfo->securePort,
+                        selectedDeviceInfo->connType,
+                        query, sizeof(query), OIC_RSRC_CRL_URI))
+    {
+        OC_LOG(ERROR, TAG, "DeviceDiscoveryHandler : Failed to generate query");
+        OICFree(secPayload->securityData);
+        OICFree(secPayload);
+        return OC_STACK_ERROR;
+    }
+    OC_LOG_V(DEBUG, TAG, "Query=%s", query);
+
+    OCCallbackData cbData =  {.context=NULL, .cb=NULL, .cd=NULL};
+    cbData.cb = &SRPProvisionCRLCB;
+    CRLData_t *crlData = (CRLData_t *) OICCalloc(1, sizeof(CRLData_t));
+    if (crlData == NULL)
+    {
+        OICFree(secPayload->securityData);
+        OICFree(secPayload);
+        OC_LOG(ERROR, TAG, "Unable to allocate memory");
+        return OC_STACK_NO_MEMORY;
+    }
+
+    crlData->deviceInfo = selectedDeviceInfo;
+    crlData->resultCallback = resultCallback;
+    crlData->numOfResults=0;
+    crlData->ctx = ctx;
+
+    crlData->resArr = (OCProvisionResult_t*)OICCalloc(1, sizeof(OCProvisionResult_t));
+    if (crlData->resArr == NULL)
+    {
+        OICFree(secPayload->securityData);
+        OICFree(secPayload);
+        OC_LOG(ERROR, TAG, "Unable to allocate memory");
+        return OC_STACK_NO_MEMORY;
+    }
+
+    cbData.context = (void *)crlData;
+    cbData.cd = NULL;
+    OCMethod method = OC_REST_POST;
+    OCDoHandle handle = NULL;
+    OC_LOG(DEBUG, TAG, "Sending CRL info to resource server");
+
+    OCStackResult ret = OCDoResource(&handle, method, query,
+            &selectedDeviceInfo->endpoint, (OCPayload*)secPayload,
+            selectedDeviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
+
+    if (ret != OC_STACK_OK)
+    {
+        OICFree(crlData->resArr);
+        OICFree(crlData);
+    }
+
+    return ret;
+}
+
+/**
+ * Internal function for handling credential generation and sending cretificate credential.
+ *
+ * @param[in] cred Instance of cred resource.
+ * @param[in] deviceInfo information about device to which credential is to be provisioned.
+ * @param[in] responseHandler callbak called by OC stack when request API receives response.
+ * @return  OC_STACK_OK in case of success and other value otherwise.
+ */
+static OCStackResult provisionCertCred(const OicSecCred_t *cred,
+        const OCProvisionDev_t *deviceInfo, CertData_t *certData,
+        OCClientResponseHandler responseHandler)
+{
+    OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
+    if(!secPayload)
+    {
+        OC_LOG(ERROR, TAG, "Failed to memory allocation");
+        return OC_STACK_NO_MEMORY;
+    }
+    secPayload->base.type = PAYLOAD_TYPE_SECURITY;
+    secPayload->securityData = BinToCredJSON(cred);
+
+    if (NULL == secPayload->securityData)
+    {
+        OICFree(secPayload);
+        OC_LOG(ERROR, TAG, "Failed to BinToCredJSON");
+        return OC_STACK_NO_MEMORY;
+    }
+
+    OC_LOG_V(INFO, TAG, "Credential for provisioning : %s",secPayload->securityData);
+    char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
+    if(!PMGenerateQuery(true,
+                        deviceInfo->endpoint.addr,
+                        deviceInfo->securePort,
+                        deviceInfo->connType,
+                        query, sizeof(query), OIC_RSRC_CRED_URI))
+    {
+        OC_LOG(ERROR, TAG, "DeviceDiscoveryHandler : Failed to generate query");
+        OICFree(secPayload->securityData);
+        OICFree(secPayload);
+        return OC_STACK_ERROR;
+    }
+    OC_LOG_V(DEBUG, TAG, "Query=%s", query);
+
+    OCCallbackData cbData = {.context=NULL, .cb=NULL, .cd=NULL};
+    cbData.cb = responseHandler;
+    cbData.context = (void *) certData;
+    cbData.cd = NULL;
+
+    OCDoHandle handle = NULL;
+    OCMethod method = OC_REST_POST;
+    OCStackResult ret = OCDoResource(&handle, method, query, 0, (OCPayload*)secPayload,
+            deviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
+    OC_LOG_V(INFO, TAG, "OCDoResource::Certificate provisioning returned : %d",ret);
+    if (ret != OC_STACK_OK)
+    {
+        OC_LOG(ERROR, TAG, "OCStack resource error");
+    }
+
+    return ret;
+}
+
+/**
+ * Callback handler for handling callback of certificate provisioning device.
+ *
+ * @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 provisionCertCB(void *ctx, OCDoHandle UNUSED,
+                                                       OCClientResponse *clientResponse)
+{
+    VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
+    CertData_t *certData = (CertData_t *) ctx;
+    (void)UNUSED;
+
+    OCProvisionResultCB resultCallback = certData->resultCallback;
+    OC_LOG(INFO, TAG, "provisionCertCred called");
+    if (clientResponse)
+    {
+        if(OC_STACK_RESOURCE_CREATED == clientResponse->result)
+        {
+            registerResultForCertProvisioning(certData, OC_STACK_RESOURCE_CREATED);
+            ((OCProvisionResultCB)(resultCallback))(certData->ctx, certData->numOfResults,
+                                                    certData->resArr,
+                                                    false);
+             OICFree(certData->resArr);
+             OICFree(certData);
+             return OC_STACK_DELETE_TRANSACTION;
+        }
+
+    }
+    OC_LOG(INFO, TAG, "provisionCertCredCB received Null clientResponse");
+    registerResultForCertProvisioning(certData, OC_STACK_ERROR);
+    ((OCProvisionResultCB)(resultCallback))(certData->ctx, certData->numOfResults,
+                                            certData->resArr,
+                                            true);
+    OICFree(certData->resArr);
+    OICFree(certData);
+    return OC_STACK_DELETE_TRANSACTION;
+}
+#endif // __WITH_X509__
+
 OCStackResult SRPProvisionCredentials(void *ctx, OicSecCredType_t type, size_t keySize,
                                       const OCProvisionDev_t *pDev1,
                                       const OCProvisionDev_t *pDev2,
                                       OCProvisionResultCB resultCallback)
 {
     VERIFY_NON_NULL(TAG, pDev1, ERROR,  OC_STACK_INVALID_PARAM);
+    if (type == SYMMETRIC_PAIR_WISE_KEY)
     VERIFY_NON_NULL(TAG, pDev2, ERROR,  OC_STACK_INVALID_PARAM);
     VERIFY_NON_NULL(TAG, resultCallback, ERROR,  OC_STACK_INVALID_CALLBACK);
 
-    if (!(keySize == OWNER_PSK_LENGTH_128 || keySize == OWNER_PSK_LENGTH_256))
+    if (type == SYMMETRIC_PAIR_WISE_KEY &&
+       !(keySize == OWNER_PSK_LENGTH_128 || keySize == OWNER_PSK_LENGTH_256))
     {
         OC_LOG(INFO, TAG, "Invalid key size");
         return OC_STACK_INVALID_PARAM;
@@ -355,6 +645,49 @@ OCStackResult SRPProvisionCredentials(void *ctx, OicSecCredType_t type, size_t k
             VERIFY_SUCCESS(TAG, (res==OC_STACK_OK), ERROR, OC_STACK_ERROR);
             return res;
         }
+#ifdef __WITH_X509__
+        case SIGNED_ASYMMETRIC_KEY:
+        {
+            const OCProvisionDev_t *firstDevice = pDev1;
+            OicSecCred_t *cred = NULL;
+            OCStackResult res = PMGenerateCertificateCredentials(&provTooldeviceID,
+                                                                &firstDevice->doxm->deviceID,&cred);
+            VERIFY_SUCCESS(TAG, (res==OC_STACK_OK), ERROR, OC_STACK_ERROR);
+            OC_LOG(INFO, TAG, "Certificate credentials generated successfully");
+            CertData_t *certData = (CertData_t *) OICCalloc(1, sizeof(CertData_t));
+            if (NULL == certData)
+            {
+                OC_LOG(ERROR, TAG, "Memory allocation problem");
+                return OC_STACK_NO_MEMORY;
+            }
+
+            certData->deviceInfo = firstDevice;
+            certData->ctx = ctx;
+            certData->credInfo = cred;
+            certData->numOfResults = 0;
+            certData->resultCallback = resultCallback;
+
+            certData->resArr = (OCProvisionResult_t*)OICCalloc(1, sizeof(OCProvisionResult_t));
+            if (NULL == certData->resArr)
+            {
+                DeleteCredList(cred);
+                OICFree(certData);
+                OC_LOG(ERROR, TAG, "Memory allocation problem");
+                return OC_STACK_NO_MEMORY;
+            }
+
+            res = provisionCertCred(cred, firstDevice, certData, &provisionCertCB);
+            if (OC_STACK_OK != res)
+            {
+                OICFree(certData->resArr);
+                OICFree(certData);
+            }
+            DeleteCredList(cred);
+            OC_LOG_V(INFO, TAG, "provisionCertCredentials returned: %d",res);
+
+            return res;
+        }
+#endif
         default:
         {
             OC_LOG(ERROR, TAG, "Invalid option.");