1 /**
2  *  Copyright Notice:
3  *  Copyright 2021-2022 DMTF. All rights reserved.
4  *  License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md
5  **/
6 
7 #include "internal/libspdm_requester_lib.h"
8 
libspdm_init_connection(void * spdm_context,bool get_version_only)9 libspdm_return_t libspdm_init_connection(void *spdm_context, bool get_version_only)
10 {
11     libspdm_return_t status;
12     libspdm_context_t *context;
13 
14     context = spdm_context;
15 
16     status = libspdm_get_version(context, NULL, NULL);
17     if (LIBSPDM_STATUS_IS_ERROR(status)) {
18         return status;
19     }
20 
21     if (!get_version_only) {
22         status = libspdm_get_capabilities(context);
23         if (LIBSPDM_STATUS_IS_ERROR(status)) {
24             return status;
25         }
26         status = libspdm_negotiate_algorithms(context);
27         if (LIBSPDM_STATUS_IS_ERROR(status)) {
28             return status;
29         }
30     }
31     return LIBSPDM_STATUS_SUCCESS;
32 }
33 
34 #if (LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP) || (LIBSPDM_ENABLE_CAPABILITY_PSK_CAP)
libspdm_start_session(void * spdm_context,bool use_psk,const void * psk_hint,uint16_t psk_hint_size,uint8_t measurement_hash_type,uint8_t slot_id,uint8_t session_policy,uint32_t * session_id,uint8_t * heartbeat_period,void * measurement_hash)35 libspdm_return_t libspdm_start_session(void *spdm_context, bool use_psk,
36                                        const void *psk_hint,
37                                        uint16_t psk_hint_size,
38                                        uint8_t measurement_hash_type,
39                                        uint8_t slot_id,
40                                        uint8_t session_policy,
41                                        uint32_t *session_id,
42                                        uint8_t *heartbeat_period,
43                                        void *measurement_hash)
44 {
45     libspdm_return_t status;
46     libspdm_context_t *context;
47 
48     #if LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP
49     libspdm_session_info_t *session_info;
50     uint8_t req_slot_id_param;
51     #endif /* LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP*/
52 
53     context = spdm_context;
54     status = LIBSPDM_STATUS_UNSUPPORTED_CAP;
55 
56     if (!use_psk) {
57     #if LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP
58         status = libspdm_send_receive_key_exchange(
59             context, measurement_hash_type, slot_id, session_policy,
60             session_id, heartbeat_period, &req_slot_id_param,
61             measurement_hash);
62         if (LIBSPDM_STATUS_IS_ERROR(status)) {
63             LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
64                            "libspdm_start_session - libspdm_send_receive_key_exchange - %p\n",
65                            status));
66             return status;
67         }
68 
69         session_info = libspdm_get_session_info_via_session_id(context, *session_id);
70         if (session_info == NULL) {
71             LIBSPDM_ASSERT(false);
72             return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
73         }
74 
75         switch (session_info->mut_auth_requested) {
76         case 0:
77             break;
78         case SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED:
79 #if !(LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP)
80             LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
81                            "libspdm_start_session - unsupported mut_auth_requested - 0x%x\n",
82                            session_info->mut_auth_requested));
83             return LIBSPDM_STATUS_INVALID_MSG_FIELD;
84 #endif
85             break;
86         case SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED_WITH_ENCAP_REQUEST:
87         case SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED_WITH_GET_DIGESTS:
88 #if (LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP) && (LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP)
89             status = libspdm_encapsulated_request(
90                 context, session_id,
91                 session_info->mut_auth_requested,
92                 &req_slot_id_param);
93             LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
94                            "libspdm_start_session - libspdm_encapsulated_request - %p\n", status));
95             if (LIBSPDM_STATUS_IS_ERROR(status)) {
96                 return status;
97             }
98 #else
99             LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
100                            "libspdm_start_session - unsupported mut_auth_requested - 0x%x\n",
101                            session_info->mut_auth_requested));
102             return LIBSPDM_STATUS_INVALID_MSG_FIELD;
103 #endif /* (LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP) && (LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP) */
104             break;
105         default:
106             LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
107                            "libspdm_start_session - unknown mut_auth_requested - 0x%x\n",
108                            session_info->mut_auth_requested));
109             return LIBSPDM_STATUS_INVALID_MSG_FIELD;
110         }
111 
112         if (req_slot_id_param == 0xF) {
113             req_slot_id_param = 0xFF;
114         }
115         status = libspdm_send_receive_finish(context, *session_id, req_slot_id_param);
116         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
117                        "libspdm_start_session - libspdm_send_receive_finish - %p\n", status));
118     #else /* LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP*/
119         LIBSPDM_ASSERT(false);
120         return LIBSPDM_STATUS_UNSUPPORTED_CAP;
121     #endif /* LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP*/
122     } else {
123     #if LIBSPDM_ENABLE_CAPABILITY_PSK_CAP
124         status = libspdm_send_receive_psk_exchange(
125             context, psk_hint, psk_hint_size,
126             measurement_hash_type, session_policy, session_id,
127             heartbeat_period, measurement_hash);
128         if (LIBSPDM_STATUS_IS_ERROR(status)) {
129             LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
130                            "libspdm_start_session - libspdm_send_receive_psk_exchange - %p\n",
131                            status));
132             return status;
133         }
134 
135         /* send PSK_FINISH only if Responder supports context.*/
136         if (libspdm_is_capabilities_flag_supported(
137                 context, true, 0,
138                 SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PSK_CAP_RESPONDER_WITH_CONTEXT)) {
139             status = libspdm_send_receive_psk_finish(context, *session_id);
140             LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
141                            "libspdm_start_session - libspdm_send_receive_psk_finish - %p\n",
142                            status));
143         }
144     #endif /* LIBSPDM_ENABLE_CAPABILITY_PSK_CAP*/
145     }
146     return status;
147 }
148 
libspdm_start_session_ex(void * spdm_context,bool use_psk,const void * psk_hint,uint16_t psk_hint_size,uint8_t measurement_hash_type,uint8_t slot_id,uint8_t session_policy,uint32_t * session_id,uint8_t * heartbeat_period,void * measurement_hash,const void * requester_random_in,size_t requester_random_in_size,void * requester_random,size_t * requester_random_size,void * responder_random,size_t * responder_random_size,const void * requester_opaque_data,size_t requester_opaque_data_size,void * responder_opaque_data,size_t * responder_opaque_data_size)149 libspdm_return_t libspdm_start_session_ex(void *spdm_context, bool use_psk,
150                                           const void *psk_hint,
151                                           uint16_t psk_hint_size,
152                                           uint8_t measurement_hash_type,
153                                           uint8_t slot_id,
154                                           uint8_t session_policy,
155                                           uint32_t *session_id,
156                                           uint8_t *heartbeat_period,
157                                           void *measurement_hash,
158                                           const void *requester_random_in,
159                                           size_t requester_random_in_size,
160                                           void *requester_random,
161                                           size_t *requester_random_size,
162                                           void *responder_random,
163                                           size_t *responder_random_size,
164                                           const void *requester_opaque_data,
165                                           size_t requester_opaque_data_size,
166                                           void *responder_opaque_data,
167                                           size_t *responder_opaque_data_size)
168 {
169     libspdm_return_t status;
170     libspdm_context_t *context;
171 
172     #if LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP
173     libspdm_session_info_t *session_info;
174     uint8_t req_slot_id_param;
175     #endif /* LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP */
176 
177     context = spdm_context;
178     status = LIBSPDM_STATUS_UNSUPPORTED_CAP;
179 
180     if (!use_psk) {
181     #if LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP
182         LIBSPDM_ASSERT (
183             requester_random_in_size == 0 || requester_random_in_size == SPDM_RANDOM_DATA_SIZE);
184         LIBSPDM_ASSERT (
185             requester_random_size == NULL || *requester_random_size == SPDM_RANDOM_DATA_SIZE);
186         LIBSPDM_ASSERT (
187             responder_random_size == NULL || *responder_random_size == SPDM_RANDOM_DATA_SIZE);
188         status = libspdm_send_receive_key_exchange_ex(
189             context, measurement_hash_type, slot_id, session_policy,
190             session_id, heartbeat_period, &req_slot_id_param,
191             measurement_hash, requester_random_in,
192             requester_random, responder_random,
193             requester_opaque_data, requester_opaque_data_size,
194             responder_opaque_data, responder_opaque_data_size);
195         if (LIBSPDM_STATUS_IS_ERROR(status)) {
196             LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
197                            "libspdm_start_session - libspdm_send_receive_key_exchange - %p\n",
198                            status));
199             return status;
200         }
201 
202         session_info = libspdm_get_session_info_via_session_id(context, *session_id);
203         if (session_info == NULL) {
204             LIBSPDM_ASSERT(false);
205             return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
206         }
207 
208         switch (session_info->mut_auth_requested) {
209         case 0:
210             break;
211         case SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED:
212 #if !(LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP)
213             LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
214                            "libspdm_start_session - unsupported mut_auth_requested - 0x%x\n",
215                            session_info->mut_auth_requested));
216             return LIBSPDM_STATUS_INVALID_MSG_FIELD;
217 #endif
218             break;
219         case SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED_WITH_ENCAP_REQUEST:
220         case SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED_WITH_GET_DIGESTS:
221 #if (LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP) && (LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP)
222             status = libspdm_encapsulated_request(
223                 context, session_id,
224                 session_info->mut_auth_requested,
225                 &req_slot_id_param);
226             LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
227                            "libspdm_start_session - libspdm_encapsulated_request - %p\n", status));
228             if (LIBSPDM_STATUS_IS_ERROR(status)) {
229                 return status;
230             }
231 #else
232             LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
233                            "libspdm_start_session - unsupported mut_auth_requested - 0x%x\n",
234                            session_info->mut_auth_requested));
235             return LIBSPDM_STATUS_INVALID_MSG_FIELD;
236 #endif /* (LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP) && (LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP) */
237             break;
238         default:
239             LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
240                            "libspdm_start_session - unknown mut_auth_requested - 0x%x\n",
241                            session_info->mut_auth_requested));
242             return LIBSPDM_STATUS_INVALID_MSG_FIELD;
243         }
244 
245         if (req_slot_id_param == 0xF) {
246             req_slot_id_param = 0xFF;
247         }
248         status = libspdm_send_receive_finish(context, *session_id, req_slot_id_param);
249         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
250                        "libspdm_start_session - libspdm_send_receive_finish - %p\n", status));
251     #else /* LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP*/
252         LIBSPDM_ASSERT(false);
253         return LIBSPDM_STATUS_UNSUPPORTED_CAP;
254     #endif /* LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP*/
255     } else {
256     #if LIBSPDM_ENABLE_CAPABILITY_PSK_CAP
257         status = libspdm_send_receive_psk_exchange_ex(
258             context, psk_hint, psk_hint_size,
259             measurement_hash_type, session_policy, session_id,
260             heartbeat_period, measurement_hash,
261             requester_random_in, requester_random_in_size,
262             requester_random, requester_random_size,
263             responder_random, responder_random_size,
264             requester_opaque_data, requester_opaque_data_size,
265             responder_opaque_data, responder_opaque_data_size);
266         if (LIBSPDM_STATUS_IS_ERROR(status)) {
267             LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
268                            "libspdm_start_session - libspdm_send_receive_psk_exchange - %p\n",
269                            status));
270             return status;
271         }
272 
273         /* send PSK_FINISH only if Responder supports context.*/
274         if (libspdm_is_capabilities_flag_supported(
275                 context, true, 0,
276                 SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PSK_CAP_RESPONDER_WITH_CONTEXT)) {
277             status = libspdm_send_receive_psk_finish(context, *session_id);
278             LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
279                            "libspdm_start_session - libspdm_send_receive_psk_finish - %p\n",
280                            status));
281         }
282     #else /* LIBSPDM_ENABLE_CAPABILITY_PSK_CAP*/
283         LIBSPDM_ASSERT(false);
284         return LIBSPDM_STATUS_UNSUPPORTED_CAP;
285     #endif /* LIBSPDM_ENABLE_CAPABILITY_PSK_CAP*/
286     }
287 
288     return status;
289 }
290 
libspdm_stop_session(void * spdm_context,uint32_t session_id,uint8_t end_session_attributes)291 libspdm_return_t libspdm_stop_session(void *spdm_context, uint32_t session_id,
292                                       uint8_t end_session_attributes)
293 {
294     libspdm_return_t status;
295     libspdm_context_t *context;
296 
297     context = spdm_context;
298 
299     status = libspdm_send_receive_end_session(context, session_id, end_session_attributes);
300     LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "libspdm_stop_session - %p\n", status));
301 
302     return status;
303 }
304 #endif /* (LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP) || (LIBSPDM_ENABLE_CAPABILITY_PSK_CAP) */
305 
libspdm_send_data(void * spdm_context,const uint32_t * session_id,bool is_app_message,const void * request,size_t request_size)306 libspdm_return_t libspdm_send_data(void *spdm_context, const uint32_t *session_id,
307                                    bool is_app_message,
308                                    const void *request, size_t request_size)
309 {
310     libspdm_return_t status;
311     libspdm_context_t *context;
312     spdm_message_header_t *spdm_request;
313     size_t spdm_request_size;
314     uint8_t *message;
315     size_t message_size;
316     size_t transport_header_size;
317 
318     context = spdm_context;
319     transport_header_size = context->local_context.capability.transport_header_size;
320 
321     status = libspdm_acquire_sender_buffer(context, &message_size, (void **)&message);
322     if (LIBSPDM_STATUS_IS_ERROR(status)) {
323         return status;
324     }
325     LIBSPDM_ASSERT (message_size >= transport_header_size +
326                     context->local_context.capability.transport_tail_size);
327     spdm_request = (void *)(message + transport_header_size);
328     spdm_request_size = message_size - transport_header_size -
329                         context->local_context.capability.transport_tail_size;
330     libspdm_copy_mem (spdm_request, spdm_request_size, request, request_size);
331     spdm_request_size = request_size;
332 
333     status = libspdm_send_request(context, session_id, is_app_message,
334                                   spdm_request_size, spdm_request);
335 
336     libspdm_release_sender_buffer(context);
337 
338     return status;
339 }
340 
libspdm_receive_data(void * spdm_context,const uint32_t * session_id,bool is_app_message,void * response,size_t * response_size)341 libspdm_return_t libspdm_receive_data(void *spdm_context, const uint32_t *session_id,
342                                       bool is_app_message,
343                                       void *response, size_t *response_size)
344 {
345     libspdm_return_t status;
346     libspdm_context_t *context;
347     spdm_error_response_t *spdm_response;
348     size_t spdm_response_size;
349     uint8_t *message;
350     size_t message_size;
351 
352     context = spdm_context;
353 
354     status = libspdm_acquire_receiver_buffer(context, &message_size, (void **)&message);
355     if (LIBSPDM_STATUS_IS_ERROR(status)) {
356         return status;
357     }
358 
359     spdm_response = (void *)(message);
360     spdm_response_size = message_size;
361 
362     status = libspdm_receive_response(context, session_id, is_app_message,
363                                       &spdm_response_size, (void **)&spdm_response);
364     if (LIBSPDM_STATUS_IS_ERROR(status)) {
365         libspdm_release_receiver_buffer (context);
366         return status;
367     }
368 
369     if (spdm_response->header.request_response_code == SPDM_ERROR) {
370         if ((spdm_response->header.param1 == SPDM_ERROR_CODE_DECRYPT_ERROR) &&
371             (session_id != NULL)) {
372             libspdm_free_session_id(context, *session_id);
373             libspdm_release_receiver_buffer (context);
374             return LIBSPDM_STATUS_SESSION_MSG_ERROR;
375         }
376     }
377 
378     if (*response_size >= spdm_response_size) {
379         libspdm_copy_mem (response, *response_size, spdm_response, spdm_response_size);
380         *response_size = spdm_response_size;
381     } else {
382         *response_size = spdm_response_size;
383         libspdm_release_receiver_buffer (context);
384         return LIBSPDM_STATUS_BUFFER_TOO_SMALL;
385     }
386 
387     libspdm_release_receiver_buffer(context);
388 
389     return LIBSPDM_STATUS_SUCCESS;
390 }
391 
libspdm_send_receive_data(void * spdm_context,const uint32_t * session_id,bool is_app_message,const void * request,size_t request_size,void * response,size_t * response_size)392 libspdm_return_t libspdm_send_receive_data(void *spdm_context, const uint32_t *session_id,
393                                            bool is_app_message,
394                                            const void *request, size_t request_size,
395                                            void *response, size_t *response_size)
396 {
397     libspdm_return_t status;
398 
399     status = libspdm_send_data(spdm_context, session_id, is_app_message, request, request_size);
400 
401     if (LIBSPDM_STATUS_IS_ERROR(status)) {
402         return status;
403     }
404 
405     return libspdm_receive_data(spdm_context, session_id, is_app_message, response, response_size);
406 }
407