Mark Radbourne / Mbed 2 deprecated FXOS8700CQ_To_Azure_IoT

Dependencies:   azure_umqtt_c iothub_mqtt_transport mbed-rtos mbed wolfSSL Socket lwip-eth lwip-sys lwip

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers sastoken.c Source File

sastoken.c

00001 // Copyright (c) Microsoft. All rights reserved.
00002 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
00003 
00004 #ifdef _CRTDBG_MAP_ALLOC
00005 #include <crtdbg.h>
00006 #endif
00007 
00008 #include "azure_c_shared_utility/gballoc.h"
00009 #include "azure_c_shared_utility/sastoken.h"
00010 #include "azure_c_shared_utility/urlencode.h"
00011 #include "azure_c_shared_utility/hmacsha256.h"
00012 #include "azure_c_shared_utility/base64.h"
00013 #include "azure_c_shared_utility/agenttime.h"
00014 #include "azure_c_shared_utility/strings.h"
00015 #include "azure_c_shared_utility/buffer_.h"
00016 #include "azure_c_shared_utility/xlogging.h"
00017 #include "azure_c_shared_utility/crt_abstractions.h"
00018 
00019 static double getExpiryValue(const char* expiryASCII)
00020 {
00021     double value = 0;
00022     size_t i = 0;
00023     for (i = 0; expiryASCII[i] != '\0'; i++)
00024     {
00025         if (expiryASCII[i] >= '0' && expiryASCII[i] <= '9')
00026         {
00027             value = value * 10 + (expiryASCII[i] - '0');
00028         }
00029         else
00030         {
00031             value = 0;
00032             break;
00033         }
00034     }
00035     return value;
00036 }
00037 
00038 bool SASToken_Validate(STRING_HANDLE sasToken)
00039 {
00040     bool result;
00041     /*Codes_SRS_SASTOKEN_25_025: [**SASToken_Validate shall get the SASToken value by invoking STRING_c_str on the handle.**]***/
00042     const char* sasTokenArray = STRING_c_str(sasToken);
00043 
00044     /***Codes_SRS_SASTOKEN_25_024: [**If handle is NULL then SASToken_Validate shall return false.**] ***/
00045     /*Codes_SRS_SASTOKEN_25_026: [**If STRING_c_str on handle return NULL then SASToken_Validate shall return false.**]***/
00046     if (sasToken == NULL || sasTokenArray == NULL)
00047     {
00048         result = false;
00049     }
00050     else
00051     {
00052         int seStart = -1, seStop = -1;
00053         int srStart = -1, srStop = -1;
00054         int sigStart = -1, sigStop = -1;
00055         int tokenLength = (int) STRING_length(sasToken);
00056         int i ;
00057         for (i = 0; i < tokenLength; i++)
00058         {
00059             if (sasTokenArray[i] == 's' && sasTokenArray[i + 1] == 'e' && sasTokenArray[i + 2] == '=') // Look for se=
00060             {
00061                 seStart = i + 3;
00062                 if (srStart > 0 && srStop < 0)
00063                 {
00064                     if (sasTokenArray[i - 1] != '&' && sasTokenArray[i - 1] == ' ') // look for either & or space
00065                         srStop = i - 1;
00066                     else if (sasTokenArray[i - 1] == '&')
00067                         srStop = i - 2;
00068                     else
00069                         seStart = -1; // as the format is not either "&se=" or " se="
00070                 }
00071                 else if (sigStart > 0 && sigStop < 0)
00072                 {
00073                     if (sasTokenArray[i - 1] != '&' && sasTokenArray[i - 1] == ' ')
00074                         sigStop = i - 1;
00075                     else if (sasTokenArray[i - 1] == '&')
00076                         sigStop = i - 2;
00077                     else
00078                         seStart = -1;
00079                 }
00080                 continue;
00081             }
00082             if (sasTokenArray[i] == 's' && sasTokenArray[i + 1] == 'r' && sasTokenArray[i + 2] == '=') // Look for sr=
00083             {
00084                 srStart = i + 3;
00085                 if (seStart > 0 && seStop < 0)
00086                 {
00087                     if (sasTokenArray[i - 1] != '&' && sasTokenArray[i - 1] == ' ')
00088                         seStop = i - 1;
00089                     else if (sasTokenArray[i - 1] == '&')
00090                         seStop = i - 2;
00091                     else
00092                         srStart = -1;
00093                 }
00094                 else if (sigStart > 0 && sigStop < 0)
00095                 {
00096                     if (sasTokenArray[i - 1] != '&' && sasTokenArray[i - 1] == ' ')
00097                         sigStop = i - 1;
00098                     else if (sasTokenArray[i - 1] == '&')
00099                         sigStop = i - 2;
00100                     else
00101                         srStart = -1;
00102                 }
00103                 continue;
00104             }
00105             if (sasTokenArray[i] == 's' && sasTokenArray[i + 1] == 'i' && sasTokenArray[i + 2] == 'g' && sasTokenArray[i + 3] == '=') // Look for sig=
00106             {
00107                 sigStart = i + 4;
00108                 if (srStart > 0 && srStop < 0)
00109                 {
00110                     if (sasTokenArray[i - 1] != '&' && sasTokenArray[i - 1] == ' ')
00111                         srStop = i - 1;
00112                     else if (sasTokenArray[i - 1] == '&')
00113                         srStop = i - 2;
00114                     else
00115                         sigStart = -1;
00116                 }
00117                 else if (seStart > 0 && seStop < 0)
00118                 {
00119                     if (sasTokenArray[i - 1] != '&' && sasTokenArray[i - 1] == ' ')
00120                         seStop = i - 1;
00121                     else if (sasTokenArray[i - 1] == '&')
00122                         seStop = i - 2;
00123                     else
00124                         sigStart = -1;
00125                 }
00126                 continue;
00127             }
00128         }
00129         /*Codes_SRS_SASTOKEN_25_027: [**If SASTOKEN does not obey the SASToken format then SASToken_Validate shall return false.**]***/
00130         /*Codes_SRS_SASTOKEN_25_028: [**SASToken_validate shall check for the presence of sr, se and sig from the token and return false if not found**]***/
00131         if (seStart < 0 || srStart < 0 || sigStart < 0)
00132         {
00133             result = false;
00134         }
00135         else
00136         {
00137             if (seStop < 0)
00138             {
00139                 seStop = tokenLength;
00140             }
00141             else if (srStop < 0)
00142             {
00143                 srStop = tokenLength;
00144             }
00145             else if (sigStop < 0)
00146             {
00147                 sigStop = tokenLength;
00148             }
00149 
00150             if ((seStop <= seStart) ||
00151                 (srStop <= srStart) ||
00152                 (sigStop <= sigStart))
00153             {
00154                 result = false;
00155             }
00156             else
00157             {
00158                 char* expiryASCII = malloc(seStop - seStart + 1);
00159                 /*Codes_SRS_SASTOKEN_25_031: [**If malloc fails during validation then SASToken_Validate shall return false.**]***/
00160                 if (expiryASCII == NULL)
00161                 {
00162                     result = false;
00163                 }
00164                 else
00165                 {
00166                     double expiry;
00167                     for (i = seStart; i < seStop; i++)
00168                     {
00169                         expiryASCII[i - seStart] = sasTokenArray[i];
00170                     }
00171                     expiryASCII[seStop - seStart] = '\0';
00172 
00173                     expiry = getExpiryValue(expiryASCII);
00174                     /*Codes_SRS_SASTOKEN_25_029: [**SASToken_validate shall check for expiry time from token and if token has expired then would return false **]***/
00175                     if (expiry <= 0)
00176                     {
00177                         result = false;
00178                     }
00179                     else
00180                     {
00181                         double secSinceEpoch = get_difftime(get_time(NULL), (time_t)0);
00182                         if (expiry < secSinceEpoch)
00183                         {
00184                             /*Codes_SRS_SASTOKEN_25_029: [**SASToken_validate shall check for expiry time from token and if token has expired then would return false **]***/
00185                             result = false;
00186                         }
00187                         else
00188                         {
00189                             /*Codes_SRS_SASTOKEN_25_030: [**SASToken_validate shall return true only if the format is obeyed and the token has not yet expired **]***/
00190                             result = true;
00191                         }
00192                     }
00193                     free(expiryASCII);
00194                 }
00195             }
00196         }
00197     }
00198 
00199     return result;
00200 }
00201 
00202 STRING_HANDLE SASToken_Create(STRING_HANDLE key, STRING_HANDLE scope, STRING_HANDLE keyName, size_t expiry)
00203 {
00204     STRING_HANDLE result = NULL;
00205     char tokenExpirationTime[32] = { 0 };
00206 
00207     /*Codes_SRS_SASTOKEN_06_001: [If key is NULL then SASToken_Create shall return NULL.]*/
00208     /*Codes_SRS_SASTOKEN_06_003: [If scope is NULL then SASToken_Create shall return NULL.]*/
00209     /*Codes_SRS_SASTOKEN_06_007: [If keyName is NULL then SASToken_Create shall return NULL.]*/
00210     if ((key == NULL) ||
00211         (scope == NULL) ||
00212         (keyName == NULL))
00213     {
00214         LogError("Invalid Parameter to SASToken_Create. handle key: %p, handle scope: %p, handle keyName: %p", key, scope, keyName);
00215     }
00216     else
00217     {
00218         BUFFER_HANDLE decodedKey;
00219         /*Codes_SRS_SASTOKEN_06_029: [The key parameter is decoded from base64.]*/
00220         if ((decodedKey = Base64_Decoder(STRING_c_str(key))) == NULL)
00221         {
00222             /*Codes_SRS_SASTOKEN_06_030: [If there is an error in the decoding then SASToken_Create shall return NULL.]*/
00223             LogError("Unable to decode the key for generating the SAS.");
00224         }
00225         else
00226         {
00227             /*Codes_SRS_SASTOKEN_06_026: [If the conversion to string form fails for any reason then SASToken_Create shall return NULL.]*/
00228             if (size_tToString(tokenExpirationTime, sizeof(tokenExpirationTime), expiry) != 0)
00229             {
00230                 LogError("For some reason converting seconds to a string failed.  No SAS can be generated.");
00231             }
00232             else
00233             {
00234                 STRING_HANDLE toBeHashed = NULL;
00235                 BUFFER_HANDLE hash = NULL;
00236                 if (((hash = BUFFER_new()) == NULL) ||
00237                     ((toBeHashed = STRING_new()) == NULL) ||
00238                     ((result = STRING_new()) == NULL))
00239                 {
00240                     LogError("Unable to allocate memory to prepare SAS token.");
00241                 }
00242                 else
00243                 {
00244                     /*Codes_SRS_SASTOKEN_06_009: [The scope is the basis for creating a STRING_HANDLE.]*/
00245                     /*Codes_SRS_SASTOKEN_06_010: [A "\n" is appended to that string.]*/
00246                     /*Codes_SRS_SASTOKEN_06_011: [tokenExpirationTime is appended to that string.]*/
00247                     if ((STRING_concat_with_STRING(toBeHashed, scope) != 0) ||
00248                         (STRING_concat(toBeHashed, "\n") != 0) ||
00249                         (STRING_concat(toBeHashed, tokenExpirationTime) != 0))
00250                     {
00251                         LogError("Unable to build the input to the HMAC to prepare SAS token.");
00252                         STRING_delete(result);
00253                         result = NULL;
00254                     }
00255                     else
00256                     {
00257                         STRING_HANDLE base64Signature = NULL;
00258                         STRING_HANDLE urlEncodedSignature = NULL;
00259                         size_t inLen = STRING_length(toBeHashed);
00260                         const unsigned char* inBuf = (const unsigned char*)STRING_c_str(toBeHashed);
00261                         size_t outLen = BUFFER_length(decodedKey);
00262                         unsigned char* outBuf = BUFFER_u_char(decodedKey);
00263                         /*Codes_SRS_SASTOKEN_06_013: [If an error is returned from the HMAC256 function then NULL is returned from SASToken_Create.]*/
00264                         /*Codes_SRS_SASTOKEN_06_012: [An HMAC256 hash is calculated using the decodedKey, over toBeHashed.]*/
00265                         /*Codes_SRS_SASTOKEN_06_014: [If there are any errors from the following operations then NULL shall be returned.]*/
00266                         /*Codes_SRS_SASTOKEN_06_015: [The hash is base 64 encoded.]*/
00267                         /*Codes_SRS_SASTOKEN_06_028: [base64Signature shall be url encoded.]*/
00268                         /*Codes_SRS_SASTOKEN_06_016: [The string "SharedAccessSignature sr=" is the first part of the result of SASToken_Create.]*/
00269                         /*Codes_SRS_SASTOKEN_06_017: [The scope parameter is appended to result.]*/
00270                         /*Codes_SRS_SASTOKEN_06_018: [The string "&sig=" is appended to result.]*/
00271                         /*Codes_SRS_SASTOKEN_06_019: [The string urlEncodedSignature shall be appended to result.]*/
00272                         /*Codes_SRS_SASTOKEN_06_020: [The string "&se=" shall be appended to result.]*/
00273                         /*Codes_SRS_SASTOKEN_06_021: [tokenExpirationTime is appended to result.]*/
00274                         /*Codes_SRS_SASTOKEN_06_022: [The string "&skn=" is appended to result.]*/
00275                         /*Codes_SRS_SASTOKEN_06_023: [The argument keyName is appended to result.]*/
00276                         if ((HMACSHA256_ComputeHash(outBuf, outLen, inBuf, inLen, hash) != HMACSHA256_OK) ||
00277                             ((base64Signature = Base64_Encode(hash)) == NULL) ||
00278                             ((urlEncodedSignature = URL_Encode(base64Signature)) == NULL) ||
00279                             (STRING_copy(result, "SharedAccessSignature sr=") != 0) ||
00280                             (STRING_concat_with_STRING(result, scope) != 0) ||
00281                             (STRING_concat(result, "&sig=") != 0) ||
00282                             (STRING_concat_with_STRING(result, urlEncodedSignature) != 0) ||
00283                             (STRING_concat(result, "&se=") != 0) ||
00284                             (STRING_concat(result, tokenExpirationTime) != 0) ||
00285                             (STRING_concat(result, "&skn=") != 0) ||
00286                             (STRING_concat_with_STRING(result, keyName) != 0))
00287                         {
00288                             LogError("Unable to build the SAS token.");
00289                             STRING_delete(result);
00290                             result = NULL;
00291                         }
00292                         else
00293                         {
00294                             /* everything OK */
00295                         }
00296                         STRING_delete(base64Signature);
00297                         STRING_delete(urlEncodedSignature);
00298                     }
00299                 }
00300                 STRING_delete(toBeHashed);
00301                 BUFFER_delete(hash);
00302             }
00303             BUFFER_delete(decodedKey);
00304         }
00305     }
00306 
00307     return result;
00308 }
00309