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