|
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 |
}
|