Webserver+3d print

Dependents:   Nucleo

Committer:
Sergunb
Date:
Sat Feb 04 18:15:49 2017 +0000
Revision:
0:8918a71cdbe9
nothing else

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Sergunb 0:8918a71cdbe9 1 /**
Sergunb 0:8918a71cdbe9 2 * @file http_server_auth.c
Sergunb 0:8918a71cdbe9 3 * @brief HTTP authentication
Sergunb 0:8918a71cdbe9 4 *
Sergunb 0:8918a71cdbe9 5 * @section License
Sergunb 0:8918a71cdbe9 6 *
Sergunb 0:8918a71cdbe9 7 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
Sergunb 0:8918a71cdbe9 8 *
Sergunb 0:8918a71cdbe9 9 * This file is part of CycloneTCP Open.
Sergunb 0:8918a71cdbe9 10 *
Sergunb 0:8918a71cdbe9 11 * This program is free software; you can redistribute it and/or
Sergunb 0:8918a71cdbe9 12 * modify it under the terms of the GNU General Public License
Sergunb 0:8918a71cdbe9 13 * as published by the Free Software Foundation; either version 2
Sergunb 0:8918a71cdbe9 14 * of the License, or (at your option) any later version.
Sergunb 0:8918a71cdbe9 15 *
Sergunb 0:8918a71cdbe9 16 * This program is distributed in the hope that it will be useful,
Sergunb 0:8918a71cdbe9 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Sergunb 0:8918a71cdbe9 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Sergunb 0:8918a71cdbe9 19 * GNU General Public License for more details.
Sergunb 0:8918a71cdbe9 20 *
Sergunb 0:8918a71cdbe9 21 * You should have received a copy of the GNU General Public License
Sergunb 0:8918a71cdbe9 22 * along with this program; if not, write to the Free Software Foundation,
Sergunb 0:8918a71cdbe9 23 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Sergunb 0:8918a71cdbe9 24 *
Sergunb 0:8918a71cdbe9 25 * @author Oryx Embedded SARL (www.oryx-embedded.com)
Sergunb 0:8918a71cdbe9 26 * @version 1.7.6
Sergunb 0:8918a71cdbe9 27 **/
Sergunb 0:8918a71cdbe9 28
Sergunb 0:8918a71cdbe9 29 //Switch to the appropriate trace level
Sergunb 0:8918a71cdbe9 30 #define TRACE_LEVEL HTTP_TRACE_LEVEL
Sergunb 0:8918a71cdbe9 31
Sergunb 0:8918a71cdbe9 32 //Dependencies
Sergunb 0:8918a71cdbe9 33 #include <stdlib.h>
Sergunb 0:8918a71cdbe9 34 #include "core/net.h"
Sergunb 0:8918a71cdbe9 35 #include "http/http_server.h"
Sergunb 0:8918a71cdbe9 36 #include "http/http_server_auth.h"
Sergunb 0:8918a71cdbe9 37 #include "http/http_server_misc.h"
Sergunb 0:8918a71cdbe9 38 #include "str.h"
Sergunb 0:8918a71cdbe9 39 #include "debug.h"
Sergunb 0:8918a71cdbe9 40
Sergunb 0:8918a71cdbe9 41 //Check TCP/IP stack configuration
Sergunb 0:8918a71cdbe9 42 #if (HTTP_SERVER_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 43
Sergunb 0:8918a71cdbe9 44
Sergunb 0:8918a71cdbe9 45 /**
Sergunb 0:8918a71cdbe9 46 * @brief Password verification
Sergunb 0:8918a71cdbe9 47 * @param[in] connection Structure representing an HTTP connection
Sergunb 0:8918a71cdbe9 48 * @param[in] password NULL-terminated string containing the password to be checked
Sergunb 0:8918a71cdbe9 49 * @param[in] mode HTTP authentication scheme to be used. Acceptable
Sergunb 0:8918a71cdbe9 50 * values are HTTP_AUTH_MODE_BASIC or HTTP_AUTH_MODE_DIGEST
Sergunb 0:8918a71cdbe9 51 * @return TRUE if the password is valid, else FALSE
Sergunb 0:8918a71cdbe9 52 **/
Sergunb 0:8918a71cdbe9 53
Sergunb 0:8918a71cdbe9 54 bool_t httpCheckPassword(HttpConnection *connection,
Sergunb 0:8918a71cdbe9 55 const char_t *password, HttpAuthMode mode)
Sergunb 0:8918a71cdbe9 56 {
Sergunb 0:8918a71cdbe9 57 //This flag tells whether the password is valid
Sergunb 0:8918a71cdbe9 58 bool_t status = FALSE;
Sergunb 0:8918a71cdbe9 59
Sergunb 0:8918a71cdbe9 60 //Debug message
Sergunb 0:8918a71cdbe9 61 TRACE_DEBUG("HTTP password verification...\r\n");
Sergunb 0:8918a71cdbe9 62
Sergunb 0:8918a71cdbe9 63 #if (HTTP_SERVER_BASIC_AUTH_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 64 //Basic authentication scheme?
Sergunb 0:8918a71cdbe9 65 if(mode == HTTP_AUTH_MODE_BASIC)
Sergunb 0:8918a71cdbe9 66 {
Sergunb 0:8918a71cdbe9 67 //Point to the authentication credentials
Sergunb 0:8918a71cdbe9 68 HttpAuthorizationHeader *auth = &connection->request.auth;
Sergunb 0:8918a71cdbe9 69
Sergunb 0:8918a71cdbe9 70 //Make sure authentication credentials have been found
Sergunb 0:8918a71cdbe9 71 if(auth->found && auth->mode == HTTP_AUTH_MODE_BASIC)
Sergunb 0:8918a71cdbe9 72 {
Sergunb 0:8918a71cdbe9 73 //Sanity check
Sergunb 0:8918a71cdbe9 74 if(auth->password != NULL)
Sergunb 0:8918a71cdbe9 75 {
Sergunb 0:8918a71cdbe9 76 //Check whether the password is valid
Sergunb 0:8918a71cdbe9 77 if(!strcmp(password, auth->password))
Sergunb 0:8918a71cdbe9 78 status = TRUE;
Sergunb 0:8918a71cdbe9 79 }
Sergunb 0:8918a71cdbe9 80 }
Sergunb 0:8918a71cdbe9 81 }
Sergunb 0:8918a71cdbe9 82 #endif
Sergunb 0:8918a71cdbe9 83 #if (HTTP_SERVER_DIGEST_AUTH_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 84 //Digest authentication scheme?
Sergunb 0:8918a71cdbe9 85 if(mode == HTTP_AUTH_MODE_DIGEST)
Sergunb 0:8918a71cdbe9 86 {
Sergunb 0:8918a71cdbe9 87 //Point to the authentication credentials
Sergunb 0:8918a71cdbe9 88 HttpAuthorizationHeader *auth = &connection->request.auth;
Sergunb 0:8918a71cdbe9 89
Sergunb 0:8918a71cdbe9 90 //Make sure authentication credentials have been found
Sergunb 0:8918a71cdbe9 91 if(auth->found && auth->mode == HTTP_AUTH_MODE_DIGEST)
Sergunb 0:8918a71cdbe9 92 {
Sergunb 0:8918a71cdbe9 93 //Sanity check
Sergunb 0:8918a71cdbe9 94 if(auth->realm != NULL && auth->nonce != NULL &&
Sergunb 0:8918a71cdbe9 95 auth->uri != NULL && auth->qop != NULL &&
Sergunb 0:8918a71cdbe9 96 auth->nc != NULL && auth->cnonce != NULL &&
Sergunb 0:8918a71cdbe9 97 auth->response != NULL)
Sergunb 0:8918a71cdbe9 98 {
Sergunb 0:8918a71cdbe9 99 error_t error;
Sergunb 0:8918a71cdbe9 100 Md5Context *md5Context;
Sergunb 0:8918a71cdbe9 101 char_t ha1[2 * MD5_DIGEST_SIZE + 1];
Sergunb 0:8918a71cdbe9 102 char_t ha2[2 * MD5_DIGEST_SIZE + 1];
Sergunb 0:8918a71cdbe9 103
Sergunb 0:8918a71cdbe9 104 //Allocate a memory buffer to hold the MD5 context
Sergunb 0:8918a71cdbe9 105 md5Context = osAllocMem(sizeof(Md5Context));
Sergunb 0:8918a71cdbe9 106
Sergunb 0:8918a71cdbe9 107 //MD5 context successfully allocated?
Sergunb 0:8918a71cdbe9 108 if(md5Context != NULL)
Sergunb 0:8918a71cdbe9 109 {
Sergunb 0:8918a71cdbe9 110 //Compute HA1 = MD5(username : realm : password)
Sergunb 0:8918a71cdbe9 111 md5Init(md5Context);
Sergunb 0:8918a71cdbe9 112 md5Update(md5Context, auth->user, strlen(auth->user));
Sergunb 0:8918a71cdbe9 113 md5Update(md5Context, ":", 1);
Sergunb 0:8918a71cdbe9 114 md5Update(md5Context, auth->realm, strlen(auth->realm));
Sergunb 0:8918a71cdbe9 115 md5Update(md5Context, ":", 1);
Sergunb 0:8918a71cdbe9 116 md5Update(md5Context, password, strlen(password));
Sergunb 0:8918a71cdbe9 117 md5Final(md5Context, NULL);
Sergunb 0:8918a71cdbe9 118
Sergunb 0:8918a71cdbe9 119 //Convert MD5 hash to hex string
Sergunb 0:8918a71cdbe9 120 httpConvertArrayToHexString(md5Context->digest, MD5_DIGEST_SIZE, ha1);
Sergunb 0:8918a71cdbe9 121 //Debug message
Sergunb 0:8918a71cdbe9 122 TRACE_DEBUG(" HA1: %s\r\n", ha1);
Sergunb 0:8918a71cdbe9 123
Sergunb 0:8918a71cdbe9 124 //Compute HA2 = MD5(method : uri)
Sergunb 0:8918a71cdbe9 125 md5Init(md5Context);
Sergunb 0:8918a71cdbe9 126 md5Update(md5Context, connection->request.method, strlen(connection->request.method));
Sergunb 0:8918a71cdbe9 127 md5Update(md5Context, ":", 1);
Sergunb 0:8918a71cdbe9 128 md5Update(md5Context, auth->uri, strlen(auth->uri));
Sergunb 0:8918a71cdbe9 129 md5Final(md5Context, NULL);
Sergunb 0:8918a71cdbe9 130
Sergunb 0:8918a71cdbe9 131 //Convert MD5 hash to hex string
Sergunb 0:8918a71cdbe9 132 httpConvertArrayToHexString(md5Context->digest, MD5_DIGEST_SIZE, ha2);
Sergunb 0:8918a71cdbe9 133 //Debug message
Sergunb 0:8918a71cdbe9 134 TRACE_DEBUG(" HA2: %s\r\n", ha2);
Sergunb 0:8918a71cdbe9 135
Sergunb 0:8918a71cdbe9 136 //Compute MD5(HA1 : nonce : nc : cnonce : qop : HA1)
Sergunb 0:8918a71cdbe9 137 md5Init(md5Context);
Sergunb 0:8918a71cdbe9 138 md5Update(md5Context, ha1, strlen(ha1));
Sergunb 0:8918a71cdbe9 139 md5Update(md5Context, ":", 1);
Sergunb 0:8918a71cdbe9 140 md5Update(md5Context, auth->nonce, strlen(auth->nonce));
Sergunb 0:8918a71cdbe9 141 md5Update(md5Context, ":", 1);
Sergunb 0:8918a71cdbe9 142 md5Update(md5Context, auth->nc, strlen(auth->nc));
Sergunb 0:8918a71cdbe9 143 md5Update(md5Context, ":", 1);
Sergunb 0:8918a71cdbe9 144 md5Update(md5Context, auth->cnonce, strlen(auth->cnonce));
Sergunb 0:8918a71cdbe9 145 md5Update(md5Context, ":", 1);
Sergunb 0:8918a71cdbe9 146 md5Update(md5Context, auth->qop, strlen(auth->qop));
Sergunb 0:8918a71cdbe9 147 md5Update(md5Context, ":", 1);
Sergunb 0:8918a71cdbe9 148 md5Update(md5Context, ha2, strlen(ha2));
Sergunb 0:8918a71cdbe9 149 md5Final(md5Context, NULL);
Sergunb 0:8918a71cdbe9 150
Sergunb 0:8918a71cdbe9 151 //Convert MD5 hash to hex string
Sergunb 0:8918a71cdbe9 152 httpConvertArrayToHexString(md5Context->digest, MD5_DIGEST_SIZE, ha1);
Sergunb 0:8918a71cdbe9 153 //Debug message
Sergunb 0:8918a71cdbe9 154 TRACE_DEBUG(" response: %s\r\n", ha1);
Sergunb 0:8918a71cdbe9 155
Sergunb 0:8918a71cdbe9 156 //Release MD5 context
Sergunb 0:8918a71cdbe9 157 osFreeMem(md5Context);
Sergunb 0:8918a71cdbe9 158
Sergunb 0:8918a71cdbe9 159 //Check response
Sergunb 0:8918a71cdbe9 160 if(!strcasecmp(auth->response, ha1))
Sergunb 0:8918a71cdbe9 161 {
Sergunb 0:8918a71cdbe9 162 //Perform nonce verification
Sergunb 0:8918a71cdbe9 163 error = httpVerifyNonce(connection->serverContext, auth->nonce, auth->nc);
Sergunb 0:8918a71cdbe9 164
Sergunb 0:8918a71cdbe9 165 //Valid nonce?
Sergunb 0:8918a71cdbe9 166 if(!error)
Sergunb 0:8918a71cdbe9 167 {
Sergunb 0:8918a71cdbe9 168 //Access to the resource is granted
Sergunb 0:8918a71cdbe9 169 status = TRUE;
Sergunb 0:8918a71cdbe9 170 }
Sergunb 0:8918a71cdbe9 171 else
Sergunb 0:8918a71cdbe9 172 {
Sergunb 0:8918a71cdbe9 173 //The client may wish to simply retry the request with a
Sergunb 0:8918a71cdbe9 174 //new encrypted response, without re-prompting the user
Sergunb 0:8918a71cdbe9 175 //for a new username and password
Sergunb 0:8918a71cdbe9 176 connection->response.auth.stale = TRUE;
Sergunb 0:8918a71cdbe9 177 }
Sergunb 0:8918a71cdbe9 178 }
Sergunb 0:8918a71cdbe9 179 }
Sergunb 0:8918a71cdbe9 180 }
Sergunb 0:8918a71cdbe9 181 }
Sergunb 0:8918a71cdbe9 182 }
Sergunb 0:8918a71cdbe9 183 #endif
Sergunb 0:8918a71cdbe9 184
Sergunb 0:8918a71cdbe9 185 //Return TRUE is the password is valid, else FALSE
Sergunb 0:8918a71cdbe9 186 return status;
Sergunb 0:8918a71cdbe9 187 }
Sergunb 0:8918a71cdbe9 188
Sergunb 0:8918a71cdbe9 189
Sergunb 0:8918a71cdbe9 190 /**
Sergunb 0:8918a71cdbe9 191 * @brief Parse Authorization header field
Sergunb 0:8918a71cdbe9 192 * @param[in] connection Structure representing an HTTP connection
Sergunb 0:8918a71cdbe9 193 * @param[in] value Authorization field value
Sergunb 0:8918a71cdbe9 194 **/
Sergunb 0:8918a71cdbe9 195
Sergunb 0:8918a71cdbe9 196 void httpParseAuthorizationField(HttpConnection *connection, char_t *value)
Sergunb 0:8918a71cdbe9 197 {
Sergunb 0:8918a71cdbe9 198 char_t *p;
Sergunb 0:8918a71cdbe9 199 char_t *token;
Sergunb 0:8918a71cdbe9 200
Sergunb 0:8918a71cdbe9 201 //Retrieve the authentication scheme
Sergunb 0:8918a71cdbe9 202 token = strtok_r(value, " \t", &p);
Sergunb 0:8918a71cdbe9 203
Sergunb 0:8918a71cdbe9 204 //Any parsing error?
Sergunb 0:8918a71cdbe9 205 if(token == NULL)
Sergunb 0:8918a71cdbe9 206 {
Sergunb 0:8918a71cdbe9 207 //Exit immediately
Sergunb 0:8918a71cdbe9 208 return;
Sergunb 0:8918a71cdbe9 209 }
Sergunb 0:8918a71cdbe9 210 #if (HTTP_SERVER_BASIC_AUTH_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 211 //Basic access authentication?
Sergunb 0:8918a71cdbe9 212 else if(!strcasecmp(token, "Basic"))
Sergunb 0:8918a71cdbe9 213 {
Sergunb 0:8918a71cdbe9 214 error_t error;
Sergunb 0:8918a71cdbe9 215 size_t n;
Sergunb 0:8918a71cdbe9 216 char_t *separator;
Sergunb 0:8918a71cdbe9 217
Sergunb 0:8918a71cdbe9 218 //Use the relevant authentication scheme
Sergunb 0:8918a71cdbe9 219 connection->request.auth.mode = HTTP_AUTH_MODE_BASIC;
Sergunb 0:8918a71cdbe9 220 //Retrieve the credentials
Sergunb 0:8918a71cdbe9 221 token = strtok_r(NULL, " \t", &p);
Sergunb 0:8918a71cdbe9 222
Sergunb 0:8918a71cdbe9 223 //Any parsing error?
Sergunb 0:8918a71cdbe9 224 if(token != NULL)
Sergunb 0:8918a71cdbe9 225 {
Sergunb 0:8918a71cdbe9 226 //Decrypt the Base64 encoded string
Sergunb 0:8918a71cdbe9 227 error = base64Decode(token, strlen(token), token, &n);
Sergunb 0:8918a71cdbe9 228
Sergunb 0:8918a71cdbe9 229 //Successful decoding?
Sergunb 0:8918a71cdbe9 230 if(!error)
Sergunb 0:8918a71cdbe9 231 {
Sergunb 0:8918a71cdbe9 232 //Properly terminate the string
Sergunb 0:8918a71cdbe9 233 token[n] = '\0';
Sergunb 0:8918a71cdbe9 234 //Check whether a separator is present
Sergunb 0:8918a71cdbe9 235 separator = strchr(token, ':');
Sergunb 0:8918a71cdbe9 236
Sergunb 0:8918a71cdbe9 237 //Separator found?
Sergunb 0:8918a71cdbe9 238 if(separator != NULL)
Sergunb 0:8918a71cdbe9 239 {
Sergunb 0:8918a71cdbe9 240 //Split the line
Sergunb 0:8918a71cdbe9 241 *separator = '\0';
Sergunb 0:8918a71cdbe9 242
Sergunb 0:8918a71cdbe9 243 //Save user name
Sergunb 0:8918a71cdbe9 244 strSafeCopy(connection->request.auth.user,
Sergunb 0:8918a71cdbe9 245 token, HTTP_SERVER_USERNAME_MAX_LEN);
Sergunb 0:8918a71cdbe9 246
Sergunb 0:8918a71cdbe9 247 //Point to the password
Sergunb 0:8918a71cdbe9 248 token = separator + 1;
Sergunb 0:8918a71cdbe9 249 //Save password
Sergunb 0:8918a71cdbe9 250 connection->request.auth.password = token;
Sergunb 0:8918a71cdbe9 251 }
Sergunb 0:8918a71cdbe9 252 }
Sergunb 0:8918a71cdbe9 253 }
Sergunb 0:8918a71cdbe9 254
Sergunb 0:8918a71cdbe9 255 //Debug message
Sergunb 0:8918a71cdbe9 256 TRACE_DEBUG("Authorization header:\r\n");
Sergunb 0:8918a71cdbe9 257 TRACE_DEBUG(" username: %s\r\n", connection->request.auth.user);
Sergunb 0:8918a71cdbe9 258 TRACE_DEBUG(" password: %s\r\n", connection->request.auth.password);
Sergunb 0:8918a71cdbe9 259 }
Sergunb 0:8918a71cdbe9 260 #endif
Sergunb 0:8918a71cdbe9 261 #if (HTTP_SERVER_DIGEST_AUTH_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 262 //Digest access authentication?
Sergunb 0:8918a71cdbe9 263 else if(!strcasecmp(token, "Digest"))
Sergunb 0:8918a71cdbe9 264 {
Sergunb 0:8918a71cdbe9 265 size_t n;
Sergunb 0:8918a71cdbe9 266 char_t *separator;
Sergunb 0:8918a71cdbe9 267 char_t *name;
Sergunb 0:8918a71cdbe9 268
Sergunb 0:8918a71cdbe9 269 //Use the relevant authentication scheme
Sergunb 0:8918a71cdbe9 270 connection->request.auth.mode = HTTP_AUTH_MODE_DIGEST;
Sergunb 0:8918a71cdbe9 271 //Get the first parameter
Sergunb 0:8918a71cdbe9 272 token = strtok_r(NULL, ",", &p);
Sergunb 0:8918a71cdbe9 273
Sergunb 0:8918a71cdbe9 274 //Parse the Authorization header field
Sergunb 0:8918a71cdbe9 275 while(token != NULL)
Sergunb 0:8918a71cdbe9 276 {
Sergunb 0:8918a71cdbe9 277 //Check whether a separator is present
Sergunb 0:8918a71cdbe9 278 separator = strchr(token, '=');
Sergunb 0:8918a71cdbe9 279
Sergunb 0:8918a71cdbe9 280 //Separator found?
Sergunb 0:8918a71cdbe9 281 if(separator != NULL)
Sergunb 0:8918a71cdbe9 282 {
Sergunb 0:8918a71cdbe9 283 //Split the string
Sergunb 0:8918a71cdbe9 284 *separator = '\0';
Sergunb 0:8918a71cdbe9 285
Sergunb 0:8918a71cdbe9 286 //Get field name and value
Sergunb 0:8918a71cdbe9 287 name = strTrimWhitespace(token);
Sergunb 0:8918a71cdbe9 288 value = strTrimWhitespace(separator + 1);
Sergunb 0:8918a71cdbe9 289
Sergunb 0:8918a71cdbe9 290 //Retrieve the length of the value field
Sergunb 0:8918a71cdbe9 291 n = strlen(value);
Sergunb 0:8918a71cdbe9 292
Sergunb 0:8918a71cdbe9 293 //Discard the surrounding quotes
Sergunb 0:8918a71cdbe9 294 if(n > 0 && value[n - 1] == '\"')
Sergunb 0:8918a71cdbe9 295 value[n - 1] = '\0';
Sergunb 0:8918a71cdbe9 296 if(value[0] == '\"')
Sergunb 0:8918a71cdbe9 297 value++;
Sergunb 0:8918a71cdbe9 298
Sergunb 0:8918a71cdbe9 299 //Check parameter name
Sergunb 0:8918a71cdbe9 300 if(!strcasecmp(name, "username"))
Sergunb 0:8918a71cdbe9 301 {
Sergunb 0:8918a71cdbe9 302 //Save user name
Sergunb 0:8918a71cdbe9 303 strSafeCopy(connection->request.auth.user,
Sergunb 0:8918a71cdbe9 304 value, HTTP_SERVER_USERNAME_MAX_LEN);
Sergunb 0:8918a71cdbe9 305 }
Sergunb 0:8918a71cdbe9 306 else if(!strcasecmp(name, "realm"))
Sergunb 0:8918a71cdbe9 307 {
Sergunb 0:8918a71cdbe9 308 //Save realm
Sergunb 0:8918a71cdbe9 309 connection->request.auth.realm = value;
Sergunb 0:8918a71cdbe9 310 }
Sergunb 0:8918a71cdbe9 311 else if(!strcasecmp(name, "nonce"))
Sergunb 0:8918a71cdbe9 312 {
Sergunb 0:8918a71cdbe9 313 //Save nonce parameter
Sergunb 0:8918a71cdbe9 314 connection->request.auth.nonce = value;
Sergunb 0:8918a71cdbe9 315 }
Sergunb 0:8918a71cdbe9 316 else if(!strcasecmp(name, "uri"))
Sergunb 0:8918a71cdbe9 317 {
Sergunb 0:8918a71cdbe9 318 //Save uri parameter
Sergunb 0:8918a71cdbe9 319 connection->request.auth.uri = value;
Sergunb 0:8918a71cdbe9 320 }
Sergunb 0:8918a71cdbe9 321 else if(!strcasecmp(name, "qop"))
Sergunb 0:8918a71cdbe9 322 {
Sergunb 0:8918a71cdbe9 323 //Save qop parameter
Sergunb 0:8918a71cdbe9 324 connection->request.auth.qop = value;
Sergunb 0:8918a71cdbe9 325 }
Sergunb 0:8918a71cdbe9 326 else if(!strcasecmp(name, "nc"))
Sergunb 0:8918a71cdbe9 327 {
Sergunb 0:8918a71cdbe9 328 //Save nc parameter
Sergunb 0:8918a71cdbe9 329 connection->request.auth.nc = value;
Sergunb 0:8918a71cdbe9 330 }
Sergunb 0:8918a71cdbe9 331 else if(!strcasecmp(name, "cnonce"))
Sergunb 0:8918a71cdbe9 332 {
Sergunb 0:8918a71cdbe9 333 //Save cnonce parameter
Sergunb 0:8918a71cdbe9 334 connection->request.auth.cnonce = value;
Sergunb 0:8918a71cdbe9 335 }
Sergunb 0:8918a71cdbe9 336 else if(!strcasecmp(name, "response"))
Sergunb 0:8918a71cdbe9 337 {
Sergunb 0:8918a71cdbe9 338 //Save response parameter
Sergunb 0:8918a71cdbe9 339 connection->request.auth.response = value;
Sergunb 0:8918a71cdbe9 340 }
Sergunb 0:8918a71cdbe9 341 else if(!strcasecmp(name, "opaque"))
Sergunb 0:8918a71cdbe9 342 {
Sergunb 0:8918a71cdbe9 343 //Save opaque parameter
Sergunb 0:8918a71cdbe9 344 connection->request.auth.opaque = value;
Sergunb 0:8918a71cdbe9 345 }
Sergunb 0:8918a71cdbe9 346
Sergunb 0:8918a71cdbe9 347 //Get next parameter
Sergunb 0:8918a71cdbe9 348 token = strtok_r(NULL, ",", &p);
Sergunb 0:8918a71cdbe9 349 }
Sergunb 0:8918a71cdbe9 350 }
Sergunb 0:8918a71cdbe9 351
Sergunb 0:8918a71cdbe9 352 //Debug message
Sergunb 0:8918a71cdbe9 353 TRACE_DEBUG("Authorization header:\r\n");
Sergunb 0:8918a71cdbe9 354 TRACE_DEBUG(" username: %s\r\n", connection->request.auth.user);
Sergunb 0:8918a71cdbe9 355 TRACE_DEBUG(" realm: %s\r\n", connection->request.auth.realm);
Sergunb 0:8918a71cdbe9 356 TRACE_DEBUG(" nonce: %s\r\n", connection->request.auth.nonce);
Sergunb 0:8918a71cdbe9 357 TRACE_DEBUG(" uri: %s\r\n", connection->request.auth.uri);
Sergunb 0:8918a71cdbe9 358 TRACE_DEBUG(" qop: %s\r\n", connection->request.auth.qop);
Sergunb 0:8918a71cdbe9 359 TRACE_DEBUG(" nc: %s\r\n", connection->request.auth.nc);
Sergunb 0:8918a71cdbe9 360 TRACE_DEBUG(" cnonce: %s\r\n", connection->request.auth.cnonce);
Sergunb 0:8918a71cdbe9 361 TRACE_DEBUG(" response: %s\r\n", connection->request.auth.response);
Sergunb 0:8918a71cdbe9 362 TRACE_DEBUG(" opaque: %s\r\n", connection->request.auth.opaque);
Sergunb 0:8918a71cdbe9 363 }
Sergunb 0:8918a71cdbe9 364 #endif
Sergunb 0:8918a71cdbe9 365 else
Sergunb 0:8918a71cdbe9 366 {
Sergunb 0:8918a71cdbe9 367 //The specified authentication scheme is not supported
Sergunb 0:8918a71cdbe9 368 return;
Sergunb 0:8918a71cdbe9 369 }
Sergunb 0:8918a71cdbe9 370
Sergunb 0:8918a71cdbe9 371 #if (HTTP_SERVER_BASIC_AUTH_SUPPORT == ENABLED || HTTP_SERVER_DIGEST_AUTH_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 372 //The Authorization header has been found
Sergunb 0:8918a71cdbe9 373 connection->request.auth.found = TRUE;
Sergunb 0:8918a71cdbe9 374
Sergunb 0:8918a71cdbe9 375 //Invoke user-defined callback, if any
Sergunb 0:8918a71cdbe9 376 if(connection->settings->authCallback != NULL)
Sergunb 0:8918a71cdbe9 377 {
Sergunb 0:8918a71cdbe9 378 //Check whether the access to the specified URI is authorized
Sergunb 0:8918a71cdbe9 379 connection->status = connection->settings->authCallback(connection,
Sergunb 0:8918a71cdbe9 380 connection->request.auth.user, connection->request.uri);
Sergunb 0:8918a71cdbe9 381 }
Sergunb 0:8918a71cdbe9 382 else
Sergunb 0:8918a71cdbe9 383 {
Sergunb 0:8918a71cdbe9 384 //Access to the specified URI is allowed
Sergunb 0:8918a71cdbe9 385 connection->status = HTTP_ACCESS_ALLOWED;
Sergunb 0:8918a71cdbe9 386 }
Sergunb 0:8918a71cdbe9 387 #endif
Sergunb 0:8918a71cdbe9 388 }
Sergunb 0:8918a71cdbe9 389
Sergunb 0:8918a71cdbe9 390
Sergunb 0:8918a71cdbe9 391 /**
Sergunb 0:8918a71cdbe9 392 * @brief Format WWW-Authenticate header field
Sergunb 0:8918a71cdbe9 393 * @param[in] connection Structure representing an HTTP connection
Sergunb 0:8918a71cdbe9 394 * @param[out] output Buffer where to format the header field
Sergunb 0:8918a71cdbe9 395 * @return Total length of the header field
Sergunb 0:8918a71cdbe9 396 **/
Sergunb 0:8918a71cdbe9 397
Sergunb 0:8918a71cdbe9 398 size_t httpAddAuthenticateField(HttpConnection *connection, char_t *output)
Sergunb 0:8918a71cdbe9 399 {
Sergunb 0:8918a71cdbe9 400 size_t n;
Sergunb 0:8918a71cdbe9 401
Sergunb 0:8918a71cdbe9 402 #if (HTTP_SERVER_BASIC_AUTH_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 403 //Basic authentication scheme?
Sergunb 0:8918a71cdbe9 404 if(connection->response.auth.mode == HTTP_AUTH_MODE_BASIC)
Sergunb 0:8918a71cdbe9 405 {
Sergunb 0:8918a71cdbe9 406 //Set WWW-Authenticate field
Sergunb 0:8918a71cdbe9 407 n = sprintf(output, "WWW-Authenticate: Basic realm=\"Protected Area\"\r\n");
Sergunb 0:8918a71cdbe9 408 }
Sergunb 0:8918a71cdbe9 409 else
Sergunb 0:8918a71cdbe9 410 #endif
Sergunb 0:8918a71cdbe9 411 #if (HTTP_SERVER_DIGEST_AUTH_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 412 //Digest authentication scheme?
Sergunb 0:8918a71cdbe9 413 if(connection->response.auth.mode == HTTP_AUTH_MODE_DIGEST)
Sergunb 0:8918a71cdbe9 414 {
Sergunb 0:8918a71cdbe9 415 error_t error;
Sergunb 0:8918a71cdbe9 416 size_t k;
Sergunb 0:8918a71cdbe9 417 uint8_t opaque[16];
Sergunb 0:8918a71cdbe9 418
Sergunb 0:8918a71cdbe9 419 //Set WWW-Authenticate field
Sergunb 0:8918a71cdbe9 420 n = sprintf(output, "WWW-Authenticate: Digest\r\n");
Sergunb 0:8918a71cdbe9 421 n += sprintf(output + n, " realm=\"Protected Area\",\r\n");
Sergunb 0:8918a71cdbe9 422 n += sprintf(output + n, " qop=\"auth\",\r\n");
Sergunb 0:8918a71cdbe9 423 n += sprintf(output + n, " nonce=\"");
Sergunb 0:8918a71cdbe9 424
Sergunb 0:8918a71cdbe9 425 //The nonce is a server-specified data string which should be uniquely
Sergunb 0:8918a71cdbe9 426 //generated each time a 401 response is made
Sergunb 0:8918a71cdbe9 427 error = httpGenerateNonce(connection->serverContext, output + n, &k);
Sergunb 0:8918a71cdbe9 428 //Any error to report?
Sergunb 0:8918a71cdbe9 429 if(error)
Sergunb 0:8918a71cdbe9 430 return error;
Sergunb 0:8918a71cdbe9 431
Sergunb 0:8918a71cdbe9 432 //Advance pointer
Sergunb 0:8918a71cdbe9 433 n += k;
Sergunb 0:8918a71cdbe9 434 //Properly terminate the nonce string
Sergunb 0:8918a71cdbe9 435 n += sprintf(output + n, "\",\r\n");
Sergunb 0:8918a71cdbe9 436
Sergunb 0:8918a71cdbe9 437 //Format opaque parameter
Sergunb 0:8918a71cdbe9 438 n += sprintf(output + n, " opaque=\"");
Sergunb 0:8918a71cdbe9 439
Sergunb 0:8918a71cdbe9 440 //Generate a random value
Sergunb 0:8918a71cdbe9 441 if(connection->settings->randCallback != NULL)
Sergunb 0:8918a71cdbe9 442 error = connection->settings->randCallback(opaque, 16);
Sergunb 0:8918a71cdbe9 443 else
Sergunb 0:8918a71cdbe9 444 error = ERROR_FAILURE;
Sergunb 0:8918a71cdbe9 445
Sergunb 0:8918a71cdbe9 446 //Random number generation failed?
Sergunb 0:8918a71cdbe9 447 if(error)
Sergunb 0:8918a71cdbe9 448 return error;
Sergunb 0:8918a71cdbe9 449
Sergunb 0:8918a71cdbe9 450 //Convert the byte array to hex string
Sergunb 0:8918a71cdbe9 451 httpConvertArrayToHexString(opaque, 16, output + n);
Sergunb 0:8918a71cdbe9 452
Sergunb 0:8918a71cdbe9 453 //Advance pointer
Sergunb 0:8918a71cdbe9 454 n += 32;
Sergunb 0:8918a71cdbe9 455 //Properly terminate the opaque string
Sergunb 0:8918a71cdbe9 456 n += sprintf(output + n, "\"");
Sergunb 0:8918a71cdbe9 457
Sergunb 0:8918a71cdbe9 458 //The STALE flag indicates that the previous request from the client
Sergunb 0:8918a71cdbe9 459 //was rejected because the nonce value was stale
Sergunb 0:8918a71cdbe9 460 if(connection->response.auth.stale)
Sergunb 0:8918a71cdbe9 461 n += sprintf(output + n, ",\r\n stale=TRUE");
Sergunb 0:8918a71cdbe9 462
Sergunb 0:8918a71cdbe9 463 //Properly terminate the WWW-Authenticate field
Sergunb 0:8918a71cdbe9 464 n += sprintf(output + n, "\r\n");
Sergunb 0:8918a71cdbe9 465 }
Sergunb 0:8918a71cdbe9 466 else
Sergunb 0:8918a71cdbe9 467 #endif
Sergunb 0:8918a71cdbe9 468 //Unknown authentication scheme?
Sergunb 0:8918a71cdbe9 469 {
Sergunb 0:8918a71cdbe9 470 //No need to add the WWW-Authenticate header field
Sergunb 0:8918a71cdbe9 471 n = 0;
Sergunb 0:8918a71cdbe9 472 }
Sergunb 0:8918a71cdbe9 473
Sergunb 0:8918a71cdbe9 474 //Return the total length of the WWW-Authenticate header field
Sergunb 0:8918a71cdbe9 475 return n;
Sergunb 0:8918a71cdbe9 476 }
Sergunb 0:8918a71cdbe9 477
Sergunb 0:8918a71cdbe9 478
Sergunb 0:8918a71cdbe9 479 /**
Sergunb 0:8918a71cdbe9 480 * @brief Nonce generation
Sergunb 0:8918a71cdbe9 481 * @param[in] context Pointer to the HTTP server context
Sergunb 0:8918a71cdbe9 482 * @param[in] output NULL-terminated string containing the nonce
Sergunb 0:8918a71cdbe9 483 * @param[in] length NULL-terminated string containing the nonce count
Sergunb 0:8918a71cdbe9 484 * @return Error code
Sergunb 0:8918a71cdbe9 485 **/
Sergunb 0:8918a71cdbe9 486
Sergunb 0:8918a71cdbe9 487 error_t httpGenerateNonce(HttpServerContext *context,
Sergunb 0:8918a71cdbe9 488 char_t *output, size_t *length)
Sergunb 0:8918a71cdbe9 489 {
Sergunb 0:8918a71cdbe9 490 #if (HTTP_SERVER_DIGEST_AUTH_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 491 error_t error;
Sergunb 0:8918a71cdbe9 492 uint_t i;
Sergunb 0:8918a71cdbe9 493 HttpNonceCacheEntry *entry;
Sergunb 0:8918a71cdbe9 494 HttpNonceCacheEntry *oldestEntry;
Sergunb 0:8918a71cdbe9 495 uint8_t nonce[HTTP_SERVER_NONCE_SIZE];
Sergunb 0:8918a71cdbe9 496
Sergunb 0:8918a71cdbe9 497 //Acquire exclusive access to the nonce cache
Sergunb 0:8918a71cdbe9 498 osAcquireMutex(&context->nonceCacheMutex);
Sergunb 0:8918a71cdbe9 499
Sergunb 0:8918a71cdbe9 500 //Keep track of the oldest entry
Sergunb 0:8918a71cdbe9 501 oldestEntry = &context->nonceCache[0];
Sergunb 0:8918a71cdbe9 502
Sergunb 0:8918a71cdbe9 503 //Loop through nonce cache entries
Sergunb 0:8918a71cdbe9 504 for(i = 0; i < HTTP_SERVER_NONCE_CACHE_SIZE; i++)
Sergunb 0:8918a71cdbe9 505 {
Sergunb 0:8918a71cdbe9 506 //Point to the current entry
Sergunb 0:8918a71cdbe9 507 entry = &context->nonceCache[i];
Sergunb 0:8918a71cdbe9 508
Sergunb 0:8918a71cdbe9 509 //Check whether the entry is currently in used or not
Sergunb 0:8918a71cdbe9 510 if(!entry->count)
Sergunb 0:8918a71cdbe9 511 break;
Sergunb 0:8918a71cdbe9 512
Sergunb 0:8918a71cdbe9 513 //Keep track of the oldest entry in the table
Sergunb 0:8918a71cdbe9 514 if(timeCompare(entry->timestamp, oldestEntry->timestamp) < 0)
Sergunb 0:8918a71cdbe9 515 oldestEntry = entry;
Sergunb 0:8918a71cdbe9 516 }
Sergunb 0:8918a71cdbe9 517
Sergunb 0:8918a71cdbe9 518 //The oldest entry is removed whenever the table runs out of space
Sergunb 0:8918a71cdbe9 519 if(i >= HTTP_SERVER_NONCE_CACHE_SIZE)
Sergunb 0:8918a71cdbe9 520 entry = oldestEntry;
Sergunb 0:8918a71cdbe9 521
Sergunb 0:8918a71cdbe9 522 //Generate a new nonce
Sergunb 0:8918a71cdbe9 523 if(context->settings.randCallback != NULL)
Sergunb 0:8918a71cdbe9 524 error = context->settings.randCallback(nonce, HTTP_SERVER_NONCE_SIZE);
Sergunb 0:8918a71cdbe9 525 else
Sergunb 0:8918a71cdbe9 526 error = ERROR_FAILURE;
Sergunb 0:8918a71cdbe9 527
Sergunb 0:8918a71cdbe9 528 //Check status code
Sergunb 0:8918a71cdbe9 529 if(!error)
Sergunb 0:8918a71cdbe9 530 {
Sergunb 0:8918a71cdbe9 531 //Convert the byte array to hex string
Sergunb 0:8918a71cdbe9 532 httpConvertArrayToHexString(nonce, HTTP_SERVER_NONCE_SIZE, entry->nonce);
Sergunb 0:8918a71cdbe9 533 //Clear nonce count
Sergunb 0:8918a71cdbe9 534 entry->count = 1;
Sergunb 0:8918a71cdbe9 535 //Save the time at which the nonce was generated
Sergunb 0:8918a71cdbe9 536 entry->timestamp = osGetSystemTime();
Sergunb 0:8918a71cdbe9 537
Sergunb 0:8918a71cdbe9 538 //Copy the nonce to the output buffer
Sergunb 0:8918a71cdbe9 539 strcpy(output, entry->nonce);
Sergunb 0:8918a71cdbe9 540 //Return the length of the nonce excluding the NULL character
Sergunb 0:8918a71cdbe9 541 *length = HTTP_SERVER_NONCE_SIZE * 2;
Sergunb 0:8918a71cdbe9 542 }
Sergunb 0:8918a71cdbe9 543 else
Sergunb 0:8918a71cdbe9 544 {
Sergunb 0:8918a71cdbe9 545 //Random number generation failed
Sergunb 0:8918a71cdbe9 546 memset(entry, 0, sizeof(HttpNonceCacheEntry));
Sergunb 0:8918a71cdbe9 547 }
Sergunb 0:8918a71cdbe9 548
Sergunb 0:8918a71cdbe9 549 //Release exclusive access to the nonce cache
Sergunb 0:8918a71cdbe9 550 osReleaseMutex(&context->nonceCacheMutex);
Sergunb 0:8918a71cdbe9 551 //Return status code
Sergunb 0:8918a71cdbe9 552 return error;
Sergunb 0:8918a71cdbe9 553
Sergunb 0:8918a71cdbe9 554 #else
Sergunb 0:8918a71cdbe9 555 //Not implemented
Sergunb 0:8918a71cdbe9 556 return ERROR_NOT_IMPLEMENTED;
Sergunb 0:8918a71cdbe9 557 #endif
Sergunb 0:8918a71cdbe9 558 }
Sergunb 0:8918a71cdbe9 559
Sergunb 0:8918a71cdbe9 560
Sergunb 0:8918a71cdbe9 561 /**
Sergunb 0:8918a71cdbe9 562 * @brief Nonce verification
Sergunb 0:8918a71cdbe9 563 * @param[in] context Pointer to the HTTP server context
Sergunb 0:8918a71cdbe9 564 * @param[in] nonce NULL-terminated string containing the nonce
Sergunb 0:8918a71cdbe9 565 * @param[in] nc NULL-terminated string containing the nonce count
Sergunb 0:8918a71cdbe9 566 * @return Error code
Sergunb 0:8918a71cdbe9 567 **/
Sergunb 0:8918a71cdbe9 568
Sergunb 0:8918a71cdbe9 569 error_t httpVerifyNonce(HttpServerContext *context,
Sergunb 0:8918a71cdbe9 570 const char_t *nonce, const char_t *nc)
Sergunb 0:8918a71cdbe9 571 {
Sergunb 0:8918a71cdbe9 572 #if (HTTP_SERVER_DIGEST_AUTH_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 573 error_t error;
Sergunb 0:8918a71cdbe9 574 uint_t i;
Sergunb 0:8918a71cdbe9 575 uint32_t count;
Sergunb 0:8918a71cdbe9 576 systime_t time;
Sergunb 0:8918a71cdbe9 577 HttpNonceCacheEntry *entry;
Sergunb 0:8918a71cdbe9 578
Sergunb 0:8918a71cdbe9 579 //Check parameters
Sergunb 0:8918a71cdbe9 580 if(nonce == NULL || nc == NULL)
Sergunb 0:8918a71cdbe9 581 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 582
Sergunb 0:8918a71cdbe9 583 //Convert the nonce count to integer
Sergunb 0:8918a71cdbe9 584 count = strtoul(nc, NULL, 16);
Sergunb 0:8918a71cdbe9 585 //Get current time
Sergunb 0:8918a71cdbe9 586 time = osGetSystemTime();
Sergunb 0:8918a71cdbe9 587
Sergunb 0:8918a71cdbe9 588 //Acquire exclusive access to the nonce cache
Sergunb 0:8918a71cdbe9 589 osAcquireMutex(&context->nonceCacheMutex);
Sergunb 0:8918a71cdbe9 590
Sergunb 0:8918a71cdbe9 591 //Loop through nonce cache entries
Sergunb 0:8918a71cdbe9 592 for(i = 0; i < HTTP_SERVER_NONCE_CACHE_SIZE; i++)
Sergunb 0:8918a71cdbe9 593 {
Sergunb 0:8918a71cdbe9 594 //Point to the current entry
Sergunb 0:8918a71cdbe9 595 entry = &context->nonceCache[i];
Sergunb 0:8918a71cdbe9 596
Sergunb 0:8918a71cdbe9 597 //Check nonce value
Sergunb 0:8918a71cdbe9 598 if(!strcasecmp(entry->nonce, nonce))
Sergunb 0:8918a71cdbe9 599 {
Sergunb 0:8918a71cdbe9 600 //Make sure the nonce timestamp has not expired
Sergunb 0:8918a71cdbe9 601 if((time - entry->timestamp) < HTTP_SERVER_NONCE_LIFETIME)
Sergunb 0:8918a71cdbe9 602 {
Sergunb 0:8918a71cdbe9 603 //Check nonce count to prevent replay attacks
Sergunb 0:8918a71cdbe9 604 if(count >= entry->count)
Sergunb 0:8918a71cdbe9 605 {
Sergunb 0:8918a71cdbe9 606 //Update nonce count to the next expected value
Sergunb 0:8918a71cdbe9 607 entry->count = count + 1;
Sergunb 0:8918a71cdbe9 608 //We are done
Sergunb 0:8918a71cdbe9 609 break;
Sergunb 0:8918a71cdbe9 610 }
Sergunb 0:8918a71cdbe9 611 }
Sergunb 0:8918a71cdbe9 612 }
Sergunb 0:8918a71cdbe9 613 }
Sergunb 0:8918a71cdbe9 614
Sergunb 0:8918a71cdbe9 615 //Check whether the nonce is valid
Sergunb 0:8918a71cdbe9 616 if(i < HTTP_SERVER_NONCE_CACHE_SIZE)
Sergunb 0:8918a71cdbe9 617 error = NO_ERROR;
Sergunb 0:8918a71cdbe9 618 else
Sergunb 0:8918a71cdbe9 619 error = ERROR_NOT_FOUND;
Sergunb 0:8918a71cdbe9 620
Sergunb 0:8918a71cdbe9 621 //Release exclusive access to the nonce cache
Sergunb 0:8918a71cdbe9 622 osReleaseMutex(&context->nonceCacheMutex);
Sergunb 0:8918a71cdbe9 623 //Return status code
Sergunb 0:8918a71cdbe9 624 return error;
Sergunb 0:8918a71cdbe9 625
Sergunb 0:8918a71cdbe9 626 #else
Sergunb 0:8918a71cdbe9 627 //Not implemented
Sergunb 0:8918a71cdbe9 628 return ERROR_NOT_IMPLEMENTED;
Sergunb 0:8918a71cdbe9 629 #endif
Sergunb 0:8918a71cdbe9 630 }
Sergunb 0:8918a71cdbe9 631
Sergunb 0:8918a71cdbe9 632 #endif
Sergunb 0:8918a71cdbe9 633