Blame src/plugins/lanplus/lanplus_crypt.c

Packit d14fb6
/*
Packit d14fb6
 * Copyright (c) 2003 Sun Microsystems, Inc.  All Rights Reserved.
Packit d14fb6
 * 
Packit d14fb6
 * Redistribution and use in source and binary forms, with or without
Packit d14fb6
 * modification, are permitted provided that the following conditions
Packit d14fb6
 * are met:
Packit d14fb6
 * 
Packit d14fb6
 * Redistribution of source code must retain the above copyright
Packit d14fb6
 * notice, this list of conditions and the following disclaimer.
Packit d14fb6
 * 
Packit d14fb6
 * Redistribution in binary form must reproduce the above copyright
Packit d14fb6
 * notice, this list of conditions and the following disclaimer in the
Packit d14fb6
 * documentation and/or other materials provided with the distribution.
Packit d14fb6
 * 
Packit d14fb6
 * Neither the name of Sun Microsystems, Inc. or the names of
Packit d14fb6
 * contributors may be used to endorse or promote products derived
Packit d14fb6
 * from this software without specific prior written permission.
Packit d14fb6
 * 
Packit d14fb6
 * This software is provided "AS IS," without a warranty of any kind.
Packit d14fb6
 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
Packit d14fb6
 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
Packit d14fb6
 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
Packit d14fb6
 * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
Packit d14fb6
 * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
Packit d14fb6
 * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.  IN NO EVENT WILL
Packit d14fb6
 * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
Packit d14fb6
 * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
Packit d14fb6
 * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
Packit d14fb6
 * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
Packit d14fb6
 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
Packit d14fb6
 */
Packit d14fb6
Packit d14fb6
#include <assert.h>
Packit d14fb6
#include <string.h>
Packit d14fb6
#if defined(HAVE_CONFIG_H)
Packit d14fb6
# include <config.h>
Packit d14fb6
#endif
Packit d14fb6
#include <ipmitool/bswap.h>
Packit d14fb6
#include <ipmitool/log.h>
Packit d14fb6
#include "lanplus.h"
Packit d14fb6
#include "lanplus_crypt.h"
Packit d14fb6
#include "lanplus_crypt_impl.h"
Packit d14fb6
Packit d14fb6
Packit d14fb6
Packit d14fb6
/*
Packit d14fb6
 * lanplus_rakp2_hmac_matches
Packit d14fb6
 * 
Packit d14fb6
 * param session holds all the state data that we need to generate the hmac
Packit d14fb6
 * param hmac is the HMAC sent by the BMC in the RAKP 2 message
Packit d14fb6
 *
Packit d14fb6
 * The HMAC was generated [per RFC2404] from : 
Packit d14fb6
 * 
Packit d14fb6
 *     SIDm     - Remote console session ID    
Packit d14fb6
 *     SIDc     - BMC session ID
Packit d14fb6
 *     Rm       - Remote console random number
Packit d14fb6
 *     Rc       - BMC random number
Packit d14fb6
 *     GUIDc    - BMC guid
Packit d14fb6
 *     ROLEm    - Requested privilege level (entire byte)
Packit d14fb6
 *     ULENGTHm - Username length
Packit d14fb6
 *     <UNAMEm> - Username (absent for null user names)
Packit d14fb6
 *
Packit d14fb6
 * generated by using Kuid.  I am aware that the subscripts on the values
Packit d14fb6
 * look backwards, but that's the way they are written in the specification.
Packit d14fb6
 *
Packit d14fb6
 * If the authentication algorithm is IPMI_AUTH_RAKP_NONE, we return success.
Packit d14fb6
 * 
Packit d14fb6
 * return 0 on success (the authcode matches)
Packit d14fb6
 *        1 on failure (the authcode does not match)
Packit d14fb6
 */
Packit d14fb6
int
Packit d14fb6
lanplus_rakp2_hmac_matches(const struct ipmi_session * session,
Packit d14fb6
		const uint8_t * bmc_mac, struct ipmi_intf * intf)
Packit d14fb6
{
Packit d14fb6
	uint8_t       * buffer;
Packit d14fb6
	int           bufferLength, i;
Packit d14fb6
	uint8_t       mac[IPMI_MAX_MD_SIZE];
Packit d14fb6
	uint32_t      macLength;
Packit d14fb6
Packit d14fb6
	uint32_t SIDm_lsbf, SIDc_lsbf;
Packit d14fb6
Packit d14fb6
Packit d14fb6
	if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE)
Packit d14fb6
		return 1;
Packit d14fb6
	
Packit d14fb6
	/* We don't yet support other algorithms */
Packit d14fb6
	assert((session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA1)
Packit d14fb6
		|| (session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_MD5)
Packit d14fb6
#ifdef HAVE_CRYPTO_SHA256
Packit d14fb6
		|| (session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA256)
Packit d14fb6
#endif /* HAVE_CRYPTO_SHA256 */
Packit d14fb6
	);
Packit d14fb6
	
Packit d14fb6
Packit d14fb6
	bufferLength =
Packit d14fb6
		4  +                       /* SIDm     */
Packit d14fb6
		4  +                       /* SIDc     */
Packit d14fb6
		16 +                       /* Rm       */
Packit d14fb6
		16 +                       /* Rc       */
Packit d14fb6
		16 +                       /* GUIDc    */
Packit d14fb6
		1  +                       /* ROLEm    */
Packit d14fb6
		1  +                       /* ULENGTHm */
Packit d14fb6
		strlen((const char *)intf->ssn_params.username); /* optional */
Packit d14fb6
Packit d14fb6
	buffer = malloc(bufferLength);
Packit d14fb6
	if (buffer == NULL) {
Packit d14fb6
		lprintf(LOG_ERR, "ipmitool: malloc failure");
Packit d14fb6
		return 1;
Packit d14fb6
	}
Packit d14fb6
Packit d14fb6
	/*
Packit d14fb6
	 * Fill the buffer.  I'm assuming that we're using the LSBF representation of the
Packit d14fb6
	 * multibyte numbers in use.
Packit d14fb6
	 */
Packit d14fb6
Packit d14fb6
	/* SIDm */
Packit d14fb6
	SIDm_lsbf = session->v2_data.console_id;
Packit d14fb6
	#if WORDS_BIGENDIAN
Packit d14fb6
	SIDm_lsbf = BSWAP_32(SIDm_lsbf);
Packit d14fb6
	#endif
Packit d14fb6
Packit d14fb6
	memcpy(buffer, &SIDm_lsbf, 4);
Packit d14fb6
Packit d14fb6
	/* SIDc */
Packit d14fb6
	SIDc_lsbf = session->v2_data.bmc_id;
Packit d14fb6
	#if WORDS_BIGENDIAN
Packit d14fb6
	SIDc_lsbf = BSWAP_32(SIDc_lsbf);
Packit d14fb6
	#endif
Packit d14fb6
	memcpy(buffer + 4, &SIDc_lsbf, 4);
Packit d14fb6
Packit d14fb6
	/* Rm */
Packit d14fb6
	#if WORDS_BIGENDIAN
Packit d14fb6
	for (i = 0; i < 16; ++i)
Packit d14fb6
		buffer[8 + i] = session->v2_data.console_rand[16 - 1 - i];
Packit d14fb6
	#else
Packit d14fb6
	for (i = 0; i < 16; ++i)
Packit d14fb6
		buffer[8 + i] = session->v2_data.console_rand[i];
Packit d14fb6
	#endif
Packit d14fb6
Packit d14fb6
	/* Rc */
Packit d14fb6
	#if WORDS_BIGENDIAN
Packit d14fb6
	for (i = 0; i < 16; ++i)
Packit d14fb6
		buffer[24 + i] = session->v2_data.bmc_rand[16 - 1 - i];
Packit d14fb6
	#else
Packit d14fb6
	for (i = 0; i < 16; ++i)
Packit d14fb6
		buffer[24 + i] = session->v2_data.bmc_rand[i];
Packit d14fb6
	#endif
Packit d14fb6
Packit d14fb6
	/* GUIDc */
Packit d14fb6
	#if WORDS_BIGENDIAN
Packit d14fb6
	for (i = 0; i < 16; ++i)
Packit d14fb6
		buffer[40 + i] = session->v2_data.bmc_guid[16 - 1 - i];
Packit d14fb6
	#else
Packit d14fb6
	for (i = 0; i < 16; ++i)
Packit d14fb6
		buffer[40 + i] = session->v2_data.bmc_guid[i];
Packit d14fb6
	#endif
Packit d14fb6
Packit d14fb6
	/* ROLEm */
Packit d14fb6
	buffer[56] = session->v2_data.requested_role;
Packit d14fb6
Packit d14fb6
	if (ipmi_oem_active(intf, "i82571spt")) {
Packit d14fb6
		/*
Packit d14fb6
		 * The HMAC calculation code in the Intel 82571 GbE
Packit d14fb6
		 * skips this bit!  Looks like a GbE bug, but we need
Packit d14fb6
		 * to work around it here anyway...
Packit d14fb6
		 */
Packit d14fb6
		buffer[56] &= ~0x10;
Packit d14fb6
	}
Packit d14fb6
Packit d14fb6
	/* ULENGTHm */
Packit d14fb6
	buffer[57] = strlen((const char *)intf->ssn_params.username);
Packit d14fb6
Packit d14fb6
	/* UserName [optional] */
Packit d14fb6
	for (i = 0; i < buffer[57]; ++i)
Packit d14fb6
		buffer[58 + i] = intf->ssn_params.username[i];
Packit d14fb6
Packit d14fb6
	if (verbose > 2)
Packit d14fb6
	{
Packit d14fb6
		printbuf((const uint8_t *)buffer, bufferLength, ">> rakp2 mac input buffer");
Packit d14fb6
		printbuf((const uint8_t *)session->authcode, IPMI_AUTHCODE_BUFFER_SIZE, ">> rakp2 mac key");
Packit d14fb6
	}
Packit d14fb6
Packit d14fb6
	/*
Packit d14fb6
	 * The buffer is complete.  Let's hash.
Packit d14fb6
	 */
Packit d14fb6
	lanplus_HMAC(session->v2_data.auth_alg,
Packit d14fb6
				 session->authcode,
Packit d14fb6
				 IPMI_AUTHCODE_BUFFER_SIZE,
Packit d14fb6
				 buffer,
Packit d14fb6
				 bufferLength,
Packit d14fb6
				 mac,
Packit d14fb6
				 &macLength);
Packit d14fb6
Packit d14fb6
	free(buffer);
Packit d14fb6
	buffer = NULL;
Packit d14fb6
Packit d14fb6
Packit d14fb6
	if (verbose > 2)
Packit d14fb6
	{
Packit d14fb6
		printbuf(mac, macLength, ">> rakp2 mac as computed by the remote console");
Packit d14fb6
	}
Packit d14fb6
Packit d14fb6
	return (memcmp(bmc_mac, mac, macLength) == 0);
Packit d14fb6
}
Packit d14fb6
Packit d14fb6
Packit d14fb6
Packit d14fb6
/*
Packit d14fb6
 * lanplus_rakp4_hmac_matches
Packit d14fb6
 * 
Packit d14fb6
 * param session holds all the state data that we need to generate the hmac
Packit d14fb6
 * param hmac is the HMAC sent by the BMC in the RAKP 4 message
Packit d14fb6
 *
Packit d14fb6
 * The HMAC was generated [per RFC2404] from : 
Packit d14fb6
 * 
Packit d14fb6
 *     Rm       - Remote console random number
Packit d14fb6
 *     SIDc     - BMC session ID
Packit d14fb6
 *     GUIDc    - BMC guid
Packit d14fb6
 *
Packit d14fb6
 * generated by using SIK (the session integrity key).  I am aware that the
Packit d14fb6
 * subscripts on the values look backwards, but that's the way they are
Packit d14fb6
 * written in the specification.
Packit d14fb6
 *
Packit d14fb6
 * If the authentication algorithm is IPMI_AUTH_RAKP_NONE, we return success.
Packit d14fb6
 * 
Packit d14fb6
 * return 1 on success (the authcode matches)
Packit d14fb6
 *        0 on failure (the authcode does not match)
Packit d14fb6
 *
Packit d14fb6
 */
Packit d14fb6
int
Packit d14fb6
lanplus_rakp4_hmac_matches(const struct ipmi_session * session,
Packit d14fb6
		const uint8_t * bmc_mac, struct ipmi_intf * intf)
Packit d14fb6
{
Packit d14fb6
	uint8_t       * buffer;
Packit d14fb6
	int           bufferLength, i;
Packit d14fb6
	uint8_t       mac[IPMI_MAX_MD_SIZE];
Packit d14fb6
	uint32_t      macLength;
Packit d14fb6
	uint32_t      cmpLength;
Packit d14fb6
	uint32_t      SIDc_lsbf;
Packit d14fb6
Packit d14fb6
	if (ipmi_oem_active(intf, "intelplus")){
Packit d14fb6
		/* Intel BMC responds with the integrity Algorithm in RAKP4 */
Packit d14fb6
		if (session->v2_data.integrity_alg == IPMI_INTEGRITY_NONE)
Packit d14fb6
			return 1;
Packit d14fb6
Packit d14fb6
		/* We don't yet support other algorithms */
Packit d14fb6
		assert((session->v2_data.integrity_alg == IPMI_INTEGRITY_HMAC_SHA1_96)
Packit d14fb6
			|| (session->v2_data.integrity_alg == IPMI_INTEGRITY_HMAC_MD5_128));
Packit d14fb6
	} else {
Packit d14fb6
		if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE)
Packit d14fb6
			return 1;
Packit d14fb6
Packit d14fb6
		/* We don't yet support other algorithms */
Packit d14fb6
		assert((session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA1)
Packit d14fb6
			|| (session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_MD5)
Packit d14fb6
#ifdef HAVE_CRYPTO_SHA256
Packit d14fb6
			|| (session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA256)
Packit d14fb6
#endif /* HAVE_CRYPTO_SHA256 */
Packit d14fb6
		);
Packit d14fb6
	}
Packit d14fb6
Packit d14fb6
	bufferLength =
Packit d14fb6
		16 +   /* Rm    */
Packit d14fb6
		4  +   /* SIDc  */
Packit d14fb6
		16;    /* GUIDc */
Packit d14fb6
Packit d14fb6
	buffer = (uint8_t *)malloc(bufferLength);
Packit d14fb6
	if (buffer == NULL) {
Packit d14fb6
		lprintf(LOG_ERR, "ipmitool: malloc failure");
Packit d14fb6
		return 1;
Packit d14fb6
	}
Packit d14fb6
Packit d14fb6
	/*
Packit d14fb6
	 * Fill the buffer.  I'm assuming that we're using the LSBF representation of the
Packit d14fb6
	 * multibyte numbers in use.
Packit d14fb6
	 */
Packit d14fb6
Packit d14fb6
	/* Rm */
Packit d14fb6
	#if WORDS_BIGENDIAN
Packit d14fb6
	for (i = 0; i < 16; ++i)
Packit d14fb6
		buffer[i] = session->v2_data.console_rand[16 - 1 - i];
Packit d14fb6
	#else
Packit d14fb6
	for (i = 0; i < 16; ++i)
Packit d14fb6
		buffer[i] = session->v2_data.console_rand[i];
Packit d14fb6
	#endif
Packit d14fb6
Packit d14fb6
Packit d14fb6
	/* SIDc */
Packit d14fb6
	SIDc_lsbf = session->v2_data.bmc_id;
Packit d14fb6
	#if WORDS_BIGENDIAN
Packit d14fb6
	SIDc_lsbf = BSWAP_32(SIDc_lsbf);
Packit d14fb6
	#endif
Packit d14fb6
	memcpy(buffer + 16, &SIDc_lsbf, 4);
Packit d14fb6
	
Packit d14fb6
Packit d14fb6
	/* GUIDc */
Packit d14fb6
	#if WORDS_BIGENDIAN
Packit d14fb6
	for (i = 0; i < 16; ++i)
Packit d14fb6
		buffer[i +  20] = session->v2_data.bmc_guid[16 - 1 - i];
Packit d14fb6
	#else
Packit d14fb6
	for (i = 0; i < 16; ++i)
Packit d14fb6
		buffer[i +  20] = session->v2_data.bmc_guid[i];
Packit d14fb6
	#endif
Packit d14fb6
Packit d14fb6
Packit d14fb6
	if (verbose > 2)
Packit d14fb6
	{
Packit d14fb6
		printbuf((const uint8_t *)buffer, bufferLength, ">> rakp4 mac input buffer");
Packit d14fb6
		printbuf(session->v2_data.sik, session->v2_data.sik_len,
Packit d14fb6
				">> rakp4 mac key (sik)");
Packit d14fb6
	}
Packit d14fb6
Packit d14fb6
Packit d14fb6
	/*
Packit d14fb6
	 * The buffer is complete.  Let's hash.
Packit d14fb6
	 */
Packit d14fb6
	lanplus_HMAC((ipmi_oem_active(intf, "intelplus")) 
Packit d14fb6
	             ? session->v2_data.integrity_alg 
Packit d14fb6
	             : session->v2_data.auth_alg ,
Packit d14fb6
				 session->v2_data.sik,
Packit d14fb6
				 session->v2_data.sik_len,
Packit d14fb6
				 buffer,
Packit d14fb6
				 bufferLength,
Packit d14fb6
				 mac,
Packit d14fb6
				 &macLength);
Packit d14fb6
Packit d14fb6
	if (verbose > 2)
Packit d14fb6
	{
Packit d14fb6
		printbuf(bmc_mac, macLength, ">> rakp4 mac as computed by the BMC");
Packit d14fb6
		printbuf(mac,     macLength, ">> rakp4 mac as computed by the remote console");
Packit d14fb6
	}
Packit d14fb6
Packit d14fb6
	if (ipmi_oem_active(intf, "intelplus")) {
Packit d14fb6
		/* Intel BMC responds with the integrity Algorithm in RAKP4 */
Packit d14fb6
		switch(session->v2_data.integrity_alg) {
Packit d14fb6
			case IPMI_INTEGRITY_HMAC_SHA1_96:
Packit d14fb6
				assert(macLength == IPMI_SHA_DIGEST_LENGTH);
Packit d14fb6
				cmpLength = IPMI_SHA1_AUTHCODE_SIZE;
Packit d14fb6
				break;
Packit d14fb6
			case IPMI_INTEGRITY_HMAC_MD5_128:
Packit d14fb6
				assert(macLength == IPMI_MD5_DIGEST_LENGTH);
Packit d14fb6
				cmpLength = IPMI_HMAC_MD5_AUTHCODE_SIZE;
Packit d14fb6
				break;
Packit d14fb6
			default:
Packit d14fb6
				assert(0);
Packit d14fb6
				break;
Packit d14fb6
		}
Packit d14fb6
	} else {
Packit d14fb6
		/* We don't yet support other algorithms */
Packit d14fb6
		switch(session->v2_data.auth_alg) {
Packit d14fb6
			case IPMI_AUTH_RAKP_HMAC_SHA1:
Packit d14fb6
				assert(macLength == IPMI_SHA_DIGEST_LENGTH);
Packit d14fb6
				cmpLength = IPMI_SHA1_AUTHCODE_SIZE;
Packit d14fb6
				break;
Packit d14fb6
			case IPMI_AUTH_RAKP_HMAC_MD5:
Packit d14fb6
				assert(macLength == IPMI_MD5_DIGEST_LENGTH);
Packit d14fb6
				cmpLength = IPMI_HMAC_MD5_AUTHCODE_SIZE;
Packit d14fb6
				break;
Packit d14fb6
#ifdef HAVE_CRYPTO_SHA256
Packit d14fb6
			case IPMI_AUTH_RAKP_HMAC_SHA256:
Packit d14fb6
				assert(macLength == IPMI_SHA256_DIGEST_LENGTH);
Packit d14fb6
				cmpLength = IPMI_HMAC_SHA256_AUTHCODE_SIZE;
Packit d14fb6
				break;
Packit d14fb6
#endif /* HAVE_CRYPTO_SHA256 */
Packit d14fb6
			default:
Packit d14fb6
				assert(0);
Packit d14fb6
				break;
Packit d14fb6
		}
Packit d14fb6
	}
Packit d14fb6
Packit d14fb6
	free(buffer);
Packit d14fb6
	buffer = NULL;
Packit d14fb6
	assert(macLength >= cmpLength);
Packit d14fb6
	return (memcmp(bmc_mac, mac, cmpLength) == 0);
Packit d14fb6
}
Packit d14fb6
Packit d14fb6
Packit d14fb6
Packit d14fb6
/*
Packit d14fb6
 * lanplus_generate_rakp3_auth_code
Packit d14fb6
 *
Packit d14fb6
 * This auth code is an HMAC generated with :
Packit d14fb6
 *
Packit d14fb6
 *     Rc         - BMC random number
Packit d14fb6
 *     SIDm       - Console session ID
Packit d14fb6
 *     ROLEm      - Requested privilege level (entire byte)
Packit d14fb6
 *     ULENGTHm   - Username length
Packit d14fb6
 *     <USERNAME> - Usename (absent for null usernames)
Packit d14fb6
 *
Packit d14fb6
 * The key used to generated the MAC is Kuid
Packit d14fb6
 *
Packit d14fb6
 * I am aware that the subscripts look backwards, but that is the way they are
Packit d14fb6
 * written in the spec.
Packit d14fb6
 * 
Packit d14fb6
 * param output_buffer [out] will hold the generated MAC
Packit d14fb6
 * param session       [in]  holds all the state data we need to generate the auth code
Packit d14fb6
 * param mac_length    [out] will be set to the length of the auth code
Packit d14fb6
 *
Packit d14fb6
 * returns 0 on success
Packit d14fb6
 *         1 on failure
Packit d14fb6
 */
Packit d14fb6
int
Packit d14fb6
lanplus_generate_rakp3_authcode(uint8_t * output_buffer,
Packit d14fb6
		const struct ipmi_session * session,
Packit d14fb6
		uint32_t * mac_length, struct ipmi_intf * intf)
Packit d14fb6
{
Packit d14fb6
	int ret = 0;
Packit d14fb6
	int input_buffer_length, i;
Packit d14fb6
	uint8_t * input_buffer;
Packit d14fb6
	uint32_t SIDm_lsbf;
Packit d14fb6
	
Packit d14fb6
Packit d14fb6
	if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE)
Packit d14fb6
	{
Packit d14fb6
		*mac_length = 0;
Packit d14fb6
		return 0;
Packit d14fb6
	}
Packit d14fb6
Packit d14fb6
	/* We don't yet support other algorithms */
Packit d14fb6
	assert((session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA1)
Packit d14fb6
		|| (session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_MD5)
Packit d14fb6
#ifdef HAVE_CRYPTO_SHA256
Packit d14fb6
		|| (session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA256)
Packit d14fb6
#endif /* HAVE_CRYPTO_SHA256 */
Packit d14fb6
	);
Packit d14fb6
Packit d14fb6
	input_buffer_length =
Packit d14fb6
		16 + /* Rc       */
Packit d14fb6
		4  + /* SIDm     */
Packit d14fb6
		1  + /* ROLEm    */
Packit d14fb6
		1  + /* ULENGTHm */
Packit d14fb6
		strlen((const char *)intf->ssn_params.username);
Packit d14fb6
Packit d14fb6
	input_buffer = malloc(input_buffer_length);
Packit d14fb6
	if (input_buffer == NULL) {
Packit d14fb6
		lprintf(LOG_ERR, "ipmitool: malloc failure");
Packit d14fb6
		return 1;
Packit d14fb6
	}
Packit d14fb6
Packit d14fb6
	/*
Packit d14fb6
	 * Fill the buffer.  I'm assuming that we're using the LSBF representation of the
Packit d14fb6
	 * multibyte numbers in use.
Packit d14fb6
	 */
Packit d14fb6
	
Packit d14fb6
	/* Rc */
Packit d14fb6
	#if WORDS_BIGENDIAN
Packit d14fb6
	for (i = 0; i < 16; ++i)
Packit d14fb6
		input_buffer[i] = session->v2_data.bmc_rand[16 - 1 - i];
Packit d14fb6
	#else
Packit d14fb6
	for (i = 0; i < 16; ++i)
Packit d14fb6
		input_buffer[i] = session->v2_data.bmc_rand[i];
Packit d14fb6
	#endif
Packit d14fb6
Packit d14fb6
	/* SIDm */
Packit d14fb6
	SIDm_lsbf = session->v2_data.console_id;
Packit d14fb6
	#if WORDS_BIGENDIAN
Packit d14fb6
	SIDm_lsbf = BSWAP_32(SIDm_lsbf);
Packit d14fb6
	#endif
Packit d14fb6
	memcpy(input_buffer + 16, &SIDm_lsbf, 4);
Packit d14fb6
	
Packit d14fb6
	/* ROLEm */
Packit d14fb6
	if (ipmi_oem_active(intf, "intelplus") || ipmi_oem_active(intf, "i82571spt"))
Packit d14fb6
		input_buffer[20] = intf->ssn_params.privlvl;
Packit d14fb6
	else 
Packit d14fb6
		input_buffer[20] = session->v2_data.requested_role;
Packit d14fb6
Packit d14fb6
	/* ULENGTHm */
Packit d14fb6
	input_buffer[21] = strlen((const char *)intf->ssn_params.username);
Packit d14fb6
Packit d14fb6
	/* USERNAME */
Packit d14fb6
	for (i = 0; i < input_buffer[21]; ++i)
Packit d14fb6
		input_buffer[22 + i] = intf->ssn_params.username[i];
Packit d14fb6
Packit d14fb6
	if (verbose > 2)
Packit d14fb6
	{
Packit d14fb6
		printbuf((const uint8_t *)input_buffer, input_buffer_length, ">> rakp3 mac input buffer");
Packit d14fb6
		printbuf((const uint8_t *)session->authcode, IPMI_AUTHCODE_BUFFER_SIZE, ">> rakp3 mac key");
Packit d14fb6
	}
Packit d14fb6
    
Packit d14fb6
	lanplus_HMAC(session->v2_data.auth_alg,
Packit d14fb6
				 session->authcode,
Packit d14fb6
				 IPMI_AUTHCODE_BUFFER_SIZE,
Packit d14fb6
				 input_buffer,
Packit d14fb6
				 input_buffer_length,
Packit d14fb6
				 output_buffer,
Packit d14fb6
				 mac_length);
Packit d14fb6
Packit d14fb6
	if (verbose > 2)
Packit d14fb6
		printbuf((const uint8_t *)output_buffer, *mac_length, "generated rakp3 mac");
Packit d14fb6
Packit d14fb6
	
Packit d14fb6
	free(input_buffer);
Packit d14fb6
	input_buffer = NULL;
Packit d14fb6
Packit d14fb6
	return ret;
Packit d14fb6
}
Packit d14fb6
Packit d14fb6
Packit d14fb6
Packit d14fb6
/*
Packit d14fb6
 * lanplus_generate_sik
Packit d14fb6
 *
Packit d14fb6
 * Generate the session integrity key (SIK) used for integrity checking 
Packit d14fb6
 * during the IPMI v2 / RMCP+ session
Packit d14fb6
 *
Packit d14fb6
 * This session integrity key is a HMAC generated with :
Packit d14fb6
 *
Packit d14fb6
 *     Rm         - Console generated random number
Packit d14fb6
 *     Rc         - BMC generated random number
Packit d14fb6
 *     ROLEm      - Requested privilege level (entire byte)
Packit d14fb6
 *     ULENGTHm   - Username length
Packit d14fb6
 *     <USERNAME> - Usename (absent for null usernames)
Packit d14fb6
 *
Packit d14fb6
 * The key used to generated the SIK is Kg if Kg is not null (two-key logins are
Packit d14fb6
 * enabled).  Otherwise Kuid (the user authcode) is used as the key to genereate
Packit d14fb6
 * the SIK.
Packit d14fb6
 *
Packit d14fb6
 * I am aware that the subscripts look backwards, but that is the way they are
Packit d14fb6
 * written in the spec.
Packit d14fb6
 * 
Packit d14fb6
 * param session [in/out] contains our input and output fields.
Packit d14fb6
 *
Packit d14fb6
 * returns 0 on success
Packit d14fb6
 *         1 on failure
Packit d14fb6
 */
Packit d14fb6
int
Packit d14fb6
lanplus_generate_sik(struct ipmi_session * session, struct ipmi_intf * intf)
Packit d14fb6
{
Packit d14fb6
	uint8_t * input_buffer;
Packit d14fb6
	int input_buffer_length, i;
Packit d14fb6
	uint8_t * input_key;
Packit d14fb6
	uint32_t mac_length;
Packit d14fb6
	
Packit d14fb6
Packit d14fb6
	memset(session->v2_data.sik, 0, sizeof(session->v2_data.sik));
Packit d14fb6
	session->v2_data.sik_len = 0;
Packit d14fb6
Packit d14fb6
	if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE)
Packit d14fb6
		return 0;
Packit d14fb6
Packit d14fb6
	/* We don't yet support other algorithms */
Packit d14fb6
	assert((session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA1)
Packit d14fb6
		|| (session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_MD5)
Packit d14fb6
#ifdef HAVE_CRYPTO_SHA256
Packit d14fb6
		|| (session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA256)
Packit d14fb6
#endif /* HAVE_CRYPTO_SHA256 */
Packit d14fb6
	);
Packit d14fb6
Packit d14fb6
	input_buffer_length =
Packit d14fb6
		16 +  /* Rm       */
Packit d14fb6
		16 +  /* Rc       */
Packit d14fb6
		1  +  /* ROLEm     */
Packit d14fb6
		1  +  /* ULENGTHm  */
Packit d14fb6
		strlen((const char *)intf->ssn_params.username);
Packit d14fb6
Packit d14fb6
	input_buffer = malloc(input_buffer_length);
Packit d14fb6
	if (input_buffer == NULL) {
Packit d14fb6
		lprintf(LOG_ERR, "ipmitool: malloc failure");
Packit d14fb6
		return 1;
Packit d14fb6
	}
Packit d14fb6
Packit d14fb6
	/*
Packit d14fb6
	 * Fill the buffer.  I'm assuming that we're using the LSBF representation of the
Packit d14fb6
	 * multibyte numbers in use.
Packit d14fb6
	 */
Packit d14fb6
Packit d14fb6
	/* Rm */
Packit d14fb6
	#if WORDS_BIGENDIAN
Packit d14fb6
	for (i = 0; i < 16; ++i)
Packit d14fb6
		input_buffer[i] = session->v2_data.console_rand[16 - 1 - i];
Packit d14fb6
	#else
Packit d14fb6
	for (i = 0; i < 16; ++i)
Packit d14fb6
		input_buffer[i] = session->v2_data.console_rand[i];
Packit d14fb6
	#endif
Packit d14fb6
	
Packit d14fb6
Packit d14fb6
	/* Rc */
Packit d14fb6
	#if WORDS_BIGENDIAN
Packit d14fb6
	for (i = 0; i < 16; ++i)
Packit d14fb6
		input_buffer[16 + i] = session->v2_data.bmc_rand[16 - 1 - i];
Packit d14fb6
	#else
Packit d14fb6
	for (i = 0; i < 16; ++i)
Packit d14fb6
		input_buffer[16 + i] = session->v2_data.bmc_rand[i];
Packit d14fb6
	#endif
Packit d14fb6
Packit d14fb6
	/* ROLEm */
Packit d14fb6
	input_buffer[32] = session->v2_data.requested_role;
Packit d14fb6
Packit d14fb6
	if (ipmi_oem_active(intf, "i82571spt")) {
Packit d14fb6
		/*
Packit d14fb6
		 * The HMAC calculation code in the Intel 82571 GbE
Packit d14fb6
		 * skips this bit!  Looks like a GbE bug, but we need
Packit d14fb6
		 * to work around it here anyway...
Packit d14fb6
		 */
Packit d14fb6
		input_buffer[32] &= ~0x10;
Packit d14fb6
	}
Packit d14fb6
Packit d14fb6
	/* ULENGTHm */
Packit d14fb6
	input_buffer[33] = strlen((const char *)intf->ssn_params.username);
Packit d14fb6
Packit d14fb6
	/* USERNAME */
Packit d14fb6
	for (i = 0; i < input_buffer[33]; ++i)
Packit d14fb6
		input_buffer[34 + i] = intf->ssn_params.username[i];
Packit d14fb6
Packit d14fb6
	if (intf->ssn_params.kg[0])
Packit d14fb6
	{
Packit d14fb6
		/* We will be hashing with Kg */
Packit d14fb6
		/*
Packit d14fb6
		 * Section 13.31 of the IPMI v2 spec describes the SIK creation
Packit d14fb6
		 * using Kg.  It specifies that Kg should not be truncated.
Packit d14fb6
		 * Kg is set in ipmi_intf.
Packit d14fb6
		 */
Packit d14fb6
		input_key        = intf->ssn_params.kg;
Packit d14fb6
	}
Packit d14fb6
	else
Packit d14fb6
	{
Packit d14fb6
		/* We will be hashing with Kuid */
Packit d14fb6
		input_key        = session->authcode;
Packit d14fb6
	}
Packit d14fb6
Packit d14fb6
	
Packit d14fb6
	if (verbose >= 2)
Packit d14fb6
		printbuf((const uint8_t *)input_buffer, input_buffer_length, "session integrity key input");
Packit d14fb6
Packit d14fb6
	lanplus_HMAC(session->v2_data.auth_alg,
Packit d14fb6
				 input_key,
Packit d14fb6
				 IPMI_AUTHCODE_BUFFER_SIZE,
Packit d14fb6
				 input_buffer,
Packit d14fb6
				 input_buffer_length,
Packit d14fb6
				 session->v2_data.sik,
Packit d14fb6
				 &mac_length);
Packit d14fb6
Packit d14fb6
	free(input_buffer);
Packit d14fb6
	input_buffer = NULL;
Packit d14fb6
	switch (session->v2_data.auth_alg) {
Packit d14fb6
		case IPMI_AUTH_RAKP_HMAC_SHA1:
Packit d14fb6
			assert(mac_length == IPMI_SHA_DIGEST_LENGTH);
Packit d14fb6
			break;
Packit d14fb6
		case IPMI_AUTH_RAKP_HMAC_MD5:
Packit d14fb6
			assert(mac_length == IPMI_MD5_DIGEST_LENGTH);
Packit d14fb6
			break;
Packit d14fb6
#ifdef HAVE_CRYPTO_SHA256
Packit d14fb6
		case IPMI_AUTH_RAKP_HMAC_SHA256:
Packit d14fb6
			assert(mac_length == IPMI_SHA256_DIGEST_LENGTH);
Packit d14fb6
			break;
Packit d14fb6
#endif /* HAVE_CRYPTO_SHA256 */
Packit d14fb6
		default:
Packit d14fb6
			assert(0);
Packit d14fb6
			break;
Packit d14fb6
	}
Packit d14fb6
Packit d14fb6
	session->v2_data.sik_len = mac_length;
Packit d14fb6
Packit d14fb6
	/*
Packit d14fb6
	 * The key MAC generated is 20 bytes, but we will only be using the first
Packit d14fb6
	 * 12 for SHA1 96
Packit d14fb6
	 */
Packit d14fb6
	if (verbose >= 2) {
Packit d14fb6
		printbuf(session->v2_data.sik, session->v2_data.sik_len,
Packit d14fb6
				"Generated session integrity key");
Packit d14fb6
	}
Packit d14fb6
	return 0;
Packit d14fb6
}
Packit d14fb6
Packit d14fb6
Packit d14fb6
Packit d14fb6
/*
Packit d14fb6
 * lanplus_generate_k1
Packit d14fb6
 *
Packit d14fb6
 * Generate K1, the key presumably used to generate integrity authcodes
Packit d14fb6
 *
Packit d14fb6
 * We use the authentication algorithm to generated the HMAC, using
Packit d14fb6
 * the session integrity key (SIK) as our key.
Packit d14fb6
 *
Packit d14fb6
 * param session [in/out].
Packit d14fb6
 *
Packit d14fb6
 * returns 0 on success
Packit d14fb6
 *         1 on failure
Packit d14fb6
 */
Packit d14fb6
int
Packit d14fb6
lanplus_generate_k1(struct ipmi_session * session)
Packit d14fb6
{
Packit d14fb6
	uint32_t mac_length;
Packit d14fb6
Packit d14fb6
	uint8_t CONST_1[] =
Packit d14fb6
		{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
Packit d14fb6
		 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01};
Packit d14fb6
Packit d14fb6
	if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE)
Packit d14fb6
		memcpy(session->v2_data.k1, CONST_1, 20);
Packit d14fb6
	else
Packit d14fb6
	{
Packit d14fb6
		lanplus_HMAC(session->v2_data.auth_alg,
Packit d14fb6
					 session->v2_data.sik,
Packit d14fb6
					 session->v2_data.sik_len, /* SIK length */
Packit d14fb6
					 CONST_1,
Packit d14fb6
					 20,
Packit d14fb6
					 session->v2_data.k1,
Packit d14fb6
					 &mac_length);
Packit d14fb6
		switch (session->v2_data.auth_alg) {
Packit d14fb6
			case IPMI_AUTH_RAKP_HMAC_SHA1:
Packit d14fb6
				assert(mac_length == IPMI_SHA_DIGEST_LENGTH);
Packit d14fb6
				break;
Packit d14fb6
			case IPMI_AUTH_RAKP_HMAC_MD5:
Packit d14fb6
				assert(mac_length == IPMI_MD5_DIGEST_LENGTH);
Packit d14fb6
				break;
Packit d14fb6
#ifdef HAVE_CRYPTO_SHA256
Packit d14fb6
			case IPMI_AUTH_RAKP_HMAC_SHA256:
Packit d14fb6
				assert(mac_length == IPMI_SHA256_DIGEST_LENGTH);
Packit d14fb6
				break;
Packit d14fb6
#endif /* HAVE_CRYPTO_SHA256 */
Packit d14fb6
			default:
Packit d14fb6
				assert(0);
Packit d14fb6
				break;
Packit d14fb6
		}
Packit d14fb6
		session->v2_data.k1_len = mac_length;
Packit d14fb6
	}
Packit d14fb6
Packit d14fb6
	if (verbose >= 2)
Packit d14fb6
		printbuf(session->v2_data.k1, session->v2_data.k1_len, "Generated K1");
Packit d14fb6
Packit d14fb6
	return 0;
Packit d14fb6
}
Packit d14fb6
Packit d14fb6
Packit d14fb6
Packit d14fb6
/*
Packit d14fb6
 * lanplus_generate_k2
Packit d14fb6
 *
Packit d14fb6
 * Generate K2, the key used for RMCP+ AES encryption.
Packit d14fb6
 *
Packit d14fb6
 * We use the authentication algorithm to generated the HMAC, using
Packit d14fb6
 * the session integrity key (SIK) as our key.
Packit d14fb6
 *
Packit d14fb6
 * param session [in/out].
Packit d14fb6
 *
Packit d14fb6
 * returns 0 on success
Packit d14fb6
 *         1 on failure
Packit d14fb6
 */
Packit d14fb6
int
Packit d14fb6
lanplus_generate_k2(struct ipmi_session * session)
Packit d14fb6
{
Packit d14fb6
	uint32_t mac_length;
Packit d14fb6
Packit d14fb6
	uint8_t CONST_2[] =
Packit d14fb6
		{0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
Packit d14fb6
		 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02};
Packit d14fb6
Packit d14fb6
	if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE)
Packit d14fb6
		memcpy(session->v2_data.k2, CONST_2, 20);
Packit d14fb6
	else
Packit d14fb6
	{
Packit d14fb6
		lanplus_HMAC(session->v2_data.auth_alg,
Packit d14fb6
					 session->v2_data.sik,
Packit d14fb6
					 session->v2_data.sik_len, /* SIK length */
Packit d14fb6
					 CONST_2,
Packit d14fb6
					 20,
Packit d14fb6
					 session->v2_data.k2,
Packit d14fb6
					 &mac_length);
Packit d14fb6
		switch (session->v2_data.auth_alg) {
Packit d14fb6
			case IPMI_AUTH_RAKP_HMAC_SHA1:
Packit d14fb6
				assert(mac_length == IPMI_SHA_DIGEST_LENGTH);
Packit d14fb6
				break;
Packit d14fb6
			case IPMI_AUTH_RAKP_HMAC_MD5:
Packit d14fb6
				assert(mac_length == IPMI_MD5_DIGEST_LENGTH);
Packit d14fb6
				break;
Packit d14fb6
#ifdef HAVE_CRYPTO_SHA256
Packit d14fb6
			case IPMI_AUTH_RAKP_HMAC_SHA256:
Packit d14fb6
				assert(mac_length == IPMI_SHA256_DIGEST_LENGTH);
Packit d14fb6
				break;
Packit d14fb6
#endif /* HAVE_CRYPTO_SHA256 */
Packit d14fb6
			default:
Packit d14fb6
				assert(0);
Packit d14fb6
				break;
Packit d14fb6
		}
Packit d14fb6
		session->v2_data.k2_len = mac_length;
Packit d14fb6
	}
Packit d14fb6
Packit d14fb6
	if (verbose >= 2)
Packit d14fb6
		printbuf(session->v2_data.k2, session->v2_data.k2_len, "Generated K2");
Packit d14fb6
Packit d14fb6
	return 0;
Packit d14fb6
}
Packit d14fb6
Packit d14fb6
Packit d14fb6
Packit d14fb6
/*
Packit d14fb6
 * lanplus_encrypt_payload
Packit d14fb6
 *
Packit d14fb6
 * Perform the appropriate encryption on the input data.  Output the encrypted
Packit d14fb6
 * data to output, including the required confidentiality header and trailer.
Packit d14fb6
 * If the crypt_alg is IPMI_CRYPT_NONE, simply copy the input to the output and
Packit d14fb6
 * set bytes_written to input_length.
Packit d14fb6
 * 
Packit d14fb6
 * param crypt_alg specifies the encryption algorithm (from table 13-19 of the
Packit d14fb6
 *       IPMI v2 spec)
Packit d14fb6
 * param key is the used as input to the encryption algorithmf
Packit d14fb6
 * param input is the input data to be encrypted
Packit d14fb6
 * param input_length is the length of the input data to be encrypted
Packit d14fb6
 * param output is the cipher text generated by the encryption process
Packit d14fb6
 * param bytes_written is the number of bytes written during the encryption
Packit d14fb6
 *       process
Packit d14fb6
 *
Packit d14fb6
 * returns 0 on success
Packit d14fb6
 *         1 on failure
Packit d14fb6
 */
Packit d14fb6
int
Packit d14fb6
lanplus_encrypt_payload(uint8_t crypt_alg,
Packit d14fb6
		const uint8_t * key, const uint8_t * input,
Packit d14fb6
		uint32_t input_length, uint8_t * output,
Packit d14fb6
		uint16_t * bytes_written)
Packit d14fb6
{
Packit d14fb6
	uint8_t * padded_input;
Packit d14fb6
	uint32_t    mod, i, bytes_encrypted;
Packit d14fb6
	uint8_t   pad_length = 0;
Packit d14fb6
Packit d14fb6
	if (crypt_alg == IPMI_CRYPT_NONE)
Packit d14fb6
	{
Packit d14fb6
		/* Just copy the input to the output */
Packit d14fb6
		*bytes_written = input_length;
Packit d14fb6
		return 0;
Packit d14fb6
	}
Packit d14fb6
	
Packit d14fb6
	/* Currently, we only support AES */
Packit d14fb6
	assert(crypt_alg == IPMI_CRYPT_AES_CBC_128);
Packit d14fb6
	assert(input_length <= IPMI_MAX_PAYLOAD_SIZE);
Packit d14fb6
Packit d14fb6
Packit d14fb6
	/*
Packit d14fb6
	 * The input to the AES encryption algorithm has to be a multiple of the
Packit d14fb6
	 * block size (16 bytes).  The extra byte we are adding is the pad length
Packit d14fb6
	 * byte.
Packit d14fb6
	 */
Packit d14fb6
	mod = (input_length + 1) % IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE;
Packit d14fb6
	if (mod)
Packit d14fb6
		pad_length = IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE - mod;
Packit d14fb6
Packit d14fb6
	padded_input = (uint8_t*)malloc(input_length + pad_length + 1);
Packit d14fb6
	if (padded_input == NULL) {
Packit d14fb6
		lprintf(LOG_ERR, "ipmitool: malloc failure");
Packit d14fb6
		return 1;
Packit d14fb6
	}
Packit d14fb6
	memcpy(padded_input, input, input_length);
Packit d14fb6
Packit d14fb6
	/* add the pad */
Packit d14fb6
	for (i = 0; i < pad_length; ++i)
Packit d14fb6
		padded_input[input_length + i] = i + 1;
Packit d14fb6
Packit d14fb6
	/* add the pad length */
Packit d14fb6
	padded_input[input_length + pad_length] = pad_length;
Packit d14fb6
Packit d14fb6
	/* Generate an initialization vector, IV, for the encryption process */
Packit d14fb6
	if (lanplus_rand(output, IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE))
Packit d14fb6
	{
Packit d14fb6
		lprintf(LOG_ERR, "lanplus_encrypt_payload: Error generating IV");
Packit d14fb6
		if (padded_input != NULL) {
Packit d14fb6
			free(padded_input);
Packit d14fb6
			padded_input = NULL;
Packit d14fb6
		}
Packit d14fb6
		return 1;
Packit d14fb6
	}
Packit d14fb6
Packit d14fb6
	if (verbose > 2)
Packit d14fb6
		printbuf(output, IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE, ">> Initialization vector");
Packit d14fb6
Packit d14fb6
Packit d14fb6
Packit d14fb6
	lanplus_encrypt_aes_cbc_128(output,                                     /* IV              */
Packit d14fb6
								key,                                        /* K2              */
Packit d14fb6
								padded_input,                               /* Data to encrypt */
Packit d14fb6
								input_length + pad_length + 1,              /* Input length    */
Packit d14fb6
								output + IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE, /* output          */
Packit d14fb6
								&bytes_encrypted);                          /* bytes written   */
Packit d14fb6
Packit d14fb6
	*bytes_written =
Packit d14fb6
		IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE + /* IV */
Packit d14fb6
		bytes_encrypted;
Packit d14fb6
Packit d14fb6
	free(padded_input);
Packit d14fb6
	padded_input = NULL;
Packit d14fb6
Packit d14fb6
	return 0;
Packit d14fb6
}
Packit d14fb6
Packit d14fb6
Packit d14fb6
Packit d14fb6
/*
Packit d14fb6
 * lanplus_has_valid_auth_code
Packit d14fb6
 *
Packit d14fb6
 * Determine whether the packets authcode field is valid for packet.
Packit d14fb6
 * 
Packit d14fb6
 * We always return success if any of the following are true. 
Packit d14fb6
 *  - this is not an IPMIv2 packet
Packit d14fb6
 *  - the session is not yet active
Packit d14fb6
 *  - the packet specifies that it is not authenticated
Packit d14fb6
 *  - the integrity algorithm agreed upon during session creation is "none"
Packit d14fb6
 *
Packit d14fb6
 * The authcode is computed using the specified integrity algorithm starting
Packit d14fb6
 * with the AuthType / Format field, and ending with the field immediately
Packit d14fb6
 * preceeding the authcode itself.
Packit d14fb6
 *
Packit d14fb6
 * The key key used to generate the authcode MAC is K1.
Packit d14fb6
 * 
Packit d14fb6
 * param rs holds the response structure.
Packit d14fb6
 * param session holds our session state, including our chosen algorithm, key, etc.
Packit d14fb6
 *
Packit d14fb6
 * returns 1 on success (authcode is valid)
Packit d14fb6
 *         0 on failure (autchode integrity check failed)
Packit d14fb6
 */
Packit d14fb6
int
Packit d14fb6
lanplus_has_valid_auth_code(struct ipmi_rs * rs, struct ipmi_session * session)
Packit d14fb6
{
Packit d14fb6
	uint8_t * bmc_authcode;
Packit d14fb6
	uint8_t generated_authcode[IPMI_MAX_MAC_SIZE];
Packit d14fb6
	uint32_t generated_authcode_length;
Packit d14fb6
	uint32_t authcode_length;
Packit d14fb6
	
Packit d14fb6
Packit d14fb6
	if ((rs->session.authtype != IPMI_SESSION_AUTHTYPE_RMCP_PLUS) ||
Packit d14fb6
		(session->v2_data.session_state != LANPLUS_STATE_ACTIVE)  ||
Packit d14fb6
		(! rs->session.bAuthenticated)                            ||
Packit d14fb6
		(session->v2_data.integrity_alg == IPMI_INTEGRITY_NONE))
Packit d14fb6
		return 1;
Packit d14fb6
	
Packit d14fb6
	switch (session->v2_data.integrity_alg) {
Packit d14fb6
		case IPMI_INTEGRITY_HMAC_SHA1_96:
Packit d14fb6
			authcode_length = IPMI_SHA1_AUTHCODE_SIZE;
Packit d14fb6
			break;
Packit d14fb6
		case IPMI_INTEGRITY_HMAC_MD5_128:
Packit d14fb6
			authcode_length = IPMI_HMAC_MD5_AUTHCODE_SIZE;
Packit d14fb6
			break;
Packit d14fb6
#ifdef HAVE_CRYPTO_SHA256
Packit d14fb6
		case IPMI_INTEGRITY_HMAC_SHA256_128:
Packit d14fb6
			authcode_length = IPMI_HMAC_SHA256_AUTHCODE_SIZE;
Packit d14fb6
			break;
Packit d14fb6
#endif /* HAVE_CRYPTO_SHA256 */
Packit d14fb6
		/* Unsupported */
Packit d14fb6
		default:
Packit d14fb6
			assert(0);
Packit d14fb6
			break;
Packit d14fb6
	}
Packit d14fb6
Packit d14fb6
	/*
Packit d14fb6
	 * For SHA1-96, the authcode will be the last 12 bytes in the packet
Packit d14fb6
	 * For SHA256-128 or MD5-128, the authcode will be the last 16 bytes in the packet
Packit d14fb6
	 */
Packit d14fb6
	bmc_authcode = rs->data + (rs->data_len - authcode_length);
Packit d14fb6
Packit d14fb6
	lanplus_HMAC(session->v2_data.integrity_alg,
Packit d14fb6
				 session->v2_data.k1,
Packit d14fb6
				 session->v2_data.k1_len,
Packit d14fb6
				 rs->data + IPMI_LANPLUS_OFFSET_AUTHTYPE,
Packit d14fb6
				 rs->data_len - IPMI_LANPLUS_OFFSET_AUTHTYPE - authcode_length,
Packit d14fb6
				 generated_authcode,
Packit d14fb6
				 &generated_authcode_length);
Packit d14fb6
Packit d14fb6
	if (verbose > 3)
Packit d14fb6
	{
Packit d14fb6
		lprintf(LOG_DEBUG+2, "Validating authcode");
Packit d14fb6
		printbuf(session->v2_data.k1, session->v2_data.k1_len, "K1");
Packit d14fb6
		printbuf(rs->data + IPMI_LANPLUS_OFFSET_AUTHTYPE,
Packit d14fb6
				 rs->data_len - IPMI_LANPLUS_OFFSET_AUTHTYPE - authcode_length,
Packit d14fb6
				 "Authcode Input Data");
Packit d14fb6
		printbuf(generated_authcode, generated_authcode_length, "Generated authcode");
Packit d14fb6
		printbuf(bmc_authcode,       authcode_length, "Expected authcode");
Packit d14fb6
	}
Packit d14fb6
Packit d14fb6
	assert(generated_authcode_length >= authcode_length);
Packit d14fb6
	return (memcmp(bmc_authcode, generated_authcode, authcode_length) == 0);
Packit d14fb6
}
Packit d14fb6
Packit d14fb6
Packit d14fb6
Packit d14fb6
/*
Packit d14fb6
 * lanplus_decrypt_payload
Packit d14fb6
 *
Packit d14fb6
 * 
Packit d14fb6
 * param input points to the beginning of the payload (which will be the IV if
Packit d14fb6
 *       we are using AES)
Packit d14fb6
 * param payload_size [out] will be set to the size of the payload EXCLUDING
Packit d14fb6
 * padding
Packit d14fb6
 * 
Packit d14fb6
 * returns 0 on success (we were able to successfully decrypt the packet)
Packit d14fb6
 *         1 on failure (we were unable to successfully decrypt the packet)
Packit d14fb6
 */
Packit d14fb6
int
Packit d14fb6
lanplus_decrypt_payload(uint8_t crypt_alg, const uint8_t * key,
Packit d14fb6
		const uint8_t * input, uint32_t input_length,
Packit d14fb6
		uint8_t * output, uint16_t * payload_size)
Packit d14fb6
{
Packit d14fb6
	uint8_t * decrypted_payload;
Packit d14fb6
	uint32_t    bytes_decrypted;
Packit d14fb6
Packit d14fb6
	if (crypt_alg == IPMI_CRYPT_NONE)
Packit d14fb6
	{
Packit d14fb6
		/* We are not encrypted.  The paylaod size is is everything. */
Packit d14fb6
		*payload_size = input_length;
Packit d14fb6
		memmove(output, input, input_length);
Packit d14fb6
		return 0;
Packit d14fb6
	}
Packit d14fb6
Packit d14fb6
	/* We only support AES */
Packit d14fb6
	assert(crypt_alg == IPMI_CRYPT_AES_CBC_128);
Packit d14fb6
Packit d14fb6
	decrypted_payload = (uint8_t*)malloc(input_length);
Packit d14fb6
	if (decrypted_payload == NULL) {
Packit d14fb6
		lprintf(LOG_ERR, "ipmitool: malloc failure");
Packit d14fb6
		return 1;
Packit d14fb6
	}
Packit d14fb6
Packit d14fb6
Packit d14fb6
	lanplus_decrypt_aes_cbc_128(input,                                /* IV              */
Packit d14fb6
								key,                                  /* Key             */
Packit d14fb6
								input                        +
Packit d14fb6
								IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE,    /* Data to decrypt */
Packit d14fb6
								input_length -
Packit d14fb6
								IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE,    /* Input length    */
Packit d14fb6
								decrypted_payload,                    /* output          */
Packit d14fb6
								&bytes_decrypted);                    /* bytes written   */
Packit d14fb6
Packit d14fb6
	if (bytes_decrypted != 0)
Packit d14fb6
	{
Packit d14fb6
		/* Success */
Packit d14fb6
		uint8_t conf_pad_length;
Packit d14fb6
		int i;
Packit d14fb6
Packit d14fb6
		memmove(output,
Packit d14fb6
				decrypted_payload,
Packit d14fb6
				bytes_decrypted);
Packit d14fb6
Packit d14fb6
		/*
Packit d14fb6
		 * We have to determine the payload size, by substracting the padding, etc.
Packit d14fb6
		 * The last byte of the decrypted payload is the confidentiality pad length.
Packit d14fb6
		 */
Packit d14fb6
		conf_pad_length = decrypted_payload[bytes_decrypted - 1];
Packit d14fb6
		*payload_size = bytes_decrypted - conf_pad_length - 1;
Packit d14fb6
Packit d14fb6
		/*
Packit d14fb6
		 * Extra test to make sure that the padding looks like it should (should start
Packit d14fb6
		 * with 0x01, 0x02, 0x03, etc...
Packit d14fb6
		 */
Packit d14fb6
		for (i = 0; i < conf_pad_length; ++i)
Packit d14fb6
		{
Packit d14fb6
			if (decrypted_payload[*payload_size + i] != (i + 1))
Packit d14fb6
			{
Packit d14fb6
				lprintf(LOG_ERR, "Malformed payload padding");
Packit d14fb6
				assert(0);
Packit d14fb6
			}
Packit d14fb6
		}
Packit d14fb6
	}
Packit d14fb6
	else
Packit d14fb6
	{
Packit d14fb6
		lprintf(LOG_ERR, "ERROR: lanplus_decrypt_aes_cbc_128 decryptd 0 bytes");
Packit d14fb6
		assert(0);
Packit d14fb6
	}
Packit d14fb6
Packit d14fb6
	free(decrypted_payload);
Packit d14fb6
	decrypted_payload = NULL;
Packit d14fb6
	return (bytes_decrypted == 0);
Packit d14fb6
}