Maintainers.txt: Update email address
[mirror_edk2.git] / CryptoPkg / Library / TlsLib / TlsProcess.c
CommitLineData
264702a0
HW
1/** @file\r
2 SSL/TLS Process Library Wrapper Implementation over OpenSSL.\r
3 The process includes the TLS handshake and packet I/O.\r
4\r
5Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>\r
6(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
2009f6b4 7SPDX-License-Identifier: BSD-2-Clause-Patent\r
264702a0
HW
8\r
9**/\r
10\r
11#include "InternalTlsLib.h"\r
12\r
7c342378 13#define MAX_BUFFER_SIZE 32768\r
264702a0
HW
14\r
15/**\r
16 Checks if the TLS handshake was done.\r
17\r
18 This function will check if the specified TLS handshake was done.\r
19\r
20 @param[in] Tls Pointer to the TLS object for handshake state checking.\r
21\r
22 @retval TRUE The TLS handshake was done.\r
23 @retval FALSE The TLS handshake was not done.\r
24\r
25**/\r
26BOOLEAN\r
27EFIAPI\r
28TlsInHandshake (\r
7c342378 29 IN VOID *Tls\r
264702a0
HW
30 )\r
31{\r
32 TLS_CONNECTION *TlsConn;\r
33\r
7c342378
MK
34 TlsConn = (TLS_CONNECTION *)Tls;\r
35 if ((TlsConn == NULL) || (TlsConn->Ssl == NULL)) {\r
264702a0
HW
36 return FALSE;\r
37 }\r
38\r
39 //\r
40 // Return the status which indicates if the TLS handshake was done.\r
41 //\r
42 return !SSL_is_init_finished (TlsConn->Ssl);\r
43}\r
44\r
45/**\r
46 Perform a TLS/SSL handshake.\r
47\r
48 This function will perform a TLS/SSL handshake.\r
49\r
50 @param[in] Tls Pointer to the TLS object for handshake operation.\r
51 @param[in] BufferIn Pointer to the most recently received TLS Handshake packet.\r
52 @param[in] BufferInSize Packet size in bytes for the most recently received TLS\r
53 Handshake packet.\r
54 @param[out] BufferOut Pointer to the buffer to hold the built packet.\r
55 @param[in, out] BufferOutSize Pointer to the buffer size in bytes. On input, it is\r
56 the buffer size provided by the caller. On output, it\r
57 is the buffer size in fact needed to contain the\r
58 packet.\r
59\r
60 @retval EFI_SUCCESS The required TLS packet is built successfully.\r
61 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:\r
62 Tls is NULL.\r
63 BufferIn is NULL but BufferInSize is NOT 0.\r
64 BufferInSize is 0 but BufferIn is NOT NULL.\r
65 BufferOutSize is NULL.\r
66 BufferOut is NULL if *BufferOutSize is not zero.\r
67 @retval EFI_BUFFER_TOO_SMALL BufferOutSize is too small to hold the response packet.\r
68 @retval EFI_ABORTED Something wrong during handshake.\r
69\r
70**/\r
71EFI_STATUS\r
72EFIAPI\r
73TlsDoHandshake (\r
7c342378
MK
74 IN VOID *Tls,\r
75 IN UINT8 *BufferIn OPTIONAL,\r
76 IN UINTN BufferInSize OPTIONAL,\r
77 OUT UINT8 *BufferOut OPTIONAL,\r
78 IN OUT UINTN *BufferOutSize\r
264702a0
HW
79 )\r
80{\r
81 TLS_CONNECTION *TlsConn;\r
82 UINTN PendingBufferSize;\r
83 INTN Ret;\r
84 UINTN ErrorCode;\r
85\r
7c342378 86 TlsConn = (TLS_CONNECTION *)Tls;\r
264702a0
HW
87 PendingBufferSize = 0;\r
88 Ret = 1;\r
89\r
7c342378
MK
90 if ((TlsConn == NULL) || \\r
91 (TlsConn->Ssl == NULL) || (TlsConn->InBio == NULL) || (TlsConn->OutBio == NULL) || \\r
92 (BufferOutSize == NULL) || \\r
93 ((BufferIn == NULL) && (BufferInSize != 0)) || \\r
94 ((BufferIn != NULL) && (BufferInSize == 0)) || \\r
95 ((BufferOut == NULL) && (*BufferOutSize != 0)))\r
96 {\r
264702a0
HW
97 return EFI_INVALID_PARAMETER;\r
98 }\r
99\r
7c342378 100 if ((BufferIn == NULL) && (BufferInSize == 0)) {\r
264702a0
HW
101 //\r
102 // If RequestBuffer is NULL and RequestSize is 0, and TLS session\r
103 // status is EfiTlsSessionNotStarted, the TLS session will be initiated\r
104 // and the response packet needs to be ClientHello.\r
105 //\r
7c342378 106 PendingBufferSize = (UINTN)BIO_ctrl_pending (TlsConn->OutBio);\r
264702a0
HW
107 if (PendingBufferSize == 0) {\r
108 SSL_set_connect_state (TlsConn->Ssl);\r
7c342378
MK
109 Ret = SSL_do_handshake (TlsConn->Ssl);\r
110 PendingBufferSize = (UINTN)BIO_ctrl_pending (TlsConn->OutBio);\r
264702a0
HW
111 }\r
112 } else {\r
7c342378 113 PendingBufferSize = (UINTN)BIO_ctrl_pending (TlsConn->OutBio);\r
264702a0 114 if (PendingBufferSize == 0) {\r
7c342378
MK
115 BIO_write (TlsConn->InBio, BufferIn, (UINT32)BufferInSize);\r
116 Ret = SSL_do_handshake (TlsConn->Ssl);\r
117 PendingBufferSize = (UINTN)BIO_ctrl_pending (TlsConn->OutBio);\r
264702a0
HW
118 }\r
119 }\r
120\r
121 if (Ret < 1) {\r
7c342378
MK
122 Ret = SSL_get_error (TlsConn->Ssl, (int)Ret);\r
123 if ((Ret == SSL_ERROR_SSL) ||\r
124 (Ret == SSL_ERROR_SYSCALL) ||\r
125 (Ret == SSL_ERROR_ZERO_RETURN))\r
126 {\r
264702a0
HW
127 DEBUG ((\r
128 DEBUG_ERROR,\r
129 "%a SSL_HANDSHAKE_ERROR State=0x%x SSL_ERROR_%a\n",\r
130 __FUNCTION__,\r
131 SSL_get_state (TlsConn->Ssl),\r
132 Ret == SSL_ERROR_SSL ? "SSL" : Ret == SSL_ERROR_SYSCALL ? "SYSCALL" : "ZERO_RETURN"\r
133 ));\r
134 DEBUG_CODE_BEGIN ();\r
7c342378
MK
135 while (TRUE) {\r
136 ErrorCode = ERR_get_error ();\r
137 if (ErrorCode == 0) {\r
138 break;\r
264702a0 139 }\r
7c342378
MK
140\r
141 DEBUG ((\r
142 DEBUG_ERROR,\r
143 "%a ERROR 0x%x=L%x:F%x:R%x\n",\r
144 __FUNCTION__,\r
145 ErrorCode,\r
146 ERR_GET_LIB (ErrorCode),\r
147 ERR_GET_FUNC (ErrorCode),\r
148 ERR_GET_REASON (ErrorCode)\r
149 ));\r
150 }\r
151\r
264702a0
HW
152 DEBUG_CODE_END ();\r
153 return EFI_ABORTED;\r
154 }\r
155 }\r
156\r
157 if (PendingBufferSize > *BufferOutSize) {\r
158 *BufferOutSize = PendingBufferSize;\r
159 return EFI_BUFFER_TOO_SMALL;\r
160 }\r
161\r
162 if (PendingBufferSize > 0) {\r
7c342378 163 *BufferOutSize = BIO_read (TlsConn->OutBio, BufferOut, (UINT32)PendingBufferSize);\r
264702a0
HW
164 } else {\r
165 *BufferOutSize = 0;\r
166 }\r
167\r
168 return EFI_SUCCESS;\r
169}\r
170\r
171/**\r
172 Handle Alert message recorded in BufferIn. If BufferIn is NULL and BufferInSize is zero,\r
173 TLS session has errors and the response packet needs to be Alert message based on error type.\r
174\r
175 @param[in] Tls Pointer to the TLS object for state checking.\r
176 @param[in] BufferIn Pointer to the most recently received TLS Alert packet.\r
177 @param[in] BufferInSize Packet size in bytes for the most recently received TLS\r
178 Alert packet.\r
179 @param[out] BufferOut Pointer to the buffer to hold the built packet.\r
180 @param[in, out] BufferOutSize Pointer to the buffer size in bytes. On input, it is\r
181 the buffer size provided by the caller. On output, it\r
182 is the buffer size in fact needed to contain the\r
183 packet.\r
184\r
185 @retval EFI_SUCCESS The required TLS packet is built successfully.\r
186 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:\r
187 Tls is NULL.\r
188 BufferIn is NULL but BufferInSize is NOT 0.\r
189 BufferInSize is 0 but BufferIn is NOT NULL.\r
190 BufferOutSize is NULL.\r
191 BufferOut is NULL if *BufferOutSize is not zero.\r
192 @retval EFI_ABORTED An error occurred.\r
193 @retval EFI_BUFFER_TOO_SMALL BufferOutSize is too small to hold the response packet.\r
194\r
195**/\r
196EFI_STATUS\r
197EFIAPI\r
198TlsHandleAlert (\r
7c342378
MK
199 IN VOID *Tls,\r
200 IN UINT8 *BufferIn OPTIONAL,\r
201 IN UINTN BufferInSize OPTIONAL,\r
202 OUT UINT8 *BufferOut OPTIONAL,\r
203 IN OUT UINTN *BufferOutSize\r
264702a0
HW
204 )\r
205{\r
206 TLS_CONNECTION *TlsConn;\r
207 UINTN PendingBufferSize;\r
208 UINT8 *TempBuffer;\r
209 INTN Ret;\r
210\r
7c342378 211 TlsConn = (TLS_CONNECTION *)Tls;\r
264702a0
HW
212 PendingBufferSize = 0;\r
213 TempBuffer = NULL;\r
214 Ret = 0;\r
215\r
7c342378
MK
216 if ((TlsConn == NULL) || \\r
217 (TlsConn->Ssl == NULL) || (TlsConn->InBio == NULL) || (TlsConn->OutBio == NULL) || \\r
218 (BufferOutSize == NULL) || \\r
219 ((BufferIn == NULL) && (BufferInSize != 0)) || \\r
220 ((BufferIn != NULL) && (BufferInSize == 0)) || \\r
221 ((BufferOut == NULL) && (*BufferOutSize != 0)))\r
222 {\r
264702a0
HW
223 return EFI_INVALID_PARAMETER;\r
224 }\r
225\r
7c342378
MK
226 PendingBufferSize = (UINTN)BIO_ctrl_pending (TlsConn->OutBio);\r
227 if ((PendingBufferSize == 0) && (BufferIn != NULL) && (BufferInSize != 0)) {\r
228 Ret = BIO_write (TlsConn->InBio, BufferIn, (UINT32)BufferInSize);\r
229 if (Ret != (INTN)BufferInSize) {\r
264702a0
HW
230 return EFI_ABORTED;\r
231 }\r
232\r
7c342378 233 TempBuffer = (UINT8 *)OPENSSL_malloc (MAX_BUFFER_SIZE);\r
264702a0
HW
234\r
235 //\r
236 // ssl3_send_alert() will be called in ssl3_read_bytes() function.\r
237 // TempBuffer is invalid since it's a Alert message, so just ignore it.\r
238 //\r
239 SSL_read (TlsConn->Ssl, TempBuffer, MAX_BUFFER_SIZE);\r
240\r
241 OPENSSL_free (TempBuffer);\r
242\r
7c342378 243 PendingBufferSize = (UINTN)BIO_ctrl_pending (TlsConn->OutBio);\r
264702a0
HW
244 }\r
245\r
246 if (PendingBufferSize > *BufferOutSize) {\r
247 *BufferOutSize = PendingBufferSize;\r
248 return EFI_BUFFER_TOO_SMALL;\r
249 }\r
250\r
251 if (PendingBufferSize > 0) {\r
7c342378 252 *BufferOutSize = BIO_read (TlsConn->OutBio, BufferOut, (UINT32)PendingBufferSize);\r
264702a0
HW
253 } else {\r
254 *BufferOutSize = 0;\r
255 }\r
256\r
257 return EFI_SUCCESS;\r
258}\r
259\r
260/**\r
261 Build the CloseNotify packet.\r
262\r
263 @param[in] Tls Pointer to the TLS object for state checking.\r
264 @param[in, out] Buffer Pointer to the buffer to hold the built packet.\r
265 @param[in, out] BufferSize Pointer to the buffer size in bytes. On input, it is\r
266 the buffer size provided by the caller. On output, it\r
267 is the buffer size in fact needed to contain the\r
268 packet.\r
269\r
270 @retval EFI_SUCCESS The required TLS packet is built successfully.\r
271 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:\r
272 Tls is NULL.\r
273 BufferSize is NULL.\r
274 Buffer is NULL if *BufferSize is not zero.\r
275 @retval EFI_BUFFER_TOO_SMALL BufferSize is too small to hold the response packet.\r
276\r
277**/\r
278EFI_STATUS\r
279EFIAPI\r
280TlsCloseNotify (\r
7c342378
MK
281 IN VOID *Tls,\r
282 IN OUT UINT8 *Buffer,\r
283 IN OUT UINTN *BufferSize\r
264702a0
HW
284 )\r
285{\r
286 TLS_CONNECTION *TlsConn;\r
287 UINTN PendingBufferSize;\r
288\r
7c342378 289 TlsConn = (TLS_CONNECTION *)Tls;\r
264702a0
HW
290 PendingBufferSize = 0;\r
291\r
7c342378
MK
292 if ((TlsConn == NULL) || \\r
293 (TlsConn->Ssl == NULL) || (TlsConn->InBio == NULL) || (TlsConn->OutBio == NULL) || \\r
294 (BufferSize == NULL) || \\r
295 ((Buffer == NULL) && (*BufferSize != 0)))\r
296 {\r
264702a0
HW
297 return EFI_INVALID_PARAMETER;\r
298 }\r
299\r
7c342378 300 PendingBufferSize = (UINTN)BIO_ctrl_pending (TlsConn->OutBio);\r
264702a0
HW
301 if (PendingBufferSize == 0) {\r
302 //\r
303 // ssl3_send_alert() and ssl3_dispatch_alert() function will be called.\r
304 //\r
305 SSL_shutdown (TlsConn->Ssl);\r
7c342378 306 PendingBufferSize = (UINTN)BIO_ctrl_pending (TlsConn->OutBio);\r
264702a0
HW
307 }\r
308\r
309 if (PendingBufferSize > *BufferSize) {\r
310 *BufferSize = PendingBufferSize;\r
311 return EFI_BUFFER_TOO_SMALL;\r
312 }\r
313\r
314 if (PendingBufferSize > 0) {\r
7c342378 315 *BufferSize = BIO_read (TlsConn->OutBio, Buffer, (UINT32)PendingBufferSize);\r
264702a0
HW
316 } else {\r
317 *BufferSize = 0;\r
318 }\r
319\r
320 return EFI_SUCCESS;\r
321}\r
322\r
323/**\r
324 Attempts to read bytes from one TLS object and places the data in Buffer.\r
325\r
326 This function will attempt to read BufferSize bytes from the TLS object\r
327 and places the data in Buffer.\r
328\r
329 @param[in] Tls Pointer to the TLS object.\r
330 @param[in,out] Buffer Pointer to the buffer to store the data.\r
331 @param[in] BufferSize The size of Buffer in bytes.\r
332\r
333 @retval >0 The amount of data successfully read from the TLS object.\r
334 @retval <=0 No data was successfully read.\r
335\r
336**/\r
337INTN\r
338EFIAPI\r
339TlsCtrlTrafficOut (\r
7c342378
MK
340 IN VOID *Tls,\r
341 IN OUT VOID *Buffer,\r
342 IN UINTN BufferSize\r
264702a0
HW
343 )\r
344{\r
345 TLS_CONNECTION *TlsConn;\r
346\r
7c342378
MK
347 TlsConn = (TLS_CONNECTION *)Tls;\r
348 if ((TlsConn == NULL) || (TlsConn->OutBio == 0)) {\r
264702a0
HW
349 return -1;\r
350 }\r
351\r
352 //\r
353 // Read and return the amount of data from the BIO.\r
354 //\r
7c342378 355 return BIO_read (TlsConn->OutBio, Buffer, (UINT32)BufferSize);\r
264702a0
HW
356}\r
357\r
358/**\r
359 Attempts to write data from the buffer to TLS object.\r
360\r
361 This function will attempt to write BufferSize bytes data from the Buffer\r
362 to the TLS object.\r
363\r
364 @param[in] Tls Pointer to the TLS object.\r
365 @param[in] Buffer Pointer to the data buffer.\r
366 @param[in] BufferSize The size of Buffer in bytes.\r
367\r
368 @retval >0 The amount of data successfully written to the TLS object.\r
369 @retval <=0 No data was successfully written.\r
370\r
371**/\r
372INTN\r
373EFIAPI\r
374TlsCtrlTrafficIn (\r
7c342378
MK
375 IN VOID *Tls,\r
376 IN VOID *Buffer,\r
377 IN UINTN BufferSize\r
264702a0
HW
378 )\r
379{\r
380 TLS_CONNECTION *TlsConn;\r
381\r
7c342378
MK
382 TlsConn = (TLS_CONNECTION *)Tls;\r
383 if ((TlsConn == NULL) || (TlsConn->InBio == 0)) {\r
264702a0
HW
384 return -1;\r
385 }\r
386\r
387 //\r
388 // Write and return the amount of data to the BIO.\r
389 //\r
7c342378 390 return BIO_write (TlsConn->InBio, Buffer, (UINT32)BufferSize);\r
264702a0 391}\r
7c342378 392\r
264702a0
HW
393/**\r
394 Attempts to read bytes from the specified TLS connection into the buffer.\r
395\r
396 This function tries to read BufferSize bytes data from the specified TLS\r
397 connection into the Buffer.\r
398\r
399 @param[in] Tls Pointer to the TLS connection for data reading.\r
400 @param[in,out] Buffer Pointer to the data buffer.\r
401 @param[in] BufferSize The size of Buffer in bytes.\r
402\r
403 @retval >0 The read operation was successful, and return value is the\r
404 number of bytes actually read from the TLS connection.\r
405 @retval <=0 The read operation was not successful.\r
406\r
407**/\r
408INTN\r
409EFIAPI\r
410TlsRead (\r
7c342378
MK
411 IN VOID *Tls,\r
412 IN OUT VOID *Buffer,\r
413 IN UINTN BufferSize\r
264702a0
HW
414 )\r
415{\r
416 TLS_CONNECTION *TlsConn;\r
417\r
7c342378
MK
418 TlsConn = (TLS_CONNECTION *)Tls;\r
419 if ((TlsConn == NULL) || (TlsConn->Ssl == NULL)) {\r
264702a0
HW
420 return -1;\r
421 }\r
422\r
423 //\r
424 // Read bytes from the specified TLS connection.\r
425 //\r
7c342378 426 return SSL_read (TlsConn->Ssl, Buffer, (UINT32)BufferSize);\r
264702a0
HW
427}\r
428\r
429/**\r
430 Attempts to write data to a TLS connection.\r
431\r
432 This function tries to write BufferSize bytes data from the Buffer into the\r
433 specified TLS connection.\r
434\r
435 @param[in] Tls Pointer to the TLS connection for data writing.\r
436 @param[in] Buffer Pointer to the data buffer.\r
437 @param[in] BufferSize The size of Buffer in bytes.\r
438\r
439 @retval >0 The write operation was successful, and return value is the\r
440 number of bytes actually written to the TLS connection.\r
441 @retval <=0 The write operation was not successful.\r
442\r
443**/\r
444INTN\r
445EFIAPI\r
446TlsWrite (\r
7c342378
MK
447 IN VOID *Tls,\r
448 IN VOID *Buffer,\r
449 IN UINTN BufferSize\r
264702a0
HW
450 )\r
451{\r
452 TLS_CONNECTION *TlsConn;\r
453\r
7c342378
MK
454 TlsConn = (TLS_CONNECTION *)Tls;\r
455 if ((TlsConn == NULL) || (TlsConn->Ssl == NULL)) {\r
264702a0
HW
456 return -1;\r
457 }\r
458\r
459 //\r
460 // Write bytes to the specified TLS connection.\r
461 //\r
7c342378 462 return SSL_write (TlsConn->Ssl, Buffer, (UINT32)BufferSize);\r
264702a0 463}\r