1 /*
2  * Copyright (c) 2003 Sun Microsystems, Inc.  All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * Redistribution of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * Redistribution in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * Neither the name of Sun Microsystems, Inc. or the names of
16  * contributors may be used to endorse or promote products derived
17  * from this software without specific prior written permission.
18  *
19  * This software is provided "AS IS," without a warranty of any kind.
20  * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
21  * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
22  * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
23  * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
24  * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
25  * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.  IN NO EVENT WILL
26  * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
27  * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
28  * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
29  * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
30  * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31  */
32 
33 #include <assert.h>
34 #include <string.h>
35 #if defined(HAVE_CONFIG_H)
36 # include <config.h>
37 #endif
38 #include <ipmitool/bswap.h>
39 #include <ipmitool/log.h>
40 #include "lanplus.h"
41 #include "lanplus_crypt.h"
42 #include "lanplus_crypt_impl.h"
43 
44 
45 
46 /*
47  * lanplus_rakp2_hmac_matches
48  *
49  * param session holds all the state data that we need to generate the hmac
50  * param hmac is the HMAC sent by the BMC in the RAKP 2 message
51  *
52  * The HMAC was generated [per RFC2404] from :
53  *
54  *     SIDm     - Remote console session ID
55  *     SIDc     - BMC session ID
56  *     Rm       - Remote console random number
57  *     Rc       - BMC random number
58  *     GUIDc    - BMC guid
59  *     ROLEm    - Requested privilege level (entire byte)
60  *     ULENGTHm - Username length
61  *     <UNAMEm> - Username (absent for null user names)
62  *
63  * generated by using Kuid.  I am aware that the subscripts on the values
64  * look backwards, but that's the way they are written in the specification.
65  *
66  * If the authentication algorithm is IPMI_AUTH_RAKP_NONE, we return success.
67  *
68  * return 0 on success (the authcode matches)
69  *        1 on failure (the authcode does not match)
70  */
71 int
72 lanplus_rakp2_hmac_matches(const struct ipmi_session * session,
73 		const uint8_t * bmc_mac, struct ipmi_intf * intf)
74 {
75 	uint8_t       * buffer;
76 	int           bufferLength, i;
77 	uint8_t       mac[20];
78 	uint32_t      macLength;
79 
80 	uint32_t SIDm_lsbf, SIDc_lsbf;
81 
82 
83 	if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE)
84 		return 1;
85 
86 	/* We don't yet support other algorithms */
87 	assert(session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA1);
88 
89 
90 	bufferLength =
91 		4  +                       /* SIDm     */
92 		4  +                       /* SIDc     */
93 		16 +                       /* Rm       */
94 		16 +                       /* Rc       */
95 		16 +                       /* GUIDc    */
96 		1  +                       /* ROLEm    */
97 		1  +                       /* ULENGTHm */
98 		strlen((const char *)intf->ssn_params.username); /* optional */
99 
100 	buffer = malloc(bufferLength);
101 	if (buffer == NULL) {
102 		lprintf(LOG_ERR, "ipmitool: malloc failure");
103 		return 1;
104 	}
105 
106 	/*
107 	 * Fill the buffer.  I'm assuming that we're using the LSBF representation of the
108 	 * multibyte numbers in use.
109 	 */
110 
111 	/* SIDm */
112 	SIDm_lsbf = session->v2_data.console_id;
113 	#if WORDS_BIGENDIAN
114 	SIDm_lsbf = BSWAP_32(SIDm_lsbf);
115 	#endif
116 
117 	memcpy(buffer, &SIDm_lsbf, 4);
118 
119 	/* SIDc */
120 	SIDc_lsbf = session->v2_data.bmc_id;
121 	#if WORDS_BIGENDIAN
122 	SIDc_lsbf = BSWAP_32(SIDc_lsbf);
123 	#endif
124 	memcpy(buffer + 4, &SIDc_lsbf, 4);
125 
126 	/* Rm */
127 	#if WORDS_BIGENDIAN
128 	for (i = 0; i < 16; ++i)
129 		buffer[8 + i] = session->v2_data.console_rand[16 - 1 - i];
130 	#else
131 	for (i = 0; i < 16; ++i)
132 		buffer[8 + i] = session->v2_data.console_rand[i];
133 	#endif
134 
135 	/* Rc */
136 	#if WORDS_BIGENDIAN
137 	for (i = 0; i < 16; ++i)
138 		buffer[24 + i] = session->v2_data.bmc_rand[16 - 1 - i];
139 	#else
140 	for (i = 0; i < 16; ++i)
141 		buffer[24 + i] = session->v2_data.bmc_rand[i];
142 	#endif
143 
144 	/* GUIDc */
145 	#if WORDS_BIGENDIAN
146 	for (i = 0; i < 16; ++i)
147 		buffer[40 + i] = session->v2_data.bmc_guid[16 - 1 - i];
148 	#else
149 	for (i = 0; i < 16; ++i)
150 		buffer[40 + i] = session->v2_data.bmc_guid[i];
151 	#endif
152 
153 	/* ROLEm */
154 	buffer[56] = session->v2_data.requested_role;
155 
156 	if (ipmi_oem_active(intf, "i82571spt")) {
157 		/*
158 		 * The HMAC calculation code in the Intel 82571 GbE
159 		 * skips this bit!  Looks like a GbE bug, but we need
160 		 * to work around it here anyway...
161 		 */
162 		buffer[56] &= ~0x10;
163 	}
164 
165 	/* ULENGTHm */
166 	buffer[57] = strlen((const char *)intf->ssn_params.username);
167 
168 	/* UserName [optional] */
169 	for (i = 0; i < buffer[57]; ++i)
170 		buffer[58 + i] = intf->ssn_params.username[i];
171 
172 	if (verbose > 2)
173 	{
174 		printbuf((const uint8_t *)buffer, bufferLength, ">> rakp2 mac input buffer");
175 		printbuf((const uint8_t *)session->authcode, IPMI_AUTHCODE_BUFFER_SIZE, ">> rakp2 mac key");
176 	}
177 
178 	/*
179 	 * The buffer is complete.  Let's hash.
180 	 */
181 	lanplus_HMAC(session->v2_data.auth_alg,
182 				 session->authcode,
183 				 IPMI_AUTHCODE_BUFFER_SIZE,
184 				 buffer,
185 				 bufferLength,
186 				 mac,
187 				 &macLength);
188 
189 	free(buffer);
190 	buffer = NULL;
191 
192 
193 	if (verbose > 2)
194 	{
195 		printbuf(mac, macLength, ">> rakp2 mac as computed by the remote console");
196 	}
197 
198 	return (memcmp(bmc_mac, mac, macLength) == 0);
199 }
200 
201 
202 
203 /*
204  * lanplus_rakp4_hmac_matches
205  *
206  * param session holds all the state data that we need to generate the hmac
207  * param hmac is the HMAC sent by the BMC in the RAKP 4 message
208  *
209  * The HMAC was generated [per RFC2404] from :
210  *
211  *     Rm       - Remote console random number
212  *     SIDc     - BMC session ID
213  *     GUIDc    - BMC guid
214  *
215  * generated by using SIK (the session integrity key).  I am aware that the
216  * subscripts on the values look backwards, but that's the way they are
217  * written in the specification.
218  *
219  * If the authentication algorithm is IPMI_AUTH_RAKP_NONE, we return success.
220  *
221  * return 1 on success (the authcode matches)
222  *        0 on failure (the authcode does not match)
223  *
224  */
225 int
226 lanplus_rakp4_hmac_matches(const struct ipmi_session * session,
227 		const uint8_t * bmc_mac, struct ipmi_intf * intf)
228 {
229 	uint8_t       * buffer;
230 	int           bufferLength, i;
231 	uint8_t       mac[20];
232 	uint32_t      macLength;
233 	uint32_t      SIDc_lsbf;
234 
235 	if (ipmi_oem_active(intf, "intelplus")){
236 		/* Intel BMC responds with the integrity Algorithm in RAKP4 */
237 		if (session->v2_data.integrity_alg == IPMI_INTEGRITY_NONE)
238 			return 1;
239 
240 		/* We don't yet support other algorithms */
241 		assert(session->v2_data.integrity_alg == IPMI_INTEGRITY_HMAC_SHA1_96);
242 	} else {
243 		if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE)
244 			return 1;
245 
246 		/* We don't yet support other algorithms */
247 		assert(session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA1);
248 	}
249 
250 	bufferLength =
251 		16 +   /* Rm    */
252 		4  +   /* SIDc  */
253 		16;    /* GUIDc */
254 
255 	buffer = (uint8_t *)malloc(bufferLength);
256 	if (buffer == NULL) {
257 		lprintf(LOG_ERR, "ipmitool: malloc failure");
258 		return 1;
259 	}
260 
261 	/*
262 	 * Fill the buffer.  I'm assuming that we're using the LSBF representation of the
263 	 * multibyte numbers in use.
264 	 */
265 
266 	/* Rm */
267 	#if WORDS_BIGENDIAN
268 	for (i = 0; i < 16; ++i)
269 		buffer[i] = session->v2_data.console_rand[16 - 1 - i];
270 	#else
271 	for (i = 0; i < 16; ++i)
272 		buffer[i] = session->v2_data.console_rand[i];
273 	#endif
274 
275 
276 	/* SIDc */
277 	SIDc_lsbf = session->v2_data.bmc_id;
278 	#if WORDS_BIGENDIAN
279 	SIDc_lsbf = BSWAP_32(SIDc_lsbf);
280 	#endif
281 	memcpy(buffer + 16, &SIDc_lsbf, 4);
282 
283 
284 	/* GUIDc */
285 	#if WORDS_BIGENDIAN
286 	for (i = 0; i < 16; ++i)
287 		buffer[i +  20] = session->v2_data.bmc_guid[16 - 1 - i];
288 	#else
289 	for (i = 0; i < 16; ++i)
290 		buffer[i +  20] = session->v2_data.bmc_guid[i];
291 	#endif
292 
293 
294 	if (verbose > 2)
295 	{
296 		printbuf((const uint8_t *)buffer, bufferLength, ">> rakp4 mac input buffer");
297 		printbuf(session->v2_data.sik, 20l, ">> rakp4 mac key (sik)");
298 	}
299 
300 
301 	/*
302 	 * The buffer is complete.  Let's hash.
303 	 */
304 	lanplus_HMAC((ipmi_oem_active(intf, "intelplus"))
305 	             ? session->v2_data.integrity_alg
306 	             : session->v2_data.auth_alg ,
307 				 session->v2_data.sik,
308 				 IPMI_SIK_BUFFER_SIZE,
309 				 buffer,
310 				 bufferLength,
311 				 mac,
312 				 &macLength);
313 
314 	if (verbose > 2)
315 	{
316 		printbuf(bmc_mac, macLength, ">> rakp4 mac as computed by the BMC");
317 		printbuf(mac,     macLength, ">> rakp4 mac as computed by the remote console");
318 	}
319 
320 
321 
322 	free(buffer);
323 	buffer = NULL;
324 	assert(macLength == 20);
325 	return (memcmp(bmc_mac, mac, 12) == 0);
326 }
327 
328 
329 
330 /*
331  * lanplus_generate_rakp3_auth_code
332  *
333  * This auth code is an HMAC generated with :
334  *
335  *     Rc         - BMC random number
336  *     SIDm       - Console session ID
337  *     ROLEm      - Requested privilege level (entire byte)
338  *     ULENGTHm   - Username length
339  *     <USERNAME> - Usename (absent for null usernames)
340  *
341  * The key used to generated the MAC is Kuid
342  *
343  * I am aware that the subscripts look backwards, but that is the way they are
344  * written in the spec.
345  *
346  * param output_buffer [out] will hold the generated MAC
347  * param session       [in]  holds all the state data we need to generate the auth code
348  * param mac_length    [out] will be set to the length of the auth code
349  *
350  * returns 0 on success
351  *         1 on failure
352  */
353 int
354 lanplus_generate_rakp3_authcode(uint8_t * output_buffer,
355 		const struct ipmi_session * session,
356 		uint32_t * mac_length, struct ipmi_intf * intf)
357 {
358 	int ret = 0;
359 	int input_buffer_length, i;
360 	uint8_t * input_buffer;
361 	uint32_t SIDm_lsbf;
362 
363 
364 	if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE)
365 	{
366 		*mac_length = 0;
367 		return 0;
368 	}
369 
370 	/* We don't yet support other algorithms */
371 	assert(session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA1);
372 
373 	input_buffer_length =
374 		16 + /* Rc       */
375 		4  + /* SIDm     */
376 		1  + /* ROLEm    */
377 		1  + /* ULENGTHm */
378 		strlen((const char *)intf->ssn_params.username);
379 
380 	input_buffer = malloc(input_buffer_length);
381 	if (input_buffer == NULL) {
382 		lprintf(LOG_ERR, "ipmitool: malloc failure");
383 		return 1;
384 	}
385 
386 	/*
387 	 * Fill the buffer.  I'm assuming that we're using the LSBF representation of the
388 	 * multibyte numbers in use.
389 	 */
390 
391 	/* Rc */
392 	#if WORDS_BIGENDIAN
393 	for (i = 0; i < 16; ++i)
394 		input_buffer[i] = session->v2_data.bmc_rand[16 - 1 - i];
395 	#else
396 	for (i = 0; i < 16; ++i)
397 		input_buffer[i] = session->v2_data.bmc_rand[i];
398 	#endif
399 
400 	/* SIDm */
401 	SIDm_lsbf = session->v2_data.console_id;
402 	#if WORDS_BIGENDIAN
403 	SIDm_lsbf = BSWAP_32(SIDm_lsbf);
404 	#endif
405 	memcpy(input_buffer + 16, &SIDm_lsbf, 4);
406 
407 	/* ROLEm */
408 	if (ipmi_oem_active(intf, "intelplus") || ipmi_oem_active(intf, "i82571spt"))
409 		input_buffer[20] = intf->ssn_params.privlvl;
410 	else
411 		input_buffer[20] = session->v2_data.requested_role;
412 
413 	/* ULENGTHm */
414 	input_buffer[21] = strlen((const char *)intf->ssn_params.username);
415 
416 	/* USERNAME */
417 	for (i = 0; i < input_buffer[21]; ++i)
418 		input_buffer[22 + i] = intf->ssn_params.username[i];
419 
420 	if (verbose > 2)
421 	{
422 		printbuf((const uint8_t *)input_buffer, input_buffer_length, ">> rakp3 mac input buffer");
423 		printbuf((const uint8_t *)session->authcode, IPMI_AUTHCODE_BUFFER_SIZE, ">> rakp3 mac key");
424 	}
425 
426 	lanplus_HMAC(session->v2_data.auth_alg,
427 				 session->authcode,
428 				 IPMI_AUTHCODE_BUFFER_SIZE,
429 				 input_buffer,
430 				 input_buffer_length,
431 				 output_buffer,
432 				 mac_length);
433 
434 	if (verbose > 2)
435 		printbuf((const uint8_t *)output_buffer, *mac_length, "generated rakp3 mac");
436 
437 
438 	free(input_buffer);
439 	input_buffer = NULL;
440 
441 	return ret;
442 }
443 
444 
445 
446 /*
447  * lanplus_generate_sik
448  *
449  * Generate the session integrity key (SIK) used for integrity checking
450  * during the IPMI v2 / RMCP+ session
451  *
452  * This session integrity key is a HMAC generated with :
453  *
454  *     Rm         - Console generated random number
455  *     Rc         - BMC generated random number
456  *     ROLEm      - Requested privilege level (entire byte)
457  *     ULENGTHm   - Username length
458  *     <USERNAME> - Usename (absent for null usernames)
459  *
460  * The key used to generated the SIK is Kg if Kg is not null (two-key logins are
461  * enabled).  Otherwise Kuid (the user authcode) is used as the key to genereate
462  * the SIK.
463  *
464  * I am aware that the subscripts look backwards, but that is the way they are
465  * written in the spec.
466  *
467  * param session [in/out] contains our input and output fields.
468  *
469  * returns 0 on success
470  *         1 on failure
471  */
472 int
473 lanplus_generate_sik(struct ipmi_session * session, struct ipmi_intf * intf)
474 {
475 	uint8_t * input_buffer;
476 	int input_buffer_length, i;
477 	uint8_t * input_key;
478 	uint32_t mac_length;
479 
480 
481 	memset(session->v2_data.sik, 0, IPMI_SIK_BUFFER_SIZE);
482 
483 	if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE)
484 		return 0;
485 
486 	/* We don't yet support other algorithms */
487 	assert(session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA1);
488 
489 	input_buffer_length =
490 		16 +  /* Rm       */
491 		16 +  /* Rc       */
492 		1  +  /* ROLEm     */
493 		1  +  /* ULENGTHm  */
494 		strlen((const char *)intf->ssn_params.username);
495 
496 	input_buffer = malloc(input_buffer_length);
497 	if (input_buffer == NULL) {
498 		lprintf(LOG_ERR, "ipmitool: malloc failure");
499 		return 1;
500 	}
501 
502 	/*
503 	 * Fill the buffer.  I'm assuming that we're using the LSBF representation of the
504 	 * multibyte numbers in use.
505 	 */
506 
507 	/* Rm */
508 	#if WORDS_BIGENDIAN
509 	for (i = 0; i < 16; ++i)
510 		input_buffer[i] = session->v2_data.console_rand[16 - 1 - i];
511 	#else
512 	for (i = 0; i < 16; ++i)
513 		input_buffer[i] = session->v2_data.console_rand[i];
514 	#endif
515 
516 
517 	/* Rc */
518 	#if WORDS_BIGENDIAN
519 	for (i = 0; i < 16; ++i)
520 		input_buffer[16 + i] = session->v2_data.bmc_rand[16 - 1 - i];
521 	#else
522 	for (i = 0; i < 16; ++i)
523 		input_buffer[16 + i] = session->v2_data.bmc_rand[i];
524 	#endif
525 
526 	/* ROLEm */
527 	input_buffer[32] = session->v2_data.requested_role;
528 
529 	if (ipmi_oem_active(intf, "i82571spt")) {
530 		/*
531 		 * The HMAC calculation code in the Intel 82571 GbE
532 		 * skips this bit!  Looks like a GbE bug, but we need
533 		 * to work around it here anyway...
534 		 */
535 		input_buffer[32] &= ~0x10;
536 	}
537 
538 	/* ULENGTHm */
539 	input_buffer[33] = strlen((const char *)intf->ssn_params.username);
540 
541 	/* USERNAME */
542 	for (i = 0; i < input_buffer[33]; ++i)
543 		input_buffer[34 + i] = intf->ssn_params.username[i];
544 
545 	if (intf->ssn_params.kg[0])
546 	{
547 		/* We will be hashing with Kg */
548 		/*
549 		 * Section 13.31 of the IPMI v2 spec describes the SIK creation
550 		 * using Kg.  It specifies that Kg should not be truncated.
551 		 * Kg is set in ipmi_intf.
552 		 */
553 		input_key        = intf->ssn_params.kg;
554 	}
555 	else
556 	{
557 		/* We will be hashing with Kuid */
558 		input_key        = session->authcode;
559 	}
560 
561 
562 	if (verbose >= 2)
563 		printbuf((const uint8_t *)input_buffer, input_buffer_length, "session integrity key input");
564 
565 	lanplus_HMAC(session->v2_data.auth_alg,
566 				 input_key,
567 				 IPMI_AUTHCODE_BUFFER_SIZE,
568 				 input_buffer,
569 				 input_buffer_length,
570 				 session->v2_data.sik,
571 				 &mac_length);
572 
573 	free(input_buffer);
574 	input_buffer = NULL;
575 	assert(mac_length == 20);
576 
577 	/*
578 	 * The key MAC generated is 20 bytes, but we will only be using the first
579 	 * 12 for SHA1 96
580 	 */
581 	if (verbose >= 2)
582 		printbuf(session->v2_data.sik, 20, "Generated session integrity key");
583 
584 	return 0;
585 }
586 
587 
588 
589 /*
590  * lanplus_generate_k1
591  *
592  * Generate K1, the key presumably used to generate integrity authcodes
593  *
594  * We use the authentication algorithm to generated the HMAC, using
595  * the session integrity key (SIK) as our key.
596  *
597  * param session [in/out].
598  *
599  * returns 0 on success
600  *         1 on failure
601  */
602 int
603 lanplus_generate_k1(struct ipmi_session * session)
604 {
605 	uint32_t mac_length;
606 
607 	uint8_t CONST_1[] =
608 		{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
609 		 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01};
610 
611 	if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE)
612 		memcpy(session->v2_data.k1, CONST_1, 20);
613 	else
614 	{
615 		lanplus_HMAC(session->v2_data.auth_alg,
616 					 session->v2_data.sik,
617 					 IPMI_SIK_BUFFER_SIZE, /* SIK length */
618 					 CONST_1,
619 					 20,
620 					 session->v2_data.k1,
621 					 &mac_length);
622 		assert(mac_length == 20);
623 	}
624 
625 	if (verbose >= 2)
626 		printbuf(session->v2_data.k1, 20, "Generated K1");
627 
628 	return 0;
629 }
630 
631 
632 
633 /*
634  * lanplus_generate_k2
635  *
636  * Generate K2, the key used for RMCP+ AES encryption.
637  *
638  * We use the authentication algorithm to generated the HMAC, using
639  * the session integrity key (SIK) as our key.
640  *
641  * param session [in/out].
642  *
643  * returns 0 on success
644  *         1 on failure
645  */
646 int
647 lanplus_generate_k2(struct ipmi_session * session)
648 {
649 	uint32_t mac_length;
650 
651 	uint8_t CONST_2[] =
652 		{0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
653 		 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02};
654 
655 	if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE)
656 		memcpy(session->v2_data.k2, CONST_2, 20);
657 	else
658 	{
659 		lanplus_HMAC(session->v2_data.auth_alg,
660 					 session->v2_data.sik,
661 					 IPMI_SIK_BUFFER_SIZE, /* SIK length */
662 					 CONST_2,
663 					 20,
664 					 session->v2_data.k2,
665 					 &mac_length);
666 		assert(mac_length == 20);
667 	}
668 
669 	if (verbose >= 2)
670 		printbuf(session->v2_data.k2, 20, "Generated K2");
671 
672 	return 0;
673 }
674 
675 
676 
677 /*
678  * lanplus_encrypt_payload
679  *
680  * Perform the appropriate encryption on the input data.  Output the encrypted
681  * data to output, including the required confidentiality header and trailer.
682  * If the crypt_alg is IPMI_CRYPT_NONE, simply copy the input to the output and
683  * set bytes_written to input_length.
684  *
685  * param crypt_alg specifies the encryption algorithm (from table 13-19 of the
686  *       IPMI v2 spec)
687  * param key is the used as input to the encryption algorithmf
688  * param input is the input data to be encrypted
689  * param input_length is the length of the input data to be encrypted
690  * param output is the cipher text generated by the encryption process
691  * param bytes_written is the number of bytes written during the encryption
692  *       process
693  *
694  * returns 0 on success
695  *         1 on failure
696  */
697 int
698 lanplus_encrypt_payload(uint8_t crypt_alg,
699 		const uint8_t * key, const uint8_t * input,
700 		uint32_t input_length, uint8_t * output,
701 		uint16_t * bytes_written)
702 {
703 	uint8_t * padded_input;
704 	uint32_t    mod, i, bytes_encrypted;
705 	uint8_t   pad_length = 0;
706 
707 	if (crypt_alg == IPMI_CRYPT_NONE)
708 	{
709 		/* Just copy the input to the output */
710 		*bytes_written = input_length;
711 		return 0;
712 	}
713 
714 	/* Currently, we only support AES */
715 	assert(crypt_alg == IPMI_CRYPT_AES_CBC_128);
716 	assert(input_length <= IPMI_MAX_PAYLOAD_SIZE);
717 
718 
719 	/*
720 	 * The input to the AES encryption algorithm has to be a multiple of the
721 	 * block size (16 bytes).  The extra byte we are adding is the pad length
722 	 * byte.
723 	 */
724 	mod = (input_length + 1) % IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE;
725 	if (mod)
726 		pad_length = IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE - mod;
727 
728 	padded_input = (uint8_t*)malloc(input_length + pad_length + 1);
729 	if (padded_input == NULL) {
730 		lprintf(LOG_ERR, "ipmitool: malloc failure");
731 		return 1;
732 	}
733 	memcpy(padded_input, input, input_length);
734 
735 	/* add the pad */
736 	for (i = 0; i < pad_length; ++i)
737 		padded_input[input_length + i] = i + 1;
738 
739 	/* add the pad length */
740 	padded_input[input_length + pad_length] = pad_length;
741 
742 	/* Generate an initialization vector, IV, for the encryption process */
743 	if (lanplus_rand(output, IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE))
744 	{
745 		lprintf(LOG_ERR, "lanplus_encrypt_payload: Error generating IV");
746 		if (padded_input != NULL) {
747 			free(padded_input);
748 			padded_input = NULL;
749 		}
750 		return 1;
751 	}
752 
753 	if (verbose > 2)
754 		printbuf(output, IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE, ">> Initialization vector");
755 
756 
757 
758 	lanplus_encrypt_aes_cbc_128(output,                                     /* IV              */
759 								key,                                        /* K2              */
760 								padded_input,                               /* Data to encrypt */
761 								input_length + pad_length + 1,              /* Input length    */
762 								output + IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE, /* output          */
763 								&bytes_encrypted);                          /* bytes written   */
764 
765 	*bytes_written =
766 		IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE + /* IV */
767 		bytes_encrypted;
768 
769 	free(padded_input);
770 	padded_input = NULL;
771 
772 	return 0;
773 }
774 
775 
776 
777 /*
778  * lanplus_has_valid_auth_code
779  *
780  * Determine whether the packets authcode field is valid for packet.
781  *
782  * We always return success if any of the following are true.
783  *  - this is not an IPMIv2 packet
784  *  - the session is not yet active
785  *  - the packet specifies that it is not authenticated
786  *  - the integrity algorithm agreed upon during session creation is "none"
787  *
788  * The authcode is computed using the specified integrity algorithm starting
789  * with the AuthType / Format field, and ending with the field immediately
790  * preceeding the authcode itself.
791  *
792  * The key key used to generate the authcode MAC is K1.
793  *
794  * param rs holds the response structure.
795  * param session holds our session state, including our chosen algorithm, key, etc.
796  *
797  * returns 1 on success (authcode is valid)
798  *         0 on failure (autchode integrity check failed)
799  */
800 int
801 lanplus_has_valid_auth_code(struct ipmi_rs * rs, struct ipmi_session * session)
802 {
803 	uint8_t * bmc_authcode;
804 	uint8_t generated_authcode[IPMI_MAX_MAC_SIZE];
805 	uint32_t generated_authcode_length;
806 
807 
808 	if ((rs->session.authtype != IPMI_SESSION_AUTHTYPE_RMCP_PLUS) ||
809 		(session->v2_data.session_state != LANPLUS_STATE_ACTIVE)  ||
810 		(! rs->session.bAuthenticated)                            ||
811 		(session->v2_data.integrity_alg == IPMI_INTEGRITY_NONE))
812 		return 1;
813 
814 	/* We only support SHA1-96 now */
815 	assert(session->v2_data.integrity_alg == IPMI_INTEGRITY_HMAC_SHA1_96);
816 
817 	/*
818 	 * For SHA1-96, the authcode will be the last 12 bytes in the packet
819 	 */
820 	bmc_authcode = rs->data + (rs->data_len - IPMI_SHA1_AUTHCODE_SIZE);
821 
822 	lanplus_HMAC(session->v2_data.integrity_alg,
823 				 session->v2_data.k1,
824 				 IPMI_AUTHCODE_BUFFER_SIZE,
825 				 rs->data + IPMI_LANPLUS_OFFSET_AUTHTYPE,
826 				 rs->data_len - IPMI_LANPLUS_OFFSET_AUTHTYPE - IPMI_SHA1_AUTHCODE_SIZE,
827 				 generated_authcode,
828 				 &generated_authcode_length);
829 
830 	if (verbose > 3)
831 	{
832 		lprintf(LOG_DEBUG+2, "Validating authcode");
833 		printbuf(session->v2_data.k1, 20, "K1");
834 		printbuf(rs->data + IPMI_LANPLUS_OFFSET_AUTHTYPE,
835 				 rs->data_len - IPMI_LANPLUS_OFFSET_AUTHTYPE - IPMI_SHA1_AUTHCODE_SIZE,
836 				 "Authcode Input Data");
837 		printbuf(generated_authcode, 12, "Generated authcode");
838 		printbuf(bmc_authcode,       12, "Expected authcode");
839 	}
840 
841 
842 	assert(generated_authcode_length == 20);
843 	return (memcmp(bmc_authcode, generated_authcode, 12) == 0);
844 }
845 
846 
847 
848 /*
849  * lanplus_decrypt_payload
850  *
851  *
852  * param input points to the beginning of the payload (which will be the IV if
853  *       we are using AES)
854  * param payload_size [out] will be set to the size of the payload EXCLUDING
855  * padding
856  *
857  * returns 0 on success (we were able to successfully decrypt the packet)
858  *         1 on failure (we were unable to successfully decrypt the packet)
859  */
860 int
861 lanplus_decrypt_payload(uint8_t crypt_alg, const uint8_t * key,
862 		const uint8_t * input, uint32_t input_length,
863 		uint8_t * output, uint16_t * payload_size)
864 {
865 	uint8_t * decrypted_payload;
866 	uint32_t    bytes_decrypted;
867 
868 	if (crypt_alg == IPMI_CRYPT_NONE)
869 	{
870 		/* We are not encrypted.  The paylaod size is is everything. */
871 		*payload_size = input_length;
872 		memmove(output, input, input_length);
873 		return 0;
874 	}
875 
876 	/* We only support AES */
877 	assert(crypt_alg == IPMI_CRYPT_AES_CBC_128);
878 
879 	decrypted_payload = (uint8_t*)malloc(input_length);
880 	if (decrypted_payload == NULL) {
881 		lprintf(LOG_ERR, "ipmitool: malloc failure");
882 		return 1;
883 	}
884 
885 
886 	lanplus_decrypt_aes_cbc_128(input,                                /* IV              */
887 								key,                                  /* Key             */
888 								input                        +
889 								IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE,    /* Data to decrypt */
890 								input_length -
891 								IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE,    /* Input length    */
892 								decrypted_payload,                    /* output          */
893 								&bytes_decrypted);                    /* bytes written   */
894 
895 	if (bytes_decrypted != 0)
896 	{
897 		/* Success */
898 		uint8_t conf_pad_length;
899 		int i;
900 
901 		memmove(output,
902 				decrypted_payload,
903 				bytes_decrypted);
904 
905 		/*
906 		 * We have to determine the payload size, by substracting the padding, etc.
907 		 * The last byte of the decrypted payload is the confidentiality pad length.
908 		 */
909 		conf_pad_length = decrypted_payload[bytes_decrypted - 1];
910 		*payload_size = bytes_decrypted - conf_pad_length - 1;
911 
912 		/*
913 		 * Extra test to make sure that the padding looks like it should (should start
914 		 * with 0x01, 0x02, 0x03, etc...
915 		 */
916 		for (i = 0; i < conf_pad_length; ++i)
917 		{
918 			if (decrypted_payload[*payload_size + i] != (i + 1))
919 			{
920 				lprintf(LOG_ERR, "Malformed payload padding");
921 				assert(0);
922 			}
923 		}
924 	}
925 	else
926 	{
927 		lprintf(LOG_ERR, "ERROR: lanplus_decrypt_aes_cbc_128 decryptd 0 bytes");
928 		assert(0);
929 	}
930 
931 	free(decrypted_payload);
932 	decrypted_payload = NULL;
933 	return (bytes_decrypted == 0);
934 }
935