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