secureresourceprovider.c 139 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/* *****************************************************************
 *
 * 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.
 *
 * *****************************************************************/
20
#include "iotivity_config.h"
21 22 23
#include <stdio.h>
#include <string.h>
#include <stdint.h>
24
#ifdef HAVE_UNISTD_H
25
#include <unistd.h>
26
#endif
27 28 29 30 31

#include "ocprovisioningmanager.h"
#include "secureresourceprovider.h"
#include "logger.h"
#include "oic_malloc.h"
32
#include "oic_string.h"
33 34 35 36
#include "aclresource.h"
#include "pstatresource.h"
#include "srmresourcestrings.h"
#include "credresource.h"
Kevin Kane's avatar
Kevin Kane committed
37
#include "csrresource.h"
38
#include "rolesresource.h"
39
#include "doxmresource.h"
Joonghwan Lee's avatar
Joonghwan Lee committed
40
#include "pconfresource.h"
41 42
#include "credentialgenerator.h"
#include "cainterface.h"
43
#include "oic_string.h"
44 45
#include "pmtypes.h"
#include "pmutility.h"
46
#include "srmutility.h"
47
#include "provisioningdatabasemanager.h"
48 49
#include "base64.h"
#include "utlist.h"
Sahil Bansal's avatar
Sahil Bansal committed
50
#include "ocpayload.h"
51
#include "srmutility.h"
52
#include "certhelpers.h"
53

54
#ifdef __WITH_DTLS__
Dmytro Zhuravlev's avatar
Dmytro Zhuravlev committed
55
#include "crlresource.h"
Greg Zaverucha's avatar
Greg Zaverucha committed
56
#endif
Dmytro Zhuravlev's avatar
Dmytro Zhuravlev committed
57

58
#define TAG "OIC_SRPAPI"
59

60 61
trustCertChainContext_t g_trustCertChainNotifier;

62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
// Enum type index for data types.
typedef enum
{
    CHAIN_TYPE = 0,                       /**< Certificate trust chain.**/
    ACL_TYPE,                             /**< Access control list.**/
    PSK_TYPE,                             /**< Pre-Shared Key.**/
    CERT_TYPE                             /**< X.509 certificate.**/
} DataType_t;

/**
 * Structure to carry general data to callback.
 */
typedef struct Data
{
    void *ctx;                                   /**< Pointer to user context.**/
    DataType_t type;                             /**< Data type of the context.**/
} Data_t;

80 81 82
/**
 * Structure to carry credential data to callback.
 */
83
typedef struct CredentialData
84 85
{
    void *ctx;                                  /**< Pointer to user context.**/
86 87 88
    const OCProvisionDev_t *deviceInfo[2];      /**< Array of pointers to OCProvisionDev_t.**/
    OicSecCred_t *credInfo[2];                  /**< Array of pointers to OicSecCred_t.**/
    int currIndex;                              /**< Index of current remote device.**/
89 90 91
    OCProvisionResultCB resultCallback;         /**< Pointer to result callback.**/
    OCProvisionResult_t *resArr;                /**< Result array.**/
    int numOfResults;                           /**< Number of results in result array.**/
92 93 94 95 96 97
    OicSecCredType_t type;                      /**< Type of credentials to be provisioned to the device.**/
    size_t keySize;                             /**< Size of key.**/
    const char *pemCert;                        /**< Certificate (SIGNED_ASYMMETRIC_KEY) encoded as PEM.**/
    const OicSecRole_t *role1;                  /**< Role of the deviceInfo[0].**/
    const OicSecRole_t *role2;                  /**< Role of the deviceInfo[1].**/
} CredentialData_t;
98 99 100 101

/**
 * Structure to carry ACL provision API data to callback.
 */
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
typedef struct ACLData
{
    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.**/
    OicSecAcl_t *acl;
    OicSecAclVersion_t aclVersion;
} ACLData_t;

/**
 * Structure to carry Trust Chain provision API data to callback.
 */
typedef struct TrustChainData
117 118
{
    void *ctx;                                  /**< Pointer to user context.**/
119
    const OCProvisionDev_t *targetDev;          /**< Pointer to OCProvisionDev_t.**/
120
    OCProvisionResultCB resultCallback;         /**< Pointer to result callback.**/
121
    uint16_t credId;                            /**< Trust chain id to be provisioned.**/
122 123
    OCProvisionResult_t *resArr;                /**< Result array.**/
    int numOfResults;                           /**< Number of results in result array.**/
124 125
} TrustChainData_t;

126

127 128 129 130 131 132 133 134 135 136
// Structure to carry get security resource APIs data to callback.
typedef struct GetSecData GetSecData_t;
struct GetSecData {
    void *ctx;
    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.**/
};

Kevin Kane's avatar
Kevin Kane committed
137 138 139 140 141 142 143 144 145
typedef struct GetCsrData GetCsrData_t;
struct GetCsrData {
    void *ctx;
    const OCProvisionDev_t *deviceInfo;         /**< Pointer to PMDevInfo_t.**/
    OCGetCSRResultCB resultCallback;            /**< Pointer to result callback.**/
    OCPMGetCsrResult_t *resArr;                 /**< Result array.**/
    size_t numOfResults;                        /**< Number of results in result array.**/
};

146 147 148 149 150 151 152 153 154
typedef struct GetRolesData GetRolesData_t;
struct GetRolesData {
    void *ctx;                                  /**< User-provided context **/
    const OCProvisionDev_t *deviceInfo;         /**< Pointer to PMDevInfo_t.**/
    OCGetRolesResultCB resultCallback;          /**< Pointer to result callback.**/
    OCPMGetRolesResult_t *resArr;               /**< Result array.**/
    size_t numOfResults;                        /**< Number of results in result array.**/
};

Joonghwan Lee's avatar
Joonghwan Lee committed
155 156 157 158 159 160 161 162 163 164 165 166 167
/**
 * Structure to carry PCONF provision API data to callback.
 */
typedef struct PconfData PconfData_t;
struct PconfData
{
    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.**/
};

168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
// Enum type index for unlink callback.
typedef enum {
    IDX_FIRST_DEVICE_RES = 0, // index for resulf of the first device
    IDX_SECOND_DEVICE_RES,    // index for result of the second device
    IDX_DB_UPDATE_RES         // index for result of updating provisioning database.
} IdxUnlinkRes_t;

// Structure to carry unlink APIs data to callback.
typedef struct UnlinkData UnlinkData_t;
struct UnlinkData {
    void *ctx;
    OCProvisionDev_t* unlinkDev;             /**< Pointer to OCProvisionDev_t to be unlinked.**/
    OCProvisionResult_t* unlinkRes;          /**< Result array.**/
    OCProvisionResultCB resultCallback;      /**< Pointer to result callback.**/
    int numOfResults;                        /**< Number of results in result array.**/
};

//Example of DELETE cred request -> coaps://0.0.0.0:5684/oic/sec/cred?sub=(BASE64 ENCODED UUID)
const char * SRP_FORM_DELETE_CREDENTIAL = "coaps://[%s]:%d%s?%s=%s";
Andrii Shtompel's avatar
Andrii Shtompel committed
187
const char * SRP_FORM_DELETE_CREDENTIAL_TCP = "coaps+tcp://[%s]:%d%s?%s=%s";
188 189 190 191 192 193 194 195 196 197 198 199 200 201

// Structure to carry remove APIs data to callback.
typedef struct RemoveData RemoveData_t;
struct RemoveData {
    void *ctx;
    OCProvisionDev_t* revokeTargetDev;      /**< Device which is going to be revoked..**/
    OCProvisionDev_t* linkedDevList;        /**< A list of devices which have invalid credential.**/
    OCProvisionResult_t* removeRes;         /**< Result array.**/
    OCProvisionResultCB resultCallback;     /**< Pointer to result callback.**/
    size_t numOfResults;                    /**< Number of results in result array.**/
    size_t sizeOfResArray;
    bool hasError;
};

202
/**
203
 * Function prototypes
204
 */
205 206 207 208 209 210
static OCStackResult provisionCredentials(void *ctx, OicSecCred_t *cred,
        const OCProvisionDev_t *deviceInfo, OCClientResponseHandler responseHandler);
static OCStackApplicationResult  ProvisionPskCB(void *ctx, OCDoHandle UNUSED,
        OCClientResponse *clientResponse);
static OCStackResult SetDOS(const Data_t *data, OicSecDeviceOnboardingState_t dos,
                            OCClientResponseHandler resultCallback);
211

212 213 214 215 216 217
typedef enum {
    DEVICE_1_FINISHED,
    DEVICE_2_FINISHED,
    DEVICE_LOCAL_FINISHED
} CredProvisioningResultCause_t;

218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
/**
 * Deallocates a block of memory.
 *
 * @param[in] data    Pointer to block of memory previously allocated for Data_t.
 */
static void FreeData(Data_t *data)
{
    switch (data->type)
    {
        case CHAIN_TYPE:
            {
                TrustChainData_t *chainData = (TrustChainData_t *) data->ctx;
                OICFree(chainData->resArr);
                OICFree(chainData);
                break;
            }
        case ACL_TYPE:
            {
                ACLData_t *aclData = (ACLData_t *) data->ctx;
                OICFree(aclData->resArr);
                OICFree(aclData);
                break;
            }
        case PSK_TYPE:
            {
                CredentialData_t *pskData = (CredentialData_t *) data->ctx;
                OICFree(pskData->resArr);
                OICFree(pskData);
                break;
            }
        default:
            {
                OIC_LOG_V(INFO, TAG, "Unknown type %d", data->type);
            }
    }
    OICFree(data);
}

256 257 258 259
/**
 * Internal function to update result in result array.
 */
static void registerResultForCredProvisioning(CredentialData_t *credData,
260
                                              OCStackResult stackresult, CredProvisioningResultCause_t cause)
261
{
262
   OCStackResult res = OC_STACK_ERROR;
263
   OIC_LOG_V(INFO,TAG,"value of credData->numOfResults is %d",credData->numOfResults);
264
   switch (cause)
265
   {
266
   case DEVICE_1_FINISHED:
267
       memcpy(credData->resArr[(credData->numOfResults)].deviceId.id,
268
              credData->deviceInfo[0]->doxm->deviceID.id,UUID_LENGTH);
269 270
       break;
   case DEVICE_2_FINISHED:
271
       memcpy(credData->resArr[(credData->numOfResults)].deviceId.id,
272
              credData->deviceInfo[1]->doxm->deviceID.id,UUID_LENGTH);
273 274 275 276 277 278 279 280 281 282 283 284 285 286
       break;
   case DEVICE_LOCAL_FINISHED:
       res = GetDoxmDeviceID(&credData->resArr[(credData->numOfResults)].deviceId);
       if (OC_STACK_OK != res)
       {
           OIC_LOG_V(WARNING, TAG, "%s: Could not retrieve own device ID to populate result for cred provisioning: %d", __func__, res);
           memset(credData->resArr[(credData->numOfResults)].deviceId.id, 0, UUID_LENGTH);
       }
       break;
   default:
       assert(!"Unknown value for cause");
       OIC_LOG_V(ERROR, TAG, "%s: unknown value of cause: %d", __func__, cause);
       memset(credData->resArr[(credData->numOfResults)].deviceId.id, 0, UUID_LENGTH);
       break;
287 288 289 290 291 292 293 294 295
   }
   credData->resArr[(credData->numOfResults)].res = stackresult;
   ++(credData->numOfResults);
}

/**
 * Callback handler for handling callback of provisioning device 2.
 *
 * @param[in] ctx             ctx value passed to callback from calling function.
296
 * @param[in] UNUSED          handle to an invocation
297 298 299 300
 * @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.
 */
301
static OCStackApplicationResult provisionCredentialCB2(void *ctx, OCDoHandle UNUSED,
302
                                                       OCClientResponse *clientResponse)
303
{
304
    VERIFY_NOT_NULL_RETURN(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
305
    CredentialData_t *credData = (CredentialData_t *) ((Data_t *) ctx)->ctx;
306
    (void)UNUSED;
307 308

    OCProvisionResultCB resultCallback = credData->resultCallback;
309
    OIC_LOG_V(DEBUG, TAG, "IN %s", __func__);
310 311
    if (clientResponse)
    {
312
        if (OC_STACK_RESOURCE_CHANGED == clientResponse->result)
313
        {
314
            registerResultForCredProvisioning(credData, OC_STACK_RESOURCE_CHANGED, DEVICE_2_FINISHED);
315 316
            OCStackResult res =  PDMLinkDevices(&credData->deviceInfo[0]->doxm->deviceID,
                                                &credData->deviceInfo[1]->doxm->deviceID);
317 318
            if (OC_STACK_OK != res)
            {
319
                OIC_LOG(ERROR, TAG, "Error occured on PDMLinkDevices");
320 321
                return OC_STACK_DELETE_TRANSACTION;
            }
322
            OIC_LOG(INFO, TAG, "Link created successfully");
323

324 325 326
            ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
                                                    credData->resArr,
                                                    false);
327 328
            FreeData(ctx);
            return OC_STACK_DELETE_TRANSACTION;
329 330 331
        }

    }
332
    OIC_LOG(INFO, TAG, "provisionCredentialCB2 received Null clientResponse");
333
    registerResultForCredProvisioning(credData, OC_STACK_ERROR, DEVICE_2_FINISHED);
334 335 336
    ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
                                            credData->resArr,
                                            true);
337 338
    FreeData(ctx);
    OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__);
339 340 341 342 343 344 345
    return OC_STACK_DELETE_TRANSACTION;
}

/**
 * Callback handler for handling callback of provisioning device 1.
 *
 * @param[in] ctx             ctx value passed to callback from calling function.
346
 * @param[in] UNUSED          handle to an invocation
347 348 349 350
 * @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.
 */
351
static OCStackApplicationResult provisionCredentialCB1(void *ctx, OCDoHandle UNUSED,
352
        OCClientResponse *clientResponse)
353
{
354
    OIC_LOG_V(DEBUG, TAG, "IN %s", __func__);
355
    VERIFY_NOT_NULL_RETURN(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
356 357
    (void) UNUSED;
    CredentialData_t *credData = (CredentialData_t *) ((Data_t *) ctx)->ctx;
358 359 360
    const OCProvisionResultCB resultCallback = credData->resultCallback;
    if (clientResponse)
    {
Randeep's avatar
Randeep committed
361
        if (OC_STACK_RESOURCE_CHANGED == clientResponse->result)
362 363
        {
            // send credentials to second device
364
            registerResultForCredProvisioning(credData, OC_STACK_RESOURCE_CHANGED, DEVICE_1_FINISHED);
365
            OCStackResult res = SetDOS((Data_t *) ctx, DOS_RFPRO, ProvisionPskCB);
366 367 368
            // If deviceInfo is NULL, this device is the second device. Don't delete the cred
            // because provisionCredentials added it to the local cred store and it now owns
            // the memory.
369 370
            if (OC_STACK_OK != res)
            {
371
                registerResultForCredProvisioning(credData, res, 2);
372 373 374
                ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
                                                        credData->resArr,
                                                        true);
375
                FreeData(ctx);
376 377 378 379
            }
        }
        else
        {
380
            registerResultForCredProvisioning(credData, OC_STACK_ERROR, DEVICE_1_FINISHED);
381 382 383
            ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
                                                    credData->resArr,
                                                    true);
384
            FreeData(ctx);
385 386 387 388
        }
    }
    else
    {
389
        OIC_LOG(INFO, TAG, "provisionCredentialCB received Null clientResponse for first device");
390
        registerResultForCredProvisioning(credData, OC_STACK_ERROR, DEVICE_1_FINISHED);
391 392 393 394
        ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
                                                credData->resArr,
                                                true);
        FreeData(ctx);
395
    }
396
    OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__);
397 398 399 400 401 402 403 404 405 406 407
    return OC_STACK_DELETE_TRANSACTION;
}

/**
 * Internal function for handling credential generation and sending credential to resource server.
 *
 * @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.
 */
408 409
static OCStackResult provisionCredentials(void *ctx, OicSecCred_t *cred,
        const OCProvisionDev_t *deviceInfo, OCClientResponseHandler responseHandler)
410
{
411
    OCStackResult res = OC_STACK_OK;
412
    CredentialData_t *credData = (CredentialData_t *) ((Data_t *) ctx)->ctx;
413

414
    if (NULL != deviceInfo)
415
    {
416
        OCSecurityPayload *secPayload = (OCSecurityPayload *)OICCalloc(1, sizeof(OCSecurityPayload));
417 418 419 420 421 422 423 424 425 426 427 428 429 430
        if (!secPayload)
        {
            OIC_LOG(ERROR, TAG, "Failed to allocate memory");
            return OC_STACK_NO_MEMORY;
        }
        secPayload->base.type = PAYLOAD_TYPE_SECURITY;
        int secureFlag = 0;
        res = CredToCBORPayload(cred, &secPayload->securityData, &secPayload->payloadSize, secureFlag);
        if ((OC_STACK_OK != res) && (NULL == secPayload->securityData))
        {
            OCPayloadDestroy((OCPayload *)secPayload);
            OIC_LOG(ERROR, TAG, "Failed to CredToCBORPayload");
            return OC_STACK_NO_MEMORY;
        }
431

432 433 434 435
        OIC_LOG(DEBUG, TAG, "Created payload for Cred:");
        OIC_LOG_BUFFER(DEBUG, TAG, secPayload->securityData, secPayload->payloadSize);
        char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = { 0 };
        if (!PMGenerateQuery(true,
436 437 438 439
                             deviceInfo->endpoint.addr,
                             deviceInfo->securePort,
                             deviceInfo->connType,
                             query, sizeof(query), OIC_RSRC_CRED_URI))
440 441 442 443 444 445
        {
            OIC_LOG(ERROR, TAG, "DeviceDiscoveryHandler : Failed to generate query");
            OCPayloadDestroy((OCPayload *)secPayload);
            return OC_STACK_ERROR;
        }
        OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
446

447
        OCCallbackData cbData = { .context = NULL, .cb = NULL, .cd = NULL };
448
        cbData.cb = responseHandler;
449
        cbData.context = ctx;
450 451 452 453
        cbData.cd = NULL;

        OCDoHandle handle = NULL;
        OCMethod method = OC_REST_POST;
454 455
        res = OCDoResource(&handle, method, query, 0, (OCPayload *)secPayload,
                           deviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
456 457 458 459 460 461 462 463 464
        OIC_LOG_V(INFO, TAG, "OCDoResource::Credential provisioning returned : %d", res);
        if (res != OC_STACK_OK)
        {
            OIC_LOG(ERROR, TAG, "OCStack resource error");
            return res;
        }
        return OC_STACK_OK;
    }
    else
465
    {
466 467 468 469 470 471 472 473
        /* Provision this credential to the local cred store. On success, the cred resource takes
         * ownership of the memory. On failure, provisionCredentialCB1 will delete the cred object.
         */
        res = AddCredential(cred);
        /* Call the result callback directly. */
        registerResultForCredProvisioning(credData, OC_STACK_RESOURCE_CHANGED, DEVICE_LOCAL_FINISHED);
        (credData->resultCallback)(credData->ctx, credData->numOfResults, credData->resArr, false);
        return res;
474 475 476
    }
}

477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776
/**
 * Updates result in result array of the target device.
 */
static void RegisterProvResult(const OCProvisionDev_t *targetDev, OCProvisionResult_t *resArr,
                               int *numOfResults, OCStackResult stackResult);
/**
 * Callback handler for handling callback of posting DOS_RFNOP.
 *
 * @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 SetReadyForNormalOperationCB(void *ctx, OCDoHandle handler,
        OCClientResponse *clientResponse)
{
    OIC_LOG_V(DEBUG, TAG, "IN %s", __func__);
    VERIFY_NOT_NULL_RETURN(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
    DataType_t dataType = ((Data_t *) ctx)->type;

    OCProvisionResultCB resultCallback = NULL;
    const OCProvisionDev_t *targetDev = NULL;
    OCProvisionResult_t *resArr = NULL;
    int *numOfResults = NULL;

    void *dataCtx = NULL;
    OIC_LOG_V(DEBUG, TAG, "Data type %d", dataType);

    switch (dataType)
    {
        case CHAIN_TYPE:
        {
            TrustChainData_t *chainData = (TrustChainData_t *) ((Data_t *) ctx)->ctx;
            resultCallback = chainData->resultCallback;
            targetDev = chainData->targetDev;
            resArr = chainData->resArr;
            numOfResults = &(chainData->numOfResults);
            dataCtx = chainData->ctx;
            break;
        }
        case ACL_TYPE:
        {
            ACLData_t *aclData = (ACLData_t *) ((Data_t *) ctx)->ctx;
            resultCallback = aclData->resultCallback;
            targetDev = aclData->deviceInfo;
            resArr = aclData->resArr;
            numOfResults = &(aclData->numOfResults);
            dataCtx = aclData->ctx;
            break;
        }
        case PSK_TYPE:
        {
            CredentialData_t *pskData = (CredentialData_t *) ((Data_t *) ctx)->ctx;
            resArr = pskData->resArr;
            numOfResults = &(pskData->numOfResults);
            dataCtx = pskData->ctx;
            OIC_LOG_V(DEBUG, TAG, "PSK index %d", pskData->currIndex);
            break;
        }
        case CERT_TYPE:
        {
            OIC_LOG_V(ERROR, TAG, "Not implemented type %d", dataType);
            OIC_LOG_V(ERROR, TAG, "OUT %s", __func__);
            return OC_STACK_DELETE_TRANSACTION;
        }
        default:
        {
            OIC_LOG_V(ERROR, TAG, "Unknown type %d", dataType);
            OIC_LOG_V(ERROR, TAG, "OUT %s", __func__);
            return OC_STACK_DELETE_TRANSACTION;
        }
    }

    if (dataType != PSK_TYPE)
    {
        RegisterProvResult(targetDev, resArr, numOfResults, clientResponse->result);
        resultCallback(dataCtx, *numOfResults, resArr, clientResponse->result != OC_STACK_RESOURCE_CHANGED);
        FreeData(ctx);
    }
    else
    {
        CredentialData_t *pskData = (CredentialData_t *) ((Data_t *) ctx)->ctx;
        if (pskData->currIndex == 0)
        {
            pskData->currIndex = 1;
            provisionCredentialCB1(ctx, handler, clientResponse);
        }
        else
        {
            provisionCredentialCB2(ctx, handler, clientResponse);
        }
    }

    OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__);
    return OC_STACK_DELETE_TRANSACTION;
}

/**
 * Updates pstat resource of server.
 */
static OCStackResult SetDOS(const Data_t *data, OicSecDeviceOnboardingState_t dos,
                            OCClientResponseHandler resultCallback)
{
    OIC_LOG_V(DEBUG, TAG, "IN %s", __func__);
    if (NULL == data || NULL == resultCallback)
    {
        OIC_LOG(ERROR, TAG, "NULL parameters");
        OIC_LOG_V(ERROR, TAG, "OUT %s", __func__);
        return OC_STACK_INVALID_PARAM;
    }


    const OCProvisionDev_t *pTargetDev = NULL;

    switch (data->type)
    {
        case CHAIN_TYPE:
        {
            pTargetDev = ((TrustChainData_t *)data->ctx)->targetDev;
            break;
        }
        case ACL_TYPE:
        {
            pTargetDev = ((ACLData_t *)data->ctx)->deviceInfo;
            break;
        }
        case PSK_TYPE:
        {
            CredentialData_t *credData = ((CredentialData_t *)data)->ctx;
            pTargetDev = credData->deviceInfo[credData->currIndex];
            break;
        }
        case CERT_TYPE:
        {
            // TODO check cert provision flow
            OIC_LOG_V(ERROR, TAG, "Not implemented type: %d", data->type);
            return OC_STACK_INVALID_PARAM;
        }
        default:
        {
            OIC_LOG_V(ERROR, TAG, "Unknown type: %d", data->type);
            return OC_STACK_INVALID_PARAM;
        }
    }

    OCStackResult res = OC_STACK_ERROR;
    OicSecPstat_t *pstat = (OicSecPstat_t *) OICCalloc(1, sizeof(OicSecPstat_t));
    if (!pstat)
    {
        OIC_LOG(ERROR, TAG, "Failed to allocate memory");
        return OC_STACK_NO_MEMORY;
    }

    pstat->dos.state = dos;

    OCSecurityPayload *secPayload = (OCSecurityPayload *) OICCalloc(1, sizeof(OCSecurityPayload));
    if (!secPayload)
    {
        OIC_LOG(ERROR, TAG, "Failed to allocate memory");
        res = OC_STACK_NO_MEMORY;
        goto error;
    }
    secPayload->base.type = PAYLOAD_TYPE_SECURITY;

    // Note [IOT-2052] all the POST payloads in the provisioningclient app
    // should be updated to use the Partial payload APIs for the SVRs, so they
    // do not include read-only Properties for the Server device current
    // state.
    bool propertiesToInclude[PSTAT_PROPERTY_COUNT] = {false};
    propertiesToInclude[PSTAT_DOS] = true;

    if (OC_STACK_OK != PstatToCBORPayloadPartial(pstat, &(secPayload->securityData),
            &(secPayload->payloadSize), propertiesToInclude))
    {
        OCPayloadDestroy((OCPayload *) secPayload);
        OIC_LOG(ERROR, TAG, "Failed to PstatToCBORPayload");
        res = OC_STACK_NO_MEMORY;
        goto error;
    }
    OIC_LOG(DEBUG, TAG, "Created payload for pstat set");
    OIC_LOG_BUFFER(DEBUG, TAG, secPayload->securityData, secPayload->payloadSize);

    char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
    if (!PMGenerateQuery(true,
                         pTargetDev->endpoint.addr,
                         pTargetDev->securePort,
                         pTargetDev->connType,
                         query, sizeof(query), OIC_RSRC_PSTAT_URI))
    {
        OIC_LOG(ERROR, TAG, "Failed to generate query");
        OCPayloadDestroy((OCPayload *) secPayload);
        res = OC_STACK_ERROR;
        goto error;
    }
    OIC_LOG_V(DEBUG, TAG, "Query=%s", query);

    OCCallbackData cbData = { .context = NULL, .cb = NULL, .cd = NULL };
    OCMethod method = OC_REST_POST;
    OCDoHandle handle = NULL;
    OCProvisionDev_t *targetDev = NULL;

    targetDev = PMCloneOCProvisionDev(pTargetDev);

    if (NULL == targetDev)
    {
        OIC_LOG(ERROR, TAG, "target dev is null");
        res = OC_STACK_ERROR;
        goto error;
    }
    cbData.cb = resultCallback;
    cbData.context = (void *) data;
    cbData.cd = NULL;
    OIC_LOG(DEBUG, TAG, "Sending PSTAT info to resource server");
    res = OCDoResource(&handle, method, query,
                       &targetDev->endpoint, (OCPayload *)secPayload,
                       targetDev->connType, OC_HIGH_QOS, &cbData, NULL, 0);
    if (OC_STACK_OK != res)
    {
        OIC_LOG(ERROR, TAG, "OCStack resource error");
    }

error:
    OICFree(pstat);
    OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__);
    return res;
}

/**
 * Restores pstat after provisioning.
 */
static OCStackApplicationResult ProvisionCB(void *ctx, OCDoHandle UNUSED,
        OCClientResponse *clientResponse)
{
    OIC_LOG_V(DEBUG, TAG, "IN %s", __func__);
    VERIFY_NOT_NULL_RETURN(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
    (void) UNUSED;
    if (clientResponse && OC_STACK_RESOURCE_CHANGED != clientResponse->result)
    {
        OIC_LOG_V(ERROR, TAG, "Responce result: %d", clientResponse->result);
    }
    if (OC_STACK_OK != SetDOS(ctx, DOS_RFNOP, SetReadyForNormalOperationCB))
    {
        OIC_LOG_V(ERROR, TAG, "OUT %s", __func__);
        return OC_STACK_DELETE_TRANSACTION;
    }

    OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__);
    return OC_STACK_DELETE_TRANSACTION;
}
/**
 * Callback for PSK provisioning.
 */
static OCStackApplicationResult  ProvisionPskCB(void *ctx, OCDoHandle UNUSED,
                                                OCClientResponse *clientResponse)
{
    VERIFY_NOT_NULL_RETURN(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
    (void) UNUSED;
    CredentialData_t *credData = (CredentialData_t *) ((Data_t *) ctx)->ctx;
    const OCProvisionDev_t *device = credData->deviceInfo[credData->currIndex];
    OicSecCred_t *cred = credData->credInfo[credData->currIndex];
    const OCProvisionResultCB resultCallback = credData->resultCallback;

    if (clientResponse)
    {
        if (OC_STACK_RESOURCE_CHANGED == clientResponse->result)
        {
            OCStackResult res = provisionCredentials(ctx, cred, device, ProvisionCB);
            if (OC_STACK_OK != res)
            {
                registerResultForCredProvisioning(credData, res, 2);
                ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
                                                        credData->resArr, true);
                FreeData(ctx);
                return OC_STACK_DELETE_TRANSACTION;
            }
        }
        else
        {
            registerResultForCredProvisioning(credData, OC_STACK_ERROR, credData->currIndex);
            ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
                                                    credData->resArr,
                                                    true);
            FreeData(ctx);
        }
    }
    else
    {
        OIC_LOG(INFO, TAG, "provisionCredentialCB received Null clientResponse for first device");
        registerResultForCredProvisioning(credData, OC_STACK_ERROR, credData->currIndex);
        ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
                                                credData->resArr,
                                                true);
        FreeData(ctx);
        credData = NULL;
    }
    return OC_STACK_DELETE_TRANSACTION;
}


777
#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
Dmytro Zhuravlev's avatar
Dmytro Zhuravlev committed
778 779 780 781 782 783 784 785 786 787 788 789 790 791
/**
 * 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.**/
};

792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811
OCStackResult SRPRegisterTrustCertChainNotifier(void *ctx, TrustCertChainChangeCB callback)
{
    if (g_trustCertChainNotifier.callback)
    {
        OIC_LOG(ERROR, TAG, "Can't register Notifier, Unregister previous one");
        return OC_STACK_ERROR;
    }

    g_trustCertChainNotifier.callback = callback;
    g_trustCertChainNotifier.context = ctx;
    return OC_STACK_OK;
}

void SRPRemoveTrustCertChainNotifier()
{
    g_trustCertChainNotifier.callback = NULL;
    g_trustCertChainNotifier.context = NULL;
    return;
}

812 813
static OCStackApplicationResult provisionCertificateCB(void *ctx, OCDoHandle UNUSED,
    OCClientResponse *clientResponse)
Dmytro Zhuravlev's avatar
Dmytro Zhuravlev committed
814
{
815
    // Just call the callback provided to SRProvisionCredentials
816
    VERIFY_NOT_NULL_RETURN(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
817
    CredentialData_t* credData = (CredentialData_t *)ctx;
Dmytro Zhuravlev's avatar
Dmytro Zhuravlev committed
818
    (void)UNUSED;
819
    bool hasError;
Dmytro Zhuravlev's avatar
Dmytro Zhuravlev committed
820

821 822
    // We expect OC_STACK_RESOURCE_CHANGED, anything else is an error
    if (clientResponse && (OC_STACK_RESOURCE_CHANGED == clientResponse->result))
Dmytro Zhuravlev's avatar
Dmytro Zhuravlev committed
823
    {
824
        hasError = false;
Dmytro Zhuravlev's avatar
Dmytro Zhuravlev committed
825
    }
826 827 828 829 830 831 832 833 834 835 836 837 838
    else
    {
        hasError = true;
    }

    OCProvisionResultCB resultCallback = credData->resultCallback;
    VERIFY_NOT_NULL_RETURN(TAG, resultCallback, ERROR, OC_STACK_DELETE_TRANSACTION);

    ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
        credData->resArr, hasError);

    OICFree(credData);

Dmytro Zhuravlev's avatar
Dmytro Zhuravlev committed
839
    return OC_STACK_DELETE_TRANSACTION;
840

841 842 843 844 845 846
}
/**
 * Callback for Trust Chain provisioning.
 */
static OCStackApplicationResult ProvisionTrustChainCB(void *ctx, OCDoHandle UNUSED,
        OCClientResponse *clientResponse)
847
{
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903
    OIC_LOG_V(INFO, TAG, "IN %s", __func__);
    (void) UNUSED;
    if (NULL == ctx)
    {
        OIC_LOG(ERROR, TAG, "Context is NULL");
        return OC_STACK_INVALID_PARAM;
    }
    if (OC_STACK_RESOURCE_CHANGED == clientResponse->result)
    {
        Data_t *data = (Data_t *) ctx;
        if (CHAIN_TYPE != data->type)
        {
            OIC_LOG(ERROR, TAG, "Invalid type");
            return OC_STACK_INVALID_PARAM;
        }
        TrustChainData_t *chainData = (TrustChainData_t *) (data->ctx);
        OicSecCred_t *trustCertChainCred = GetCredEntryByCredId(chainData->credId);
        if (NULL == trustCertChainCred)
        {
            OIC_LOG(ERROR, TAG, "Can not find matched Trust Cert. Chain.");
            return OC_STACK_NO_RESOURCE;
        }

        OCSecurityPayload *secPayload = (OCSecurityPayload *)OICCalloc(1, sizeof(OCSecurityPayload));
        if (!secPayload)
        {
            DeleteCredList(trustCertChainCred);
            OIC_LOG(ERROR, TAG, "Failed to allocate memory");
            return OC_STACK_NO_MEMORY;
        }
        secPayload->base.type = PAYLOAD_TYPE_SECURITY;
        int secureFlag = 1; /* Don't send the private key to the device, if it happens to be present */
        if (OC_STACK_OK != CredToCBORPayload(trustCertChainCred, &secPayload->securityData,
                                             &secPayload->payloadSize, secureFlag))
        {
            DeleteCredList(trustCertChainCred);
            OCPayloadDestroy((OCPayload *)secPayload);
            OIC_LOG(ERROR, TAG, "Failed to CredToCBORPayload");
            return OC_STACK_NO_MEMORY;
        }
        DeleteCredList(trustCertChainCred);
        OIC_LOG(DEBUG, TAG, "Created payload for Cred:");
        OIC_LOG_BUFFER(DEBUG, TAG, secPayload->securityData, secPayload->payloadSize);

        char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
        if (!PMGenerateQuery(true,
                             chainData->targetDev->endpoint.addr,
                             chainData->targetDev->securePort,
                             chainData->targetDev->connType,
                             query, sizeof(query), OIC_RSRC_CRED_URI))
        {
            OIC_LOG(ERROR, TAG, "Failed to generate query");
            OCPayloadDestroy((OCPayload *)secPayload);
            return OC_STACK_ERROR;
        }
        OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
904

905 906 907 908 909 910 911 912 913 914 915 916 917 918 919
        OCCallbackData cbData =  {.context = NULL, .cb = NULL, .cd = NULL};
        cbData.cb = ProvisionCB;
        cbData.context = ctx;
        cbData.cd = NULL;
        OCMethod method = OC_REST_POST;
        OCDoHandle handle = NULL;
        OIC_LOG(DEBUG, TAG, "Sending Cred info to resource server");
        OCStackResult ret = OCDoResource(&handle, method, query,
                                         &chainData->targetDev->endpoint, (OCPayload *)secPayload,
                                         chainData->targetDev->connType, OC_HIGH_QOS, &cbData, NULL, 0);
        if (ret != OC_STACK_OK)
        {
            OIC_LOG_V(INFO, TAG, "OUT %s", __func__);
            return ret;
        }
920 921 922
    }
    else
    {
923 924
        OIC_LOG_V(ERROR, TAG, "OUT %s", __func__);
        return OC_STACK_ERROR;
925 926
    }

927 928
    OIC_LOG_V(INFO, TAG, "OUT %s", __func__);
    return OC_STACK_OK;
929 930
}

931 932 933
OCStackResult SRPProvisionTrustCertChain(void *ctx, OicSecCredType_t type, uint16_t credId,
        const OCProvisionDev_t *selectedDeviceInfo, OCProvisionResultCB resultCallback)
{
934
    OIC_LOG_V(INFO, TAG, "IN %s", __func__);
935 936
    VERIFY_NOT_NULL_RETURN(TAG, selectedDeviceInfo, ERROR,  OC_STACK_INVALID_PARAM);
    VERIFY_NOT_NULL_RETURN(TAG, resultCallback, ERROR,  OC_STACK_INVALID_CALLBACK);
937
    if (SIGNED_ASYMMETRIC_KEY != type)
938 939 940 941 942
    {
        OIC_LOG(INFO, TAG, "Invalid key type");
        return OC_STACK_INVALID_PARAM;
    }

943 944
    TrustChainData_t *chainData = (TrustChainData_t *) OICCalloc(1, sizeof(TrustChainData_t));
    if (NULL == chainData)
945 946 947 948
    {
        OIC_LOG(ERROR, TAG, "Memory allocation problem");
        return OC_STACK_NO_MEMORY;
    }
949 950 951 952 953
    chainData->targetDev = selectedDeviceInfo;
    chainData->resultCallback = resultCallback;
    chainData->credId = credId;
    chainData->ctx = ctx;
    chainData->numOfResults = 0;
954 955

    int noOfRiCalls = 1;
956 957
    chainData->resArr = (OCProvisionResult_t *)OICCalloc(noOfRiCalls, sizeof(OCProvisionResult_t));
    if (chainData->resArr == NULL)
958
    {
959
        OICFree(chainData);
960 961 962 963
        OIC_LOG(ERROR, TAG, "Unable to allocate memory");
        return OC_STACK_NO_MEMORY;
    }

964 965 966
    Data_t *data = (Data_t *) OICCalloc(1, sizeof(Data_t));
    data->type = CHAIN_TYPE;
    data->ctx = chainData;
967

968 969 970 971 972 973
    if (SetDOS(data, DOS_RFPRO, ProvisionTrustChainCB) != OC_STACK_OK)
    {
        FreeData(data);
        OIC_LOG_V(INFO, TAG, "OUT %s", __func__);
        return OC_STACK_ERROR;
    }
974

975
    OIC_LOG_V(INFO, TAG, "OUT %s", __func__);
976 977 978
    return OC_STACK_OK;
}

979
OCStackResult SRPSaveTrustCertChain(const uint8_t *trustCertChain, size_t chainSize,
980 981 982
                                            OicEncodingType_t encodingType, uint16_t *credId)
{
    OIC_LOG(DEBUG, TAG, "IN SRPSaveTrustCertChain");
983 984
    VERIFY_NOT_NULL_RETURN(TAG, trustCertChain, ERROR,  OC_STACK_INVALID_PARAM);
    VERIFY_NOT_NULL_RETURN(TAG, credId, ERROR,  OC_STACK_INVALID_PARAM);
985 986 987 988

    OCStackResult res = OC_STACK_ERROR;

    OicSecCred_t *cred = (OicSecCred_t *)OICCalloc(1, sizeof(*cred));
989
    VERIFY_NOT_NULL_RETURN(TAG, cred, ERROR, OC_STACK_NO_MEMORY);
990

991 992 993
    res = GetDoxmDeviceID(&cred->subject);
    if (OC_STACK_OK != res)
    {
994
        OIC_LOG(ERROR, TAG, "Can't get the device id(GetDoxmDeviceID)");
995 996 997
        DeleteCredList(cred);
        return res;
    }
998

999
    cred->credUsage= (char *)OICCalloc(1, strlen(TRUST_CA) + 1);
1000
    VERIFY_NOT_NULL_RETURN(TAG, cred->credUsage, ERROR, OC_STACK_NO_MEMORY);
1001
    OICStrcpy(cred->credUsage, strlen(TRUST_CA) + 1, TRUST_CA);
1002 1003 1004

    cred->credType = SIGNED_ASYMMETRIC_KEY;

js126.lee's avatar
js126.lee committed
1005 1006 1007
    if (encodingType == OIC_ENCODING_PEM)
    {
        cred->optionalData.data = (uint8_t *)OICCalloc(1, chainSize + 1);
1008
        VERIFY_NOT_NULL_RETURN(TAG, cred->optionalData.data, ERROR, OC_STACK_NO_MEMORY);
js126.lee's avatar
js126.lee committed
1009 1010
        cred->optionalData.len = chainSize + 1;
    }
1011
    else if (encodingType == OIC_ENCODING_DER)
js126.lee's avatar
js126.lee committed
1012 1013
    {
        cred->optionalData.data = (uint8_t *)OICCalloc(1, chainSize);
1014
        VERIFY_NOT_NULL_RETURN(TAG, cred->optionalData.data, ERROR, OC_STACK_NO_MEMORY);
js126.lee's avatar
js126.lee committed
1015 1016
        cred->optionalData.len = chainSize;
    }
1017 1018 1019 1020 1021 1022
    else
    {
        OIC_LOG_V(ERROR, TAG, "Unknown encoding in %s", __func__);
        DeleteCredList(cred);
        return OC_STACK_INVALID_PARAM;
    }
1023 1024
    memcpy(cred->optionalData.data, trustCertChain, chainSize);
    cred->optionalData.encoding = encodingType;
1025
    cred->optionalData.revstat = false;
1026 1027 1028 1029 1030 1031 1032 1033 1034

    res = AddCredential(cred);
    if(res != OC_STACK_OK)
    {
        DeleteCredList(cred);
        return res;
    }
    *credId = cred->credId;

1035 1036 1037
    if (g_trustCertChainNotifier.callback)
    {
        uint8_t *certChain = (uint8_t*)OICCalloc(1, sizeof(uint8_t) * chainSize);
1038
        VERIFY_NOT_NULL_RETURN(TAG, certChain, ERROR, OC_STACK_NO_MEMORY);
1039
        memcpy(certChain, trustCertChain, chainSize);
1040
        g_trustCertChainNotifier.callback(g_trustCertChainNotifier.context, *credId,
1041 1042 1043 1044
                certChain, chainSize);
        OICFree(certChain);
    }

1045 1046 1047 1048
    OIC_LOG(DEBUG, TAG, "OUT SRPSaveTrustCertChain");

    return res;
}
Andrii Shtompel's avatar
Andrii Shtompel committed
1049

1050
static OCStackResult saveCertChain(OicSecKey_t * cert, OicSecKey_t * key, uint16_t *credId, const char* usage)
Andrii Shtompel's avatar
Andrii Shtompel committed
1051
{
1052
    OIC_LOG_V(DEBUG, TAG, "IN %s", __func__);
1053 1054
    VERIFY_NOT_NULL_RETURN(TAG, cert, ERROR,  OC_STACK_INVALID_PARAM);
    VERIFY_NOT_NULL_RETURN(TAG, cert->data, ERROR,  OC_STACK_INVALID_PARAM);
Andrii Shtompel's avatar
Andrii Shtompel committed
1055 1056 1057 1058 1059 1060 1061 1062 1063 1064

    VERIFY_NOT_NULL_RETURN(TAG, credId, ERROR,  OC_STACK_INVALID_PARAM);
    VERIFY_NOT_NULL_RETURN(TAG, usage, ERROR, OC_STACK_INVALID_PARAM);

    if (NULL == key && PRIMARY_CERT == usage)
    {
        OIC_LOG_V(ERROR, TAG, "Key is NULL, but it is mandatory if usage is %s", PRIMARY_CERT);
        return OC_STACK_INVALID_PARAM;
    }

1065 1066 1067 1068 1069
    if (key != NULL)
    {
        /* Key is optional. */
        VERIFY_NOT_NULL_RETURN(TAG, key->data, ERROR, OC_STACK_INVALID_PARAM);
    }
Andrii Shtompel's avatar
Andrii Shtompel committed
1070 1071 1072 1073

    OCStackResult res = OC_STACK_ERROR;

    OicSecCred_t *cred = (OicSecCred_t *)OICCalloc(1, sizeof(*cred));
1074
    VERIFY_NOT_NULL_RETURN(TAG, cred, ERROR, OC_STACK_NO_MEMORY);
Andrii Shtompel's avatar
Andrii Shtompel committed
1075 1076 1077

    OIC_LOG_V(DEBUG, TAG, "IN: %s", __func__);

1078 1079
    res = GetDoxmDeviceID(&cred->subject);
    if (OC_STACK_OK != res)
Andrii Shtompel's avatar
Andrii Shtompel committed
1080
    {
1081
        OIC_LOG(ERROR, TAG, "Can't get the device id(GetDoxmDeviceID)");
1082 1083
        DeleteCredList(cred);
        return res;
Andrii Shtompel's avatar
Andrii Shtompel committed
1084 1085
    }

1086
    cred->credUsage= (char *)OICCalloc(1, strlen(usage) + 1);
1087
    VERIFY_NOT_NULL_RETURN(TAG, cred->credUsage, ERROR, OC_STACK_NO_MEMORY);
1088
    OICStrcpy(cred->credUsage, strlen(usage) + 1, usage);
Andrii Shtompel's avatar
Andrii Shtompel committed
1089 1090 1091

    cred->credType = SIGNED_ASYMMETRIC_KEY;

1092
    OicSecKey_t *publicData = &cred->publicData;
Andrii Shtompel's avatar
Andrii Shtompel committed
1093
    publicData->data = (uint8_t *)OICCalloc(1, cert->len);
1094
    VERIFY_NOT_NULL_RETURN(TAG, publicData->data, ERROR, OC_STACK_NO_MEMORY);
Andrii Shtompel's avatar
Andrii Shtompel committed
1095 1096
    memcpy(publicData->data, cert->data, cert->len);
    publicData->len = cert->len;
1097
    publicData->encoding = cert->encoding;
Andrii Shtompel's avatar
Andrii Shtompel committed
1098

1099 1100 1101 1102 1103 1104 1105 1106 1107
    if (key != NULL)
    {
        OicSecKey_t *privateData = &cred->privateData;
        privateData->data = (uint8_t *)OICCalloc(1, key->len);
        VERIFY_NOT_NULL_RETURN(TAG, privateData->data, ERROR, OC_STACK_NO_MEMORY);
        memcpy(privateData->data, key->data, key->len);
        privateData->len = key->len;
        privateData->encoding = key->encoding;
    }
Andrii Shtompel's avatar
Andrii Shtompel committed
1108 1109 1110 1111 1112 1113 1114 1115 1116

    res = AddCredential(cred);
    if(res != OC_STACK_OK)
    {
        DeleteCredList(cred);
        return res;
    }
    *credId = cred->credId;

1117
    OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__);
Andrii Shtompel's avatar
Andrii Shtompel committed
1118 1119 1120

    return res;
}
1121 1122 1123 1124 1125 1126

OCStackResult SRPSaveOwnCertChain(OicSecKey_t * cert, OicSecKey_t * key, uint16_t *credId)
{
    return saveCertChain(cert, key, credId, PRIMARY_CERT);
}

1127 1128 1129 1130 1131
OCStackResult SRPSaveOwnRoleCert(OicSecKey_t * cert, uint16_t *credId)
{
    return saveCertChain(cert, NULL, credId, ROLE_CERT);
}

1132
#endif // __WITH_DTLS__ || __WITH_TLS__
Dmytro Zhuravlev's avatar
Dmytro Zhuravlev committed
1133

1134 1135 1136
OCStackResult SRPProvisionCredentials(void *ctx, OicSecCredType_t type, size_t keySize,
                                      const OCProvisionDev_t *pDev1,
                                      const OCProvisionDev_t *pDev2,
1137
                                      const char* pemCert,
1138 1139
                                      const OicSecRole_t *role1,
                                      const OicSecRole_t *role2,
1140 1141
                                      OCProvisionResultCB resultCallback)
{
1142
    VERIFY_NOT_NULL_RETURN(TAG, pDev1, ERROR,  OC_STACK_INVALID_PARAM);
1143 1144
    if (!resultCallback)
    {
1145
        OIC_LOG(INFO, TAG, "SRPProvisionCredentials: NULL Callback");
1146 1147
        return OC_STACK_INVALID_CALLBACK;
    }
1148
    if ((SYMMETRIC_PAIR_WISE_KEY == type) &&
1149 1150
        (NULL != pDev2) &&
        (0 == memcmp(&pDev1->doxm->deviceID, &pDev2->doxm->deviceID, sizeof(OicUuid_t))))
1151
    {
1152
        OIC_LOG(INFO, TAG, "SRPProvisionCredentials : Same device ID");
1153
        return OC_STACK_INVALID_PARAM;
1154
    }
1155

1156 1157
    if (SYMMETRIC_PAIR_WISE_KEY == type &&
       !(OWNER_PSK_LENGTH_128 == keySize || OWNER_PSK_LENGTH_256 == keySize))
1158
    {
1159
        OIC_LOG(INFO, TAG, "Invalid key size");
1160 1161 1162
        return OC_STACK_INVALID_PARAM;
    }

1163
    OIC_LOG(INFO, TAG, "In SRPProvisionCredentials");
1164

1165
    if ((SYMMETRIC_PAIR_WISE_KEY == type) && (NULL != pDev2))
1166
    {
1167 1168 1169 1170 1171
        bool linkExisits = true;
        OCStackResult res = PDMIsLinkExists(&pDev1->doxm->deviceID, &pDev2->doxm->deviceID, &linkExisits);

        if (res != OC_STACK_OK)
        {
1172
            OIC_LOG(ERROR, TAG, "Internal error occured");
1173 1174 1175 1176
            return res;
        }
        if (linkExisits)
        {
1177
            OIC_LOG(ERROR, TAG, "Link already exists");
1178 1179
            return OC_STACK_INVALID_PARAM;
        }
1180 1181
    }

1182 1183 1184
    OicUuid_t provTooldeviceID =   {{0,}};
    if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
    {
1185
        OIC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
1186 1187
        return OC_STACK_ERROR;
    }
1188
    OIC_LOG(INFO, TAG, "retrieved deviceid");
1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202

    CredentialData_t *credData = (CredentialData_t *) OICCalloc(1, sizeof(CredentialData_t));
    Data_t *data = (Data_t *) OICCalloc(1, sizeof(Data_t));
    if (NULL == credData || NULL == data)
    {

        OICFree(credData);
        OICFree(data);
        OIC_LOG(ERROR, TAG, "Memory allocation problem");
        return OC_STACK_NO_MEMORY;
    }

    data->ctx = credData;

1203 1204 1205 1206
    switch (type)
    {
        case SYMMETRIC_PAIR_WISE_KEY:
        {
1207
            data->type = PSK_TYPE;
1208 1209 1210
            OicSecCred_t *firstCred = NULL;
            OicSecCred_t *secondCred = NULL;
            OCStackResult res = PMGeneratePairWiseCredentials(type, keySize, &provTooldeviceID,
1211 1212 1213 1214 1215
                                &pDev1->doxm->deviceID, (NULL != pDev2) ? &pDev2->doxm->deviceID :
                                &provTooldeviceID,
                                role1, role2,
                                &firstCred, &secondCred);
            VERIFY_SUCCESS_RETURN(TAG, (res == OC_STACK_OK), ERROR, OC_STACK_ERROR);
1216
            OIC_LOG(INFO, TAG, "Credentials generated successfully");
1217 1218 1219 1220 1221

            credData->deviceInfo[0] = pDev1;
            credData->deviceInfo[1] = pDev2;
            credData->credInfo[0] = firstCred;
            credData->credInfo[1] = secondCred;
1222
            credData->ctx = ctx;
1223
            credData->currIndex = 0;
1224 1225 1226 1227 1228 1229
            credData->numOfResults = 0;
            credData->