2 Implementation of EFI TLS Protocol Interfaces.
4 Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>
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.
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.
18 EFI_TLS_PROTOCOL mTlsProtocol
= {
21 TlsBuildResponsePacket
,
28 The SetSessionData() function set data for a new TLS session. All session data should
29 be set before BuildResponsePacket() invoked.
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.
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:
41 DataSize is invalid for DataType.
42 @retval EFI_UNSUPPORTED The DataType is unsupported.
43 @retval EFI_ACCESS_DENIED If the DataType is one of below:
47 @retval EFI_NOT_READY Current TLS session state is NOT
48 EfiTlsSessionStateNotStarted.
49 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
54 IN EFI_TLS_PROTOCOL
*This
,
55 IN EFI_TLS_SESSION_DATA_TYPE DataType
,
61 TLS_INSTANCE
*Instance
;
63 CONST EFI_TLS_CIPHER
*TlsCipherList
;
72 if (This
== NULL
|| Data
== NULL
|| DataSize
== 0) {
73 return EFI_INVALID_PARAMETER
;
76 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
78 Instance
= TLS_INSTANCE_FROM_PROTOCOL (This
);
80 if (DataType
!= EfiTlsSessionState
&& Instance
->TlsSessionState
!= EfiTlsSessionNotStarted
){
81 Status
= EFI_NOT_READY
;
87 // Session Configuration
90 if (DataSize
!= sizeof (EFI_TLS_VERSION
)) {
91 Status
= EFI_INVALID_PARAMETER
;
95 Status
= TlsSetVersion (Instance
->TlsConn
, ((EFI_TLS_VERSION
*) Data
)->Major
, ((EFI_TLS_VERSION
*) Data
)->Minor
);
97 case EfiTlsConnectionEnd
:
98 if (DataSize
!= sizeof (EFI_TLS_CONNECTION_END
)) {
99 Status
= EFI_INVALID_PARAMETER
;
103 Status
= TlsSetConnectionEnd (Instance
->TlsConn
, *((EFI_TLS_CONNECTION_END
*) Data
));
105 case EfiTlsCipherList
:
106 if (DataSize
% sizeof (EFI_TLS_CIPHER
) != 0) {
107 Status
= EFI_INVALID_PARAMETER
;
111 CipherId
= AllocatePool (DataSize
);
112 if (CipherId
== NULL
) {
113 Status
= EFI_OUT_OF_RESOURCES
;
117 TlsCipherList
= (CONST EFI_TLS_CIPHER
*) Data
;
118 CipherCount
= DataSize
/ sizeof (EFI_TLS_CIPHER
);
119 for (Index
= 0; Index
< CipherCount
; Index
++) {
120 CipherId
[Index
] = ((TlsCipherList
[Index
].Data1
<< 8) |
121 TlsCipherList
[Index
].Data2
);
124 Status
= TlsSetCipherList (Instance
->TlsConn
, CipherId
, CipherCount
);
128 case EfiTlsCompressionMethod
:
130 // TLS seems only define one CompressionMethod.null, which specifies that data exchanged via the
131 // record protocol will not be compressed.
132 // More information from OpenSSL: http://www.openssl.org/docs/manmaster/ssl/SSL_COMP_add_compression_method.html
133 // The TLS RFC does however not specify compression methods or their corresponding identifiers,
134 // so there is currently no compatible way to integrate compression with unknown peers.
135 // It is therefore currently not recommended to integrate compression into applications.
136 // Applications for non-public use may agree on certain compression methods.
137 // Using different compression methods with the same identifier will lead to connection failure.
139 for (Index
= 0; Index
< DataSize
/ sizeof (EFI_TLS_COMPRESSION
); Index
++) {
140 Status
= TlsSetCompressionMethod (*((UINT8
*) Data
+ Index
));
141 if (EFI_ERROR (Status
)) {
147 case EfiTlsExtensionData
:
148 Status
= EFI_UNSUPPORTED
;
150 case EfiTlsVerifyMethod
:
151 if (DataSize
!= sizeof (EFI_TLS_VERIFY
)) {
152 Status
= EFI_INVALID_PARAMETER
;
156 TlsSetVerify (Instance
->TlsConn
, *((UINT32
*) Data
));
158 case EfiTlsSessionID
:
159 if (DataSize
!= sizeof (EFI_TLS_SESSION_ID
)) {
160 Status
= EFI_INVALID_PARAMETER
;
164 Status
= TlsSetSessionId (
166 ((EFI_TLS_SESSION_ID
*) Data
)->Data
,
167 ((EFI_TLS_SESSION_ID
*) Data
)->Length
170 case EfiTlsSessionState
:
171 if (DataSize
!= sizeof (EFI_TLS_SESSION_STATE
)) {
172 Status
= EFI_INVALID_PARAMETER
;
176 Instance
->TlsSessionState
= *(EFI_TLS_SESSION_STATE
*) Data
;
179 // Session information
181 case EfiTlsClientRandom
:
182 Status
= EFI_ACCESS_DENIED
;
184 case EfiTlsServerRandom
:
185 Status
= EFI_ACCESS_DENIED
;
187 case EfiTlsKeyMaterial
:
188 Status
= EFI_ACCESS_DENIED
;
194 Status
= EFI_UNSUPPORTED
;
198 gBS
->RestoreTPL (OldTpl
);
203 Get TLS session data.
205 The GetSessionData() function return the TLS session information.
207 @param[in] This Pointer to the EFI_TLS_PROTOCOL instance.
208 @param[in] DataType TLS session data type.
209 @param[in, out] Data Pointer to session data.
210 @param[in, out] DataSize Total size of session data. On input, it means
211 the size of Data buffer. On output, it means the size
212 of copied Data buffer if EFI_SUCCESS, and means the
213 size of desired Data buffer if EFI_BUFFER_TOO_SMALL.
215 @retval EFI_SUCCESS The TLS session data is got successfully.
216 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
219 Data is NULL if *DataSize is not zero.
220 @retval EFI_UNSUPPORTED The DataType is unsupported.
221 @retval EFI_NOT_FOUND The TLS session data is not found.
222 @retval EFI_NOT_READY The DataType is not ready in current session state.
223 @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold the data.
228 IN EFI_TLS_PROTOCOL
*This
,
229 IN EFI_TLS_SESSION_DATA_TYPE DataType
,
230 IN OUT VOID
*Data
, OPTIONAL
231 IN OUT UINTN
*DataSize
235 TLS_INSTANCE
*Instance
;
239 Status
= EFI_SUCCESS
;
241 if (This
== NULL
|| DataSize
== NULL
|| (Data
== NULL
&& *DataSize
!= 0)) {
242 return EFI_INVALID_PARAMETER
;
245 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
247 Instance
= TLS_INSTANCE_FROM_PROTOCOL (This
);
249 if (Instance
->TlsSessionState
== EfiTlsSessionNotStarted
&&
250 (DataType
== EfiTlsSessionID
|| DataType
== EfiTlsClientRandom
||
251 DataType
== EfiTlsServerRandom
|| DataType
== EfiTlsKeyMaterial
)) {
252 Status
= EFI_NOT_READY
;
258 if (*DataSize
< sizeof (EFI_TLS_VERSION
)) {
259 *DataSize
= sizeof (EFI_TLS_VERSION
);
260 Status
= EFI_BUFFER_TOO_SMALL
;
263 *DataSize
= sizeof (EFI_TLS_VERSION
);
264 *((UINT16
*) Data
) = HTONS (TlsGetVersion (Instance
->TlsConn
));
266 case EfiTlsConnectionEnd
:
267 if (*DataSize
< sizeof (EFI_TLS_CONNECTION_END
)) {
268 *DataSize
= sizeof (EFI_TLS_CONNECTION_END
);
269 Status
= EFI_BUFFER_TOO_SMALL
;
272 *DataSize
= sizeof (EFI_TLS_CONNECTION_END
);
273 *((UINT8
*) Data
) = TlsGetConnectionEnd (Instance
->TlsConn
);
275 case EfiTlsCipherList
:
277 // Get the current session cipher suite.
279 if (*DataSize
< sizeof (EFI_TLS_CIPHER
)) {
280 *DataSize
= sizeof (EFI_TLS_CIPHER
);
281 Status
= EFI_BUFFER_TOO_SMALL
;
284 *DataSize
= sizeof(EFI_TLS_CIPHER
);
285 Status
= TlsGetCurrentCipher (Instance
->TlsConn
, (UINT16
*) Data
);
286 *((UINT16
*) Data
) = HTONS (*((UINT16
*) Data
));
288 case EfiTlsCompressionMethod
:
290 // Get the current session compression method.
292 if (*DataSize
< sizeof (EFI_TLS_COMPRESSION
)) {
293 *DataSize
= sizeof (EFI_TLS_COMPRESSION
);
294 Status
= EFI_BUFFER_TOO_SMALL
;
297 *DataSize
= sizeof (EFI_TLS_COMPRESSION
);
298 Status
= TlsGetCurrentCompressionId (Instance
->TlsConn
, (UINT8
*) Data
);
300 case EfiTlsExtensionData
:
301 Status
= EFI_UNSUPPORTED
;
303 case EfiTlsVerifyMethod
:
304 if (*DataSize
< sizeof (EFI_TLS_VERIFY
)) {
305 *DataSize
= sizeof (EFI_TLS_VERIFY
);
306 Status
= EFI_BUFFER_TOO_SMALL
;
309 *DataSize
= sizeof (EFI_TLS_VERIFY
);
310 *((UINT32
*) Data
) = TlsGetVerify (Instance
->TlsConn
);
312 case EfiTlsSessionID
:
313 if (*DataSize
< sizeof (EFI_TLS_SESSION_ID
)) {
314 *DataSize
= sizeof (EFI_TLS_SESSION_ID
);
315 Status
= EFI_BUFFER_TOO_SMALL
;
318 *DataSize
= sizeof (EFI_TLS_SESSION_ID
);
319 Status
= TlsGetSessionId (
321 ((EFI_TLS_SESSION_ID
*) Data
)->Data
,
322 &(((EFI_TLS_SESSION_ID
*) Data
)->Length
)
325 case EfiTlsSessionState
:
326 if (*DataSize
< sizeof (EFI_TLS_SESSION_STATE
)) {
327 *DataSize
= sizeof (EFI_TLS_SESSION_STATE
);
328 Status
= EFI_BUFFER_TOO_SMALL
;
331 *DataSize
= sizeof (EFI_TLS_SESSION_STATE
);
332 CopyMem (Data
, &Instance
->TlsSessionState
, *DataSize
);
334 case EfiTlsClientRandom
:
335 if (*DataSize
< sizeof (EFI_TLS_RANDOM
)) {
336 *DataSize
= sizeof (EFI_TLS_RANDOM
);
337 Status
= EFI_BUFFER_TOO_SMALL
;
340 *DataSize
= sizeof (EFI_TLS_RANDOM
);
341 TlsGetClientRandom (Instance
->TlsConn
, (UINT8
*) Data
);
343 case EfiTlsServerRandom
:
344 if (*DataSize
< sizeof (EFI_TLS_RANDOM
)) {
345 *DataSize
= sizeof (EFI_TLS_RANDOM
);
346 Status
= EFI_BUFFER_TOO_SMALL
;
349 *DataSize
= sizeof (EFI_TLS_RANDOM
);
350 TlsGetServerRandom (Instance
->TlsConn
, (UINT8
*) Data
);
352 case EfiTlsKeyMaterial
:
353 if (*DataSize
< sizeof (EFI_TLS_MASTER_SECRET
)) {
354 *DataSize
= sizeof (EFI_TLS_MASTER_SECRET
);
355 Status
= EFI_BUFFER_TOO_SMALL
;
358 *DataSize
= sizeof (EFI_TLS_MASTER_SECRET
);
359 Status
= TlsGetKeyMaterial (Instance
->TlsConn
, (UINT8
*) Data
);
365 Status
= EFI_UNSUPPORTED
;
369 gBS
->RestoreTPL (OldTpl
);
374 Build response packet according to TLS state machine. This function is only valid for
375 alert, handshake and change_cipher_spec content type.
377 The BuildResponsePacket() function builds TLS response packet in response to the TLS
378 request packet specified by RequestBuffer and RequestSize. If RequestBuffer is NULL and
379 RequestSize is 0, and TLS session status is EfiTlsSessionNotStarted, the TLS session
380 will be initiated and the response packet needs to be ClientHello. If RequestBuffer is
381 NULL and RequestSize is 0, and TLS session status is EfiTlsSessionClosing, the TLS
382 session will be closed and response packet needs to be CloseNotify. If RequestBuffer is
383 NULL and RequestSize is 0, and TLS session status is EfiTlsSessionError, the TLS
384 session has errors and the response packet needs to be Alert message based on error
387 @param[in] This Pointer to the EFI_TLS_PROTOCOL instance.
388 @param[in] RequestBuffer Pointer to the most recently received TLS packet. NULL
389 means TLS need initiate the TLS session and response
390 packet need to be ClientHello.
391 @param[in] RequestSize Packet size in bytes for the most recently received TLS
392 packet. 0 is only valid when RequestBuffer is NULL.
393 @param[out] Buffer Pointer to the buffer to hold the built packet.
394 @param[in, out] BufferSize Pointer to the buffer size in bytes. On input, it is
395 the buffer size provided by the caller. On output, it
396 is the buffer size in fact needed to contain the
399 @retval EFI_SUCCESS The required TLS packet is built successfully.
400 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
402 RequestBuffer is NULL but RequestSize is NOT 0.
403 RequestSize is 0 but RequestBuffer is NOT NULL.
405 Buffer is NULL if *BufferSize is not zero.
406 @retval EFI_BUFFER_TOO_SMALL BufferSize is too small to hold the response packet.
407 @retval EFI_NOT_READY Current TLS session state is NOT ready to build
409 @retval EFI_ABORTED Something wrong build response packet.
413 TlsBuildResponsePacket (
414 IN EFI_TLS_PROTOCOL
*This
,
415 IN UINT8
*RequestBuffer
, OPTIONAL
416 IN UINTN RequestSize
, OPTIONAL
417 OUT UINT8
*Buffer
, OPTIONAL
418 IN OUT UINTN
*BufferSize
422 TLS_INSTANCE
*Instance
;
425 Status
= EFI_SUCCESS
;
427 if ((This
== NULL
) || (BufferSize
== NULL
) ||
428 (RequestBuffer
== NULL
&& RequestSize
!= 0) ||
429 (RequestBuffer
!= NULL
&& RequestSize
== 0) ||
430 (Buffer
== NULL
&& *BufferSize
!=0)) {
431 return EFI_INVALID_PARAMETER
;
434 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
436 Instance
= TLS_INSTANCE_FROM_PROTOCOL (This
);
438 if(RequestBuffer
== NULL
&& RequestSize
== 0) {
439 switch (Instance
->TlsSessionState
) {
440 case EfiTlsSessionNotStarted
:
444 Status
= TlsDoHandshake (
451 if (EFI_ERROR (Status
)) {
456 // *BufferSize should not be zero when ClientHello.
458 if (*BufferSize
== 0) {
459 Status
= EFI_ABORTED
;
463 Instance
->TlsSessionState
= EfiTlsSessionHandShaking
;
466 case EfiTlsSessionClosing
:
468 // TLS session will be closed and response packet needs to be CloseNotify.
470 Status
= TlsCloseNotify (
475 if (EFI_ERROR (Status
)) {
480 // *BufferSize should not be zero when build CloseNotify message.
482 if (*BufferSize
== 0) {
483 Status
= EFI_ABORTED
;
488 case EfiTlsSessionError
:
490 // TLS session has errors and the response packet needs to be Alert
491 // message based on error type.
493 Status
= TlsHandleAlert (
500 if (EFI_ERROR (Status
)) {
507 // Current TLS session state is NOT ready to build ResponsePacket.
509 Status
= EFI_NOT_READY
;
513 // 1. Received packet may have multiple TLS record messages.
514 // 2. One TLS record message may have multiple handshake protocol.
515 // 3. Some errors may be happened in handshake.
516 // TlsDoHandshake() can handle all of those cases.
518 if (TlsInHandshake (Instance
->TlsConn
)) {
519 Status
= TlsDoHandshake (
526 if (EFI_ERROR (Status
)) {
530 if (!TlsInHandshake (Instance
->TlsConn
)) {
531 Instance
->TlsSessionState
= EfiTlsSessionDataTransferring
;
535 // Must be alert message, Decrypt it and build the ResponsePacket.
537 ASSERT (((TLS_RECORD_HEADER
*) RequestBuffer
)->ContentType
== TlsContentTypeAlert
);
539 Status
= TlsHandleAlert (
546 if (EFI_ERROR (Status
)) {
547 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
548 Instance
->TlsSessionState
= EfiTlsSessionError
;
557 gBS
->RestoreTPL (OldTpl
);
562 Decrypt or encrypt TLS packet during session. This function is only valid after
563 session connected and for application_data content type.
565 The ProcessPacket () function process each inbound or outbound TLS APP packet.
567 @param[in] This Pointer to the EFI_TLS_PROTOCOL instance.
568 @param[in, out] FragmentTable Pointer to a list of fragment. The caller will take
569 responsible to handle the original FragmentTable while
570 it may be reallocated in TLS driver. If CryptMode is
571 EfiTlsEncrypt, on input these fragments contain the TLS
572 header and plain text TLS APP payload; on output these
573 fragments contain the TLS header and cipher text TLS
574 APP payload. If CryptMode is EfiTlsDecrypt, on input
575 these fragments contain the TLS header and cipher text
576 TLS APP payload; on output these fragments contain the
577 TLS header and plain text TLS APP payload.
578 @param[in] FragmentCount Number of fragment.
579 @param[in] CryptMode Crypt mode.
581 @retval EFI_SUCCESS The operation completed successfully.
582 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
584 FragmentTable is NULL.
585 FragmentCount is NULL.
586 CryptoMode is invalid.
587 @retval EFI_NOT_READY Current TLS session state is NOT
588 EfiTlsSessionDataTransferring.
589 @retval EFI_ABORTED Something wrong decryption the message. TLS session
590 status will become EfiTlsSessionError. The caller need
591 call BuildResponsePacket() to generate Error Alert
592 message and send it out.
593 @retval EFI_OUT_OF_RESOURCES No enough resource to finish the operation.
598 IN EFI_TLS_PROTOCOL
*This
,
599 IN OUT EFI_TLS_FRAGMENT_DATA
**FragmentTable
,
600 IN UINT32
*FragmentCount
,
601 IN EFI_TLS_CRYPT_MODE CryptMode
605 TLS_INSTANCE
*Instance
;
609 Status
= EFI_SUCCESS
;
611 if (This
== NULL
|| FragmentTable
== NULL
|| FragmentCount
== NULL
) {
612 return EFI_INVALID_PARAMETER
;
615 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
617 Instance
= TLS_INSTANCE_FROM_PROTOCOL (This
);
619 if (Instance
->TlsSessionState
!= EfiTlsSessionDataTransferring
) {
620 Status
= EFI_NOT_READY
;
625 // Packet sent or received may have multiple TLS record messages (Application data type).
626 // So,on input these fragments contain the TLS header and TLS APP payload;
627 // on output these fragments also contain the TLS header and TLS APP payload.
631 Status
= TlsEncryptPacket (Instance
, FragmentTable
, FragmentCount
);
634 Status
= TlsDecryptPacket (Instance
, FragmentTable
, FragmentCount
);
637 return EFI_INVALID_PARAMETER
;
641 gBS
->RestoreTPL (OldTpl
);