Line data Source code
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_responder_lib.h"
8 : #include "internal/libspdm_secured_message_lib.h"
9 :
10 : #if LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP
11 :
12 : /**
13 : * Get the SPDM encapsulated KEY_UPDATE request.
14 : *
15 : * @param spdm_context A pointer to the SPDM context.
16 : * @param encap_request_size size in bytes of the encapsulated request data.
17 : * On input, it means the size in bytes of encapsulated request data buffer.
18 : * On output, it means the size in bytes of copied encapsulated request data buffer if RETURN_SUCCESS is returned,
19 : * and means the size in bytes of desired encapsulated request data buffer if RETURN_BUFFER_TOO_SMALL is returned.
20 : * @param encap_request A pointer to the encapsulated request data.
21 : *
22 : * @retval RETURN_SUCCESS The encapsulated request is returned.
23 : * @retval RETURN_BUFFER_TOO_SMALL The buffer is too small to hold the data.
24 : **/
25 : libspdm_return_t
26 2 : libspdm_get_encap_request_key_update(libspdm_context_t *spdm_context,
27 : size_t *encap_request_size,
28 : void *encap_request)
29 : {
30 : spdm_key_update_request_t *spdm_request;
31 : uint32_t session_id;
32 : libspdm_session_info_t *session_info;
33 : libspdm_session_state_t session_state;
34 : bool result;
35 :
36 2 : spdm_context->encap_context.last_encap_request_size = 0;
37 :
38 2 : if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_11) {
39 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
40 : }
41 :
42 2 : if (!libspdm_is_capabilities_flag_supported(
43 : spdm_context, false,
44 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_KEY_UPD_CAP,
45 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_KEY_UPD_CAP)) {
46 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
47 : }
48 :
49 2 : if (!spdm_context->last_spdm_request_session_id_valid) {
50 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
51 : }
52 2 : session_id = spdm_context->last_spdm_request_session_id;
53 : session_info =
54 2 : libspdm_get_session_info_via_session_id(spdm_context, session_id);
55 2 : if (session_info == NULL) {
56 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
57 : }
58 2 : session_state = libspdm_secured_message_get_session_state(
59 : session_info->secured_message_context);
60 2 : if (session_state != LIBSPDM_SESSION_STATE_ESTABLISHED) {
61 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
62 : }
63 :
64 2 : LIBSPDM_ASSERT(*encap_request_size >= sizeof(spdm_key_update_request_t));
65 2 : *encap_request_size = sizeof(spdm_key_update_request_t);
66 :
67 2 : spdm_request = encap_request;
68 :
69 2 : spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
70 2 : spdm_request->header.request_response_code = SPDM_KEY_UPDATE;
71 :
72 2 : libspdm_reset_message_buffer_via_request_code(spdm_context, session_info,
73 2 : spdm_request->header.request_response_code);
74 :
75 2 : if (spdm_context->encap_context.last_encap_request_header
76 2 : .request_response_code != SPDM_KEY_UPDATE) {
77 2 : spdm_request->header.param1 =
78 : SPDM_KEY_UPDATE_OPERATIONS_TABLE_UPDATE_KEY;
79 2 : spdm_request->header.param2 = 0;
80 2 : if(!libspdm_get_random_number(sizeof(spdm_request->header.param2),
81 : &spdm_request->header.param2)) {
82 0 : return LIBSPDM_STATUS_LOW_ENTROPY;
83 : }
84 : } else {
85 0 : spdm_request->header.param1 =
86 : SPDM_KEY_UPDATE_OPERATIONS_TABLE_VERIFY_NEW_KEY;
87 0 : spdm_request->header.param2 = 1;
88 0 : if(!libspdm_get_random_number(sizeof(spdm_request->header.param2),
89 : &spdm_request->header.param2)) {
90 0 : return LIBSPDM_STATUS_LOW_ENTROPY;
91 : }
92 :
93 : /* Create new key*/
94 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
95 : "libspdm_create_update_session_data_key[%x] Responder\n",
96 : session_id));
97 0 : result = libspdm_create_update_session_data_key(
98 : session_info->secured_message_context,
99 : LIBSPDM_KEY_UPDATE_ACTION_RESPONDER);
100 0 : if (!result) {
101 0 : return LIBSPDM_STATUS_CRYPTO_ERROR;
102 : }
103 0 : libspdm_trigger_key_update_callback(
104 : spdm_context, session_id, LIBSPDM_KEY_UPDATE_OPERATION_CREATE_UPDATE,
105 : LIBSPDM_KEY_UPDATE_ACTION_RESPONDER);
106 :
107 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
108 : "libspdm_activate_update_session_data_key[%x] Responder new\n",
109 : session_id));
110 0 : result = libspdm_activate_update_session_data_key(
111 : session_info->secured_message_context,
112 : LIBSPDM_KEY_UPDATE_ACTION_RESPONDER, true);
113 0 : if (!result) {
114 0 : return LIBSPDM_STATUS_CRYPTO_ERROR;
115 : }
116 0 : libspdm_trigger_key_update_callback(
117 : spdm_context, session_id, LIBSPDM_KEY_UPDATE_OPERATION_COMMIT_UPDATE,
118 : LIBSPDM_KEY_UPDATE_ACTION_RESPONDER);
119 : }
120 :
121 2 : libspdm_copy_mem(&spdm_context->encap_context.last_encap_request_header,
122 : sizeof(spdm_context->encap_context.last_encap_request_header),
123 2 : &spdm_request->header, sizeof(spdm_message_header_t));
124 2 : spdm_context->encap_context.last_encap_request_size =
125 2 : *encap_request_size;
126 :
127 2 : return LIBSPDM_STATUS_SUCCESS;
128 : }
129 :
130 : /**
131 : * Process the SPDM encapsulated KEY_UPDATE response.
132 : *
133 : * @param spdm_context A pointer to the SPDM context.
134 : * @param encap_response_size size in bytes of the encapsulated response data.
135 : * @param encap_response A pointer to the encapsulated response data.
136 : * @param need_continue Indicate if encapsulated communication need continue.
137 : *
138 : * @retval RETURN_SUCCESS The encapsulated response is processed.
139 : * @retval RETURN_BUFFER_TOO_SMALL The buffer is too small to hold the data.
140 : * @retval RETURN_SECURITY_VIOLATION Any verification fails.
141 : **/
142 6 : libspdm_return_t libspdm_process_encap_response_key_update(
143 : libspdm_context_t *spdm_context, size_t encap_response_size,
144 : const void *encap_response, bool *need_continue)
145 : {
146 : spdm_key_update_request_t *spdm_request;
147 : const spdm_key_update_response_t *spdm_response;
148 : size_t spdm_response_size;
149 : uint32_t session_id;
150 : libspdm_session_info_t *session_info;
151 : libspdm_session_state_t session_state;
152 :
153 6 : if (!spdm_context->last_spdm_request_session_id_valid) {
154 1 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
155 : }
156 5 : session_id = spdm_context->last_spdm_request_session_id;
157 : session_info =
158 5 : libspdm_get_session_info_via_session_id(spdm_context, session_id);
159 5 : if (session_info == NULL) {
160 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
161 : }
162 5 : session_state = libspdm_secured_message_get_session_state(
163 : session_info->secured_message_context);
164 5 : if (session_state != LIBSPDM_SESSION_STATE_ESTABLISHED) {
165 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
166 : }
167 :
168 5 : spdm_request =
169 : (void *)&spdm_context->encap_context.last_encap_request_header;
170 :
171 5 : spdm_response = encap_response;
172 5 : spdm_response_size = encap_response_size;
173 :
174 5 : if (spdm_response->header.spdm_version != libspdm_get_connection_version (spdm_context)) {
175 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
176 : }
177 :
178 5 : if (spdm_response->header.request_response_code == SPDM_ERROR) {
179 1 : if (spdm_response->header.param1 == SPDM_ERROR_CODE_DECRYPT_ERROR) {
180 1 : libspdm_free_session_id(spdm_context, session_id);
181 1 : return LIBSPDM_STATUS_SESSION_MSG_ERROR;
182 : }
183 : }
184 :
185 : /* this message can only be in secured session
186 : * thus don't need to consider transport layer padding, just check its exact size */
187 4 : if ((spdm_response_size != sizeof(spdm_key_update_response_t)) ||
188 4 : (spdm_response->header.request_response_code !=
189 4 : SPDM_KEY_UPDATE_ACK) ||
190 4 : (spdm_response->header.param1 != spdm_request->header.param1) ||
191 3 : (spdm_response->header.param2 != spdm_request->header.param2)) {
192 1 : if (spdm_request->header.param1 !=
193 : SPDM_KEY_UPDATE_OPERATIONS_TABLE_VERIFY_NEW_KEY) {
194 1 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "libspdm_key_update[%x] failed\n",
195 : session_id));
196 : } else {
197 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "SpdmVerifyKey[%x] failed\n",
198 : session_id));
199 : }
200 1 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
201 : }
202 :
203 3 : if (spdm_request->header.param1 !=
204 : SPDM_KEY_UPDATE_OPERATIONS_TABLE_VERIFY_NEW_KEY) {
205 2 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "libspdm_key_update[%x] success\n",
206 : session_id));
207 2 : *need_continue = true;
208 : } else {
209 1 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "SpdmVerifyKey[%x] Success\n", session_id));
210 1 : *need_continue = false;
211 : }
212 :
213 3 : return LIBSPDM_STATUS_SUCCESS;
214 : }
215 :
216 : #endif /* LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP*/
|