4
* MontaVista RMCP+ code for handling RAKP algorithms
6
* Author: MontaVista Software, Inc.
7
* Corey Minyard <minyard@mvista.com>
10
* Copyright 2004 MontaVista Software Inc.
12
* This program is free software; you can redistribute it and/or
13
* modify it under the terms of the GNU Lesser General Public License
14
* as published by the Free Software Foundation; either version 2 of
15
* the License, or (at your option) any later version.
18
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
19
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
26
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
27
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
* You should have received a copy of the GNU Lesser General Public
30
* License along with this program; if not, write to the Free
31
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
36
#include <OpenIPMI/ipmi_conn.h>
37
#include <OpenIPMI/ipmi_msgbits.h>
38
#include <OpenIPMI/ipmi_auth.h>
39
#include <OpenIPMI/ipmi_err.h>
40
#include <OpenIPMI/ipmi_lan.h>
42
#include <OpenIPMI/internal/ipmi_int.h>
44
typedef struct rakp_info_s rakp_info_t;
46
typedef int (*init_cb)(rakp_info_t *info);
47
typedef void (*cleanup_cb)(rakp_info_t *info);
48
typedef int (*check_cb)(rakp_info_t *info,
50
unsigned int data_len);
51
typedef int (*set_cb)(rakp_info_t *info,
53
unsigned int *data_len,
54
unsigned int total_len);
58
ipmi_rmcpp_auth_t *ainfo;
60
ipmi_rmcpp_set_info_cb set;
61
ipmi_rmcpp_finish_auth_cb done;
66
unsigned char msg_tag;
70
/* Check an set the auth keys for the various rakp messages. The
71
data passed in is the whole message. For set3, the data_len
72
points to the current message size and total_len is the
73
total_len available. It should update data_len to the actual
74
length. These functions may be NULL and will not be used. */
82
rakp_done(rakp_info_t *info,
87
info->done(ipmi, err, addr_num, info->cb_data);
94
check_rakp_rsp(ipmi_con_t *ipmi,
98
unsigned int min_length,
105
if (msg->data_len < 2) {
106
ipmi_log(IPMI_LOG_ERR_INFO,
107
"rakp.c(%s): Message data too short: %d",
108
caller, msg->data_len);
113
/* Got an RMCP+ error. */
114
return IPMI_RMCPP_ERR_VAL(msg->data[1]);
117
if (msg->data_len < min_length) {
118
ipmi_log(IPMI_LOG_ERR_INFO,
119
"rakp.c(%s): Message data too short: %d",
120
caller, msg->data_len);
128
handle_rakp4(ipmi_con_t *ipmi, ipmi_msgi_t *rspi)
130
ipmi_msg_t *msg = &rspi->msg;
131
rakp_info_t *info = rspi->data1;
132
int addr_num = (long) rspi->data4;
136
/* In this function, there's not way to report the error to the
137
managed system, just report it locally. */
139
rv = check_rakp_rsp(ipmi, info, msg, "handle_rakp4", 8, addr_num);
144
rv = info->check4(info, msg->data, msg->data_len);
149
session_id = ipmi_get_uint32(msg->data+4);
150
if (session_id != ipmi_rmcpp_auth_get_my_session_id(info->ainfo)) {
151
ipmi_log(IPMI_LOG_ERR_INFO,
152
"rakp.c(handle_rakp4): "
153
" Got wrong session id: 0x%x",
159
rakp_done(info, ipmi, addr_num, 0);
160
return IPMI_MSG_ITEM_NOT_USED;
163
rakp_done(info, ipmi, addr_num, rv);
164
return IPMI_MSG_ITEM_NOT_USED;
168
send_rakp3(ipmi_con_t *ipmi, rakp_info_t *info,
169
ipmi_msgi_t *rspi, int addr_num, int err)
172
unsigned char data[64];
174
ipmi_rmcpp_addr_t addr;
176
memset(data, 0, sizeof(data));
177
data[0] = info->msg_tag;
179
ipmi_set_uint32(data+4, ipmi_rmcpp_auth_get_mgsys_session_id(info->ainfo));
181
msg.netfn = IPMI_RMCPP_DUMMY_NETFN;
185
addr.addr_type = IPMI_RMCPP_ADDR_START + IPMI_RMCPP_PAYLOAD_TYPE_RAKP_3;
191
rv = info->set3(info, data, &len, sizeof(data));
198
/* Don't handle the responst (if one comes back) on an error. */
199
rv = ipmi_lan_send_command_forceip(ipmi, addr_num,
200
(ipmi_addr_t *) &addr, sizeof(addr),
203
rv = ipmi_lan_send_command_forceip(ipmi, addr_num,
204
(ipmi_addr_t *) &addr, sizeof(addr),
205
&msg, handle_rakp4, rspi);
210
handle_rakp2(ipmi_con_t *ipmi, ipmi_msgi_t *rspi)
212
ipmi_msg_t *msg = &rspi->msg;
213
rakp_info_t *info = rspi->data1;
214
int addr_num = (long) rspi->data4;
221
rv = check_rakp_rsp(ipmi, info, msg, "handle_rakp2", 40, addr_num);
223
err = IPMI_RMCPP_ILLEGAL_PARAMETER;
227
p = ipmi_rmcpp_auth_get_mgsys_rand(info->ainfo, &plen);
230
memcpy(p, msg->data+8, 16);
231
ipmi_rmcpp_auth_set_mgsys_rand_len(info->ainfo, 16);
233
p = ipmi_rmcpp_auth_get_mgsys_guid(info->ainfo, &plen);
236
memcpy(p, msg->data+24, 16);
237
ipmi_rmcpp_auth_set_mgsys_guid_len(info->ainfo, 16);
239
session_id = ipmi_get_uint32(msg->data+4);
240
if (session_id != ipmi_rmcpp_auth_get_my_session_id(info->ainfo)) {
241
ipmi_log(IPMI_LOG_ERR_INFO,
242
"rakp.c(handle_rakp2): "
243
" Got wrong session id: 0x%x",
245
err = IPMI_RMCPP_INVALID_SESSION_ID;
250
rv = info->check2(info, msg->data, msg->data_len);
252
if (DEBUG_RAWMSG || DEBUG_MSG_ERR)
253
ipmi_log(IPMI_LOG_DEBUG, "Integrity check fail for rakp 2");
254
err = IPMI_RMCPP_INVALID_INTEGRITY_CHECK_VALUE;
259
rv = info->set(ipmi, addr_num, info->ainfo, info->cb_data);
261
if (DEBUG_RAWMSG || DEBUG_MSG_ERR)
262
ipmi_log(IPMI_LOG_DEBUG, "Error setting values from rakp 2");
263
err = IPMI_RMCPP_INSUFFICIENT_RESOURCES_FOR_SESSION;
267
rv = send_rakp3(ipmi, info, rspi, addr_num, 0);
269
if (DEBUG_RAWMSG || DEBUG_MSG_ERR)
270
ipmi_log(IPMI_LOG_DEBUG, "Error sending rakp 3");
271
err = IPMI_RMCPP_INSUFFICIENT_RESOURCES_FOR_SESSION;
275
return IPMI_MSG_ITEM_USED;
278
rv = send_rakp3(ipmi, info, rspi, addr_num, err);
279
rakp_done(info, ipmi, addr_num, rv);
281
return IPMI_MSG_ITEM_NOT_USED;
283
/* Yes, we use it to send the error response. */
284
return IPMI_MSG_ITEM_USED;
288
send_rakp1(ipmi_con_t *ipmi, rakp_info_t *info,
289
ipmi_msgi_t *rspi, int addr_num)
292
unsigned char data[44];
294
ipmi_rmcpp_addr_t addr;
295
const unsigned char *p;
298
memset(data, 0, sizeof(data));
299
data[0] = info->msg_tag;
300
ipmi_set_uint32(data+4, ipmi_rmcpp_auth_get_mgsys_session_id(info->ainfo));
302
p = ipmi_rmcpp_auth_get_my_rand(info->ainfo, &plen);
305
memcpy(data+8, p, 16);
307
data[24] = ipmi_rmcpp_auth_get_role(info->ainfo);
308
data[27] = ipmi_rmcpp_auth_get_username_len(info->ainfo);
309
p = ipmi_rmcpp_auth_get_username(info->ainfo, &plen);
312
memcpy(data+28, p, data[27]);
314
msg.netfn = IPMI_RMCPP_DUMMY_NETFN;
317
msg.data_len = 28 + data[27];
318
addr.addr_type = IPMI_RMCPP_ADDR_START + IPMI_RMCPP_PAYLOAD_TYPE_RAKP_1;
321
rv = ipmi_lan_send_command_forceip(ipmi, addr_num,
322
(ipmi_addr_t *) &addr, sizeof(addr),
323
&msg, handle_rakp2, rspi);
328
start_rakp(ipmi_con_t *ipmi,
330
unsigned char msg_tag,
331
ipmi_rmcpp_auth_t *ainfo,
337
ipmi_rmcpp_set_info_cb set,
338
ipmi_rmcpp_finish_auth_cb done,
347
info = ipmi_mem_alloc(sizeof(*info));
350
memset(info, 0, sizeof(*info));
352
rspi = ipmi_alloc_msg_item();
358
info->msg_tag = msg_tag;
360
info->cleanup = cleanup;
363
info->cb_data = cb_data;
364
info->check2 = check2;
366
info->check4 = check4;
367
info->hacks = ipmi->hacks;
369
p = ipmi_rmcpp_auth_get_my_rand(info->ainfo, &plen);
372
ipmi_rmcpp_auth_set_my_rand_len(info->ainfo, 16);
373
rv = ipmi->os_hnd->get_random(ipmi->os_hnd, p, 16);
375
ipmi_free_msg_item(rspi);
383
ipmi_free_msg_item(rspi);
389
rv = send_rakp1(ipmi, info, rspi, addr_num);
393
ipmi_free_msg_item(rspi);
403
start_rakp_none(ipmi_con_t *ipmi,
405
unsigned char msg_tag,
406
ipmi_rmcpp_auth_t *ainfo,
407
ipmi_rmcpp_set_info_cb set,
408
ipmi_rmcpp_finish_auth_cb done,
411
return start_rakp(ipmi, addr_num, msg_tag, ainfo,
412
NULL, NULL, NULL, NULL, NULL,
416
static ipmi_rmcpp_authentication_t rakp_none_auth =
421
/***********************************************************************
425
***********************************************************************/
427
#include <openssl/hmac.h>
429
typedef struct rakp_hmac_key_s
431
unsigned int key_len;
432
unsigned int integ_len;
433
const EVP_MD *evp_md;
437
rakp_hmac_c2(rakp_info_t *info,
439
unsigned int data_len)
441
unsigned char idata[74];
443
unsigned char integ_data[20];
444
rakp_hmac_key_t *rinfo = info->key_data;
445
const unsigned char *p;
450
if (data_len < 40+rinfo->key_len)
453
ipmi_set_uint32(idata+0, ipmi_rmcpp_auth_get_my_session_id(info->ainfo));
454
ipmi_set_uint32(idata+4, ipmi_rmcpp_auth_get_mgsys_session_id(info->ainfo));
455
p = ipmi_rmcpp_auth_get_my_rand(info->ainfo, &plen);
456
memcpy(idata+8, p, 16);
457
p = ipmi_rmcpp_auth_get_mgsys_rand(info->ainfo, &plen);
458
memcpy(idata+24, p, 16);
459
p = ipmi_rmcpp_auth_get_mgsys_guid(info->ainfo, &plen);
460
memcpy(idata+40, p, 16);
461
idata[56] = ipmi_rmcpp_auth_get_role(info->ainfo);
462
idata[57] = ipmi_rmcpp_auth_get_username_len(info->ainfo);
465
p = ipmi_rmcpp_auth_get_username(info->ainfo, &plen);
466
memcpy(idata+58, p, idata[57]);
468
p = ipmi_rmcpp_auth_get_password(info->ainfo, &plen);
469
if (plen < rinfo->key_len)
471
HMAC(rinfo->evp_md, p, rinfo->key_len, idata, 58+idata[57], integ_data, &ilen);
472
if (memcmp(data+40, integ_data, rinfo->key_len) != 0)
475
/* Now generate the SIK */
476
p = ipmi_rmcpp_auth_get_my_rand(info->ainfo, &plen);
477
memcpy(idata+0, p, 16);
478
p = ipmi_rmcpp_auth_get_mgsys_rand(info->ainfo, &plen);
479
memcpy(idata+16, p, 16);
480
idata[32] = ipmi_rmcpp_auth_get_role(info->ainfo);
481
idata[33] = ipmi_rmcpp_auth_get_username_len(info->ainfo);
482
p = ipmi_rmcpp_auth_get_username(info->ainfo, &plen);
483
memcpy(idata+34, p, idata[33]);
484
p = ipmi_rmcpp_auth_get_bmc_key(info->ainfo, &plen);
485
if (plen < rinfo->key_len)
487
s = ipmi_rmcpp_auth_get_sik(info->ainfo, &plen);
488
if (plen < rinfo->key_len)
490
HMAC(rinfo->evp_md, p, rinfo->key_len, idata, 34+idata[33], s, &ilen);
491
ipmi_rmcpp_auth_set_sik_len(info->ainfo, rinfo->key_len);
493
/* Now generate k1 and k2. */
494
k = ipmi_rmcpp_auth_get_k1(info->ainfo, &plen);
495
if (plen < rinfo->key_len)
497
memset(idata, 1, rinfo->key_len);
498
HMAC(rinfo->evp_md, s, rinfo->key_len, idata, rinfo->key_len, k, &ilen);
499
ipmi_rmcpp_auth_set_k2_len(info->ainfo, rinfo->key_len);
500
k = ipmi_rmcpp_auth_get_k2(info->ainfo, &plen);
501
if (plen < rinfo->key_len)
503
memset(idata, 2, rinfo->key_len);
504
HMAC(rinfo->evp_md, s, rinfo->key_len, idata, rinfo->key_len, k, &ilen);
505
ipmi_rmcpp_auth_set_k2_len(info->ainfo, rinfo->key_len);
511
rakp_hmac_s3(rakp_info_t *info,
513
unsigned int *data_len,
514
unsigned int total_len)
516
unsigned char idata[38];
518
rakp_hmac_key_t *rinfo = info->key_data;
519
const unsigned char *p;
522
if (((*data_len)+rinfo->key_len) > total_len)
525
p = ipmi_rmcpp_auth_get_mgsys_rand(info->ainfo, &plen);
526
memcpy(idata+0, p, 16);
527
ipmi_set_uint32(idata+16, ipmi_rmcpp_auth_get_my_session_id(info->ainfo));
528
idata[20] = ipmi_rmcpp_auth_get_role(info->ainfo);
529
if (info->hacks & IPMI_CONN_HACK_RAKP3_WRONG_ROLEM)
530
/* For the RAKP4 message, the Intel BMC only uses the bottom 4
533
idata[21] = ipmi_rmcpp_auth_get_username_len(info->ainfo);
536
p = ipmi_rmcpp_auth_get_username(info->ainfo, &plen);
537
memcpy(idata+22, p, idata[21]);
539
p = ipmi_rmcpp_auth_get_password(info->ainfo, &plen);
540
if (plen < rinfo->key_len)
543
HMAC(rinfo->evp_md, p, rinfo->key_len, idata, 22+idata[21],
544
data+*data_len, &ilen);
545
*data_len += rinfo->key_len;
550
rakp_hmac_c4(rakp_info_t *info,
552
unsigned int data_len)
554
unsigned char idata[36];
556
unsigned char integ_data[20];
557
rakp_hmac_key_t *rinfo = info->key_data;
558
const unsigned char *p;
561
if (data_len < 8+rinfo->integ_len)
564
p = ipmi_rmcpp_auth_get_my_rand(info->ainfo, &plen);
565
memcpy(idata+0, p, 16);
566
ipmi_set_uint32(idata+16, ipmi_rmcpp_auth_get_mgsys_session_id(info->ainfo));
567
p = ipmi_rmcpp_auth_get_mgsys_guid(info->ainfo, &plen);
570
memcpy(idata+20, p, 16);
572
p = ipmi_rmcpp_auth_get_sik(info->ainfo, &plen);
573
HMAC(rinfo->evp_md, p, rinfo->key_len, idata, 36, integ_data, &ilen);
574
if (memcmp(data+8, integ_data, rinfo->integ_len) != 0)
581
rakp_hmac_cleanup(rakp_info_t *info)
583
rakp_hmac_key_t *key_data = info->key_data;
585
ipmi_mem_free(key_data);
589
rakp_sha1_init(rakp_info_t *info)
591
rakp_hmac_key_t *key_data;
593
key_data = ipmi_mem_alloc(sizeof(*key_data));
596
key_data->evp_md = EVP_sha1();
597
key_data->key_len = 20;
598
key_data->integ_len = 12;
599
info->key_data = key_data;
604
start_rakp_hmac_sha1(ipmi_con_t *ipmi,
606
unsigned char msg_tag,
607
ipmi_rmcpp_auth_t *ainfo,
608
ipmi_rmcpp_set_info_cb set,
609
ipmi_rmcpp_finish_auth_cb done,
612
return start_rakp(ipmi, addr_num, msg_tag, ainfo,
613
rakp_sha1_init, rakp_hmac_cleanup,
614
rakp_hmac_c2, rakp_hmac_s3, rakp_hmac_c4,
618
static ipmi_rmcpp_authentication_t rakp_hmac_sha1_auth =
624
rakp_md5_init(rakp_info_t *info)
626
rakp_hmac_key_t *key_data;
628
key_data = ipmi_mem_alloc(sizeof(*key_data));
631
key_data->evp_md = EVP_md5();
632
key_data->key_len = 16;
633
key_data->integ_len = 16;
634
info->key_data = key_data;
639
start_rakp_hmac_md5(ipmi_con_t *ipmi,
641
unsigned char msg_tag,
642
ipmi_rmcpp_auth_t *ainfo,
643
ipmi_rmcpp_set_info_cb set,
644
ipmi_rmcpp_finish_auth_cb done,
647
return start_rakp(ipmi, addr_num, msg_tag, ainfo,
648
rakp_md5_init, rakp_hmac_cleanup,
649
rakp_hmac_c2, rakp_hmac_s3, rakp_hmac_c4,
653
static ipmi_rmcpp_authentication_t rakp_hmac_md5_auth =
659
/**********************************************************************
661
* RAKP message formatting
663
*********************************************************************/
666
rakp_format_msg(ipmi_con_t *ipmi,
668
unsigned int addr_len,
670
unsigned char *out_data,
671
unsigned int *out_data_len,
675
if (msg->data_len > *out_data_len)
678
memcpy(out_data, msg->data, msg->data_len);
681
*out_data_len = msg->data_len;
686
rakp_get_recv_seq(ipmi_con_t *ipmi,
688
unsigned int data_len,
699
rakp_handle_recv(ipmi_con_t *ipmi,
701
ipmi_addr_t *orig_addr,
702
unsigned int orig_addr_len,
703
ipmi_msg_t *orig_msg,
705
unsigned int data_len)
707
ipmi_msg_t *msg = &(rspi->msg);
708
if (data_len > sizeof(rspi->data))
710
memcpy(rspi->data, data, data_len);
711
msg->data = rspi->data;
712
msg->data_len = data_len;
717
rakp_handle_recv_async(ipmi_con_t *ipmi,
719
unsigned int data_len)
724
rakp_get_msg_tag(unsigned char *tmsg,
725
unsigned int data_len,
730
*tag = ipmi_get_uint32(tmsg+4) - 1; /* session id */
734
static ipmi_payload_t rakp_payload =
735
{ rakp_format_msg, rakp_get_recv_seq, rakp_handle_recv,
736
rakp_handle_recv_async, rakp_get_msg_tag };
739
_ipmi_rakp_init(void)
743
rv = ipmi_rmcpp_register_authentication
744
(IPMI_LANP_AUTHENTICATION_ALGORITHM_RAKP_NONE,
750
rv = ipmi_rmcpp_register_authentication
751
(IPMI_LANP_AUTHENTICATION_ALGORITHM_RAKP_HMAC_SHA1,
752
&rakp_hmac_sha1_auth);
756
rv = ipmi_rmcpp_register_authentication
757
(IPMI_LANP_AUTHENTICATION_ALGORITHM_RAKP_HMAC_MD5,
758
&rakp_hmac_md5_auth);
763
rv = ipmi_rmcpp_register_payload(IPMI_RMCPP_PAYLOAD_TYPE_RAKP_1,
767
rv = ipmi_rmcpp_register_payload(IPMI_RMCPP_PAYLOAD_TYPE_RAKP_2,
771
rv = ipmi_rmcpp_register_payload(IPMI_RMCPP_PAYLOAD_TYPE_RAKP_3,
775
rv = ipmi_rmcpp_register_payload(IPMI_RMCPP_PAYLOAD_TYPE_RAKP_4,