Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: azure_umqtt_c iothub_mqtt_transport mbed-rtos mbed wolfSSL Socket lwip-eth lwip-sys lwip
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
Generated on Wed Jul 13 2022 07:19:04 by
1.7.2