예제 #1
0
/*
  unseal a packet
*/
NTSTATUS schannel_unseal_packet(struct gensec_security *gensec_security, 
				TALLOC_CTX *mem_ctx, 
				uint8_t *data, size_t length, 
				const uint8_t *whole_pdu, size_t pdu_length, 
				const DATA_BLOB *sig)
{
	struct schannel_state *state = talloc_get_type(gensec_security->private_data, struct schannel_state);
	
	uint8_t digest_final[16];
	uint8_t confounder[8];
	uint8_t seq_num[8];
	uint8_t sealing_key[16];
	static const uint8_t netsec_sig[8] = NETSEC_SEAL_SIGNATURE;

	if (sig->length != 32) {
		return NT_STATUS_ACCESS_DENIED;
	}

	memcpy(confounder, sig->data+24, 8);

	RSIVAL(seq_num, 0, state->seq_num);
	SIVAL(seq_num, 4, state->initiator?0:0x80);

	netsec_get_sealing_key(state->creds->session_key, seq_num, sealing_key);
	arcfour_crypt(confounder, sealing_key, 8);
	arcfour_crypt(data, sealing_key, length);

	schannel_digest(state->creds->session_key, 
			netsec_sig, confounder, 
			data, length, digest_final);

	if (memcmp(digest_final, sig->data+16, 8) != 0) {
		dump_data_pw("calc digest:", digest_final, 8);
		dump_data_pw("wire digest:", sig->data+16, 8);
		return NT_STATUS_ACCESS_DENIED;
	}

	netsec_deal_with_seq_num(state, digest_final, seq_num);

	if (memcmp(seq_num, sig->data+8, 8) != 0) {
		dump_data_pw("calc seq num:", seq_num, 8);
		dump_data_pw("wire seq num:", sig->data+8, 8);
		return NT_STATUS_ACCESS_DENIED;
	}

	return NT_STATUS_OK;
}
예제 #2
0
/*
  seal a packet
*/
NTSTATUS schannel_seal_packet(struct gensec_security *gensec_security, 
			      TALLOC_CTX *mem_ctx, 
			      uint8_t *data, size_t length, 
			      const uint8_t *whole_pdu, size_t pdu_length, 
			      DATA_BLOB *sig)
{
	struct schannel_state *state = talloc_get_type(gensec_security->private_data, struct schannel_state);

	uint8_t digest_final[16];
	uint8_t confounder[8];
	uint8_t seq_num[8];
	uint8_t sealing_key[16];
	static const uint8_t netsec_sig[8] = NETSEC_SEAL_SIGNATURE;

	generate_random_buffer(confounder, 8);

	RSIVAL(seq_num, 0, state->seq_num);
	SIVAL(seq_num, 4, state->initiator?0x80:0);

	schannel_digest(state->creds->session_key, 
			netsec_sig, confounder, 
			data, length, digest_final);

	netsec_get_sealing_key(state->creds->session_key, seq_num, sealing_key);
	arcfour_crypt(confounder, sealing_key, 8);
	arcfour_crypt(data, sealing_key, length);

	netsec_deal_with_seq_num(state, digest_final, seq_num);

	(*sig) = data_blob_talloc(mem_ctx, NULL, 32);

	memcpy(sig->data, netsec_sig, 8);
	memcpy(sig->data+8, seq_num, 8);
	memcpy(sig->data+16, digest_final, 8);
	memcpy(sig->data+24, confounder, 8);

	dump_data_pw("signature:", sig->data+ 0, 8);
	dump_data_pw("seq_num  :", sig->data+ 8, 8);
	dump_data_pw("digest   :", sig->data+16, 8);
	dump_data_pw("confound :", sig->data+24, 8);

	return NT_STATUS_OK;
}
예제 #3
0
BOOL netsec_decode(struct netsec_auth_struct *a, int auth_flags,
		   enum netsec_direction direction, 
		   RPC_AUTH_NETSEC_CHK * verf, char *data, size_t data_len)
{
	uchar digest_final[16];

	static const uchar netsec_seal_sig[8] = NETSEC_SEAL_SIGNATURE;
	static const uchar netsec_sign_sig[8] = NETSEC_SIGN_SIGNATURE;
	const uchar *netsec_sig = NULL;

	uchar seq_num[8];

	DEBUG(10,("SCHANNEL: netsec_encode seq_num=%d data_len=%lu\n", a->seq_num, (unsigned long)data_len));
	
	if (auth_flags & AUTH_PIPE_SEAL) {
		netsec_sig = netsec_seal_sig;
	} else if (auth_flags & AUTH_PIPE_SIGN) {
		netsec_sig = netsec_sign_sig;
	}

	/* Create the expected sequence number for comparison */
	RSIVAL(seq_num, 0, a->seq_num);

	switch (direction) {
	case SENDER_IS_INITIATOR:
		SIVAL(seq_num, 4, 0x80);
		break;
	case SENDER_IS_ACCEPTOR:
		SIVAL(seq_num, 4, 0x0);
		break;
	}

	DEBUG(10,("SCHANNEL: netsec_decode seq_num=%d data_len=%lu\n", a->seq_num, (unsigned long)data_len));
	dump_data_pw("a->sess_key:\n", a->sess_key, sizeof(a->sess_key));

	dump_data_pw("seq_num:\n", seq_num, sizeof(seq_num));

	/* extract the sequence number (key based on supplied packet digest) */
	/* needs to be done before the sealing, as the original version 
	   is used in the sealing stuff... */
	netsec_deal_with_seq_num(a, verf);

	if (memcmp(verf->seq_num, seq_num, sizeof(seq_num))) {
		/* don't even bother with the below if the sequence number is out */
		/* The sequence number is MD5'ed with a key based on the whole-packet
		   digest, as supplied by the client.  We check that it's a valid 
		   checksum after the decode, below
		*/
		DEBUG(2, ("netsec_decode: FAILED: packet sequence number:\n"));
		dump_data(2, (const char*)verf->seq_num, sizeof(verf->seq_num));
		DEBUG(2, ("should be:\n"));
		dump_data(2, (const char*)seq_num, sizeof(seq_num));

		return False;
	}

	if (memcmp(verf->sig, netsec_sig, sizeof(verf->sig))) {
		/* Validate that the other end sent the expected header */
		DEBUG(2, ("netsec_decode: FAILED: packet header:\n"));
		dump_data(2, (const char*)verf->sig, sizeof(verf->sig));
		DEBUG(2, ("should be:\n"));
		dump_data(2, (const char*)netsec_sig, sizeof(netsec_sig));
		return False;
	}

	if (auth_flags & AUTH_PIPE_SEAL) {
		uchar sealing_key[16];
		
		/* get the key to extract the data with */
		netsec_get_sealing_key(a, verf, sealing_key);

		/* extract the verification data */
		dump_data_pw("verf->confounder:\n", verf->confounder, 
			     sizeof(verf->confounder));
		SamOEMhash(verf->confounder, sealing_key, 8);

		dump_data_pw("verf->confounder_dec:\n", verf->confounder, 
			     sizeof(verf->confounder));
		
		/* extract the packet payload */
		dump_data_pw("data   :\n", (const unsigned char *)data, data_len);
		SamOEMhash((unsigned char *)data, sealing_key, data_len);
		dump_data_pw("datadec:\n", (const unsigned char *)data, data_len);	
	}

	/* digest includes 'data' after unsealing */
	netsec_digest(a, auth_flags, verf, data, data_len, digest_final);

	dump_data_pw("Calculated digest:\n", digest_final, 
		     sizeof(digest_final));
	dump_data_pw("verf->packet_digest:\n", verf->packet_digest, 
		     sizeof(verf->packet_digest));
	
	/* compare - if the client got the same result as us, then
	   it must know the session key */
	return (memcmp(digest_final, verf->packet_digest, 
		       sizeof(verf->packet_digest)) == 0);
}
예제 #4
0
/*******************************************************************
 Encode a blob of data using the netsec (schannel) alogrithm, also produceing
 a checksum over the original data.  We currently only support
 signing and sealing togeather - the signing-only code is close, but not
 quite compatible with what MS does.
 ********************************************************************/
void netsec_encode(struct netsec_auth_struct *a, int auth_flags, 
		   enum netsec_direction direction,
		   RPC_AUTH_NETSEC_CHK * verf,
		   char *data, size_t data_len)
{
	uchar digest_final[16];
	uchar confounder[8];
	uchar seq_num[8];
	static const uchar nullbytes[8];

	static const uchar netsec_seal_sig[8] = NETSEC_SEAL_SIGNATURE;
	static const uchar netsec_sign_sig[8] = NETSEC_SIGN_SIGNATURE;
	const uchar *netsec_sig = NULL;

	DEBUG(10,("SCHANNEL: netsec_encode seq_num=%d data_len=%lu\n", a->seq_num, (unsigned long)data_len));
	
	if (auth_flags & AUTH_PIPE_SEAL) {
		netsec_sig = netsec_seal_sig;
	} else if (auth_flags & AUTH_PIPE_SIGN) {
		netsec_sig = netsec_sign_sig;
	}

	/* fill the 'confounder' with random data */
	generate_random_buffer(confounder, sizeof(confounder), False);

	dump_data_pw("a->sess_key:\n", a->sess_key, sizeof(a->sess_key));

	RSIVAL(seq_num, 0, a->seq_num);

	switch (direction) {
	case SENDER_IS_INITIATOR:
		SIVAL(seq_num, 4, 0x80);
		break;
	case SENDER_IS_ACCEPTOR:
		SIVAL(seq_num, 4, 0x0);
		break;
	}

	dump_data_pw("verf->seq_num:\n", seq_num, sizeof(verf->seq_num));

	init_rpc_auth_netsec_chk(verf, netsec_sig, nullbytes,
				 seq_num, confounder);
				
	/* produce a digest of the packet to prove it's legit (before we seal it) */
	netsec_digest(a, auth_flags, verf, data, data_len, digest_final);
	memcpy(verf->packet_digest, digest_final, sizeof(verf->packet_digest));

	if (auth_flags & AUTH_PIPE_SEAL) {
		uchar sealing_key[16];

		/* get the key to encode the data with */
		netsec_get_sealing_key(a, verf, sealing_key);

		/* encode the verification data */
		dump_data_pw("verf->confounder:\n", verf->confounder, sizeof(verf->confounder));
		SamOEMhash(verf->confounder, sealing_key, 8);

		dump_data_pw("verf->confounder_enc:\n", verf->confounder, sizeof(verf->confounder));
		
		/* encode the packet payload */
		dump_data_pw("data:\n", (const unsigned char *)data, data_len);
		SamOEMhash((unsigned char *)data, sealing_key, data_len);
		dump_data_pw("data_enc:\n", (const unsigned char *)data, data_len);
	}

	/* encode the sequence number (key based on packet digest) */
	/* needs to be done after the sealing, as the original version 
	   is used in the sealing stuff... */
	netsec_deal_with_seq_num(a, verf);

	return;
}