iPXE
Data Structures | Defines | Functions | Variables
httpdigest.c File Reference

Hyper Text Transfer Protocol (HTTP) Digest authentication. More...

#include <stdio.h>
#include <errno.h>
#include <strings.h>
#include <ipxe/uri.h>
#include <ipxe/md5.h>
#include <ipxe/base16.h>
#include <ipxe/vsprintf.h>
#include <ipxe/http.h>

Go to the source code of this file.

Data Structures

struct  http_digest_field
 An HTTP Digest "WWW-Authenticate" response field. More...

Defines

#define EACCES_USERNAME   __einfo_error ( EINFO_EACCES_USERNAME )
#define EINFO_EACCES_USERNAME
#define HTTP_DIGEST_FIELD(_name)
 Define an HTTP Digest "WWW-Authenticate" response field.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static void http_digest_field (struct http_transaction *http, struct http_digest_field *field, char *value)
 Set HTTP Digest "WWW-Authenticate" response field value.
static int http_parse_digest_auth (struct http_transaction *http, char *line)
 Parse HTTP "WWW-Authenticate" header for Digest authentication.
static void http_digest_init (struct md5_context *ctx)
 Initialise HTTP Digest.
static void http_digest_update (struct md5_context *ctx, const char *string)
 Update HTTP Digest with new data.
static void http_digest_final (struct md5_context *ctx, char *out, size_t len)
 Finalise HTTP Digest.
static int http_digest_authenticate (struct http_transaction *http)
 Perform HTTP Digest authentication.
static int http_format_digest_auth (struct http_transaction *http, char *buf, size_t len)
 Construct HTTP "Authorization" header for Digest authentication.
 REQUIRING_SYMBOL (http_digest_auth)
 REQUIRE_OBJECT (httpauth)

Variables

static struct http_digest_field http_digest_fields []
 HTTP Digest "WWW-Authenticate" fields.
struct http_authentication
http_digest_auth 
__http_authentication
 HTTP Digest authentication scheme.

Detailed Description

Hyper Text Transfer Protocol (HTTP) Digest authentication.

Definition in file httpdigest.c.


Define Documentation

Definition at line 43 of file httpdigest.c.

Referenced by http_digest_authenticate().

Value:
__einfo_uniqify ( EINFO_EACCES, 0x01,                           \
                          "No username available for Digest authentication" )

Definition at line 44 of file httpdigest.c.

#define HTTP_DIGEST_FIELD (   _name)
Value:
{                                       \
                .name = #_name,                                         \
                .offset = offsetof ( struct http_transaction,           \
                                     response.auth.digest._name ),      \
        }

Define an HTTP Digest "WWW-Authenticate" response field.

Definition at line 57 of file httpdigest.c.


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
static void http_digest_field ( struct http_transaction http,
struct http_digest_field field,
char *  value 
) [inline, static]

Set HTTP Digest "WWW-Authenticate" response field value.

Parameters:
httpHTTP transaction
fieldResponse field
valueField value

Definition at line 71 of file httpdigest.c.

References http_digest_field::offset, and value.

                                                                   {
        char **ptr;

        ptr = ( ( ( void * ) http ) + field->offset );
        *ptr = value;
}
static int http_parse_digest_auth ( struct http_transaction http,
char *  line 
) [static]

Parse HTTP "WWW-Authenticate" header for Digest authentication.

Parameters:
httpHTTP transaction
lineRemaining header line
Return values:
rcReturn status code

Definition at line 95 of file httpdigest.c.

References http_request_auth::auth, http_request::auth, http_response::flags, http_digest_fields, HTTP_RESPONSE_RETRY, http_token(), key, http_digest_field::name, http_transaction::request, http_transaction::response, strcasecmp(), and value.

                                                 {
        struct http_digest_field *field;
        char *key;
        char *value;
        unsigned int i;

        /* Process fields */
        while ( ( key = http_token ( &line, &value ) ) ) {
                for ( i = 0 ; i < ( sizeof ( http_digest_fields ) /
                                    sizeof ( http_digest_fields[0] ) ) ; i++){
                        field = &http_digest_fields[i];
                        if ( strcasecmp ( key, field->name ) == 0 )
                                http_digest_field ( http, field, value );
                }
        }

        /* Allow HTTP request to be retried if the request had not
         * already tried authentication.
         */
        if ( ! http->request.auth.auth )
                http->response.flags |= HTTP_RESPONSE_RETRY;

        return 0;
}
static void http_digest_init ( struct md5_context ctx) [static]

Initialise HTTP Digest.

Parameters:
ctxDigest context
stringInitial string

Definition at line 127 of file httpdigest.c.

References digest_init(), and md5_algorithm.

Referenced by http_digest_authenticate().

                                                         {

        /* Initialise MD5 digest */
        digest_init ( &md5_algorithm, ctx );
}
static void http_digest_update ( struct md5_context ctx,
const char *  string 
) [static]

Update HTTP Digest with new data.

Parameters:
ctxDigest context
stringString to append

Definition at line 139 of file httpdigest.c.

References digest_update(), md5_context::len, md5_algorithm, and strlen().

Referenced by http_digest_authenticate().

                                                                               {
        static const char colon = ':';

        /* Add (possibly colon-separated) field to MD5 digest */
        if ( ctx->len )
                digest_update ( &md5_algorithm, ctx, &colon, sizeof ( colon ) );
        digest_update ( &md5_algorithm, ctx, string, strlen ( string ) );
}
static void http_digest_final ( struct md5_context ctx,
char *  out,
size_t  len 
) [static]

Finalise HTTP Digest.

Parameters:
ctxDigest context
outBuffer for digest output
lenBuffer length

Definition at line 155 of file httpdigest.c.

References digest, digest_final(), md5_algorithm, and MD5_DIGEST_SIZE.

Referenced by http_digest_authenticate().

                                             {
        uint8_t digest[MD5_DIGEST_SIZE];

        /* Finalise and base16-encode MD5 digest */
        digest_final ( &md5_algorithm, ctx, digest );
        base16_encode ( digest, sizeof ( digest ), out, len );
}
static int http_digest_authenticate ( struct http_transaction http) [static]

Perform HTTP Digest authentication.

Parameters:
httpHTTP transaction
Return values:
rcReturn status code

Definition at line 170 of file httpdigest.c.

References http_request_auth_digest::algorithm, http_response_auth_digest::algorithm, http_request::auth, http_response::auth, base16_encoded_len(), http_request_auth_digest::cnonce, DBGC, http_request_auth::digest, http_response_auth::digest, EACCES_USERNAME, EINVAL, http_digest_final(), http_digest_init(), HTTP_DIGEST_NC, http_digest_update(), MD5_DIGEST_SIZE, http_request::method, http_method::name, http_response_auth_digest::nonce, uri::password, http_request_auth_digest::qop, http_response_auth_digest::qop, random(), http_response_auth_digest::realm, http_transaction::request, http_request_auth_digest::response, http_transaction::response, rsp, snprintf(), strcasecmp(), http_request::uri, http_transaction::uri, uri::user, and http_request_auth_digest::username.

                                                                      {
        struct http_request_auth_digest *req = &http->request.auth.digest;
        struct http_response_auth_digest *rsp = &http->response.auth.digest;
        char ha1[ base16_encoded_len ( MD5_DIGEST_SIZE ) + 1 /* NUL */ ];
        char ha2[ base16_encoded_len ( MD5_DIGEST_SIZE ) + 1 /* NUL */ ];
        static const char md5sess[] = "MD5-sess";
        static const char md5[] = "MD5";
        struct md5_context ctx;
        const char *password;

        /* Check for required response parameters */
        if ( ! rsp->realm ) {
                DBGC ( http, "HTTP %p has no realm for Digest authentication\n",
                       http );
                return -EINVAL;
        }
        if ( ! rsp->nonce ) {
                DBGC ( http, "HTTP %p has no nonce for Digest authentication\n",
                       http );
                return -EINVAL;
        }

        /* Record username and password */
        if ( ! http->uri->user ) {
                DBGC ( http, "HTTP %p has no username for Digest "
                       "authentication\n", http );
                return -EACCES_USERNAME;
        }
        req->username = http->uri->user;
        password = ( http->uri->password ? http->uri->password : "" );

        /* Handle quality of protection */
        if ( rsp->qop ) {

                /* Use "auth" in subsequent request */
                req->qop = "auth";

                /* Generate a client nonce */
                snprintf ( req->cnonce, sizeof ( req->cnonce ),
                           "%08lx", random() );

                /* Determine algorithm */
                req->algorithm = md5;
                if ( rsp->algorithm &&
                     ( strcasecmp ( rsp->algorithm, md5sess ) == 0 ) ) {
                        req->algorithm = md5sess;
                }
        }

        /* Generate HA1 */
        http_digest_init ( &ctx );
        http_digest_update ( &ctx, req->username );
        http_digest_update ( &ctx, rsp->realm );
        http_digest_update ( &ctx, password );
        http_digest_final ( &ctx, ha1, sizeof ( ha1 ) );
        if ( req->algorithm == md5sess ) {
                http_digest_init ( &ctx );
                http_digest_update ( &ctx, ha1 );
                http_digest_update ( &ctx, rsp->nonce );
                http_digest_update ( &ctx, req->cnonce );
                http_digest_final ( &ctx, ha1, sizeof ( ha1 ) );
        }

        /* Generate HA2 */
        http_digest_init ( &ctx );
        http_digest_update ( &ctx, http->request.method->name );
        http_digest_update ( &ctx, http->request.uri );
        http_digest_final ( &ctx, ha2, sizeof ( ha2 ) );

        /* Generate response */
        http_digest_init ( &ctx );
        http_digest_update ( &ctx, ha1 );
        http_digest_update ( &ctx, rsp->nonce );
        if ( req->qop ) {
                http_digest_update ( &ctx, HTTP_DIGEST_NC );
                http_digest_update ( &ctx, req->cnonce );
                http_digest_update ( &ctx, req->qop );
        }
        http_digest_update ( &ctx, ha2 );
        http_digest_final ( &ctx, req->response, sizeof ( req->response ) );

        return 0;
}
static int http_format_digest_auth ( struct http_transaction http,
char *  buf,
size_t  len 
) [static]

Construct HTTP "Authorization" header for Digest authentication.

Parameters:
httpHTTP transaction
bufBuffer
lenLength of buffer
Return values:
lenLength of header value, or negative error

Definition at line 262 of file httpdigest.c.

References http_request_auth_digest::algorithm, assert, http_request::auth, http_response::auth, http_request_auth_digest::cnonce, http_request_auth::digest, http_response_auth::digest, HTTP_DIGEST_NC, http_response_auth_digest::nonce, NULL, http_response_auth_digest::opaque, http_request_auth_digest::qop, http_response_auth_digest::realm, http_transaction::request, http_request_auth_digest::response, http_transaction::response, rsp, ssnprintf(), http_request::uri, and http_request_auth_digest::username.

                                                             {
        struct http_request_auth_digest *req = &http->request.auth.digest;
        struct http_response_auth_digest *rsp = &http->response.auth.digest;
        size_t used = 0;

        /* Sanity checks */
        assert ( rsp->realm != NULL );
        assert ( rsp->nonce != NULL );
        assert ( req->username != NULL );
        if ( req->qop ) {
                assert ( req->algorithm != NULL );
                assert ( req->cnonce[0] != '\0' );
        }
        assert ( req->response[0] != '\0' );

        /* Construct response */
        used += ssnprintf ( ( buf + used ), ( len - used ),
                            "realm=\"%s\", nonce=\"%s\", uri=\"%s\", "
                            "username=\"%s\"", rsp->realm, rsp->nonce,
                            http->request.uri, req->username );
        if ( rsp->opaque ) {
                used += ssnprintf ( ( buf + used ), ( len - used ),
                                    ", opaque=\"%s\"", rsp->opaque );
        }
        if ( req->qop ) {
                used += ssnprintf ( ( buf + used ), ( len - used ),
                                    ", qop=%s, algorithm=%s, cnonce=\"%s\", "
                                    "nc=" HTTP_DIGEST_NC, req->qop,
                                    req->algorithm, req->cnonce );
        }
        used += ssnprintf ( ( buf + used ), ( len - used ),
                            ", response=\"%s\"", req->response );

        return used;
}
REQUIRING_SYMBOL ( http_digest_auth  )
REQUIRE_OBJECT ( httpauth  )

Variable Documentation

Initial value:

HTTP Digest "WWW-Authenticate" fields.

Definition at line 80 of file httpdigest.c.

Referenced by http_parse_digest_auth().

struct http_authentication http_digest_auth __http_authentication
Initial value:
 {
        .name = "Digest",
        .parse = http_parse_digest_auth,
        .authenticate = http_digest_authenticate,
        .format = http_format_digest_auth,
}

HTTP Digest authentication scheme.

Definition at line 300 of file httpdigest.c.