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