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