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