1 /*
2 * Copyright (C) 2003-2015 FreeIPMI Core Team
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif /* HAVE_CONFIG_H */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #ifdef STDC_HEADERS
26 #include <string.h>
27 #endif /* STDC_HEADERS */
28 #include <limits.h>
29 #include <assert.h>
30 #include <errno.h>
31
32 #include "freeipmi/interface/ipmi-rmcpplus-interface.h"
33 #include "freeipmi/cmds/ipmi-messaging-support-cmds.h"
34 #include "freeipmi/cmds/ipmi-sol-cmds.h"
35 #include "freeipmi/fiid/fiid.h"
36 #include "freeipmi/interface/ipmi-interface.h"
37 #include "freeipmi/interface/ipmi-lan-interface.h"
38 #include "freeipmi/interface/rmcp-interface.h"
39 #include "freeipmi/payload/ipmi-sol-payload.h"
40 #include "freeipmi/spec/ipmi-authentication-type-spec.h"
41 #include "freeipmi/spec/ipmi-privilege-level-spec.h"
42 #include "freeipmi/spec/ipmi-rmcpplus-status-spec.h"
43 #include "freeipmi/util/ipmi-rmcpplus-util.h"
44 #include "freeipmi/util/ipmi-util.h"
45
46 #include "ipmi-network.h"
47 #include "libcommon/ipmi-crypt.h"
48 #include "libcommon/ipmi-fiid-util.h"
49 #include "libcommon/ipmi-fill-util.h"
50 #include "libcommon/ipmi-md5.h"
51 #include "libcommon/ipmi-trace.h"
52
53 #include "freeipmi-portability.h"
54 #include "secure.h"
55
56 #define IPMI_MAX_RMCPPLUS_AUTHENTICATION_CODE_LENGTH 64
57 #define IPMI_MAX_CONFIDENTIALITY_HEADER_LENGTH 64
58 #define IPMI_MAX_CONFIDENTIALITY_TRAILER_LENGTH 64
59 #define IPMI_MAX_KEY_EXCHANGE_AUTHENTICATION_CODE_LENGTH 64
60
61 #define IPMI_MAX_INTEGRITY_DATA_LENGTH 32
62
63 fiid_template_t tmpl_rmcpplus_session_hdr =
64 {
65 { 4, "authentication_type", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
66 { 4, "reserved1", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
67 { 6, "payload_type", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
68 { 1, "payload_type.authenticated", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
69 { 1, "payload_type.encrypted", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
70 { 24, "oem_iana", FIID_FIELD_OPTIONAL | FIID_FIELD_LENGTH_FIXED},
71 { 8, "reserved2", FIID_FIELD_OPTIONAL | FIID_FIELD_LENGTH_FIXED},
72 { 16, "oem_payload_id", FIID_FIELD_OPTIONAL | FIID_FIELD_LENGTH_FIXED},
73 { 32, "session_id", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
74 /* 0h outside of a session, seperate #'s if authenticated or unauthenticated session */
75 { 32, "session_sequence_number", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
76 /* length of just the payload */
77 { 16, "ipmi_payload_len", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
78 { 0, "", 0}
79 };
80
81 /* doesn't exist if session_id = 0h */
82 fiid_template_t tmpl_rmcpplus_session_trlr =
83 {
84 { 32, "integrity_pad", FIID_FIELD_OPTIONAL | FIID_FIELD_LENGTH_VARIABLE},
85 { 8, "pad_length", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
86 { 8, "next_header", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
87 { 256, "authentication_code", FIID_FIELD_OPTIONAL | FIID_FIELD_LENGTH_VARIABLE},
88 { 0, "", 0}
89 };
90 /* note: the ipmi spec wording is terrible. The integrity pad is to
91 * ensure that the data passed to the HMAC is a multiple of 4, not
92 * just the integrity field. Sigh ...
93 */
94
95 fiid_template_t tmpl_rmcpplus_payload =
96 {
97 { 512, "confidentiality_header", FIID_FIELD_OPTIONAL | FIID_FIELD_LENGTH_VARIABLE},
98 /* 524288 = 65536 * 8 = 2^16 * 8, b/c ipmi_payload_len is 2 bytes */
99 { 524288, "payload_data", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_VARIABLE},
100 { 512, "confidentiality_trailer", FIID_FIELD_OPTIONAL | FIID_FIELD_LENGTH_VARIABLE},
101 { 0, "", 0}
102 };
103
104 fiid_template_t tmpl_rmcpplus_open_session_request =
105 {
106 { 8, "message_tag", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
107 { 4, "requested_maximum_privilege_level", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
108 { 4, "reserved1", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
109 { 16, "reserved2", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
110 { 32, "remote_console_session_id", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
111 { 8, "authentication_payload.payload_type", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
112 { 16, "reserved3", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
113 { 8, "authentication_payload.payload_length", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
114 { 6, "authentication_payload.authentication_algorithm", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
115 { 2, "reserved4", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
116 { 24, "reserved5", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
117 { 8, "integrity_payload.payload_type", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
118 { 16, "reserved6", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
119 { 8, "integrity_payload.payload_length", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
120 { 6, "integrity_payload.integrity_algorithm", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
121 { 2, "reserved7", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
122 { 24, "reserved8", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
123 { 8, "confidentiality_payload.payload_type", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
124 { 16, "reserved9", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
125 { 8, "confidentiality_payload.payload_length", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
126 { 6, "confidentiality_payload.confidentiality_algorithm", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
127 { 2, "reserved10", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
128 { 24, "reserved11", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
129 { 0, "", 0}
130 };
131
132 fiid_template_t tmpl_rmcpplus_open_session_response =
133 {
134 { 8, "message_tag", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED | FIID_FIELD_MAKES_PACKET_SUFFICIENT},
135 { 8, "rmcpplus_status_code", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED | FIID_FIELD_MAKES_PACKET_SUFFICIENT},
136 { 4, "maximum_privilege_level", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
137 { 4, "reserved1", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
138 { 8, "reserved2", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
139 { 32, "remote_console_session_id", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
140 /* 0h not valid */
141 { 32, "managed_system_session_id", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
142 { 8, "authentication_payload.payload_type", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
143 { 16, "reserved3", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
144 { 8, "authentication_payload.payload_length", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
145 { 6, "authentication_payload.authentication_algorithm", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
146 { 2, "reserved4", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
147 { 24, "reserved5", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
148 { 8, "integrity_payload.payload_type", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
149 { 16, "reserved6", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
150 { 8, "integrity_payload.payload_length", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
151 { 6, "integrity_payload.integrity_algorithm", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
152 { 2, "reserved7", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
153 { 24, "reserved8", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
154 { 8, "confidentiality_payload.payload_type", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
155 { 16, "reserved9", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
156 { 8, "confidentiality_payload.payload_length", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
157 { 6, "confidentiality_payload.confidentiality_algorithm", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
158 { 2, "reserved10", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
159 { 24, "reserved11", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
160 { 0, "", 0}
161 };
162
163 fiid_template_t tmpl_rmcpplus_rakp_message_1 =
164 {
165 { 8, "message_tag", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
166 { 24, "reserved1", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
167 { 32, "managed_system_session_id", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
168 { 128, "remote_console_random_number", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
169 { 4, "requested_maximum_privilege_level", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
170 { 1, "name_only_lookup", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
171 { 3, "reserved2", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
172 { 16, "reserved3", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
173 { 8, "user_name_length", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
174 { 128, "user_name", FIID_FIELD_OPTIONAL | FIID_FIELD_LENGTH_VARIABLE},
175 { 0, "", 0}
176 };
177
178 fiid_template_t tmpl_rmcpplus_rakp_message_2 =
179 {
180 { 8, "message_tag", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED | FIID_FIELD_MAKES_PACKET_SUFFICIENT},
181 { 8, "rmcpplus_status_code", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED | FIID_FIELD_MAKES_PACKET_SUFFICIENT},
182 { 16, "reserved1", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
183 { 32, "remote_console_session_id", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
184 { 128, "managed_system_random_number", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
185 { 128, "managed_system_guid", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
186 { 512, "key_exchange_authentication_code", FIID_FIELD_OPTIONAL | FIID_FIELD_LENGTH_VARIABLE},
187 { 0, "", 0}
188 };
189
190 fiid_template_t tmpl_rmcpplus_rakp_message_3 =
191 {
192 { 8, "message_tag", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
193 { 8, "rmcpplus_status_code", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
194 { 16, "reserved1", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
195 { 32, "managed_system_session_id", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
196 { 512, "key_exchange_authentication_code", FIID_FIELD_OPTIONAL | FIID_FIELD_LENGTH_VARIABLE},
197 { 0, "", 0}
198 };
199
200 /* achu: The IPMI 2.0 Spec version 1.0 lists the 4th field as
201 * "management_console_session_id", not "managed_system_session_id"
202 * or "remote_console_session_id". I'm assuming this is a typo and
203 * that "remote_console_session_id" is what is really meant.
204 */
205 fiid_template_t tmpl_rmcpplus_rakp_message_4 =
206 {
207 { 8, "message_tag", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED | FIID_FIELD_MAKES_PACKET_SUFFICIENT},
208 { 8, "rmcpplus_status_code", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED | FIID_FIELD_MAKES_PACKET_SUFFICIENT},
209 { 16, "reserved1", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
210 { 32, "remote_console_session_id", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
211 { 512, "integrity_check_value", FIID_FIELD_OPTIONAL | FIID_FIELD_LENGTH_VARIABLE},
212 { 0, "", 0}
213 };
214
215 int
ipmi_rmcpplus_init(void)216 ipmi_rmcpplus_init (void)
217 {
218 if (crypt_init ())
219 return (-1);
220 return (0);
221 }
222
223 int
fill_rmcpplus_session_hdr(uint8_t payload_type,uint8_t payload_authenticated,uint8_t payload_encrypted,uint32_t oem_iana,uint16_t oem_payload_id,uint32_t session_id,uint32_t session_sequence_number,fiid_obj_t obj_rmcpplus_session_hdr)224 fill_rmcpplus_session_hdr (uint8_t payload_type,
225 uint8_t payload_authenticated,
226 uint8_t payload_encrypted,
227 uint32_t oem_iana,
228 uint16_t oem_payload_id,
229 uint32_t session_id,
230 uint32_t session_sequence_number,
231 fiid_obj_t obj_rmcpplus_session_hdr)
232 {
233 if (!IPMI_PAYLOAD_TYPE_VALID (payload_type)
234 || !IPMI_PAYLOAD_AUTHENTICATED_FLAG_VALID (payload_authenticated)
235 || !IPMI_PAYLOAD_ENCRYPTED_FLAG_VALID (payload_encrypted)
236 || (IPMI_PAYLOAD_TYPE_SESSION_SETUP (payload_type)
237 && (payload_authenticated
238 || payload_encrypted
239 || session_id
240 || session_sequence_number))
241 || !fiid_obj_valid (obj_rmcpplus_session_hdr))
242 {
243 SET_ERRNO (EINVAL);
244 return (-1);
245 }
246
247 if (FIID_OBJ_TEMPLATE_COMPARE (obj_rmcpplus_session_hdr, tmpl_rmcpplus_session_hdr) < 0)
248 {
249 ERRNO_TRACE (errno);
250 return (-1);
251 }
252
253 FILL_FIID_OBJ_CLEAR (obj_rmcpplus_session_hdr);
254
255 FILL_FIID_OBJ_SET (obj_rmcpplus_session_hdr, "authentication_type", IPMI_AUTHENTICATION_TYPE_RMCPPLUS);
256 FILL_FIID_OBJ_SET (obj_rmcpplus_session_hdr, "reserved1", 0);
257 FILL_FIID_OBJ_SET (obj_rmcpplus_session_hdr, "payload_type", payload_type);
258 FILL_FIID_OBJ_SET (obj_rmcpplus_session_hdr, "payload_type.authenticated", payload_authenticated);
259 FILL_FIID_OBJ_SET (obj_rmcpplus_session_hdr, "payload_type.encrypted", payload_encrypted);
260 if (payload_type == IPMI_PAYLOAD_TYPE_OEM_EXPLICIT)
261 {
262 FILL_FIID_OBJ_SET (obj_rmcpplus_session_hdr, "oem_iana", oem_iana);
263 FILL_FIID_OBJ_SET (obj_rmcpplus_session_hdr, "reserved2", 0);
264 FILL_FIID_OBJ_SET (obj_rmcpplus_session_hdr, "oem_payload_id", oem_payload_id);
265 }
266 FILL_FIID_OBJ_SET (obj_rmcpplus_session_hdr, "session_id", session_id);
267 FILL_FIID_OBJ_SET (obj_rmcpplus_session_hdr, "session_sequence_number", session_sequence_number);
268
269 /* ipmi_payload_len will be calculated during packet assembly */
270
271 return (0);
272 }
273
274 int
fill_rmcpplus_session_trlr(fiid_obj_t obj_rmcpplus_session_trlr)275 fill_rmcpplus_session_trlr (fiid_obj_t obj_rmcpplus_session_trlr)
276 {
277 if (!fiid_obj_valid (obj_rmcpplus_session_trlr))
278 {
279 SET_ERRNO (EINVAL);
280 return (-1);
281 }
282
283 if (FIID_OBJ_TEMPLATE_COMPARE (obj_rmcpplus_session_trlr, tmpl_rmcpplus_session_trlr) < 0)
284 {
285 ERRNO_TRACE (errno);
286 return (-1);
287 }
288
289 FILL_FIID_OBJ_CLEAR (obj_rmcpplus_session_trlr);
290
291 /* Computing hashes and checking for correct input is done during
292 * the packet assembly. Padding calculations will also be done
293 * during packet assembly.
294 */
295
296 FILL_FIID_OBJ_SET (obj_rmcpplus_session_trlr, "next_header", IPMI_NEXT_HEADER);
297
298 return (0);
299 }
300
301 int
fill_rmcpplus_payload(const void * confidentiality_header,unsigned int confidentiality_header_len,const void * payload_data,unsigned int payload_data_len,const void * confidentiality_trailer,unsigned int confidentiality_trailer_len,fiid_obj_t obj_cmd_rq)302 fill_rmcpplus_payload (const void *confidentiality_header,
303 unsigned int confidentiality_header_len,
304 const void *payload_data,
305 unsigned int payload_data_len,
306 const void *confidentiality_trailer,
307 unsigned int confidentiality_trailer_len,
308 fiid_obj_t obj_cmd_rq)
309 {
310 if ((confidentiality_header && confidentiality_header_len > IPMI_MAX_CONFIDENTIALITY_HEADER_LENGTH)
311 || (payload_data && payload_data_len > IPMI_MAX_PAYLOAD_LENGTH)
312 || (confidentiality_trailer && confidentiality_trailer_len > IPMI_MAX_CONFIDENTIALITY_TRAILER_LENGTH)
313 || !fiid_obj_valid (obj_cmd_rq))
314 {
315 SET_ERRNO (EINVAL);
316 return (-1);
317 }
318
319 if (FIID_OBJ_TEMPLATE_COMPARE (obj_cmd_rq, tmpl_rmcpplus_payload) < 0)
320 {
321 ERRNO_TRACE (errno);
322 return (-1);
323 }
324
325 FILL_FIID_OBJ_CLEAR (obj_cmd_rq);
326
327 if (confidentiality_header)
328 FILL_FIID_OBJ_SET_DATA (obj_cmd_rq,
329 "confidentiality_header",
330 confidentiality_header,
331 confidentiality_header_len);
332
333 if (payload_data)
334 FILL_FIID_OBJ_SET_DATA (obj_cmd_rq,
335 "payload_data",
336 payload_data,
337 payload_data_len);
338
339 if (confidentiality_trailer)
340 FILL_FIID_OBJ_SET_DATA (obj_cmd_rq,
341 "confidentiality_trailer",
342 confidentiality_trailer,
343 confidentiality_trailer_len);
344
345 return (0);
346 }
347
348 int
fill_rmcpplus_open_session(uint8_t message_tag,uint8_t requested_maximum_privilege_level,uint32_t remote_console_session_id,uint8_t authentication_algorithm,uint8_t integrity_algorithm,uint8_t confidentiality_algorithm,fiid_obj_t obj_cmd_rq)349 fill_rmcpplus_open_session (uint8_t message_tag,
350 uint8_t requested_maximum_privilege_level,
351 uint32_t remote_console_session_id,
352 uint8_t authentication_algorithm,
353 uint8_t integrity_algorithm,
354 uint8_t confidentiality_algorithm,
355 fiid_obj_t obj_cmd_rq)
356 {
357 if (!IPMI_2_0_PRIVILEGE_LEVEL_VALID (requested_maximum_privilege_level)
358 || !IPMI_AUTHENTICATION_ALGORITHM_VALID (authentication_algorithm)
359 || !IPMI_INTEGRITY_ALGORITHM_VALID (integrity_algorithm)
360 || !IPMI_CONFIDENTIALITY_ALGORITHM_VALID (confidentiality_algorithm)
361 || !fiid_obj_valid (obj_cmd_rq))
362 {
363 SET_ERRNO (EINVAL);
364 return (-1);
365 }
366
367 if (FIID_OBJ_TEMPLATE_COMPARE (obj_cmd_rq, tmpl_rmcpplus_open_session_request) < 0)
368 {
369 ERRNO_TRACE (errno);
370 return (-1);
371 }
372
373 FILL_FIID_OBJ_CLEAR (obj_cmd_rq);
374
375 FILL_FIID_OBJ_SET (obj_cmd_rq,
376 "message_tag",
377 message_tag);
378 FILL_FIID_OBJ_SET (obj_cmd_rq,
379 "reserved1",
380 0);
381 FILL_FIID_OBJ_SET (obj_cmd_rq,
382 "reserved2",
383 0);
384 FILL_FIID_OBJ_SET (obj_cmd_rq,
385 "requested_maximum_privilege_level",
386 requested_maximum_privilege_level);
387 FILL_FIID_OBJ_SET (obj_cmd_rq,
388 "remote_console_session_id",
389 remote_console_session_id);
390 FILL_FIID_OBJ_SET (obj_cmd_rq,
391 "authentication_payload.payload_type",
392 IPMI_AUTHENTICATION_PAYLOAD_TYPE);
393 FILL_FIID_OBJ_SET (obj_cmd_rq,
394 "reserved3",
395 0);
396 FILL_FIID_OBJ_SET (obj_cmd_rq,
397 "authentication_payload.payload_length",
398 IPMI_AUTHENTICATION_PAYLOAD_LENGTH);
399 FILL_FIID_OBJ_SET (obj_cmd_rq,
400 "authentication_payload.authentication_algorithm",
401 authentication_algorithm);
402 FILL_FIID_OBJ_SET (obj_cmd_rq,
403 "reserved4",
404 0);
405 FILL_FIID_OBJ_SET (obj_cmd_rq,
406 "reserved5",
407 0);
408 FILL_FIID_OBJ_SET (obj_cmd_rq,
409 "integrity_payload.payload_type",
410 IPMI_INTEGRITY_PAYLOAD_TYPE);
411 FILL_FIID_OBJ_SET (obj_cmd_rq,
412 "reserved6",
413 0);
414 FILL_FIID_OBJ_SET (obj_cmd_rq,
415 "integrity_payload.payload_length",
416 IPMI_INTEGRITY_PAYLOAD_LENGTH);
417 FILL_FIID_OBJ_SET (obj_cmd_rq,
418 "integrity_payload.integrity_algorithm",
419 integrity_algorithm);
420 FILL_FIID_OBJ_SET (obj_cmd_rq,
421 "reserved7",
422 0);
423 FILL_FIID_OBJ_SET (obj_cmd_rq,
424 "reserved8",
425 0);
426 FILL_FIID_OBJ_SET (obj_cmd_rq,
427 "confidentiality_payload.payload_type",
428 IPMI_CONFIDENTIALITY_PAYLOAD_TYPE);
429 FILL_FIID_OBJ_SET (obj_cmd_rq,
430 "reserved9",
431 0);
432 FILL_FIID_OBJ_SET (obj_cmd_rq,
433 "confidentiality_payload.payload_length",
434 IPMI_CONFIDENTIALITY_PAYLOAD_LENGTH);
435 FILL_FIID_OBJ_SET (obj_cmd_rq,
436 "confidentiality_payload.confidentiality_algorithm",
437 confidentiality_algorithm);
438 FILL_FIID_OBJ_SET (obj_cmd_rq,
439 "reserved10",
440 0);
441 FILL_FIID_OBJ_SET (obj_cmd_rq,
442 "reserved11",
443 0);
444
445 return (0);
446 }
447
448 int
fill_rmcpplus_rakp_message_1(uint8_t message_tag,uint32_t managed_system_session_id,const void * remote_console_random_number,unsigned int remote_console_random_number_len,uint8_t requested_maximum_privilege_level,uint8_t name_only_lookup_flag,const char * user_name,unsigned int user_name_len,fiid_obj_t obj_cmd_rq)449 fill_rmcpplus_rakp_message_1 (uint8_t message_tag,
450 uint32_t managed_system_session_id,
451 const void *remote_console_random_number,
452 unsigned int remote_console_random_number_len,
453 uint8_t requested_maximum_privilege_level,
454 uint8_t name_only_lookup_flag,
455 const char *user_name,
456 unsigned int user_name_len,
457 fiid_obj_t obj_cmd_rq)
458 {
459 if (!remote_console_random_number
460 || (remote_console_random_number_len < IPMI_REMOTE_CONSOLE_RANDOM_NUMBER_LENGTH)
461 || !IPMI_PRIVILEGE_LEVEL_VALID (requested_maximum_privilege_level)
462 || !IPMI_USER_NAME_LOOKUP_VALID (name_only_lookup_flag)
463 || (user_name && user_name_len > IPMI_MAX_USER_NAME_LENGTH)
464 || !fiid_obj_valid (obj_cmd_rq))
465 {
466 SET_ERRNO (EINVAL);
467 return (-1);
468 }
469
470 if (FIID_OBJ_TEMPLATE_COMPARE (obj_cmd_rq, tmpl_rmcpplus_rakp_message_1) < 0)
471 {
472 ERRNO_TRACE (errno);
473 return (-1);
474 }
475
476 FILL_FIID_OBJ_CLEAR (obj_cmd_rq);
477
478 FILL_FIID_OBJ_SET (obj_cmd_rq,
479 "message_tag",
480 message_tag);
481 FILL_FIID_OBJ_SET (obj_cmd_rq,
482 "reserved1",
483 0);
484 FILL_FIID_OBJ_SET (obj_cmd_rq,
485 "managed_system_session_id",
486 managed_system_session_id);
487 FILL_FIID_OBJ_SET_DATA (obj_cmd_rq,
488 "remote_console_random_number",
489 remote_console_random_number,
490 remote_console_random_number_len);
491 FILL_FIID_OBJ_SET (obj_cmd_rq,
492 "requested_maximum_privilege_level",
493 requested_maximum_privilege_level);
494 FILL_FIID_OBJ_SET (obj_cmd_rq,
495 "name_only_lookup",
496 name_only_lookup_flag);
497 FILL_FIID_OBJ_SET (obj_cmd_rq,
498 "reserved2",
499 0);
500 FILL_FIID_OBJ_SET (obj_cmd_rq,
501 "reserved3",
502 0);
503 FILL_FIID_OBJ_SET (obj_cmd_rq,
504 "user_name_length",
505 user_name_len);
506
507 if (user_name && user_name_len)
508 FILL_FIID_OBJ_SET_DATA (obj_cmd_rq,
509 "user_name",
510 user_name,
511 user_name_len);
512
513 return (0);
514 }
515
516 int
fill_rmcpplus_rakp_message_3(uint8_t message_tag,uint8_t rmcpplus_status_code,uint32_t managed_system_session_id,const void * key_exchange_authentication_code,unsigned int key_exchange_authentication_code_len,fiid_obj_t obj_cmd_rq)517 fill_rmcpplus_rakp_message_3 (uint8_t message_tag,
518 uint8_t rmcpplus_status_code,
519 uint32_t managed_system_session_id,
520 const void *key_exchange_authentication_code,
521 unsigned int key_exchange_authentication_code_len,
522 fiid_obj_t obj_cmd_rq)
523 {
524 if ((key_exchange_authentication_code
525 && key_exchange_authentication_code_len > IPMI_MAX_KEY_EXCHANGE_AUTHENTICATION_CODE_LENGTH)
526 || !RMCPPLUS_STATUS_VALID (rmcpplus_status_code)
527 || !fiid_obj_valid (obj_cmd_rq))
528 {
529 SET_ERRNO (EINVAL);
530 return (-1);
531 }
532
533 if (FIID_OBJ_TEMPLATE_COMPARE (obj_cmd_rq, tmpl_rmcpplus_rakp_message_3) < 0)
534 {
535 ERRNO_TRACE (errno);
536 return (-1);
537 }
538
539 FILL_FIID_OBJ_CLEAR (obj_cmd_rq);
540
541 FILL_FIID_OBJ_SET (obj_cmd_rq,
542 "message_tag",
543 message_tag);
544 FILL_FIID_OBJ_SET (obj_cmd_rq,
545 "reserved1",
546 0);
547 FILL_FIID_OBJ_SET (obj_cmd_rq,
548 "rmcpplus_status_code",
549 rmcpplus_status_code);
550 FILL_FIID_OBJ_SET (obj_cmd_rq,
551 "managed_system_session_id",
552 managed_system_session_id);
553
554 if (key_exchange_authentication_code && key_exchange_authentication_code_len > 0)
555 FILL_FIID_OBJ_SET_DATA (obj_cmd_rq,
556 "key_exchange_authentication_code",
557 key_exchange_authentication_code,
558 key_exchange_authentication_code_len);
559
560 return (0);
561 }
562
563 static int
_construct_payload_buf(uint8_t payload_type,fiid_obj_t obj_lan_msg_hdr,fiid_obj_t obj_cmd,void * payload_buf,unsigned int payload_buf_len)564 _construct_payload_buf (uint8_t payload_type,
565 fiid_obj_t obj_lan_msg_hdr,
566 fiid_obj_t obj_cmd,
567 void *payload_buf,
568 unsigned int payload_buf_len)
569 {
570 int obj_lan_msg_hdr_len = 0;
571 int obj_cmd_len = 0;
572 int obj_lan_msg_trlr_len = 0;
573 int checksum_start_offset, len, rv = -1;
574 unsigned int payload_len;
575 uint8_t checksum;
576 unsigned int indx = 0;
577 fiid_obj_t obj_lan_msg_trlr = NULL;
578
579 assert ((payload_type == IPMI_PAYLOAD_TYPE_IPMI
580 || payload_type == IPMI_PAYLOAD_TYPE_SOL)
581 && !(payload_type == IPMI_PAYLOAD_TYPE_IPMI
582 && !(fiid_obj_valid (obj_lan_msg_hdr)
583 && fiid_obj_template_compare (obj_lan_msg_hdr, tmpl_lan_msg_hdr_rq) == 1
584 && fiid_obj_packet_valid (obj_lan_msg_hdr) == 1))
585 && fiid_obj_valid (obj_cmd)
586 && !(payload_type == IPMI_PAYLOAD_TYPE_SOL
587 && !(fiid_obj_template_compare (obj_cmd, tmpl_sol_payload_data) == 1
588 || fiid_obj_template_compare (obj_cmd, tmpl_sol_payload_data_remote_console_to_bmc) == 1))
589 && payload_buf
590 && payload_buf_len);
591
592 if (payload_type == IPMI_PAYLOAD_TYPE_IPMI)
593 {
594 if ((obj_lan_msg_hdr_len = fiid_obj_len_bytes (obj_lan_msg_hdr)) < 0)
595 {
596 FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_hdr);
597 goto cleanup;
598 }
599 if ((obj_lan_msg_trlr_len = fiid_template_len_bytes (tmpl_lan_msg_trlr)) < 0)
600 {
601 ERRNO_TRACE (errno);
602 goto cleanup;
603 }
604 }
605
606 if ((obj_cmd_len = fiid_obj_len_bytes (obj_cmd)) < 0)
607 {
608 FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
609 goto cleanup;
610 }
611
612 payload_len = obj_lan_msg_hdr_len + obj_cmd_len + obj_lan_msg_trlr_len;
613
614 if (payload_len > IPMI_MAX_PAYLOAD_LENGTH)
615 {
616 SET_ERRNO (EINVAL);
617 goto cleanup;
618 }
619
620 if (payload_len > payload_buf_len)
621 {
622 SET_ERRNO (ENOSPC);
623 goto cleanup;
624 }
625
626 if (payload_type == IPMI_PAYLOAD_TYPE_IPMI)
627 {
628 if ((len = fiid_obj_get_all (obj_lan_msg_hdr,
629 payload_buf + indx,
630 payload_buf_len - indx)) < 0)
631 {
632 FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_hdr);
633 goto cleanup;
634 }
635 indx += len;
636 }
637
638 if ((len = fiid_obj_get_all (obj_cmd,
639 payload_buf + indx,
640 payload_buf_len - indx)) < 0)
641 {
642 FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
643 goto cleanup;
644 }
645 indx += len;
646
647 if (payload_type == IPMI_PAYLOAD_TYPE_IPMI)
648 {
649 if (!(obj_lan_msg_trlr = fiid_obj_create (tmpl_lan_msg_trlr)))
650 {
651 ERRNO_TRACE (errno);
652 goto cleanup;
653 }
654
655 if ((checksum_start_offset = fiid_template_field_end_bytes (tmpl_lan_msg_hdr_rq,
656 "checksum1")) < 0)
657 {
658 ERRNO_TRACE (errno);
659 goto cleanup;
660 }
661 checksum = ipmi_checksum (payload_buf + checksum_start_offset, indx - checksum_start_offset);
662
663 if (fiid_obj_set_all (obj_lan_msg_trlr, &checksum, sizeof (checksum)) < 0)
664 {
665 FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_trlr);
666 goto cleanup;
667 }
668
669 if ((len = fiid_obj_get_all (obj_lan_msg_trlr,
670 payload_buf + indx,
671 payload_buf_len - indx)) < 0)
672 {
673 FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_trlr);
674 goto cleanup;
675 }
676 indx += len;
677 }
678
679 rv = indx;
680 cleanup:
681 fiid_obj_destroy (obj_lan_msg_trlr);
682 return (rv);
683 }
684
685 static int
_construct_payload_confidentiality_none(uint8_t payload_type,fiid_obj_t obj_lan_msg_hdr,fiid_obj_t obj_cmd,fiid_obj_t obj_rmcpplus_payload)686 _construct_payload_confidentiality_none (uint8_t payload_type,
687 fiid_obj_t obj_lan_msg_hdr,
688 fiid_obj_t obj_cmd,
689 fiid_obj_t obj_rmcpplus_payload)
690 {
691 uint8_t payload_buf[IPMI_MAX_PAYLOAD_LENGTH];
692 int payload_len;
693
694 assert ((payload_type == IPMI_PAYLOAD_TYPE_IPMI
695 || payload_type == IPMI_PAYLOAD_TYPE_SOL)
696 && !(payload_type == IPMI_PAYLOAD_TYPE_IPMI
697 && !fiid_obj_valid (obj_lan_msg_hdr))
698 && fiid_obj_valid (obj_cmd)
699 && !(payload_type == IPMI_PAYLOAD_TYPE_SOL
700 && !(fiid_obj_template_compare (obj_cmd, tmpl_sol_payload_data) == 1
701 || fiid_obj_template_compare (obj_cmd, tmpl_sol_payload_data_remote_console_to_bmc) == 1))
702 && fiid_obj_valid (obj_rmcpplus_payload)
703 && fiid_obj_template_compare (obj_rmcpplus_payload, tmpl_rmcpplus_payload) == 1);
704
705 if ((payload_len = _construct_payload_buf (payload_type,
706 obj_lan_msg_hdr,
707 obj_cmd,
708 payload_buf,
709 IPMI_MAX_PAYLOAD_LENGTH)) < 0)
710 {
711 ERRNO_TRACE (errno);
712 return (-1);
713 }
714
715 if (fiid_obj_set_data (obj_rmcpplus_payload,
716 "payload_data",
717 payload_buf,
718 payload_len) < 0)
719 {
720 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_payload);
721 return (-1);
722 }
723
724 return (payload_len);
725 }
726
727 static int
_construct_payload_confidentiality_aes_cbc_128(uint8_t payload_type,uint8_t payload_encrypted,fiid_obj_t obj_lan_msg_hdr,fiid_obj_t obj_cmd,const void * confidentiality_key,unsigned int confidentiality_key_len,fiid_obj_t obj_rmcpplus_payload)728 _construct_payload_confidentiality_aes_cbc_128 (uint8_t payload_type,
729 uint8_t payload_encrypted,
730 fiid_obj_t obj_lan_msg_hdr,
731 fiid_obj_t obj_cmd,
732 const void *confidentiality_key,
733 unsigned int confidentiality_key_len,
734 fiid_obj_t obj_rmcpplus_payload)
735 {
736 uint8_t iv[IPMI_CRYPT_AES_CBC_128_IV_LENGTH];
737 int iv_len;
738 uint8_t payload_buf[IPMI_MAX_PAYLOAD_LENGTH];
739 uint8_t pad_len, pad_tmp;
740 int payload_len, cipher_keylen, cipher_blocklen, encrypt_len;
741
742 /* Note: Confidentiality Key for AES_CBS_128 is K2 */
743
744 assert ((payload_type == IPMI_PAYLOAD_TYPE_IPMI
745 || payload_type == IPMI_PAYLOAD_TYPE_SOL)
746 && payload_encrypted
747 && !(payload_type == IPMI_PAYLOAD_TYPE_IPMI
748 && !fiid_obj_valid (obj_lan_msg_hdr))
749 && fiid_obj_valid (obj_cmd)
750 && !(payload_type == IPMI_PAYLOAD_TYPE_SOL
751 && !(fiid_obj_template_compare (obj_cmd, tmpl_sol_payload_data) == 1
752 || fiid_obj_template_compare (obj_cmd, tmpl_sol_payload_data_remote_console_to_bmc) == 1))
753 && fiid_obj_packet_valid (obj_cmd) == 1
754 && confidentiality_key
755 && confidentiality_key_len
756 && fiid_obj_valid (obj_rmcpplus_payload)
757 && fiid_obj_template_compare (obj_rmcpplus_payload, tmpl_rmcpplus_payload) == 1);
758
759 if ((cipher_keylen = crypt_cipher_key_len (IPMI_CRYPT_CIPHER_AES)) < 0)
760 {
761 ERRNO_TRACE (errno);
762 return (-1);
763 }
764
765 assert (!(cipher_keylen < IPMI_CRYPT_AES_CBC_128_KEY_LENGTH));
766
767 if (confidentiality_key_len < IPMI_CRYPT_AES_CBC_128_KEY_LENGTH)
768 {
769 SET_ERRNO (EINVAL);
770 return (-1);
771 }
772
773 confidentiality_key_len = IPMI_CRYPT_AES_CBC_128_KEY_LENGTH;
774
775 if ((cipher_blocklen = crypt_cipher_block_len (IPMI_CRYPT_CIPHER_AES)) < 0)
776 {
777 ERRNO_TRACE (errno);
778 return (-1);
779 }
780
781 assert (cipher_blocklen == IPMI_CRYPT_AES_CBC_128_BLOCK_LENGTH);
782
783 if ((iv_len = ipmi_get_random (iv, IPMI_CRYPT_AES_CBC_128_IV_LENGTH)) < 0)
784 {
785 ERRNO_TRACE (errno);
786 return (-1);
787 }
788
789 if (iv_len != IPMI_CRYPT_AES_CBC_128_IV_LENGTH)
790 {
791 ERRNO_TRACE (errno);
792 return (-1);
793 }
794
795 if ((payload_len = _construct_payload_buf (payload_type,
796 obj_lan_msg_hdr,
797 obj_cmd,
798 payload_buf,
799 IPMI_MAX_PAYLOAD_LENGTH)) < 0)
800 {
801 ERRNO_TRACE (errno);
802 return (-1);
803 }
804
805 /* Pad the data appropriately */
806
807 /* +1 is for the pad length field */
808 pad_tmp = ((payload_len + 1) % IPMI_CRYPT_AES_CBC_128_BLOCK_LENGTH);
809 if (pad_tmp)
810 pad_len = IPMI_CRYPT_AES_CBC_128_BLOCK_LENGTH - pad_tmp;
811 else
812 pad_len = 0;
813
814 if ((payload_len + pad_len + 1) > IPMI_MAX_PAYLOAD_LENGTH)
815 {
816 SET_ERRNO (ENOSPC);
817 return (-1);
818 }
819
820 if (pad_len)
821 {
822 unsigned int i;
823 for (i = 0; i < pad_len; i++)
824 payload_buf[payload_len + i] = i + 1;
825 }
826 payload_buf[payload_len + pad_len] = pad_len;
827
828 /* +1 for pad length field */
829 if ((encrypt_len = crypt_cipher_encrypt (IPMI_CRYPT_CIPHER_AES,
830 IPMI_CRYPT_CIPHER_MODE_CBC,
831 confidentiality_key,
832 confidentiality_key_len,
833 iv,
834 iv_len,
835 payload_buf,
836 payload_len + pad_len + 1)) < 0)
837 {
838 ERRNO_TRACE (errno);
839 return (-1);
840 }
841
842 if (encrypt_len != (payload_len + pad_len + 1))
843 {
844 SET_ERRNO (EINVAL);
845 return (-1);
846 }
847
848 if (fiid_obj_set_data (obj_rmcpplus_payload,
849 "confidentiality_header",
850 iv,
851 IPMI_CRYPT_AES_CBC_128_IV_LENGTH) < 0)
852 {
853 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_payload);
854 return (-1);
855 }
856
857 if (fiid_obj_set_data (obj_rmcpplus_payload,
858 "payload_data",
859 payload_buf,
860 payload_len) < 0)
861 {
862 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_payload);
863 return (-1);
864 }
865
866 if (fiid_obj_set_data (obj_rmcpplus_payload,
867 "confidentiality_trailer",
868 payload_buf + payload_len,
869 pad_len + 1) < 0)
870 {
871 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_payload);
872 return (-1);
873 }
874
875 return (iv_len + payload_len + pad_len + 1);
876 }
877
878 static int
_construct_payload_rakp(uint8_t payload_type,fiid_obj_t obj_cmd,fiid_obj_t obj_rmcpplus_payload)879 _construct_payload_rakp (uint8_t payload_type,
880 fiid_obj_t obj_cmd,
881 fiid_obj_t obj_rmcpplus_payload)
882 {
883 uint8_t obj_cmd_buf[IPMI_MAX_PAYLOAD_LENGTH];
884 int obj_cmd_len = 0;
885
886 assert ((payload_type == IPMI_PAYLOAD_TYPE_RMCPPLUS_OPEN_SESSION_REQUEST
887 || payload_type == IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_1
888 || payload_type == IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_3)
889 && fiid_obj_valid (obj_cmd)
890 && !(payload_type == IPMI_PAYLOAD_TYPE_RMCPPLUS_OPEN_SESSION_REQUEST
891 && fiid_obj_template_compare (obj_cmd, tmpl_rmcpplus_open_session_request) < 0)
892 && !(payload_type == IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_1
893 && fiid_obj_template_compare (obj_cmd, tmpl_rmcpplus_rakp_message_1) < 0)
894 && !(payload_type == IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_3
895 && fiid_obj_template_compare (obj_cmd, tmpl_rmcpplus_rakp_message_3) < 0)
896 && fiid_obj_valid (obj_rmcpplus_payload)
897 && fiid_obj_template_compare (obj_rmcpplus_payload, tmpl_rmcpplus_payload) == 1
898 && fiid_obj_packet_valid (obj_cmd) == 1);
899
900 if ((obj_cmd_len = fiid_obj_get_all (obj_cmd,
901 obj_cmd_buf,
902 IPMI_MAX_PAYLOAD_LENGTH)) < 0)
903 {
904 FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
905 return (-1);
906 }
907
908 if (fiid_obj_set_data (obj_rmcpplus_payload,
909 "payload_data",
910 obj_cmd_buf,
911 obj_cmd_len) < 0)
912 {
913 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_payload);
914 return (-1);
915 }
916
917 return (obj_cmd_len);
918 }
919
920 static int
_construct_payload(uint8_t payload_type,uint8_t payload_encrypted,uint8_t authentication_algorithm,uint8_t confidentiality_algorithm,fiid_obj_t obj_lan_msg_hdr,fiid_obj_t obj_cmd,const void * confidentiality_key,unsigned int confidentiality_key_len,fiid_obj_t obj_rmcpplus_payload)921 _construct_payload (uint8_t payload_type,
922 uint8_t payload_encrypted,
923 uint8_t authentication_algorithm,
924 uint8_t confidentiality_algorithm,
925 fiid_obj_t obj_lan_msg_hdr,
926 fiid_obj_t obj_cmd,
927 const void *confidentiality_key,
928 unsigned int confidentiality_key_len,
929 fiid_obj_t obj_rmcpplus_payload)
930 {
931 assert ((payload_type == IPMI_PAYLOAD_TYPE_IPMI
932 || payload_type == IPMI_PAYLOAD_TYPE_SOL
933 || payload_type == IPMI_PAYLOAD_TYPE_RMCPPLUS_OPEN_SESSION_REQUEST
934 || payload_type == IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_1
935 || payload_type == IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_3)
936 && IPMI_AUTHENTICATION_ALGORITHM_SUPPORTED (authentication_algorithm)
937 && IPMI_CONFIDENTIALITY_ALGORITHM_SUPPORTED (confidentiality_algorithm)
938 && !(payload_type == IPMI_PAYLOAD_TYPE_IPMI
939 && !fiid_obj_valid (obj_lan_msg_hdr))
940 && fiid_obj_valid (obj_cmd)
941 && fiid_obj_valid (obj_rmcpplus_payload)
942 && fiid_obj_template_compare (obj_lan_msg_hdr, tmpl_lan_msg_hdr_rq) == 1
943 && fiid_obj_template_compare (obj_rmcpplus_payload, tmpl_rmcpplus_payload) == 1);
944
945 if (payload_type == IPMI_PAYLOAD_TYPE_IPMI
946 || payload_type == IPMI_PAYLOAD_TYPE_SOL)
947 {
948
949 if (confidentiality_algorithm == IPMI_CONFIDENTIALITY_ALGORITHM_NONE)
950 return (_construct_payload_confidentiality_none (payload_type,
951 obj_lan_msg_hdr,
952 obj_cmd,
953 obj_rmcpplus_payload));
954 else /* IPMI_CONFIDENTIALITY_ALGORITHM_AES_CBC_128 */
955 return (_construct_payload_confidentiality_aes_cbc_128 (payload_type,
956 payload_encrypted,
957 obj_lan_msg_hdr,
958 obj_cmd,
959 confidentiality_key,
960 confidentiality_key_len,
961 obj_rmcpplus_payload));
962 }
963 else
964 return (_construct_payload_rakp (payload_type,
965 obj_cmd,
966 obj_rmcpplus_payload));
967 }
968
969 static int
_construct_session_trlr_pad(uint8_t integrity_algorithm,unsigned int ipmi_msg_len,fiid_obj_t obj_rmcpplus_session_trlr)970 _construct_session_trlr_pad (uint8_t integrity_algorithm,
971 unsigned int ipmi_msg_len,
972 fiid_obj_t obj_rmcpplus_session_trlr)
973 {
974 int pad_length_field_len, next_header_field_len;
975 unsigned int pad_length = 0;
976 uint8_t pad_bytes[IPMI_INTEGRITY_PAD_MULTIPLE] = { IPMI_INTEGRITY_PAD_DATA,
977 IPMI_INTEGRITY_PAD_DATA,
978 IPMI_INTEGRITY_PAD_DATA,
979 IPMI_INTEGRITY_PAD_DATA};
980
981 assert (IPMI_INTEGRITY_ALGORITHM_SUPPORTED (integrity_algorithm)
982 && fiid_obj_valid (obj_rmcpplus_session_trlr)
983 && fiid_obj_template_compare (obj_rmcpplus_session_trlr, tmpl_rmcpplus_session_trlr) == 1);
984
985 if ((pad_length_field_len = fiid_template_field_len_bytes (tmpl_rmcpplus_session_trlr,
986 "pad_length")) < 0)
987 {
988 ERRNO_TRACE (errno);
989 return (-1);
990 }
991 if ((next_header_field_len = fiid_template_field_len_bytes (tmpl_rmcpplus_session_trlr,
992 "next_header")) < 0)
993 {
994 ERRNO_TRACE (errno);
995 return (-1);
996 }
997
998 ipmi_msg_len += pad_length_field_len;
999 ipmi_msg_len += next_header_field_len;
1000
1001 if (ipmi_msg_len % IPMI_INTEGRITY_PAD_MULTIPLE)
1002 pad_length = IPMI_INTEGRITY_PAD_MULTIPLE - (ipmi_msg_len % IPMI_INTEGRITY_PAD_MULTIPLE);
1003
1004 if (pad_length)
1005 {
1006 if (fiid_obj_set_data (obj_rmcpplus_session_trlr,
1007 "integrity_pad",
1008 pad_bytes,
1009 pad_length) < 0)
1010 {
1011 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_trlr);
1012 return (-1);
1013 }
1014 }
1015
1016 if (fiid_obj_set (obj_rmcpplus_session_trlr,
1017 "pad_length",
1018 pad_length) < 0)
1019 {
1020 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_trlr);
1021 return (-1);
1022 }
1023
1024 return (0);
1025 }
1026
1027 static int
_calculate_authentication_code_len(uint8_t integrity_algorithm)1028 _calculate_authentication_code_len (uint8_t integrity_algorithm)
1029 {
1030 int authentication_code_len;
1031
1032 assert ((integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_NONE
1033 || integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_HMAC_SHA1_96
1034 || integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_HMAC_MD5_128
1035 || integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_MD5_128
1036 || integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_HMAC_SHA256_128));
1037
1038 if (integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_NONE)
1039 authentication_code_len = 0;
1040 else if (integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_HMAC_SHA1_96)
1041 authentication_code_len = IPMI_HMAC_SHA1_96_AUTHENTICATION_CODE_LENGTH;
1042 else if (integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_HMAC_MD5_128)
1043 authentication_code_len = IPMI_HMAC_MD5_128_AUTHENTICATION_CODE_LENGTH;
1044 else if (integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_MD5_128)
1045 authentication_code_len = IPMI_MD5_128_AUTHENTICATION_CODE_LENGTH;
1046 else /* IPMI_INTEGRITY_ALGORITHM_HMAC_SHA256_128 */
1047 authentication_code_len = IPMI_HMAC_SHA256_128_AUTHENTICATION_CODE_LENGTH;
1048
1049 return (authentication_code_len);
1050 }
1051
1052 static int
_construct_session_trlr_authentication_code(uint8_t integrity_algorithm,const void * integrity_key,unsigned int integrity_key_len,const void * authentication_code_data,unsigned int authentication_code_data_len,fiid_obj_t obj_rmcpplus_session_trlr,void * pkt_data,unsigned int pkt_data_len,void * authentication_code_buf,unsigned int authentication_code_buf_len)1053 _construct_session_trlr_authentication_code (uint8_t integrity_algorithm,
1054 const void *integrity_key,
1055 unsigned int integrity_key_len,
1056 const void *authentication_code_data,
1057 unsigned int authentication_code_data_len,
1058 fiid_obj_t obj_rmcpplus_session_trlr,
1059 void *pkt_data,
1060 unsigned int pkt_data_len,
1061 void *authentication_code_buf,
1062 unsigned int authentication_code_buf_len)
1063 {
1064 int crypt_digest_len, authentication_code_len, integrity_digest_len, len, rv = -1;
1065 unsigned int hash_algorithm, hash_flags, expected_digest_len, copy_digest_len, hash_data_len;
1066 uint8_t hash_data[IPMI_MAX_PAYLOAD_LENGTH];
1067 uint8_t integrity_digest[IPMI_MAX_INTEGRITY_DATA_LENGTH];
1068 uint8_t pwbuf[IPMI_2_0_MAX_PASSWORD_LENGTH];
1069
1070 assert ((integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_HMAC_SHA1_96
1071 || integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_HMAC_MD5_128
1072 || integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_MD5_128
1073 || integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_HMAC_SHA256_128)
1074 && !(integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_MD5_128
1075 && authentication_code_data
1076 && authentication_code_data_len > IPMI_2_0_MAX_PASSWORD_LENGTH)
1077 && fiid_obj_valid (obj_rmcpplus_session_trlr)
1078 && pkt_data
1079 && pkt_data_len
1080 && authentication_code_buf
1081 && authentication_code_buf_len);
1082
1083 if (FIID_OBJ_TEMPLATE_COMPARE (obj_rmcpplus_session_trlr, tmpl_rmcpplus_session_trlr) < 0)
1084 {
1085 ERRNO_TRACE (errno);
1086 return (-1);
1087 }
1088
1089 /* Check if the user provided an authentication code, if so, use it */
1090
1091 if ((len = fiid_obj_field_len_bytes (obj_rmcpplus_session_trlr,
1092 "authentication_code")) < 0)
1093 {
1094 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_trlr);
1095 return (-1);
1096 }
1097
1098 if (len)
1099 {
1100 if ((len = fiid_obj_get_data (obj_rmcpplus_session_trlr,
1101 "authentication_code",
1102 authentication_code_buf,
1103 authentication_code_buf_len)) < 0)
1104 {
1105 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_trlr);
1106 return (-1);
1107 }
1108 return (len);
1109 }
1110
1111 if ((authentication_code_len = _calculate_authentication_code_len (integrity_algorithm)) < 0)
1112 {
1113 ERRNO_TRACE (errno);
1114 goto cleanup;
1115 }
1116
1117 /* Note: Integrity Key for HMAC_SHA1_96 and HMAC_MD5_128 is K1 */
1118
1119 if (integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_HMAC_SHA1_96)
1120 {
1121 hash_algorithm = IPMI_CRYPT_HASH_SHA1;
1122 hash_flags = IPMI_CRYPT_HASH_FLAGS_HMAC;
1123 expected_digest_len = IPMI_HMAC_SHA1_DIGEST_LENGTH;
1124 copy_digest_len = IPMI_HMAC_SHA1_96_AUTHENTICATION_CODE_LENGTH;
1125 }
1126 else if (integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_HMAC_MD5_128)
1127 {
1128 hash_algorithm = IPMI_CRYPT_HASH_MD5;
1129 hash_flags = IPMI_CRYPT_HASH_FLAGS_HMAC;
1130 expected_digest_len = IPMI_HMAC_MD5_DIGEST_LENGTH;
1131 copy_digest_len = IPMI_HMAC_MD5_128_AUTHENTICATION_CODE_LENGTH;
1132 }
1133 else if (integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_MD5_128)
1134 {
1135 hash_algorithm = IPMI_CRYPT_HASH_MD5;
1136 hash_flags = 0;
1137 expected_digest_len = MD5_DIGEST_LENGTH;
1138 copy_digest_len = IPMI_MD5_128_AUTHENTICATION_CODE_LENGTH;
1139 }
1140 else /* IPMI_INTEGRITY_ALGORITHM_HMAC_SHA256_128 */
1141 {
1142 hash_algorithm = IPMI_CRYPT_HASH_SHA256;
1143 hash_flags = IPMI_CRYPT_HASH_FLAGS_HMAC;
1144 expected_digest_len = IPMI_HMAC_SHA256_DIGEST_LENGTH;
1145 copy_digest_len = IPMI_HMAC_SHA256_128_AUTHENTICATION_CODE_LENGTH;
1146 }
1147
1148 if ((crypt_digest_len = crypt_hash_digest_len (hash_algorithm)) < 0)
1149 {
1150 ERRNO_TRACE (errno);
1151 goto cleanup;
1152 }
1153
1154 assert (crypt_digest_len == expected_digest_len);
1155
1156 hash_data_len = 0;
1157
1158 if (integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_MD5_128)
1159 {
1160 /* achu: Password must be zero padded */
1161 memset (pwbuf, '\0', IPMI_2_0_MAX_PASSWORD_LENGTH);
1162
1163 if (authentication_code_data && authentication_code_data_len)
1164 memcpy (pwbuf, authentication_code_data, authentication_code_data_len);
1165
1166 memcpy (hash_data + hash_data_len,
1167 pwbuf,
1168 IPMI_2_0_MAX_PASSWORD_LENGTH);
1169 hash_data_len += IPMI_2_0_MAX_PASSWORD_LENGTH;
1170 }
1171
1172 memcpy (hash_data + hash_data_len, pkt_data, pkt_data_len);
1173 hash_data_len += pkt_data_len;
1174
1175 if (integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_MD5_128)
1176 {
1177 memcpy (hash_data + hash_data_len,
1178 pwbuf,
1179 IPMI_2_0_MAX_PASSWORD_LENGTH);
1180 hash_data_len += IPMI_2_0_MAX_PASSWORD_LENGTH;
1181 }
1182
1183 if ((integrity_digest_len = crypt_hash (hash_algorithm,
1184 hash_flags,
1185 integrity_key,
1186 integrity_key_len,
1187 hash_data,
1188 hash_data_len,
1189 integrity_digest,
1190 IPMI_MAX_INTEGRITY_DATA_LENGTH)) < 0)
1191 {
1192 ERRNO_TRACE (errno);
1193 goto cleanup;
1194 }
1195
1196 if (integrity_digest_len != crypt_digest_len)
1197 {
1198 SET_ERRNO (EINVAL);
1199 goto cleanup;
1200 }
1201
1202 if (integrity_digest_len > authentication_code_buf_len)
1203 {
1204 SET_ERRNO (ENOSPC);
1205 goto cleanup;
1206 }
1207
1208 memcpy (authentication_code_buf, integrity_digest, copy_digest_len);
1209
1210 rv = copy_digest_len;
1211 cleanup:
1212 /* secure_memset b/c contains password */
1213 secure_memset (pwbuf, '\0', IPMI_2_0_MAX_PASSWORD_LENGTH);
1214 return (rv);
1215 }
1216
1217 int
assemble_ipmi_rmcpplus_pkt(uint8_t authentication_algorithm,uint8_t integrity_algorithm,uint8_t confidentiality_algorithm,const void * integrity_key,unsigned int integrity_key_len,const void * confidentiality_key,unsigned int confidentiality_key_len,const void * authentication_code_data,unsigned int authentication_code_data_len,fiid_obj_t obj_rmcp_hdr,fiid_obj_t obj_rmcpplus_session_hdr,fiid_obj_t obj_lan_msg_hdr,fiid_obj_t obj_cmd,fiid_obj_t obj_rmcpplus_session_trlr,void * pkt,unsigned int pkt_len,unsigned int flags)1218 assemble_ipmi_rmcpplus_pkt (uint8_t authentication_algorithm,
1219 uint8_t integrity_algorithm,
1220 uint8_t confidentiality_algorithm,
1221 const void *integrity_key,
1222 unsigned int integrity_key_len,
1223 const void *confidentiality_key,
1224 unsigned int confidentiality_key_len,
1225 const void *authentication_code_data,
1226 unsigned int authentication_code_data_len,
1227 fiid_obj_t obj_rmcp_hdr,
1228 fiid_obj_t obj_rmcpplus_session_hdr,
1229 fiid_obj_t obj_lan_msg_hdr,
1230 fiid_obj_t obj_cmd,
1231 fiid_obj_t obj_rmcpplus_session_trlr,
1232 void *pkt,
1233 unsigned int pkt_len,
1234 unsigned int flags)
1235 {
1236 unsigned int indx = 0;
1237 int obj_rmcp_hdr_len, obj_len, oem_iana_len, oem_payload_id_len, payload_len, len, rv = -1;
1238 uint8_t payload_type, payload_authenticated, payload_encrypted;
1239 uint32_t session_id, session_sequence_number;
1240 uint64_t val;
1241 fiid_obj_t obj_rmcpplus_payload = NULL;
1242 fiid_obj_t obj_session_hdr_temp = NULL;
1243 fiid_obj_t obj_rmcpplus_session_trlr_temp = NULL;
1244 unsigned int flags_mask = 0;
1245
1246 /* achu: obj_lan_msg_hdr only needed for payload type IPMI
1247 *
1248 * If integrity_algorithm != NONE, technically the key can be NULL
1249 */
1250 if (!IPMI_AUTHENTICATION_ALGORITHM_SUPPORTED (authentication_algorithm)
1251 || !IPMI_INTEGRITY_ALGORITHM_SUPPORTED (integrity_algorithm)
1252 || (integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_MD5_128
1253 && authentication_code_data
1254 && authentication_code_data_len > IPMI_2_0_MAX_PASSWORD_LENGTH)
1255 || !IPMI_CONFIDENTIALITY_ALGORITHM_SUPPORTED (confidentiality_algorithm)
1256 || (confidentiality_algorithm == IPMI_CONFIDENTIALITY_ALGORITHM_AES_CBC_128
1257 && !(confidentiality_key
1258 && confidentiality_key_len))
1259 || !fiid_obj_valid (obj_rmcp_hdr)
1260 || !fiid_obj_valid (obj_rmcpplus_session_hdr)
1261 || !fiid_obj_valid (obj_cmd)
1262 || !pkt
1263 || !pkt_len
1264 || (flags & ~flags_mask))
1265 {
1266 SET_ERRNO (EINVAL);
1267 return (-1);
1268 }
1269
1270 if (FIID_OBJ_TEMPLATE_COMPARE (obj_rmcp_hdr, tmpl_rmcp_hdr) < 0)
1271 {
1272 ERRNO_TRACE (errno);
1273 return (-1);
1274 }
1275 if (FIID_OBJ_TEMPLATE_COMPARE (obj_rmcpplus_session_hdr, tmpl_rmcpplus_session_hdr) < 0)
1276 {
1277 ERRNO_TRACE (errno);
1278 return (-1);
1279 }
1280
1281 if (FIID_OBJ_PACKET_VALID (obj_rmcp_hdr) < 0)
1282 {
1283 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcp_hdr);
1284 return (-1);
1285 }
1286 if (FIID_OBJ_PACKET_VALID (obj_cmd) < 0)
1287 {
1288 FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
1289 return (-1);
1290 }
1291
1292 /*
1293 * Can't use fiid_obj_packet_valid() on obj_rmcpplus_session_hdr b/c
1294 * a ipmi_payload_len is required but may not be set yet.
1295 */
1296
1297 if (FIID_OBJ_GET (obj_rmcpplus_session_hdr,
1298 "payload_type",
1299 &val) < 0)
1300 {
1301 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_hdr);
1302 return (-1);
1303 }
1304 payload_type = val;
1305
1306 if (FIID_OBJ_GET (obj_rmcpplus_session_hdr,
1307 "payload_type.authenticated",
1308 &val) < 0)
1309 {
1310 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_hdr);
1311 return (-1);
1312 }
1313 payload_authenticated = val;
1314
1315 if (FIID_OBJ_GET (obj_rmcpplus_session_hdr,
1316 "payload_type.encrypted",
1317 &val) < 0)
1318 {
1319 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_hdr);
1320 return (-1);
1321 }
1322 payload_encrypted = val;
1323
1324 if (FIID_OBJ_GET (obj_rmcpplus_session_hdr,
1325 "session_id",
1326 &val) < 0)
1327 {
1328 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_hdr);
1329 return (-1);
1330 }
1331 session_id = val;
1332
1333 if (FIID_OBJ_GET (obj_rmcpplus_session_hdr,
1334 "session_sequence_number",
1335 &val) < 0)
1336 {
1337 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_hdr);
1338 return (-1);
1339 }
1340 session_sequence_number = val;
1341
1342 /* Note: We don't check consider OPEN_SESSION_RESPONSE, RAKP2 or
1343 * RAKP4 payload types b/c they are responses, not requests.
1344 */
1345 if ((payload_type != IPMI_PAYLOAD_TYPE_IPMI
1346 && payload_type != IPMI_PAYLOAD_TYPE_SOL
1347 && payload_type != IPMI_PAYLOAD_TYPE_RMCPPLUS_OPEN_SESSION_REQUEST
1348 && payload_type != IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_1
1349 && payload_type != IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_3)
1350 || (IPMI_PAYLOAD_TYPE_SESSION_SETUP (payload_type)
1351 && (payload_authenticated
1352 || payload_encrypted
1353 || session_id
1354 || session_sequence_number))
1355 || (session_id
1356 && payload_authenticated == IPMI_PAYLOAD_FLAG_UNAUTHENTICATED
1357 && integrity_algorithm != IPMI_INTEGRITY_ALGORITHM_NONE)
1358 || (session_id
1359 && payload_authenticated == IPMI_PAYLOAD_FLAG_AUTHENTICATED
1360 && !(integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_HMAC_SHA1_96
1361 || integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_HMAC_MD5_128
1362 || integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_MD5_128
1363 || integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_HMAC_SHA256_128))
1364 || (confidentiality_algorithm == IPMI_CONFIDENTIALITY_ALGORITHM_NONE
1365 && payload_encrypted != IPMI_PAYLOAD_FLAG_UNENCRYPTED))
1366 {
1367 SET_ERRNO (EINVAL);
1368 return (-1);
1369 }
1370
1371 if (payload_type == IPMI_PAYLOAD_TYPE_IPMI)
1372 {
1373 if (!fiid_obj_valid (obj_lan_msg_hdr))
1374 {
1375 SET_ERRNO (EINVAL);
1376 return (-1);
1377 }
1378 if (FIID_OBJ_TEMPLATE_COMPARE (obj_lan_msg_hdr, tmpl_lan_msg_hdr_rq) < 0)
1379 {
1380 ERRNO_TRACE (errno);
1381 return (-1);
1382 }
1383 if (FIID_OBJ_PACKET_VALID (obj_lan_msg_hdr) < 0)
1384 {
1385 ERRNO_TRACE (errno);
1386 return (-1);
1387 }
1388 }
1389 else if (payload_type == IPMI_PAYLOAD_TYPE_SOL)
1390 {
1391 if (FIID_OBJ_TEMPLATE_COMPARE (obj_cmd, tmpl_sol_payload_data) < 0
1392 && FIID_OBJ_TEMPLATE_COMPARE (obj_cmd, tmpl_sol_payload_data_remote_console_to_bmc) < 0)
1393 {
1394 ERRNO_TRACE (errno);
1395 return (-1);
1396 }
1397 }
1398 else if (payload_type == IPMI_PAYLOAD_TYPE_RMCPPLUS_OPEN_SESSION_REQUEST)
1399 {
1400 if (FIID_OBJ_TEMPLATE_COMPARE (obj_cmd, tmpl_rmcpplus_open_session_request) < 0)
1401 {
1402 ERRNO_TRACE (errno);
1403 return (-1);
1404 }
1405 }
1406 else if (payload_type == IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_1)
1407 {
1408 if (FIID_OBJ_TEMPLATE_COMPARE (obj_cmd, tmpl_rmcpplus_rakp_message_1) < 0)
1409 {
1410 ERRNO_TRACE (errno);
1411 return (-1);
1412 }
1413 }
1414 else if (payload_type == IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_3)
1415 {
1416 if (FIID_OBJ_TEMPLATE_COMPARE (obj_cmd, tmpl_rmcpplus_rakp_message_3) < 0)
1417 {
1418 ERRNO_TRACE (errno);
1419 return (-1);
1420 }
1421 }
1422
1423 if (session_id && payload_authenticated == IPMI_PAYLOAD_FLAG_AUTHENTICATED)
1424 {
1425 /*
1426 * Can't use fiid_obj_packet_valid() on obj_rmcpplus_session_trlr b/c
1427 * integrity pad, pad length, and authentication code may not be set.
1428 */
1429 if (!fiid_obj_valid (obj_rmcpplus_session_trlr))
1430 {
1431 SET_ERRNO (EINVAL);
1432 return (-1);
1433 }
1434 if (FIID_OBJ_TEMPLATE_COMPARE (obj_rmcpplus_session_trlr, tmpl_rmcpplus_session_trlr) < 0)
1435 {
1436 ERRNO_TRACE (errno);
1437 return (-1);
1438 }
1439 }
1440
1441 if ((oem_iana_len = fiid_obj_field_len (obj_rmcpplus_session_hdr, "oem_iana")) < 0)
1442 {
1443 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_hdr);
1444 return (-1);
1445 }
1446 if ((oem_payload_id_len = fiid_obj_field_len (obj_rmcpplus_session_hdr, "oem_payload_id")) < 0)
1447 {
1448 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_hdr);
1449 return (-1);
1450 }
1451
1452 /* achu: The OEM payload type isn't supported, but I'll leave this
1453 * code for the sake of potential future support
1454 */
1455 if (payload_type == IPMI_PAYLOAD_TYPE_OEM_EXPLICIT)
1456 {
1457 SET_ERRNO (EINVAL);
1458 return (-1);
1459 }
1460 else
1461 {
1462 if (oem_iana_len
1463 || oem_payload_id_len)
1464 {
1465 SET_ERRNO (EINVAL);
1466 return (-1);
1467 }
1468 }
1469
1470 /*
1471 * Copy RMCP header into packet
1472 */
1473 indx = 0;
1474 if ((obj_rmcp_hdr_len = fiid_obj_len_bytes (obj_rmcp_hdr)) < 0)
1475 {
1476 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcp_hdr);
1477 return (-1);
1478 }
1479
1480 if (obj_rmcp_hdr_len > (pkt_len - indx))
1481 {
1482 SET_ERRNO (ENOSPC);
1483 return (-1);
1484 }
1485
1486 if ((obj_rmcp_hdr_len = fiid_obj_get_all (obj_rmcp_hdr,
1487 pkt + indx,
1488 pkt_len - indx)) < 0)
1489 {
1490 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcp_hdr);
1491 return (-1);
1492 }
1493 indx += obj_rmcp_hdr_len;
1494
1495 /*
1496 * Copy Session Header into packet
1497 */
1498 if ((len = fiid_obj_block_len_bytes (obj_rmcpplus_session_hdr,
1499 "authentication_type",
1500 "session_sequence_number")) < 0)
1501 {
1502 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_hdr);
1503 return (-1);
1504 }
1505 if (len > (pkt_len - indx))
1506 {
1507 SET_ERRNO (ENOSPC);
1508 return (-1);
1509 }
1510
1511 if ((len = fiid_obj_get_block (obj_rmcpplus_session_hdr,
1512 "authentication_type",
1513 "session_sequence_number",
1514 pkt + indx,
1515 pkt_len - indx)) < 0)
1516 {
1517 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_hdr);
1518 return (-1);
1519 }
1520 indx += len;
1521
1522 /*
1523 * Construct/Encrypt Payload and copy into packet
1524 */
1525 if (!(obj_rmcpplus_payload = fiid_obj_create (tmpl_rmcpplus_payload)))
1526 {
1527 ERRNO_TRACE (errno);
1528 goto cleanup;
1529 }
1530
1531 if ((payload_len = _construct_payload (payload_type,
1532 payload_encrypted,
1533 authentication_algorithm,
1534 confidentiality_algorithm,
1535 obj_lan_msg_hdr,
1536 obj_cmd,
1537 confidentiality_key,
1538 confidentiality_key_len,
1539 obj_rmcpplus_payload)) < 0)
1540 {
1541 ERRNO_TRACE (errno);
1542 goto cleanup;
1543 }
1544
1545 /*
1546 * Copy IPMI Payload Length into packet
1547 */
1548
1549 if (!(obj_session_hdr_temp = fiid_obj_create (tmpl_rmcpplus_session_hdr)))
1550 {
1551 ERRNO_TRACE (errno);
1552 goto cleanup;
1553 }
1554
1555 if (fiid_obj_set (obj_session_hdr_temp,
1556 "ipmi_payload_len",
1557 payload_len) < 0)
1558 {
1559 FIID_OBJECT_ERROR_TO_ERRNO (obj_session_hdr_temp);
1560 goto cleanup;
1561 }
1562
1563 if ((obj_len = fiid_obj_len_bytes (obj_session_hdr_temp)) < 0)
1564 {
1565 FIID_OBJECT_ERROR_TO_ERRNO (obj_session_hdr_temp);
1566 goto cleanup;
1567 }
1568
1569 if (obj_len > (pkt_len - indx))
1570 {
1571 SET_ERRNO (ENOSPC);
1572 goto cleanup;
1573 }
1574
1575 if ((obj_len = fiid_obj_get_all (obj_session_hdr_temp,
1576 pkt + indx,
1577 pkt_len - indx)) < 0)
1578 {
1579 FIID_OBJECT_ERROR_TO_ERRNO (obj_session_hdr_temp);
1580 goto cleanup;
1581 }
1582 indx += obj_len;
1583
1584 /*
1585 * Copy IPMI Payload into packet
1586 */
1587
1588 if ((obj_len = fiid_obj_len_bytes (obj_rmcpplus_payload)) < 0)
1589 {
1590 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_payload);
1591 goto cleanup;
1592 }
1593
1594 if (obj_len > (pkt_len - indx))
1595 {
1596 SET_ERRNO (ENOSPC);
1597 goto cleanup;
1598 }
1599
1600 if ((obj_len = fiid_obj_get_all (obj_rmcpplus_payload,
1601 pkt + indx,
1602 pkt_len - indx)) < 0)
1603 {
1604 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_payload);
1605 goto cleanup;
1606 }
1607 indx += obj_len;
1608
1609 if (session_id && payload_authenticated == IPMI_PAYLOAD_FLAG_AUTHENTICATED)
1610 {
1611 uint8_t authentication_code_buf[IPMI_MAX_PAYLOAD_LENGTH];
1612 int authentication_code_len;
1613
1614 if (!(obj_rmcpplus_session_trlr_temp = fiid_obj_dup (obj_rmcpplus_session_trlr)))
1615 {
1616 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_trlr);
1617 goto cleanup;
1618 }
1619
1620 if (_construct_session_trlr_pad (integrity_algorithm,
1621 (indx - obj_rmcp_hdr_len),
1622 obj_rmcpplus_session_trlr_temp) < 0)
1623 {
1624 ERRNO_TRACE (errno);
1625 goto cleanup;
1626 }
1627
1628 if ((len = fiid_obj_block_len_bytes (obj_rmcpplus_session_trlr_temp,
1629 "integrity_pad",
1630 "next_header")) < 0)
1631 {
1632 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_trlr_temp);
1633 goto cleanup;
1634 }
1635 if (len > (pkt_len - indx))
1636 {
1637 SET_ERRNO (ENOSPC);
1638 goto cleanup;
1639 }
1640
1641 if ((len = fiid_obj_get_block (obj_rmcpplus_session_trlr_temp,
1642 "integrity_pad",
1643 "next_header",
1644 pkt + indx,
1645 pkt_len - indx)) < 0)
1646 {
1647 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_trlr_temp);
1648 goto cleanup;
1649 }
1650 indx += len;
1651
1652 /* achu: Note that the integrity code is all data prior to the authentication_code, so this
1653 * call must be done after the pad, pad length, and next header are copied into
1654 * the pkt buffer.
1655 */
1656 if ((authentication_code_len = _construct_session_trlr_authentication_code (integrity_algorithm,
1657 integrity_key,
1658 integrity_key_len,
1659 authentication_code_data,
1660 authentication_code_data_len,
1661 obj_rmcpplus_session_trlr_temp,
1662 pkt + obj_rmcp_hdr_len,
1663 indx - obj_rmcp_hdr_len,
1664 authentication_code_buf,
1665 IPMI_MAX_PAYLOAD_LENGTH)) < 0)
1666 {
1667 ERRNO_TRACE (errno);
1668 goto cleanup;
1669 }
1670
1671 if (authentication_code_len)
1672 {
1673 if (authentication_code_len > (pkt_len - indx))
1674 {
1675 SET_ERRNO (ENOSPC);
1676 goto cleanup;
1677 }
1678 memcpy (pkt + indx, authentication_code_buf, authentication_code_len);
1679 indx += authentication_code_len;
1680 }
1681 }
1682
1683 if (indx > INT_MAX)
1684 {
1685 SET_ERRNO (EMSGSIZE);
1686 goto cleanup;
1687 }
1688
1689 rv = indx;
1690 cleanup:
1691 fiid_obj_destroy (obj_rmcpplus_payload);
1692 fiid_obj_destroy (obj_session_hdr_temp);
1693 fiid_obj_destroy (obj_rmcpplus_session_trlr_temp);
1694 return (rv);
1695 }
1696
1697 /* return 1 on full parse, 0 if not, -1 on error */
1698 static int
_deconstruct_payload_buf(uint8_t payload_type,fiid_obj_t obj_lan_msg_hdr,fiid_obj_t obj_cmd,fiid_obj_t obj_lan_msg_trlr,const void * pkt,unsigned int lan_msg_len)1699 _deconstruct_payload_buf (uint8_t payload_type,
1700 fiid_obj_t obj_lan_msg_hdr,
1701 fiid_obj_t obj_cmd,
1702 fiid_obj_t obj_lan_msg_trlr,
1703 const void *pkt,
1704 unsigned int lan_msg_len)
1705 {
1706 int obj_lan_msg_trlr_len, len;
1707 unsigned int obj_cmd_len, indx = 0;
1708
1709 assert ((payload_type == IPMI_PAYLOAD_TYPE_IPMI
1710 || payload_type == IPMI_PAYLOAD_TYPE_SOL)
1711 && !(payload_type == IPMI_PAYLOAD_TYPE_IPMI
1712 && !(fiid_obj_valid (obj_lan_msg_hdr)
1713 && fiid_obj_template_compare (obj_lan_msg_hdr,
1714 tmpl_lan_msg_hdr_rs) == 1
1715 && fiid_obj_valid (obj_lan_msg_trlr)
1716 && fiid_obj_template_compare (obj_lan_msg_trlr,
1717 tmpl_lan_msg_trlr) == 1))
1718 && fiid_obj_valid (obj_cmd)
1719 && !(payload_type == IPMI_PAYLOAD_TYPE_SOL
1720 && !(fiid_obj_template_compare (obj_cmd,
1721 tmpl_sol_payload_data) == 1
1722 || fiid_obj_template_compare (obj_cmd,
1723 tmpl_sol_payload_data_bmc_to_remote_console) == 1))
1724 && pkt
1725 && lan_msg_len);
1726
1727 if (payload_type == IPMI_PAYLOAD_TYPE_IPMI)
1728 {
1729 if ((obj_lan_msg_trlr_len = fiid_template_len_bytes (tmpl_lan_msg_trlr)) < 0)
1730 {
1731 ERRNO_TRACE (errno);
1732 return (-1);
1733 }
1734
1735 if ((len = fiid_obj_set_all (obj_lan_msg_hdr,
1736 pkt + indx,
1737 lan_msg_len - indx)) < 0)
1738 {
1739 FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_hdr);
1740 return (-1);
1741 }
1742 indx += len;
1743
1744 if (indx >= lan_msg_len)
1745 {
1746 /* cannot parse packet */
1747 ERR_TRACE ("malformed packet", EINVAL);
1748 return (0);
1749 }
1750
1751 /* achu: For payload_type == IPMI Whatever is in between the
1752 * header and the trailer is the command data
1753 */
1754
1755 if ((lan_msg_len - indx) <= obj_lan_msg_trlr_len)
1756 {
1757 /* cannot parse packet */
1758 ERR_TRACE ("malformed packet", EINVAL);
1759 return (0);
1760 }
1761
1762 obj_cmd_len = (lan_msg_len - indx) - obj_lan_msg_trlr_len;
1763 }
1764 else /* payload_type == IPMI_PAYLOAD_TYPE_SOL */
1765 obj_cmd_len = lan_msg_len;
1766
1767 if ((len = fiid_obj_set_all (obj_cmd,
1768 pkt + indx,
1769 obj_cmd_len)) < 0)
1770 {
1771 FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
1772 return (-1);
1773 }
1774 indx += len;
1775
1776 if (payload_type == IPMI_PAYLOAD_TYPE_IPMI)
1777 {
1778 if (indx >= lan_msg_len)
1779 {
1780 /* cannot parse packet */
1781 ERR_TRACE ("malformed packet", EINVAL);
1782 return (0);
1783 }
1784
1785 if ((len = fiid_obj_set_all (obj_lan_msg_trlr,
1786 pkt + indx,
1787 lan_msg_len - indx)) < 0)
1788 {
1789 FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_trlr);
1790 return (-1);
1791 }
1792 }
1793
1794 return (1);
1795 }
1796
1797 /* return 1 on full parse, 0 if not, -1 on error */
1798 static int
_deconstruct_payload_confidentiality_none(uint8_t payload_type,fiid_obj_t obj_rmcpplus_payload,fiid_obj_t obj_lan_msg_hdr,fiid_obj_t obj_cmd,fiid_obj_t obj_lan_msg_trlr,const void * pkt,uint16_t ipmi_payload_len)1799 _deconstruct_payload_confidentiality_none (uint8_t payload_type,
1800 fiid_obj_t obj_rmcpplus_payload,
1801 fiid_obj_t obj_lan_msg_hdr,
1802 fiid_obj_t obj_cmd,
1803 fiid_obj_t obj_lan_msg_trlr,
1804 const void *pkt,
1805 uint16_t ipmi_payload_len)
1806 {
1807 int ret;
1808
1809 assert ((payload_type == IPMI_PAYLOAD_TYPE_IPMI
1810 || payload_type == IPMI_PAYLOAD_TYPE_SOL)
1811 && fiid_obj_valid (obj_rmcpplus_payload)
1812 && fiid_obj_template_compare (obj_rmcpplus_payload, tmpl_rmcpplus_payload) == 1
1813 && !(payload_type == IPMI_PAYLOAD_TYPE_IPMI
1814 && !(fiid_obj_valid (obj_lan_msg_hdr)
1815 && fiid_obj_template_compare (obj_lan_msg_hdr, tmpl_lan_msg_hdr_rs) == 1
1816 && fiid_obj_valid (obj_lan_msg_trlr)
1817 && fiid_obj_template_compare (obj_lan_msg_trlr, tmpl_lan_msg_trlr) == 1))
1818 && fiid_obj_valid (obj_cmd)
1819 && !(payload_type == IPMI_PAYLOAD_TYPE_SOL
1820 && !(fiid_obj_template_compare (obj_cmd, tmpl_sol_payload_data) == 1
1821 || fiid_obj_template_compare (obj_cmd, tmpl_sol_payload_data_bmc_to_remote_console) == 1))
1822 && pkt
1823 && ipmi_payload_len);
1824
1825 /* achu: No encryption, so ipmi_payload_len is the length of
1826 * the msg_hdr, cmd, and msg_trlr.
1827 */
1828 if ((ret = _deconstruct_payload_buf (payload_type,
1829 obj_lan_msg_hdr,
1830 obj_cmd,
1831 obj_lan_msg_trlr,
1832 pkt,
1833 ipmi_payload_len)) < 0)
1834 {
1835 ERRNO_TRACE (errno);
1836 return (-1);
1837 }
1838
1839 if (!ret)
1840 return (0);
1841
1842 if (fiid_obj_set_data (obj_rmcpplus_payload,
1843 "payload_data",
1844 pkt,
1845 ipmi_payload_len) < 0)
1846
1847 {
1848 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_payload);
1849 return (-1);
1850 }
1851
1852 return (1);
1853 }
1854
1855 /* return 1 on full parse, 0 if not, -1 on error */
1856 static int
_deconstruct_payload_confidentiality_aes_cbc_128(uint8_t payload_type,uint8_t payload_encrypted,fiid_obj_t obj_rmcpplus_payload,fiid_obj_t obj_lan_msg_hdr,fiid_obj_t obj_cmd,fiid_obj_t obj_lan_msg_trlr,const void * confidentiality_key,unsigned int confidentiality_key_len,const void * pkt,uint16_t ipmi_payload_len)1857 _deconstruct_payload_confidentiality_aes_cbc_128 (uint8_t payload_type,
1858 uint8_t payload_encrypted,
1859 fiid_obj_t obj_rmcpplus_payload,
1860 fiid_obj_t obj_lan_msg_hdr,
1861 fiid_obj_t obj_cmd,
1862 fiid_obj_t obj_lan_msg_trlr,
1863 const void *confidentiality_key,
1864 unsigned int confidentiality_key_len,
1865 const void *pkt,
1866 uint16_t ipmi_payload_len)
1867 {
1868 uint8_t iv[IPMI_CRYPT_AES_CBC_128_IV_LENGTH];
1869 uint8_t payload_buf[IPMI_MAX_PAYLOAD_LENGTH];
1870 uint8_t pad_length;
1871 int cipher_keylen, cipher_blocklen, decrypt_len;
1872 unsigned int payload_data_len, cmd_data_len, indx = 0;
1873
1874 /* Note: Confidentiality Key for AES_CBS_128 is K2 */
1875
1876 assert ((payload_type == IPMI_PAYLOAD_TYPE_IPMI
1877 || payload_type == IPMI_PAYLOAD_TYPE_SOL)
1878 && payload_encrypted == IPMI_PAYLOAD_FLAG_ENCRYPTED
1879 && fiid_obj_valid (obj_rmcpplus_payload)
1880 && fiid_obj_template_compare (obj_rmcpplus_payload, tmpl_rmcpplus_payload) == 1
1881 && !(payload_type == IPMI_PAYLOAD_TYPE_IPMI
1882 && !(fiid_obj_valid (obj_lan_msg_hdr)
1883 && fiid_obj_template_compare (obj_lan_msg_hdr, tmpl_lan_msg_hdr_rs) == 1
1884 && fiid_obj_valid (obj_lan_msg_trlr)
1885 && fiid_obj_template_compare (obj_lan_msg_trlr, tmpl_lan_msg_trlr) == 1))
1886 && fiid_obj_valid (obj_cmd)
1887 && !(payload_type == IPMI_PAYLOAD_TYPE_SOL
1888 && !(fiid_obj_template_compare (obj_cmd, tmpl_sol_payload_data) == 1
1889 || fiid_obj_template_compare (obj_cmd, tmpl_sol_payload_data_bmc_to_remote_console) == 1))
1890 && confidentiality_key
1891 && pkt
1892 && ipmi_payload_len);
1893
1894 if ((cipher_keylen = crypt_cipher_key_len (IPMI_CRYPT_CIPHER_AES)) < 0)
1895 {
1896 ERRNO_TRACE (errno);
1897 return (-1);
1898 }
1899
1900 assert (!(cipher_keylen < IPMI_CRYPT_AES_CBC_128_KEY_LENGTH));
1901
1902 if (confidentiality_key_len < IPMI_CRYPT_AES_CBC_128_KEY_LENGTH)
1903 {
1904 SET_ERRNO (EINVAL);
1905 return (-1);
1906 }
1907
1908 confidentiality_key_len = IPMI_CRYPT_AES_CBC_128_KEY_LENGTH;
1909
1910 if ((cipher_blocklen = crypt_cipher_block_len (IPMI_CRYPT_CIPHER_AES)) < 0)
1911 {
1912 ERRNO_TRACE (errno);
1913 return (-1);
1914 }
1915
1916 assert (cipher_blocklen == IPMI_CRYPT_AES_CBC_128_BLOCK_LENGTH);
1917
1918 if (ipmi_payload_len < IPMI_CRYPT_AES_CBC_128_BLOCK_LENGTH)
1919 {
1920 /* cannot parse packet */
1921 ERR_TRACE ("malformed packet", EINVAL);
1922 return (0);
1923 }
1924
1925 payload_data_len = ipmi_payload_len - IPMI_CRYPT_AES_CBC_128_BLOCK_LENGTH;
1926
1927 if (!payload_data_len)
1928 {
1929 /* cannot parse packet */
1930 ERR_TRACE ("malformed packet", EINVAL);
1931 return (0);
1932 }
1933
1934 memcpy (iv, pkt, IPMI_CRYPT_AES_CBC_128_BLOCK_LENGTH);
1935 indx += IPMI_CRYPT_AES_CBC_128_BLOCK_LENGTH;
1936 memcpy (payload_buf, pkt + indx, payload_data_len);
1937
1938 if (fiid_obj_set_data (obj_rmcpplus_payload,
1939 "confidentiality_header",
1940 iv,
1941 IPMI_CRYPT_AES_CBC_128_BLOCK_LENGTH) < 0)
1942 {
1943 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_payload);
1944 return (-1);
1945 }
1946
1947 if ((decrypt_len = crypt_cipher_decrypt (IPMI_CRYPT_CIPHER_AES,
1948 IPMI_CRYPT_CIPHER_MODE_CBC,
1949 confidentiality_key,
1950 confidentiality_key_len,
1951 iv,
1952 IPMI_CRYPT_AES_CBC_128_BLOCK_LENGTH,
1953 payload_buf,
1954 payload_data_len)) < 0)
1955 {
1956 ERRNO_TRACE (errno);
1957 return (-1);
1958 }
1959
1960 if (decrypt_len != payload_data_len)
1961 {
1962 SET_ERRNO (EINVAL);
1963 return (-1);
1964 }
1965
1966 pad_length = payload_buf[payload_data_len - 1];
1967 if (pad_length > IPMI_CRYPT_AES_CBC_128_BLOCK_LENGTH)
1968 {
1969 /* cannot parse packet */
1970 ERR_TRACE ("malformed packet", EINVAL);
1971 return (0);
1972 }
1973
1974 if ((pad_length + 1) > payload_data_len)
1975 {
1976 /* cannot parse packet */
1977 ERR_TRACE ("malformed packet", EINVAL);
1978 return (0);
1979 }
1980
1981 cmd_data_len = payload_data_len - pad_length - 1;
1982
1983 if (!cmd_data_len)
1984 {
1985 /* cannot parse packet */
1986 ERR_TRACE ("malformed packet", EINVAL);
1987 return (0);
1988 }
1989
1990 if (fiid_obj_set_data (obj_rmcpplus_payload,
1991 "payload_data",
1992 payload_buf,
1993 cmd_data_len) < 0)
1994 {
1995 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_payload);
1996 return (-1);
1997 }
1998
1999 if (fiid_obj_set_data (obj_rmcpplus_payload,
2000 "confidentiality_trailer",
2001 payload_buf + cmd_data_len,
2002 pad_length + 1), 0)
2003 {
2004 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_payload);
2005 return (-1);
2006 }
2007
2008 /* achu: User is responsible for checking if padding is not corrupt */
2009
2010 return _deconstruct_payload_buf (payload_type,
2011 obj_lan_msg_hdr,
2012 obj_cmd,
2013 obj_lan_msg_trlr,
2014 payload_buf,
2015 cmd_data_len);
2016 }
2017
2018 /* return 1 on full parse, 0 if not, -1 on error */
2019 static int
_deconstruct_payload_rakp(uint8_t payload_type,fiid_obj_t obj_rmcpplus_payload,fiid_obj_t obj_cmd,const void * pkt,uint16_t ipmi_payload_len)2020 _deconstruct_payload_rakp (uint8_t payload_type,
2021 fiid_obj_t obj_rmcpplus_payload,
2022 fiid_obj_t obj_cmd,
2023 const void *pkt,
2024 uint16_t ipmi_payload_len)
2025 {
2026 assert ((payload_type == IPMI_PAYLOAD_TYPE_RMCPPLUS_OPEN_SESSION_RESPONSE
2027 || payload_type == IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_2
2028 || payload_type == IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_4)
2029 && fiid_obj_valid (obj_cmd)
2030 && !(payload_type == IPMI_PAYLOAD_TYPE_RMCPPLUS_OPEN_SESSION_RESPONSE
2031 && fiid_obj_template_compare (obj_cmd, tmpl_rmcpplus_open_session_response) < 0)
2032 && !(payload_type == IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_2
2033 && fiid_obj_template_compare (obj_cmd, tmpl_rmcpplus_rakp_message_2) < 0)
2034 && !(payload_type == IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_4
2035 && fiid_obj_template_compare (obj_cmd, tmpl_rmcpplus_rakp_message_4) < 0)
2036 && fiid_obj_valid (obj_rmcpplus_payload)
2037 && fiid_obj_template_compare (obj_rmcpplus_payload, tmpl_rmcpplus_payload) == 1
2038 && pkt
2039 && ipmi_payload_len);
2040
2041 if (fiid_obj_set_data (obj_rmcpplus_payload,
2042 "payload_data",
2043 pkt,
2044 ipmi_payload_len) < 0)
2045 {
2046 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_payload);
2047 return (-1);
2048 }
2049
2050 if (fiid_obj_set_all (obj_cmd,
2051 pkt,
2052 ipmi_payload_len) < 0)
2053 {
2054 FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
2055 return (-1);
2056 }
2057
2058 return (1);
2059 }
2060
2061 /* return 1 on full parse, 0 if not, -1 on error */
2062 static int
_deconstruct_payload(uint8_t payload_type,uint8_t payload_encrypted,uint8_t authentication_algorithm,uint8_t confidentiality_algorithm,fiid_obj_t obj_rmcpplus_payload,fiid_obj_t obj_lan_msg_hdr,fiid_obj_t obj_cmd,fiid_obj_t obj_lan_msg_trlr,const void * confidentiality_key,unsigned int confidentiality_key_len,const void * pkt,uint16_t ipmi_payload_len)2063 _deconstruct_payload (uint8_t payload_type,
2064 uint8_t payload_encrypted,
2065 uint8_t authentication_algorithm,
2066 uint8_t confidentiality_algorithm,
2067 fiid_obj_t obj_rmcpplus_payload,
2068 fiid_obj_t obj_lan_msg_hdr,
2069 fiid_obj_t obj_cmd,
2070 fiid_obj_t obj_lan_msg_trlr,
2071 const void *confidentiality_key,
2072 unsigned int confidentiality_key_len,
2073 const void *pkt,
2074 uint16_t ipmi_payload_len)
2075 {
2076 assert ((payload_type == IPMI_PAYLOAD_TYPE_IPMI
2077 || payload_type == IPMI_PAYLOAD_TYPE_SOL
2078 || payload_type == IPMI_PAYLOAD_TYPE_RMCPPLUS_OPEN_SESSION_RESPONSE
2079 || payload_type == IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_2
2080 || payload_type == IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_4)
2081 && IPMI_PAYLOAD_ENCRYPTED_FLAG_VALID (payload_encrypted)
2082 && IPMI_AUTHENTICATION_ALGORITHM_SUPPORTED (authentication_algorithm)
2083 && IPMI_CONFIDENTIALITY_ALGORITHM_SUPPORTED (confidentiality_algorithm)
2084 && fiid_obj_valid (obj_rmcpplus_payload)
2085 && fiid_obj_template_compare (obj_rmcpplus_payload, tmpl_rmcpplus_payload) == 1
2086 && fiid_obj_valid (obj_cmd)
2087 && pkt
2088 && ipmi_payload_len);
2089
2090 /* Note: We don't check consider OPEN_SESSION_REQUEST, RAKP1 or
2091 * RAKP3 special b/c they are requests, not responses
2092 */
2093 if (payload_type == IPMI_PAYLOAD_TYPE_IPMI
2094 || payload_type == IPMI_PAYLOAD_TYPE_SOL)
2095 {
2096 if (confidentiality_algorithm == IPMI_CONFIDENTIALITY_ALGORITHM_NONE)
2097 return (_deconstruct_payload_confidentiality_none (payload_type,
2098 obj_rmcpplus_payload,
2099 obj_lan_msg_hdr,
2100 obj_cmd,
2101 obj_lan_msg_trlr,
2102 pkt,
2103 ipmi_payload_len));
2104 else /* IPMI_CONFIDENTIALITY_ALGORITHM_AES_CBC_128 */
2105 return (_deconstruct_payload_confidentiality_aes_cbc_128 (payload_type,
2106 payload_encrypted,
2107 obj_rmcpplus_payload,
2108 obj_lan_msg_hdr,
2109 obj_cmd,
2110 obj_lan_msg_trlr,
2111 confidentiality_key,
2112 confidentiality_key_len,
2113 pkt,
2114 ipmi_payload_len));
2115 }
2116 else
2117 return (_deconstruct_payload_rakp (payload_type,
2118 obj_rmcpplus_payload,
2119 obj_cmd,
2120 pkt,
2121 ipmi_payload_len));
2122 }
2123
2124 int
unassemble_ipmi_rmcpplus_pkt(uint8_t authentication_algorithm,uint8_t integrity_algorithm,uint8_t confidentiality_algorithm,const void * integrity_key,unsigned int integrity_key_len,const void * confidentiality_key,unsigned int confidentiality_key_len,const void * pkt,unsigned int pkt_len,fiid_obj_t obj_rmcp_hdr,fiid_obj_t obj_rmcpplus_session_hdr,fiid_obj_t obj_rmcpplus_payload,fiid_obj_t obj_lan_msg_hdr,fiid_obj_t obj_cmd,fiid_obj_t obj_lan_msg_trlr,fiid_obj_t obj_rmcpplus_session_trlr,unsigned int flags)2125 unassemble_ipmi_rmcpplus_pkt (uint8_t authentication_algorithm,
2126 uint8_t integrity_algorithm,
2127 uint8_t confidentiality_algorithm,
2128 const void *integrity_key,
2129 unsigned int integrity_key_len,
2130 const void *confidentiality_key,
2131 unsigned int confidentiality_key_len,
2132 const void *pkt,
2133 unsigned int pkt_len,
2134 fiid_obj_t obj_rmcp_hdr,
2135 fiid_obj_t obj_rmcpplus_session_hdr,
2136 fiid_obj_t obj_rmcpplus_payload,
2137 fiid_obj_t obj_lan_msg_hdr,
2138 fiid_obj_t obj_cmd,
2139 fiid_obj_t obj_lan_msg_trlr,
2140 fiid_obj_t obj_rmcpplus_session_trlr,
2141 unsigned int flags)
2142 {
2143 unsigned int indx = 0;
2144 int obj_rmcp_hdr_len, obj_len;
2145 uint8_t payload_type, payload_authenticated, payload_encrypted;
2146 uint32_t session_id, session_sequence_number;
2147 uint16_t ipmi_payload_len;
2148 int ret, check_session_trlr_valid = 0;
2149 uint64_t val;
2150 unsigned int flags_mask = (IPMI_INTERFACE_FLAGS_NO_LEGAL_CHECK);
2151
2152 /* achu: obj_lan_msg_hdr & trlr only needed for payload type IPMI
2153 *
2154 * If integrity_algorithm != NONE, technically the key can be NULL
2155 */
2156 if (!IPMI_AUTHENTICATION_ALGORITHM_SUPPORTED (authentication_algorithm)
2157 || !IPMI_INTEGRITY_ALGORITHM_SUPPORTED (integrity_algorithm)
2158 || !IPMI_CONFIDENTIALITY_ALGORITHM_SUPPORTED (confidentiality_algorithm)
2159 || (confidentiality_algorithm == IPMI_CONFIDENTIALITY_ALGORITHM_AES_CBC_128
2160 && !(confidentiality_key
2161 && confidentiality_key_len))
2162 || !pkt
2163 || !fiid_obj_valid (obj_rmcp_hdr)
2164 || !fiid_obj_valid (obj_rmcpplus_session_hdr)
2165 || !fiid_obj_valid (obj_rmcpplus_payload)
2166 || !fiid_obj_valid (obj_cmd)
2167 || (flags & ~flags_mask))
2168 {
2169 SET_ERRNO (EINVAL);
2170 return (-1);
2171 }
2172
2173 if (FIID_OBJ_TEMPLATE_COMPARE (obj_rmcp_hdr, tmpl_rmcp_hdr) < 0)
2174 {
2175 ERRNO_TRACE (errno);
2176 return (-1);
2177 }
2178 if (FIID_OBJ_TEMPLATE_COMPARE (obj_rmcpplus_session_hdr, tmpl_rmcpplus_session_hdr) < 0)
2179 {
2180 ERRNO_TRACE (errno);
2181 return (-1);
2182 }
2183 if (FIID_OBJ_TEMPLATE_COMPARE (obj_rmcpplus_payload, tmpl_rmcpplus_payload) < 0)
2184 {
2185 ERRNO_TRACE (errno);
2186 return (-1);
2187 }
2188
2189 if (fiid_obj_clear (obj_rmcp_hdr) < 0)
2190 {
2191 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcp_hdr);
2192 return (-1);
2193 }
2194
2195 if (fiid_obj_clear (obj_rmcpplus_session_hdr) < 0)
2196 {
2197 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_hdr);
2198 return (-1);
2199 }
2200
2201 if (fiid_obj_clear (obj_rmcpplus_payload) < 0)
2202 {
2203 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_payload);
2204 return (-1);
2205 }
2206
2207 if (fiid_obj_clear (obj_cmd) < 0)
2208 {
2209 FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
2210 return (-1);
2211 }
2212
2213 /*
2214 * Extract RMCP header
2215 */
2216 if ((obj_rmcp_hdr_len = fiid_obj_set_all (obj_rmcp_hdr,
2217 pkt + indx,
2218 pkt_len - indx)) < 0)
2219 {
2220 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcp_hdr);
2221 return (-1);
2222 }
2223 indx += obj_rmcp_hdr_len;
2224
2225 if (pkt_len <= indx)
2226 {
2227 /* cannot parse packet */
2228 ERR_TRACE ("malformed packet", EINVAL);
2229 return (0);
2230 }
2231
2232 /*
2233 * Extract auth_type and payload information
2234 */
2235 if ((obj_len = fiid_obj_set_block (obj_rmcpplus_session_hdr,
2236 "authentication_type",
2237 "payload_type.encrypted",
2238 pkt + indx,
2239 pkt_len - indx)) < 0)
2240 {
2241 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_hdr);
2242 return (-1);
2243 }
2244 indx += obj_len;
2245
2246 if (pkt_len <= indx)
2247 {
2248 /* cannot parse packet */
2249 ERR_TRACE ("malformed packet", EINVAL);
2250 return (0);
2251 }
2252
2253 if (FIID_OBJ_GET (obj_rmcpplus_session_hdr,
2254 "payload_type",
2255 &val) < 0)
2256 {
2257 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_hdr);
2258 return (-1);
2259 }
2260 payload_type = val;
2261
2262 if (payload_type != IPMI_PAYLOAD_TYPE_IPMI
2263 && payload_type != IPMI_PAYLOAD_TYPE_SOL
2264 && payload_type != IPMI_PAYLOAD_TYPE_RMCPPLUS_OPEN_SESSION_RESPONSE
2265 && payload_type != IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_2
2266 && payload_type != IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_4)
2267 {
2268 /* cannot parse packet */
2269 ERR_TRACE ("malformed packet", EINVAL);
2270 return (0);
2271 }
2272
2273 #if 0
2274 /*
2275 * Extract OEM IANA and OEM Payload ID
2276 */
2277
2278 /* achu: The OEM payload type isn't supported, but I'll leave this
2279 * code for the sake of potential future support
2280 */
2281 if (payload_type == IPMI_PAYLOAD_TYPE_OEM_EXPLICIT)
2282 {
2283 if ((obj_len = fiid_obj_set_block (obj_rmcpplus_session_hdr,
2284 "oem_iana",
2285 "oem_payload_id",
2286 pkt + indx,
2287 pkt_len - indx)) < 0)
2288 {
2289 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_hdr);
2290 return (-1);
2291 }
2292 indx += obj_len;
2293
2294 if (pkt_len <= indx)
2295 {
2296 /* cannot parse packet */
2297 ERR_TRACE ("malformed packet", EINVAL);
2298 return (0);
2299 }
2300 }
2301 #endif
2302
2303 /*
2304 * Extract Session ID, Session Sequence Number, and Payload Length
2305 */
2306 if ((obj_len = fiid_obj_set_block (obj_rmcpplus_session_hdr,
2307 "session_id",
2308 "ipmi_payload_len",
2309 pkt + indx,
2310 pkt_len - indx)) < 0)
2311 {
2312 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_hdr);
2313 return (-1);
2314 }
2315 indx += obj_len;
2316
2317 if (pkt_len <= indx)
2318 {
2319 /* cannot parse packet */
2320 ERR_TRACE ("malformed packet", EINVAL);
2321 return (0);
2322 }
2323
2324 if (FIID_OBJ_GET (obj_rmcpplus_session_hdr,
2325 "payload_type.authenticated",
2326 &val) < 0)
2327 {
2328 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_hdr);
2329 return (-1);
2330 }
2331 payload_authenticated = val;
2332
2333 if (FIID_OBJ_GET (obj_rmcpplus_session_hdr,
2334 "payload_type.encrypted",
2335 &val) < 0)
2336 {
2337 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_hdr);
2338 return (-1);
2339 }
2340 payload_encrypted = val;
2341
2342 if (FIID_OBJ_GET (obj_rmcpplus_session_hdr,
2343 "session_id",
2344 &val) < 0)
2345 {
2346 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_hdr);
2347 return (-1);
2348 }
2349 session_id = val;
2350
2351 if (FIID_OBJ_GET (obj_rmcpplus_session_hdr,
2352 "session_sequence_number",
2353 &val) < 0)
2354 {
2355 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_hdr);
2356 return (-1);
2357 }
2358 session_sequence_number = val;
2359
2360 if (FIID_OBJ_GET (obj_rmcpplus_session_hdr,
2361 "ipmi_payload_len",
2362 &val) < 0)
2363 {
2364 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_hdr);
2365 return (-1);
2366 }
2367 ipmi_payload_len = val;
2368
2369 if ((IPMI_PAYLOAD_TYPE_SESSION_SETUP (payload_type)
2370 && (payload_authenticated
2371 || payload_encrypted
2372 || session_id
2373 || session_sequence_number))
2374 || (session_id
2375 && payload_authenticated == IPMI_PAYLOAD_FLAG_UNAUTHENTICATED
2376 && integrity_algorithm != IPMI_INTEGRITY_ALGORITHM_NONE)
2377 || (session_id
2378 && payload_authenticated == IPMI_PAYLOAD_FLAG_AUTHENTICATED
2379 && !(integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_HMAC_SHA1_96
2380 || integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_HMAC_MD5_128
2381 || integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_MD5_128
2382 || integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_HMAC_SHA256_128))
2383 || (confidentiality_algorithm == IPMI_CONFIDENTIALITY_ALGORITHM_NONE
2384 && payload_encrypted != IPMI_PAYLOAD_FLAG_UNENCRYPTED)
2385 || !ipmi_payload_len)
2386 {
2387 /* cannot parse packet */
2388 ERR_TRACE ("malformed packet", EINVAL);
2389 return (0);
2390 }
2391
2392 if (payload_type == IPMI_PAYLOAD_TYPE_IPMI)
2393 {
2394 if (!fiid_obj_valid (obj_lan_msg_hdr)
2395 || !fiid_obj_valid (obj_lan_msg_trlr))
2396 {
2397 SET_ERRNO (EINVAL);
2398 return (-1);
2399 }
2400 if (FIID_OBJ_TEMPLATE_COMPARE (obj_lan_msg_hdr, tmpl_lan_msg_hdr_rs) < 0)
2401 {
2402 ERRNO_TRACE (errno);
2403 return (-1);
2404 }
2405 if (FIID_OBJ_TEMPLATE_COMPARE (obj_lan_msg_trlr, tmpl_lan_msg_trlr) < 0)
2406 {
2407 ERRNO_TRACE (errno);
2408 return (-1);
2409 }
2410 if (fiid_obj_clear (obj_lan_msg_hdr) < 0)
2411 {
2412 FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_hdr);
2413 return (-1);
2414 }
2415 if (fiid_obj_clear (obj_lan_msg_trlr) < 0)
2416 {
2417 FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_trlr);
2418 return (-1);
2419 }
2420 }
2421 else if (payload_type == IPMI_PAYLOAD_TYPE_SOL)
2422 {
2423 if (FIID_OBJ_TEMPLATE_COMPARE (obj_cmd, tmpl_sol_payload_data) < 0
2424 && FIID_OBJ_TEMPLATE_COMPARE (obj_cmd, tmpl_sol_payload_data_bmc_to_remote_console) < 0)
2425 {
2426 ERRNO_TRACE (errno);
2427 return (-1);
2428 }
2429 }
2430 else if (payload_type == IPMI_PAYLOAD_TYPE_RMCPPLUS_OPEN_SESSION_RESPONSE)
2431 {
2432 if (FIID_OBJ_TEMPLATE_COMPARE (obj_cmd, tmpl_rmcpplus_open_session_response) < 0)
2433 {
2434 ERRNO_TRACE (errno);
2435 return (-1);
2436 }
2437 }
2438 else if (payload_type == IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_2)
2439 {
2440 if (FIID_OBJ_TEMPLATE_COMPARE (obj_cmd, tmpl_rmcpplus_rakp_message_2) < 0)
2441 {
2442 ERRNO_TRACE (errno);
2443 return (-1);
2444 }
2445 }
2446 else if (payload_type == IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_4)
2447 {
2448 if (FIID_OBJ_TEMPLATE_COMPARE (obj_cmd, tmpl_rmcpplus_rakp_message_4) < 0)
2449 {
2450 ERRNO_TRACE (errno);
2451 return (-1);
2452 }
2453 }
2454
2455 if (session_id && payload_authenticated == IPMI_PAYLOAD_FLAG_AUTHENTICATED)
2456 {
2457 if (!fiid_obj_valid (obj_rmcpplus_session_trlr))
2458 {
2459 SET_ERRNO (EINVAL);
2460 return (-1);
2461 }
2462 if (FIID_OBJ_TEMPLATE_COMPARE (obj_rmcpplus_session_trlr, tmpl_rmcpplus_session_trlr) < 0)
2463 {
2464 ERRNO_TRACE (errno);
2465 return (-1);
2466 }
2467 if (fiid_obj_clear (obj_rmcpplus_session_trlr) < 0)
2468 {
2469 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_trlr);
2470 return (-1);
2471 }
2472
2473 check_session_trlr_valid++;
2474 }
2475
2476 if ((pkt_len - indx) < ipmi_payload_len)
2477 {
2478 ERR_TRACE ("shorten ipmi_payload_len", EINVAL);
2479 ipmi_payload_len = pkt_len - indx;
2480 }
2481
2482 /*
2483 * Deconstruct/Decrypt Payload
2484 */
2485 if ((ret = _deconstruct_payload (payload_type,
2486 payload_encrypted,
2487 authentication_algorithm,
2488 confidentiality_algorithm,
2489 obj_rmcpplus_payload,
2490 obj_lan_msg_hdr,
2491 obj_cmd,
2492 obj_lan_msg_trlr,
2493 confidentiality_key,
2494 confidentiality_key_len,
2495 pkt + indx,
2496 ipmi_payload_len)) < 0)
2497 {
2498 ERRNO_TRACE (errno);
2499 return (-1);
2500 }
2501
2502 if (!ret)
2503 return (0);
2504
2505 indx += ipmi_payload_len;
2506
2507 if (session_id && payload_authenticated == IPMI_PAYLOAD_FLAG_AUTHENTICATED)
2508 {
2509 int pad_length_field_len, next_header_field_len;
2510 unsigned int authentication_code_len;
2511 uint8_t pad_length;
2512
2513 if (integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_NONE)
2514 authentication_code_len = 0;
2515 else if (integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_HMAC_SHA1_96)
2516 authentication_code_len = IPMI_HMAC_SHA1_96_AUTHENTICATION_CODE_LENGTH;
2517 else if (integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_HMAC_MD5_128)
2518 authentication_code_len = IPMI_HMAC_MD5_128_AUTHENTICATION_CODE_LENGTH;
2519 else if (integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_MD5_128)
2520 authentication_code_len = IPMI_MD5_128_AUTHENTICATION_CODE_LENGTH;
2521 else /* IPMI_INTEGRITY_ALGORITHM_HMAC_SHA256_128 */
2522 authentication_code_len = IPMI_HMAC_SHA256_128_AUTHENTICATION_CODE_LENGTH;
2523
2524 if ((pad_length_field_len = fiid_template_field_len_bytes (tmpl_rmcpplus_session_trlr, "pad_length")) < 0)
2525 {
2526 ERRNO_TRACE (errno);
2527 return (-1);
2528 }
2529 if ((next_header_field_len = fiid_template_field_len_bytes (tmpl_rmcpplus_session_trlr, "next_header")) < 0)
2530 {
2531 ERRNO_TRACE (errno);
2532 return (-1);
2533 }
2534
2535 /* achu: There needs to be atleast the next_header and pad_length fields */
2536 if ((pkt_len - indx) < (authentication_code_len + pad_length_field_len + next_header_field_len))
2537 {
2538 /* cannot parse packet */
2539 ERR_TRACE ("malformed packet", EINVAL);
2540 return (0);
2541 }
2542
2543 if (authentication_code_len)
2544 {
2545 if (fiid_obj_set_data (obj_rmcpplus_session_trlr,
2546 "authentication_code",
2547 pkt + indx + ((pkt_len - indx) - authentication_code_len),
2548 authentication_code_len) < 0)
2549 {
2550 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_trlr);
2551 return (-1);
2552 }
2553 }
2554
2555 if (fiid_obj_set_data (obj_rmcpplus_session_trlr,
2556 "next_header",
2557 pkt + indx + ((pkt_len - indx) - authentication_code_len - next_header_field_len),
2558 next_header_field_len) < 0)
2559 {
2560 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_trlr);
2561 return (-1);
2562 }
2563
2564 if (fiid_obj_set_data (obj_rmcpplus_session_trlr,
2565 "pad_length",
2566 pkt + indx + ((pkt_len - indx) - authentication_code_len - next_header_field_len - pad_length_field_len),
2567 pad_length_field_len) < 0)
2568 {
2569 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_trlr);
2570 return (-1);
2571 }
2572
2573 if (FIID_OBJ_GET (obj_rmcpplus_session_trlr,
2574 "pad_length",
2575 &val) < 0)
2576 {
2577 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_trlr);
2578 return (-1);
2579 }
2580 pad_length = val;
2581
2582 if (pad_length > IPMI_INTEGRITY_PAD_MULTIPLE)
2583 {
2584 /* cannot parse packet */
2585 ERR_TRACE ("malformed packet", EINVAL);
2586 return (0);
2587 }
2588
2589 if (pad_length > (pkt_len - indx - authentication_code_len - pad_length_field_len - next_header_field_len))
2590 {
2591 ERR_TRACE ("shorten pad_length", EINVAL);
2592 pad_length = (pkt_len - indx - authentication_code_len - pad_length_field_len - next_header_field_len);
2593 }
2594
2595 if (fiid_obj_set_data (obj_rmcpplus_session_trlr,
2596 "integrity_pad",
2597 pkt + indx,
2598 pad_length) < 0)
2599 {
2600 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcpplus_session_trlr);
2601 return (-1);
2602 }
2603 }
2604
2605 if (payload_type == IPMI_PAYLOAD_TYPE_IPMI)
2606 {
2607 if (FIID_OBJ_PACKET_VALID (obj_rmcp_hdr) == 1
2608 && FIID_OBJ_PACKET_VALID (obj_rmcpplus_session_hdr) == 1
2609 && FIID_OBJ_PACKET_VALID (obj_rmcpplus_payload) == 1
2610 && FIID_OBJ_PACKET_VALID (obj_lan_msg_hdr) == 1
2611 && ((flags & IPMI_INTERFACE_FLAGS_NO_LEGAL_CHECK) || FIID_OBJ_PACKET_SUFFICIENT (obj_cmd) == 1)
2612 && FIID_OBJ_PACKET_VALID (obj_lan_msg_trlr) == 1
2613 && (!check_session_trlr_valid
2614 || FIID_OBJ_PACKET_VALID (obj_rmcpplus_session_trlr) == 1))
2615 return (1);
2616 }
2617 else
2618 {
2619 if (FIID_OBJ_PACKET_VALID (obj_rmcp_hdr) == 1
2620 && FIID_OBJ_PACKET_VALID (obj_rmcpplus_session_hdr) == 1
2621 && FIID_OBJ_PACKET_VALID (obj_rmcpplus_payload) == 1
2622 && ((flags & IPMI_INTERFACE_FLAGS_NO_LEGAL_CHECK) || FIID_OBJ_PACKET_SUFFICIENT (obj_cmd) == 1)
2623 && (!check_session_trlr_valid
2624 || FIID_OBJ_PACKET_VALID (obj_rmcpplus_session_trlr) == 1))
2625 return (1);
2626 }
2627
2628 return (0);
2629 }
2630
2631 ssize_t
ipmi_rmcpplus_sendto(int s,const void * buf,size_t len,int flags,const struct sockaddr * to,socklen_t tolen)2632 ipmi_rmcpplus_sendto (int s,
2633 const void *buf,
2634 size_t len,
2635 int flags,
2636 const struct sockaddr *to,
2637 socklen_t tolen)
2638 {
2639 /* achu: Per specification table 13-8, no legacy padding for IPMI
2640 * 2.0 packets, so call common sendto.
2641 */
2642 return (ipmi_network_sendto (s, buf, len, flags, to, tolen));
2643 }
2644
2645 ssize_t
ipmi_rmcpplus_recvfrom(int s,void * buf,size_t len,int flags,struct sockaddr * from,socklen_t * fromlen)2646 ipmi_rmcpplus_recvfrom (int s,
2647 void *buf,
2648 size_t len,
2649 int flags,
2650 struct sockaddr *from,
2651 socklen_t *fromlen)
2652 {
2653 return (ipmi_network_recvfrom (s, buf, len, flags, from, fromlen));
2654 }
2655