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) {
166 Status
= EFI_INVALID_PARAMETER
;
170 if ((TlsVerifyHost
->Flags
& EFI_TLS_VERIFY_FLAG_NO_WILDCARDS
) != 0 &&
171 ((TlsVerifyHost
->Flags
& EFI_TLS_VERIFY_FLAG_NO_PARTIAL_WILDCARDS
) != 0 ||
172 (TlsVerifyHost
->Flags
& EFI_TLS_VERIFY_FLAG_MULTI_LABEL_WILDCARDS
) != 0)) {
173 Status
= EFI_INVALID_PARAMETER
;
177 Status
= This
->GetSessionData (This
, EfiTlsVerifyMethod
, &VerifyMethod
, &VerifyMethodSize
);
178 if (EFI_ERROR (Status
)) {
182 if ((VerifyMethod
& EFI_TLS_VERIFY_PEER
) == 0) {
183 Status
= EFI_INVALID_PARAMETER
;
187 Status
= TlsSetVerifyHost (Instance
->TlsConn
, TlsVerifyHost
->Flags
, TlsVerifyHost
->HostName
);
190 case EfiTlsSessionID
:
191 if (DataSize
!= sizeof (EFI_TLS_SESSION_ID
)) {
192 Status
= EFI_INVALID_PARAMETER
;
196 Status
= TlsSetSessionId (
198 ((EFI_TLS_SESSION_ID
*) Data
)->Data
,
199 ((EFI_TLS_SESSION_ID
*) Data
)->Length
202 case EfiTlsSessionState
:
203 if (DataSize
!= sizeof (EFI_TLS_SESSION_STATE
)) {
204 Status
= EFI_INVALID_PARAMETER
;
208 Instance
->TlsSessionState
= *(EFI_TLS_SESSION_STATE
*) Data
;
211 // Session information
213 case EfiTlsClientRandom
:
214 Status
= EFI_ACCESS_DENIED
;
216 case EfiTlsServerRandom
:
217 Status
= EFI_ACCESS_DENIED
;
219 case EfiTlsKeyMaterial
:
220 Status
= EFI_ACCESS_DENIED
;
226 Status
= EFI_UNSUPPORTED
;
230 gBS
->RestoreTPL (OldTpl
);
235 Get TLS session data.
237 The GetSessionData() function return the TLS session information.
239 @param[in] This Pointer to the EFI_TLS_PROTOCOL instance.
240 @param[in] DataType TLS session data type.
241 @param[in, out] Data Pointer to session data.
242 @param[in, out] DataSize Total size of session data. On input, it means
243 the size of Data buffer. On output, it means the size
244 of copied Data buffer if EFI_SUCCESS, and means the
245 size of desired Data buffer if EFI_BUFFER_TOO_SMALL.
247 @retval EFI_SUCCESS The TLS session data is got successfully.
248 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
251 Data is NULL if *DataSize is not zero.
252 @retval EFI_UNSUPPORTED The DataType is unsupported.
253 @retval EFI_NOT_FOUND The TLS session data is not found.
254 @retval EFI_NOT_READY The DataType is not ready in current session state.
255 @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold the data.
260 IN EFI_TLS_PROTOCOL
*This
,
261 IN EFI_TLS_SESSION_DATA_TYPE DataType
,
262 IN OUT VOID
*Data OPTIONAL
,
263 IN OUT UINTN
*DataSize
267 TLS_INSTANCE
*Instance
;
271 Status
= EFI_SUCCESS
;
273 if (This
== NULL
|| DataSize
== NULL
|| (Data
== NULL
&& *DataSize
!= 0)) {
274 return EFI_INVALID_PARAMETER
;
277 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
279 Instance
= TLS_INSTANCE_FROM_PROTOCOL (This
);
281 if (Instance
->TlsSessionState
== EfiTlsSessionNotStarted
&&
282 (DataType
== EfiTlsSessionID
|| DataType
== EfiTlsClientRandom
||
283 DataType
== EfiTlsServerRandom
|| DataType
== EfiTlsKeyMaterial
)) {
284 Status
= EFI_NOT_READY
;
290 if (*DataSize
< sizeof (EFI_TLS_VERSION
)) {
291 *DataSize
= sizeof (EFI_TLS_VERSION
);
292 Status
= EFI_BUFFER_TOO_SMALL
;
295 *DataSize
= sizeof (EFI_TLS_VERSION
);
296 *((UINT16
*) Data
) = HTONS (TlsGetVersion (Instance
->TlsConn
));
298 case EfiTlsConnectionEnd
:
299 if (*DataSize
< sizeof (EFI_TLS_CONNECTION_END
)) {
300 *DataSize
= sizeof (EFI_TLS_CONNECTION_END
);
301 Status
= EFI_BUFFER_TOO_SMALL
;
304 *DataSize
= sizeof (EFI_TLS_CONNECTION_END
);
305 *((UINT8
*) Data
) = TlsGetConnectionEnd (Instance
->TlsConn
);
307 case EfiTlsCipherList
:
309 // Get the current session cipher suite.
311 if (*DataSize
< sizeof (EFI_TLS_CIPHER
)) {
312 *DataSize
= sizeof (EFI_TLS_CIPHER
);
313 Status
= EFI_BUFFER_TOO_SMALL
;
316 *DataSize
= sizeof(EFI_TLS_CIPHER
);
317 Status
= TlsGetCurrentCipher (Instance
->TlsConn
, (UINT16
*) Data
);
318 *((UINT16
*) Data
) = HTONS (*((UINT16
*) Data
));
320 case EfiTlsCompressionMethod
:
322 // Get the current session compression method.
324 if (*DataSize
< sizeof (EFI_TLS_COMPRESSION
)) {
325 *DataSize
= sizeof (EFI_TLS_COMPRESSION
);
326 Status
= EFI_BUFFER_TOO_SMALL
;
329 *DataSize
= sizeof (EFI_TLS_COMPRESSION
);
330 Status
= TlsGetCurrentCompressionId (Instance
->TlsConn
, (UINT8
*) Data
);
332 case EfiTlsExtensionData
:
333 Status
= EFI_UNSUPPORTED
;
335 case EfiTlsVerifyMethod
:
336 if (*DataSize
< sizeof (EFI_TLS_VERIFY
)) {
337 *DataSize
= sizeof (EFI_TLS_VERIFY
);
338 Status
= EFI_BUFFER_TOO_SMALL
;
341 *DataSize
= sizeof (EFI_TLS_VERIFY
);
342 *((UINT32
*) Data
) = TlsGetVerify (Instance
->TlsConn
);
344 case EfiTlsSessionID
:
345 if (*DataSize
< sizeof (EFI_TLS_SESSION_ID
)) {
346 *DataSize
= sizeof (EFI_TLS_SESSION_ID
);
347 Status
= EFI_BUFFER_TOO_SMALL
;
350 *DataSize
= sizeof (EFI_TLS_SESSION_ID
);
351 Status
= TlsGetSessionId (
353 ((EFI_TLS_SESSION_ID
*) Data
)->Data
,
354 &(((EFI_TLS_SESSION_ID
*) Data
)->Length
)
357 case EfiTlsSessionState
:
358 if (*DataSize
< sizeof (EFI_TLS_SESSION_STATE
)) {
359 *DataSize
= sizeof (EFI_TLS_SESSION_STATE
);
360 Status
= EFI_BUFFER_TOO_SMALL
;
363 *DataSize
= sizeof (EFI_TLS_SESSION_STATE
);
364 CopyMem (Data
, &Instance
->TlsSessionState
, *DataSize
);
366 case EfiTlsClientRandom
:
367 if (*DataSize
< sizeof (EFI_TLS_RANDOM
)) {
368 *DataSize
= sizeof (EFI_TLS_RANDOM
);
369 Status
= EFI_BUFFER_TOO_SMALL
;
372 *DataSize
= sizeof (EFI_TLS_RANDOM
);
373 TlsGetClientRandom (Instance
->TlsConn
, (UINT8
*) Data
);
375 case EfiTlsServerRandom
:
376 if (*DataSize
< sizeof (EFI_TLS_RANDOM
)) {
377 *DataSize
= sizeof (EFI_TLS_RANDOM
);
378 Status
= EFI_BUFFER_TOO_SMALL
;
381 *DataSize
= sizeof (EFI_TLS_RANDOM
);
382 TlsGetServerRandom (Instance
->TlsConn
, (UINT8
*) Data
);
384 case EfiTlsKeyMaterial
:
385 if (*DataSize
< sizeof (EFI_TLS_MASTER_SECRET
)) {
386 *DataSize
= sizeof (EFI_TLS_MASTER_SECRET
);
387 Status
= EFI_BUFFER_TOO_SMALL
;
390 *DataSize
= sizeof (EFI_TLS_MASTER_SECRET
);
391 Status
= TlsGetKeyMaterial (Instance
->TlsConn
, (UINT8
*) Data
);
397 Status
= EFI_UNSUPPORTED
;
401 gBS
->RestoreTPL (OldTpl
);
406 Build response packet according to TLS state machine. This function is only valid for
407 alert, handshake and change_cipher_spec content type.
409 The BuildResponsePacket() function builds TLS response packet in response to the TLS
410 request packet specified by RequestBuffer and RequestSize. If RequestBuffer is NULL and
411 RequestSize is 0, and TLS session status is EfiTlsSessionNotStarted, the TLS session
412 will be initiated and the response packet needs to be ClientHello. If RequestBuffer is
413 NULL and RequestSize is 0, and TLS session status is EfiTlsSessionClosing, the TLS
414 session will be closed and response packet needs to be CloseNotify. If RequestBuffer is
415 NULL and RequestSize is 0, and TLS session status is EfiTlsSessionError, the TLS
416 session has errors and the response packet needs to be Alert message based on error
419 @param[in] This Pointer to the EFI_TLS_PROTOCOL instance.
420 @param[in] RequestBuffer Pointer to the most recently received TLS packet. NULL
421 means TLS need initiate the TLS session and response
422 packet need to be ClientHello.
423 @param[in] RequestSize Packet size in bytes for the most recently received TLS
424 packet. 0 is only valid when RequestBuffer is NULL.
425 @param[out] Buffer Pointer to the buffer to hold the built packet.
426 @param[in, out] BufferSize Pointer to the buffer size in bytes. On input, it is
427 the buffer size provided by the caller. On output, it
428 is the buffer size in fact needed to contain the
431 @retval EFI_SUCCESS The required TLS packet is built successfully.
432 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
434 RequestBuffer is NULL but RequestSize is NOT 0.
435 RequestSize is 0 but RequestBuffer is NOT NULL.
437 Buffer is NULL if *BufferSize is not zero.
438 @retval EFI_BUFFER_TOO_SMALL BufferSize is too small to hold the response packet.
439 @retval EFI_NOT_READY Current TLS session state is NOT ready to build
441 @retval EFI_ABORTED Something wrong build response packet.
445 TlsBuildResponsePacket (
446 IN EFI_TLS_PROTOCOL
*This
,
447 IN UINT8
*RequestBuffer OPTIONAL
,
448 IN UINTN RequestSize OPTIONAL
,
449 OUT UINT8
*Buffer OPTIONAL
,
450 IN OUT UINTN
*BufferSize
454 TLS_INSTANCE
*Instance
;
457 Status
= EFI_SUCCESS
;
459 if ((This
== NULL
) || (BufferSize
== NULL
) ||
460 (RequestBuffer
== NULL
&& RequestSize
!= 0) ||
461 (RequestBuffer
!= NULL
&& RequestSize
== 0) ||
462 (Buffer
== NULL
&& *BufferSize
!=0)) {
463 return EFI_INVALID_PARAMETER
;
466 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
468 Instance
= TLS_INSTANCE_FROM_PROTOCOL (This
);
470 if(RequestBuffer
== NULL
&& RequestSize
== 0) {
471 switch (Instance
->TlsSessionState
) {
472 case EfiTlsSessionNotStarted
:
476 Status
= TlsDoHandshake (
483 if (EFI_ERROR (Status
)) {
488 // *BufferSize should not be zero when ClientHello.
490 if (*BufferSize
== 0) {
491 Status
= EFI_ABORTED
;
495 Instance
->TlsSessionState
= EfiTlsSessionHandShaking
;
498 case EfiTlsSessionClosing
:
500 // TLS session will be closed and response packet needs to be CloseNotify.
502 Status
= TlsCloseNotify (
507 if (EFI_ERROR (Status
)) {
512 // *BufferSize should not be zero when build CloseNotify message.
514 if (*BufferSize
== 0) {
515 Status
= EFI_ABORTED
;
520 case EfiTlsSessionError
:
522 // TLS session has errors and the response packet needs to be Alert
523 // message based on error type.
525 Status
= TlsHandleAlert (
532 if (EFI_ERROR (Status
)) {
539 // Current TLS session state is NOT ready to build ResponsePacket.
541 Status
= EFI_NOT_READY
;
545 // 1. Received packet may have multiple TLS record messages.
546 // 2. One TLS record message may have multiple handshake protocol.
547 // 3. Some errors may be happened in handshake.
548 // TlsDoHandshake() can handle all of those cases.
550 if (TlsInHandshake (Instance
->TlsConn
)) {
551 Status
= TlsDoHandshake (
558 if (EFI_ERROR (Status
)) {
562 if (!TlsInHandshake (Instance
->TlsConn
)) {
563 Instance
->TlsSessionState
= EfiTlsSessionDataTransferring
;
567 // Must be alert message, Decrypt it and build the ResponsePacket.
569 ASSERT (((TLS_RECORD_HEADER
*) RequestBuffer
)->ContentType
== TlsContentTypeAlert
);
571 Status
= TlsHandleAlert (
578 if (EFI_ERROR (Status
)) {
579 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
580 Instance
->TlsSessionState
= EfiTlsSessionError
;
589 gBS
->RestoreTPL (OldTpl
);
594 Decrypt or encrypt TLS packet during session. This function is only valid after
595 session connected and for application_data content type.
597 The ProcessPacket () function process each inbound or outbound TLS APP packet.
599 @param[in] This Pointer to the EFI_TLS_PROTOCOL instance.
600 @param[in, out] FragmentTable Pointer to a list of fragment. The caller will take
601 responsible to handle the original FragmentTable while
602 it may be reallocated in TLS driver. If CryptMode is
603 EfiTlsEncrypt, on input these fragments contain the TLS
604 header and plain text TLS APP payload; on output these
605 fragments contain the TLS header and cipher text TLS
606 APP payload. If CryptMode is EfiTlsDecrypt, on input
607 these fragments contain the TLS header and cipher text
608 TLS APP payload; on output these fragments contain the
609 TLS header and plain text TLS APP payload.
610 @param[in] FragmentCount Number of fragment.
611 @param[in] CryptMode Crypt mode.
613 @retval EFI_SUCCESS The operation completed successfully.
614 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
616 FragmentTable is NULL.
617 FragmentCount is NULL.
618 CryptoMode is invalid.
619 @retval EFI_NOT_READY Current TLS session state is NOT
620 EfiTlsSessionDataTransferring.
621 @retval EFI_ABORTED Something wrong decryption the message. TLS session
622 status will become EfiTlsSessionError. The caller need
623 call BuildResponsePacket() to generate Error Alert
624 message and send it out.
625 @retval EFI_OUT_OF_RESOURCES No enough resource to finish the operation.
630 IN EFI_TLS_PROTOCOL
*This
,
631 IN OUT EFI_TLS_FRAGMENT_DATA
**FragmentTable
,
632 IN UINT32
*FragmentCount
,
633 IN EFI_TLS_CRYPT_MODE CryptMode
637 TLS_INSTANCE
*Instance
;
641 Status
= EFI_SUCCESS
;
643 if (This
== NULL
|| FragmentTable
== NULL
|| FragmentCount
== NULL
) {
644 return EFI_INVALID_PARAMETER
;
647 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
649 Instance
= TLS_INSTANCE_FROM_PROTOCOL (This
);
651 if (Instance
->TlsSessionState
!= EfiTlsSessionDataTransferring
) {
652 Status
= EFI_NOT_READY
;
657 // Packet sent or received may have multiple TLS record messages (Application data type).
658 // So,on input these fragments contain the TLS header and TLS APP payload;
659 // on output these fragments also contain the TLS header and TLS APP payload.
663 Status
= TlsEncryptPacket (Instance
, FragmentTable
, FragmentCount
);
666 Status
= TlsDecryptPacket (Instance
, FragmentTable
, FragmentCount
);
669 return EFI_INVALID_PARAMETER
;
673 gBS
->RestoreTPL (OldTpl
);