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 algorithm context */
51 /** MD5 context */
53 /** Length of colon field separator before next field */
54 size_t colon_len;
55};
56
57/** An HTTP Digest "WWW-Authenticate" response field */
59 /** Name */
60 const char *name;
61 /** Offset */
62 size_t offset;
63};
64
65/** Define an HTTP Digest "WWW-Authenticate" response field */
66#define HTTP_DIGEST_FIELD( _name ) { \
67 .name = #_name, \
68 .offset = offsetof ( struct http_transaction, \
69 response.auth.digest._name ), \
70 }
71
72/**
73 * Set HTTP Digest "WWW-Authenticate" response field value
74 *
75 * @v http HTTP transaction
76 * @v field Response field
77 * @v value Field value
78 */
79static inline void
81 struct http_digest_field *field, char *value ) {
82 char **ptr;
83
84 ptr = ( ( ( void * ) http ) + field->offset );
85 *ptr = value;
86}
87
88/** HTTP Digest "WWW-Authenticate" fields */
96
97/**
98 * Parse HTTP "WWW-Authenticate" header for Digest authentication
99 *
100 * @v http HTTP transaction
101 * @v line Remaining header line
102 * @ret rc Return status code
103 */
104static int http_parse_digest_auth ( struct http_transaction *http,
105 char *line ) {
106 struct http_digest_field *field;
107 char *key;
108 char *value;
109 unsigned int i;
110
111 /* Process fields */
112 while ( ( key = http_token ( &line, &value ) ) ) {
113 for ( i = 0 ; i < ( sizeof ( http_digest_fields ) /
114 sizeof ( http_digest_fields[0] ) ) ; i++){
115 field = &http_digest_fields[i];
116 if ( strcasecmp ( key, field->name ) == 0 )
117 http_digest_field ( http, field, value );
118 }
119 }
120
121 /* Allow HTTP request to be retried if the request had not
122 * already tried authentication.
123 */
124 if ( ! http->request.auth.auth )
126
127 return 0;
128}
129
130/**
131 * Initialise HTTP Digest
132 *
133 * @v ctx Digest context
134 * @v string Initial string
135 */
136static void http_digest_init ( struct http_digest_context *ctx ) {
137
138 /* Initialise MD5 digest */
139 digest_init ( &md5_algorithm, ctx->md5 );
140
141 /* Omit colon before first field */
142 ctx->colon_len = 0;
143}
144
145/**
146 * Update HTTP Digest with new data
147 *
148 * @v ctx Digest context
149 * @v string String to append
150 */
152 const char *string ) {
153 static const char colon = ':';
154
155 /* Add (possibly colon-separated) field to MD5 digest */
156 digest_update ( &md5_algorithm, ctx->md5, &colon, ctx->colon_len );
157 digest_update ( &md5_algorithm, ctx->md5, string, strlen ( string ) );
158
159 /* Include colon before any subsequent fields */
160 ctx->colon_len = sizeof ( colon );
161}
162
163/**
164 * Finalise HTTP Digest
165 *
166 * @v ctx Digest context
167 * @v out Buffer for digest output
168 * @v len Buffer length
169 */
170static void http_digest_final ( struct http_digest_context *ctx, char *out,
171 size_t len ) {
172 uint8_t digest[MD5_DIGEST_SIZE];
173
174 /* Finalise and base16-encode MD5 digest */
175 digest_final ( &md5_algorithm, ctx->md5, digest );
176 base16_encode ( digest, sizeof ( digest ), out, len );
177}
178
179/**
180 * Perform HTTP Digest authentication
181 *
182 * @v http HTTP transaction
183 * @ret rc Return status code
184 */
185static int http_digest_authenticate ( struct http_transaction *http ) {
186 struct http_request_auth_digest *req = &http->request.auth.digest;
188 char ha1[ base16_encoded_len ( MD5_DIGEST_SIZE ) + 1 /* NUL */ ];
189 char ha2[ base16_encoded_len ( MD5_DIGEST_SIZE ) + 1 /* NUL */ ];
190 static const char md5sess[] = "MD5-sess";
191 static const char md5[] = "MD5";
193 const char *password;
194
195 /* Check for required response parameters */
196 if ( ! rsp->realm ) {
197 DBGC ( http, "HTTP %p has no realm for Digest authentication\n",
198 http );
199 return -EINVAL;
200 }
201 if ( ! rsp->nonce ) {
202 DBGC ( http, "HTTP %p has no nonce for Digest authentication\n",
203 http );
204 return -EINVAL;
205 }
206
207 /* Record username and password */
208 if ( ! http->uri->user ) {
209 DBGC ( http, "HTTP %p has no username for Digest "
210 "authentication\n", http );
211 return -EACCES_USERNAME;
212 }
213 req->username = http->uri->user;
214 password = ( http->uri->password ? http->uri->password : "" );
215
216 /* Handle quality of protection */
217 if ( rsp->qop ) {
218
219 /* Use "auth" in subsequent request */
220 req->qop = "auth";
221
222 /* Generate a client nonce */
223 snprintf ( req->cnonce, sizeof ( req->cnonce ),
224 "%08lx", random() );
225
226 /* Determine algorithm */
227 req->algorithm = md5;
228 if ( rsp->algorithm &&
229 ( strcasecmp ( rsp->algorithm, md5sess ) == 0 ) ) {
230 req->algorithm = md5sess;
231 }
232 }
233
234 /* Generate HA1 */
237 http_digest_update ( &ctx, rsp->realm );
239 http_digest_final ( &ctx, ha1, sizeof ( ha1 ) );
240 if ( req->algorithm == md5sess ) {
242 http_digest_update ( &ctx, ha1 );
243 http_digest_update ( &ctx, rsp->nonce );
244 http_digest_update ( &ctx, req->cnonce );
245 http_digest_final ( &ctx, ha1, sizeof ( ha1 ) );
246 }
247
248 /* Generate HA2 */
251 http_digest_update ( &ctx, http->request.uri );
252 http_digest_final ( &ctx, ha2, sizeof ( ha2 ) );
253
254 /* Generate response */
256 http_digest_update ( &ctx, ha1 );
257 http_digest_update ( &ctx, rsp->nonce );
258 if ( req->qop ) {
260 http_digest_update ( &ctx, req->cnonce );
261 http_digest_update ( &ctx, req->qop );
262 }
263 http_digest_update ( &ctx, ha2 );
264 http_digest_final ( &ctx, req->response, sizeof ( req->response ) );
265
266 return 0;
267}
268
269/**
270 * Construct HTTP "Authorization" header for Digest authentication
271 *
272 * @v http HTTP transaction
273 * @v buf Buffer
274 * @v len Length of buffer
275 * @ret len Length of header value, or negative error
276 */
278 char *buf, size_t len ) {
279 struct http_request_auth_digest *req = &http->request.auth.digest;
281 size_t used = 0;
282
283 /* Sanity checks */
284 assert ( rsp->realm != NULL );
285 assert ( rsp->nonce != NULL );
286 assert ( req->username != NULL );
287 if ( req->qop ) {
288 assert ( req->algorithm != NULL );
289 assert ( req->cnonce[0] != '\0' );
290 }
291 assert ( req->response[0] != '\0' );
292
293 /* Construct response */
294 used += ssnprintf ( ( buf + used ), ( len - used ),
295 "realm=\"%s\", nonce=\"%s\", uri=\"%s\", "
296 "username=\"%s\"", rsp->realm, rsp->nonce,
297 http->request.uri, req->username );
298 if ( rsp->opaque ) {
299 used += ssnprintf ( ( buf + used ), ( len - used ),
300 ", opaque=\"%s\"", rsp->opaque );
301 }
302 if ( req->qop ) {
303 used += ssnprintf ( ( buf + used ), ( len - used ),
304 ", qop=%s, algorithm=%s, cnonce=\"%s\", "
305 "nc=" HTTP_DIGEST_NC, req->qop,
306 req->algorithm, req->cnonce );
307 }
308 used += ssnprintf ( ( buf + used ), ( len - used ),
309 ", response=\"%s\"", req->response );
310
311 return used;
312}
313
314/** HTTP Digest authentication scheme */
316 .name = "Digest",
317 .parse = http_parse_digest_auth,
318 .authenticate = http_digest_authenticate,
319 .format = http_format_digest_auth,
320};
321
322/* Drag in HTTP authentication support */
323REQUIRING_SYMBOL ( http_digest_auth );
324REQUIRE_OBJECT ( httpauth );
#define NULL
NULL pointer (VOID *).
Definition Base.h:321
struct golan_eq_context ctx
Definition CIB_PRM.h:0
__be32 out[4]
Definition CIB_PRM.h:8
union @162305117151260234136356364136041353210355154177 key
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:530
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:921
#define REQUIRE_OBJECT(object)
Require an object.
Definition compiler.h:227
#define EINVAL
Invalid argument.
Definition errno.h:429
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:951
#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:127
@ HTTP_RESPONSE_RETRY
Transaction may be retried on failure.
Definition http.h:368
#define __http_authentication
Declare an HTTP authentication scheme.
Definition http.h:558
#define EACCES_USERNAME
Definition httpbasic.c:41
char * http_token(char **line, char **value)
Get HTTP response token.
Definition httpcore.c:219
static void http_digest_init(struct http_digest_context *ctx)
Initialise HTTP Digest.
Definition httpdigest.c:136
static struct http_digest_field http_digest_fields[]
HTTP Digest "WWW-Authenticate" fields.
Definition httpdigest.c:89
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:277
static void http_digest_update(struct http_digest_context *ctx, const char *string)
Update HTTP Digest with new data.
Definition httpdigest.c:151
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:80
static int http_digest_authenticate(struct http_transaction *http)
Perform HTTP Digest authentication.
Definition httpdigest.c:185
#define HTTP_DIGEST_FIELD(_name)
Define an HTTP Digest "WWW-Authenticate" response field.
Definition httpdigest.c:66
static void http_digest_final(struct http_digest_context *ctx, char *out, size_t len)
Finalise HTTP Digest.
Definition httpdigest.c:170
static int http_parse_digest_auth(struct http_transaction *http, char *line)
Parse HTTP "WWW-Authenticate" header for Digest authentication.
Definition httpdigest.c:104
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:294
static void digest_final(struct digest_algorithm *digest, void *ctx, void *out)
Definition crypto.h:305
static void digest_update(struct digest_algorithm *digest, void *ctx, const void *data, size_t len)
Definition crypto.h:299
String functions.
uint64_t rsp
Definition librm.h:18
static struct dynamic_item password
Definition login_ui.c:37
MD5 algorithm.
#define MD5_CTX_SIZE
MD5 context size.
Definition md5.h:51
struct digest_algorithm md5_algorithm
#define MD5_DIGEST_SIZE
MD5 digest size.
Definition md5.h:57
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:526
An HTTP Digest algorithm context.
Definition httpdigest.c:50
size_t colon_len
Length of colon field separator before next field.
Definition httpdigest.c:54
uint8_t md5[MD5_CTX_SIZE]
MD5 context.
Definition httpdigest.c:52
An HTTP Digest "WWW-Authenticate" response field.
Definition httpdigest.c:58
const char * name
Name.
Definition httpdigest.c:60
size_t offset
Offset.
Definition httpdigest.c:62
const char * name
Method name (e.g.
Definition http.h:102
HTTP request Digest authentication descriptor.
Definition http.h:169
char cnonce[HTTP_DIGEST_CNONCE_LEN+1]
Client nonce.
Definition http.h:177
const char * qop
Quality of protection.
Definition http.h:173
char response[HTTP_DIGEST_RESPONSE_LEN+1]
Response.
Definition http.h:179
const char * algorithm
Algorithm.
Definition http.h:175
const char * username
Username.
Definition http.h:171
struct http_authentication * auth
Authentication scheme (if any).
Definition http.h:197
struct http_request_auth_digest digest
Digest authentication descriptor.
Definition http.h:203
struct http_request_auth auth
Authentication descriptor.
Definition http.h:230
struct http_method * method
Method.
Definition http.h:220
const char * uri
Request URI string.
Definition http.h:222
HTTP response Digest authorization descriptor.
Definition http.h:281
struct http_response_auth_digest digest
Digest authorization descriptor.
Definition http.h:311
unsigned int flags
Flags.
Definition http.h:358
struct http_response_auth auth
Authorization descriptor.
Definition http.h:354
An HTTP transaction.
Definition http.h:423
struct http_response response
Response.
Definition http.h:446
struct uri * uri
Request URI.
Definition http.h:442
struct http_request request
Request.
Definition http.h:444
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