TI's CC3100 websocket camera demo with Arducam mini ov5642 and freertos. Should work with other M3's. Work in progress test demo.
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 Wed Jul 13 2022 15:58:45 by 1.7.2