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 @retval EFI_UNSUPPORTED The DataType is unsupported.
42 @retval EFI_ACCESS_DENIED If the DataType is one of below:
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.
53 IN EFI_TLS_PROTOCOL
*This
,
54 IN EFI_TLS_SESSION_DATA_TYPE DataType
,
60 TLS_INSTANCE
*Instance
;
69 if (This
== NULL
|| Data
== NULL
|| DataSize
== 0) {
70 return EFI_INVALID_PARAMETER
;
73 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
75 Instance
= TLS_INSTANCE_FROM_PROTOCOL (This
);
77 if (DataType
!= EfiTlsSessionState
&& Instance
->TlsSessionState
!= EfiTlsSessionNotStarted
){
78 Status
= EFI_NOT_READY
;
84 // Session Configuration
87 if (DataSize
!= sizeof (EFI_TLS_VERSION
)) {
88 Status
= EFI_INVALID_PARAMETER
;
92 Status
= TlsSetVersion (Instance
->TlsConn
, ((EFI_TLS_VERSION
*) Data
)->Major
, ((EFI_TLS_VERSION
*) Data
)->Minor
);
94 case EfiTlsConnectionEnd
:
95 if (DataSize
!= sizeof (EFI_TLS_CONNECTION_END
)) {
96 Status
= EFI_INVALID_PARAMETER
;
100 Status
= TlsSetConnectionEnd (Instance
->TlsConn
, *((EFI_TLS_CONNECTION_END
*) Data
));
102 case EfiTlsCipherList
:
103 CipherId
= AllocatePool (DataSize
);
104 if (CipherId
== NULL
) {
105 Status
= EFI_OUT_OF_RESOURCES
;
109 for (Index
= 0; Index
< DataSize
/ sizeof (EFI_TLS_CIPHER
); Index
++) {
110 *(CipherId
+Index
) = HTONS (*(((UINT16
*) Data
) + Index
));
113 Status
= TlsSetCipherList (Instance
->TlsConn
, CipherId
, DataSize
/ sizeof (EFI_TLS_CIPHER
));
117 case EfiTlsCompressionMethod
:
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.
128 for (Index
= 0; Index
< DataSize
/ sizeof (EFI_TLS_COMPRESSION
); Index
++) {
129 Status
= TlsSetCompressionMethod (*((UINT8
*) Data
+ Index
));
130 if (EFI_ERROR (Status
)) {
136 case EfiTlsExtensionData
:
137 Status
= EFI_UNSUPPORTED
;
139 case EfiTlsVerifyMethod
:
140 if (DataSize
!= sizeof (EFI_TLS_VERIFY
)) {
141 Status
= EFI_INVALID_PARAMETER
;
145 TlsSetVerify (Instance
->TlsConn
, *((UINT32
*) Data
));
147 case EfiTlsSessionID
:
148 if (DataSize
!= sizeof (EFI_TLS_SESSION_ID
)) {
149 Status
= EFI_INVALID_PARAMETER
;
153 Status
= TlsSetSessionId (
155 ((EFI_TLS_SESSION_ID
*) Data
)->Data
,
156 ((EFI_TLS_SESSION_ID
*) Data
)->Length
159 case EfiTlsSessionState
:
160 if (DataSize
!= sizeof (EFI_TLS_SESSION_STATE
)) {
161 Status
= EFI_INVALID_PARAMETER
;
165 Instance
->TlsSessionState
= *(EFI_TLS_SESSION_STATE
*) Data
;
168 // Session information
170 case EfiTlsClientRandom
:
171 Status
= EFI_ACCESS_DENIED
;
173 case EfiTlsServerRandom
:
174 Status
= EFI_ACCESS_DENIED
;
176 case EfiTlsKeyMaterial
:
177 Status
= EFI_ACCESS_DENIED
;
183 Status
= EFI_UNSUPPORTED
;
187 gBS
->RestoreTPL (OldTpl
);
192 Get TLS session data.
194 The GetSessionData() function return the TLS session information.
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.
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:
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.
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
224 TLS_INSTANCE
*Instance
;
228 Status
= EFI_SUCCESS
;
230 if (This
== NULL
|| DataSize
== NULL
|| (Data
== NULL
&& *DataSize
!= 0)) {
231 return EFI_INVALID_PARAMETER
;
234 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
236 Instance
= TLS_INSTANCE_FROM_PROTOCOL (This
);
238 if (Instance
->TlsSessionState
== EfiTlsSessionNotStarted
&&
239 (DataType
== EfiTlsSessionID
|| DataType
== EfiTlsClientRandom
||
240 DataType
== EfiTlsServerRandom
|| DataType
== EfiTlsKeyMaterial
)) {
241 Status
= EFI_NOT_READY
;
247 if (*DataSize
< sizeof (EFI_TLS_VERSION
)) {
248 *DataSize
= sizeof (EFI_TLS_VERSION
);
249 Status
= EFI_BUFFER_TOO_SMALL
;
252 *DataSize
= sizeof (EFI_TLS_VERSION
);
253 *((UINT16
*) Data
) = HTONS (TlsGetVersion (Instance
->TlsConn
));
255 case EfiTlsConnectionEnd
:
256 if (*DataSize
< sizeof (EFI_TLS_CONNECTION_END
)) {
257 *DataSize
= sizeof (EFI_TLS_CONNECTION_END
);
258 Status
= EFI_BUFFER_TOO_SMALL
;
261 *DataSize
= sizeof (EFI_TLS_CONNECTION_END
);
262 *((UINT8
*) Data
) = TlsGetConnectionEnd (Instance
->TlsConn
);
264 case EfiTlsCipherList
:
266 // Get the current session cipher suite.
268 if (*DataSize
< sizeof (EFI_TLS_CIPHER
)) {
269 *DataSize
= sizeof (EFI_TLS_CIPHER
);
270 Status
= EFI_BUFFER_TOO_SMALL
;
273 *DataSize
= sizeof(EFI_TLS_CIPHER
);
274 Status
= TlsGetCurrentCipher (Instance
->TlsConn
, (UINT16
*) Data
);
275 *((UINT16
*) Data
) = HTONS (*((UINT16
*) Data
));
277 case EfiTlsCompressionMethod
:
279 // Get the current session compression method.
281 if (*DataSize
< sizeof (EFI_TLS_COMPRESSION
)) {
282 *DataSize
= sizeof (EFI_TLS_COMPRESSION
);
283 Status
= EFI_BUFFER_TOO_SMALL
;
286 *DataSize
= sizeof (EFI_TLS_COMPRESSION
);
287 Status
= TlsGetCurrentCompressionId (Instance
->TlsConn
, (UINT8
*) Data
);
289 case EfiTlsExtensionData
:
290 Status
= EFI_UNSUPPORTED
;
292 case EfiTlsVerifyMethod
:
293 if (*DataSize
< sizeof (EFI_TLS_VERIFY
)) {
294 *DataSize
= sizeof (EFI_TLS_VERIFY
);
295 Status
= EFI_BUFFER_TOO_SMALL
;
298 *DataSize
= sizeof (EFI_TLS_VERIFY
);
299 *((UINT32
*) Data
) = TlsGetVerify (Instance
->TlsConn
);
301 case EfiTlsSessionID
:
302 if (*DataSize
< sizeof (EFI_TLS_SESSION_ID
)) {
303 *DataSize
= sizeof (EFI_TLS_SESSION_ID
);
304 Status
= EFI_BUFFER_TOO_SMALL
;
307 *DataSize
= sizeof (EFI_TLS_SESSION_ID
);
308 Status
= TlsGetSessionId (
310 ((EFI_TLS_SESSION_ID
*) Data
)->Data
,
311 &(((EFI_TLS_SESSION_ID
*) Data
)->Length
)
314 case EfiTlsSessionState
:
315 if (*DataSize
< sizeof (EFI_TLS_SESSION_STATE
)) {
316 *DataSize
= sizeof (EFI_TLS_SESSION_STATE
);
317 Status
= EFI_BUFFER_TOO_SMALL
;
320 *DataSize
= sizeof (EFI_TLS_SESSION_STATE
);
321 CopyMem (Data
, &Instance
->TlsSessionState
, *DataSize
);
323 case EfiTlsClientRandom
:
324 if (*DataSize
< sizeof (EFI_TLS_RANDOM
)) {
325 *DataSize
= sizeof (EFI_TLS_RANDOM
);
326 Status
= EFI_BUFFER_TOO_SMALL
;
329 *DataSize
= sizeof (EFI_TLS_RANDOM
);
330 TlsGetClientRandom (Instance
->TlsConn
, (UINT8
*) Data
);
332 case EfiTlsServerRandom
:
333 if (*DataSize
< sizeof (EFI_TLS_RANDOM
)) {
334 *DataSize
= sizeof (EFI_TLS_RANDOM
);
335 Status
= EFI_BUFFER_TOO_SMALL
;
338 *DataSize
= sizeof (EFI_TLS_RANDOM
);
339 TlsGetServerRandom (Instance
->TlsConn
, (UINT8
*) Data
);
341 case EfiTlsKeyMaterial
:
342 if (*DataSize
< sizeof (EFI_TLS_MASTER_SECRET
)) {
343 *DataSize
= sizeof (EFI_TLS_MASTER_SECRET
);
344 Status
= EFI_BUFFER_TOO_SMALL
;
347 *DataSize
= sizeof (EFI_TLS_MASTER_SECRET
);
348 Status
= TlsGetKeyMaterial (Instance
->TlsConn
, (UINT8
*) Data
);
354 Status
= EFI_UNSUPPORTED
;
358 gBS
->RestoreTPL (OldTpl
);
363 Build response packet according to TLS state machine. This function is only valid for
364 alert, handshake and change_cipher_spec content type.
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
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
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:
391 RequestBuffer is NULL but RequestSize is NOT 0.
392 RequestSize is 0 but RequestBuffer is NOT 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
398 @retval EFI_ABORTED Something wrong build response packet.
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
411 TLS_INSTANCE
*Instance
;
414 Status
= EFI_SUCCESS
;
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
;
423 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
425 Instance
= TLS_INSTANCE_FROM_PROTOCOL (This
);
427 if(RequestBuffer
== NULL
&& RequestSize
== 0) {
428 switch (Instance
->TlsSessionState
) {
429 case EfiTlsSessionNotStarted
:
433 Status
= TlsDoHandshake (
440 if (EFI_ERROR (Status
)) {
445 // *BufferSize should not be zero when ClientHello.
447 if (*BufferSize
== 0) {
448 Status
= EFI_ABORTED
;
452 Instance
->TlsSessionState
= EfiTlsSessionHandShaking
;
455 case EfiTlsSessionClosing
:
457 // TLS session will be closed and response packet needs to be CloseNotify.
459 Status
= TlsCloseNotify (
464 if (EFI_ERROR (Status
)) {
469 // *BufferSize should not be zero when build CloseNotify message.
471 if (*BufferSize
== 0) {
472 Status
= EFI_ABORTED
;
477 case EfiTlsSessionError
:
479 // TLS session has errors and the response packet needs to be Alert
480 // message based on error type.
482 Status
= TlsHandleAlert (
489 if (EFI_ERROR (Status
)) {
496 // Current TLS session state is NOT ready to build ResponsePacket.
498 Status
= EFI_NOT_READY
;
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.
507 if (TlsInHandshake (Instance
->TlsConn
)) {
508 Status
= TlsDoHandshake (
515 if (EFI_ERROR (Status
)) {
519 if (!TlsInHandshake (Instance
->TlsConn
)) {
520 Instance
->TlsSessionState
= EfiTlsSessionDataTransferring
;
524 // Must be alert message, Decrypt it and build the ResponsePacket.
526 ASSERT (((TLS_RECORD_HEADER
*) RequestBuffer
)->ContentType
== TlsContentTypeAlert
);
528 Status
= TlsHandleAlert (
535 if (EFI_ERROR (Status
)) {
536 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
537 Instance
->TlsSessionState
= EfiTlsSessionError
;
546 gBS
->RestoreTPL (OldTpl
);
551 Decrypt or encrypt TLS packet during session. This function is only valid after
552 session connected and for application_data content type.
554 The ProcessPacket () function process each inbound or outbound TLS APP packet.
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.
570 @retval EFI_SUCCESS The operation completed successfully.
571 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
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.
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
594 TLS_INSTANCE
*Instance
;
598 Status
= EFI_SUCCESS
;
600 if (This
== NULL
|| FragmentTable
== NULL
|| FragmentCount
== NULL
) {
601 return EFI_INVALID_PARAMETER
;
604 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
606 Instance
= TLS_INSTANCE_FROM_PROTOCOL (This
);
608 if (Instance
->TlsSessionState
!= EfiTlsSessionDataTransferring
) {
609 Status
= EFI_NOT_READY
;
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.
620 Status
= TlsEncryptPacket (Instance
, FragmentTable
, FragmentCount
);
623 Status
= TlsDecryptPacket (Instance
, FragmentTable
, FragmentCount
);
626 return EFI_INVALID_PARAMETER
;
630 gBS
->RestoreTPL (OldTpl
);