Microsoft Azure IoTHub client libraries

Dependents:   sht15_remote_monitoring RobotArmDemo iothub_client_sample_amqp f767zi_mqtt ... more

This library implements the Microsoft Azure IoTHub client library. The code is replicated from https://github.com/Azure/azure-iot-sdks

Revision:
46:6a69294b6119
Parent:
45:54c11b1b1407
Child:
47:aaa262b5f898
diff -r 54c11b1b1407 -r 6a69294b6119 iothub_client_ll_uploadtoblob.c
--- a/iothub_client_ll_uploadtoblob.c	Fri Jul 01 10:42:36 2016 -0700
+++ b/iothub_client_ll_uploadtoblob.c	Mon Jul 18 16:45:01 2016 -0700
@@ -30,10 +30,17 @@
 
 #define AUTHORIZATION_SCHEME_VALUES \
     DEVICE_KEY, \
+    X509,       \
     SAS_TOKEN
 
 DEFINE_ENUM(AUTHORIZATION_SCHEME, AUTHORIZATION_SCHEME_VALUES);
 
+typedef struct UPLOADTOBLOB_X509_CREDENTIALS_TAG
+{
+    const char* x509certificate;
+    const char* x509privatekey;
+}UPLOADTOBLOB_X509_CREDENTIALS;
+
 typedef struct IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE_DATA_TAG
 {
     STRING_HANDLE deviceId;                     /*needed for file upload*/
@@ -42,6 +49,7 @@
     union {
         STRING_HANDLE deviceKey;    /*used when authorizationScheme is DEVICE_KEY*/
         STRING_HANDLE sas;          /*used when authorizationScheme is SAS_TOKEN*/
+        UPLOADTOBLOB_X509_CREDENTIALS x509credentials; /*assumed to be used when both deviceKey and deviceSasToken are NULL*/
     } credentials;                              /*needed for file upload*/
 }IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE_DATA;
 
@@ -79,7 +87,7 @@
                 memcpy((char*)handleData->hostname, config->iotHubName, iotHubNameLength);
                 ((char*)handleData->hostname)[iotHubNameLength] = '.';
                 memcpy((char*)handleData->hostname + iotHubNameLength + 1, config->iotHubSuffix, iotHubSuffixLength + 1); /*+1 will copy the \0 too*/
-                if (config->deviceSasToken != NULL)
+                if ((config->deviceSasToken != NULL) && (config->deviceKey == NULL))
                 {
                     handleData->authorizationScheme = SAS_TOKEN;
                     handleData->credentials.sas = STRING_construct(config->deviceSasToken);
@@ -96,7 +104,7 @@
                         /*return as is*/
                     }
                 }
-                else
+                else if ((config->deviceSasToken == NULL) && (config->deviceKey != NULL))
                 {
                     handleData->authorizationScheme = DEVICE_KEY;
                     handleData->credentials.deviceKey = STRING_construct(config->deviceKey);
@@ -113,6 +121,13 @@
                         /*return as is*/
                     }
                 }
+                else if ((config->deviceSasToken == NULL) && (config->deviceKey == NULL))
+                {
+                    handleData->authorizationScheme = X509;
+                    handleData->credentials.x509credentials.x509certificate = NULL;
+                    handleData->credentials.x509credentials.x509privatekey = NULL;
+                    /*return as is*/
+                }
             }
         }
     }
@@ -160,11 +175,12 @@
             else
             {
                 /*Codes_SRS_IOTHUBCLIENT_LL_02_072: [ IoTHubClient_LL_UploadToBlob shall add the following name:value to request HTTP headers: ] "Content-Type": "application/json" "Accept": "application/json" "User-Agent": "iothubclient/" IOTHUB_SDK_VERSION*/
+                /*Codes_SRS_IOTHUBCLIENT_LL_02_107: [ - "Authorization" header shall not be build. ]*/
                 if (!(
                     (HTTPHeaders_AddHeaderNameValuePair(requestHttpHeaders, "Content-Type", "application/json") == HTTP_HEADERS_OK) &&
                     (HTTPHeaders_AddHeaderNameValuePair(requestHttpHeaders, "Accept", "application/json") == HTTP_HEADERS_OK) &&
                     (HTTPHeaders_AddHeaderNameValuePair(requestHttpHeaders, "User-Agent", "iothubclient/" IOTHUB_SDK_VERSION) == HTTP_HEADERS_OK) &&
-                    (HTTPHeaders_AddHeaderNameValuePair(requestHttpHeaders, "Authorization", "") == HTTP_HEADERS_OK)
+                    (handleData->authorizationScheme==X509 || (HTTPHeaders_AddHeaderNameValuePair(requestHttpHeaders, "Authorization", "") == HTTP_HEADERS_OK))
                     ))
                 {
                     /*Codes_SRS_IOTHUBCLIENT_LL_02_071: [ If creating the HTTP headers fails then IoTHubClient_LL_UploadToBlob shall fail and return IOTHUB_CLIENT_ERROR. ]*/
@@ -174,12 +190,49 @@
                 else
                 {
                     int wasIoTHubRequestSuccess = 0; /*!=0 means responseContent has a buffer that should be parsed by parson after executing the below switch*/
+                    /* set the result to error by default */
+                    result = __LINE__;
                     switch (handleData->authorizationScheme)
                     {
                     default:
                     {
                         /*wasIoTHubRequestSuccess takes care of the return value*/
                         LogError("Internal Error: unexpected value in handleData->authorizationScheme = %d", handleData->authorizationScheme);
+                        result = __LINE__;
+                        break;
+                    }
+                    case(X509):
+                    {
+                        unsigned int statusCode;
+                        /*Codes_SRS_IOTHUBCLIENT_LL_02_108: [ IoTHubClient_LL_UploadToBlob shall execute HTTPAPIEX_ExecuteRequest passing the following information for arguments: ]*/
+                        if (HTTPAPIEX_ExecuteRequest(
+                            iotHubHttpApiExHandle,          /*HTTPAPIEX_HANDLE handle - the handle created at the beginning of `IoTHubClient_LL_UploadToBlob`*/
+                            HTTPAPI_REQUEST_GET,            /*HTTPAPI_REQUEST_TYPE requestType - HTTPAPI_REQUEST_GET*/
+                            STRING_c_str(relativePath),     /*const char* relativePath - the HTTP relative path*/
+                            requestHttpHeaders,             /*HTTP_HEADERS_HANDLE requestHttpHeadersHandle - request HTTP headers*/
+                            NULL,                           /*BUFFER_HANDLE requestContent - NULL*/
+                            &statusCode,                    /*unsigned int* statusCode - the address of an unsigned int that will contain the HTTP status code*/
+                            NULL,                           /*HTTP_HEADERS_HANDLE responseHttpHeadersHandl - NULL*/
+                            responseContent                 /*BUFFER_HANDLE responseContent - the HTTP response BUFFER_HANDLE - responseContent*/
+                        ) != HTTPAPIEX_OK)
+                        {
+                            /*Codes_SRS_IOTHUBCLIENT_LL_02_076: [ If HTTPAPIEX_ExecuteRequest call fails then IoTHubClient_LL_UploadToBlob shall fail and return IOTHUB_CLIENT_ERROR. ]*/
+                            result = __LINE__;
+                            LogError("unable to HTTPAPIEX_ExecuteRequest");
+                        }
+                        else
+                        {
+                            /*Codes_SRS_IOTHUBCLIENT_LL_02_077: [ If HTTP statusCode is greater than or equal to 300 then IoTHubClient_LL_UploadToBlob shall fail and return IOTHUB_CLIENT_ERROR. ]*/
+                            if (statusCode >= 300)
+                            {
+                                result = __LINE__;
+                                LogError("HTTP code was %u", statusCode);
+                            }
+                            else
+                            {
+                                wasIoTHubRequestSuccess = 1;
+                            }
+                        }
                         break;
                     }
                     case (SAS_TOKEN):
@@ -217,7 +270,6 @@
                                 if (statusCode >= 300)
                                 {
                                     result = __LINE__;
-                                    wasIoTHubRequestSuccess = 0;
                                     LogError("HTTP code was %u", statusCode);
                                 }
                                 else
@@ -505,6 +557,37 @@
                         result = __LINE__;
                         break;
                     }
+                    case (X509):
+                    {
+                        unsigned int notificationStatusCode;
+                        if (HTTPAPIEX_ExecuteRequest(
+                            iotHubHttpApiExHandle,
+                            HTTPAPI_REQUEST_POST,
+                            STRING_c_str(relativePathNotification),
+                            requestHttpHeaders,
+                            messageBody,
+                            &notificationStatusCode,
+                            NULL,
+                            NULL) != HTTPAPIEX_OK)
+                        {
+                            LogError("unable to do HTTPAPIEX_ExecuteRequest");
+                            result = __LINE__;
+                        }
+                        else
+                        {
+                            if (notificationStatusCode >= 300)
+                            {
+                                /*Codes_SRS_IOTHUBCLIENT_LL_02_087: [If the statusCode of the HTTP request is greater than or equal to 300 then IoTHubClient_LL_UploadToBlob shall fail and return IOTHUB_CLIENT_ERROR]*/
+                                LogError("server didn't like the notification request");
+                                result = __LINE__;
+                            }
+                            else
+                            {
+                                result = 0;
+                            }
+                        }
+                        break;
+                    }
                     case (DEVICE_KEY):
                     {
                         STRING_HANDLE empty = STRING_new();
@@ -632,115 +715,133 @@
         }
         else
         {
-            STRING_HANDLE correlationId = STRING_new();
-            if (correlationId == NULL)
+            if (
+                (handleData->authorizationScheme == X509) &&
+
+                /*transmit the x509certificate and x509privatekey*/
+                /*Codes_SRS_IOTHUBCLIENT_LL_02_106: [ - x509certificate and x509privatekey saved options shall be passed on the HTTPAPIEX_SetOption ]*/
+                (!(
+                    (HTTPAPIEX_SetOption(iotHubHttpApiExHandle, "x509certificate", handleData->credentials.x509credentials.x509certificate) == HTTPAPIEX_OK) &&
+                    (HTTPAPIEX_SetOption(iotHubHttpApiExHandle, "x509privatekey", handleData->credentials.x509credentials.x509privatekey) == HTTPAPIEX_OK)
+                ))
+                )
             {
-                LogError("unable to STRING_new");
+                LogError("unable to HTTPAPIEX_SetOption for x509");
                 result = IOTHUB_CLIENT_ERROR;
             }
             else
             {
-                STRING_HANDLE sasUri = STRING_new();
-                if (sasUri == NULL)
+
+                STRING_HANDLE correlationId = STRING_new();
+                if (correlationId == NULL)
                 {
                     LogError("unable to STRING_new");
                     result = IOTHUB_CLIENT_ERROR;
                 }
                 else
                 {
-                    /*Codes_SRS_IOTHUBCLIENT_LL_02_070: [ IoTHubClient_LL_UploadToBlob shall create request HTTP headers. ]*/
-                    HTTP_HEADERS_HANDLE requestHttpHeaders = HTTPHeaders_Alloc(); /*these are build by step 1 and used by step 3 too*/
-                    if (requestHttpHeaders == NULL)
+                    STRING_HANDLE sasUri = STRING_new();
+                    if (sasUri == NULL)
                     {
-                        LogError("unable to HTTPHeaders_Alloc");
+                        LogError("unable to STRING_new");
                         result = IOTHUB_CLIENT_ERROR;
                     }
                     else
                     {
-                        /*do step 1*/
-                        if (IoTHubClient_LL_UploadToBlob_step1and2(handleData, iotHubHttpApiExHandle, requestHttpHeaders, destinationFileName, correlationId, sasUri) != 0)
+                        /*Codes_SRS_IOTHUBCLIENT_LL_02_070: [ IoTHubClient_LL_UploadToBlob shall create request HTTP headers. ]*/
+                        HTTP_HEADERS_HANDLE requestHttpHeaders = HTTPHeaders_Alloc(); /*these are build by step 1 and used by step 3 too*/
+                        if (requestHttpHeaders == NULL)
                         {
-                            LogError("error in IoTHubClient_LL_UploadToBlob_step1");
+                            LogError("unable to HTTPHeaders_Alloc");
                             result = IOTHUB_CLIENT_ERROR;
                         }
                         else
                         {
-                            /*do step 2.*/
-
-                            unsigned int httpResponse;
-                            BUFFER_HANDLE responseToIoTHub = BUFFER_new();
-                            if (responseToIoTHub == NULL)
+                            /*do step 1*/
+                            if (IoTHubClient_LL_UploadToBlob_step1and2(handleData, iotHubHttpApiExHandle, requestHttpHeaders, destinationFileName, correlationId, sasUri) != 0)
                             {
+                                LogError("error in IoTHubClient_LL_UploadToBlob_step1");
                                 result = IOTHUB_CLIENT_ERROR;
-                                LogError("unable to BUFFER_new");
                             }
                             else
                             {
-                                int step2success;
-                                /*Codes_SRS_IOTHUBCLIENT_LL_02_083: [ IoTHubClient_LL_UploadToBlob shall call Blob_UploadFromSasUri and capture the HTTP return code and HTTP body. ]*/
-                                step2success = (Blob_UploadFromSasUri(STRING_c_str(sasUri), source, size, &httpResponse, responseToIoTHub) == BLOB_OK);
-                                if (!step2success)
-                                {
-                                    /*Codes_SRS_IOTHUBCLIENT_LL_02_084: [ If Blob_UploadFromSasUri fails then IoTHubClient_LL_UploadToBlob shall fail and return IOTHUB_CLIENT_ERROR. ]*/
-                                    LogError("unable to Blob_UploadFromSasUri");
+                                /*do step 2.*/
 
-                                    /*do step 3*/ /*try*/
-                                    /*Codes_SRS_IOTHUBCLIENT_LL_02_091: [ If step 2 fails without establishing an HTTP dialogue, then the HTTP message body shall look like: ]*/
-                                    if (BUFFER_build(responseToIoTHub, (const unsigned char*)FILE_UPLOAD_FAILED_BODY, sizeof(FILE_UPLOAD_FAILED_BODY) / sizeof(FILE_UPLOAD_FAILED_BODY[0])) == 0)
-                                    {
-                                        if (IoTHubClient_LL_UploadToBlob_step3(handleData, correlationId, iotHubHttpApiExHandle, requestHttpHeaders, responseToIoTHub) != 0)
-                                        {
-                                            LogError("IoTHubClient_LL_UploadToBlob_step3 failed");
-                                        }
-                                    }
+                                unsigned int httpResponse;
+                                BUFFER_HANDLE responseToIoTHub = BUFFER_new();
+                                if (responseToIoTHub == NULL)
+                                {
                                     result = IOTHUB_CLIENT_ERROR;
+                                    LogError("unable to BUFFER_new");
                                 }
                                 else
                                 {
-                                    /*must make a json*/
-
-                                    int requiredStringLength = snprintf(NULL, 0, "{\"isSuccess\":%s, \"statusCode\":%d, \"statusDescription\":\"%s\"}", ((httpResponse < 300) ? "true" : "false"), httpResponse, BUFFER_u_char(responseToIoTHub));
+                                    int step2success;
+                                    /*Codes_SRS_IOTHUBCLIENT_LL_02_083: [ IoTHubClient_LL_UploadToBlob shall call Blob_UploadFromSasUri and capture the HTTP return code and HTTP body. ]*/
+                                    step2success = (Blob_UploadFromSasUri(STRING_c_str(sasUri), source, size, &httpResponse, responseToIoTHub) == BLOB_OK);
+                                    if (!step2success)
+                                    {
+                                        /*Codes_SRS_IOTHUBCLIENT_LL_02_084: [ If Blob_UploadFromSasUri fails then IoTHubClient_LL_UploadToBlob shall fail and return IOTHUB_CLIENT_ERROR. ]*/
+                                        LogError("unable to Blob_UploadFromSasUri");
 
-                                    char* requiredString = malloc(requiredStringLength + 1);
-                                    if (requiredString == 0)
-                                    {
-                                        LogError("unable to malloc");
+                                        /*do step 3*/ /*try*/
+                                        /*Codes_SRS_IOTHUBCLIENT_LL_02_091: [ If step 2 fails without establishing an HTTP dialogue, then the HTTP message body shall look like: ]*/
+                                        if (BUFFER_build(responseToIoTHub, (const unsigned char*)FILE_UPLOAD_FAILED_BODY, sizeof(FILE_UPLOAD_FAILED_BODY) / sizeof(FILE_UPLOAD_FAILED_BODY[0])) == 0)
+                                        {
+                                            if (IoTHubClient_LL_UploadToBlob_step3(handleData, correlationId, iotHubHttpApiExHandle, requestHttpHeaders, responseToIoTHub) != 0)
+                                            {
+                                                LogError("IoTHubClient_LL_UploadToBlob_step3 failed");
+                                            }
+                                        }
                                         result = IOTHUB_CLIENT_ERROR;
                                     }
                                     else
                                     {
-                                        /*do again snprintf*/
-                                        (void)snprintf(requiredString, requiredStringLength + 1, "{\"isSuccess\":%s, \"statusCode\":%d, \"statusDescription\":\"%s\"}", ((httpResponse < 300) ? "true" : "false"), httpResponse, BUFFER_u_char(responseToIoTHub));
-                                        BUFFER_HANDLE toBeTransmitted = BUFFER_create(requiredString, requiredStringLength);
-                                        if (toBeTransmitted == NULL)
+                                        /*must make a json*/
+
+                                        int requiredStringLength = snprintf(NULL, 0, "{\"isSuccess\":%s, \"statusCode\":%d, \"statusDescription\":\"%s\"}", ((httpResponse < 300) ? "true" : "false"), httpResponse, BUFFER_u_char(responseToIoTHub));
+
+                                        char* requiredString = malloc(requiredStringLength + 1);
+                                        if (requiredString == 0)
                                         {
-                                            LogError("unable to BUFFER_create");
+                                            LogError("unable to malloc");
                                             result = IOTHUB_CLIENT_ERROR;
                                         }
                                         else
                                         {
-                                            if (IoTHubClient_LL_UploadToBlob_step3(handleData, correlationId, iotHubHttpApiExHandle, requestHttpHeaders, toBeTransmitted) != 0)
+                                            /*do again snprintf*/
+                                            (void)snprintf(requiredString, requiredStringLength + 1, "{\"isSuccess\":%s, \"statusCode\":%d, \"statusDescription\":\"%s\"}", ((httpResponse < 300) ? "true" : "false"), httpResponse, BUFFER_u_char(responseToIoTHub));
+                                            BUFFER_HANDLE toBeTransmitted = BUFFER_create((const unsigned char*)requiredString, requiredStringLength);
+                                            if (toBeTransmitted == NULL)
                                             {
-                                                LogError("IoTHubClient_LL_UploadToBlob_step3 failed");
+                                                LogError("unable to BUFFER_create");
                                                 result = IOTHUB_CLIENT_ERROR;
                                             }
                                             else
                                             {
-                                                result = (httpResponse < 300) ? IOTHUB_CLIENT_OK : IOTHUB_CLIENT_ERROR;
+                                                if (IoTHubClient_LL_UploadToBlob_step3(handleData, correlationId, iotHubHttpApiExHandle, requestHttpHeaders, toBeTransmitted) != 0)
+                                                {
+                                                    LogError("IoTHubClient_LL_UploadToBlob_step3 failed");
+                                                    result = IOTHUB_CLIENT_ERROR;
+                                                }
+                                                else
+                                                {
+                                                    result = (httpResponse < 300) ? IOTHUB_CLIENT_OK : IOTHUB_CLIENT_ERROR;
+                                                }
+                                                BUFFER_delete(toBeTransmitted);
                                             }
-                                            BUFFER_delete(toBeTransmitted);
+                                            free(requiredString);
                                         }
-                                        free(requiredString);
                                     }
+                                    BUFFER_delete(responseToIoTHub);
                                 }
-                                BUFFER_delete(responseToIoTHub);
                             }
+                            HTTPHeaders_Free(requestHttpHeaders);
                         }
-                        HTTPHeaders_Free(requestHttpHeaders);
+                        STRING_delete(sasUri);
                     }
-                    STRING_delete(sasUri);
+                    STRING_delete(correlationId);
                 }
-                STRING_delete(correlationId);
             }
             HTTPAPIEX_Destroy(iotHubHttpApiExHandle);
         }
@@ -769,6 +870,18 @@
                 STRING_delete(handleData->credentials.deviceKey);
                 break;
             }
+            case(X509):
+            {
+                if (handleData->credentials.x509credentials.x509certificate != NULL)
+                {
+                    free((void*)handleData->credentials.x509credentials.x509certificate);
+                }
+                if (handleData->credentials.x509credentials.x509privatekey != NULL)
+                {
+                    free((void*)handleData->credentials.x509credentials.x509privatekey);
+                }
+                break;
+            }
             default:
             {
                 LogError("INTERNAL ERROR");
@@ -780,4 +893,94 @@
         free(handleData);
     }
 }
+
+IOTHUB_CLIENT_RESULT IoTHubClient_LL_UploadToBlob_SetOption(IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE handle, const char* optionName, const void* value)
+{
+    IOTHUB_CLIENT_RESULT result;
+    /*Codes_SRS_IOTHUBCLIENT_LL_02_110: [ If parameter handle is NULL then IoTHubClient_LL_UploadToBlob_SetOption shall fail and return IOTHUB_CLIENT_ERROR. ]*/
+    if (handle == NULL)
+    {
+        LogError("invalid argument detected: IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE handle=%p, const char* optionName=%s, const void* value=%p", handle, optionName, value);
+        result = IOTHUB_CLIENT_ERROR;
+    }
+    else
+    {
+        IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE_DATA* handleData = (IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE_DATA*)handle;
+
+        /*Codes_SRS_IOTHUBCLIENT_LL_02_100: [ x509certificate - then value then is a null terminated string that contains the x509 certificate. ]*/
+        if (strcmp(optionName, "x509certificate") == 0)
+        {
+            /*Codes_SRS_IOTHUBCLIENT_LL_02_109: [ If the authentication scheme is NOT x509 then IoTHubClient_LL_UploadToBlob_SetOption shall return IOTHUB_CLIENT_INVALID_ARG. ]*/
+            if (handleData->authorizationScheme != X509)
+            {
+                LogError("trying to set a x509 certificate while the authentication scheme is not x509");
+                result = IOTHUB_CLIENT_INVALID_ARG;
+            }
+            else
+            {
+                /*Codes_SRS_IOTHUBCLIENT_LL_02_103: [ The options shall be saved. ]*/
+                /*try to make a copy of the certificate*/
+                char* temp;
+                if (mallocAndStrcpy_s(&temp, value) != 0)
+                {
+                    /*Codes_SRS_IOTHUBCLIENT_LL_02_104: [ If saving fails, then IoTHubClient_LL_UploadToBlob_SetOption shall fail and return IOTHUB_CLIENT_ERROR. ]*/
+                    LogError("unable to mallocAndStrcpy_s");
+                    result = IOTHUB_CLIENT_ERROR;
+                }
+                else
+                {
+                    /*Codes_SRS_IOTHUBCLIENT_LL_02_105: [ Otherwise IoTHubClient_LL_UploadToBlob_SetOption shall succeed and return IOTHUB_CLIENT_OK. ]*/
+                    if (handleData->credentials.x509credentials.x509certificate != NULL) /*free any previous values, if any*/
+                    {
+                        free((void*)handleData->credentials.x509credentials.x509certificate);
+                    }
+                    handleData->credentials.x509credentials.x509certificate = temp;
+                    result = IOTHUB_CLIENT_OK;
+                }
+            }
+        }
+        /*Codes_SRS_IOTHUBCLIENT_LL_02_101: [ x509privatekey - then value is a null terminated string that contains the x509 privatekey. ]*/
+        else if (strcmp(optionName, "x509privatekey") == 0)
+        {
+            /*Codes_SRS_IOTHUBCLIENT_LL_02_109: [ If the authentication scheme is NOT x509 then IoTHubClient_LL_UploadToBlob_SetOption shall return IOTHUB_CLIENT_INVALID_ARG. ]*/
+            if (handleData->authorizationScheme != X509)
+            {
+                LogError("trying to set a x509 privatekey while the authentication scheme is not x509");
+                result = IOTHUB_CLIENT_INVALID_ARG;
+            }
+            else
+            {
+                /*Codes_SRS_IOTHUBCLIENT_LL_02_103: [ The options shall be saved. ]*/
+                /*try to make a copy of the privatekey*/
+                char* temp;
+                if (mallocAndStrcpy_s(&temp, value) != 0)
+                {
+                    /*Codes_SRS_IOTHUBCLIENT_LL_02_104: [ If saving fails, then IoTHubClient_LL_UploadToBlob_SetOption shall fail and return IOTHUB_CLIENT_ERROR. ]*/
+                    LogError("unable to mallocAndStrcpy_s");
+                    result = IOTHUB_CLIENT_ERROR;
+                }
+                else
+                {
+                    /*Codes_SRS_IOTHUBCLIENT_LL_02_105: [ Otherwise IoTHubClient_LL_UploadToBlob_SetOption shall succeed and return IOTHUB_CLIENT_OK. ]*/
+                    if (handleData->credentials.x509credentials.x509privatekey != NULL) /*free any previous values, if any*/
+                    {
+                        free((void*)handleData->credentials.x509credentials.x509privatekey);
+                    }
+                    handleData->credentials.x509credentials.x509privatekey = temp;
+                    result = IOTHUB_CLIENT_OK;
+                }
+            }
+        }
+        else
+        {
+            /*Codes_SRS_IOTHUBCLIENT_LL_02_102: [ If an unknown option is presented then IoTHubClient_LL_UploadToBlob_SetOption shall return IOTHUB_CLIENT_INVALID_ARG. ]*/
+            result = IOTHUB_CLIENT_INVALID_ARG;
+        }
+    }
+    return result;
+}
+
+
 #endif /*DONT_USE_UPLOADTOBLOB*/
+
+