A Port of TI's Webserver for the CC3000
Embed:
(wiki syntax)
Show/hide line numbers
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