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