1 /*
2 * rakp.c
3 *
4 * MontaVista RMCP+ code for handling RAKP algorithms
5 *
6 * Author: MontaVista Software, Inc.
7 * Corey Minyard <minyard@mvista.com>
8 * source@mvista.com
9 *
10 * Copyright 2004 MontaVista Software Inc.
11 *
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.
16 *
17 *
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.
28 *
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.
32 */
33
34 #include <config.h>
35
36 #include <string.h>
37
38 #include <OpenIPMI/ipmi_conn.h>
39 #include <OpenIPMI/ipmi_msgbits.h>
40 #include <OpenIPMI/ipmi_auth.h>
41 #include <OpenIPMI/ipmi_err.h>
42 #include <OpenIPMI/ipmi_lan.h>
43
44 #include <OpenIPMI/internal/ipmi_int.h>
45
46 typedef struct rakp_info_s rakp_info_t;
47
48 typedef int (*init_cb)(rakp_info_t *info);
49 typedef void (*cleanup_cb)(rakp_info_t *info);
50 typedef int (*check_cb)(rakp_info_t *info,
51 unsigned char *data,
52 unsigned int data_len);
53 typedef int (*set_cb)(rakp_info_t *info,
54 unsigned char *data,
55 unsigned int *data_len,
56 unsigned int total_len);
57
58 struct rakp_info_s
59 {
60 ipmi_rmcpp_auth_t *ainfo;
61
62 ipmi_rmcpp_set_info_cb set;
63 ipmi_rmcpp_finish_auth_cb done;
64 void *cb_data;
65
66 unsigned int hacks;
67
68 unsigned char msg_tag;
69
70 void *key_data;
71
72 /* Check an set the auth keys for the various rakp messages. The
73 data passed in is the whole message. For set3, the data_len
74 points to the current message size and total_len is the
75 total_len available. It should update data_len to the actual
76 length. These functions may be NULL and will not be used. */
77 cleanup_cb cleanup;
78 check_cb check2;
79 set_cb set3;
80 check_cb check4;
81 };
82
83 static void
rakp_done(rakp_info_t * info,ipmi_con_t * ipmi,int addr_num,int err)84 rakp_done(rakp_info_t *info,
85 ipmi_con_t *ipmi,
86 int addr_num,
87 int err)
88 {
89 info->done(ipmi, err, addr_num, info->cb_data);
90 if (info->cleanup)
91 info->cleanup(info);
92 ipmi_mem_free(info);
93 }
94
95 static int
check_rakp_rsp(ipmi_con_t * ipmi,rakp_info_t * info,ipmi_msg_t * msg,char * caller,unsigned int min_length,int addr_num)96 check_rakp_rsp(ipmi_con_t *ipmi,
97 rakp_info_t *info,
98 ipmi_msg_t *msg,
99 char *caller,
100 unsigned int min_length,
101 int addr_num)
102 {
103 if (!ipmi)
104 return ECANCELED;
105
106 if (msg->data_len == 1) {
107 /* This is kind of a cheap hack, this can happen when there is
108 a timeout. */
109 ipmi_log(IPMI_LOG_ERR_INFO,
110 "rakp.c(%s): IPMI error: %d",
111 caller, msg->data[0]);
112 return IPMI_IPMI_ERR_VAL(msg->data[0]);
113 }
114
115 if (msg->data_len < 2) {
116 ipmi_log(IPMI_LOG_ERR_INFO,
117 "rakp.c(%s): Message data too short: %d",
118 caller, msg->data_len);
119 return EINVAL;
120 }
121
122 if (msg->data[1])
123 /* Got an RMCP+ error. */
124 return IPMI_RMCPP_ERR_VAL(msg->data[1]);
125
126 if (msg->data_len < min_length) {
127 ipmi_log(IPMI_LOG_ERR_INFO,
128 "rakp.c(%s): Message data too short: %d",
129 caller, msg->data_len);
130 return EINVAL;
131 }
132
133 return 0;
134 }
135
136 static int
handle_rakp4(ipmi_con_t * ipmi,ipmi_msgi_t * rspi)137 handle_rakp4(ipmi_con_t *ipmi, ipmi_msgi_t *rspi)
138 {
139 ipmi_msg_t *msg = &rspi->msg;
140 rakp_info_t *info = rspi->data1;
141 int addr_num = (long) rspi->data4;
142 int rv;
143 uint32_t session_id;
144
145 /* In this function, there's not way to report the error to the
146 managed system, just report it locally. */
147
148 rv = check_rakp_rsp(ipmi, info, msg, "handle_rakp4", 8, addr_num);
149 if (rv)
150 goto out;
151
152 if (info->check4) {
153 rv = info->check4(info, msg->data, msg->data_len);
154 if (rv)
155 goto out;
156 }
157
158 session_id = ipmi_get_uint32(msg->data+4);
159 if (session_id != ipmi_rmcpp_auth_get_my_session_id(info->ainfo)) {
160 ipmi_log(IPMI_LOG_ERR_INFO,
161 "rakp.c(handle_rakp4): "
162 " Got wrong session id: 0x%x",
163 session_id);
164 rv = EINVAL;
165 goto out;
166 }
167
168 rakp_done(info, ipmi, addr_num, 0);
169 return IPMI_MSG_ITEM_NOT_USED;
170
171 out:
172 rakp_done(info, ipmi, addr_num, rv);
173 return IPMI_MSG_ITEM_NOT_USED;
174 }
175
176 static int
send_rakp3(ipmi_con_t * ipmi,rakp_info_t * info,ipmi_msgi_t * rspi,int addr_num,int err)177 send_rakp3(ipmi_con_t *ipmi, rakp_info_t *info,
178 ipmi_msgi_t *rspi, int addr_num, int err)
179 {
180 int rv;
181 unsigned char data[64];
182 ipmi_msg_t msg;
183 ipmi_rmcpp_addr_t addr;
184
185 memset(data, 0, sizeof(data));
186 data[0] = info->msg_tag;
187 data[1] = err;
188 ipmi_set_uint32(data+4, ipmi_rmcpp_auth_get_mgsys_session_id(info->ainfo));
189
190 msg.netfn = IPMI_RMCPP_DUMMY_NETFN;
191 msg.cmd = 0;
192 msg.data = data;
193 msg.data_len = 8;
194 addr.addr_type = IPMI_RMCPP_ADDR_START + IPMI_RMCPP_PAYLOAD_TYPE_RAKP_3;
195 rspi->data1 = info;
196
197 if (info->set3) {
198 unsigned int len;
199 len = msg.data_len;
200 rv = info->set3(info, data, &len, sizeof(data));
201 if (rv)
202 return rv;
203 msg.data_len = len;
204 }
205
206 if (err)
207 /* Don't handle the responst (if one comes back) on an error. */
208 rv = ipmi_lan_send_command_forceip(ipmi, addr_num,
209 (ipmi_addr_t *) &addr, sizeof(addr),
210 &msg, NULL, rspi);
211 else
212 rv = ipmi_lan_send_command_forceip(ipmi, addr_num,
213 (ipmi_addr_t *) &addr, sizeof(addr),
214 &msg, handle_rakp4, rspi);
215 return rv;
216 }
217
218 static int
handle_rakp2(ipmi_con_t * ipmi,ipmi_msgi_t * rspi)219 handle_rakp2(ipmi_con_t *ipmi, ipmi_msgi_t *rspi)
220 {
221 ipmi_msg_t *msg = &rspi->msg;
222 rakp_info_t *info = rspi->data1;
223 int addr_num = (long) rspi->data4;
224 int rv;
225 uint32_t session_id;
226 int err = 0;
227 unsigned char *p;
228 unsigned int plen;
229 int rv2;
230
231 rv = check_rakp_rsp(ipmi, info, msg, "handle_rakp2", 40, addr_num);
232 if (rv) {
233 err = IPMI_RMCPP_ILLEGAL_PARAMETER;
234 goto out;
235 }
236
237 p = ipmi_rmcpp_auth_get_mgsys_rand(info->ainfo, &plen);
238 if (plen < 16)
239 return EINVAL;
240 memcpy(p, msg->data+8, 16);
241 ipmi_rmcpp_auth_set_mgsys_rand_len(info->ainfo, 16);
242
243 p = ipmi_rmcpp_auth_get_mgsys_guid(info->ainfo, &plen);
244 if (plen < 16)
245 return EINVAL;
246 memcpy(p, msg->data+24, 16);
247 ipmi_rmcpp_auth_set_mgsys_guid_len(info->ainfo, 16);
248
249 session_id = ipmi_get_uint32(msg->data+4);
250 if (session_id != ipmi_rmcpp_auth_get_my_session_id(info->ainfo)) {
251 ipmi_log(IPMI_LOG_ERR_INFO,
252 "rakp.c(handle_rakp2): "
253 " Got wrong session id: 0x%x",
254 session_id);
255 err = IPMI_RMCPP_INVALID_SESSION_ID;
256 goto out;
257 }
258
259 if (info->check2) {
260 rv = info->check2(info, msg->data, msg->data_len);
261 if (rv) {
262 if (DEBUG_RAWMSG || DEBUG_MSG_ERR)
263 ipmi_log(IPMI_LOG_DEBUG, "Integrity check fail for rakp 2");
264 err = IPMI_RMCPP_INVALID_INTEGRITY_CHECK_VALUE;
265 goto out;
266 }
267 }
268
269 rv = info->set(ipmi, addr_num, info->ainfo, info->cb_data);
270 if (rv) {
271 if (DEBUG_RAWMSG || DEBUG_MSG_ERR)
272 ipmi_log(IPMI_LOG_DEBUG, "Error setting values from rakp 2");
273 err = IPMI_RMCPP_INSUFFICIENT_RESOURCES_FOR_SESSION;
274 goto out;
275 }
276
277 rv = send_rakp3(ipmi, info, rspi, addr_num, 0);
278 if (rv) {
279 if (DEBUG_RAWMSG || DEBUG_MSG_ERR)
280 ipmi_log(IPMI_LOG_DEBUG, "Error sending rakp 3");
281 err = IPMI_RMCPP_INSUFFICIENT_RESOURCES_FOR_SESSION;
282 goto out;
283 }
284
285 return IPMI_MSG_ITEM_USED;
286
287 out:
288 rv2 = EINVAL;
289 if (ipmi)
290 rv2 = send_rakp3(ipmi, info, rspi, addr_num, err);
291 rakp_done(info, ipmi, addr_num, rv);
292 if (rv2)
293 return IPMI_MSG_ITEM_NOT_USED;
294 else
295 /* Yes, we use it to send the error response. */
296 return IPMI_MSG_ITEM_USED;
297 }
298
299 static int
send_rakp1(ipmi_con_t * ipmi,rakp_info_t * info,ipmi_msgi_t * rspi,int addr_num)300 send_rakp1(ipmi_con_t *ipmi, rakp_info_t *info,
301 ipmi_msgi_t *rspi, int addr_num)
302 {
303 int rv;
304 unsigned char data[44];
305 ipmi_msg_t msg;
306 ipmi_rmcpp_addr_t addr;
307 const unsigned char *p;
308 unsigned int plen;
309
310 memset(data, 0, sizeof(data));
311 data[0] = info->msg_tag;
312 ipmi_set_uint32(data+4, ipmi_rmcpp_auth_get_mgsys_session_id(info->ainfo));
313
314 p = ipmi_rmcpp_auth_get_my_rand(info->ainfo, &plen);
315 if (plen < 16)
316 return EINVAL;
317 memcpy(data+8, p, 16);
318
319 data[24] = ipmi_rmcpp_auth_get_role(info->ainfo);
320 data[27] = ipmi_rmcpp_auth_get_username_len(info->ainfo);
321 p = ipmi_rmcpp_auth_get_username(info->ainfo, &plen);
322 if (plen < 16)
323 return EINVAL;
324 memcpy(data+28, p, data[27]);
325
326 msg.netfn = IPMI_RMCPP_DUMMY_NETFN;
327 msg.cmd = 0;
328 msg.data = data;
329 msg.data_len = 28 + data[27];
330 addr.addr_type = IPMI_RMCPP_ADDR_START + IPMI_RMCPP_PAYLOAD_TYPE_RAKP_1;
331 rspi->data1 = info;
332
333 rv = ipmi_lan_send_command_forceip(ipmi, addr_num,
334 (ipmi_addr_t *) &addr, sizeof(addr),
335 &msg, handle_rakp2, rspi);
336 return rv;
337 }
338
339 static int
start_rakp(ipmi_con_t * ipmi,int addr_num,unsigned char msg_tag,ipmi_rmcpp_auth_t * ainfo,init_cb init,cleanup_cb cleanup,check_cb check2,set_cb set3,check_cb check4,ipmi_rmcpp_set_info_cb set,ipmi_rmcpp_finish_auth_cb done,void * cb_data)340 start_rakp(ipmi_con_t *ipmi,
341 int addr_num,
342 unsigned char msg_tag,
343 ipmi_rmcpp_auth_t *ainfo,
344 init_cb init,
345 cleanup_cb cleanup,
346 check_cb check2,
347 set_cb set3,
348 check_cb check4,
349 ipmi_rmcpp_set_info_cb set,
350 ipmi_rmcpp_finish_auth_cb done,
351 void *cb_data)
352 {
353 rakp_info_t *info;
354 ipmi_msgi_t *rspi;
355 int rv;
356 unsigned char *p;
357 unsigned int plen;
358
359 info = ipmi_mem_alloc(sizeof(*info));
360 if (!info)
361 return ENOMEM;
362 memset(info, 0, sizeof(*info));
363
364 rspi = ipmi_alloc_msg_item();
365 if (!rspi) {
366 ipmi_mem_free(info);
367 return ENOMEM;
368 }
369
370 info->msg_tag = msg_tag;
371 info->ainfo = ainfo;
372 info->cleanup = cleanup;
373 info->set = set;
374 info->done = done;
375 info->cb_data = cb_data;
376 info->check2 = check2;
377 info->set3 = set3;
378 info->check4 = check4;
379 info->hacks = ipmi->hacks;
380
381 p = ipmi_rmcpp_auth_get_my_rand(info->ainfo, &plen);
382 if (plen < 16)
383 return EINVAL;
384 ipmi_rmcpp_auth_set_my_rand_len(info->ainfo, 16);
385 rv = ipmi->os_hnd->get_random(ipmi->os_hnd, p, 16);
386 if (rv) {
387 ipmi_free_msg_item(rspi);
388 ipmi_mem_free(info);
389 return rv;
390 }
391
392 if (init) {
393 rv = init(info);
394 if (rv) {
395 ipmi_free_msg_item(rspi);
396 ipmi_mem_free(info);
397 return rv;
398 }
399 }
400
401 rv = send_rakp1(ipmi, info, rspi, addr_num);
402 if (rv) {
403 if (cleanup)
404 cleanup(info);
405 ipmi_free_msg_item(rspi);
406 ipmi_mem_free(info);
407 return rv;
408 }
409
410 return 0;
411 }
412
413
414 static int
start_rakp_none(ipmi_con_t * ipmi,int addr_num,unsigned char msg_tag,ipmi_rmcpp_auth_t * ainfo,ipmi_rmcpp_set_info_cb set,ipmi_rmcpp_finish_auth_cb done,void * cb_data)415 start_rakp_none(ipmi_con_t *ipmi,
416 int addr_num,
417 unsigned char msg_tag,
418 ipmi_rmcpp_auth_t *ainfo,
419 ipmi_rmcpp_set_info_cb set,
420 ipmi_rmcpp_finish_auth_cb done,
421 void *cb_data)
422 {
423 return start_rakp(ipmi, addr_num, msg_tag, ainfo,
424 NULL, NULL, NULL, NULL, NULL,
425 set, done, cb_data);
426 }
427
428 static ipmi_rmcpp_authentication_t rakp_none_auth =
429 {
430 start_rakp_none
431 };
432
433 /***********************************************************************
434 *
435 * cipher handling
436 *
437 ***********************************************************************/
438 #ifdef HAVE_OPENSSL
439 #include <openssl/hmac.h>
440
441 typedef struct rakp_hmac_key_s
442 {
443 unsigned int key_len;
444 unsigned int integ_len;
445 const EVP_MD *evp_md;
446 } rakp_hmac_key_t;
447
448 static int
rakp_hmac_c2(rakp_info_t * info,unsigned char * data,unsigned int data_len)449 rakp_hmac_c2(rakp_info_t *info,
450 unsigned char *data,
451 unsigned int data_len)
452 {
453 unsigned char idata[74];
454 unsigned int ilen;
455 unsigned char integ_data[20];
456 rakp_hmac_key_t *rinfo = info->key_data;
457 const unsigned char *p;
458 unsigned char *s;
459 unsigned char *k;
460 unsigned int plen;
461
462 if (data_len < 40+rinfo->key_len)
463 return E2BIG;
464
465 ipmi_set_uint32(idata+0, ipmi_rmcpp_auth_get_my_session_id(info->ainfo));
466 ipmi_set_uint32(idata+4, ipmi_rmcpp_auth_get_mgsys_session_id(info->ainfo));
467 p = ipmi_rmcpp_auth_get_my_rand(info->ainfo, &plen);
468 memcpy(idata+8, p, 16);
469 p = ipmi_rmcpp_auth_get_mgsys_rand(info->ainfo, &plen);
470 memcpy(idata+24, p, 16);
471 p = ipmi_rmcpp_auth_get_mgsys_guid(info->ainfo, &plen);
472 memcpy(idata+40, p, 16);
473 idata[56] = ipmi_rmcpp_auth_get_role(info->ainfo);
474 idata[57] = ipmi_rmcpp_auth_get_username_len(info->ainfo);
475 if (idata[57] > 16)
476 return EINVAL;
477 p = ipmi_rmcpp_auth_get_username(info->ainfo, &plen);
478 memcpy(idata+58, p, idata[57]);
479
480 p = ipmi_rmcpp_auth_get_password(info->ainfo, &plen);
481 if (plen < rinfo->key_len)
482 return EINVAL;
483 HMAC(rinfo->evp_md, p, rinfo->key_len, idata, 58+idata[57], integ_data, &ilen);
484 if (memcmp(data+40, integ_data, rinfo->key_len) != 0)
485 return EINVAL;
486
487 /* Now generate the SIK */
488 p = ipmi_rmcpp_auth_get_my_rand(info->ainfo, &plen);
489 memcpy(idata+0, p, 16);
490 p = ipmi_rmcpp_auth_get_mgsys_rand(info->ainfo, &plen);
491 memcpy(idata+16, p, 16);
492 idata[32] = ipmi_rmcpp_auth_get_role(info->ainfo);
493 idata[33] = ipmi_rmcpp_auth_get_username_len(info->ainfo);
494 p = ipmi_rmcpp_auth_get_username(info->ainfo, &plen);
495 memcpy(idata+34, p, idata[33]);
496 p = ipmi_rmcpp_auth_get_bmc_key(info->ainfo, &plen);
497 if (plen < rinfo->key_len)
498 return EINVAL;
499 s = ipmi_rmcpp_auth_get_sik(info->ainfo, &plen);
500 if (plen < rinfo->key_len)
501 return EINVAL;
502 HMAC(rinfo->evp_md, p, rinfo->key_len, idata, 34+idata[33], s, &ilen);
503 ipmi_rmcpp_auth_set_sik_len(info->ainfo, rinfo->key_len);
504
505 /* Now generate k1 and k2. */
506 k = ipmi_rmcpp_auth_get_k1(info->ainfo, &plen);
507 if (plen < rinfo->key_len)
508 return EINVAL;
509 memset(idata, 1, rinfo->key_len);
510 HMAC(rinfo->evp_md, s, rinfo->key_len, idata, rinfo->key_len, k, &ilen);
511 ipmi_rmcpp_auth_set_k2_len(info->ainfo, rinfo->key_len);
512 k = ipmi_rmcpp_auth_get_k2(info->ainfo, &plen);
513 if (plen < rinfo->key_len)
514 return EINVAL;
515 memset(idata, 2, rinfo->key_len);
516 HMAC(rinfo->evp_md, s, rinfo->key_len, idata, rinfo->key_len, k, &ilen);
517 ipmi_rmcpp_auth_set_k2_len(info->ainfo, rinfo->key_len);
518
519 return 0;
520 }
521
522 static int
rakp_hmac_s3(rakp_info_t * info,unsigned char * data,unsigned int * data_len,unsigned int total_len)523 rakp_hmac_s3(rakp_info_t *info,
524 unsigned char *data,
525 unsigned int *data_len,
526 unsigned int total_len)
527 {
528 unsigned char idata[38];
529 unsigned int ilen;
530 rakp_hmac_key_t *rinfo = info->key_data;
531 const unsigned char *p;
532 unsigned int plen;
533
534 if (((*data_len)+rinfo->key_len) > total_len)
535 return E2BIG;
536
537 p = ipmi_rmcpp_auth_get_mgsys_rand(info->ainfo, &plen);
538 memcpy(idata+0, p, 16);
539 ipmi_set_uint32(idata+16, ipmi_rmcpp_auth_get_my_session_id(info->ainfo));
540 idata[20] = ipmi_rmcpp_auth_get_role(info->ainfo);
541 if (info->hacks & IPMI_CONN_HACK_RAKP3_WRONG_ROLEM)
542 /* For the RAKP3 message, the Intel BMC only uses the bottom 4
543 nibbles. */
544 idata[20] &= 0xf;
545 idata[21] = ipmi_rmcpp_auth_get_username_len(info->ainfo);
546 if (idata[21] > 16)
547 return EINVAL;
548 p = ipmi_rmcpp_auth_get_username(info->ainfo, &plen);
549 memcpy(idata+22, p, idata[21]);
550
551 p = ipmi_rmcpp_auth_get_password(info->ainfo, &plen);
552 if (plen < rinfo->key_len)
553 return EINVAL;
554
555 HMAC(rinfo->evp_md, p, rinfo->key_len, idata, 22+idata[21],
556 data+*data_len, &ilen);
557 *data_len += rinfo->key_len;
558 return 0;
559 }
560
561 static int
rakp_hmac_c4(rakp_info_t * info,unsigned char * data,unsigned int data_len)562 rakp_hmac_c4(rakp_info_t *info,
563 unsigned char *data,
564 unsigned int data_len)
565 {
566 unsigned char idata[36];
567 unsigned int ilen;
568 unsigned char integ_data[20];
569 rakp_hmac_key_t *rinfo = info->key_data;
570 const unsigned char *p;
571 unsigned int plen;
572
573 if (data_len < 8+rinfo->integ_len)
574 return E2BIG;
575
576 p = ipmi_rmcpp_auth_get_my_rand(info->ainfo, &plen);
577 memcpy(idata+0, p, 16);
578 ipmi_set_uint32(idata+16, ipmi_rmcpp_auth_get_mgsys_session_id(info->ainfo));
579 p = ipmi_rmcpp_auth_get_mgsys_guid(info->ainfo, &plen);
580 if (plen < 16)
581 return EINVAL;
582 memcpy(idata+20, p, 16);
583
584 p = ipmi_rmcpp_auth_get_sik(info->ainfo, &plen);
585 HMAC(rinfo->evp_md, p, rinfo->key_len, idata, 36, integ_data, &ilen);
586 if (memcmp(data+8, integ_data, rinfo->integ_len) != 0)
587 return EINVAL;
588
589 return 0;
590 }
591
592 static void
rakp_hmac_cleanup(rakp_info_t * info)593 rakp_hmac_cleanup(rakp_info_t *info)
594 {
595 rakp_hmac_key_t *key_data = info->key_data;
596
597 ipmi_mem_free(key_data);
598 }
599
600 static int
rakp_sha1_init(rakp_info_t * info)601 rakp_sha1_init(rakp_info_t *info)
602 {
603 rakp_hmac_key_t *key_data;
604
605 key_data = ipmi_mem_alloc(sizeof(*key_data));
606 if (!key_data)
607 return ENOMEM;
608 key_data->evp_md = EVP_sha1();
609 key_data->key_len = 20;
610 key_data->integ_len = 12;
611 info->key_data = key_data;
612 return 0;
613 }
614
615 static int
start_rakp_hmac_sha1(ipmi_con_t * ipmi,int addr_num,unsigned char msg_tag,ipmi_rmcpp_auth_t * ainfo,ipmi_rmcpp_set_info_cb set,ipmi_rmcpp_finish_auth_cb done,void * cb_data)616 start_rakp_hmac_sha1(ipmi_con_t *ipmi,
617 int addr_num,
618 unsigned char msg_tag,
619 ipmi_rmcpp_auth_t *ainfo,
620 ipmi_rmcpp_set_info_cb set,
621 ipmi_rmcpp_finish_auth_cb done,
622 void *cb_data)
623 {
624 return start_rakp(ipmi, addr_num, msg_tag, ainfo,
625 rakp_sha1_init, rakp_hmac_cleanup,
626 rakp_hmac_c2, rakp_hmac_s3, rakp_hmac_c4,
627 set, done, cb_data);
628 }
629
630 static ipmi_rmcpp_authentication_t rakp_hmac_sha1_auth =
631 {
632 start_rakp_hmac_sha1
633 };
634
635 static int
rakp_md5_init(rakp_info_t * info)636 rakp_md5_init(rakp_info_t *info)
637 {
638 rakp_hmac_key_t *key_data;
639
640 key_data = ipmi_mem_alloc(sizeof(*key_data));
641 if (!key_data)
642 return ENOMEM;
643 key_data->evp_md = EVP_md5();
644 key_data->key_len = 16;
645 key_data->integ_len = 16;
646 info->key_data = key_data;
647 return 0;
648 }
649
650 static int
start_rakp_hmac_md5(ipmi_con_t * ipmi,int addr_num,unsigned char msg_tag,ipmi_rmcpp_auth_t * ainfo,ipmi_rmcpp_set_info_cb set,ipmi_rmcpp_finish_auth_cb done,void * cb_data)651 start_rakp_hmac_md5(ipmi_con_t *ipmi,
652 int addr_num,
653 unsigned char msg_tag,
654 ipmi_rmcpp_auth_t *ainfo,
655 ipmi_rmcpp_set_info_cb set,
656 ipmi_rmcpp_finish_auth_cb done,
657 void *cb_data)
658 {
659 return start_rakp(ipmi, addr_num, msg_tag, ainfo,
660 rakp_md5_init, rakp_hmac_cleanup,
661 rakp_hmac_c2, rakp_hmac_s3, rakp_hmac_c4,
662 set, done, cb_data);
663 }
664
665 static ipmi_rmcpp_authentication_t rakp_hmac_md5_auth =
666 {
667 start_rakp_hmac_md5
668 };
669 #endif
670
671 /**********************************************************************
672 *
673 * RAKP message formatting
674 *
675 *********************************************************************/
676
677 static int
rakp_format_msg(ipmi_con_t * ipmi,const ipmi_addr_t * addr,unsigned int addr_len,const ipmi_msg_t * msg,unsigned char * out_data,unsigned int * out_data_len,int * out_of_session,unsigned char seq)678 rakp_format_msg(ipmi_con_t *ipmi,
679 const ipmi_addr_t *addr,
680 unsigned int addr_len,
681 const ipmi_msg_t *msg,
682 unsigned char *out_data,
683 unsigned int *out_data_len,
684 int *out_of_session,
685 unsigned char seq)
686 {
687 if (msg->data_len > *out_data_len)
688 return E2BIG;
689
690 memcpy(out_data, msg->data, msg->data_len);
691 out_data[0] = seq;
692 *out_of_session = 1;
693 *out_data_len = msg->data_len;
694 return 0;
695 }
696
697 static int
rakp_get_recv_seq(ipmi_con_t * ipmi,unsigned char * data,unsigned int data_len,unsigned char * seq)698 rakp_get_recv_seq(ipmi_con_t *ipmi,
699 unsigned char *data,
700 unsigned int data_len,
701 unsigned char *seq)
702 {
703 if (data_len < 1)
704 return EINVAL;
705
706 *seq = data[0];
707 return 0;
708 }
709
710 static int
rakp_handle_recv(ipmi_con_t * ipmi,ipmi_msgi_t * rspi,ipmi_addr_t * orig_addr,unsigned int orig_addr_len,ipmi_msg_t * orig_msg,unsigned char * data,unsigned int data_len)711 rakp_handle_recv(ipmi_con_t *ipmi,
712 ipmi_msgi_t *rspi,
713 ipmi_addr_t *orig_addr,
714 unsigned int orig_addr_len,
715 ipmi_msg_t *orig_msg,
716 unsigned char *data,
717 unsigned int data_len)
718 {
719 ipmi_msg_t *msg = &(rspi->msg);
720 if (data_len > sizeof(rspi->data))
721 return E2BIG;
722 memcpy(rspi->data, data, data_len);
723 msg->data = rspi->data;
724 msg->data_len = data_len;
725 return 0;
726 }
727
728 static void
rakp_handle_recv_async(ipmi_con_t * ipmi,unsigned char * tmsg,unsigned int data_len)729 rakp_handle_recv_async(ipmi_con_t *ipmi,
730 unsigned char *tmsg,
731 unsigned int data_len)
732 {
733 }
734
735 static int
rakp_get_msg_tag(unsigned char * tmsg,unsigned int data_len,unsigned char * tag)736 rakp_get_msg_tag(unsigned char *tmsg,
737 unsigned int data_len,
738 unsigned char *tag)
739 {
740 if (data_len < 8)
741 return EINVAL;
742 *tag = ipmi_get_uint32(tmsg+4) - 1; /* session id */
743 return 0;
744 }
745
746 static ipmi_payload_t rakp_payload =
747 { rakp_format_msg, rakp_get_recv_seq, rakp_handle_recv,
748 rakp_handle_recv_async, rakp_get_msg_tag };
749
750 void
i_ipmi_rakp_shutdown(void)751 i_ipmi_rakp_shutdown(void)
752 {
753 ipmi_rmcpp_register_payload(IPMI_RMCPP_PAYLOAD_TYPE_RAKP_4, NULL);
754 ipmi_rmcpp_register_payload(IPMI_RMCPP_PAYLOAD_TYPE_RAKP_3, NULL);
755 ipmi_rmcpp_register_payload(IPMI_RMCPP_PAYLOAD_TYPE_RAKP_2, NULL);
756 ipmi_rmcpp_register_payload(IPMI_RMCPP_PAYLOAD_TYPE_RAKP_1, NULL);
757 #ifdef HAVE_OPENSSL
758 ipmi_rmcpp_register_authentication
759 (IPMI_LANP_AUTHENTICATION_ALGORITHM_RAKP_HMAC_MD5, NULL);
760 ipmi_rmcpp_register_authentication
761 (IPMI_LANP_AUTHENTICATION_ALGORITHM_RAKP_HMAC_SHA1, NULL);
762 #endif
763 ipmi_rmcpp_register_authentication
764 (IPMI_LANP_AUTHENTICATION_ALGORITHM_RAKP_NONE, NULL);
765 }
766
767 int
i_ipmi_rakp_init(void)768 i_ipmi_rakp_init(void)
769 {
770 int rv;
771
772 rv = ipmi_rmcpp_register_authentication
773 (IPMI_LANP_AUTHENTICATION_ALGORITHM_RAKP_NONE,
774 &rakp_none_auth);
775 if (rv)
776 return rv;
777
778 #ifdef HAVE_OPENSSL
779 rv = ipmi_rmcpp_register_authentication
780 (IPMI_LANP_AUTHENTICATION_ALGORITHM_RAKP_HMAC_SHA1,
781 &rakp_hmac_sha1_auth);
782 if (rv) {
783 i_ipmi_rakp_shutdown();
784 return rv;
785 }
786
787 rv = ipmi_rmcpp_register_authentication
788 (IPMI_LANP_AUTHENTICATION_ALGORITHM_RAKP_HMAC_MD5,
789 &rakp_hmac_md5_auth);
790 if (rv) {
791 i_ipmi_rakp_shutdown();
792 return rv;
793 }
794 #endif
795
796 rv = ipmi_rmcpp_register_payload(IPMI_RMCPP_PAYLOAD_TYPE_RAKP_1,
797 &rakp_payload);
798 if (rv) {
799 i_ipmi_rakp_shutdown();
800 return rv;
801 }
802
803 rv = ipmi_rmcpp_register_payload(IPMI_RMCPP_PAYLOAD_TYPE_RAKP_2,
804 &rakp_payload);
805 if (rv) {
806 i_ipmi_rakp_shutdown();
807 return rv;
808 }
809
810 rv = ipmi_rmcpp_register_payload(IPMI_RMCPP_PAYLOAD_TYPE_RAKP_3,
811 &rakp_payload);
812 if (rv) {
813 i_ipmi_rakp_shutdown();
814 return rv;
815 }
816
817 rv = ipmi_rmcpp_register_payload(IPMI_RMCPP_PAYLOAD_TYPE_RAKP_4,
818 &rakp_payload);
819 if (rv) {
820 i_ipmi_rakp_shutdown();
821 return rv;
822 }
823
824 return 0;
825 }
826