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:
Alexander Amelkin 2018-11-01 19:25:51 +03:00 committed by Alexander Amelkin
parent 1283382e82
commit 65a2c548d8
5 changed files with 148 additions and 94 deletions

View File

@ -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*/

View File

@ -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),

View File

@ -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, &params->authcode_set, sizeof(session->authcode)); memcpy(&session->authcode,
&params->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;