iPXE
Functions | Variables
ntlm.c File Reference

NT LAN Manager (NTLM) authentication. More...

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <byteswap.h>
#include <ipxe/md4.h>
#include <ipxe/md5.h>
#include <ipxe/hmac.h>
#include <ipxe/ntlm.h>

Go to the source code of this file.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
int ntlm_challenge (struct ntlm_challenge *challenge, size_t len, struct ntlm_challenge_info *info)
 Parse NTLM Challenge.
void ntlm_key (const char *domain, const char *username, const char *password, struct ntlm_key *key)
 Calculate NTLM verification key.
void ntlm_response (struct ntlm_challenge_info *info, struct ntlm_key *key, struct ntlm_nonce *nonce, struct ntlm_lm_response *lm, struct ntlm_nt_response *nt)
 Construct NTLM responses.
static void * ntlm_append (struct ntlm_header *header, struct ntlm_data *data, void *payload, size_t len)
 Append data to NTLM message.
static void * ntlm_append_string (struct ntlm_header *header, struct ntlm_data *data, void *payload, const char *string)
 Append Unicode string data to NTLM message.
size_t ntlm_authenticate (struct ntlm_challenge_info *info, const char *domain, const char *username, const char *workstation, struct ntlm_lm_response *lm, struct ntlm_nt_response *nt, struct ntlm_authenticate *auth)
 Construct NTLM Authenticate message.
size_t ntlm_authenticate_len (struct ntlm_challenge_info *info, const char *domain, const char *username, const char *workstation)
 Calculate NTLM Authenticate message length.

Variables

struct ntlm_negotiate ntlm_negotiate
 Negotiate message.

Detailed Description

NT LAN Manager (NTLM) authentication.

Definition in file ntlm.c.


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
int ntlm_challenge ( struct ntlm_challenge challenge,
size_t  len,
struct ntlm_challenge_info info 
)

Parse NTLM Challenge.

Parameters:
challengeChallenge message
lenLength of Challenge message
infoChallenge information to fill in
Return values:
rcReturn status code

Definition at line 68 of file ntlm.c.

References DBGC, DBGC_HDA, EINVAL, ntlm_challenge::info, le16_to_cpu, le32_to_cpu, ntlm_data::len, ntlm_challenge_info::len, ntlm_challenge::nonce, ntlm_challenge_info::nonce, ntlm_data::offset, offset, and ntlm_challenge_info::target.

                                                        {
        size_t offset;

        DBGC ( challenge, "NTLM challenge message:\n" );
        DBGC_HDA ( challenge, 0, challenge, len );

        /* Sanity checks */
        if ( len < sizeof ( *challenge ) ) {
                DBGC ( challenge, "NTLM underlength challenge (%zd bytes)\n",
                       len );
                return -EINVAL;
        }

        /* Extract nonce */
        info->nonce = &challenge->nonce;
        DBGC ( challenge, "NTLM challenge nonce:\n" );
        DBGC_HDA ( challenge, 0, info->nonce, sizeof ( *info->nonce ) );

        /* Extract target information */
        info->len = le16_to_cpu ( challenge->info.len );
        offset = le32_to_cpu ( challenge->info.offset );
        if ( ( offset > len ) ||
             ( info->len > ( len - offset ) ) ) {
                DBGC ( challenge, "NTLM target information outside "
                       "challenge\n" );
                DBGC_HDA ( challenge, 0, challenge, len );
                return -EINVAL;
        }
        info->target = ( ( ( void * ) challenge ) + offset );
        DBGC ( challenge, "NTLM challenge target information:\n" );
        DBGC_HDA ( challenge, 0, info->target, info->len );

        return 0;
}
void ntlm_key ( const char *  domain,
const char *  username,
const char *  password,
struct ntlm_key key 
)

Calculate NTLM verification key.

Parameters:
domainDomain name (or NULL)
usernameUser name (or NULL)
passwordPassword (or NULL)
keyKey to fill in

This is the NTOWFv2() function as defined in MS-NLMP.

Definition at line 114 of file ntlm.c.

References cpu_to_le16, ctx, DBGC, DBGC_HDA, digest, digest_final(), digest_init(), digest_update(), hmac_final(), hmac_init(), hmac_update(), md4_algorithm, MD4_CTX_SIZE, MD4_DIGEST_SIZE, md5_algorithm, MD5_CTX_SIZE, ntlm_key::raw, toupper(), and wc.

Referenced by http_ntlm_authenticate(), ntlm_authenticate_okx(), and ntlm_key_okx().

                                                             {
        struct digest_algorithm *md4 = &md4_algorithm;
        struct digest_algorithm *md5 = &md5_algorithm;
        union {
                uint8_t md4[MD4_CTX_SIZE];
                uint8_t md5[MD5_CTX_SIZE];
        } ctx;
        uint8_t digest[MD4_DIGEST_SIZE];
        size_t digest_len;
        uint8_t c;
        uint16_t wc;

        /* Use empty usernames/passwords if not specified */
        if ( ! domain )
                domain = "";
        if ( ! username )
                username = "";
        if ( ! password )
                password = "";

        /* Construct MD4 digest of (Unicode) password */
        digest_init ( md4, ctx.md4 );
        while ( ( c = *(password++) ) ) {
                wc = cpu_to_le16 ( c );
                digest_update ( md4, ctx.md4, &wc, sizeof ( wc ) );
        }
        digest_final ( md4, ctx.md4, digest );

        /* Construct HMAC-MD5 of (Unicode) upper-case username */
        digest_len = sizeof ( digest );
        hmac_init ( md5, ctx.md5, digest, &digest_len );
        while ( ( c = *(username++) ) ) {
                wc = cpu_to_le16 ( toupper ( c ) );
                hmac_update ( md5, ctx.md5, &wc, sizeof ( wc ) );
        }
        while ( ( c = *(domain++) ) ) {
                wc = cpu_to_le16 ( c );
                hmac_update ( md5, ctx.md5, &wc, sizeof ( wc ) );
        }
        hmac_final ( md5, ctx.md5, digest, &digest_len, key->raw );
        DBGC ( key, "NTLM key:\n" );
        DBGC_HDA ( key, 0, key, sizeof ( *key ) );
}
void ntlm_response ( struct ntlm_challenge_info info,
struct ntlm_key key,
struct ntlm_nonce nonce,
struct ntlm_lm_response lm,
struct ntlm_nt_response nt 
)

Construct NTLM responses.

Parameters:
infoChallenge information
keyVerification key
nonceNonce, or NULL to use a random nonce
lmLAN Manager response to fill in
ntNT response to fill in

Definition at line 168 of file ntlm.c.

References ctx, DBGC, DBGC_HDA, ntlm_lm_response::digest, ntlm_nt_response::digest, ntlm_nt_response::high, hmac_final(), hmac_init(), hmac_update(), ntlm_challenge_info::len, md5_algorithm, MD5_CTX_SIZE, memcpy(), memset(), ntlm_lm_response::nonce, ntlm_nt_response::nonce, ntlm_challenge_info::nonce, NTLM_VERSION_NTLMV2, offsetof, random(), ntlm_nonce::raw, ntlm_key::raw, ntlm_challenge_info::target, ntlm_nt_response::version, version, and ntlm_nt_response::zero.

Referenced by http_ntlm_authenticate(), and ntlm_authenticate_okx().

                                                   {
        struct digest_algorithm *md5 = &md5_algorithm;
        struct ntlm_nonce tmp_nonce;
        uint8_t ctx[MD5_CTX_SIZE];
        size_t key_len = sizeof ( *key );
        unsigned int i;

        /* Generate random nonce, if needed */
        if ( ! nonce ) {
                for ( i = 0 ; i < sizeof ( tmp_nonce ) ; i++ )
                        tmp_nonce.raw[i] = random();
                nonce = &tmp_nonce;
        }

        /* Construct LAN Manager response */
        memcpy ( &lm->nonce, nonce, sizeof ( lm->nonce ) );
        hmac_init ( md5, ctx, key->raw, &key_len );
        hmac_update ( md5, ctx, info->nonce, sizeof ( *info->nonce ) );
        hmac_update ( md5, ctx, &lm->nonce, sizeof ( lm->nonce ) );
        hmac_final ( md5, ctx, key->raw, &key_len, lm->digest );
        DBGC ( key, "NTLM LAN Manager response:\n" );
        DBGC_HDA ( key, 0, lm, sizeof ( *lm ) );

        /* Construct NT response */
        memset ( nt, 0, sizeof ( *nt ) );
        nt->version = NTLM_VERSION_NTLMV2;
        nt->high = NTLM_VERSION_NTLMV2;
        memcpy ( &nt->nonce, nonce, sizeof ( nt->nonce ) );
        hmac_init ( md5, ctx, key->raw, &key_len );
        hmac_update ( md5, ctx, info->nonce, sizeof ( *info->nonce ) );
        hmac_update ( md5, ctx, &nt->version,
                      ( sizeof ( *nt ) -
                        offsetof ( typeof ( *nt ), version ) ) );
        hmac_update ( md5, ctx, info->target, info->len );
        hmac_update ( md5, ctx, &nt->zero, sizeof ( nt->zero ) );
        hmac_final ( md5, ctx, key->raw, &key_len, nt->digest );
        DBGC ( key, "NTLM NT response prefix:\n" );
        DBGC_HDA ( key, 0, nt, sizeof ( *nt ) );
}
static void* ntlm_append ( struct ntlm_header header,
struct ntlm_data data,
void *  payload,
size_t  len 
) [static]

Append data to NTLM message.

Parameters:
headerMessage header, or NULL to only calculate next payload
dataData descriptor
payloadData payload
lenLength of data
Return values:
payloadNext data payload

Definition at line 219 of file ntlm.c.

References cpu_to_le16, cpu_to_le32, ntlm_data::len, ntlm_data::max_len, and ntlm_data::offset.

Referenced by ntlm_append_string(), and ntlm_authenticate().

                                                        {

        /* Populate data descriptor */
        if ( header ) {
                data->offset = cpu_to_le32 ( payload - ( ( void * ) header ) );
                data->len = data->max_len = cpu_to_le16 ( len );
        }

        return ( payload + len );
}
static void* ntlm_append_string ( struct ntlm_header header,
struct ntlm_data data,
void *  payload,
const char *  string 
) [static]

Append Unicode string data to NTLM message.

Parameters:
headerMessage header, or NULL to only calculate next payload
dataData descriptor
payloadData payload
stringString to append, or NULL
Return values:
payloadNext data payload

Definition at line 240 of file ntlm.c.

References cpu_to_le16, and ntlm_append().

Referenced by ntlm_authenticate().

                                                        {
        uint16_t *tmp = payload;
        uint8_t c;

        /* Convert string to Unicode */
        for ( tmp = payload ; ( string && ( c = *(string++) ) ) ; tmp++ ) {
                if ( header )
                        *tmp = cpu_to_le16 ( c );
        }

        /* Append string data */
        return ntlm_append ( header, data, payload,
                             ( ( ( void * ) tmp ) - payload ) );
}
size_t ntlm_authenticate ( struct ntlm_challenge_info info,
const char *  domain,
const char *  username,
const char *  workstation,
struct ntlm_lm_response lm,
struct ntlm_nt_response nt,
struct ntlm_authenticate auth 
)

Construct NTLM Authenticate message.

Parameters:
infoChallenge information
domainDomain name, or NULL
usernameUser name, or NULL
workstationWorkstation name, or NULL
lmLAN Manager response
ntNT response
authMessage to fill in, or NULL to only calculate length
Return values:
lenLength of message

Definition at line 269 of file ntlm.c.

References cpu_to_le32, DBGC, DBGC_HDA, ntlm_authenticate::domain, ntlm_negotiate::flags, ntlm_authenticate::flags, ntlm_negotiate::header, ntlm_authenticate::header, ntlm_challenge_info::len, len, ntlm_authenticate::lm, ntlm_header::magic, memcpy(), memset(), ntlm_authenticate::nt, ntlm_append(), ntlm_append_string(), NTLM_AUTHENTICATE, ntlm_challenge_info::target, ntlm_header::type, ntlm_authenticate::user, ntlm_authenticate::workstation, and ntlm_nt_response::zero.

Referenced by http_format_ntlm_auth(), and ntlm_authenticate_len().

                                                            {
        void *tmp;
        size_t nt_len;
        size_t len;

        /* Construct response header */
        if ( auth ) {
                memset ( auth, 0, sizeof ( *auth ) );
                memcpy ( auth->header.magic, ntlm_negotiate.header.magic,
                         sizeof ( auth->header.magic ) );
                auth->header.type = cpu_to_le32 ( NTLM_AUTHENTICATE );
                auth->flags = ntlm_negotiate.flags;
        }
        tmp = ( ( ( void * ) auth ) + sizeof ( *auth ) );

        /* Construct LAN Manager response */
        if ( auth )
                memcpy ( tmp, lm, sizeof ( *lm ) );
        tmp = ntlm_append ( &auth->header, &auth->lm, tmp, sizeof ( *lm ) );

        /* Construct NT response */
        nt_len = ( sizeof ( *nt ) + info->len + sizeof ( nt->zero ) );
        if ( auth ) {
                memcpy ( tmp, nt, sizeof ( *nt ) );
                memcpy ( ( tmp + sizeof ( *nt ) ), info->target, info->len );
                memset ( ( tmp + sizeof ( *nt ) + info->len ), 0,
                         sizeof ( nt->zero ) );
        }
        tmp = ntlm_append ( &auth->header, &auth->nt, tmp, nt_len );

        /* Populate domain, user, and workstation names */
        tmp = ntlm_append_string ( &auth->header, &auth->domain, tmp, domain );
        tmp = ntlm_append_string ( &auth->header, &auth->user, tmp, username );
        tmp = ntlm_append_string ( &auth->header, &auth->workstation, tmp,
                                   workstation );

        /* Calculate length */
        len = ( tmp - ( ( void * ) auth ) );
        if ( auth ) {
                DBGC ( auth, "NTLM authenticate message:\n" );
                DBGC_HDA ( auth, 0, auth, len );
        }

        return len;
}
size_t ntlm_authenticate_len ( struct ntlm_challenge_info info,
const char *  domain,
const char *  username,
const char *  workstation 
)

Calculate NTLM Authenticate message length.

Parameters:
infoChallenge information
domainDomain name, or NULL
usernameUser name, or NULL
workstationWorkstation name, or NULL
Return values:
lenLength of Authenticate message

Definition at line 328 of file ntlm.c.

References ntlm_authenticate(), and NULL.

Referenced by http_ntlm_authenticate(), and ntlm_authenticate_okx().

                                                         {

        return ntlm_authenticate ( info, domain, username, workstation,
                                   NULL, NULL, NULL );
}

Variable Documentation

Initial value:

Negotiate message.

This message content is fixed since there is no need to specify the calling workstation name or domain name, and the set of flags is mandated by the MS-NLMP specification.

Definition at line 48 of file ntlm.c.