From 8ca47f21ca9e121ceabf3eab68244206c5a5b7ae Mon Sep 17 00:00:00 2001 From: Zdenek Styblik Date: Sat, 28 May 2016 13:25:36 +0200 Subject: [PATCH] ID:441 - Add support for HMAC_MD5 and HMAC_SHA256 Commit adds support for cipher suites 6/7/8 (HMAC-MD5) and cipher suites 15/16/17 (HMAC_SHA256). This also fixes: * ID:442 - IPMI_AUTH_RAKP_HMAC_MD5 support in lanplus * ID:141 - RMCP+ Cipher-suite 17 not supported Original author Liebig Holger(Fujitsu). Code cleanup done by Florian Breu and Zdenek Styblik. --- configure.ac | 10 ++ include/ipmitool/ipmi.h | 5 +- include/ipmitool/ipmi_constants.h | 2 + include/ipmitool/ipmi_intf.h | 13 +- lib/ipmi_strings.c | 6 + src/plugins/lanplus/lanplus.c | 121 +++++++++++--- src/plugins/lanplus/lanplus.h | 18 ++- src/plugins/lanplus/lanplus_crypt.c | 196 +++++++++++++++++++---- src/plugins/lanplus/lanplus_crypt_impl.c | 11 +- src/plugins/lanplus/lanplus_dump.c | 39 ++++- 10 files changed, 347 insertions(+), 74 deletions(-) diff --git a/configure.ac b/configure.ac index 35e0471..4e473bf 100644 --- a/configure.ac +++ b/configure.ac @@ -164,6 +164,16 @@ AC_CHECK_LIB([crypto], [EVP_aes_128_cbc], fi], [have_crypto=no], [-lcrypto]) +AC_CHECK_LIB([crypto], [EVP_sha256], + [if test "x$xenable_internal_sha256" != "xyes"; then + if test "x$have_crypto" != "xyes"; then + LIBS="$LIBS -lcrypto" + have_sha256=yes + fi + AC_DEFINE(HAVE_CRYPTO_SHA256, [1], [Define to 1 if libcrypto supports SHA256.]) + fi], + [], [-lcrypto]) + AC_CHECK_LIB([crypto], [MD5_Init], [if test "x$xenable_internal_md5" != "xyes"; then if test "x$have_crypto" != "xyes"; then diff --git a/include/ipmitool/ipmi.h b/include/ipmitool/ipmi.h index ac15415..6e42d06 100644 --- a/include/ipmitool/ipmi.h +++ b/include/ipmitool/ipmi.h @@ -46,6 +46,7 @@ #endif #define IPMI_BUF_SIZE 1024 +#define IPMI_MAX_MD_SIZE 0x20 #if HAVE_PRAGMA_PACK #define ATTRIBUTE_PACKING @@ -211,13 +212,13 @@ struct ipmi_rs { uint32_t console_id; uint8_t bmc_rand[16]; /* Random number generated by the BMC */ uint8_t bmc_guid[16]; - uint8_t key_exchange_auth_code[20]; + uint8_t key_exchange_auth_code[IPMI_MAX_MD_SIZE]; } rakp2_message; struct { uint8_t message_tag; uint8_t rakp_return_code; uint32_t console_id; - uint8_t integrity_check_value[20]; + uint8_t integrity_check_value[IPMI_MAX_MD_SIZE]; } rakp4_message; struct { uint8_t packet_sequence_number; diff --git a/include/ipmitool/ipmi_constants.h b/include/ipmitool/ipmi_constants.h index 2aad2cf..8f2bc87 100644 --- a/include/ipmitool/ipmi_constants.h +++ b/include/ipmitool/ipmi_constants.h @@ -118,12 +118,14 @@ #define IPMI_AUTH_RAKP_NONE 0x00 #define IPMI_AUTH_RAKP_HMAC_SHA1 0x01 #define IPMI_AUTH_RAKP_HMAC_MD5 0x02 +#define IPMI_AUTH_RAKP_HMAC_SHA256 0x03 /* From table 13-18 of the IPMI v2 specification */ #define IPMI_INTEGRITY_NONE 0x00 #define IPMI_INTEGRITY_HMAC_SHA1_96 0x01 #define IPMI_INTEGRITY_HMAC_MD5_128 0x02 #define IPMI_INTEGRITY_MD5_128 0x03 +#define IPMI_INTEGRITY_HMAC_SHA256_128 0x04 /* From table 13-19 of the IPMI v2 specfication */ #define IPMI_CRYPT_NONE 0x00 diff --git a/include/ipmitool/ipmi_intf.h b/include/ipmitool/ipmi_intf.h index 67f6019..9285baa 100644 --- a/include/ipmitool/ipmi_intf.h +++ b/include/ipmitool/ipmi_intf.h @@ -59,7 +59,7 @@ enum LANPLUS_SESSION_STATE { #define IPMI_AUTHCODE_BUFFER_SIZE 20 -#define IPMI_SIK_BUFFER_SIZE 20 +#define IPMI_SIK_BUFFER_SIZE IPMI_MAX_MD_SIZE #define IPMI_KG_BUFFER_SIZE 21 /* key plus null byte */ struct ipmi_session_params { @@ -131,10 +131,13 @@ struct ipmi_session { uint8_t requested_role; /* As sent in the RAKP 1 message */ uint8_t rakp2_return_code; - uint8_t sik[IPMI_SIK_BUFFER_SIZE]; /* Session integrity key */ - uint8_t kg[IPMI_KG_BUFFER_SIZE]; /* BMC key */ - uint8_t k1[20]; /* Used for Integrity checking? */ - uint8_t k2[20]; /* First 16 bytes used for AES */ + uint8_t sik[IPMI_SIK_BUFFER_SIZE]; /* Session integrity key */ + uint8_t sik_len; /* Session Integrity key length */ + uint8_t kg[IPMI_KG_BUFFER_SIZE]; /* BMC key */ + uint8_t k1[IPMI_MAX_MD_SIZE]; /* Used for Integrity checking? */ + uint8_t k1_len; /* K1 key length */ + uint8_t k2[IPMI_MAX_MD_SIZE]; /* First 16 bytes used for AES */ + uint8_t k2_len; /* K2 key length */ } v2_data; diff --git a/lib/ipmi_strings.c b/lib/ipmi_strings.c index fa4e107..f14bc21 100644 --- a/lib/ipmi_strings.c +++ b/lib/ipmi_strings.c @@ -621,6 +621,9 @@ const struct valstr ipmi_auth_algorithms[] = { { IPMI_AUTH_RAKP_NONE, "none" }, { IPMI_AUTH_RAKP_HMAC_SHA1, "hmac_sha1" }, { IPMI_AUTH_RAKP_HMAC_MD5, "hmac_md5" }, +#ifdef HAVE_CRYPTO_SHA256 + { IPMI_AUTH_RAKP_HMAC_SHA256, "hmac_sha256" }, +#endif /* HAVE_CRYPTO_SHA256 */ { 0x00, NULL } }; @@ -629,6 +632,9 @@ const struct valstr ipmi_integrity_algorithms[] = { { IPMI_INTEGRITY_HMAC_SHA1_96, "hmac_sha1_96" }, { IPMI_INTEGRITY_HMAC_MD5_128, "hmac_md5_128" }, { IPMI_INTEGRITY_MD5_128 , "md5_128" }, +#ifdef HAVE_CRYPTO_SHA256 + { IPMI_INTEGRITY_HMAC_SHA256_128, "sha256_128" }, +#endif /* HAVE_CRYPTO_SHA256 */ { 0x00, NULL } }; diff --git a/src/plugins/lanplus/lanplus.c b/src/plugins/lanplus/lanplus.c index 2a89a14..a9ff926 100644 --- a/src/plugins/lanplus/lanplus.c +++ b/src/plugins/lanplus/lanplus.c @@ -169,9 +169,14 @@ int lanplus_get_requested_ciphers(int cipher_suite_id, uint8_t * integrity_alg, uint8_t * crypt_alg) { +#ifdef HAVE_CRYPTO_SHA256 + if ((cipher_suite_id < 0) || (cipher_suite_id > 17)) { + return 1; + } +#else if ((cipher_suite_id < 0) || (cipher_suite_id > 14)) return 1; - +#endif /* HAVE_CRYPTO_SHA256 */ /* See table 22-19 for the source of the statement */ switch (cipher_suite_id) { @@ -250,6 +255,23 @@ int lanplus_get_requested_ciphers(int cipher_suite_id, *integrity_alg = IPMI_INTEGRITY_MD5_128; *crypt_alg = IPMI_CRYPT_XRC4_40; break; +#ifdef HAVE_CRYPTO_SHA256 + case 15: + *auth_alg = IPMI_AUTH_RAKP_HMAC_SHA256; + *integrity_alg = IPMI_INTEGRITY_NONE; + *crypt_alg = IPMI_CRYPT_NONE; + break; + case 16: + *auth_alg = IPMI_AUTH_RAKP_HMAC_SHA256; + *integrity_alg = IPMI_INTEGRITY_HMAC_SHA256_128; + *crypt_alg = IPMI_CRYPT_NONE; + break; + case 17: + *auth_alg = IPMI_AUTH_RAKP_HMAC_SHA256; + *integrity_alg = IPMI_INTEGRITY_HMAC_SHA256_128; + *crypt_alg = IPMI_CRYPT_AES_CBC_128; + break; +#endif /* HAVE_CRYPTO_SHA256 */ } return 0; @@ -1022,15 +1044,34 @@ read_rakp2_message( break; case IPMI_AUTH_RAKP_HMAC_SHA1: - /* We need to copy 20 bytes */ - for (i = 0; i < 20; ++i) - rsp->payload.rakp2_message.key_exchange_auth_code[i] = - rsp->data[offset + 40 + i]; - break; + /* We need to copy 20 bytes */ + for (i = 0; i < IPMI_SHA_DIGEST_LENGTH; ++i) { + rsp->payload.rakp2_message.key_exchange_auth_code[i] = + rsp->data[offset + 40 + i]; + } + break; case IPMI_AUTH_RAKP_HMAC_MD5: - lprintf(LOG_ERR, "read_rakp2_message: no support for " - "IPMI_AUTH_RAKP_HMAC_MD5"); + /* We need to copy 16 bytes */ + for (i = 0; i < IPMI_MD5_DIGEST_LENGTH; ++i) { + rsp->payload.rakp2_message.key_exchange_auth_code[i] = + rsp->data[offset + 40 + i]; + } + break; + +#ifdef HAVE_CRYPTO_SHA256 + case IPMI_AUTH_RAKP_HMAC_SHA256: + /* We need to copy 32 bytes */ + for (i = 0; i < IPMI_SHA256_DIGEST_LENGTH; ++i) { + rsp->payload.rakp2_message.key_exchange_auth_code[i] = + rsp->data[offset + 40 + i]; + } + break; +#endif /* HAVE_CRYPTO_SHA256 */ + + default: + lprintf(LOG_ERR, "read_rakp2_message: no support " + "for authentication algorithm 0x%x", auth_alg); assert(0); break; } @@ -1088,13 +1129,32 @@ read_rakp4_message( break; case IPMI_AUTH_RAKP_HMAC_SHA1: - /* We need to copy 12 bytes */ - for (i = 0; i < 12; ++i) - rsp->payload.rakp4_message.integrity_check_value[i] = - rsp->data[offset + 8 + i]; - break; + /* We need to copy 12 bytes */ + for (i = 0; i < IPMI_SHA1_AUTHCODE_SIZE; ++i) { + rsp->payload.rakp4_message.integrity_check_value[i] = + rsp->data[offset + 8 + i]; + } + break; case IPMI_AUTH_RAKP_HMAC_MD5: + /* We need to copy 16 bytes */ + for (i = 0; i < IPMI_HMAC_MD5_AUTHCODE_SIZE; ++i) { + rsp->payload.rakp4_message.integrity_check_value[i] = + rsp->data[offset + 8 + i]; + } + break; + +#ifdef HAVE_CRYPTO_SHA256 + case IPMI_AUTH_RAKP_HMAC_SHA256: + /* We need to copy 16 bytes */ + for (i = 0; i < IPMI_HMAC_SHA256_AUTHCODE_SIZE; ++i) { + rsp->payload.rakp4_message.integrity_check_value[i] = + rsp->data[offset + 8 + i]; + } + break; +#endif /* HAVE_CRYPTO_SHA256 */ + + default: lprintf(LOG_ERR, "read_rakp4_message: no support " "for authentication algorithm 0x%x", auth_alg); assert(0); @@ -1760,7 +1820,11 @@ ipmi_lanplus_build_v2x_msg( if ((session->v2_data.session_state == LANPLUS_STATE_ACTIVE) && (session->v2_data.integrity_alg != IPMI_INTEGRITY_NONE)) { - uint32_t i, hmac_length, integrity_pad_size = 0, hmac_input_size; + uint32_t i; + uint32_t hmac_length; + uint32_t auth_length = 0; + uint32_t integrity_pad_size = 0; + uint32_t hmac_input_size; uint8_t * hmac_output; uint32_t start_of_session_trailer = IPMI_LANPLUS_OFFSET_PAYLOAD + @@ -1818,22 +1882,43 @@ ipmi_lanplus_build_v2x_msg( /* Auth Code */ lanplus_HMAC(session->v2_data.integrity_alg, session->v2_data.k1, /* key */ - 20, /* key length */ + session->v2_data.k1_len, /* key length */ msg + IPMI_LANPLUS_OFFSET_AUTHTYPE, /* hmac input */ hmac_input_size, hmac_output, &hmac_length); - assert(hmac_length == 20); + switch(session->v2_data.integrity_alg) { + case IPMI_INTEGRITY_HMAC_SHA1_96: + assert(hmac_length == IPMI_SHA_DIGEST_LENGTH); + auth_length = IPMI_SHA1_AUTHCODE_SIZE; + break; + case IPMI_INTEGRITY_HMAC_MD5_128 : + assert(hmac_length == IPMI_MD5_DIGEST_LENGTH); + auth_length = IPMI_HMAC_MD5_AUTHCODE_SIZE; + break; +#ifdef HAVE_CRYPTO_SHA256 + case IPMI_INTEGRITY_HMAC_SHA256_128: + assert(hmac_length == IPMI_SHA256_DIGEST_LENGTH); + auth_length = IPMI_HMAC_SHA256_AUTHCODE_SIZE; + break; +#endif /* HAVE_CRYPTO_SHA256 */ + default: + assert(0); + break; + } if (verbose > 2) - printbuf(hmac_output, 12, "authcode output"); + printbuf(hmac_output, auth_length, "authcode output"); /* Set session_trailer_length appropriately */ session_trailer_length = integrity_pad_size + 2 + /* pad length + next header */ - 12; /* Size of the authcode (we only use the first 12 bytes) */ + auth_length; /* Size of the authcode. We only + * use the first 12(SHA1) or + * 16(MD5/SHA256) bytes. + */ } diff --git a/src/plugins/lanplus/lanplus.h b/src/plugins/lanplus/lanplus.h index 4b6ae1e..d967462 100644 --- a/src/plugins/lanplus/lanplus.h +++ b/src/plugins/lanplus/lanplus.h @@ -96,12 +96,20 @@ #define IPMI_MAX_CONF_HEADER_SIZE 0x20 #define IPMI_MAX_PAYLOAD_SIZE 0xFFFF /* Includes confidentiality header/trailer */ #define IPMI_MAX_CONF_TRAILER_SIZE 0x20 -#define IPMI_MAX_INTEGRITY_PAD_SIZE 0x20 -#define IPMI_MAX_AUTH_CODE_SIZE 0x20 +#define IPMI_MAX_INTEGRITY_PAD_SIZE IPMI_MAX_MD_SIZE +#define IPMI_MAX_AUTH_CODE_SIZE IPMI_MAX_MD_SIZE #define IPMI_REQUEST_MESSAGE_SIZE 0x07 -#define IPMI_MAX_MAC_SIZE 0x14 /* The largest mac we ever expect to generate */ -#define IPMI_SHA1_AUTHCODE_SIZE 0x0C +#define IPMI_MAX_MAC_SIZE IPMI_MAX_MD_SIZE /* The largest mac we ever expect to generate */ + +#define IPMI_SHA1_AUTHCODE_SIZE 12 +#define IPMI_HMAC_MD5_AUTHCODE_SIZE 16 +#define IPMI_MD5_AUTHCODE_SIZE 16 +#define IPMI_HMAC_SHA256_AUTHCODE_SIZE 16 + +#define IPMI_SHA_DIGEST_LENGTH 20 +#define IPMI_MD5_DIGEST_LENGTH 16 +#define IPMI_SHA256_DIGEST_LENGTH 32 /* *This is accurate, as long as we're only passing 1 auth algorithm, @@ -109,7 +117,7 @@ */ #define IPMI_OPEN_SESSION_REQUEST_SIZE 32 #define IPMI_RAKP1_MESSAGE_SIZE 44 -#define IPMI_RAKP3_MESSAGE_MAX_SIZE 28 +#define IPMI_RAKP3_MESSAGE_MAX_SIZE (8 + IPMI_MAX_MD_SIZE) #define IPMI_MAX_USER_NAME_LENGTH 16 diff --git a/src/plugins/lanplus/lanplus_crypt.c b/src/plugins/lanplus/lanplus_crypt.c index 1cdd050..cb963f4 100644 --- a/src/plugins/lanplus/lanplus_crypt.c +++ b/src/plugins/lanplus/lanplus_crypt.c @@ -74,7 +74,7 @@ lanplus_rakp2_hmac_matches(const struct ipmi_session * session, { uint8_t * buffer; int bufferLength, i; - uint8_t mac[20]; + uint8_t mac[IPMI_MAX_MD_SIZE]; uint32_t macLength; uint32_t SIDm_lsbf, SIDc_lsbf; @@ -84,7 +84,12 @@ lanplus_rakp2_hmac_matches(const struct ipmi_session * session, return 1; /* We don't yet support other algorithms */ - assert(session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA1); + assert((session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA1) + || (session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_MD5) +#ifdef HAVE_CRYPTO_SHA256 + || (session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA256) +#endif /* HAVE_CRYPTO_SHA256 */ + ); bufferLength = @@ -228,8 +233,9 @@ lanplus_rakp4_hmac_matches(const struct ipmi_session * session, { uint8_t * buffer; int bufferLength, i; - uint8_t mac[20]; + uint8_t mac[IPMI_MAX_MD_SIZE]; uint32_t macLength; + uint32_t cmpLength; uint32_t SIDc_lsbf; if (ipmi_oem_active(intf, "intelplus")){ @@ -238,13 +244,19 @@ lanplus_rakp4_hmac_matches(const struct ipmi_session * session, return 1; /* We don't yet support other algorithms */ - assert(session->v2_data.integrity_alg == IPMI_INTEGRITY_HMAC_SHA1_96); + assert((session->v2_data.integrity_alg == IPMI_INTEGRITY_HMAC_SHA1_96) + || (session->v2_data.integrity_alg == IPMI_INTEGRITY_HMAC_MD5_128)); } else { if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE) return 1; /* We don't yet support other algorithms */ - assert(session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA1); + assert((session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA1) + || (session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_MD5) +#ifdef HAVE_CRYPTO_SHA256 + || (session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA256) +#endif /* HAVE_CRYPTO_SHA256 */ + ); } bufferLength = @@ -294,7 +306,8 @@ lanplus_rakp4_hmac_matches(const struct ipmi_session * session, if (verbose > 2) { printbuf((const uint8_t *)buffer, bufferLength, ">> rakp4 mac input buffer"); - printbuf(session->v2_data.sik, 20l, ">> rakp4 mac key (sik)"); + printbuf(session->v2_data.sik, session->v2_data.sik_len, + ">> rakp4 mac key (sik)"); } @@ -305,7 +318,7 @@ lanplus_rakp4_hmac_matches(const struct ipmi_session * session, ? session->v2_data.integrity_alg : session->v2_data.auth_alg , session->v2_data.sik, - IPMI_SIK_BUFFER_SIZE, + session->v2_data.sik_len, buffer, bufferLength, mac, @@ -317,12 +330,48 @@ lanplus_rakp4_hmac_matches(const struct ipmi_session * session, printbuf(mac, macLength, ">> rakp4 mac as computed by the remote console"); } - + if (ipmi_oem_active(intf, "intelplus")) { + /* Intel BMC responds with the integrity Algorithm in RAKP4 */ + switch(session->v2_data.integrity_alg) { + case IPMI_INTEGRITY_HMAC_SHA1_96: + assert(macLength == IPMI_SHA_DIGEST_LENGTH); + cmpLength = IPMI_SHA1_AUTHCODE_SIZE; + break; + case IPMI_INTEGRITY_HMAC_MD5_128: + assert(macLength == IPMI_MD5_DIGEST_LENGTH); + cmpLength = IPMI_HMAC_MD5_AUTHCODE_SIZE; + break; + default: + assert(0); + break; + } + } else { + /* We don't yet support other algorithms */ + switch(session->v2_data.auth_alg) { + case IPMI_AUTH_RAKP_HMAC_SHA1: + assert(macLength == IPMI_SHA_DIGEST_LENGTH); + cmpLength = IPMI_SHA1_AUTHCODE_SIZE; + break; + case IPMI_AUTH_RAKP_HMAC_MD5: + assert(macLength == IPMI_MD5_DIGEST_LENGTH); + cmpLength = IPMI_HMAC_MD5_AUTHCODE_SIZE; + break; +#ifdef HAVE_CRYPTO_SHA256 + case IPMI_AUTH_RAKP_HMAC_SHA256: + assert(macLength == IPMI_SHA256_DIGEST_LENGTH); + cmpLength = IPMI_HMAC_SHA256_AUTHCODE_SIZE; + break; +#endif /* HAVE_CRYPTO_SHA256 */ + default: + assert(0); + break; + } + } free(buffer); buffer = NULL; - assert(macLength == 20); - return (memcmp(bmc_mac, mac, 12) == 0); + assert(macLength >= cmpLength); + return (memcmp(bmc_mac, mac, cmpLength) == 0); } @@ -368,7 +417,12 @@ lanplus_generate_rakp3_authcode(uint8_t * output_buffer, } /* We don't yet support other algorithms */ - assert(session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA1); + assert((session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA1) + || (session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_MD5) +#ifdef HAVE_CRYPTO_SHA256 + || (session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA256) +#endif /* HAVE_CRYPTO_SHA256 */ + ); input_buffer_length = 16 + /* Rc */ @@ -478,13 +532,19 @@ lanplus_generate_sik(struct ipmi_session * session, struct ipmi_intf * intf) uint32_t mac_length; - memset(session->v2_data.sik, 0, IPMI_SIK_BUFFER_SIZE); + memset(session->v2_data.sik, 0, sizeof(session->v2_data.sik)); + session->v2_data.sik_len = 0; if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE) return 0; /* We don't yet support other algorithms */ - assert(session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA1); + assert((session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA1) + || (session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_MD5) +#ifdef HAVE_CRYPTO_SHA256 + || (session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA256) +#endif /* HAVE_CRYPTO_SHA256 */ + ); input_buffer_length = 16 + /* Rm */ @@ -572,15 +632,33 @@ lanplus_generate_sik(struct ipmi_session * session, struct ipmi_intf * intf) free(input_buffer); input_buffer = NULL; - assert(mac_length == 20); + switch (session->v2_data.auth_alg) { + case IPMI_AUTH_RAKP_HMAC_SHA1: + assert(mac_length == IPMI_SHA_DIGEST_LENGTH); + break; + case IPMI_AUTH_RAKP_HMAC_MD5: + assert(mac_length == IPMI_MD5_DIGEST_LENGTH); + break; +#ifdef HAVE_CRYPTO_SHA256 + case IPMI_AUTH_RAKP_HMAC_SHA256: + assert(mac_length == IPMI_SHA256_DIGEST_LENGTH); + break; +#endif /* HAVE_CRYPTO_SHA256 */ + default: + assert(0); + break; + } + + session->v2_data.sik_len = mac_length; /* * The key MAC generated is 20 bytes, but we will only be using the first * 12 for SHA1 96 */ - if (verbose >= 2) - printbuf(session->v2_data.sik, 20, "Generated session integrity key"); - + if (verbose >= 2) { + printbuf(session->v2_data.sik, session->v2_data.sik_len, + "Generated session integrity key"); + } return 0; } @@ -614,16 +692,32 @@ lanplus_generate_k1(struct ipmi_session * session) { lanplus_HMAC(session->v2_data.auth_alg, session->v2_data.sik, - IPMI_SIK_BUFFER_SIZE, /* SIK length */ + session->v2_data.sik_len, /* SIK length */ CONST_1, 20, session->v2_data.k1, &mac_length); - assert(mac_length == 20); + switch (session->v2_data.auth_alg) { + case IPMI_AUTH_RAKP_HMAC_SHA1: + assert(mac_length == IPMI_SHA_DIGEST_LENGTH); + break; + case IPMI_AUTH_RAKP_HMAC_MD5: + assert(mac_length == IPMI_MD5_DIGEST_LENGTH); + break; +#ifdef HAVE_CRYPTO_SHA256 + case IPMI_AUTH_RAKP_HMAC_SHA256: + assert(mac_length == IPMI_SHA256_DIGEST_LENGTH); + break; +#endif /* HAVE_CRYPTO_SHA256 */ + default: + assert(0); + break; + } + session->v2_data.k1_len = mac_length; } if (verbose >= 2) - printbuf(session->v2_data.k1, 20, "Generated K1"); + printbuf(session->v2_data.k1, session->v2_data.k1_len, "Generated K1"); return 0; } @@ -658,16 +752,32 @@ lanplus_generate_k2(struct ipmi_session * session) { lanplus_HMAC(session->v2_data.auth_alg, session->v2_data.sik, - IPMI_SIK_BUFFER_SIZE, /* SIK length */ + session->v2_data.sik_len, /* SIK length */ CONST_2, 20, session->v2_data.k2, &mac_length); - assert(mac_length == 20); + switch (session->v2_data.auth_alg) { + case IPMI_AUTH_RAKP_HMAC_SHA1: + assert(mac_length == IPMI_SHA_DIGEST_LENGTH); + break; + case IPMI_AUTH_RAKP_HMAC_MD5: + assert(mac_length == IPMI_MD5_DIGEST_LENGTH); + break; +#ifdef HAVE_CRYPTO_SHA256 + case IPMI_AUTH_RAKP_HMAC_SHA256: + assert(mac_length == IPMI_SHA256_DIGEST_LENGTH); + break; +#endif /* HAVE_CRYPTO_SHA256 */ + default: + assert(0); + break; + } + session->v2_data.k2_len = mac_length; } if (verbose >= 2) - printbuf(session->v2_data.k2, 20, "Generated K2"); + printbuf(session->v2_data.k2, session->v2_data.k2_len, "Generated K2"); return 0; } @@ -803,6 +913,7 @@ lanplus_has_valid_auth_code(struct ipmi_rs * rs, struct ipmi_session * session) uint8_t * bmc_authcode; uint8_t generated_authcode[IPMI_MAX_MAC_SIZE]; uint32_t generated_authcode_length; + uint32_t authcode_length; if ((rs->session.authtype != IPMI_SESSION_AUTHTYPE_RMCP_PLUS) || @@ -811,36 +922,51 @@ lanplus_has_valid_auth_code(struct ipmi_rs * rs, struct ipmi_session * session) (session->v2_data.integrity_alg == IPMI_INTEGRITY_NONE)) return 1; - /* We only support SHA1-96 now */ - assert(session->v2_data.integrity_alg == IPMI_INTEGRITY_HMAC_SHA1_96); + switch (session->v2_data.integrity_alg) { + case IPMI_INTEGRITY_HMAC_SHA1_96: + authcode_length = IPMI_SHA1_AUTHCODE_SIZE; + break; + case IPMI_INTEGRITY_HMAC_MD5_128: + authcode_length = IPMI_HMAC_MD5_AUTHCODE_SIZE; + break; +#ifdef HAVE_CRYPTO_SHA256 + case IPMI_INTEGRITY_HMAC_SHA256_128: + authcode_length = IPMI_HMAC_SHA256_AUTHCODE_SIZE; + break; +#endif /* HAVE_CRYPTO_SHA256 */ + /* Unsupported */ + default: + assert(0); + break; + } /* * For SHA1-96, the authcode will be the last 12 bytes in the packet + * For SHA256-128 or MD5-128, the authcode will be the last 16 bytes in the packet */ - bmc_authcode = rs->data + (rs->data_len - IPMI_SHA1_AUTHCODE_SIZE); + bmc_authcode = rs->data + (rs->data_len - authcode_length); lanplus_HMAC(session->v2_data.integrity_alg, session->v2_data.k1, - IPMI_AUTHCODE_BUFFER_SIZE, + session->v2_data.k1_len, rs->data + IPMI_LANPLUS_OFFSET_AUTHTYPE, - rs->data_len - IPMI_LANPLUS_OFFSET_AUTHTYPE - IPMI_SHA1_AUTHCODE_SIZE, + rs->data_len - IPMI_LANPLUS_OFFSET_AUTHTYPE - authcode_length, generated_authcode, &generated_authcode_length); if (verbose > 3) { lprintf(LOG_DEBUG+2, "Validating authcode"); - printbuf(session->v2_data.k1, 20, "K1"); + printbuf(session->v2_data.k1, session->v2_data.k1_len, "K1"); printbuf(rs->data + IPMI_LANPLUS_OFFSET_AUTHTYPE, - rs->data_len - IPMI_LANPLUS_OFFSET_AUTHTYPE - IPMI_SHA1_AUTHCODE_SIZE, + rs->data_len - IPMI_LANPLUS_OFFSET_AUTHTYPE - authcode_length, "Authcode Input Data"); - printbuf(generated_authcode, 12, "Generated authcode"); - printbuf(bmc_authcode, 12, "Expected authcode"); + printbuf(generated_authcode, generated_authcode_length, "Generated authcode"); + printbuf(bmc_authcode, authcode_length, "Expected authcode"); } - - assert(generated_authcode_length == 20); - return (memcmp(bmc_authcode, generated_authcode, 12) == 0); + assert(generated_authcode_length >= authcode_length); + return (memcmp(bmc_authcode, generated_authcode, authcode_length) == 0); } diff --git a/src/plugins/lanplus/lanplus_crypt_impl.c b/src/plugins/lanplus/lanplus_crypt_impl.c index cde6c54..d5fac37 100644 --- a/src/plugins/lanplus/lanplus_crypt_impl.c +++ b/src/plugins/lanplus/lanplus_crypt_impl.c @@ -99,7 +99,8 @@ lanplus_rand(uint8_t * buffer, uint32_t num_bytes) /* * lanplus_HMAC * - * param mac specifies the algorithm to be used, currently only SHA1 is supported + * param mac specifies the algorithm to be used, currently SHA1, SHA256 and MD5 + * are supported * param key is the key used for HMAC generation * param key_len is the lenght of key * param d is the data to be MAC'd @@ -123,6 +124,14 @@ lanplus_HMAC(uint8_t mac, if ((mac == IPMI_AUTH_RAKP_HMAC_SHA1) || (mac == IPMI_INTEGRITY_HMAC_SHA1_96)) evp_md = EVP_sha1(); + else if ((mac == IPMI_AUTH_RAKP_HMAC_MD5) || + (mac == IPMI_INTEGRITY_HMAC_MD5_128)) + evp_md = EVP_md5(); +#ifdef HAVE_CRYPTO_SHA256 + else if ((mac == IPMI_AUTH_RAKP_HMAC_SHA256) || + (mac == IPMI_INTEGRITY_HMAC_SHA256_128)) + evp_md = EVP_sha256(); +#endif /* HAVE_CRYPTO_SHA256 */ else { lprintf(LOG_DEBUG, "Invalid mac type 0x%x in lanplus_HMAC\n", mac); diff --git a/src/plugins/lanplus/lanplus_dump.c b/src/plugins/lanplus/lanplus_dump.c index 8d52fab..bbfc1b0 100644 --- a/src/plugins/lanplus/lanplus_dump.c +++ b/src/plugins/lanplus/lanplus_dump.c @@ -31,6 +31,7 @@ */ #include "lanplus.h" +#include "lanplus_crypt.h" #include "lanplus_dump.h" extern const struct valstr ipmi_rakp_return_codes[]; @@ -127,16 +128,27 @@ void lanplus_dump_rakp2_message(const struct ipmi_rs * rsp, uint8_t auth_alg) break; case IPMI_AUTH_RAKP_HMAC_SHA1: printf("%s Key exchange auth code [sha1] : 0x", DUMP_PREFIX_INCOMING); - for (i = 0; i < 20; ++i) + for (i = 0; i < IPMI_SHA_DIGEST_LENGTH; ++i) { printf("%02x", rsp->payload.rakp2_message.key_exchange_auth_code[i]); - printf("\n"); + } + printf("\n"); break; case IPMI_AUTH_RAKP_HMAC_MD5: printf("%s Key exchange auth code [md5] : 0x", DUMP_PREFIX_INCOMING); - for (i = 0; i < 16; ++i) + for (i = 0; i < IPMI_MD5_DIGEST_LENGTH; ++i) { printf("%02x", rsp->payload.rakp2_message.key_exchange_auth_code[i]); - printf("\n"); + } + printf("\n"); break; +#ifdef HAVE_CRYPTO_SHA256 + case IPMI_AUTH_RAKP_HMAC_SHA256: + printf("%s Key exchange auth code [sha256]: 0x", DUMP_PREFIX_INCOMING); + for (i = 0; i < IPMI_SHA256_DIGEST_LENGTH; ++i) { + printf("%02x", rsp->payload.rakp2_message.key_exchange_auth_code[i]); + } + printf("\n"); + break; +#endif /* HAVE_CRYPTO_SHA256 */ default: printf("%s Key exchange auth code : invalid", DUMP_PREFIX_INCOMING); } @@ -174,16 +186,27 @@ void lanplus_dump_rakp4_message(const struct ipmi_rs * rsp, uint8_t auth_alg) break; case IPMI_AUTH_RAKP_HMAC_SHA1: printf("%s Key exchange auth code [sha1] : 0x", DUMP_PREFIX_INCOMING); - for (i = 0; i < 12; ++i) + for (i = 0; i < IPMI_SHA1_AUTHCODE_SIZE; ++i) { printf("%02x", rsp->payload.rakp4_message.integrity_check_value[i]); - printf("\n"); + } + printf("\n"); break; case IPMI_AUTH_RAKP_HMAC_MD5: printf("%s Key exchange auth code [md5] : 0x", DUMP_PREFIX_INCOMING); - for (i = 0; i < 12; ++i) + for (i = 0; i < IPMI_HMAC_MD5_AUTHCODE_SIZE; ++i) { printf("%02x", rsp->payload.rakp4_message.integrity_check_value[i]); - printf("\n"); + } + printf("\n"); break; +#ifdef HAVE_CRYPTO_SHA256 + case IPMI_AUTH_RAKP_HMAC_SHA256: + printf("%s Key exchange auth code [sha256]: 0x", DUMP_PREFIX_INCOMING); + for (i = 0; i < IPMI_HMAC_SHA256_AUTHCODE_SIZE; ++i) { + printf("%02x", rsp->payload.rakp4_message.integrity_check_value[i]); + } + printf("\n"); + break; +#endif /* HAVE_CRYPTO_SHA256 */ default: printf("%s Key exchange auth code : invalid", DUMP_PREFIX_INCOMING); }