1 /** @file
2   Implementation of EFI TLS Protocol Interfaces.
3 
4   Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
5 
6   This program and the accompanying materials
7   are licensed and made available under the terms and conditions of the BSD License
8   which accompanies this distribution.  The full text of the license may be found at
9   http://opensource.org/licenses/bsd-license.php.
10 
11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include "TlsImpl.h"
17 
18 EFI_TLS_PROTOCOL  mTlsProtocol = {
19   TlsSetSessionData,
20   TlsGetSessionData,
21   TlsBuildResponsePacket,
22   TlsProcessPacket
23 };
24 
25 /**
26   Set TLS session data.
27 
28   The SetSessionData() function set data for a new TLS session. All session data should
29   be set before BuildResponsePacket() invoked.
30 
31   @param[in]  This                Pointer to the EFI_TLS_PROTOCOL instance.
32   @param[in]  DataType            TLS session data type.
33   @param[in]  Data                Pointer to session data.
34   @param[in]  DataSize            Total size of session data.
35 
36   @retval EFI_SUCCESS             The TLS session data is set successfully.
37   @retval EFI_INVALID_PARAMETER   One or more of the following conditions is TRUE:
38                                   This is NULL.
39                                   Data is NULL.
40                                   DataSize is 0.
41   @retval EFI_UNSUPPORTED         The DataType is unsupported.
42   @retval EFI_ACCESS_DENIED       If the DataType is one of below:
43                                   EfiTlsClientRandom
44                                   EfiTlsServerRandom
45                                   EfiTlsKeyMaterial
46   @retval EFI_NOT_READY           Current TLS session state is NOT
47                                   EfiTlsSessionStateNotStarted.
48   @retval EFI_OUT_OF_RESOURCES    Required system resources could not be allocated.
49 **/
50 EFI_STATUS
51 EFIAPI
TlsSetSessionData(IN EFI_TLS_PROTOCOL * This,IN EFI_TLS_SESSION_DATA_TYPE DataType,IN VOID * Data,IN UINTN DataSize)52 TlsSetSessionData (
53   IN     EFI_TLS_PROTOCOL              *This,
54   IN     EFI_TLS_SESSION_DATA_TYPE     DataType,
55   IN     VOID                          *Data,
56   IN     UINTN                         DataSize
57   )
58 {
59   EFI_STATUS                Status;
60   TLS_INSTANCE              *Instance;
61   UINT16                    *CipherId;
62   UINTN                     Index;
63 
64   EFI_TPL                   OldTpl;
65 
66   Status = EFI_SUCCESS;
67   CipherId = NULL;
68 
69   if (This == NULL || Data == NULL || DataSize == 0) {
70     return EFI_INVALID_PARAMETER;
71   }
72 
73   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
74 
75   Instance = TLS_INSTANCE_FROM_PROTOCOL (This);
76 
77   if (DataType != EfiTlsSessionState  && Instance->TlsSessionState != EfiTlsSessionNotStarted){
78     Status = EFI_NOT_READY;
79     goto ON_EXIT;
80   }
81 
82   switch (DataType) {
83   //
84   // Session Configuration
85   //
86   case EfiTlsVersion:
87     if (DataSize != sizeof (EFI_TLS_VERSION)) {
88       Status = EFI_INVALID_PARAMETER;
89       goto ON_EXIT;
90     }
91 
92     Status = TlsSetVersion (Instance->TlsConn, ((EFI_TLS_VERSION *) Data)->Major, ((EFI_TLS_VERSION *) Data)->Minor);
93     break;
94   case EfiTlsConnectionEnd:
95     if (DataSize != sizeof (EFI_TLS_CONNECTION_END)) {
96       Status = EFI_INVALID_PARAMETER;
97       goto ON_EXIT;
98     }
99 
100     Status = TlsSetConnectionEnd (Instance->TlsConn, *((EFI_TLS_CONNECTION_END *) Data));
101     break;
102   case EfiTlsCipherList:
103     CipherId = AllocatePool (DataSize);
104     if (CipherId == NULL) {
105       Status = EFI_OUT_OF_RESOURCES;
106       goto ON_EXIT;
107     }
108 
109     for (Index = 0; Index < DataSize / sizeof (EFI_TLS_CIPHER); Index++) {
110       *(CipherId +Index) = HTONS (*(((UINT16 *) Data) + Index));
111     }
112 
113     Status = TlsSetCipherList (Instance->TlsConn, CipherId, DataSize / sizeof (EFI_TLS_CIPHER));
114 
115     FreePool (CipherId);
116     break;
117   case EfiTlsCompressionMethod:
118     //
119     // TLS seems only define one CompressionMethod.null, which specifies that data exchanged via the
120     // record protocol will not be compressed.
121     // More information from OpenSSL: http://www.openssl.org/docs/manmaster/ssl/SSL_COMP_add_compression_method.html
122     // The TLS RFC does however not specify compression methods or their corresponding identifiers,
123     // so there is currently no compatible way to integrate compression with unknown peers.
124     // It is therefore currently not recommended to integrate compression into applications.
125     // Applications for non-public use may agree on certain compression methods.
126     // Using different compression methods with the same identifier will lead to connection failure.
127     //
128     for (Index = 0; Index < DataSize / sizeof (EFI_TLS_COMPRESSION); Index++) {
129       Status = TlsSetCompressionMethod (*((UINT8 *) Data + Index));
130       if (EFI_ERROR (Status)) {
131         break;
132       }
133     }
134 
135     break;
136   case EfiTlsExtensionData:
137     Status = EFI_UNSUPPORTED;
138     goto ON_EXIT;
139   case EfiTlsVerifyMethod:
140     if (DataSize != sizeof (EFI_TLS_VERIFY)) {
141       Status = EFI_INVALID_PARAMETER;
142       goto ON_EXIT;
143     }
144 
145     TlsSetVerify (Instance->TlsConn, *((UINT32 *) Data));
146     break;
147   case EfiTlsSessionID:
148     if (DataSize != sizeof (EFI_TLS_SESSION_ID)) {
149       Status = EFI_INVALID_PARAMETER;
150       goto ON_EXIT;
151     }
152 
153     Status = TlsSetSessionId (
154                Instance->TlsConn,
155                ((EFI_TLS_SESSION_ID *) Data)->Data,
156                ((EFI_TLS_SESSION_ID *) Data)->Length
157                );
158     break;
159   case EfiTlsSessionState:
160     if (DataSize != sizeof (EFI_TLS_SESSION_STATE)) {
161       Status = EFI_INVALID_PARAMETER;
162       goto ON_EXIT;
163     }
164 
165     Instance->TlsSessionState = *(EFI_TLS_SESSION_STATE *) Data;
166     break;
167   //
168   // Session information
169   //
170   case EfiTlsClientRandom:
171     Status = EFI_ACCESS_DENIED;
172     break;
173   case EfiTlsServerRandom:
174     Status = EFI_ACCESS_DENIED;
175     break;
176   case EfiTlsKeyMaterial:
177     Status = EFI_ACCESS_DENIED;
178     break;
179   //
180   // Unsupported type.
181   //
182   default:
183     Status = EFI_UNSUPPORTED;
184   }
185 
186 ON_EXIT:
187   gBS->RestoreTPL (OldTpl);
188   return Status;
189 }
190 
191 /**
192   Get TLS session data.
193 
194   The GetSessionData() function return the TLS session information.
195 
196   @param[in]       This           Pointer to the EFI_TLS_PROTOCOL instance.
197   @param[in]       DataType       TLS session data type.
198   @param[in, out]  Data           Pointer to session data.
199   @param[in, out]  DataSize       Total size of session data. On input, it means
200                                   the size of Data buffer. On output, it means the size
201                                   of copied Data buffer if EFI_SUCCESS, and means the
202                                   size of desired Data buffer if EFI_BUFFER_TOO_SMALL.
203 
204   @retval EFI_SUCCESS             The TLS session data is got successfully.
205   @retval EFI_INVALID_PARAMETER   One or more of the following conditions is TRUE:
206                                   This is NULL.
207                                   DataSize is NULL.
208                                   Data is NULL if *DataSize is not zero.
209   @retval EFI_UNSUPPORTED         The DataType is unsupported.
210   @retval EFI_NOT_FOUND           The TLS session data is not found.
211   @retval EFI_NOT_READY           The DataType is not ready in current session state.
212   @retval EFI_BUFFER_TOO_SMALL    The buffer is too small to hold the data.
213 **/
214 EFI_STATUS
215 EFIAPI
TlsGetSessionData(IN EFI_TLS_PROTOCOL * This,IN EFI_TLS_SESSION_DATA_TYPE DataType,IN OUT VOID * Data,OPTIONAL IN OUT UINTN * DataSize)216 TlsGetSessionData (
217   IN     EFI_TLS_PROTOCOL              *This,
218   IN     EFI_TLS_SESSION_DATA_TYPE     DataType,
219   IN OUT VOID                          *Data,  OPTIONAL
220   IN OUT UINTN                         *DataSize
221   )
222 {
223   EFI_STATUS                Status;
224   TLS_INSTANCE              *Instance;
225 
226   EFI_TPL                   OldTpl;
227 
228   Status = EFI_SUCCESS;
229 
230   if (This == NULL || DataSize == NULL || (Data == NULL && *DataSize != 0)) {
231     return EFI_INVALID_PARAMETER;
232   }
233 
234   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
235 
236   Instance = TLS_INSTANCE_FROM_PROTOCOL (This);
237 
238   if (Instance->TlsSessionState == EfiTlsSessionNotStarted &&
239     (DataType == EfiTlsSessionID || DataType == EfiTlsClientRandom ||
240     DataType == EfiTlsServerRandom || DataType == EfiTlsKeyMaterial)) {
241     Status = EFI_NOT_READY;
242     goto ON_EXIT;
243   }
244 
245   switch (DataType) {
246   case EfiTlsVersion:
247     if (*DataSize < sizeof (EFI_TLS_VERSION)) {
248       *DataSize = sizeof (EFI_TLS_VERSION);
249       Status = EFI_BUFFER_TOO_SMALL;
250       goto ON_EXIT;
251     }
252     *DataSize = sizeof (EFI_TLS_VERSION);
253     *((UINT16 *) Data) = HTONS (TlsGetVersion (Instance->TlsConn));
254     break;
255   case EfiTlsConnectionEnd:
256     if (*DataSize < sizeof (EFI_TLS_CONNECTION_END)) {
257       *DataSize = sizeof (EFI_TLS_CONNECTION_END);
258       Status = EFI_BUFFER_TOO_SMALL;
259       goto ON_EXIT;
260     }
261     *DataSize = sizeof (EFI_TLS_CONNECTION_END);
262     *((UINT8 *) Data) = TlsGetConnectionEnd (Instance->TlsConn);
263     break;
264   case EfiTlsCipherList:
265     //
266     // Get the current session cipher suite.
267     //
268     if (*DataSize < sizeof (EFI_TLS_CIPHER)) {
269       *DataSize = sizeof (EFI_TLS_CIPHER);
270       Status = EFI_BUFFER_TOO_SMALL;
271       goto ON_EXIT;
272     }
273     *DataSize = sizeof(EFI_TLS_CIPHER);
274     Status = TlsGetCurrentCipher (Instance->TlsConn, (UINT16 *) Data);
275     *((UINT16 *) Data) = HTONS (*((UINT16 *) Data));
276     break;
277   case EfiTlsCompressionMethod:
278     //
279     // Get the current session compression method.
280     //
281     if (*DataSize < sizeof (EFI_TLS_COMPRESSION)) {
282       *DataSize = sizeof (EFI_TLS_COMPRESSION);
283       Status = EFI_BUFFER_TOO_SMALL;
284       goto ON_EXIT;
285     }
286     *DataSize = sizeof (EFI_TLS_COMPRESSION);
287     Status = TlsGetCurrentCompressionId (Instance->TlsConn, (UINT8 *) Data);
288     break;
289   case EfiTlsExtensionData:
290     Status = EFI_UNSUPPORTED;
291     goto ON_EXIT;
292   case EfiTlsVerifyMethod:
293     if (*DataSize < sizeof (EFI_TLS_VERIFY)) {
294       *DataSize = sizeof (EFI_TLS_VERIFY);
295       Status = EFI_BUFFER_TOO_SMALL;
296       goto ON_EXIT;
297     }
298     *DataSize = sizeof (EFI_TLS_VERIFY);
299     *((UINT32 *) Data) = TlsGetVerify (Instance->TlsConn);
300     break;
301   case EfiTlsSessionID:
302     if (*DataSize < sizeof (EFI_TLS_SESSION_ID)) {
303       *DataSize = sizeof (EFI_TLS_SESSION_ID);
304       Status = EFI_BUFFER_TOO_SMALL;
305       goto ON_EXIT;
306     }
307     *DataSize = sizeof (EFI_TLS_SESSION_ID);
308     Status = TlsGetSessionId (
309                Instance->TlsConn,
310                ((EFI_TLS_SESSION_ID *) Data)->Data,
311                &(((EFI_TLS_SESSION_ID *) Data)->Length)
312                );
313     break;
314   case EfiTlsSessionState:
315     if (*DataSize < sizeof (EFI_TLS_SESSION_STATE)) {
316       *DataSize = sizeof (EFI_TLS_SESSION_STATE);
317       Status = EFI_BUFFER_TOO_SMALL;
318       goto ON_EXIT;
319     }
320     *DataSize = sizeof (EFI_TLS_SESSION_STATE);
321     CopyMem (Data, &Instance->TlsSessionState, *DataSize);
322     break;
323   case EfiTlsClientRandom:
324     if (*DataSize < sizeof (EFI_TLS_RANDOM)) {
325       *DataSize = sizeof (EFI_TLS_RANDOM);
326       Status = EFI_BUFFER_TOO_SMALL;
327       goto ON_EXIT;
328     }
329     *DataSize = sizeof (EFI_TLS_RANDOM);
330     TlsGetClientRandom (Instance->TlsConn, (UINT8 *) Data);
331     break;
332   case EfiTlsServerRandom:
333     if (*DataSize < sizeof (EFI_TLS_RANDOM)) {
334       *DataSize = sizeof (EFI_TLS_RANDOM);
335       Status = EFI_BUFFER_TOO_SMALL;
336       goto ON_EXIT;
337     }
338     *DataSize = sizeof (EFI_TLS_RANDOM);
339     TlsGetServerRandom (Instance->TlsConn, (UINT8 *) Data);
340     break;
341   case EfiTlsKeyMaterial:
342     if (*DataSize < sizeof (EFI_TLS_MASTER_SECRET)) {
343       *DataSize = sizeof (EFI_TLS_MASTER_SECRET);
344       Status = EFI_BUFFER_TOO_SMALL;
345       goto ON_EXIT;
346     }
347     *DataSize = sizeof (EFI_TLS_MASTER_SECRET);
348     Status = TlsGetKeyMaterial (Instance->TlsConn, (UINT8 *) Data);
349     break;
350   //
351   // Unsupported type.
352   //
353   default:
354     Status = EFI_UNSUPPORTED;
355   }
356 
357 ON_EXIT:
358   gBS->RestoreTPL (OldTpl);
359   return Status;
360 }
361 
362 /**
363   Build response packet according to TLS state machine. This function is only valid for
364   alert, handshake and change_cipher_spec content type.
365 
366   The BuildResponsePacket() function builds TLS response packet in response to the TLS
367   request packet specified by RequestBuffer and RequestSize. If RequestBuffer is NULL and
368   RequestSize is 0, and TLS session status is EfiTlsSessionNotStarted, the TLS session
369   will be initiated and the response packet needs to be ClientHello. If RequestBuffer is
370   NULL and RequestSize is 0, and TLS session status is EfiTlsSessionClosing, the TLS
371   session will be closed and response packet needs to be CloseNotify. If RequestBuffer is
372   NULL and RequestSize is 0, and TLS session status is EfiTlsSessionError, the TLS
373   session has errors and the response packet needs to be Alert message based on error
374   type.
375 
376   @param[in]       This           Pointer to the EFI_TLS_PROTOCOL instance.
377   @param[in]       RequestBuffer  Pointer to the most recently received TLS packet. NULL
378                                   means TLS need initiate the TLS session and response
379                                   packet need to be ClientHello.
380   @param[in]       RequestSize    Packet size in bytes for the most recently received TLS
381                                   packet. 0 is only valid when RequestBuffer is NULL.
382   @param[out]      Buffer         Pointer to the buffer to hold the built packet.
383   @param[in, out]  BufferSize     Pointer to the buffer size in bytes. On input, it is
384                                   the buffer size provided by the caller. On output, it
385                                   is the buffer size in fact needed to contain the
386                                   packet.
387 
388   @retval EFI_SUCCESS             The required TLS packet is built successfully.
389   @retval EFI_INVALID_PARAMETER   One or more of the following conditions is TRUE:
390                                   This is NULL.
391                                   RequestBuffer is NULL but RequestSize is NOT 0.
392                                   RequestSize is 0 but RequestBuffer is NOT NULL.
393                                   BufferSize is NULL.
394                                   Buffer is NULL if *BufferSize is not zero.
395   @retval EFI_BUFFER_TOO_SMALL    BufferSize is too small to hold the response packet.
396   @retval EFI_NOT_READY           Current TLS session state is NOT ready to build
397                                   ResponsePacket.
398   @retval EFI_ABORTED             Something wrong build response packet.
399 **/
400 EFI_STATUS
401 EFIAPI
TlsBuildResponsePacket(IN EFI_TLS_PROTOCOL * This,IN UINT8 * RequestBuffer,OPTIONAL IN UINTN RequestSize,OPTIONAL OUT UINT8 * Buffer,OPTIONAL IN OUT UINTN * BufferSize)402 TlsBuildResponsePacket (
403   IN     EFI_TLS_PROTOCOL              *This,
404   IN     UINT8                         *RequestBuffer, OPTIONAL
405   IN     UINTN                         RequestSize, OPTIONAL
406      OUT UINT8                         *Buffer, OPTIONAL
407   IN OUT UINTN                         *BufferSize
408   )
409 {
410   EFI_STATUS                Status;
411   TLS_INSTANCE              *Instance;
412   EFI_TPL                   OldTpl;
413 
414   Status = EFI_SUCCESS;
415 
416   if ((This == NULL) || (BufferSize == NULL) ||
417       (RequestBuffer == NULL && RequestSize != 0) ||
418       (RequestBuffer != NULL && RequestSize == 0) ||
419       (Buffer == NULL && *BufferSize !=0)) {
420     return EFI_INVALID_PARAMETER;
421   }
422 
423   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
424 
425   Instance = TLS_INSTANCE_FROM_PROTOCOL (This);
426 
427   if(RequestBuffer == NULL && RequestSize == 0) {
428     switch (Instance->TlsSessionState) {
429     case EfiTlsSessionNotStarted:
430       //
431       // ClientHello.
432       //
433       Status = TlsDoHandshake (
434                  Instance->TlsConn,
435                  NULL,
436                  0,
437                  Buffer,
438                  BufferSize
439                  );
440       if (EFI_ERROR (Status)) {
441         goto ON_EXIT;
442       }
443 
444       //
445       // *BufferSize should not be zero when ClientHello.
446       //
447       if (*BufferSize == 0) {
448         Status = EFI_ABORTED;
449         goto ON_EXIT;
450       }
451 
452       Instance->TlsSessionState = EfiTlsSessionHandShaking;
453 
454       break;
455     case EfiTlsSessionClosing:
456       //
457       // TLS session will be closed and response packet needs to be CloseNotify.
458       //
459       Status = TlsCloseNotify (
460                  Instance->TlsConn,
461                  Buffer,
462                  BufferSize
463                  );
464       if (EFI_ERROR (Status)) {
465         goto ON_EXIT;
466       }
467 
468       //
469       // *BufferSize should not be zero when build CloseNotify message.
470       //
471       if (*BufferSize == 0) {
472         Status = EFI_ABORTED;
473         goto ON_EXIT;
474       }
475 
476       break;
477     case EfiTlsSessionError:
478       //
479       // TLS session has errors and the response packet needs to be Alert
480       // message based on error type.
481       //
482       Status = TlsHandleAlert (
483                  Instance->TlsConn,
484                  NULL,
485                  0,
486                  Buffer,
487                  BufferSize
488                  );
489       if (EFI_ERROR (Status)) {
490         goto ON_EXIT;
491       }
492 
493       break;
494     default:
495       //
496       // Current TLS session state is NOT ready to build ResponsePacket.
497       //
498       Status = EFI_NOT_READY;
499     }
500   } else {
501     //
502     // 1. Received packet may have multiple TLS record messages.
503     // 2. One TLS record message may have multiple handshake protocol.
504     // 3. Some errors may be happened in handshake.
505     // TlsDoHandshake() can handle all of those cases.
506     //
507     if (TlsInHandshake (Instance->TlsConn)) {
508       Status = TlsDoHandshake (
509                  Instance->TlsConn,
510                  RequestBuffer,
511                  RequestSize,
512                  Buffer,
513                  BufferSize
514                  );
515       if (EFI_ERROR (Status)) {
516         goto ON_EXIT;
517       }
518 
519       if (!TlsInHandshake (Instance->TlsConn)) {
520         Instance->TlsSessionState = EfiTlsSessionDataTransferring;
521       }
522     } else {
523       //
524       // Must be alert message, Decrypt it and build the ResponsePacket.
525       //
526       ASSERT (((TLS_RECORD_HEADER *) RequestBuffer)->ContentType == TLS_CONTENT_TYPE_ALERT);
527 
528       Status = TlsHandleAlert (
529                  Instance->TlsConn,
530                  RequestBuffer,
531                  RequestSize,
532                  Buffer,
533                  BufferSize
534                  );
535       if (EFI_ERROR (Status)) {
536         if (Status != EFI_BUFFER_TOO_SMALL) {
537           Instance->TlsSessionState = EfiTlsSessionError;
538         }
539 
540         goto ON_EXIT;
541       }
542     }
543   }
544 
545 ON_EXIT:
546   gBS->RestoreTPL (OldTpl);
547   return Status;
548 }
549 
550 /**
551   Decrypt or encrypt TLS packet during session. This function is only valid after
552   session connected and for application_data content type.
553 
554   The ProcessPacket () function process each inbound or outbound TLS APP packet.
555 
556   @param[in]       This           Pointer to the EFI_TLS_PROTOCOL instance.
557   @param[in, out]  FragmentTable  Pointer to a list of fragment. The caller will take
558                                   responsible to handle the original FragmentTable while
559                                   it may be reallocated in TLS driver. If CryptMode is
560                                   EfiTlsEncrypt, on input these fragments contain the TLS
561                                   header and plain text TLS APP payload; on output these
562                                   fragments contain the TLS header and cipher text TLS
563                                   APP payload. If CryptMode is EfiTlsDecrypt, on input
564                                   these fragments contain the TLS header and cipher text
565                                   TLS APP payload; on output these fragments contain the
566                                   TLS header and plain text TLS APP payload.
567   @param[in]       FragmentCount  Number of fragment.
568   @param[in]       CryptMode      Crypt mode.
569 
570   @retval EFI_SUCCESS             The operation completed successfully.
571   @retval EFI_INVALID_PARAMETER   One or more of the following conditions is TRUE:
572                                   This is NULL.
573                                   FragmentTable is NULL.
574                                   FragmentCount is NULL.
575                                   CryptoMode is invalid.
576   @retval EFI_NOT_READY           Current TLS session state is NOT
577                                   EfiTlsSessionDataTransferring.
578   @retval EFI_ABORTED             Something wrong decryption the message. TLS session
579                                   status will become EfiTlsSessionError. The caller need
580                                   call BuildResponsePacket() to generate Error Alert
581                                   message and send it out.
582   @retval EFI_OUT_OF_RESOURCES    No enough resource to finish the operation.
583 **/
584 EFI_STATUS
585 EFIAPI
TlsProcessPacket(IN EFI_TLS_PROTOCOL * This,IN OUT EFI_TLS_FRAGMENT_DATA ** FragmentTable,IN UINT32 * FragmentCount,IN EFI_TLS_CRYPT_MODE CryptMode)586 TlsProcessPacket (
587   IN     EFI_TLS_PROTOCOL              *This,
588   IN OUT EFI_TLS_FRAGMENT_DATA         **FragmentTable,
589   IN     UINT32                        *FragmentCount,
590   IN     EFI_TLS_CRYPT_MODE            CryptMode
591   )
592 {
593   EFI_STATUS                Status;
594   TLS_INSTANCE              *Instance;
595 
596   EFI_TPL                   OldTpl;
597 
598   Status = EFI_SUCCESS;
599 
600   if (This == NULL || FragmentTable == NULL || FragmentCount == NULL) {
601     return EFI_INVALID_PARAMETER;
602   }
603 
604   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
605 
606   Instance = TLS_INSTANCE_FROM_PROTOCOL (This);
607 
608   if (Instance->TlsSessionState != EfiTlsSessionDataTransferring) {
609     Status = EFI_NOT_READY;
610     goto ON_EXIT;
611   }
612 
613   //
614   // Packet sent or received may have multiple TLS record messages (Application data type).
615   // So,on input these fragments contain the TLS header and TLS APP payload;
616   // on output these fragments also contain the TLS header and TLS APP payload.
617   //
618   switch (CryptMode) {
619   case EfiTlsEncrypt:
620     Status = TlsEncryptPacket (Instance, FragmentTable, FragmentCount);
621     break;
622   case EfiTlsDecrypt:
623     Status = TlsDecryptPacket (Instance, FragmentTable, FragmentCount);
624     break;
625   default:
626     return EFI_INVALID_PARAMETER;
627   }
628 
629 ON_EXIT:
630   gBS->RestoreTPL (OldTpl);
631   return Status;
632 }
633