NTLMSSP auth / sign / seal blob-exchanging

Luke Kenneth Casson Leighton lkcl at samba-tng.org
Wed Oct 17 18:02:03 GMT 2001


hi there andrew b., nice to see you on dcerpc.net.
drop an ssh identity.pub in the Public Key field
if you'd like to help out directly with the ntsecapi,
btw.

regarding the ntsecapi - ntl,ssp development
(http://dcerpc.net/cvs, module ntsecapi), i now have
8 or so functions:

/* server-side */

int ntlmssp_auth_gen(ntlmssp_sec_state_p_t l,
			char *auth_info, size_t *auth_info_len);

int ntlmssp_bind_auth_resp(ntlmssp_sec_state_p_t l,
				char *data, size_t data_len);

/* client _and_ server-side */

int ntlmssp_auth_init(ntlmssp_sec_state_p_t l,
				unsigned char **server_princ_name);

int ntlmssp_sign_seal(ntlmssp_sec_state_p_t l, 
				char *data, size_t data_len,
				char *auth_data, size_t auth_data_len);

int ntlmssp_unsign_unseal(ntlmssp_sec_state_p_t l,
				char *data, size_t data_len,
				char *auth_data, size_t auth_len);

/* client-side */

int ntlmssp_create_bind_req(ntlmssp_sec_state_p_t l,
				unsigned char *server_princ_name,
				struct ntuser_creds *usr,
				char *auth_req_data, size_t *auth_req_len);

int ntlmssp_create_bind_cont(ntlmssp_sec_state_p_t l,
				unsigned char *server_princ_name,
				struct ntuser_creds *usr,
				char *auth_resp_data, size_t *auth_resp_len);

int ntlmssp_decode_bind_resp(ntlmssp_sec_state_p_t l,
				char *auth_data, size_t auth_data_len);


now, the create_bind_req, bind_auth_resp and create_bind_cont
are the "NTLMSSP\0\1...", "NTLMSSP\0\2...", and "NTLMSSP\0\3..."
"blobs" that you see on-wire in DCE/RPC and also in
CAP_EXTENDED_SECURITY when you use SPNEGO to negotiate NTLM auth.

they are decoded with RPC_NTLMSSP_AUTH_NEG, CHAL and RESP
structures.

they are used in srv_pipe_ntlmssp.c, cli_pipe_ntlmssp.c and
also in libsmb/clientgen.c directly in the 4-hour-hacked-up
CAP_EXTENDED_SECURITY blobbing i worked on absolutely ages
ago.

the point is, that these three functions should not be in
the ntlmssp_api, they should be in the ntlmssp_auth_api.


basically, what i think the implementation of check_domain_security()
should be is:

status_t check_domain_security(user, domain, chal, lm_resp, nt_resp,
	NET_USERINFO_3 **usr3)
{
	/* as implemented in rpc_ntlmssp.h in head and TNG */
	RPC_NTLMSSP_AUTH_NEG neg;
	RPC_NTLMSSP_AUTH_CHAL chal;
	RPC_NTLMSSP_AUTH_RESP resp;

	/* ntlmssp_auth.h */
	ntlmssp_auth_state_t auth_state;

	prs_struct negp;
	prs_struct chalp;
	prs_struct respp;

	neg.sig = "NTLMSSP\0\1";
	neg.domain = domain;
	neg.wksta = global_myname;
	neg.flags = 0xb3b2;

	/* as implemented in parse_ntlmssp.c in head and TNG */
	rpc_io_ntlmssp_auth_neg(&negp, neg.sig);

	chal.sig = "NTLMSSP\0\2";
	chal.challenge = chal;
	chal.flags = 0x82b1;

	/* as implemented in parse_ntlmssp.c in head and TNG */
	rpc_io_ntlmssp_auth_chal(&chalp, chal.sig);

	resp.sig = "NTLMSSP\0\3";
	resp.user = user;
	resp.domain = domain;
	resp.wksta = global_myname;
	resp.lm_resp = lm_resp;
	resp.nt_resp = nt_resp;

	/* as implemented in parse_ntlmssp.c in head and TNG */
	rpc_io_ntlmssp_auth_resp(&respp, resp.sig);
	
	/* as implemented in ntlmssp_auth API */
	return ntlmssp_auth_blob(&auth_state, negp, usr3)
	&&     ntlmssp_auth_blob(&auth_state, chalp, usr3)
	&&     ntlmssp_auth_blob(&auth_state, respp, usr3);
}

this is actually very close to what is already in smbencrypt.c
except less formal.

implementing CAP_EXTENDED_SECURITY is then _incredibly_ simple:
just do the last _three_ lines of the above function!

that's really, really all there is to it.

the implementation of ntlmssp_auth_blob will look at
the first 9 bytes, check that the first 8 are "NTLMSSP"
and decide what to do based on the 9th, which is what
happens in rpc_srv_ntlmssp.c's ntlmssp_verify() _anyway_.

basically, inside ntlmssp_auth_blob is this:

if (strncmp(blob, "NTLMSSP", 9) != 0)
	return False;

switch blob[8]:
{
	case 1: return decode_client_request_blob();
	case 2: return decode_server_challenge_blob();
	case 3: return decode_client_response_blob();
	default: return False;
};

you could then, having decoded the blobs and stored
the decoded information in the auth_state (which
is what i do in rpc_srv_ntlmssp.c and what smbd does
in global variables, yukk - see get_client_challenge())
and _then_ call what is now the existing check_server_security()
function.



i think it may actually be sensible to treat the usr3
also as a (void*, size_t) blob, and, for simplicity,
to return the user_session_key and the first 8 bytes
of the LM# in a _separate_ (void*, size_t) blob
because i'll be damned if i'm going to add
NET_USERINFO_3 decoding to the bleeding ntsecapi
codebase just to unpack a darn session key and other
info unless someone _really_ twists my arm :)

so, basically, right, from a "generic" point of view,
the NET_USERINFO_3 structure is "user credentials",
i.e. username, uid, groups, profile etc., and the
user_session_key+LM#[0..7] is ... ummm...

i don't actually know the technical name for it!
user session credentials ?

luke




More information about the samba-technical mailing list