2 Implementation of EFI TLS Protocol Interfaces.
4 Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
12 EFI_TLS_PROTOCOL mTlsProtocol
= {
15 TlsBuildResponsePacket
,
22 The SetSessionData() function set data for a new TLS session. All session data should
23 be set before BuildResponsePacket() invoked.
25 @param[in] This Pointer to the EFI_TLS_PROTOCOL instance.
26 @param[in] DataType TLS session data type.
27 @param[in] Data Pointer to session data.
28 @param[in] DataSize Total size of session data.
30 @retval EFI_SUCCESS The TLS session data is set successfully.
31 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
35 DataSize is invalid for DataType.
36 @retval EFI_UNSUPPORTED The DataType is unsupported.
37 @retval EFI_ACCESS_DENIED If the DataType is one of below:
41 @retval EFI_NOT_READY Current TLS session state is NOT
42 EfiTlsSessionStateNotStarted.
43 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
48 IN EFI_TLS_PROTOCOL
*This
,
49 IN EFI_TLS_SESSION_DATA_TYPE DataType
,
55 TLS_INSTANCE
*Instance
;
57 CONST EFI_TLS_CIPHER
*TlsCipherList
;
59 CONST EFI_TLS_VERIFY_HOST
*TlsVerifyHost
;
60 EFI_TLS_VERIFY VerifyMethod
;
61 UINTN VerifyMethodSize
;
68 VerifyMethodSize
= sizeof (EFI_TLS_VERIFY
);
70 if ((This
== NULL
) || (Data
== NULL
) || (DataSize
== 0)) {
71 return EFI_INVALID_PARAMETER
;
74 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
76 Instance
= TLS_INSTANCE_FROM_PROTOCOL (This
);
78 if ((DataType
!= EfiTlsSessionState
) && (Instance
->TlsSessionState
!= EfiTlsSessionNotStarted
)) {
79 Status
= EFI_NOT_READY
;
85 // Session Configuration
88 if (DataSize
!= sizeof (EFI_TLS_VERSION
)) {
89 Status
= EFI_INVALID_PARAMETER
;
93 Status
= TlsSetVersion (Instance
->TlsConn
, ((EFI_TLS_VERSION
*)Data
)->Major
, ((EFI_TLS_VERSION
*)Data
)->Minor
);
95 case EfiTlsConnectionEnd
:
96 if (DataSize
!= sizeof (EFI_TLS_CONNECTION_END
)) {
97 Status
= EFI_INVALID_PARAMETER
;
101 Status
= TlsSetConnectionEnd (Instance
->TlsConn
, *((EFI_TLS_CONNECTION_END
*)Data
));
103 case EfiTlsCipherList
:
104 if (DataSize
% sizeof (EFI_TLS_CIPHER
) != 0) {
105 Status
= EFI_INVALID_PARAMETER
;
109 CipherId
= AllocatePool (DataSize
);
110 if (CipherId
== NULL
) {
111 Status
= EFI_OUT_OF_RESOURCES
;
115 TlsCipherList
= (CONST EFI_TLS_CIPHER
*)Data
;
116 CipherCount
= DataSize
/ sizeof (EFI_TLS_CIPHER
);
117 for (Index
= 0; Index
< CipherCount
; Index
++) {
118 CipherId
[Index
] = ((TlsCipherList
[Index
].Data1
<< 8) |
119 TlsCipherList
[Index
].Data2
);
122 Status
= TlsSetCipherList (Instance
->TlsConn
, CipherId
, CipherCount
);
126 case EfiTlsCompressionMethod
:
128 // TLS seems only define one CompressionMethod.null, which specifies that data exchanged via the
129 // record protocol will not be compressed.
130 // More information from OpenSSL: http://www.openssl.org/docs/manmaster/ssl/SSL_COMP_add_compression_method.html
131 // The TLS RFC does however not specify compression methods or their corresponding identifiers,
132 // so there is currently no compatible way to integrate compression with unknown peers.
133 // It is therefore currently not recommended to integrate compression into applications.
134 // Applications for non-public use may agree on certain compression methods.
135 // Using different compression methods with the same identifier will lead to connection failure.
137 for (Index
= 0; Index
< DataSize
/ sizeof (EFI_TLS_COMPRESSION
); Index
++) {
138 Status
= TlsSetCompressionMethod (*((UINT8
*)Data
+ Index
));
139 if (EFI_ERROR (Status
)) {
145 case EfiTlsExtensionData
:
146 Status
= EFI_UNSUPPORTED
;
148 case EfiTlsVerifyMethod
:
149 if (DataSize
!= sizeof (EFI_TLS_VERIFY
)) {
150 Status
= EFI_INVALID_PARAMETER
;
154 TlsSetVerify (Instance
->TlsConn
, *((UINT32
*)Data
));
156 case EfiTlsVerifyHost
:
157 if (DataSize
!= sizeof (EFI_TLS_VERIFY_HOST
)) {
158 Status
= EFI_INVALID_PARAMETER
;
162 TlsVerifyHost
= (CONST EFI_TLS_VERIFY_HOST
*)Data
;
164 if (((TlsVerifyHost
->Flags
& EFI_TLS_VERIFY_FLAG_ALWAYS_CHECK_SUBJECT
) != 0) &&
165 ((TlsVerifyHost
->Flags
& EFI_TLS_VERIFY_FLAG_NEVER_CHECK_SUBJECT
) != 0))
167 Status
= EFI_INVALID_PARAMETER
;
171 if (((TlsVerifyHost
->Flags
& EFI_TLS_VERIFY_FLAG_NO_WILDCARDS
) != 0) &&
172 (((TlsVerifyHost
->Flags
& EFI_TLS_VERIFY_FLAG_NO_PARTIAL_WILDCARDS
) != 0) ||
173 ((TlsVerifyHost
->Flags
& EFI_TLS_VERIFY_FLAG_MULTI_LABEL_WILDCARDS
) != 0)))
175 Status
= EFI_INVALID_PARAMETER
;
179 Status
= This
->GetSessionData (This
, EfiTlsVerifyMethod
, &VerifyMethod
, &VerifyMethodSize
);
180 if (EFI_ERROR (Status
)) {
184 if ((VerifyMethod
& EFI_TLS_VERIFY_PEER
) == 0) {
185 Status
= EFI_INVALID_PARAMETER
;
189 Status
= TlsSetVerifyHost (Instance
->TlsConn
, TlsVerifyHost
->Flags
, TlsVerifyHost
->HostName
);
192 case EfiTlsSessionID
:
193 if (DataSize
!= sizeof (EFI_TLS_SESSION_ID
)) {
194 Status
= EFI_INVALID_PARAMETER
;
198 Status
= TlsSetSessionId (
200 ((EFI_TLS_SESSION_ID
*)Data
)->Data
,
201 ((EFI_TLS_SESSION_ID
*)Data
)->Length
204 case EfiTlsSessionState
:
205 if (DataSize
!= sizeof (EFI_TLS_SESSION_STATE
)) {
206 Status
= EFI_INVALID_PARAMETER
;
210 Instance
->TlsSessionState
= *(EFI_TLS_SESSION_STATE
*)Data
;
213 // Session information
215 case EfiTlsClientRandom
:
216 Status
= EFI_ACCESS_DENIED
;
218 case EfiTlsServerRandom
:
219 Status
= EFI_ACCESS_DENIED
;
221 case EfiTlsKeyMaterial
:
222 Status
= EFI_ACCESS_DENIED
;
228 Status
= EFI_UNSUPPORTED
;
232 gBS
->RestoreTPL (OldTpl
);
237 Get TLS session data.
239 The GetSessionData() function return the TLS session information.
241 @param[in] This Pointer to the EFI_TLS_PROTOCOL instance.
242 @param[in] DataType TLS session data type.
243 @param[in, out] Data Pointer to session data.
244 @param[in, out] DataSize Total size of session data. On input, it means
245 the size of Data buffer. On output, it means the size
246 of copied Data buffer if EFI_SUCCESS, and means the
247 size of desired Data buffer if EFI_BUFFER_TOO_SMALL.
249 @retval EFI_SUCCESS The TLS session data is got successfully.
250 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
253 Data is NULL if *DataSize is not zero.
254 @retval EFI_UNSUPPORTED The DataType is unsupported.
255 @retval EFI_NOT_FOUND The TLS session data is not found.
256 @retval EFI_NOT_READY The DataType is not ready in current session state.
257 @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold the data.
262 IN EFI_TLS_PROTOCOL
*This
,
263 IN EFI_TLS_SESSION_DATA_TYPE DataType
,
264 IN OUT VOID
*Data OPTIONAL
,
265 IN OUT UINTN
*DataSize
269 TLS_INSTANCE
*Instance
;
273 Status
= EFI_SUCCESS
;
275 if ((This
== NULL
) || (DataSize
== NULL
) || ((Data
== NULL
) && (*DataSize
!= 0))) {
276 return EFI_INVALID_PARAMETER
;
279 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
281 Instance
= TLS_INSTANCE_FROM_PROTOCOL (This
);
283 if ((Instance
->TlsSessionState
== EfiTlsSessionNotStarted
) &&
284 ((DataType
== EfiTlsSessionID
) || (DataType
== EfiTlsClientRandom
) ||
285 (DataType
== EfiTlsServerRandom
) || (DataType
== EfiTlsKeyMaterial
)))
287 Status
= EFI_NOT_READY
;
293 if (*DataSize
< sizeof (EFI_TLS_VERSION
)) {
294 *DataSize
= sizeof (EFI_TLS_VERSION
);
295 Status
= EFI_BUFFER_TOO_SMALL
;
299 *DataSize
= sizeof (EFI_TLS_VERSION
);
300 *((UINT16
*)Data
) = HTONS (TlsGetVersion (Instance
->TlsConn
));
302 case EfiTlsConnectionEnd
:
303 if (*DataSize
< sizeof (EFI_TLS_CONNECTION_END
)) {
304 *DataSize
= sizeof (EFI_TLS_CONNECTION_END
);
305 Status
= EFI_BUFFER_TOO_SMALL
;
309 *DataSize
= sizeof (EFI_TLS_CONNECTION_END
);
310 *((UINT8
*)Data
) = TlsGetConnectionEnd (Instance
->TlsConn
);
312 case EfiTlsCipherList
:
314 // Get the current session cipher suite.
316 if (*DataSize
< sizeof (EFI_TLS_CIPHER
)) {
317 *DataSize
= sizeof (EFI_TLS_CIPHER
);
318 Status
= EFI_BUFFER_TOO_SMALL
;
322 *DataSize
= sizeof (EFI_TLS_CIPHER
);
323 Status
= TlsGetCurrentCipher (Instance
->TlsConn
, (UINT16
*)Data
);
324 *((UINT16
*)Data
) = HTONS (*((UINT16
*)Data
));
326 case EfiTlsCompressionMethod
:
328 // Get the current session compression method.
330 if (*DataSize
< sizeof (EFI_TLS_COMPRESSION
)) {
331 *DataSize
= sizeof (EFI_TLS_COMPRESSION
);
332 Status
= EFI_BUFFER_TOO_SMALL
;
336 *DataSize
= sizeof (EFI_TLS_COMPRESSION
);
337 Status
= TlsGetCurrentCompressionId (Instance
->TlsConn
, (UINT8
*)Data
);
339 case EfiTlsExtensionData
:
340 Status
= EFI_UNSUPPORTED
;
342 case EfiTlsVerifyMethod
:
343 if (*DataSize
< sizeof (EFI_TLS_VERIFY
)) {
344 *DataSize
= sizeof (EFI_TLS_VERIFY
);
345 Status
= EFI_BUFFER_TOO_SMALL
;
349 *DataSize
= sizeof (EFI_TLS_VERIFY
);
350 *((UINT32
*)Data
) = TlsGetVerify (Instance
->TlsConn
);
352 case EfiTlsSessionID
:
353 if (*DataSize
< sizeof (EFI_TLS_SESSION_ID
)) {
354 *DataSize
= sizeof (EFI_TLS_SESSION_ID
);
355 Status
= EFI_BUFFER_TOO_SMALL
;
359 *DataSize
= sizeof (EFI_TLS_SESSION_ID
);
360 Status
= TlsGetSessionId (
362 ((EFI_TLS_SESSION_ID
*)Data
)->Data
,
363 &(((EFI_TLS_SESSION_ID
*)Data
)->Length
)
366 case EfiTlsSessionState
:
367 if (*DataSize
< sizeof (EFI_TLS_SESSION_STATE
)) {
368 *DataSize
= sizeof (EFI_TLS_SESSION_STATE
);
369 Status
= EFI_BUFFER_TOO_SMALL
;
373 *DataSize
= sizeof (EFI_TLS_SESSION_STATE
);
374 CopyMem (Data
, &Instance
->TlsSessionState
, *DataSize
);
376 case EfiTlsClientRandom
:
377 if (*DataSize
< sizeof (EFI_TLS_RANDOM
)) {
378 *DataSize
= sizeof (EFI_TLS_RANDOM
);
379 Status
= EFI_BUFFER_TOO_SMALL
;
383 *DataSize
= sizeof (EFI_TLS_RANDOM
);
384 TlsGetClientRandom (Instance
->TlsConn
, (UINT8
*)Data
);
386 case EfiTlsServerRandom
:
387 if (*DataSize
< sizeof (EFI_TLS_RANDOM
)) {
388 *DataSize
= sizeof (EFI_TLS_RANDOM
);
389 Status
= EFI_BUFFER_TOO_SMALL
;
393 *DataSize
= sizeof (EFI_TLS_RANDOM
);
394 TlsGetServerRandom (Instance
->TlsConn
, (UINT8
*)Data
);
396 case EfiTlsKeyMaterial
:
397 if (*DataSize
< sizeof (EFI_TLS_MASTER_SECRET
)) {
398 *DataSize
= sizeof (EFI_TLS_MASTER_SECRET
);
399 Status
= EFI_BUFFER_TOO_SMALL
;
403 *DataSize
= sizeof (EFI_TLS_MASTER_SECRET
);
404 Status
= TlsGetKeyMaterial (Instance
->TlsConn
, (UINT8
*)Data
);
410 Status
= EFI_UNSUPPORTED
;
414 gBS
->RestoreTPL (OldTpl
);
419 Build response packet according to TLS state machine. This function is only valid for
420 alert, handshake and change_cipher_spec content type.
422 The BuildResponsePacket() function builds TLS response packet in response to the TLS
423 request packet specified by RequestBuffer and RequestSize. If RequestBuffer is NULL and
424 RequestSize is 0, and TLS session status is EfiTlsSessionNotStarted, the TLS session
425 will be initiated and the response packet needs to be ClientHello. If RequestBuffer is
426 NULL and RequestSize is 0, and TLS session status is EfiTlsSessionClosing, the TLS
427 session will be closed and response packet needs to be CloseNotify. If RequestBuffer is
428 NULL and RequestSize is 0, and TLS session status is EfiTlsSessionError, the TLS
429 session has errors and the response packet needs to be Alert message based on error
432 @param[in] This Pointer to the EFI_TLS_PROTOCOL instance.
433 @param[in] RequestBuffer Pointer to the most recently received TLS packet. NULL
434 means TLS need initiate the TLS session and response
435 packet need to be ClientHello.
436 @param[in] RequestSize Packet size in bytes for the most recently received TLS
437 packet. 0 is only valid when RequestBuffer is NULL.
438 @param[out] Buffer Pointer to the buffer to hold the built packet.
439 @param[in, out] BufferSize Pointer to the buffer size in bytes. On input, it is
440 the buffer size provided by the caller. On output, it
441 is the buffer size in fact needed to contain the
444 @retval EFI_SUCCESS The required TLS packet is built successfully.
445 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
447 RequestBuffer is NULL but RequestSize is NOT 0.
448 RequestSize is 0 but RequestBuffer is NOT NULL.
450 Buffer is NULL if *BufferSize is not zero.
451 @retval EFI_BUFFER_TOO_SMALL BufferSize is too small to hold the response packet.
452 @retval EFI_NOT_READY Current TLS session state is NOT ready to build
454 @retval EFI_ABORTED Something wrong build response packet.
458 TlsBuildResponsePacket (
459 IN EFI_TLS_PROTOCOL
*This
,
460 IN UINT8
*RequestBuffer OPTIONAL
,
461 IN UINTN RequestSize OPTIONAL
,
462 OUT UINT8
*Buffer OPTIONAL
,
463 IN OUT UINTN
*BufferSize
467 TLS_INSTANCE
*Instance
;
470 Status
= EFI_SUCCESS
;
472 if ((This
== NULL
) || (BufferSize
== NULL
) ||
473 ((RequestBuffer
== NULL
) && (RequestSize
!= 0)) ||
474 ((RequestBuffer
!= NULL
) && (RequestSize
== 0)) ||
475 ((Buffer
== NULL
) && (*BufferSize
!= 0)))
477 return EFI_INVALID_PARAMETER
;
480 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
482 Instance
= TLS_INSTANCE_FROM_PROTOCOL (This
);
484 if ((RequestBuffer
== NULL
) && (RequestSize
== 0)) {
485 switch (Instance
->TlsSessionState
) {
486 case EfiTlsSessionNotStarted
:
490 Status
= TlsDoHandshake (
497 if (EFI_ERROR (Status
)) {
502 // *BufferSize should not be zero when ClientHello.
504 if (*BufferSize
== 0) {
505 Status
= EFI_ABORTED
;
509 Instance
->TlsSessionState
= EfiTlsSessionHandShaking
;
512 case EfiTlsSessionClosing
:
514 // TLS session will be closed and response packet needs to be CloseNotify.
516 Status
= TlsCloseNotify (
521 if (EFI_ERROR (Status
)) {
526 // *BufferSize should not be zero when build CloseNotify message.
528 if (*BufferSize
== 0) {
529 Status
= EFI_ABORTED
;
534 case EfiTlsSessionError
:
536 // TLS session has errors and the response packet needs to be Alert
537 // message based on error type.
539 Status
= TlsHandleAlert (
546 if (EFI_ERROR (Status
)) {
553 // Current TLS session state is NOT ready to build ResponsePacket.
555 Status
= EFI_NOT_READY
;
559 // 1. Received packet may have multiple TLS record messages.
560 // 2. One TLS record message may have multiple handshake protocol.
561 // 3. Some errors may be happened in handshake.
562 // TlsDoHandshake() can handle all of those cases.
564 if (TlsInHandshake (Instance
->TlsConn
)) {
565 Status
= TlsDoHandshake (
572 if (EFI_ERROR (Status
)) {
576 if (!TlsInHandshake (Instance
->TlsConn
)) {
577 Instance
->TlsSessionState
= EfiTlsSessionDataTransferring
;
581 // Must be alert message, Decrypt it and build the ResponsePacket.
583 ASSERT (((TLS_RECORD_HEADER
*)RequestBuffer
)->ContentType
== TlsContentTypeAlert
);
585 Status
= TlsHandleAlert (
592 if (EFI_ERROR (Status
)) {
593 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
594 Instance
->TlsSessionState
= EfiTlsSessionError
;
603 gBS
->RestoreTPL (OldTpl
);
608 Decrypt or encrypt TLS packet during session. This function is only valid after
609 session connected and for application_data content type.
611 The ProcessPacket () function process each inbound or outbound TLS APP packet.
613 @param[in] This Pointer to the EFI_TLS_PROTOCOL instance.
614 @param[in, out] FragmentTable Pointer to a list of fragment. The caller will take
615 responsible to handle the original FragmentTable while
616 it may be reallocated in TLS driver. If CryptMode is
617 EfiTlsEncrypt, on input these fragments contain the TLS
618 header and plain text TLS APP payload; on output these
619 fragments contain the TLS header and cipher text TLS
620 APP payload. If CryptMode is EfiTlsDecrypt, on input
621 these fragments contain the TLS header and cipher text
622 TLS APP payload; on output these fragments contain the
623 TLS header and plain text TLS APP payload.
624 @param[in] FragmentCount Number of fragment.
625 @param[in] CryptMode Crypt mode.
627 @retval EFI_SUCCESS The operation completed successfully.
628 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
630 FragmentTable is NULL.
631 FragmentCount is NULL.
632 CryptoMode is invalid.
633 @retval EFI_NOT_READY Current TLS session state is NOT
634 EfiTlsSessionDataTransferring.
635 @retval EFI_ABORTED Something wrong decryption the message. TLS session
636 status will become EfiTlsSessionError. The caller need
637 call BuildResponsePacket() to generate Error Alert
638 message and send it out.
639 @retval EFI_OUT_OF_RESOURCES No enough resource to finish the operation.
644 IN EFI_TLS_PROTOCOL
*This
,
645 IN OUT EFI_TLS_FRAGMENT_DATA
**FragmentTable
,
646 IN UINT32
*FragmentCount
,
647 IN EFI_TLS_CRYPT_MODE CryptMode
651 TLS_INSTANCE
*Instance
;
655 Status
= EFI_SUCCESS
;
657 if ((This
== NULL
) || (FragmentTable
== NULL
) || (FragmentCount
== NULL
)) {
658 return EFI_INVALID_PARAMETER
;
661 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
663 Instance
= TLS_INSTANCE_FROM_PROTOCOL (This
);
665 if (Instance
->TlsSessionState
!= EfiTlsSessionDataTransferring
) {
666 Status
= EFI_NOT_READY
;
671 // Packet sent or received may have multiple TLS record messages (Application data type).
672 // So,on input these fragments contain the TLS header and TLS APP payload;
673 // on output these fragments also contain the TLS header and TLS APP payload.
677 Status
= TlsEncryptPacket (Instance
, FragmentTable
, FragmentCount
);
680 Status
= TlsDecryptPacket (Instance
, FragmentTable
, FragmentCount
);
683 return EFI_INVALID_PARAMETER
;
687 gBS
->RestoreTPL (OldTpl
);