2
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions
8
* Redistribution of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
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.
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.
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.
32
* You acknowledge that this software is not designed or intended for use
33
* in the design, construction, operation or maintenance of any nuclear
40
#include <ipmitool/bswap.h>
41
#include <ipmitool/log.h>
43
#include "lanplus_crypt.h"
44
#include "lanplus_crypt_impl.h"
49
* lanplus_rakp2_hmac_matches
51
* param session holds all the state data that we need to generate the hmac
52
* param hmac is the HMAC sent by the BMC in the RAKP 2 message
54
* The HMAC was generated [per RFC2404] from :
56
* SIDm - Remote console session ID
57
* SIDc - BMC session ID
58
* Rm - Remote console random number
59
* Rc - BMC random number
61
* ROLEm - Requested privilege level (entire byte)
62
* ULENGTHm - Username length
63
* <UNAMEm> - Username (absent for null user names)
65
* generated by using Kuid. I am aware that the subscripts on the values
66
* look backwards, but that's the way they are written in the specification.
68
* If the authentication algorithm is IPMI_AUTH_RAKP_NONE, we return success.
70
* return 0 on success (the authcode matches)
71
* 1 on failure (the authcode does not match)
73
int lanplus_rakp2_hmac_matches(const struct ipmi_session * session,
74
const uint8_t * bmc_mac,
75
struct ipmi_intf * intf)
82
uint32_t SIDm_lsbf, SIDc_lsbf;
85
if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE)
88
/* We don't yet support other algorithms */
89
assert(session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA1);
100
strlen(session->username); /* optional */
102
buffer = malloc(bufferLength);
103
if (buffer == NULL) {
104
lprintf(LOG_ERR, "ipmitool: malloc failure");
109
* Fill the buffer. I'm assuming that we're using the LSBF representation of the
110
* multibyte numbers in use.
114
SIDm_lsbf = session->v2_data.console_id;
116
SIDm_lsbf = BSWAP_32(SIDm_lsbf);
119
memcpy(buffer, &SIDm_lsbf, 4);
122
SIDc_lsbf = session->v2_data.bmc_id;
124
SIDc_lsbf = BSWAP_32(SIDc_lsbf);
126
memcpy(buffer + 4, &SIDc_lsbf, 4);
130
for (i = 0; i < 16; ++i)
131
buffer[8 + i] = session->v2_data.console_rand[16 - 1 - i];
133
for (i = 0; i < 16; ++i)
134
buffer[8 + i] = session->v2_data.console_rand[i];
139
for (i = 0; i < 16; ++i)
140
buffer[24 + i] = session->v2_data.bmc_rand[16 - 1 - i];
142
for (i = 0; i < 16; ++i)
143
buffer[24 + i] = session->v2_data.bmc_rand[i];
148
for (i = 0; i < 16; ++i)
149
buffer[40 + i] = session->v2_data.bmc_guid[16 - 1 - i];
151
for (i = 0; i < 16; ++i)
152
buffer[40 + i] = session->v2_data.bmc_guid[i];
156
buffer[56] = session->v2_data.requested_role;
159
buffer[57] = strlen(session->username);
161
/* UserName [optional] */
162
for (i = 0; i < buffer[57]; ++i)
163
buffer[58 + i] = session->username[i];
167
printbuf(buffer, bufferLength, ">> rakp2 mac input buffer");
168
printbuf((char*)(session->authcode), IPMI_AUTHCODE_BUFFER_SIZE, ">> rakp2 mac key");
172
* The buffer is complete. Let's hash.
174
lanplus_HMAC(session->v2_data.auth_alg,
176
IPMI_AUTHCODE_BUFFER_SIZE,
187
printbuf(mac, macLength, ">> rakp2 mac as computed by the remote console");
190
return (memcmp(bmc_mac, mac, macLength) == 0);
196
* lanplus_rakp4_hmac_matches
198
* param session holds all the state data that we need to generate the hmac
199
* param hmac is the HMAC sent by the BMC in the RAKP 4 message
201
* The HMAC was generated [per RFC2404] from :
203
* Rm - Remote console random number
204
* SIDc - BMC session ID
207
* generated by using SIK (the session integrity key). I am aware that the
208
* subscripts on the values look backwards, but that's the way they are
209
* written in the specification.
211
* If the authentication algorithm is IPMI_AUTH_RAKP_NONE, we return success.
213
* return 1 on success (the authcode matches)
214
* 0 on failure (the authcode does not match)
217
int lanplus_rakp4_hmac_matches(const struct ipmi_session * session,
218
const uint8_t * bmc_mac,
219
struct ipmi_intf * intf)
228
if (ipmi_oem_active(intf, "intelplus")){
229
/* Intel BMC responds with the integrity Algorithm in RAKP4 */
230
if (session->v2_data.integrity_alg == IPMI_INTEGRITY_NONE)
233
/* We don't yet support other algorithms */
234
assert(session->v2_data.integrity_alg == IPMI_INTEGRITY_HMAC_SHA1_96);
237
if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE)
240
/* We don't yet support other algorithms */
241
assert(session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA1);
249
buffer = (char*)malloc(bufferLength);
250
if (buffer == NULL) {
251
lprintf(LOG_ERR, "ipmitool: malloc failure");
256
* Fill the buffer. I'm assuming that we're using the LSBF representation of the
257
* multibyte numbers in use.
262
for (i = 0; i < 16; ++i)
263
buffer[i] = session->v2_data.console_rand[16 - 1 - i];
265
for (i = 0; i < 16; ++i)
266
buffer[i] = session->v2_data.console_rand[i];
271
SIDc_lsbf = session->v2_data.bmc_id;
273
SIDc_lsbf = BSWAP_32(SIDc_lsbf);
275
memcpy(buffer + 16, &SIDc_lsbf, 4);
280
for (i = 0; i < 16; ++i)
281
buffer[i + 20] = session->v2_data.bmc_guid[16 - 1 - i];
283
for (i = 0; i < 16; ++i)
284
buffer[i + 20] = session->v2_data.bmc_guid[i];
290
printbuf(buffer, bufferLength, ">> rakp4 mac input buffer");
291
printbuf(session->v2_data.sik, 20l, ">> rakp4 mac key (sik)");
296
* The buffer is complete. Let's hash.
298
lanplus_HMAC((ipmi_oem_active(intf, "intelplus"))
299
? session->v2_data.integrity_alg
300
: session->v2_data.auth_alg ,
301
session->v2_data.sik,
302
IPMI_SIK_BUFFER_SIZE,
310
printbuf(bmc_mac, macLength, ">> rakp4 mac as computed by the BMC");
311
printbuf(mac, macLength, ">> rakp4 mac as computed by the remote console");
317
assert(macLength == 20);
318
return (memcmp(bmc_mac, mac, 12) == 0);
324
* lanplus_generate_rakp3_auth_code
326
* This auth code is an HMAC generated with :
328
* Rc - BMC random number
329
* SIDm - Console session ID
330
* ROLEm - Requested privilege level (entire byte)
331
* ULENGTHm - Username length
332
* <USERNAME> - Usename (absent for null usernames)
334
* The key used to generated the MAC is Kuid
336
* I am aware that the subscripts look backwards, but that is the way they are
337
* written in the spec.
339
* param output_buffer [out] will hold the generated MAC
340
* param session [in] holds all the state data we need to generate the auth code
341
* param mac_length [out] will be set to the length of the auth code
343
* returns 0 on success
346
int lanplus_generate_rakp3_authcode(char * output_buffer,
347
const struct ipmi_session * session,
348
uint32_t * mac_length,
349
struct ipmi_intf * intf)
352
int input_buffer_length, i;
357
if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE)
363
/* We don't yet support other algorithms */
364
assert(session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA1);
366
input_buffer_length =
371
strlen(session->username);
373
input_buffer = malloc(input_buffer_length);
374
if (input_buffer == NULL) {
375
lprintf(LOG_ERR, "ipmitool: malloc failure");
380
* Fill the buffer. I'm assuming that we're using the LSBF representation of the
381
* multibyte numbers in use.
386
for (i = 0; i < 16; ++i)
387
input_buffer[i] = session->v2_data.bmc_rand[16 - 1 - i];
389
for (i = 0; i < 16; ++i)
390
input_buffer[i] = session->v2_data.bmc_rand[i];
394
SIDm_lsbf = session->v2_data.console_id;
396
SIDm_lsbf = BSWAP_32(SIDm_lsbf);
398
memcpy(input_buffer + 16, &SIDm_lsbf, 4);
401
if (ipmi_oem_active(intf, "intelplus"))
402
input_buffer[20] = session->privlvl;
404
input_buffer[20] = session->v2_data.requested_role;
407
input_buffer[21] = strlen(session->username);
410
for (i = 0; i < input_buffer[21]; ++i)
411
input_buffer[22 + i] = session->username[i];
415
printbuf(input_buffer, input_buffer_length, ">> rakp3 mac input buffer");
416
printbuf((char*)(session->authcode), IPMI_AUTHCODE_BUFFER_SIZE, ">> rakp3 mac key");
419
lanplus_HMAC(session->v2_data.auth_alg,
421
IPMI_AUTHCODE_BUFFER_SIZE,
428
printbuf(output_buffer, *mac_length, "generated rakp3 mac");
439
* lanplus_generate_sik
441
* Generate the session integrity key (SIK) used for integrity checking
442
* during the IPMI v2 / RMCP+ session
444
* This session integrity key is a HMAC generated with :
446
* Rm - Console generated random number
447
* Rc - BMC generated random number
448
* ROLEm - Requested privilege level (entire byte)
449
* ULENGTHm - Username length
450
* <USERNAME> - Usename (absent for null usernames)
452
* The key used to generated the SIK is Kg if Kg is not null (two-key logins are
453
* enabled). Otherwise Kuid (the user authcode) is used as the key to genereate
456
* I am aware that the subscripts look backwards, but that is the way they are
457
* written in the spec.
459
* param session [in/out] contains our input and output fields.
461
* returns 0 on success
464
int lanplus_generate_sik(struct ipmi_session * session)
467
int input_buffer_length, i;
472
memset(session->v2_data.sik, 0, IPMI_SIK_BUFFER_SIZE);
474
if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE)
477
/* We don't yet support other algorithms */
478
assert(session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA1);
480
input_buffer_length =
485
strlen(session->username);
487
input_buffer = malloc(input_buffer_length);
488
if (input_buffer == NULL) {
489
lprintf(LOG_ERR, "ipmitool: malloc failure");
494
* Fill the buffer. I'm assuming that we're using the LSBF representation of the
495
* multibyte numbers in use.
500
for (i = 0; i < 16; ++i)
501
input_buffer[i] = session->v2_data.console_rand[16 - 1 - i];
503
for (i = 0; i < 16; ++i)
504
input_buffer[i] = session->v2_data.console_rand[i];
510
for (i = 0; i < 16; ++i)
511
input_buffer[16 + i] = session->v2_data.bmc_rand[16 - 1 - i];
513
for (i = 0; i < 16; ++i)
514
input_buffer[16 + i] = session->v2_data.bmc_rand[i];
518
input_buffer[32] = session->v2_data.requested_role;
521
input_buffer[33] = strlen(session->username);
524
for (i = 0; i < input_buffer[33]; ++i)
525
input_buffer[34 + i] = session->username[i];
527
if (session->v2_data.kg[0])
529
/* We will be hashing with Kg */
531
* TODO: Section 13.31 of the IPMI v2 spec describes the SIK creation
532
* using Kg. It specifies that Kg should not be truncated, but I
533
* do not know what is meant by that.
535
lprintf(LOG_ERR, "lanplus_generate_sik: We dont yet support hashing with Kg");
538
input_key = session->v2_data.kg;
542
/* We will be hashing with Kuid */
543
input_key = session->authcode;
548
printbuf(input_buffer, input_buffer_length, "session integrity key input");
550
lanplus_HMAC(session->v2_data.auth_alg,
552
IPMI_AUTHCODE_BUFFER_SIZE,
555
session->v2_data.sik,
559
assert(mac_length == 20);
562
* The key MAC generated is 20 bytes, but we will only be using the first
566
printbuf(session->v2_data.sik, 20, "Generated session integrity key");
574
* lanplus_generate_k1
576
* Generate K1, the key presumably used to generate integrity authcodes
578
* We use the authentication algorithm to generated the HMAC, using
579
* the session integrity key (SIK) as our key.
581
* param session [in/out].
583
* returns 0 on success
586
int lanplus_generate_k1(struct ipmi_session * session)
591
{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
592
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01};
594
if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE)
595
memcpy(session->v2_data.k1, CONST_1, 20);
598
lanplus_HMAC(session->v2_data.auth_alg,
599
session->v2_data.sik,
600
IPMI_SIK_BUFFER_SIZE, /* SIK length */
605
assert(mac_length == 20);
609
printbuf(session->v2_data.k1, 20, "Generated K1");
617
* lanplus_generate_k2
619
* Generate K2, the key used for RMCP+ AES encryption.
621
* We use the authentication algorithm to generated the HMAC, using
622
* the session integrity key (SIK) as our key.
624
* param session [in/out].
626
* returns 0 on success
629
int lanplus_generate_k2(struct ipmi_session * session)
634
{0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
635
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02};
637
if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE)
638
memcpy(session->v2_data.k2, CONST_2, 20);
641
lanplus_HMAC(session->v2_data.auth_alg,
642
session->v2_data.sik,
643
IPMI_SIK_BUFFER_SIZE, /* SIK length */
648
assert(mac_length == 20);
652
printbuf(session->v2_data.k2, 20, "Generated K2");
660
* lanplus_encrypt_payload
662
* Perform the appropriate encryption on the input data. Output the encrypted
663
* data to output, including the required confidentiality header and trailer.
664
* If the crypt_alg is IPMI_CRYPT_NONE, simply copy the input to the output and
665
* set bytes_written to input_length.
667
* param crypt_alg specifies the encryption algorithm (from table 13-19 of the
669
* param key is the used as input to the encryption algorithmf
670
* param input is the input data to be encrypted
671
* param input_length is the length of the input data to be encrypted
672
* param output is the cipher text generated by the encryption process
673
* param bytes_written is the number of bytes written during the encryption
676
* returns 0 on success
679
int lanplus_encrypt_payload(uint8_t crypt_alg,
681
const uint8_t * input,
682
uint32_t input_length,
684
uint16_t * bytes_written)
686
uint8_t * padded_input;
687
uint32_t mod, i, bytes_encrypted;
688
uint8_t pad_length = 0;
690
if (crypt_alg == IPMI_CRYPT_NONE)
692
/* Just copy the input to the output */
693
*bytes_written = input_length;
697
/* Currently, we only support AES */
698
assert(crypt_alg == IPMI_CRYPT_AES_CBC_128);
699
assert(input_length <= IPMI_MAX_PAYLOAD_SIZE);
703
* The input to the AES encryption algorithm has to be a multiple of the
704
* block size (16 bytes). The extra byte we are adding is the pad length
707
mod = (input_length + 1) % IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE;
709
pad_length = IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE - mod;
711
padded_input = (uint8_t*)malloc(input_length + pad_length + 1);
712
if (padded_input == NULL) {
713
lprintf(LOG_ERR, "ipmitool: malloc failure");
716
memcpy(padded_input, input, input_length);
719
for (i = 0; i < pad_length; ++i)
720
padded_input[input_length + i] = i + 1;
722
/* add the pad length */
723
padded_input[input_length + pad_length] = pad_length;
725
/* Generate an initialization vector, IV, for the encryption process */
726
if (lanplus_rand(output, IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE))
728
lprintf(LOG_ERR, "lanplus_encrypt_payload: Error generating IV");
733
printbuf(output, IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE, ">> Initialization vector");
737
lanplus_encrypt_aes_cbc_128(output, /* IV */
739
padded_input, /* Data to encrypt */
740
input_length + pad_length + 1, /* Input length */
741
output + IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE, /* output */
742
&bytes_encrypted); /* bytes written */
745
IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE + /* IV */
756
* lanplus_has_valid_auth_code
758
* Determine whether the packets authcode field is valid for packet.
760
* We always return success if any of the following are true.
761
* - this is not an IPMIv2 packet
762
* - the session is not yet active
763
* - the packet specifies that it is not authenticated
764
* - the integrity algorithm agreed upon during session creation is "none"
766
* The authcode is computed using the specified integrity algorithm starting
767
* with the AuthType / Format field, and ending with the field immediately
768
* preceeding the authcode itself.
770
* The key key used to generate the authcode MAC is K1.
772
* param rs holds the response structure.
773
* param session holds our session state, including our chosen algorithm, key, etc.
775
* returns 1 on success (authcode is valid)
776
* 0 on failure (autchode integrity check failed)
778
int lanplus_has_valid_auth_code(struct ipmi_rs * rs,
779
struct ipmi_session * session)
781
uint8_t * bmc_authcode;
782
uint8_t generated_authcode[IPMI_MAX_MAC_SIZE];
783
uint32_t generated_authcode_length;
786
if ((rs->session.authtype != IPMI_SESSION_AUTHTYPE_RMCP_PLUS) ||
787
(session->v2_data.session_state != LANPLUS_STATE_ACTIVE) ||
788
(! rs->session.bAuthenticated) ||
789
(session->v2_data.integrity_alg == IPMI_INTEGRITY_NONE))
792
/* We only support SHA1-96 now */
793
assert(session->v2_data.integrity_alg == IPMI_INTEGRITY_HMAC_SHA1_96);
796
* For SHA1-96, the authcode will be the last 12 bytes in the packet
798
bmc_authcode = rs->data + (rs->data_len - IPMI_SHA1_AUTHCODE_SIZE);
800
lanplus_HMAC(session->v2_data.integrity_alg,
802
IPMI_AUTHCODE_BUFFER_SIZE,
803
rs->data + IMPI_LANPLUS_OFFSET_AUTHTYPE,
804
rs->data_len - IMPI_LANPLUS_OFFSET_AUTHTYPE - IPMI_SHA1_AUTHCODE_SIZE,
806
&generated_authcode_length);
810
lprintf(LOG_DEBUG+2, "Validating authcode");
811
printbuf(session->v2_data.k1, 20, "K1");
812
printbuf(rs->data + IMPI_LANPLUS_OFFSET_AUTHTYPE,
813
rs->data_len - IMPI_LANPLUS_OFFSET_AUTHTYPE - IPMI_SHA1_AUTHCODE_SIZE,
814
"Authcode Input Data");
815
printbuf(generated_authcode, 12, "Generated authcode");
816
printbuf(bmc_authcode, 12, "Expected authcode");
820
assert(generated_authcode_length == 20);
821
return (memcmp(bmc_authcode, generated_authcode, 12) == 0);
827
* lanplus_decrypt_payload
830
* param input points to the beginning of the payload (which will be the IV if
832
* param payload_size [out] will be set to the size of the payload EXCLUDING
835
* returns 0 on success (we were able to successfully decrypt the packet)
836
* 1 on failure (we were unable to successfully decrypt the packet)
838
int lanplus_decrypt_payload(uint8_t crypt_alg,
840
const uint8_t * input,
841
uint32_t input_length,
843
uint16_t * payload_size)
845
uint8_t * decrypted_payload;
846
uint32_t bytes_decrypted;
848
if (crypt_alg == IPMI_CRYPT_NONE)
850
/* We are not encrypted. The paylaod size is is everything. */
851
*payload_size = input_length;
852
memmove(output, input, input_length);
856
/* We only support AES */
857
assert(crypt_alg == IPMI_CRYPT_AES_CBC_128);
859
decrypted_payload = (uint8_t*)malloc(input_length);
860
if (decrypted_payload == NULL) {
861
lprintf(LOG_ERR, "ipmitool: malloc failure");
866
lanplus_decrypt_aes_cbc_128(input, /* IV */
869
IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE, /* Data to decrypt */
871
IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE, /* Input length */
872
decrypted_payload, /* output */
873
&bytes_decrypted); /* bytes written */
875
if (bytes_decrypted != 0)
878
uint8_t conf_pad_length;
886
* We have to determine the payload size, by substracting the padding, etc.
887
* The last byte of the decrypted payload is the confidentiality pad length.
889
conf_pad_length = decrypted_payload[bytes_decrypted - 1];
890
*payload_size = bytes_decrypted - conf_pad_length - 1;
893
* Extra test to make sure that the padding looks like it should (should start
894
* with 0x01, 0x02, 0x03, etc...
896
for (i = 0; i < conf_pad_length; ++i)
898
if (decrypted_payload[*payload_size + i] == i)
900
lprintf(LOG_ERR, "Malformed payload padding");
907
lprintf(LOG_ERR, "ERROR: lanplus_decrypt_aes_cbc_128 decryptd 0 bytes");
911
free(decrypted_payload);
912
return (bytes_decrypted == 0);