2 Implementation of EFI TLS Protocol Interfaces.
4 Copyright (c) 2016 - 2017, 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
;
66 if (This
== NULL
|| Data
== NULL
|| DataSize
== 0) {
67 return EFI_INVALID_PARAMETER
;
70 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
72 Instance
= TLS_INSTANCE_FROM_PROTOCOL (This
);
74 if (DataType
!= EfiTlsSessionState
&& Instance
->TlsSessionState
!= EfiTlsSessionNotStarted
){
75 Status
= EFI_NOT_READY
;
81 // Session Configuration
84 if (DataSize
!= sizeof (EFI_TLS_VERSION
)) {
85 Status
= EFI_INVALID_PARAMETER
;
89 Status
= TlsSetVersion (Instance
->TlsConn
, ((EFI_TLS_VERSION
*) Data
)->Major
, ((EFI_TLS_VERSION
*) Data
)->Minor
);
91 case EfiTlsConnectionEnd
:
92 if (DataSize
!= sizeof (EFI_TLS_CONNECTION_END
)) {
93 Status
= EFI_INVALID_PARAMETER
;
97 Status
= TlsSetConnectionEnd (Instance
->TlsConn
, *((EFI_TLS_CONNECTION_END
*) Data
));
99 case EfiTlsCipherList
:
100 if (DataSize
% sizeof (EFI_TLS_CIPHER
) != 0) {
101 Status
= EFI_INVALID_PARAMETER
;
105 CipherId
= AllocatePool (DataSize
);
106 if (CipherId
== NULL
) {
107 Status
= EFI_OUT_OF_RESOURCES
;
111 TlsCipherList
= (CONST EFI_TLS_CIPHER
*) Data
;
112 CipherCount
= DataSize
/ sizeof (EFI_TLS_CIPHER
);
113 for (Index
= 0; Index
< CipherCount
; Index
++) {
114 CipherId
[Index
] = ((TlsCipherList
[Index
].Data1
<< 8) |
115 TlsCipherList
[Index
].Data2
);
118 Status
= TlsSetCipherList (Instance
->TlsConn
, CipherId
, CipherCount
);
122 case EfiTlsCompressionMethod
:
124 // TLS seems only define one CompressionMethod.null, which specifies that data exchanged via the
125 // record protocol will not be compressed.
126 // More information from OpenSSL: http://www.openssl.org/docs/manmaster/ssl/SSL_COMP_add_compression_method.html
127 // The TLS RFC does however not specify compression methods or their corresponding identifiers,
128 // so there is currently no compatible way to integrate compression with unknown peers.
129 // It is therefore currently not recommended to integrate compression into applications.
130 // Applications for non-public use may agree on certain compression methods.
131 // Using different compression methods with the same identifier will lead to connection failure.
133 for (Index
= 0; Index
< DataSize
/ sizeof (EFI_TLS_COMPRESSION
); Index
++) {
134 Status
= TlsSetCompressionMethod (*((UINT8
*) Data
+ Index
));
135 if (EFI_ERROR (Status
)) {
141 case EfiTlsExtensionData
:
142 Status
= EFI_UNSUPPORTED
;
144 case EfiTlsVerifyMethod
:
145 if (DataSize
!= sizeof (EFI_TLS_VERIFY
)) {
146 Status
= EFI_INVALID_PARAMETER
;
150 TlsSetVerify (Instance
->TlsConn
, *((UINT32
*) Data
));
152 case EfiTlsSessionID
:
153 if (DataSize
!= sizeof (EFI_TLS_SESSION_ID
)) {
154 Status
= EFI_INVALID_PARAMETER
;
158 Status
= TlsSetSessionId (
160 ((EFI_TLS_SESSION_ID
*) Data
)->Data
,
161 ((EFI_TLS_SESSION_ID
*) Data
)->Length
164 case EfiTlsSessionState
:
165 if (DataSize
!= sizeof (EFI_TLS_SESSION_STATE
)) {
166 Status
= EFI_INVALID_PARAMETER
;
170 Instance
->TlsSessionState
= *(EFI_TLS_SESSION_STATE
*) Data
;
173 // Session information
175 case EfiTlsClientRandom
:
176 Status
= EFI_ACCESS_DENIED
;
178 case EfiTlsServerRandom
:
179 Status
= EFI_ACCESS_DENIED
;
181 case EfiTlsKeyMaterial
:
182 Status
= EFI_ACCESS_DENIED
;
188 Status
= EFI_UNSUPPORTED
;
192 gBS
->RestoreTPL (OldTpl
);
197 Get TLS session data.
199 The GetSessionData() function return the TLS session information.
201 @param[in] This Pointer to the EFI_TLS_PROTOCOL instance.
202 @param[in] DataType TLS session data type.
203 @param[in, out] Data Pointer to session data.
204 @param[in, out] DataSize Total size of session data. On input, it means
205 the size of Data buffer. On output, it means the size
206 of copied Data buffer if EFI_SUCCESS, and means the
207 size of desired Data buffer if EFI_BUFFER_TOO_SMALL.
209 @retval EFI_SUCCESS The TLS session data is got successfully.
210 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
213 Data is NULL if *DataSize is not zero.
214 @retval EFI_UNSUPPORTED The DataType is unsupported.
215 @retval EFI_NOT_FOUND The TLS session data is not found.
216 @retval EFI_NOT_READY The DataType is not ready in current session state.
217 @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold the data.
222 IN EFI_TLS_PROTOCOL
*This
,
223 IN EFI_TLS_SESSION_DATA_TYPE DataType
,
224 IN OUT VOID
*Data
, OPTIONAL
225 IN OUT UINTN
*DataSize
229 TLS_INSTANCE
*Instance
;
233 Status
= EFI_SUCCESS
;
235 if (This
== NULL
|| DataSize
== NULL
|| (Data
== NULL
&& *DataSize
!= 0)) {
236 return EFI_INVALID_PARAMETER
;
239 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
241 Instance
= TLS_INSTANCE_FROM_PROTOCOL (This
);
243 if (Instance
->TlsSessionState
== EfiTlsSessionNotStarted
&&
244 (DataType
== EfiTlsSessionID
|| DataType
== EfiTlsClientRandom
||
245 DataType
== EfiTlsServerRandom
|| DataType
== EfiTlsKeyMaterial
)) {
246 Status
= EFI_NOT_READY
;
252 if (*DataSize
< sizeof (EFI_TLS_VERSION
)) {
253 *DataSize
= sizeof (EFI_TLS_VERSION
);
254 Status
= EFI_BUFFER_TOO_SMALL
;
257 *DataSize
= sizeof (EFI_TLS_VERSION
);
258 *((UINT16
*) Data
) = HTONS (TlsGetVersion (Instance
->TlsConn
));
260 case EfiTlsConnectionEnd
:
261 if (*DataSize
< sizeof (EFI_TLS_CONNECTION_END
)) {
262 *DataSize
= sizeof (EFI_TLS_CONNECTION_END
);
263 Status
= EFI_BUFFER_TOO_SMALL
;
266 *DataSize
= sizeof (EFI_TLS_CONNECTION_END
);
267 *((UINT8
*) Data
) = TlsGetConnectionEnd (Instance
->TlsConn
);
269 case EfiTlsCipherList
:
271 // Get the current session cipher suite.
273 if (*DataSize
< sizeof (EFI_TLS_CIPHER
)) {
274 *DataSize
= sizeof (EFI_TLS_CIPHER
);
275 Status
= EFI_BUFFER_TOO_SMALL
;
278 *DataSize
= sizeof(EFI_TLS_CIPHER
);
279 Status
= TlsGetCurrentCipher (Instance
->TlsConn
, (UINT16
*) Data
);
280 *((UINT16
*) Data
) = HTONS (*((UINT16
*) Data
));
282 case EfiTlsCompressionMethod
:
284 // Get the current session compression method.
286 if (*DataSize
< sizeof (EFI_TLS_COMPRESSION
)) {
287 *DataSize
= sizeof (EFI_TLS_COMPRESSION
);
288 Status
= EFI_BUFFER_TOO_SMALL
;
291 *DataSize
= sizeof (EFI_TLS_COMPRESSION
);
292 Status
= TlsGetCurrentCompressionId (Instance
->TlsConn
, (UINT8
*) Data
);
294 case EfiTlsExtensionData
:
295 Status
= EFI_UNSUPPORTED
;
297 case EfiTlsVerifyMethod
:
298 if (*DataSize
< sizeof (EFI_TLS_VERIFY
)) {
299 *DataSize
= sizeof (EFI_TLS_VERIFY
);
300 Status
= EFI_BUFFER_TOO_SMALL
;
303 *DataSize
= sizeof (EFI_TLS_VERIFY
);
304 *((UINT32
*) Data
) = TlsGetVerify (Instance
->TlsConn
);
306 case EfiTlsSessionID
:
307 if (*DataSize
< sizeof (EFI_TLS_SESSION_ID
)) {
308 *DataSize
= sizeof (EFI_TLS_SESSION_ID
);
309 Status
= EFI_BUFFER_TOO_SMALL
;
312 *DataSize
= sizeof (EFI_TLS_SESSION_ID
);
313 Status
= TlsGetSessionId (
315 ((EFI_TLS_SESSION_ID
*) Data
)->Data
,
316 &(((EFI_TLS_SESSION_ID
*) Data
)->Length
)
319 case EfiTlsSessionState
:
320 if (*DataSize
< sizeof (EFI_TLS_SESSION_STATE
)) {
321 *DataSize
= sizeof (EFI_TLS_SESSION_STATE
);
322 Status
= EFI_BUFFER_TOO_SMALL
;
325 *DataSize
= sizeof (EFI_TLS_SESSION_STATE
);
326 CopyMem (Data
, &Instance
->TlsSessionState
, *DataSize
);
328 case EfiTlsClientRandom
:
329 if (*DataSize
< sizeof (EFI_TLS_RANDOM
)) {
330 *DataSize
= sizeof (EFI_TLS_RANDOM
);
331 Status
= EFI_BUFFER_TOO_SMALL
;
334 *DataSize
= sizeof (EFI_TLS_RANDOM
);
335 TlsGetClientRandom (Instance
->TlsConn
, (UINT8
*) Data
);
337 case EfiTlsServerRandom
:
338 if (*DataSize
< sizeof (EFI_TLS_RANDOM
)) {
339 *DataSize
= sizeof (EFI_TLS_RANDOM
);
340 Status
= EFI_BUFFER_TOO_SMALL
;
343 *DataSize
= sizeof (EFI_TLS_RANDOM
);
344 TlsGetServerRandom (Instance
->TlsConn
, (UINT8
*) Data
);
346 case EfiTlsKeyMaterial
:
347 if (*DataSize
< sizeof (EFI_TLS_MASTER_SECRET
)) {
348 *DataSize
= sizeof (EFI_TLS_MASTER_SECRET
);
349 Status
= EFI_BUFFER_TOO_SMALL
;
352 *DataSize
= sizeof (EFI_TLS_MASTER_SECRET
);
353 Status
= TlsGetKeyMaterial (Instance
->TlsConn
, (UINT8
*) Data
);
359 Status
= EFI_UNSUPPORTED
;
363 gBS
->RestoreTPL (OldTpl
);
368 Build response packet according to TLS state machine. This function is only valid for
369 alert, handshake and change_cipher_spec content type.
371 The BuildResponsePacket() function builds TLS response packet in response to the TLS
372 request packet specified by RequestBuffer and RequestSize. If RequestBuffer is NULL and
373 RequestSize is 0, and TLS session status is EfiTlsSessionNotStarted, the TLS session
374 will be initiated and the response packet needs to be ClientHello. If RequestBuffer is
375 NULL and RequestSize is 0, and TLS session status is EfiTlsSessionClosing, the TLS
376 session will be closed and response packet needs to be CloseNotify. If RequestBuffer is
377 NULL and RequestSize is 0, and TLS session status is EfiTlsSessionError, the TLS
378 session has errors and the response packet needs to be Alert message based on error
381 @param[in] This Pointer to the EFI_TLS_PROTOCOL instance.
382 @param[in] RequestBuffer Pointer to the most recently received TLS packet. NULL
383 means TLS need initiate the TLS session and response
384 packet need to be ClientHello.
385 @param[in] RequestSize Packet size in bytes for the most recently received TLS
386 packet. 0 is only valid when RequestBuffer is NULL.
387 @param[out] Buffer Pointer to the buffer to hold the built packet.
388 @param[in, out] BufferSize Pointer to the buffer size in bytes. On input, it is
389 the buffer size provided by the caller. On output, it
390 is the buffer size in fact needed to contain the
393 @retval EFI_SUCCESS The required TLS packet is built successfully.
394 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
396 RequestBuffer is NULL but RequestSize is NOT 0.
397 RequestSize is 0 but RequestBuffer is NOT NULL.
399 Buffer is NULL if *BufferSize is not zero.
400 @retval EFI_BUFFER_TOO_SMALL BufferSize is too small to hold the response packet.
401 @retval EFI_NOT_READY Current TLS session state is NOT ready to build
403 @retval EFI_ABORTED Something wrong build response packet.
407 TlsBuildResponsePacket (
408 IN EFI_TLS_PROTOCOL
*This
,
409 IN UINT8
*RequestBuffer
, OPTIONAL
410 IN UINTN RequestSize
, OPTIONAL
411 OUT UINT8
*Buffer
, OPTIONAL
412 IN OUT UINTN
*BufferSize
416 TLS_INSTANCE
*Instance
;
419 Status
= EFI_SUCCESS
;
421 if ((This
== NULL
) || (BufferSize
== NULL
) ||
422 (RequestBuffer
== NULL
&& RequestSize
!= 0) ||
423 (RequestBuffer
!= NULL
&& RequestSize
== 0) ||
424 (Buffer
== NULL
&& *BufferSize
!=0)) {
425 return EFI_INVALID_PARAMETER
;
428 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
430 Instance
= TLS_INSTANCE_FROM_PROTOCOL (This
);
432 if(RequestBuffer
== NULL
&& RequestSize
== 0) {
433 switch (Instance
->TlsSessionState
) {
434 case EfiTlsSessionNotStarted
:
438 Status
= TlsDoHandshake (
445 if (EFI_ERROR (Status
)) {
450 // *BufferSize should not be zero when ClientHello.
452 if (*BufferSize
== 0) {
453 Status
= EFI_ABORTED
;
457 Instance
->TlsSessionState
= EfiTlsSessionHandShaking
;
460 case EfiTlsSessionClosing
:
462 // TLS session will be closed and response packet needs to be CloseNotify.
464 Status
= TlsCloseNotify (
469 if (EFI_ERROR (Status
)) {
474 // *BufferSize should not be zero when build CloseNotify message.
476 if (*BufferSize
== 0) {
477 Status
= EFI_ABORTED
;
482 case EfiTlsSessionError
:
484 // TLS session has errors and the response packet needs to be Alert
485 // message based on error type.
487 Status
= TlsHandleAlert (
494 if (EFI_ERROR (Status
)) {
501 // Current TLS session state is NOT ready to build ResponsePacket.
503 Status
= EFI_NOT_READY
;
507 // 1. Received packet may have multiple TLS record messages.
508 // 2. One TLS record message may have multiple handshake protocol.
509 // 3. Some errors may be happened in handshake.
510 // TlsDoHandshake() can handle all of those cases.
512 if (TlsInHandshake (Instance
->TlsConn
)) {
513 Status
= TlsDoHandshake (
520 if (EFI_ERROR (Status
)) {
524 if (!TlsInHandshake (Instance
->TlsConn
)) {
525 Instance
->TlsSessionState
= EfiTlsSessionDataTransferring
;
529 // Must be alert message, Decrypt it and build the ResponsePacket.
531 ASSERT (((TLS_RECORD_HEADER
*) RequestBuffer
)->ContentType
== TlsContentTypeAlert
);
533 Status
= TlsHandleAlert (
540 if (EFI_ERROR (Status
)) {
541 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
542 Instance
->TlsSessionState
= EfiTlsSessionError
;
551 gBS
->RestoreTPL (OldTpl
);
556 Decrypt or encrypt TLS packet during session. This function is only valid after
557 session connected and for application_data content type.
559 The ProcessPacket () function process each inbound or outbound TLS APP packet.
561 @param[in] This Pointer to the EFI_TLS_PROTOCOL instance.
562 @param[in, out] FragmentTable Pointer to a list of fragment. The caller will take
563 responsible to handle the original FragmentTable while
564 it may be reallocated in TLS driver. If CryptMode is
565 EfiTlsEncrypt, on input these fragments contain the TLS
566 header and plain text TLS APP payload; on output these
567 fragments contain the TLS header and cipher text TLS
568 APP payload. If CryptMode is EfiTlsDecrypt, on input
569 these fragments contain the TLS header and cipher text
570 TLS APP payload; on output these fragments contain the
571 TLS header and plain text TLS APP payload.
572 @param[in] FragmentCount Number of fragment.
573 @param[in] CryptMode Crypt mode.
575 @retval EFI_SUCCESS The operation completed successfully.
576 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
578 FragmentTable is NULL.
579 FragmentCount is NULL.
580 CryptoMode is invalid.
581 @retval EFI_NOT_READY Current TLS session state is NOT
582 EfiTlsSessionDataTransferring.
583 @retval EFI_ABORTED Something wrong decryption the message. TLS session
584 status will become EfiTlsSessionError. The caller need
585 call BuildResponsePacket() to generate Error Alert
586 message and send it out.
587 @retval EFI_OUT_OF_RESOURCES No enough resource to finish the operation.
592 IN EFI_TLS_PROTOCOL
*This
,
593 IN OUT EFI_TLS_FRAGMENT_DATA
**FragmentTable
,
594 IN UINT32
*FragmentCount
,
595 IN EFI_TLS_CRYPT_MODE CryptMode
599 TLS_INSTANCE
*Instance
;
603 Status
= EFI_SUCCESS
;
605 if (This
== NULL
|| FragmentTable
== NULL
|| FragmentCount
== NULL
) {
606 return EFI_INVALID_PARAMETER
;
609 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
611 Instance
= TLS_INSTANCE_FROM_PROTOCOL (This
);
613 if (Instance
->TlsSessionState
!= EfiTlsSessionDataTransferring
) {
614 Status
= EFI_NOT_READY
;
619 // Packet sent or received may have multiple TLS record messages (Application data type).
620 // So,on input these fragments contain the TLS header and TLS APP payload;
621 // on output these fragments also contain the TLS header and TLS APP payload.
625 Status
= TlsEncryptPacket (Instance
, FragmentTable
, FragmentCount
);
628 Status
= TlsDecryptPacket (Instance
, FragmentTable
, FragmentCount
);
631 return EFI_INVALID_PARAMETER
;
635 gBS
->RestoreTPL (OldTpl
);