source: azure_iot_hub_f767zi/trunk/azure_iot_sdk/provisioning_client/src/prov_device_ll_client.c@ 464

Last change on this file since 464 was 464, checked in by coas-nagasima, 3 years ago

WolfSSLとAzure IoT SDKを更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 54.3 KB
Line 
1// Copyright (c) Microsoft. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
4#include <stdlib.h>
5#include <stdbool.h>
6#include <stdint.h>
7
8#include "parson.h"
9
10#include "azure_c_shared_utility/gballoc.h"
11#include "azure_c_shared_utility/xlogging.h"
12#include "azure_c_shared_utility/strings.h"
13#include "azure_c_shared_utility/buffer_.h"
14#include "azure_c_shared_utility/uniqueid.h"
15#include "azure_c_shared_utility/sastoken.h"
16#include "azure_c_shared_utility/crt_abstractions.h"
17#include "azure_c_shared_utility/azure_base64.h"
18#include "azure_c_shared_utility/urlencode.h"
19#include "azure_c_shared_utility/shared_util_options.h"
20#include "azure_c_shared_utility/tickcounter.h"
21
22#include "azure_prov_client/internal/prov_auth_client.h"
23#include "azure_prov_client/internal/prov_transport_private.h"
24#include "azure_prov_client/prov_device_ll_client.h"
25#include "azure_prov_client/prov_client_const.h"
26
27static const char* const OPTION_LOG_TRACE = "logtrace";
28
29static const char* const JSON_NODE_STATUS = "status";
30static const char* const JSON_NODE_REG_STATUS = "registrationState";
31static const char* const JSON_NODE_AUTH_KEY = "authenticationKey";
32static const char* const JSON_NODE_DEVICE_ID = "deviceId";
33static const char* const JSON_NODE_KEY_NAME = "keyName";
34static const char* const JSON_NODE_OPERATION_ID = "operationId";
35static const char* const JSON_NODE_ASSIGNED_HUB = "assignedHub";
36static const char* const JSON_NODE_TPM_NODE = "tpm";
37static const char* const JSON_NODE_DATE_TIME = "lastUpdatedDateTimeUtc";
38static const char* const JSON_NODE_ERROR_MSG = "errorMessage";
39static const char* const JSON_NODE_ERROR_CODE = "errorCode";
40static const char* const PROV_FAILED_STATUS = "failed";
41static const char* const PROV_BLACKLISTED_STATUS = "blacklisted";
42static const char* const JSON_CUSTOM_DATA_TAG = "payload";
43static const char* const JSON_NODE_RETURNED_DATA = "payload";
44
45static const char* const SAS_TOKEN_SCOPE_FMT = "%s/registrations/%s";
46
47static const char* const REGISTRATION_ID = "registrationId";
48static const char* const JSON_ENDORSMENT_KEY_NODE = "endorsementKey";
49static const char* const JSON_STORAGE_ROOT_KEY_NODE = "storageRootKey";
50
51#define DPS_HUB_ERROR_NO_HUB 400208
52#define DPS_HUB_ERROR_UNAUTH 400209
53
54#define SAS_TOKEN_DEFAULT_LIFETIME 2400
55#define EPOCH_TIME_T_VALUE (time_t)0
56#define MAX_AUTH_ATTEMPTS 3
57#define PROV_DEFAULT_TIMEOUT 60
58
59typedef enum CLIENT_STATE_TAG
60{
61 CLIENT_STATE_READY,
62
63 CLIENT_STATE_REGISTER_SEND,
64 CLIENT_STATE_REGISTER_SENT,
65 CLIENT_STATE_REGISTER_RECV,
66
67 CLIENT_STATE_STATUS_SEND,
68 CLIENT_STATE_STATUS_SENT,
69 CLIENT_STATE_STATUS_RECV,
70
71 CLIENT_STATE_ERROR
72} CLIENT_STATE;
73
74typedef struct IOTHUB_REQ_INFO_TAG
75{
76 char* iothub_url;
77 char* iothub_key;
78 char* device_id;
79} IOTHUB_REQ_INFO;
80
81typedef struct PROV_INSTANCE_INFO_TAG
82{
83 PROV_DEVICE_CLIENT_REGISTER_DEVICE_CALLBACK register_callback;
84 void* user_context;
85 PROV_DEVICE_CLIENT_REGISTER_STATUS_CALLBACK register_status_cb;
86 void* status_user_ctx;
87 PROV_DEVICE_RESULT error_reason;
88
89 const PROV_DEVICE_TRANSPORT_PROVIDER* prov_transport_protocol;
90 PROV_DEVICE_TRANSPORT_HANDLE transport_handle;
91 bool transport_open;
92
93 TICK_COUNTER_HANDLE tick_counter;
94
95 tickcounter_ms_t last_send_time_ms;
96 tickcounter_ms_t timeout_value;
97 size_t retry_after_ms;
98
99 uint8_t prov_timeout;
100
101 char* registration_id;
102 bool user_supplied_reg_id;
103
104 PROV_AUTH_HANDLE prov_auth_handle;
105
106 bool is_connected;
107
108 PROV_AUTH_TYPE hsm_type;
109
110 IOTHUB_REQ_INFO iothub_info;
111
112 CLIENT_STATE prov_state;
113
114 size_t auth_attempts_made;
115
116 char* scope_id;
117
118 char* custom_request_data;
119 char* custom_response_data;
120} PROV_INSTANCE_INFO;
121
122static char* prov_transport_challenge_callback(const unsigned char* nonce, size_t nonce_len, const char* key_name, void* user_ctx)
123{
124 char* result;
125 if (user_ctx == NULL)
126 {
127 LogError("Bad argument user_ctx is NULL");
128 result = NULL;
129 }
130 else
131 {
132 PROV_INSTANCE_INFO* prov_info = (PROV_INSTANCE_INFO*)user_ctx;
133 if ((prov_info->hsm_type == PROV_AUTH_TYPE_TPM) && nonce == NULL)
134 {
135 LogError("Bad argument nonce is NULL");
136 result = NULL;
137 }
138 else
139 {
140 char* token_scope;
141 size_t token_scope_len;
142
143 size_t sec_since_epoch = (size_t)(difftime(get_time(NULL), EPOCH_TIME_T_VALUE) + 0);
144 size_t expiry_time = sec_since_epoch + SAS_TOKEN_DEFAULT_LIFETIME;
145
146 // Construct Token scope
147 token_scope_len = strlen(SAS_TOKEN_SCOPE_FMT) + strlen(prov_info->scope_id) + strlen(prov_info->registration_id);
148
149 token_scope = malloc(token_scope_len + 1);
150 if (token_scope == NULL)
151 {
152 LogError("Failure to allocate token scope");
153 result = NULL;
154 }
155 else if (sprintf(token_scope, SAS_TOKEN_SCOPE_FMT, prov_info->scope_id, prov_info->registration_id) <= 0)
156 {
157 LogError("Failure to constructing token_scope");
158 free(token_scope);
159 result = NULL;
160 }
161 else
162 {
163 STRING_HANDLE encoded_token = URL_EncodeString(token_scope);
164 if (encoded_token == NULL)
165 {
166 LogError("Failure to url encoding string");
167 result = NULL;
168 }
169 else
170 {
171 if (prov_info->hsm_type == PROV_AUTH_TYPE_TPM && (prov_auth_import_key(prov_info->prov_auth_handle, nonce, nonce_len) != 0))
172 {
173 LogError("Failure to import the provisioning key");
174 result = NULL;
175 }
176 else
177 {
178 if ((result = prov_auth_construct_sas_token(prov_info->prov_auth_handle, STRING_c_str(encoded_token), key_name, expiry_time)) == NULL)
179 {
180 LogError("Failure to import the provisioning key");
181 result = NULL;
182 }
183 }
184 STRING_delete(encoded_token);
185 }
186 free(token_scope);
187 }
188 }
189 }
190 return result;
191}
192
193static void on_transport_error(PROV_DEVICE_TRANSPORT_ERROR transport_error, void* user_ctx)
194{
195 if (user_ctx != NULL)
196 {
197 PROV_INSTANCE_INFO* prov_info = (PROV_INSTANCE_INFO*)user_ctx;
198 switch (transport_error)
199 {
200 case PROV_DEVICE_ERROR_KEY_FAIL:
201 prov_info->error_reason = PROV_DEVICE_RESULT_KEY_ERROR;
202 break;
203 case PROV_DEVICE_ERROR_KEY_UNAUTHORIZED:
204 prov_info->error_reason = PROV_DEVICE_RESULT_DEV_AUTH_ERROR;
205 break;
206
207 case PROV_DEVICE_ERROR_MEMORY:
208 prov_info->error_reason = PROV_DEVICE_RESULT_MEMORY;
209 break;
210 }
211 }
212}
213
214static PROV_DEVICE_TRANSPORT_STATUS retrieve_status_type(const char* prov_status)
215{
216 PROV_DEVICE_TRANSPORT_STATUS result;
217 if (strcmp(prov_status, PROV_UNASSIGNED_STATUS) == 0)
218 {
219 result = PROV_DEVICE_TRANSPORT_STATUS_UNASSIGNED;
220 }
221 else if (strcmp(prov_status, PROV_ASSIGNING_STATUS) == 0)
222 {
223 result = PROV_DEVICE_TRANSPORT_STATUS_ASSIGNING;
224 }
225 else if (strcmp(prov_status, PROV_ASSIGNED_STATUS) == 0)
226 {
227 result = PROV_DEVICE_TRANSPORT_STATUS_ASSIGNED;
228 }
229 else if (strcmp(prov_status, PROV_FAILED_STATUS) == 0)
230 {
231 result = PROV_DEVICE_TRANSPORT_STATUS_ERROR;
232 }
233 else if (strcmp(prov_status, PROV_BLACKLISTED_STATUS) == 0)
234 {
235 result = PROV_DEVICE_TRANSPORT_STATUS_BLACKLISTED;
236 }
237 else if (strcmp(prov_status, PROV_DISABLE_STATUS) == 0)
238 {
239 result = PROV_DEVICE_TRANSPORT_STATUS_DISABLED;
240 }
241 else
242 {
243 result = PROV_DEVICE_TRANSPORT_STATUS_ERROR;
244 }
245 return result;
246}
247
248static int retrieve_json_number(JSON_Object* json_object, const char* field_name)
249{
250 int result;
251 JSON_Value* json_field;
252 if ((json_field = json_object_get_value(json_object, field_name)) == NULL)
253 {
254 LogError("failure retrieving json operation id");
255 result = 0;
256 }
257 else
258 {
259 result = (int)json_value_get_number(json_field);
260 }
261 return result;
262}
263
264static void retrieve_json_payload(JSON_Object* json_object, PROV_INSTANCE_INFO* prov_info)
265{
266 JSON_Value* json_field;
267
268 // Returned Data is not available
269 if ((json_field = json_object_get_value(json_object, JSON_NODE_RETURNED_DATA)) != NULL)
270 {
271 prov_info->custom_response_data = json_serialize_to_string(json_field);
272 }
273}
274
275static char* retrieve_json_string(JSON_Object* json_object, const char* field_name, bool is_required)
276{
277 char* result;
278 JSON_Value* json_field;
279 if ((json_field = json_object_get_value(json_object, field_name)) == NULL)
280 {
281 if (is_required)
282 {
283 LogError("failure retrieving json object value %s", field_name);
284 }
285 result = NULL;
286 }
287 else
288 {
289 const char* json_item = json_value_get_string(json_field);
290 if (json_item != NULL)
291 {
292 if (mallocAndStrcpy_s(&result, json_item) != 0)
293 {
294 LogError("failure retrieving operation id");
295 result = NULL;
296 }
297 }
298 else
299 {
300 result = NULL;
301 }
302 }
303 return result;
304}
305
306static JSON_Value* construct_security_type_json(PROV_INSTANCE_INFO* prov_info, const char* ek_value, const char* srk_value)
307{
308 JSON_Value* result;
309
310 JSON_Object* json_object;
311 result = json_value_init_object();
312 if (result == NULL)
313 {
314 LogError("Failure constructing json information");
315 }
316 else if ((json_object = json_value_get_object(result)) == NULL)
317 {
318 LogError("failure retrieving node root object");
319 json_value_free(result);
320 result = NULL;
321 }
322 else
323 {
324 if (json_object_set_string(json_object, REGISTRATION_ID, prov_info->registration_id) != JSONSuccess)
325 {
326 LogError("failure setting registration Id json node");
327 json_value_free(result);
328 result = NULL;
329 }
330 else
331 {
332 if (prov_info->hsm_type == PROV_AUTH_TYPE_TPM)
333 {
334 // tpm_node value only gets released on failure
335 JSON_Object* tpm_object;
336 JSON_Value* tpm_node = json_value_init_object();
337 if (tpm_node == NULL)
338 {
339 LogError("failure constructing json tpm object");
340 json_value_free(tpm_node);
341 json_value_free(result);
342 result = NULL;
343 }
344 else if ((tpm_object = json_value_get_object(tpm_node)) == NULL)
345 {
346 LogError("failure retrieving node root object");
347 json_value_free(tpm_node);
348 json_value_free(result);
349 result = NULL;
350 }
351 else if (json_object_set_string(tpm_object, JSON_ENDORSMENT_KEY_NODE, ek_value) != JSONSuccess)
352 {
353 LogError("failure setting endorsement key node");
354 json_value_free(tpm_node);
355 json_value_free(result);
356 result = NULL;
357 }
358 else if (json_object_set_string(tpm_object, JSON_STORAGE_ROOT_KEY_NODE, srk_value) != JSONSuccess)
359 {
360 LogError("failure setting tpm storage root key node");
361 json_value_free(tpm_node);
362 json_value_free(result);
363 result = NULL;
364 }
365 else if (json_object_set_value(json_object, JSON_NODE_TPM_NODE, tpm_node) != JSONSuccess)
366 {
367 LogError("failure constructing json tpm object");
368 json_value_free(tpm_node);
369 json_value_free(result);
370 result = NULL;
371 }
372 }
373 }
374 }
375 return result;
376}
377
378static char* prov_transport_create_json_payload(const char* ek_value, const char* srk_value, void* user_ctx)
379{
380 char* result = NULL;
381 if (user_ctx == NULL)
382 {
383 LogError("failure user_ctx is NULL");
384 }
385 else
386 {
387 PROV_INSTANCE_INFO* prov_info = (PROV_INSTANCE_INFO*)user_ctx;
388
389 JSON_Value* json_root = construct_security_type_json(prov_info, ek_value, srk_value);
390 if (json_root == NULL)
391 {
392 LogError("Failure constructing security json");
393 }
394 else
395 {
396 bool error_encountered = false;
397 if (prov_info->custom_request_data != NULL)
398 {
399 JSON_Object* json_object;
400 JSON_Value* json_custom_data = NULL;
401
402 if ((json_object = json_value_get_object(json_root)) == NULL)
403 {
404 LogError("failure retrieving node root object");
405 error_encountered = true;
406 }
407 else if ((json_custom_data = json_parse_string(prov_info->custom_request_data)) == NULL)
408 {
409 LogError("failure parsing custom info. This custom info MUST be valid json");
410 error_encountered = true;
411 }
412 // Success on json_object_set_value transfers ownership of json_custom_data to json_object, so do not
413 // explicitly free json_custom_data after this point.
414 else if (json_object_set_value(json_object, JSON_CUSTOM_DATA_TAG, json_custom_data) != JSONSuccess)
415 {
416 LogError("failure setting %s value", JSON_CUSTOM_DATA_TAG);
417 json_value_free(json_custom_data);
418 error_encountered = true;
419 }
420 }
421
422 if (!error_encountered)
423 {
424 char* json_string = json_serialize_to_string(json_root);
425 if (json_string == NULL)
426 {
427 LogError("failure serializing json to string");
428 }
429 else
430 {
431 if (mallocAndStrcpy_s(&result, json_string) != 0)
432 {
433 LogError("failure constructing json result value");
434 }
435 json_free_serialized_string(json_string);
436 }
437 }
438 json_value_free(json_root);
439 }
440 }
441
442 return result;
443}
444
445static PROV_JSON_INFO* prov_transport_process_json_reply(const char* json_document, void* user_ctx)
446{
447 PROV_JSON_INFO* result;
448 JSON_Value* root_value;
449 JSON_Object* json_object;
450 if (user_ctx == NULL)
451 {
452 LogError("failure user_ctx is NULL");
453 result = NULL;
454 }
455 else if ((root_value = json_parse_string(json_document)) == NULL)
456 {
457 LogError("failure calling json_parse_string");
458 result = NULL;
459 }
460 else if ((json_object = json_value_get_object(root_value)) == NULL)
461 {
462 LogError("failure retrieving node root object");
463 json_value_free(root_value);
464 result = NULL;
465 }
466 else if ((result = malloc(sizeof(PROV_JSON_INFO))) == NULL)
467 {
468 LogError("failure allocating PROV_JSON_INFO");
469 json_value_free(root_value);
470 }
471 else
472 {
473 memset(result, 0, sizeof(PROV_JSON_INFO));
474 PROV_INSTANCE_INFO* prov_info = (PROV_INSTANCE_INFO*)user_ctx;
475 JSON_Value* json_status = json_object_get_value(json_object, JSON_NODE_STATUS);
476
477 if (json_status == NULL)
478 {
479 // Under TPM the status will be error if this is an authorization request. We need to make it unassigned.
480 if (prov_info->hsm_type == PROV_AUTH_TYPE_TPM)
481 {
482 result->prov_status = PROV_DEVICE_TRANSPORT_STATUS_UNASSIGNED;
483 }
484 else
485 {
486 result->prov_status = PROV_DEVICE_TRANSPORT_STATUS_ERROR;
487 }
488 }
489 else
490 {
491 // status can be NULL
492 const char* json_string = json_value_get_string(json_status);
493 if (json_string == NULL)
494 {
495 result->prov_status = PROV_DEVICE_TRANSPORT_STATUS_ERROR;
496 }
497 else
498 {
499 result->prov_status = retrieve_status_type(json_string);
500 }
501 }
502 switch (result->prov_status)
503 {
504 case PROV_DEVICE_TRANSPORT_STATUS_UNASSIGNED:
505 {
506 JSON_Value* auth_key;
507 if ((auth_key = json_object_get_value(json_object, JSON_NODE_AUTH_KEY)) == NULL)
508 {
509 LogError("failure retrieving json auth key value");
510 prov_info->error_reason = PROV_DEVICE_RESULT_PARSING;
511 free(result);
512 result = NULL;
513 }
514 else
515 {
516 const char* nonce_field = json_value_get_string(auth_key);
517 if ((result->authorization_key = Azure_Base64_Decode(nonce_field)) == NULL)
518 {
519 LogError("failure creating buffer nonce field");
520 prov_info->error_reason = PROV_DEVICE_RESULT_MEMORY;
521 free(result);
522 result = NULL;
523 }
524 else
525 {
526 result->key_name = retrieve_json_string(json_object, JSON_NODE_KEY_NAME, true);
527 if (result->key_name == NULL)
528 {
529 LogError("failure retrieving keyname field");
530 prov_info->error_reason = PROV_DEVICE_RESULT_PARSING;
531 BUFFER_delete(result->authorization_key);
532 free(result);
533 result = NULL;
534 }
535 }
536 }
537 break;
538 }
539
540 case PROV_DEVICE_TRANSPORT_STATUS_ASSIGNING:
541 if ((result->operation_id = retrieve_json_string(json_object, JSON_NODE_OPERATION_ID, true)) == NULL)
542 {
543 LogError("Failure: operation_id node is mising");
544 prov_info->error_reason = PROV_DEVICE_RESULT_PARSING;
545 free(result);
546 result = NULL;
547 }
548 break;
549
550 case PROV_DEVICE_TRANSPORT_STATUS_ASSIGNED:
551 {
552 JSON_Object* json_reg_status_node;
553 if ((json_reg_status_node = json_object_get_object(json_object, JSON_NODE_REG_STATUS)) == NULL)
554 {
555 LogError("failure retrieving json registration status node");
556 prov_info->error_reason = PROV_DEVICE_RESULT_PARSING;
557 free(result);
558 result = NULL;
559 }
560 else
561 {
562 if (prov_info->hsm_type == PROV_AUTH_TYPE_TPM)
563 {
564 JSON_Object* json_tpm_node;
565 JSON_Value* auth_key;
566
567 if ((json_tpm_node = json_object_get_object(json_reg_status_node, JSON_NODE_TPM_NODE)) == NULL)
568 {
569 LogError("failure retrieving tpm node json_tpm_node: %p, auth key: %p", json_tpm_node, result->authorization_key);
570 free(result);
571 prov_info->error_reason = PROV_DEVICE_RESULT_PARSING;
572 result = NULL;
573 }
574 else if ((auth_key = json_object_get_value(json_tpm_node, JSON_NODE_AUTH_KEY)) == NULL)
575 {
576 LogError("failure retrieving json auth key value");
577 free(result);
578 prov_info->error_reason = PROV_DEVICE_RESULT_PARSING;
579 result = NULL;
580 }
581 else
582 {
583 const char* nonce_field = json_value_get_string(auth_key);
584 if (nonce_field == NULL)
585 {
586 LogError("failure getting nonce field from json");
587 prov_info->error_reason = PROV_DEVICE_RESULT_MEMORY;
588 free(result);
589 result = NULL;
590 }
591 else if ((result->authorization_key = Azure_Base64_Decode(nonce_field)) == NULL)
592 {
593 LogError("failure creating buffer nonce field");
594 prov_info->error_reason = PROV_DEVICE_RESULT_MEMORY;
595 free(result);
596 result = NULL;
597 }
598 }
599 }
600
601 if (result != NULL)
602 {
603 if (
604 ((result->iothub_uri = retrieve_json_string(json_reg_status_node, JSON_NODE_ASSIGNED_HUB, true)) == NULL) ||
605 ((result->device_id = retrieve_json_string(json_reg_status_node, JSON_NODE_DEVICE_ID, true)) == NULL)
606 )
607 {
608 LogError("failure retrieving json value assigned_hub: %p, device_id: %p", result->iothub_uri, result->device_id);
609 prov_info->error_reason = PROV_DEVICE_RESULT_PARSING;
610 free(result->iothub_uri);
611 free(result->authorization_key);
612 free(result);
613 result = NULL;
614 }
615 else
616 {
617 // Get the returned Data from the payload if it's there
618 retrieve_json_payload(json_reg_status_node, prov_info);
619 }
620 }
621 }
622 break;
623 }
624
625 case PROV_DEVICE_TRANSPORT_STATUS_BLACKLISTED:
626 LogError("The device is unauthorized with service");
627 prov_info->error_reason = PROV_DEVICE_RESULT_ERROR;
628 free(result);
629 result = NULL;
630 break;
631
632 case PROV_DEVICE_TRANSPORT_STATUS_ERROR:
633 {
634 char* json_operation_id = NULL;
635 JSON_Object* json_reg_state = NULL;
636 if ((json_reg_state = json_object_get_object(json_object, JSON_NODE_REG_STATUS)) != NULL &&
637 (json_operation_id = retrieve_json_string(json_object, JSON_NODE_OPERATION_ID, true)) != NULL)
638 {
639 int error_code = retrieve_json_number(json_reg_state, JSON_NODE_ERROR_CODE);
640 switch (error_code)
641 {
642 case DPS_HUB_ERROR_NO_HUB:
643 prov_info->error_reason = PROV_DEVICE_RESULT_HUB_NOT_SPECIFIED;
644 break;
645 case DPS_HUB_ERROR_UNAUTH:
646 prov_info->error_reason = PROV_DEVICE_RESULT_UNAUTHORIZED;
647 break;
648 default:
649 prov_info->error_reason = PROV_DEVICE_RESULT_DEV_AUTH_ERROR;
650 break;
651 }
652#ifndef NO_LOGGING
653 JSON_Value* json_error_date_time = NULL;
654 JSON_Value* json_error_msg = NULL;
655 if ((json_error_msg = json_object_get_value(json_reg_state, JSON_NODE_ERROR_MSG)) != NULL &&
656 (json_error_date_time = json_object_get_value(json_reg_state, JSON_NODE_DATE_TIME)) != NULL)
657 {
658 LogError("Provisioning Failure: OperationId: %s - Date: %s - Msg: %s", json_operation_id, json_value_get_string(json_error_date_time), json_value_get_string(json_error_msg) );
659 }
660 else
661 {
662 LogError("Unsuccessful json encountered: %s", json_document);
663 }
664 free(json_operation_id);
665#endif
666 }
667 else
668 {
669 prov_info->error_reason = PROV_DEVICE_RESULT_DEV_AUTH_ERROR;
670 LogError("Unsuccessful json encountered: %s", json_document);
671 }
672 free(result);
673 result = NULL;
674 break;
675 }
676
677 case PROV_DEVICE_TRANSPORT_STATUS_DISABLED:
678 LogError("The device has been disabled by DPS service");
679 prov_info->error_reason = PROV_DEVICE_RESULT_DISABLED;
680 free(result);
681 result = NULL;
682 break;
683
684 default:
685 LogError("invalid json status specified %d", result->prov_status);
686 free(result);
687 result = NULL;
688 break;
689 }
690 json_value_free(root_value);
691 }
692 return result;
693}
694
695static void cleanup_prov_info(PROV_INSTANCE_INFO* prov_info)
696{
697 if (prov_info->transport_open)
698 {
699 prov_info->prov_transport_protocol->prov_transport_close(prov_info->transport_handle);
700 prov_info->transport_open = false;
701 prov_info->is_connected = false;
702 }
703 free(prov_info->registration_id);
704 prov_info->registration_id = NULL;
705 free(prov_info->iothub_info.device_id);
706 prov_info->iothub_info.device_id = NULL;
707 free(prov_info->iothub_info.iothub_key);
708 prov_info->iothub_info.iothub_key = NULL;
709 free(prov_info->iothub_info.iothub_url);
710 prov_info->iothub_info.iothub_url = NULL;
711 prov_info->auth_attempts_made = 0;
712}
713
714static void on_transport_registration_data(PROV_DEVICE_TRANSPORT_RESULT transport_result, BUFFER_HANDLE iothub_key, const char* assigned_hub, const char* device_id, void* user_ctx)
715{
716 if (user_ctx == NULL)
717 {
718 LogError("user context was unexpectantly NULL");
719 }
720 else
721 {
722 PROV_INSTANCE_INFO* prov_info = (PROV_INSTANCE_INFO*)user_ctx;
723 if (transport_result == PROV_DEVICE_TRANSPORT_RESULT_OK)
724 {
725 if (prov_info->hsm_type == PROV_AUTH_TYPE_TPM)
726 {
727 if (iothub_key == NULL)
728 {
729 prov_info->prov_state = CLIENT_STATE_ERROR;
730 if (prov_info->error_reason == PROV_DEVICE_RESULT_OK)
731 {
732 prov_info->error_reason = PROV_DEVICE_RESULT_KEY_ERROR;
733 }
734 LogError("invalid iothub device key");
735 }
736 else
737 {
738 const unsigned char* key_value = BUFFER_u_char(iothub_key);
739 size_t key_len = BUFFER_length(iothub_key);
740
741 /* Codes_SRS_SECURE_ENCLAVE_CLIENT_07_028: [ prov_auth_import_key shall import the specified key into the tpm using secure_device_import_key secure enclave function. ] */
742 if (prov_auth_import_key(prov_info->prov_auth_handle, key_value, key_len) != 0)
743 {
744 prov_info->prov_state = CLIENT_STATE_ERROR;
745 prov_info->error_reason = PROV_DEVICE_RESULT_KEY_ERROR;
746 LogError("Failure to import the provisioning key");
747 }
748 }
749 }
750
751 if (prov_info->prov_state != CLIENT_STATE_ERROR)
752 {
753 prov_info->register_callback(PROV_DEVICE_RESULT_OK, assigned_hub, device_id, prov_info->user_context);
754 prov_info->prov_state = CLIENT_STATE_READY;
755 cleanup_prov_info(prov_info);
756 }
757 }
758 else if (transport_result == PROV_DEVICE_TRANSPORT_RESULT_UNAUTHORIZED)
759 {
760 prov_info->prov_state = CLIENT_STATE_ERROR;
761 prov_info->error_reason = PROV_DEVICE_RESULT_DEV_AUTH_ERROR;
762 LogError("provisioning result is unauthorized");
763 }
764 else
765 {
766 prov_info->prov_state = CLIENT_STATE_ERROR;
767 if (prov_info->error_reason == PROV_DEVICE_RESULT_OK)
768 {
769 prov_info->error_reason = PROV_DEVICE_RESULT_TRANSPORT;
770 }
771 LogError("Failure retrieving data from the provisioning service");
772 }
773 }
774}
775
776static void on_transport_status(PROV_DEVICE_TRANSPORT_STATUS transport_status, uint32_t retry_interval, void* user_ctx)
777{
778 if (user_ctx == NULL)
779 {
780 LogError("user_ctx was unexpectatly NULL");
781 }
782 else
783 {
784 PROV_INSTANCE_INFO* prov_info = (PROV_INSTANCE_INFO*)user_ctx;
785
786 prov_info->retry_after_ms = (size_t)retry_interval * 1000; // retry_interval is in seconds.
787
788 switch (transport_status)
789 {
790 case PROV_DEVICE_TRANSPORT_STATUS_CONNECTED:
791 prov_info->is_connected = true;
792 if (prov_info->register_status_cb != NULL)
793 {
794 prov_info->register_status_cb(PROV_DEVICE_REG_STATUS_CONNECTED, prov_info->status_user_ctx);
795 }
796 break;
797 case PROV_DEVICE_TRANSPORT_STATUS_AUTHENTICATED:
798 case PROV_DEVICE_TRANSPORT_STATUS_ASSIGNING:
799 case PROV_DEVICE_TRANSPORT_STATUS_UNASSIGNED:
800 prov_info->prov_state = CLIENT_STATE_STATUS_SEND;
801 if (transport_status == PROV_DEVICE_TRANSPORT_STATUS_UNASSIGNED)
802 {
803 if (prov_info->register_status_cb != NULL)
804 {
805 prov_info->register_status_cb(PROV_DEVICE_REG_STATUS_REGISTERING, prov_info->status_user_ctx);
806 }
807 }
808 else if (transport_status == PROV_DEVICE_TRANSPORT_STATUS_ASSIGNING)
809 {
810 if (prov_info->register_status_cb != NULL)
811 {
812 prov_info->register_status_cb(PROV_DEVICE_REG_STATUS_ASSIGNING, prov_info->status_user_ctx);
813 }
814 }
815 break;
816 case PROV_DEVICE_TRANSPORT_STATUS_TRANSIENT:
817 if (prov_info->prov_state == CLIENT_STATE_REGISTER_SENT)
818 {
819 prov_info->prov_state = CLIENT_STATE_REGISTER_SEND;
820 }
821 else if (prov_info->prov_state == CLIENT_STATE_STATUS_SENT)
822 {
823 prov_info->prov_state = CLIENT_STATE_STATUS_SEND;
824 }
825 else
826 {
827 // Ideally this should not happen
828 LogError("State Error: Transient Error occured in the %d state", (int)transport_status);
829 }
830 break;
831 default:
832 LogError("Unknown status encountered");
833 break;
834 }
835 }
836}
837
838static void destroy_instance(PROV_INSTANCE_INFO* prov_info)
839{
840 cleanup_prov_info(prov_info);
841 // Clean custom request data
842 free(prov_info->custom_request_data);
843 prov_info->custom_request_data = NULL;
844 if (prov_info->custom_response_data != NULL)
845 {
846 json_free_serialized_string(prov_info->custom_response_data);
847 prov_info->custom_response_data = NULL;
848 }
849 prov_info->prov_transport_protocol->prov_transport_destroy(prov_info->transport_handle);
850 prov_info->transport_handle = NULL;
851 free(prov_info->scope_id);
852 prov_auth_destroy(prov_info->prov_auth_handle);
853 tickcounter_destroy(prov_info->tick_counter);
854 free(prov_info);
855}
856
857PROV_DEVICE_LL_HANDLE Prov_Device_LL_Create(const char* uri, const char* id_scope, PROV_DEVICE_TRANSPORT_PROVIDER_FUNCTION protocol)
858{
859 PROV_INSTANCE_INFO* result;
860 /* Codes_SRS_PROV_CLIENT_07_001: [If uri is NULL Prov_Device_LL_CreateFromUri shall return NULL.] */
861 if (uri == NULL || id_scope == NULL || protocol == NULL)
862 {
863 LogError("Invalid parameter specified uri: %p, id_scope: %p, protocol: %p", uri, id_scope, protocol);
864 result = NULL;
865 }
866 else
867 {
868 srand((unsigned int)get_time(NULL));
869
870 /* Codes_SRS_PROV_CLIENT_07_002: [ Prov_Device_LL_CreateFromUri shall allocate a PROV_DEVICE_LL_HANDLE and initialize all members. ] */
871 result = (PROV_INSTANCE_INFO*)malloc(sizeof(PROV_INSTANCE_INFO));
872 if (result == NULL)
873 {
874 LogError("unable to allocate Instance Info");
875 }
876 else
877 {
878 memset(result, 0, sizeof(PROV_INSTANCE_INFO));
879
880 /* Codes_SRS_PROV_CLIENT_07_028: [ CLIENT_STATE_READY is the initial state after the object is created which will send a uhttp_client_open call to the http endpoint. ] */
881 result->prov_state = CLIENT_STATE_READY;
882 result->retry_after_ms = PROV_GET_THROTTLE_TIME * 1000;
883 result->prov_transport_protocol = protocol();
884 result->error_reason = PROV_DEVICE_RESULT_OK;
885
886 /* Codes_SRS_PROV_CLIENT_07_034: [ Prov_Device_LL_Create shall construct a id_scope by base64 encoding the uri. ] */
887 if (mallocAndStrcpy_s(&result->scope_id, id_scope) != 0)
888 {
889 /* Codes_SRS_PROV_CLIENT_07_003: [ If any error is encountered, Prov_Device_LL_CreateFromUri shall return NULL. ] */
890 LogError("failed to construct id_scope");
891 free(result);
892 result = NULL;
893 }
894 else if ((result->prov_auth_handle = prov_auth_create()) == NULL)
895 {
896 /* Codes_SRS_PROV_CLIENT_07_003: [ If any error is encountered, Prov_Device_LL_CreateFromUri shall return NULL. ] */
897 LogError("failed calling prov_auth_create\r\n");
898 destroy_instance(result);
899 result = NULL;
900 }
901 else if ((result->tick_counter = tickcounter_create()) == NULL)
902 {
903 LogError("failure: allocating tickcounter");
904 destroy_instance(result);
905 result = NULL;
906 }
907 else
908 {
909 TRANSPORT_HSM_TYPE hsm_type;
910 if ((result->hsm_type = prov_auth_get_type(result->prov_auth_handle)) == PROV_AUTH_TYPE_TPM)
911 {
912 hsm_type = TRANSPORT_HSM_TYPE_TPM;
913 }
914 else if (result->hsm_type == PROV_AUTH_TYPE_KEY)
915 {
916 hsm_type = TRANSPORT_HSM_TYPE_SYMM_KEY;
917 }
918 else
919 {
920 hsm_type = TRANSPORT_HSM_TYPE_X509;
921 }
922
923 if ((result->transport_handle = result->prov_transport_protocol->prov_transport_create(uri, hsm_type, result->scope_id, PROV_API_VERSION, on_transport_error, result)) == NULL)
924 {
925 /* Codes_SRS_PROV_CLIENT_07_003: [ If any error is encountered, Prov_Device_LL_CreateFromUri shall return NULL. ] */
926 LogError("failed calling into transport create");
927 destroy_instance(result);
928 result = NULL;
929 }
930 else
931 {
932 // Ensure that we are passed the throttling time and send on the first send
933 (void)tickcounter_get_current_ms(result->tick_counter, &result->last_send_time_ms);
934 result->last_send_time_ms += result->retry_after_ms;
935 }
936 }
937 }
938 }
939 return (PROV_DEVICE_LL_HANDLE)result;
940}
941
942void Prov_Device_LL_Destroy(PROV_DEVICE_LL_HANDLE handle)
943{
944 /* Codes_SRS_PROV_CLIENT_07_005: [ If handle is NULL Prov_Device_LL_Destroy shall do nothing. ] */
945 if (handle != NULL)
946 {
947 /* Codes_SRS_PROV_CLIENT_07_006: [ Prov_Device_LL_Destroy shall destroy resources associated with the IoTHub_client ] */
948 destroy_instance(handle);
949 }
950}
951
952PROV_DEVICE_RESULT Prov_Device_LL_Register_Device(PROV_DEVICE_LL_HANDLE handle, PROV_DEVICE_CLIENT_REGISTER_DEVICE_CALLBACK register_callback, void* user_context, PROV_DEVICE_CLIENT_REGISTER_STATUS_CALLBACK reg_status_cb, void* status_ctx)
953{
954 PROV_DEVICE_RESULT result;
955 /* Codes_SRS_PROV_CLIENT_07_007: [ If handle or register_callback is NULL, Prov_Device_LL_Register_Device shall return PROV_CLIENT_INVALID_ARG. ] */
956 if (handle == NULL || register_callback == NULL)
957 {
958 LogError("Invalid parameter specified handle: %p register_callback: %p", handle, register_callback);
959 result = PROV_DEVICE_RESULT_INVALID_ARG;
960 }
961 /* Codes_SRS_PROV_CLIENT_07_035: [ Prov_Device_LL_Create shall store the registration_id from the security module. ] */
962 else if (handle->registration_id == NULL && (handle->registration_id = prov_auth_get_registration_id(handle->prov_auth_handle)) == NULL)
963 {
964 /* Codes_SRS_PROV_CLIENT_07_003: [ If any error is encountered, Prov_Device_LL_CreateFromUri shall return NULL. ] */
965 LogError("failure: Unable to retrieve registration Id from device auth.");
966 result = PROV_DEVICE_RESULT_ERROR;
967 }
968 else
969 {
970 BUFFER_HANDLE ek_value = NULL;
971 BUFFER_HANDLE srk_value = NULL;
972
973 if (handle->prov_state != CLIENT_STATE_READY)
974 {
975 LogError("state is invalid");
976 if (!handle->user_supplied_reg_id)
977 {
978 free(handle->registration_id);
979 handle->registration_id = NULL;
980 }
981 result = PROV_DEVICE_RESULT_ERROR;
982 }
983 else
984 {
985 if (handle->hsm_type == PROV_AUTH_TYPE_TPM)
986 {
987 if ((ek_value = prov_auth_get_endorsement_key(handle->prov_auth_handle)) == NULL)
988 {
989 LogError("Could not get endorsement key from tpm");
990 if (!handle->user_supplied_reg_id)
991 {
992 free(handle->registration_id);
993 handle->registration_id = NULL;
994 }
995 result = PROV_DEVICE_RESULT_ERROR;
996 }
997 else if ((srk_value = prov_auth_get_storage_key(handle->prov_auth_handle)) == NULL)
998 {
999 LogError("Could not get storage root key from tpm");
1000 if (!handle->user_supplied_reg_id)
1001 {
1002 free(handle->registration_id);
1003 handle->registration_id = NULL;
1004 }
1005 result = PROV_DEVICE_RESULT_ERROR;
1006 BUFFER_delete(ek_value);
1007 }
1008 else
1009 {
1010 result = PROV_DEVICE_RESULT_OK;
1011 }
1012 }
1013 else if (handle->hsm_type == PROV_AUTH_TYPE_X509)
1014 {
1015 char* x509_cert;
1016 char* x509_private_key;
1017 if ((x509_cert = prov_auth_get_certificate(handle->prov_auth_handle)) == NULL)
1018 {
1019 LogError("Could not get the x509 certificate");
1020 if (!handle->user_supplied_reg_id)
1021 {
1022 free(handle->registration_id);
1023 handle->registration_id = NULL;
1024 }
1025 result = PROV_DEVICE_RESULT_ERROR;
1026 }
1027 else if ((x509_private_key = prov_auth_get_alias_key(handle->prov_auth_handle)) == NULL)
1028 {
1029 LogError("Could not get the x509 alias key");
1030 if (!handle->user_supplied_reg_id)
1031 {
1032 free(handle->registration_id);
1033 handle->registration_id = NULL;
1034 }
1035 free(x509_cert);
1036 result = PROV_DEVICE_RESULT_ERROR;
1037 }
1038 else
1039 {
1040 if (handle->prov_transport_protocol->prov_transport_x509_cert(handle->transport_handle, x509_cert, x509_private_key) != 0)
1041 {
1042 LogError("unable to set the x509 certificate information on transport");
1043 if (!handle->user_supplied_reg_id)
1044 {
1045 free(handle->registration_id);
1046 handle->registration_id = NULL;
1047 }
1048 result = PROV_DEVICE_RESULT_ERROR;
1049 }
1050 else
1051 {
1052 result = PROV_DEVICE_RESULT_OK;
1053 }
1054 free(x509_cert);
1055 free(x509_private_key);
1056 }
1057 }
1058 else
1059 {
1060 result = PROV_DEVICE_RESULT_OK;
1061 }
1062 }
1063 if (result == PROV_DEVICE_RESULT_OK)
1064 {
1065 /* Codes_SRS_PROV_CLIENT_07_008: [ Prov_Device_LL_Register_Device shall set the state to send the registration request to on subsequent DoWork calls. ] */
1066 handle->register_callback = register_callback;
1067 handle->user_context = user_context;
1068
1069 handle->register_status_cb = reg_status_cb;
1070 handle->status_user_ctx = status_ctx;
1071
1072 // Free the custom data if its been allocated
1073 if (handle->custom_response_data != NULL)
1074 {
1075 json_free_serialized_string(handle->custom_response_data);
1076 handle->custom_response_data = NULL;
1077 }
1078
1079 if (handle->prov_transport_protocol->prov_transport_open(handle->transport_handle, handle->registration_id, ek_value, srk_value, on_transport_registration_data, handle, on_transport_status, handle, prov_transport_challenge_callback, handle) != 0)
1080 {
1081 LogError("Failure establishing connection");
1082 if (!handle->user_supplied_reg_id)
1083 {
1084 free(handle->registration_id);
1085 handle->registration_id = NULL;
1086 }
1087 handle->register_callback = NULL;
1088 handle->user_context = NULL;
1089
1090 handle->register_status_cb = NULL;
1091 handle->status_user_ctx = NULL;
1092 result = PROV_DEVICE_RESULT_ERROR;
1093 }
1094 else
1095 {
1096 handle->transport_open = true;
1097 handle->prov_state = CLIENT_STATE_REGISTER_SEND;
1098 /* Codes_SRS_PROV_CLIENT_07_009: [ Upon success Prov_Device_LL_Register_Device shall return PROV_CLIENT_OK. ] */
1099 result = PROV_DEVICE_RESULT_OK;
1100 }
1101 BUFFER_delete(ek_value);
1102 BUFFER_delete(srk_value);
1103 }
1104 }
1105 return result;
1106}
1107
1108void Prov_Device_LL_DoWork(PROV_DEVICE_LL_HANDLE handle)
1109{
1110 /* Codes_SRS_PROV_CLIENT_07_010: [ If handle is NULL, Prov_Device_LL_DoWork shall do nothing. ] */
1111 if (handle != NULL)
1112 {
1113 PROV_INSTANCE_INFO* prov_info = (PROV_INSTANCE_INFO*)handle;
1114 /* Codes_SRS_PROV_CLIENT_07_011: [ Prov_Device_LL_DoWork shall call the underlying http_client_dowork function ] */
1115 if (prov_info->prov_state != CLIENT_STATE_ERROR)
1116 {
1117 prov_info->prov_transport_protocol->prov_transport_dowork(prov_info->transport_handle);
1118 }
1119 if (prov_info->is_connected || prov_info->prov_state == CLIENT_STATE_ERROR)
1120 {
1121 tickcounter_ms_t current_time = 0;
1122
1123 switch (prov_info->prov_state)
1124 {
1125 case CLIENT_STATE_REGISTER_SEND:
1126 if (tickcounter_get_current_ms(prov_info->tick_counter, &current_time) != 0)
1127 {
1128 LogError("Failure getting the current time");
1129 prov_info->error_reason = PROV_DEVICE_RESULT_ERROR;
1130 prov_info->prov_state = CLIENT_STATE_ERROR;
1131 }
1132 else
1133 {
1134 if ((current_time - prov_info->last_send_time_ms) > prov_info->retry_after_ms)
1135 {
1136 /* Codes_SRS_PROV_CLIENT_07_013: [ CLIENT_STATE_REGISTER_SEND which shall construct an initial call to the service with endorsement information ] */
1137 if (prov_info->prov_transport_protocol->prov_transport_register(prov_info->transport_handle, prov_transport_process_json_reply, prov_transport_create_json_payload, prov_info) != 0)
1138 {
1139 LogError("Failure registering device");
1140 if (prov_info->error_reason == PROV_DEVICE_RESULT_OK)
1141 {
1142 prov_info->error_reason = PROV_DEVICE_RESULT_TRANSPORT;
1143 }
1144 prov_info->prov_state = CLIENT_STATE_ERROR;
1145 }
1146 else
1147 {
1148 (void)tickcounter_get_current_ms(prov_info->tick_counter, &prov_info->timeout_value);
1149 prov_info->prov_state = CLIENT_STATE_REGISTER_SENT;
1150 }
1151 prov_info->last_send_time_ms = current_time;
1152 }
1153 }
1154 break;
1155
1156 case CLIENT_STATE_STATUS_SEND:
1157 {
1158 if (tickcounter_get_current_ms(prov_info->tick_counter, &current_time) != 0)
1159 {
1160 LogError("Failure getting the current time");
1161 prov_info->error_reason = PROV_DEVICE_RESULT_ERROR;
1162 prov_info->prov_state = CLIENT_STATE_ERROR;
1163 }
1164 else
1165 {
1166 if ((current_time - prov_info->last_send_time_ms) > prov_info->retry_after_ms)
1167 {
1168 /* Codes_SRS_PROV_CLIENT_07_026: [ Upon receiving the reply of the CLIENT_STATE_URL_REQ_SEND message from iothub_client shall process the the reply of the CLIENT_STATE_URL_REQ_SEND state ] */
1169 if (prov_info->prov_transport_protocol->prov_transport_get_op_status(prov_info->transport_handle) != 0)
1170 {
1171 LogError("Failure sending operation status");
1172 if (prov_info->error_reason == PROV_DEVICE_RESULT_OK)
1173 {
1174 prov_info->error_reason = PROV_DEVICE_RESULT_TRANSPORT;
1175 }
1176 prov_info->prov_state = CLIENT_STATE_ERROR;
1177 }
1178 else
1179 {
1180 prov_info->prov_state = CLIENT_STATE_STATUS_SENT;
1181 if (tickcounter_get_current_ms(prov_info->tick_counter, &prov_info->timeout_value) != 0)
1182 {
1183 LogError("Failure getting the current time");
1184 prov_info->error_reason = PROV_DEVICE_RESULT_ERROR;
1185 prov_info->prov_state = CLIENT_STATE_ERROR;
1186 }
1187 }
1188 prov_info->last_send_time_ms = current_time;
1189 }
1190 }
1191 break;
1192 }
1193
1194 case CLIENT_STATE_REGISTER_SENT:
1195 case CLIENT_STATE_STATUS_SENT:
1196 {
1197 if (prov_info->prov_timeout > 0)
1198 {
1199 (void)tickcounter_get_current_ms(prov_info->tick_counter, &current_time);
1200 if ((current_time - prov_info->timeout_value) / 1000 > prov_info->prov_timeout)
1201 {
1202 LogError("Timeout waiting for reply");
1203 prov_info->error_reason = PROV_DEVICE_RESULT_TIMEOUT;
1204 prov_info->prov_state = CLIENT_STATE_ERROR;
1205 }
1206 }
1207 break;
1208 }
1209
1210 case CLIENT_STATE_READY:
1211 break;
1212
1213 case CLIENT_STATE_ERROR:
1214 default:
1215 prov_info->register_callback(prov_info->error_reason, NULL, NULL, prov_info->user_context);
1216 prov_info->prov_state = CLIENT_STATE_READY;
1217 cleanup_prov_info(prov_info);
1218 break;
1219 }
1220 }
1221 else
1222 {
1223 // Check the connection
1224 if ((prov_info->prov_state != CLIENT_STATE_READY) && (prov_info->prov_timeout > 0))
1225 {
1226 tickcounter_ms_t current_time = 0;
1227 (void)tickcounter_get_current_ms(prov_info->tick_counter, &current_time);
1228 if ((current_time - prov_info->timeout_value) / 1000 > prov_info->prov_timeout)
1229 {
1230 LogError("Timed out connecting to provisioning service");
1231 prov_info->error_reason = PROV_DEVICE_RESULT_TIMEOUT;
1232 prov_info->prov_state = CLIENT_STATE_ERROR;
1233 }
1234 }
1235 }
1236 }
1237}
1238
1239PROV_DEVICE_RESULT Prov_Device_LL_SetOption(PROV_DEVICE_LL_HANDLE handle, const char* option_name, const void* value)
1240{
1241 PROV_DEVICE_RESULT result;
1242 if (handle == NULL || option_name == NULL)
1243 {
1244 LogError("Invalid parameter specified handle: %p option_name: %p", handle, option_name);
1245 result = PROV_DEVICE_RESULT_INVALID_ARG;
1246 }
1247 else
1248 {
1249 if (strcmp(option_name, OPTION_TRUSTED_CERT) == 0)
1250 {
1251 const char* cert_info = (const char*)value;
1252 if (handle->prov_transport_protocol->prov_transport_trusted_cert(handle->transport_handle, cert_info) != 0)
1253 {
1254 result = PROV_DEVICE_RESULT_ERROR;
1255 LogError("failure allocating certificate");
1256 }
1257 else
1258 {
1259 result = PROV_DEVICE_RESULT_OK;
1260 }
1261 }
1262 else if (strcmp(OPTION_LOG_TRACE, option_name) == 0)
1263 {
1264 bool log_trace = *((bool*)value);
1265 if (handle->prov_transport_protocol->prov_transport_set_trace(handle->transport_handle, log_trace) != 0)
1266 {
1267 result = PROV_DEVICE_RESULT_ERROR;
1268 LogError("failure setting trace option");
1269 }
1270 else
1271 {
1272 result = PROV_DEVICE_RESULT_OK;
1273 }
1274 }
1275 else if (strcmp(OPTION_HTTP_PROXY, option_name) == 0)
1276 {
1277 /* Codes_SRS_IOTHUB_TRANSPORT_MQTT_COMMON_01_001: [ If `option` is `proxy_data`, `value` shall be used as an `HTTP_PROXY_OPTIONS*`. ]*/
1278 HTTP_PROXY_OPTIONS* proxy_options = (HTTP_PROXY_OPTIONS*)value;
1279
1280 if (handle->prov_transport_protocol->prov_transport_set_proxy(handle->transport_handle, proxy_options) != 0)
1281 {
1282 LogError("setting proxy options");
1283 result = PROV_DEVICE_RESULT_ERROR;
1284 }
1285 else
1286 {
1287 result = PROV_DEVICE_RESULT_OK;
1288 }
1289 }
1290 else if (strcmp(PROV_OPTION_TIMEOUT, option_name) == 0)
1291 {
1292 if (value == NULL)
1293 {
1294 LogError("setting PROV_OPTION_TIMEOUT option");
1295 result = PROV_DEVICE_RESULT_ERROR;
1296 }
1297 else
1298 {
1299 handle->prov_timeout = *((uint8_t*)value);
1300 result = PROV_DEVICE_RESULT_OK;
1301 }
1302 }
1303 else if (strcmp(PROV_REGISTRATION_ID, option_name) == 0)
1304 {
1305 if (handle->prov_state != CLIENT_STATE_READY)
1306 {
1307 LogError("registration id cannot be set after registration has begun");
1308 result = PROV_DEVICE_RESULT_ERROR;
1309 }
1310 else if (value == NULL)
1311 {
1312 LogError("value must be set to the correct registration id");
1313 result = PROV_DEVICE_RESULT_ERROR;
1314 }
1315 else
1316 {
1317 char* temp_reg;
1318 if (mallocAndStrcpy_s(&temp_reg, (const char*)value) != 0)
1319 {
1320 LogError("Failure allocating setting registration id");
1321 result = PROV_DEVICE_RESULT_ERROR;
1322 }
1323 else if (prov_auth_set_registration_id(handle->prov_auth_handle, temp_reg) != 0)
1324 {
1325 LogError("Failure setting registration id");
1326 free(temp_reg);
1327 result = PROV_DEVICE_RESULT_ERROR;
1328 }
1329 else
1330 {
1331 if (handle->registration_id != NULL)
1332 {
1333 free(handle->registration_id);
1334 }
1335 handle->registration_id = temp_reg;
1336 handle->user_supplied_reg_id = true;
1337 result = PROV_DEVICE_RESULT_OK;
1338 }
1339 }
1340 }
1341 else
1342 {
1343 if (handle->prov_transport_protocol->prov_transport_set_option(handle->transport_handle, option_name, value) != 0)
1344 {
1345 LogError("Failure in prov transport set option\n");
1346 result = PROV_DEVICE_RESULT_ERROR;
1347 }
1348 else
1349 {
1350 result = PROV_DEVICE_RESULT_OK;
1351 }
1352 }
1353 }
1354 return result;
1355}
1356
1357const char* Prov_Device_LL_GetVersionString(void)
1358{
1359 return PROV_DEVICE_CLIENT_VERSION;
1360}
1361
1362PROV_DEVICE_RESULT Prov_Device_LL_Set_Provisioning_Payload(PROV_DEVICE_LL_HANDLE handle, const char* jsonDataField)
1363{
1364 PROV_DEVICE_RESULT result;
1365 if (handle == NULL)
1366 {
1367 LogError("Invalid parameter specified handle: %p", handle);
1368 result = PROV_DEVICE_RESULT_INVALID_ARG;
1369 }
1370 else
1371 {
1372 char* temp_data;
1373 if (mallocAndStrcpy_s(&temp_data, jsonDataField) != 0)
1374 {
1375 LogError("Failure setting custom provisioning data");
1376 result = PROV_DEVICE_RESULT_ERROR;
1377 }
1378 else
1379 {
1380 if (handle->custom_request_data != NULL)
1381 {
1382 free(handle->custom_request_data);
1383 }
1384 handle->custom_request_data = temp_data;
1385 result = PROV_DEVICE_RESULT_OK;
1386 }
1387 }
1388 return result;
1389}
1390
1391const char* Prov_Device_LL_Get_Provisioning_Payload(PROV_DEVICE_LL_HANDLE handle)
1392{
1393 const char* result;
1394 if (handle == NULL)
1395 {
1396 LogError("Invalid parameter specified handle: %p", handle);
1397 result = NULL;
1398 }
1399 else
1400 {
1401 result = handle->custom_response_data;
1402 }
1403 return result;
1404}
Note: See TracBrowser for help on using the repository browser.