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 * 00003 * HttpAuth.c 00004 * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions 00008 * are met: 00009 * 00010 * Redistributions of source code must retain the above copyright 00011 * notice, this list of conditions and the following disclaimer. 00012 * 00013 * Redistributions in binary form must reproduce the above copyright 00014 * notice, this list of conditions and the following disclaimer in the 00015 * documentation and/or other materials provided with the 00016 * distribution. 00017 * 00018 * Neither the name of Texas Instruments Incorporated nor the names of 00019 * its contributors may be used to endorse or promote products derived 00020 * from this software without specific prior written permission. 00021 * 00022 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00023 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00024 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 00025 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 00026 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00027 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 00028 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00029 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00030 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00031 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 00032 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00033 * 00034 *****************************************************************************/ 00035 #include "HttpAuth.h" 00036 00037 #ifdef HTTP_CORE_ENABLE_AUTH 00038 00039 #include "md5.h" 00040 #include <string.h> 00041 #include "HttpString.h" 00042 /** 00043 * @addtogroup HttpAuth 00044 * @{ 00045 */ 00046 00047 #define DIGEST_AUTHENTICATION_BUFFER_SIZE (32) 00048 00049 /** 00050 * This structure holds the HTTP digest-access authentication state 00051 */ 00052 struct HttpAuthState 00053 { 00054 /// Last-generated nonce 00055 uint8 nonce[DIGEST_AUTHENTICATION_BUFFER_SIZE]; 00056 /// Last-generated opaque 00057 uint8 opaque[DIGEST_AUTHENTICATION_BUFFER_SIZE]; 00058 /// The hash of the username, realm, and password 00059 uint8 ha1[DIGEST_AUTHENTICATION_BUFFER_SIZE]; 00060 }; 00061 00062 00063 00064 /// The global state for digest-access authentication 00065 00066 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}, 00067 // {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}, 00068 // {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}}; 00069 00070 /// 00071 MD5_CTX MD5state; 00072 00073 char HTTP_AUTH_REALM[] = "mbed web server"; 00074 00075 /// Header strings to be used for response headers 00076 char HTTP_AUTHENTICATE_RESPONSE_REALM[] = "WWW-Authenticate: Digest realm=\""; 00077 char HTTP_AUTHENTICATE_RESPONSE_NONCE[] = "\",qop=\"auth\",nonce=\""; 00078 char HTTP_AUTHENTICATE_RESPONSE_OPAQUE[] = "\",opaque=\""; 00079 char HTTP_AUTHENTICATE_RESPONSE_EOH[] = "\"\r\n"; 00080 00081 /// Authenticate header tokens 00082 char HTTP_AUTHENTICATE_REALM[] = "realm"; 00083 char HTTP_AUTHENTICATE_QOP[] = "qop"; 00084 char HTTP_AUTHENTICATE_AUTH[] = "auth"; 00085 char HTTP_AUTHENTICATE_NONCE[] = "nonce"; 00086 char HTTP_AUTHENTICATE_OPAQUE[] = "opaque"; 00087 char HTTP_AUTHENTICATE_DIGEST[] = "digest"; 00088 char HTTP_AUTHENTICATE_URI[] = "uri"; 00089 char HTTP_AUTHENTICATE_NC[] = "nc="; 00090 char HTTP_AUTHENTICATE_CNONCE[] = "cnonce"; 00091 char HTTP_AUTHENTICATE_RESPONSE[] = "response"; 00092 char HTTP_AUTHENTICATE_USERNAME[] = "username"; 00093 char HTTP_DELIMITER_QUOTE[] = "\""; 00094 char HTTP_DELIMITER_COMMA[] = ","; 00095 00096 00097 /// The length of the response authentication header 00098 /// The two 32 numbers represent nonce and opaque strings and the -5 is to compensate for the sizeof() calls 00099 uint16 HTTP_AUTHENTICATE_RESPONSE_HEADER_LENGTH = 00100 sizeof(HTTP_AUTHENTICATE_RESPONSE_REALM) + 00101 sizeof(HTTP_AUTHENTICATE_RESPONSE_NONCE) + 00102 sizeof(HTTP_AUTHENTICATE_RESPONSE_OPAQUE) + 00103 sizeof(HTTP_AUTHENTICATE_RESPONSE_EOH) + 00104 sizeof(HTTP_AUTH_REALM) + 00105 DIGEST_AUTHENTICATION_BUFFER_SIZE + DIGEST_AUTHENTICATION_BUFFER_SIZE - 5; 00106 00107 00108 /** 00109 * Simple random generator 00110 * To improve randomness the initial seed has to be dynamic 00111 */ 00112 static uint32 GetRandomUint() 00113 { 00114 // set static seed 00115 static uint32 m_z = 1234; 00116 static uint32 m_w = 98877; 00117 00118 m_z = 36969 * (m_z & 65535) + (m_z >> 16); 00119 m_w = 18000 * (m_w & 65535) + (m_w >> 16); 00120 return (m_z << 16) + m_w; 00121 } 00122 00123 static void MD5_FinalToString(uint8* str, MD5_CTX *md5stat) 00124 { 00125 uint8 tmp[16]; 00126 uint8 i; 00127 struct HttpBlob location; 00128 location.uLength = 2; 00129 location.pData = str; 00130 MD5_Final(tmp, md5stat); 00131 for (i=0; i<16; i++, location.pData += 2) 00132 HttpString_htoa(tmp[i], &location, 1); 00133 } 00134 00135 00136 /** 00137 * This function will generate random 16 bytes to be used for Nonce and opaque strings 00138 */ 00139 static void Generate32BytesRandomString(uint8 *str) 00140 { 00141 struct HttpBlob str1; 00142 str1.uLength = 8; 00143 str1.pData = str; 00144 HttpString_htoa(GetRandomUint(), &str1, 1); 00145 str1.pData = str + 8; 00146 HttpString_htoa(GetRandomUint(), &str1, 1); 00147 str1.pData = str + 16; 00148 HttpString_htoa(GetRandomUint(), &str1, 1); 00149 str1.pData = str + 24; 00150 HttpString_htoa(GetRandomUint(), &str1, 1); 00151 } 00152 00153 void HttpAuth_Init(struct HttpBlob username, struct HttpBlob password) 00154 { 00155 MD5_Init(&MD5state); 00156 MD5_Update(&MD5state, username.pData, username.uLength); 00157 MD5_Update(&MD5state, (unsigned char*)":", 1); 00158 MD5_Update(&MD5state, HTTP_AUTH_REALM, sizeof(HTTP_AUTH_REALM)-1); 00159 MD5_Update(&MD5state, (unsigned char*)":", 1); 00160 MD5_Update(&MD5state, password.pData, password.uLength); 00161 MD5_FinalToString(g_authState.ha1, &MD5state); 00162 } 00163 00164 static void AddStringToBlob(struct HttpBlob * trgt, char *str, uint16 length) 00165 { 00166 memcpy(trgt->pData + trgt->uLength, str, length); 00167 trgt->uLength += length; 00168 } 00169 00170 void HttpAuth_ResponseAuthenticate(struct HttpRequest* pRequest, struct HttpBlob* pWWWAuthenticate) 00171 { 00172 struct HttpBlob headerBlob; 00173 00174 if (pWWWAuthenticate->uLength < HTTP_AUTHENTICATE_RESPONSE_HEADER_LENGTH) 00175 { 00176 pWWWAuthenticate->uLength = 0; 00177 return; 00178 } 00179 // There is enough space to add the authenticate header 00180 00181 headerBlob.pData = pWWWAuthenticate->pData; 00182 headerBlob.uLength = 0; 00183 00184 // Generate new Nonce and opaque 00185 Generate32BytesRandomString(g_authState.nonce); 00186 Generate32BytesRandomString(g_authState.opaque); 00187 00188 // Build response header 00189 AddStringToBlob(&headerBlob, HTTP_AUTHENTICATE_RESPONSE_REALM, sizeof(HTTP_AUTHENTICATE_RESPONSE_REALM)-1); 00190 AddStringToBlob(&headerBlob, HTTP_AUTH_REALM, sizeof(HTTP_AUTH_REALM) -1); 00191 AddStringToBlob(&headerBlob, HTTP_AUTHENTICATE_RESPONSE_NONCE, sizeof(HTTP_AUTHENTICATE_RESPONSE_NONCE) -1); 00192 AddStringToBlob(&headerBlob, (char*)g_authState.nonce, sizeof(g_authState.nonce)); 00193 AddStringToBlob(&headerBlob, HTTP_AUTHENTICATE_RESPONSE_OPAQUE, sizeof(HTTP_AUTHENTICATE_RESPONSE_OPAQUE) -1); 00194 AddStringToBlob(&headerBlob, (char*)g_authState.opaque, sizeof(g_authState.opaque)); 00195 AddStringToBlob(&headerBlob, HTTP_AUTHENTICATE_RESPONSE_EOH, sizeof(HTTP_AUTHENTICATE_RESPONSE_EOH) - 1); 00196 00197 pWWWAuthenticate->uLength = headerBlob.uLength; 00198 } 00199 00200 /** 00201 * Find/verify name value pair in the input blob 00202 * 00203 * After return the location is stays in the same place since the order of the name value pairs in not constant 00204 * Returns: if header not found return 0 00205 * if value token is NULL - return pointer to start of value length of value till the \" delimiter 00206 * if value token is not NULL - return 1 if values match 00207 */ 00208 static uint16 HttpAuth_VerifyHeaderNameValue(struct HttpBlob *location, char* nameToken, uint8 tokenlenLen, char *value, uint8 valuelen, char** outValue) 00209 { 00210 uint8 * found; 00211 struct HttpBlob originalLocation; 00212 originalLocation.uLength = location->uLength; 00213 originalLocation.pData = location->pData; 00214 00215 found = HttpString_nextToken(nameToken, tokenlenLen, *location); 00216 00217 // Missing header name 00218 if (found == 0) 00219 return 0; 00220 else 00221 { 00222 location->uLength = originalLocation.uLength - (uint16)(found - originalLocation.pData) - (tokenlenLen + 2); 00223 location->pData = found + tokenlenLen + 2; 00224 // Return the value pointer and size 00225 if (value == NULL) 00226 { 00227 *outValue= (char*)location->pData; 00228 nameToken = (char *)location->pData; 00229 found = HttpString_nextToken(HTTP_DELIMITER_QUOTE, sizeof(HTTP_DELIMITER_QUOTE) - 1, *location); 00230 if (found==0) 00231 found = HttpString_nextToken(HTTP_DELIMITER_COMMA, sizeof(HTTP_DELIMITER_COMMA) - 1, *location); 00232 00233 // Restore current location 00234 location->uLength = originalLocation.uLength; 00235 location->pData = originalLocation.pData; 00236 return (uint16)((char *)found - nameToken); 00237 } 00238 00239 found = HttpString_nextToken(value, valuelen, *location); 00240 // Value does not match - restore location 00241 if (found == 0) 00242 { 00243 location->uLength = originalLocation.uLength; 00244 location->pData = originalLocation.pData; 00245 return 0; 00246 } 00247 00248 // Restore location 00249 location->uLength = originalLocation.uLength; 00250 location->pData = originalLocation.pData; 00251 return 1; 00252 } 00253 } 00254 00255 00256 void HttpAuth_RequestAuthenticate(struct HttpRequest* pRequest, struct HttpBlob authorization) 00257 { 00258 uint8 ha2[DIGEST_AUTHENTICATION_BUFFER_SIZE], correctResponse[DIGEST_AUTHENTICATION_BUFFER_SIZE]; 00259 struct HttpBlob currentLocation, blob; 00260 // HA1 was not copmuted 00261 if ((uint32)*g_authState.ha1 == 0) 00262 { 00263 return; 00264 } 00265 00266 // Parse the header - find relevant tokens and handle 00267 currentLocation.pData = authorization.pData; 00268 currentLocation.uLength = authorization.uLength; 00269 00270 // Verify the mandatory tokens, whose content we ignore are present 00271 00272 // verify we are in degest authentication method, any other is not supported 00273 if (HttpString_nextToken(HTTP_AUTHENTICATE_DIGEST, sizeof(HTTP_AUTHENTICATE_DIGEST)-1, currentLocation) == 0) 00274 return; 00275 00276 // verify username exists 00277 if (HttpString_nextToken(HTTP_AUTHENTICATE_USERNAME, sizeof(HTTP_AUTHENTICATE_USERNAME)-1, currentLocation) == 0) 00278 return; 00279 00280 // Verify realm 00281 if (HttpAuth_VerifyHeaderNameValue(¤tLocation, HTTP_AUTHENTICATE_REALM, sizeof(HTTP_AUTHENTICATE_REALM)-1, HTTP_AUTH_REALM, sizeof(HTTP_AUTH_REALM)-1, 0) != 1) 00282 return; 00283 00284 // Verify correct nonce 00285 if (HttpAuth_VerifyHeaderNameValue(¤tLocation, HTTP_AUTHENTICATE_NONCE, sizeof(HTTP_AUTHENTICATE_NONCE)-1, (char *)g_authState.nonce, DIGEST_AUTHENTICATION_BUFFER_SIZE, 0) != 1) 00286 return; 00287 00288 // Verify correct opaque 00289 if (HttpAuth_VerifyHeaderNameValue(¤tLocation, HTTP_AUTHENTICATE_OPAQUE, sizeof(HTTP_AUTHENTICATE_OPAQUE)-1, (char *)g_authState.opaque, DIGEST_AUTHENTICATION_BUFFER_SIZE, 0) != 1) 00290 return; 00291 00292 // Find neccessary tokents and compute HA2 if some tokens are not found - return 00293 blob.pData = NULL; 00294 blob.uLength = HttpAuth_VerifyHeaderNameValue(¤tLocation, HTTP_AUTHENTICATE_URI, sizeof(HTTP_AUTHENTICATE_URI)-1, 0, 0, (char**)&blob.pData); 00295 // Uri is missing 00296 if (blob.uLength == 0) 00297 return; 00298 00299 MD5_Init(&MD5state); 00300 if ((pRequest->uFlags & HTTP_REQUEST_FLAG_METHOD_POST) != 0) 00301 MD5_Update(&MD5state, (unsigned char*)"POST", 4); 00302 else 00303 MD5_Update(&MD5state, (unsigned char*)"GET", 3); 00304 MD5_Update(&MD5state, (unsigned char*)":", 1); 00305 MD5_Update(&MD5state, blob.pData, blob.uLength); 00306 MD5_FinalToString(ha2, &MD5state); 00307 00308 // Find tokens to compute correct response 00309 blob.pData = HttpString_nextToken(HTTP_AUTHENTICATE_NC, sizeof(HTTP_AUTHENTICATE_NC)-1, currentLocation); 00310 // Ncount is missing 00311 if (blob.pData == 0) 00312 return; 00313 blob.pData += sizeof(HTTP_AUTHENTICATE_NC) - 1; 00314 blob.uLength = 8; 00315 00316 MD5_Init(&MD5state); 00317 MD5_Update(&MD5state, g_authState.ha1, DIGEST_AUTHENTICATION_BUFFER_SIZE); 00318 MD5_Update(&MD5state, (unsigned char*)":", 1); 00319 MD5_Update(&MD5state, g_authState.nonce, DIGEST_AUTHENTICATION_BUFFER_SIZE); 00320 MD5_Update(&MD5state, (unsigned char*)":", 1); 00321 MD5_Update(&MD5state, blob.pData, blob.uLength); 00322 00323 blob.pData = NULL; 00324 blob.uLength = HttpAuth_VerifyHeaderNameValue(¤tLocation, HTTP_AUTHENTICATE_CNONCE, sizeof(HTTP_AUTHENTICATE_CNONCE)-1, 0, 0, (char **)&blob.pData); 00325 // Cnonce is missing 00326 if (blob.uLength == 0) 00327 return; 00328 MD5_Update(&MD5state, (unsigned char*)":", 1); 00329 MD5_Update(&MD5state, blob.pData, blob.uLength); 00330 MD5_Update(&MD5state, (unsigned char*)":auth:", 6); 00331 MD5_Update(&MD5state, ha2, DIGEST_AUTHENTICATION_BUFFER_SIZE); 00332 MD5_FinalToString(correctResponse, &MD5state); 00333 00334 // Compare received response to the one computed locally - if equal then authorize 00335 blob.pData = NULL; 00336 blob.uLength = HttpAuth_VerifyHeaderNameValue(¤tLocation, HTTP_AUTHENTICATE_RESPONSE, sizeof(HTTP_AUTHENTICATE_RESPONSE)-1, 0, 0, (char **)&blob.pData); 00337 // Response is missing 00338 if (blob.uLength != DIGEST_AUTHENTICATION_BUFFER_SIZE) 00339 return; 00340 00341 currentLocation.pData = correctResponse; 00342 currentLocation.uLength = DIGEST_AUTHENTICATION_BUFFER_SIZE; 00343 // if the responses are equal 00344 if (HttpString_strcmp(blob, currentLocation) == 0) 00345 pRequest->uFlags |= HTTP_REQUEST_FLAG_AUTHENTICATED; 00346 00347 } 00348 #endif 00349
Generated on Wed Jul 13 2022 13:30:51 by
1.7.2