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