mirror of
https://github.com/ipmitool/ipmitool.git
synced 2025-05-10 18:47:22 +00:00
lanplus: Refactoring
Some minor formatting corrections. Also introduced a new helper function to reduce nesting level. Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
This commit is contained in:
parent
1283382e82
commit
65a2c548d8
@ -176,18 +176,23 @@ struct get_channel_auth_cap_rsp {
|
|||||||
int _ipmi_get_channel_access(struct ipmi_intf *intf,
|
int _ipmi_get_channel_access(struct ipmi_intf *intf,
|
||||||
struct channel_access_t *channel_access,
|
struct channel_access_t *channel_access,
|
||||||
uint8_t get_volatile_settings);
|
uint8_t get_volatile_settings);
|
||||||
int ipmi_get_channel_cipher_suites(struct ipmi_intf *intf, const char *payload_type,
|
int ipmi_get_channel_cipher_suites(struct ipmi_intf *intf,
|
||||||
uint8_t channel, struct cipher_suite_info *suites, size_t *count);
|
const char *payload_type,
|
||||||
|
uint8_t channel,
|
||||||
|
struct cipher_suite_info *suites,
|
||||||
|
size_t *count);
|
||||||
int _ipmi_get_channel_info(struct ipmi_intf *intf,
|
int _ipmi_get_channel_info(struct ipmi_intf *intf,
|
||||||
struct channel_info_t *channel_info);
|
struct channel_info_t *channel_info);
|
||||||
int _ipmi_set_channel_access(struct ipmi_intf *intf,
|
int _ipmi_set_channel_access(struct ipmi_intf *intf,
|
||||||
struct channel_access_t channel_access, uint8_t access_option,
|
struct channel_access_t channel_access,
|
||||||
|
uint8_t access_option,
|
||||||
uint8_t privilege_option);
|
uint8_t privilege_option);
|
||||||
|
|
||||||
uint8_t ipmi_get_channel_medium(struct ipmi_intf * intf, uint8_t channel);
|
uint8_t ipmi_get_channel_medium(struct ipmi_intf * intf, uint8_t channel);
|
||||||
uint8_t ipmi_current_channel_medium(struct ipmi_intf * intf);
|
uint8_t ipmi_current_channel_medium(struct ipmi_intf * intf);
|
||||||
int ipmi_channel_main(struct ipmi_intf * intf, int argc, char ** argv);
|
int ipmi_channel_main(struct ipmi_intf * intf, int argc, char ** argv);
|
||||||
int ipmi_get_channel_auth_cap(struct ipmi_intf * intf, uint8_t channel, uint8_t priv);
|
int ipmi_get_channel_auth_cap(struct ipmi_intf * intf,
|
||||||
|
uint8_t channel, uint8_t priv);
|
||||||
int ipmi_get_channel_info(struct ipmi_intf * intf, uint8_t channel);
|
int ipmi_get_channel_info(struct ipmi_intf * intf, uint8_t channel);
|
||||||
|
|
||||||
#endif /*IPMI_CHANNEL_H*/
|
#endif /*IPMI_CHANNEL_H*/
|
||||||
|
@ -342,75 +342,108 @@ ipmi_get_channel_auth_cap(struct ipmi_intf *intf, uint8_t channel, uint8_t priv)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t
|
static inline size_t parse_cipher_suite(uint8_t *cipher_suite_data,
|
||||||
parse_channel_cipher_suite_data(uint8_t *cipher_suite_data, size_t data_len,
|
size_t data_len,
|
||||||
struct cipher_suite_info* suites, size_t nr_suites)
|
uint32_t *iana,
|
||||||
|
uint8_t *auth_alg,
|
||||||
|
uint8_t *integrity_alg,
|
||||||
|
uint8_t *crypt_alg,
|
||||||
|
enum cipher_suite_ids *cipher_suite_id)
|
||||||
{
|
{
|
||||||
size_t count = 0;
|
size_t size = 0;
|
||||||
size_t offset = 0;
|
const char *incomplete = "Incomplete data record in cipher suite data";
|
||||||
uint32_t iana;
|
|
||||||
uint8_t auth_alg, integrity_alg, crypt_alg;
|
|
||||||
uint8_t cipher_suite_id;
|
|
||||||
|
|
||||||
memset(suites, 0, sizeof(*suites) * nr_suites);
|
if (*cipher_suite_data == STANDARD_CIPHER_SUITE) {
|
||||||
|
|
||||||
while (offset < data_len && count < nr_suites) {
|
|
||||||
auth_alg = IPMI_AUTH_RAKP_NONE;
|
|
||||||
integrity_alg = IPMI_INTEGRITY_NONE;
|
|
||||||
crypt_alg = IPMI_CRYPT_NONE;
|
|
||||||
if (cipher_suite_data[offset] == STANDARD_CIPHER_SUITE) {
|
|
||||||
struct std_cipher_suite_record_t *record =
|
struct std_cipher_suite_record_t *record =
|
||||||
(struct std_cipher_suite_record_t*)(&cipher_suite_data[offset]);
|
(struct std_cipher_suite_record_t*)cipher_suite_data;
|
||||||
/* standard type */
|
|
||||||
iana = 0;
|
|
||||||
|
|
||||||
/* Verify that we have at least a full record left; id + 3 algs */
|
/* Verify that we have at least a full record left; id + 3 algs */
|
||||||
if ((data_len - offset) < sizeof(*record)) {
|
if (data_len < sizeof(*record)) {
|
||||||
lprintf(LOG_INFO, "Incomplete data record in cipher suite data");
|
lprintf(LOG_INFO, "%s", incomplete);
|
||||||
break;
|
goto out;
|
||||||
}
|
}
|
||||||
cipher_suite_id = record->cipher_suite_id;
|
|
||||||
auth_alg = CIPHER_ALG_MASK & record->auth_alg;
|
/* IANA code remains default (0) */
|
||||||
integrity_alg = CIPHER_ALG_MASK & record->integrity_alg;
|
*cipher_suite_id = record->cipher_suite_id;
|
||||||
crypt_alg = CIPHER_ALG_MASK & record->crypt_alg;
|
*auth_alg = CIPHER_ALG_MASK & record->auth_alg;
|
||||||
offset += sizeof(*record);
|
*integrity_alg = CIPHER_ALG_MASK & record->integrity_alg;
|
||||||
} else if (cipher_suite_data[offset] == OEM_CIPHER_SUITE) {
|
*crypt_alg = CIPHER_ALG_MASK & record->crypt_alg;
|
||||||
|
size = sizeof(*record);
|
||||||
|
} else if (*cipher_suite_data == OEM_CIPHER_SUITE) {
|
||||||
/* OEM record type */
|
/* OEM record type */
|
||||||
struct oem_cipher_suite_record_t *record =
|
struct oem_cipher_suite_record_t *record =
|
||||||
(struct oem_cipher_suite_record_t*)(&cipher_suite_data[offset]);
|
(struct oem_cipher_suite_record_t*)cipher_suite_data;
|
||||||
/* Verify that we have at least a full record left
|
/* Verify that we have at least a full record left
|
||||||
* id + iana + 3 algs
|
* id + iana + 3 algs
|
||||||
*/
|
*/
|
||||||
if ((data_len - offset) < sizeof(*record)) {
|
if (data_len < sizeof(*record)) {
|
||||||
lprintf(LOG_INFO, "Incomplete data record in cipher suite data");
|
lprintf(LOG_INFO, "%s", incomplete);
|
||||||
break;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
cipher_suite_id = record->cipher_suite_id;
|
|
||||||
|
|
||||||
/* Grab the IANA */
|
/* Grab the IANA */
|
||||||
iana = ipmi24toh(record->iana);
|
*iana = ipmi24toh(record->iana);
|
||||||
auth_alg = CIPHER_ALG_MASK & record->auth_alg;
|
*cipher_suite_id = record->cipher_suite_id;
|
||||||
integrity_alg = CIPHER_ALG_MASK & record->integrity_alg;
|
*auth_alg = CIPHER_ALG_MASK & record->auth_alg;
|
||||||
crypt_alg = CIPHER_ALG_MASK & record->crypt_alg;
|
*integrity_alg = CIPHER_ALG_MASK & record->integrity_alg;
|
||||||
offset += sizeof(*record);
|
*crypt_alg = CIPHER_ALG_MASK & record->crypt_alg;
|
||||||
|
size = sizeof(*record);
|
||||||
} else {
|
} else {
|
||||||
lprintf(LOG_INFO, "Bad start of record byte in cipher suite data (offset %d, value %x)", offset, cipher_suite_data[offset]);
|
lprintf(LOG_INFO, "Bad start of record byte in cipher suite data "
|
||||||
|
"(value %x)", *cipher_suite_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
parse_channel_cipher_suite_data(uint8_t *cipher_suite_data, size_t data_len,
|
||||||
|
struct cipher_suite_info* suites,
|
||||||
|
size_t nr_suites)
|
||||||
|
{
|
||||||
|
size_t count = 0;
|
||||||
|
size_t offset = 0;
|
||||||
|
|
||||||
|
/* Default everything to zeroes */
|
||||||
|
memset(suites, 0, sizeof(*suites) * nr_suites);
|
||||||
|
|
||||||
|
while (offset < data_len && count < nr_suites) {
|
||||||
|
size_t suite_size;
|
||||||
|
|
||||||
|
/* Set non-zero defaults */
|
||||||
|
suites[count].auth_alg = IPMI_AUTH_RAKP_NONE;
|
||||||
|
suites[count].integrity_alg = IPMI_INTEGRITY_NONE;
|
||||||
|
suites[count].crypt_alg = IPMI_CRYPT_NONE;
|
||||||
|
|
||||||
|
/* Update fields from cipher suite data */
|
||||||
|
suite_size = parse_cipher_suite(cipher_suite_data + offset,
|
||||||
|
data_len - offset,
|
||||||
|
&suites[count].iana,
|
||||||
|
&suites[count].auth_alg,
|
||||||
|
&suites[count].integrity_alg,
|
||||||
|
&suites[count].crypt_alg,
|
||||||
|
&suites[count].cipher_suite_id);
|
||||||
|
|
||||||
|
if (!suite_size) {
|
||||||
|
lprintf(LOG_INFO,
|
||||||
|
"Failed to parse cipher suite data at offset %d",
|
||||||
|
offset);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
suites[count].cipher_suite_id = cipher_suite_id;
|
|
||||||
suites[count].iana = iana;
|
offset += suite_size;
|
||||||
suites[count].auth_alg = auth_alg;
|
|
||||||
suites[count].integrity_alg = integrity_alg;
|
|
||||||
suites[count].crypt_alg = crypt_alg;
|
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
ipmi_get_channel_cipher_suites(struct ipmi_intf *intf, const char *payload_type,
|
ipmi_get_channel_cipher_suites(struct ipmi_intf *intf,
|
||||||
uint8_t channel, struct cipher_suite_info *suites, size_t *count)
|
const char *payload_type,
|
||||||
|
uint8_t channel,
|
||||||
|
struct cipher_suite_info *suites,
|
||||||
|
size_t *count)
|
||||||
{
|
{
|
||||||
struct ipmi_rs *rsp;
|
struct ipmi_rs *rsp;
|
||||||
struct ipmi_rq req;
|
struct ipmi_rq req;
|
||||||
@ -464,8 +497,8 @@ ipmi_get_channel_cipher_suites(struct ipmi_intf *intf, const char *payload_type,
|
|||||||
* Increment our list for the next call
|
* Increment our list for the next call
|
||||||
*/
|
*/
|
||||||
++list_index;
|
++list_index;
|
||||||
} while ((rsp->data_len == (sizeof(uint8_t) + MAX_CIPHER_SUITE_DATA_LEN)) &&
|
} while ((rsp->data_len == (sizeof(uint8_t) + MAX_CIPHER_SUITE_DATA_LEN))
|
||||||
(list_index < MAX_CIPHER_SUITE_RECORD_OFFSET));
|
&& (list_index < MAX_CIPHER_SUITE_RECORD_OFFSET));
|
||||||
|
|
||||||
*count = parse_channel_cipher_suite_data(cipher_suite_data, offset, suites,
|
*count = parse_channel_cipher_suite_data(cipher_suite_data, offset, suites,
|
||||||
nr_suites);
|
nr_suites);
|
||||||
@ -473,13 +506,16 @@ ipmi_get_channel_cipher_suites(struct ipmi_intf *intf, const char *payload_type,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ipmi_print_channel_cipher_suites(struct ipmi_intf *intf, const char *payload_type,
|
ipmi_print_channel_cipher_suites(struct ipmi_intf *intf,
|
||||||
|
const char *payload_type,
|
||||||
uint8_t channel)
|
uint8_t channel)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
struct cipher_suite_info suites[MAX_CIPHER_SUITE_COUNT];
|
struct cipher_suite_info suites[MAX_CIPHER_SUITE_COUNT];
|
||||||
size_t nr_suites = sizeof(*suites);
|
size_t nr_suites = sizeof(*suites);
|
||||||
|
const char *header_str =
|
||||||
|
"ID IANA Auth Alg Integrity Alg Confidentiality Alg";
|
||||||
|
|
||||||
rc = ipmi_get_channel_cipher_suites(intf, payload_type, channel,
|
rc = ipmi_get_channel_cipher_suites(intf, payload_type, channel,
|
||||||
suites, &nr_suites);
|
suites, &nr_suites);
|
||||||
@ -487,13 +523,13 @@ ipmi_print_channel_cipher_suites(struct ipmi_intf *intf, const char *payload_typ
|
|||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
if (! csv_output) {
|
if (!csv_output) {
|
||||||
printf("ID IANA Auth Alg Integrity Alg Confidentiality Alg\n");
|
printf("%s\n", header_str);
|
||||||
}
|
}
|
||||||
for (i = 0; i < nr_suites; i++) {
|
for (i = 0; i < nr_suites; i++) {
|
||||||
/* We have everything we need to spit out a cipher suite record */
|
/* We have everything we need to spit out a cipher suite record */
|
||||||
printf((csv_output? "%d,%s,%s,%s,%s\n" :
|
printf(csv_output ? "%d,%s,%s,%s,%s\n"
|
||||||
"%-4d %-7s %-15s %-15s %-15s\n"),
|
: "%-4d %-7s %-15s %-15s %-15s\n",
|
||||||
suites[i].cipher_suite_id,
|
suites[i].cipher_suite_id,
|
||||||
iana_string(suites[i].iana),
|
iana_string(suites[i].iana),
|
||||||
val2str(suites[i].auth_alg, ipmi_auth_algorithms),
|
val2str(suites[i].auth_alg, ipmi_auth_algorithms),
|
||||||
|
@ -163,10 +163,11 @@ extern int verbose;
|
|||||||
* returns 0 on success
|
* returns 0 on success
|
||||||
* 1 on failure
|
* 1 on failure
|
||||||
*/
|
*/
|
||||||
int lanplus_get_requested_ciphers(enum cipher_suite_ids cipher_suite_id,
|
int
|
||||||
uint8_t * auth_alg,
|
lanplus_get_requested_ciphers(enum cipher_suite_ids cipher_suite_id,
|
||||||
uint8_t * integrity_alg,
|
uint8_t *auth_alg,
|
||||||
uint8_t * crypt_alg)
|
uint8_t *integrity_alg,
|
||||||
|
uint8_t *crypt_alg)
|
||||||
{
|
{
|
||||||
/* See table 22-19 for the source of the statement */
|
/* See table 22-19 for the source of the statement */
|
||||||
switch (cipher_suite_id)
|
switch (cipher_suite_id)
|
||||||
@ -3383,15 +3384,16 @@ ipmi_find_best_cipher_suite(struct ipmi_intf *intf)
|
|||||||
#ifdef HAVE_CRYPTO_SHA256
|
#ifdef HAVE_CRYPTO_SHA256
|
||||||
struct cipher_suite_info suites[MAX_CIPHER_SUITE_COUNT];
|
struct cipher_suite_info suites[MAX_CIPHER_SUITE_COUNT];
|
||||||
size_t nr_suites = ARRAY_SIZE(suites);
|
size_t nr_suites = ARRAY_SIZE(suites);
|
||||||
|
|
||||||
/* cipher suite best order is chosen with this criteria:
|
/* cipher suite best order is chosen with this criteria:
|
||||||
* HMAC-MD5 and MD5 are BAD; xRC4 is bad; AES128 is required
|
* HMAC-MD5 and MD5 are BAD; xRC4 is bad; AES128 is required
|
||||||
* HMAC-SHA256 > HMAC-SHA1
|
* HMAC-SHA256 > HMAC-SHA1
|
||||||
* secure authentication > encrypted content
|
* secure authentication > encrypted content
|
||||||
*
|
*
|
||||||
* With xRC4 out, all cipher suites with MD5 out, and cipher suite 3 being
|
* With xRC4 out, all cipher suites with MD5 out, and cipher suite 3
|
||||||
* required by the spec, the only better defined standard cipher suite is
|
* being required by the spec, the only better defined standard cipher
|
||||||
* 17. So if SHA256 is available, we should try to use that, otherwise,
|
* suite is 17. So if SHA256 is available, we should try to use that,
|
||||||
* fall back to 3.
|
* otherwise, fall back to 3.
|
||||||
*/
|
*/
|
||||||
const enum cipher_suite_ids cipher_order_preferred[] = {
|
const enum cipher_suite_ids cipher_order_preferred[] = {
|
||||||
IPMI_LANPLUS_CIPHER_SUITE_17,
|
IPMI_LANPLUS_CIPHER_SUITE_17,
|
||||||
@ -3403,14 +3405,18 @@ ipmi_find_best_cipher_suite(struct ipmi_intf *intf)
|
|||||||
if (ipmi_get_channel_cipher_suites(intf, "ipmi", IPMI_LAN_CHANNEL_E,
|
if (ipmi_get_channel_cipher_suites(intf, "ipmi", IPMI_LAN_CHANNEL_E,
|
||||||
suites, &nr_suites) < 0)
|
suites, &nr_suites) < 0)
|
||||||
{
|
{
|
||||||
/* default legacy behavior - cipher suite 3 if none is requested */
|
/* default legacy behavior - fall back to cipher suite 3 */
|
||||||
return IPMI_LANPLUS_CIPHER_SUITE_3;
|
return IPMI_LANPLUS_CIPHER_SUITE_3;
|
||||||
}
|
}
|
||||||
for (ipref = 0; ipref < nr_preferred &&
|
for (ipref = 0;
|
||||||
IPMI_LANPLUS_CIPHER_SUITE_RESERVED == best_suite; ipref++)
|
ipref < nr_preferred &&
|
||||||
|
IPMI_LANPLUS_CIPHER_SUITE_RESERVED == best_suite;
|
||||||
|
ipref++)
|
||||||
{
|
{
|
||||||
for (i = 0; i < nr_suites; i++) {
|
for (i = 0; i < nr_suites; i++) {
|
||||||
if (cipher_order_preferred[ipref] == suites[i].cipher_suite_id) {
|
if (cipher_order_preferred[ipref]
|
||||||
|
== suites[i].cipher_suite_id)
|
||||||
|
{
|
||||||
best_suite = cipher_order_preferred[ipref];
|
best_suite = cipher_order_preferred[ipref];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3477,7 +3483,9 @@ ipmi_lanplus_open(struct ipmi_intf * intf)
|
|||||||
/* Setup our lanplus session state */
|
/* Setup our lanplus session state */
|
||||||
memset(session, 0, sizeof(struct ipmi_session));
|
memset(session, 0, sizeof(struct ipmi_session));
|
||||||
session->timeout = params->timeout;
|
session->timeout = params->timeout;
|
||||||
memcpy(&session->authcode, ¶ms->authcode_set, sizeof(session->authcode));
|
memcpy(&session->authcode,
|
||||||
|
¶ms->authcode_set,
|
||||||
|
sizeof(session->authcode));
|
||||||
session->v2_data.auth_alg = IPMI_AUTH_RAKP_NONE;
|
session->v2_data.auth_alg = IPMI_AUTH_RAKP_NONE;
|
||||||
session->v2_data.crypt_alg = IPMI_CRYPT_NONE;
|
session->v2_data.crypt_alg = IPMI_CRYPT_NONE;
|
||||||
session->sol_data.sequence_number = 1;
|
session->sol_data.sequence_number = 1;
|
||||||
@ -3496,25 +3504,30 @@ ipmi_lanplus_open(struct ipmi_intf * intf)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ipmi_oem_active(intf, "i82571spt") && ! auth_cap.v20_data_available) {
|
if (!ipmi_oem_active(intf, "i82571spt") &&
|
||||||
|
!auth_cap.v20_data_available)
|
||||||
|
{
|
||||||
lprintf(LOG_INFO, "This BMC does not support IPMI v2 / RMCP+");
|
lprintf(LOG_INFO, "This BMC does not support IPMI v2 / RMCP+");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If no cipher suite was provided, query the channel cipher suite list and
|
* If no cipher suite was provided, query the channel cipher suite list
|
||||||
* pick the best one available
|
* and pick the best one available
|
||||||
*/
|
*/
|
||||||
if (IPMI_LANPLUS_CIPHER_SUITE_RESERVED ==
|
if (IPMI_LANPLUS_CIPHER_SUITE_RESERVED ==
|
||||||
intf->ssn_params.cipher_suite_id)
|
intf->ssn_params.cipher_suite_id)
|
||||||
{
|
{
|
||||||
ipmi_intf_session_set_cipher_suite_id(intf,
|
ipmi_intf_session_set_cipher_suite_id(
|
||||||
ipmi_find_best_cipher_suite(intf));
|
intf,
|
||||||
|
ipmi_find_best_cipher_suite(intf)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the open/rakp1/rakp3 sequence encounters a timeout, the whole sequence
|
* If the open/rakp1/rakp3 sequence encounters a timeout, the whole
|
||||||
* needs to restart. The individual messages are not individually retryable,
|
* sequence needs to restart. The individual messages are not
|
||||||
* as the session state is advancing.
|
* individually retryable, as the session state is advancing.
|
||||||
*/
|
*/
|
||||||
for (retry = 0; retry < IPMI_LAN_RETRY; retry++) {
|
for (retry = 0; retry < IPMI_LAN_RETRY; retry++) {
|
||||||
session->v2_data.session_state = LANPLUS_STATE_PRESESSION;
|
session->v2_data.session_state = LANPLUS_STATE_PRESESSION;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user