xref: /openbmc/ipmitool/src/plugins/lanplus/lanplus_crypt.c (revision eb54136775f63a6a159f3c55ee4772d7aa363cc4)
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