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.
HttpAuth.cpp
00001 //***************************************************************************** 00002 // Copyright (C) 2014 Texas Instruments Incorporated 00003 // 00004 // All rights reserved. Property of Texas Instruments Incorporated. 00005 // Restricted rights to use, duplicate or disclose this code are 00006 // granted through contract. 00007 // The program may not be used without the written permission of 00008 // Texas Instruments Incorporated or against the terms and conditions 00009 // stipulated in the agreement under which this program has been supplied, 00010 // and under no circumstances can it be used with non-TI connectivity device. 00011 // 00012 //***************************************************************************** 00013 00014 #include "HttpAuth.h" 00015 00016 #ifdef HTTP_CORE_ENABLE_AUTH 00017 00018 #include <string.h> 00019 #include "HttpString.h" 00020 /** 00021 * @addtogroup HttpAuth 00022 * @{ 00023 */ 00024 00025 #define DIGEST_AUTHENTICATION_BUFFER_SIZE (32) 00026 00027 /** 00028 * This structure holds the HTTP digest-access authentication state 00029 */ 00030 struct HttpAuthState 00031 { 00032 /// Last-generated nonce 00033 UINT8 nonce[DIGEST_AUTHENTICATION_BUFFER_SIZE]; 00034 /// Last-generated opaque 00035 UINT8 opaque[DIGEST_AUTHENTICATION_BUFFER_SIZE]; 00036 /// The hash of the username, realm, and password 00037 UINT8 ha1[DIGEST_AUTHENTICATION_BUFFER_SIZE]; 00038 }; 00039 00040 00041 00042 /// The global state for digest-access authentication 00043 00044 static struct HttpAuthState g_authState; // = { {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 00045 // {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 00046 // {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; 00047 00048 /// 00049 MD5_CTX MD5state; 00050 00051 char HTTP_AUTH_REALM[] = "cc3200 web server"; 00052 00053 /// Header strings to be used for response headers 00054 char HTTP_AUTHENTICATE_RESPONSE_REALM[] = "WWW-Authenticate: Digest realm=\""; 00055 char HTTP_AUTHENTICATE_RESPONSE_NONCE[] = "\",qop=\"auth\",nonce=\""; 00056 char HTTP_AUTHENTICATE_RESPONSE_OPAQUE[] = "\",opaque=\""; 00057 char HTTP_AUTHENTICATE_RESPONSE_EOH[] = "\"\r\n"; 00058 00059 /// Authenticate header tokens 00060 char HTTP_AUTHENTICATE_REALM[] = "realm"; 00061 char HTTP_AUTHENTICATE_QOP[] = "qop"; 00062 char HTTP_AUTHENTICATE_AUTH[] = "auth"; 00063 char HTTP_AUTHENTICATE_NONCE[] = "nonce"; 00064 char HTTP_AUTHENTICATE_OPAQUE[] = "opaque"; 00065 char HTTP_AUTHENTICATE_DIGEST[] = "digest"; 00066 char HTTP_AUTHENTICATE_URI[] = "uri"; 00067 char HTTP_AUTHENTICATE_NC[] = "nc="; 00068 char HTTP_AUTHENTICATE_CNONCE[] = "cnonce"; 00069 char HTTP_AUTHENTICATE_RESPONSE[] = "response"; 00070 char HTTP_AUTHENTICATE_USERNAME[] = "username"; 00071 char HTTP_DELIMITER_QUOTE[] = "\""; 00072 char HTTP_DELIMITER_COMMA[] = ","; 00073 00074 00075 /// The length of the response authentication header 00076 /// The two 32 numbers represent nonce and opaque strings and the -5 is to compensate for the sizeof() calls 00077 UINT16 HTTP_AUTHENTICATE_RESPONSE_HEADER_LENGTH = 00078 sizeof(HTTP_AUTHENTICATE_RESPONSE_REALM) + 00079 sizeof(HTTP_AUTHENTICATE_RESPONSE_NONCE) + 00080 sizeof(HTTP_AUTHENTICATE_RESPONSE_OPAQUE) + 00081 sizeof(HTTP_AUTHENTICATE_RESPONSE_EOH) + 00082 sizeof(HTTP_AUTH_REALM) + 00083 DIGEST_AUTHENTICATION_BUFFER_SIZE + DIGEST_AUTHENTICATION_BUFFER_SIZE - 5; 00084 00085 00086 /** 00087 * Simple random generator 00088 * To improve randomness the initial seed has to be dynamic 00089 */ 00090 static UINT32 GetRandomUint() 00091 { 00092 // set static seed 00093 static UINT32 m_z = 1234; 00094 static UINT32 m_w = 98877; 00095 00096 m_z = 36969 * (m_z & 65535) + (m_z >> 16); 00097 m_w = 18000 * (m_w & 65535) + (m_w >> 16); 00098 return (m_z << 16) + m_w; 00099 } 00100 00101 static void MD5_FinalToString(UINT8* str, MD5_CTX *md5stat) 00102 { 00103 UINT8 tmp[16]; 00104 UINT8 i; 00105 struct HttpBlob location; 00106 location.uLength = 2; 00107 location.pData = str; 00108 MD5_Final(tmp, md5stat); 00109 for (i=0; i<16; i++, location.pData += 2) 00110 HttpString_htoa(tmp[i], &location, 1); 00111 } 00112 00113 00114 /** 00115 * This function will generate random 16 bytes to be used for Nonce and opaque strings 00116 */ 00117 static void Generate32BytesRandomString(UINT8 *str) 00118 { 00119 struct HttpBlob str1; 00120 str1.uLength = 8; 00121 str1.pData = str; 00122 HttpString_htoa(GetRandomUint(), &str1, 1); 00123 str1.pData = str + 8; 00124 HttpString_htoa(GetRandomUint(), &str1, 1); 00125 str1.pData = str + 16; 00126 HttpString_htoa(GetRandomUint(), &str1, 1); 00127 str1.pData = str + 24; 00128 HttpString_htoa(GetRandomUint(), &str1, 1); 00129 } 00130 00131 void HttpAuth_Init(struct HttpBlob username, struct HttpBlob password) 00132 { 00133 MD5_Init(&MD5state); 00134 MD5_Update(&MD5state, username.pData, username.uLength); 00135 MD5_Update(&MD5state, ":", 1); 00136 MD5_Update(&MD5state, HTTP_AUTH_REALM, sizeof(HTTP_AUTH_REALM)-1); 00137 MD5_Update(&MD5state, ":", 1); 00138 MD5_Update(&MD5state, password.pData, password.uLength); 00139 MD5_FinalToString(g_authState.ha1, &MD5state); 00140 } 00141 00142 static void AddStringToBlob(struct HttpBlob * trgt, char *str, UINT16 length) 00143 { 00144 memcpy(trgt->pData + trgt->uLength, str, length); 00145 trgt->uLength += length; 00146 } 00147 00148 void HttpAuth_ResponseAuthenticate(struct HttpRequest* pRequest, struct HttpBlob* pWWWAuthenticate) 00149 { 00150 struct HttpBlob headerBlob; 00151 00152 if (pWWWAuthenticate->uLength < HTTP_AUTHENTICATE_RESPONSE_HEADER_LENGTH) 00153 { 00154 pWWWAuthenticate->uLength = 0; 00155 return; 00156 } 00157 // There is enough space to add the authenticate header 00158 00159 headerBlob.pData = pWWWAuthenticate->pData; 00160 headerBlob.uLength = 0; 00161 00162 // Generate new Nonce and opaque 00163 Generate32BytesRandomString(g_authState.nonce); 00164 Generate32BytesRandomString(g_authState.opaque); 00165 00166 // Build response header 00167 AddStringToBlob(&headerBlob, HTTP_AUTHENTICATE_RESPONSE_REALM, sizeof(HTTP_AUTHENTICATE_RESPONSE_REALM)-1); 00168 AddStringToBlob(&headerBlob, HTTP_AUTH_REALM, sizeof(HTTP_AUTH_REALM) -1); 00169 AddStringToBlob(&headerBlob, HTTP_AUTHENTICATE_RESPONSE_NONCE, sizeof(HTTP_AUTHENTICATE_RESPONSE_NONCE) -1); 00170 AddStringToBlob(&headerBlob, (char*)g_authState.nonce, sizeof(g_authState.nonce)); 00171 AddStringToBlob(&headerBlob, HTTP_AUTHENTICATE_RESPONSE_OPAQUE, sizeof(HTTP_AUTHENTICATE_RESPONSE_OPAQUE) -1); 00172 AddStringToBlob(&headerBlob, (char*)g_authState.opaque, sizeof(g_authState.opaque)); 00173 AddStringToBlob(&headerBlob, HTTP_AUTHENTICATE_RESPONSE_EOH, sizeof(HTTP_AUTHENTICATE_RESPONSE_EOH) - 1); 00174 00175 pWWWAuthenticate->uLength = headerBlob.uLength; 00176 } 00177 00178 /** 00179 * Find/verify name value pair in the input blob 00180 * 00181 * After return the location is stays in the same place since the order of the name value pairs in not constant 00182 * Returns: if header not found return 0 00183 * if value token is NULL - return pointer to start of value length of value till the \" delimiter 00184 * if value token is not NULL - return 1 if values match 00185 */ 00186 static UINT16 HttpAuth_VerifyHeaderNameValue(struct HttpBlob *location, char* nameToken, UINT8 tokenlenLen, char *value, UINT8 valuelen, char** outValue) 00187 { 00188 UINT8 * found; 00189 struct HttpBlob originalLocation; 00190 originalLocation.uLength = location->uLength; 00191 originalLocation.pData = location->pData; 00192 00193 found = HttpString_nextToken(nameToken, tokenlenLen, *location); 00194 00195 // Missing header name 00196 if (found == 0) 00197 return 0; 00198 else 00199 { 00200 location->uLength = originalLocation.uLength - (UINT16)(found - originalLocation.pData) - (tokenlenLen + 2); 00201 location->pData = found + tokenlenLen + 2; 00202 // Return the value pointer and size 00203 if (value == NULL) 00204 { 00205 *outValue= (char*)location->pData; 00206 nameToken = (char *)location->pData; 00207 found = HttpString_nextToken(HTTP_DELIMITER_QUOTE, sizeof(HTTP_DELIMITER_QUOTE) - 1, *location); 00208 if (found==0) 00209 found = HttpString_nextToken(HTTP_DELIMITER_COMMA, sizeof(HTTP_DELIMITER_COMMA) - 1, *location); 00210 00211 // Restore current location 00212 location->uLength = originalLocation.uLength; 00213 location->pData = originalLocation.pData; 00214 return (UINT16)((char *)found - nameToken); 00215 } 00216 00217 found = HttpString_nextToken(value, valuelen, *location); 00218 // Value does not match - restore location 00219 if (found == 0) 00220 { 00221 location->uLength = originalLocation.uLength; 00222 location->pData = originalLocation.pData; 00223 return 0; 00224 } 00225 00226 // Restore location 00227 location->uLength = originalLocation.uLength; 00228 location->pData = originalLocation.pData; 00229 return 1; 00230 } 00231 } 00232 00233 00234 void HttpAuth_RequestAuthenticate(struct HttpRequest* pRequest, struct HttpBlob authorization) 00235 { 00236 UINT8 ha2[DIGEST_AUTHENTICATION_BUFFER_SIZE], correctResponse[DIGEST_AUTHENTICATION_BUFFER_SIZE]; 00237 struct HttpBlob currentLocation, blob; 00238 // HA1 was not copmuted 00239 if ((UINT32)*g_authState.ha1 == 0) 00240 { 00241 return; 00242 } 00243 00244 // Parse the header - find relevant tokens and handle 00245 currentLocation.pData = authorization.pData; 00246 currentLocation.uLength = authorization.uLength; 00247 00248 // Verify the mandatory tokens, whose content we ignore are present 00249 00250 // verify we are in degest authentication method, any other is not supported 00251 if (HttpString_nextToken(HTTP_AUTHENTICATE_DIGEST, sizeof(HTTP_AUTHENTICATE_DIGEST)-1, currentLocation) == 0) 00252 return; 00253 00254 // verify username exists 00255 if (HttpString_nextToken(HTTP_AUTHENTICATE_USERNAME, sizeof(HTTP_AUTHENTICATE_USERNAME)-1, currentLocation) == 0) 00256 return; 00257 00258 // Verify realm 00259 if (HttpAuth_VerifyHeaderNameValue(¤tLocation, HTTP_AUTHENTICATE_REALM, sizeof(HTTP_AUTHENTICATE_REALM)-1, HTTP_AUTH_REALM, sizeof(HTTP_AUTH_REALM)-1, 0) != 1) 00260 return; 00261 00262 // Verify correct nonce 00263 if (HttpAuth_VerifyHeaderNameValue(¤tLocation, HTTP_AUTHENTICATE_NONCE, sizeof(HTTP_AUTHENTICATE_NONCE)-1, (char *)g_authState.nonce, DIGEST_AUTHENTICATION_BUFFER_SIZE, 0) != 1) 00264 return; 00265 00266 // Verify correct opaque 00267 if (HttpAuth_VerifyHeaderNameValue(¤tLocation, HTTP_AUTHENTICATE_OPAQUE, sizeof(HTTP_AUTHENTICATE_OPAQUE)-1, (char *)g_authState.opaque, DIGEST_AUTHENTICATION_BUFFER_SIZE, 0) != 1) 00268 return; 00269 00270 // Find neccessary tokents and compute HA2 if some tokens are not found - return 00271 blob.pData = NULL; 00272 blob.uLength = HttpAuth_VerifyHeaderNameValue(¤tLocation, HTTP_AUTHENTICATE_URI, sizeof(HTTP_AUTHENTICATE_URI)-1, 0, 0, (char**)&blob.pData); 00273 // Uri is missing 00274 if (blob.uLength == 0) 00275 return; 00276 00277 MD5_Init(&MD5state); 00278 if ((pRequest->uFlags & HTTP_REQUEST_FLAG_METHOD_POST) != 0) 00279 MD5_Update(&MD5state, "POST", 4); 00280 else 00281 MD5_Update(&MD5state, "GET", 3); 00282 MD5_Update(&MD5state, ":", 1); 00283 MD5_Update(&MD5state, blob.pData, blob.uLength); 00284 MD5_FinalToString(ha2, &MD5state); 00285 00286 // Find tokens to compute correct response 00287 blob.pData = HttpString_nextToken(HTTP_AUTHENTICATE_NC, sizeof(HTTP_AUTHENTICATE_NC)-1, currentLocation); 00288 // Ncount is missing 00289 if (blob.pData == 0) 00290 return; 00291 blob.pData += sizeof(HTTP_AUTHENTICATE_NC) - 1; 00292 blob.uLength = 8; 00293 00294 MD5_Init(&MD5state); 00295 MD5_Update(&MD5state, g_authState.ha1, DIGEST_AUTHENTICATION_BUFFER_SIZE); 00296 MD5_Update(&MD5state, ":", 1); 00297 MD5_Update(&MD5state, g_authState.nonce, DIGEST_AUTHENTICATION_BUFFER_SIZE); 00298 MD5_Update(&MD5state, ":", 1); 00299 MD5_Update(&MD5state, blob.pData, blob.uLength); 00300 00301 blob.pData = NULL; 00302 blob.uLength = HttpAuth_VerifyHeaderNameValue(¤tLocation, HTTP_AUTHENTICATE_CNONCE, sizeof(HTTP_AUTHENTICATE_CNONCE)-1, 0, 0, (char **)&blob.pData); 00303 // Cnonce is missing 00304 if (blob.uLength == 0) 00305 return; 00306 MD5_Update(&MD5state, ":", 1); 00307 MD5_Update(&MD5state, blob.pData, blob.uLength); 00308 MD5_Update(&MD5state, ":auth:", 6); 00309 MD5_Update(&MD5state, ha2, DIGEST_AUTHENTICATION_BUFFER_SIZE); 00310 MD5_FinalToString(correctResponse, &MD5state); 00311 00312 // Compare received response to the one computed locally - if equal then authorize 00313 blob.pData = NULL; 00314 blob.uLength = HttpAuth_VerifyHeaderNameValue(¤tLocation, HTTP_AUTHENTICATE_RESPONSE, sizeof(HTTP_AUTHENTICATE_RESPONSE)-1, 0, 0, (char **)&blob.pData); 00315 // Response is missing 00316 if (blob.uLength != DIGEST_AUTHENTICATION_BUFFER_SIZE) 00317 return; 00318 00319 currentLocation.pData = correctResponse; 00320 currentLocation.uLength = DIGEST_AUTHENTICATION_BUFFER_SIZE; 00321 // if the responses are equal 00322 if (HttpString_strcmp(blob, currentLocation) == 0) 00323 pRequest->uFlags |= HTTP_REQUEST_FLAG_AUTHENTICATED; 00324 00325 } 00326 #endif 00327 00328 /// @} 00329 00330
Generated on Tue Jul 12 2022 22:22:38 by
1.7.2