1 /** @file
2 SSL/TLS Process Library Wrapper Implementation over OpenSSL.
3 The process includes the TLS handshake and packet I/O.
4
5 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
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
TlsInHandshake(IN VOID * Tls)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
TlsDoHandshake(IN VOID * Tls,IN UINT8 * BufferIn,OPTIONAL IN UINTN BufferInSize,OPTIONAL OUT UINT8 * BufferOut,OPTIONAL IN OUT UINTN * BufferOutSize)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;
90 unsigned long ErrorCode;
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
TlsHandleAlert(IN VOID * Tls,IN UINT8 * BufferIn,OPTIONAL IN UINTN BufferInSize,OPTIONAL OUT UINT8 * BufferOut,OPTIONAL IN OUT UINTN * BufferOutSize)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
TlsCloseNotify(IN VOID * Tls,IN OUT UINT8 * Buffer,IN OUT UINTN * BufferSize)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
TlsCtrlTrafficOut(IN VOID * Tls,IN OUT VOID * Buffer,IN UINTN BufferSize)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
TlsCtrlTrafficIn(IN VOID * Tls,IN VOID * Buffer,IN UINTN BufferSize)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
TlsRead(IN VOID * Tls,IN OUT VOID * Buffer,IN UINTN BufferSize)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
TlsWrite(IN VOID * Tls,IN VOID * Buffer,IN UINTN BufferSize)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 }
463