iPXE
httpdigest.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25FILE_SECBOOT ( PERMITTED );
26
27/**
28 * @file
29 *
30 * Hyper Text Transfer Protocol (HTTP) Digest authentication
31 *
32 */
33
34#include <stdio.h>
35#include <errno.h>
36#include <strings.h>
37#include <ipxe/uri.h>
38#include <ipxe/md5.h>
39#include <ipxe/base16.h>
40#include <ipxe/vsprintf.h>
41#include <ipxe/http.h>
42
43/* Disambiguate the various error causes */
44#define EACCES_USERNAME __einfo_error ( EINFO_EACCES_USERNAME )
45#define EINFO_EACCES_USERNAME \
46 __einfo_uniqify ( EINFO_EACCES, 0x01, \
47 "No username available for Digest authentication" )
48
49/** An HTTP Digest "WWW-Authenticate" response field */
51 /** Name */
52 const char *name;
53 /** Offset */
54 size_t offset;
55};
56
57/** Define an HTTP Digest "WWW-Authenticate" response field */
58#define HTTP_DIGEST_FIELD( _name ) { \
59 .name = #_name, \
60 .offset = offsetof ( struct http_transaction, \
61 response.auth.digest._name ), \
62 }
63
64/**
65 * Set HTTP Digest "WWW-Authenticate" response field value
66 *
67 * @v http HTTP transaction
68 * @v field Response field
69 * @v value Field value
70 */
71static inline void
73 struct http_digest_field *field, char *value ) {
74 char **ptr;
75
76 ptr = ( ( ( void * ) http ) + field->offset );
77 *ptr = value;
78}
79
80/** HTTP Digest "WWW-Authenticate" fields */
88
89/**
90 * Parse HTTP "WWW-Authenticate" header for Digest authentication
91 *
92 * @v http HTTP transaction
93 * @v line Remaining header line
94 * @ret rc Return status code
95 */
96static int http_parse_digest_auth ( struct http_transaction *http,
97 char *line ) {
98 struct http_digest_field *field;
99 char *key;
100 char *value;
101 unsigned int i;
102
103 /* Process fields */
104 while ( ( key = http_token ( &line, &value ) ) ) {
105 for ( i = 0 ; i < ( sizeof ( http_digest_fields ) /
106 sizeof ( http_digest_fields[0] ) ) ; i++){
107 field = &http_digest_fields[i];
108 if ( strcasecmp ( key, field->name ) == 0 )
109 http_digest_field ( http, field, value );
110 }
111 }
112
113 /* Allow HTTP request to be retried if the request had not
114 * already tried authentication.
115 */
116 if ( ! http->request.auth.auth )
118
119 return 0;
120}
121
122/**
123 * Initialise HTTP Digest
124 *
125 * @v ctx Digest context
126 * @v string Initial string
127 */
128static void http_digest_init ( struct md5_context *ctx ) {
129
130 /* Initialise MD5 digest */
132}
133
134/**
135 * Update HTTP Digest with new data
136 *
137 * @v ctx Digest context
138 * @v string String to append
139 */
140static void http_digest_update ( struct md5_context *ctx, const char *string ) {
141 static const char colon = ':';
142
143 /* Add (possibly colon-separated) field to MD5 digest */
144 if ( ctx->len )
145 digest_update ( &md5_algorithm, ctx, &colon, sizeof ( colon ) );
146 digest_update ( &md5_algorithm, ctx, string, strlen ( string ) );
147}
148
149/**
150 * Finalise HTTP Digest
151 *
152 * @v ctx Digest context
153 * @v out Buffer for digest output
154 * @v len Buffer length
155 */
156static void http_digest_final ( struct md5_context *ctx, char *out,
157 size_t len ) {
158 uint8_t digest[MD5_DIGEST_SIZE];
159
160 /* Finalise and base16-encode MD5 digest */
161 digest_final ( &md5_algorithm, ctx, digest );
162 base16_encode ( digest, sizeof ( digest ), out, len );
163}
164
165/**
166 * Perform HTTP Digest authentication
167 *
168 * @v http HTTP transaction
169 * @ret rc Return status code
170 */
171static int http_digest_authenticate ( struct http_transaction *http ) {
172 struct http_request_auth_digest *req = &http->request.auth.digest;
174 char ha1[ base16_encoded_len ( MD5_DIGEST_SIZE ) + 1 /* NUL */ ];
175 char ha2[ base16_encoded_len ( MD5_DIGEST_SIZE ) + 1 /* NUL */ ];
176 static const char md5sess[] = "MD5-sess";
177 static const char md5[] = "MD5";
178 struct md5_context ctx;
179 const char *password;
180
181 /* Check for required response parameters */
182 if ( ! rsp->realm ) {
183 DBGC ( http, "HTTP %p has no realm for Digest authentication\n",
184 http );
185 return -EINVAL;
186 }
187 if ( ! rsp->nonce ) {
188 DBGC ( http, "HTTP %p has no nonce for Digest authentication\n",
189 http );
190 return -EINVAL;
191 }
192
193 /* Record username and password */
194 if ( ! http->uri->user ) {
195 DBGC ( http, "HTTP %p has no username for Digest "
196 "authentication\n", http );
197 return -EACCES_USERNAME;
198 }
199 req->username = http->uri->user;
200 password = ( http->uri->password ? http->uri->password : "" );
201
202 /* Handle quality of protection */
203 if ( rsp->qop ) {
204
205 /* Use "auth" in subsequent request */
206 req->qop = "auth";
207
208 /* Generate a client nonce */
209 snprintf ( req->cnonce, sizeof ( req->cnonce ),
210 "%08lx", random() );
211
212 /* Determine algorithm */
213 req->algorithm = md5;
214 if ( rsp->algorithm &&
215 ( strcasecmp ( rsp->algorithm, md5sess ) == 0 ) ) {
216 req->algorithm = md5sess;
217 }
218 }
219
220 /* Generate HA1 */
223 http_digest_update ( &ctx, rsp->realm );
225 http_digest_final ( &ctx, ha1, sizeof ( ha1 ) );
226 if ( req->algorithm == md5sess ) {
228 http_digest_update ( &ctx, ha1 );
229 http_digest_update ( &ctx, rsp->nonce );
230 http_digest_update ( &ctx, req->cnonce );
231 http_digest_final ( &ctx, ha1, sizeof ( ha1 ) );
232 }
233
234 /* Generate HA2 */
237 http_digest_update ( &ctx, http->request.uri );
238 http_digest_final ( &ctx, ha2, sizeof ( ha2 ) );
239
240 /* Generate response */
242 http_digest_update ( &ctx, ha1 );
243 http_digest_update ( &ctx, rsp->nonce );
244 if ( req->qop ) {
246 http_digest_update ( &ctx, req->cnonce );
247 http_digest_update ( &ctx, req->qop );
248 }
249 http_digest_update ( &ctx, ha2 );
250 http_digest_final ( &ctx, req->response, sizeof ( req->response ) );
251
252 return 0;
253}
254
255/**
256 * Construct HTTP "Authorization" header for Digest authentication
257 *
258 * @v http HTTP transaction
259 * @v buf Buffer
260 * @v len Length of buffer
261 * @ret len Length of header value, or negative error
262 */
264 char *buf, size_t len ) {
265 struct http_request_auth_digest *req = &http->request.auth.digest;
267 size_t used = 0;
268
269 /* Sanity checks */
270 assert ( rsp->realm != NULL );
271 assert ( rsp->nonce != NULL );
272 assert ( req->username != NULL );
273 if ( req->qop ) {
274 assert ( req->algorithm != NULL );
275 assert ( req->cnonce[0] != '\0' );
276 }
277 assert ( req->response[0] != '\0' );
278
279 /* Construct response */
280 used += ssnprintf ( ( buf + used ), ( len - used ),
281 "realm=\"%s\", nonce=\"%s\", uri=\"%s\", "
282 "username=\"%s\"", rsp->realm, rsp->nonce,
283 http->request.uri, req->username );
284 if ( rsp->opaque ) {
285 used += ssnprintf ( ( buf + used ), ( len - used ),
286 ", opaque=\"%s\"", rsp->opaque );
287 }
288 if ( req->qop ) {
289 used += ssnprintf ( ( buf + used ), ( len - used ),
290 ", qop=%s, algorithm=%s, cnonce=\"%s\", "
291 "nc=" HTTP_DIGEST_NC, req->qop,
292 req->algorithm, req->cnonce );
293 }
294 used += ssnprintf ( ( buf + used ), ( len - used ),
295 ", response=\"%s\"", req->response );
296
297 return used;
298}
299
300/** HTTP Digest authentication scheme */
302 .name = "Digest",
303 .parse = http_parse_digest_auth,
304 .authenticate = http_digest_authenticate,
305 .format = http_format_digest_auth,
306};
307
308/* Drag in HTTP authentication support */
309REQUIRING_SYMBOL ( http_digest_auth );
310REQUIRE_OBJECT ( httpauth );
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
union @162305117151260234136356364136041353210355154177 key
Sense key.
Definition scsi.h:3
struct golan_eq_context ctx
Definition CIB_PRM.h:0
__be32 out[4]
Definition CIB_PRM.h:8
pseudo_bit_t value[0x00020]
Definition arbel.h:2
unsigned char uint8_t
Definition stdint.h:10
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
Base16 encoding.
static size_t base16_encoded_len(size_t raw_len)
Calculate length of base16-encoded data.
Definition base16.h:25
ring len
Length.
Definition dwmac.h:226
Error codes.
#define DBGC(...)
Definition compiler.h:505
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define REQUIRE_OBJECT(object)
Require an object.
Definition compiler.h:202
#define EINVAL
Invalid argument.
Definition errno.h:429
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
#define REQUIRING_SYMBOL(symbol)
Specify the file's requiring symbol.
Definition compiler.h:140
Hyper Text Transport Protocol.
#define HTTP_DIGEST_NC
HTTP Digest authentication client nonce count.
Definition http.h:120
@ HTTP_RESPONSE_RETRY
Transaction may be retried on failure.
Definition http.h:361
#define __http_authentication
Declare an HTTP authentication scheme.
Definition http.h:551
#define EACCES_USERNAME
Definition httpbasic.c:41
char * http_token(char **line, char **value)
Get HTTP response token.
Definition httpcore.c:196
static void http_digest_update(struct md5_context *ctx, const char *string)
Update HTTP Digest with new data.
Definition httpdigest.c:140
static void http_digest_init(struct md5_context *ctx)
Initialise HTTP Digest.
Definition httpdigest.c:128
static void http_digest_final(struct md5_context *ctx, char *out, size_t len)
Finalise HTTP Digest.
Definition httpdigest.c:156
static struct http_digest_field http_digest_fields[]
HTTP Digest "WWW-Authenticate" fields.
Definition httpdigest.c:81
static int http_format_digest_auth(struct http_transaction *http, char *buf, size_t len)
Construct HTTP "Authorization" header for Digest authentication.
Definition httpdigest.c:263
static void http_digest_field(struct http_transaction *http, struct http_digest_field *field, char *value)
Set HTTP Digest "WWW-Authenticate" response field value.
Definition httpdigest.c:72
static int http_digest_authenticate(struct http_transaction *http)
Perform HTTP Digest authentication.
Definition httpdigest.c:171
#define HTTP_DIGEST_FIELD(_name)
Define an HTTP Digest "WWW-Authenticate" response field.
Definition httpdigest.c:58
static int http_parse_digest_auth(struct http_transaction *http, char *line)
Parse HTTP "WWW-Authenticate" header for Digest authentication.
Definition httpdigest.c:96
u16 algorithm
Authentication algorithm (Open System or Shared Key)
Definition ieee80211.h:1
static void digest_init(struct digest_algorithm *digest, void *ctx)
Definition crypto.h:219
static void digest_final(struct digest_algorithm *digest, void *ctx, void *out)
Definition crypto.h:230
static void digest_update(struct digest_algorithm *digest, void *ctx, const void *data, size_t len)
Definition crypto.h:224
String functions.
uint64_t rsp
Definition librm.h:18
static struct dynamic_item password
Definition login_ui.c:37
struct digest_algorithm md5_algorithm
MD5 algorithm.
Definition md5.c:287
MD5 algorithm.
#define MD5_DIGEST_SIZE
MD5 digest size.
Definition md5.h:73
long int random(void)
Generate a pseudo-random number between 0 and 2147483647L or 2147483562?
Definition random.c:32
int strcasecmp(const char *first, const char *second)
Compare case-insensitive strings.
Definition string.c:209
size_t strlen(const char *src)
Get length of string.
Definition string.c:244
An HTTP authentication scheme.
Definition http.h:519
An HTTP Digest "WWW-Authenticate" response field.
Definition httpdigest.c:50
const char * name
Name.
Definition httpdigest.c:52
size_t offset
Offset.
Definition httpdigest.c:54
const char * name
Method name (e.g.
Definition http.h:102
HTTP request Digest authentication descriptor.
Definition http.h:162
char cnonce[HTTP_DIGEST_CNONCE_LEN+1]
Client nonce.
Definition http.h:170
const char * qop
Quality of protection.
Definition http.h:166
char response[HTTP_DIGEST_RESPONSE_LEN+1]
Response.
Definition http.h:172
const char * algorithm
Algorithm.
Definition http.h:168
const char * username
Username.
Definition http.h:164
struct http_authentication * auth
Authentication scheme (if any)
Definition http.h:190
struct http_request_auth_digest digest
Digest authentication descriptor.
Definition http.h:196
struct http_request_auth auth
Authentication descriptor.
Definition http.h:223
struct http_method * method
Method.
Definition http.h:213
const char * uri
Request URI string.
Definition http.h:215
HTTP response Digest authorization descriptor.
Definition http.h:274
struct http_response_auth_digest digest
Digest authorization descriptor.
Definition http.h:304
unsigned int flags
Flags.
Definition http.h:351
struct http_response_auth auth
Authorization descriptor.
Definition http.h:347
An HTTP transaction.
Definition http.h:416
struct http_response response
Response.
Definition http.h:439
struct uri * uri
Request URI.
Definition http.h:435
struct http_request request
Request.
Definition http.h:437
An MD5 context.
Definition md5.h:59
const char * user
User name.
Definition uri.h:73
const char * password
Password.
Definition uri.h:75
Uniform Resource Identifiers.
int ssnprintf(char *buf, ssize_t ssize, const char *fmt,...)
Version of vsnprintf() that accepts a signed buffer size.
Definition vsprintf.c:421
int snprintf(char *buf, size_t size, const char *fmt,...)
Write a formatted string to a buffer.
Definition vsprintf.c:383
printf() and friends
u8 nonce[32]
Nonce value.
Definition wpa.h:25