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
lanplus_rakp2_hmac_matches(const struct ipmi_session * session,const uint8_t * bmc_mac,struct ipmi_intf * intf)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
lanplus_rakp4_hmac_matches(const struct ipmi_session * session,const uint8_t * bmc_mac,struct ipmi_intf * intf)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
lanplus_generate_rakp3_authcode(uint8_t * output_buffer,const struct ipmi_session * session,uint32_t * mac_length,struct ipmi_intf * intf)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
lanplus_generate_sik(struct ipmi_session * session,struct ipmi_intf * intf)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
lanplus_generate_k1(struct ipmi_session * session)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
lanplus_generate_k2(struct ipmi_session * session)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
lanplus_encrypt_payload(uint8_t crypt_alg,const uint8_t * key,const uint8_t * input,uint32_t input_length,uint8_t * output,uint16_t * bytes_written)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
lanplus_has_valid_auth_code(struct ipmi_rs * rs,struct ipmi_session * session)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
lanplus_decrypt_payload(uint8_t crypt_alg,const uint8_t * key,const uint8_t * input,uint32_t input_length,uint8_t * output,uint16_t * payload_size)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