X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=CryptoPkg%2FLibrary%2FTlsLib%2FTlsConfig.c;h=0673c9d5322e87ce85649bf953cc98da660fd012;hp=c1d91a599482528228520f078eae79779e63a4d1;hb=HEAD;hpb=5eadb54e26e239429e8b4fe18897781f2321738a diff --git a/CryptoPkg/Library/TlsLib/TlsConfig.c b/CryptoPkg/Library/TlsLib/TlsConfig.c index c1d91a5994..60559de4a7 100644 --- a/CryptoPkg/Library/TlsLib/TlsConfig.c +++ b/CryptoPkg/Library/TlsLib/TlsConfig.c @@ -1,15 +1,9 @@ /** @file SSL/TLS Configuration Library Wrapper Implementation over OpenSSL. -Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.
(C) Copyright 2016 Hewlett Packard Enterprise Development LP
-This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -19,43 +13,87 @@ typedef struct { // // IANA/IETF defined Cipher Suite ID // - UINT16 IanaCipher; + UINT16 IanaCipher; // // OpenSSL-used Cipher Suite String // - CONST CHAR8 *OpensslCipher; + CONST CHAR8 *OpensslCipher; + // + // Length of OpensslCipher + // + UINTN OpensslCipherLength; } TLS_CIPHER_MAPPING; +// +// Create a TLS_CIPHER_MAPPING initializer from IanaCipher and OpensslCipher so +// that OpensslCipherLength is filled in automatically. IanaCipher must be an +// integer constant expression, and OpensslCipher must be a string literal. +// +#define MAP(IanaCipher, OpensslCipher) \ + { (IanaCipher), (OpensslCipher), sizeof (OpensslCipher) - 1 } + // // The mapping table between IANA/IETF Cipher Suite definitions and // OpenSSL-used Cipher Suite name. // // Keep the table uniquely sorted by the IanaCipher field, in increasing order. // -STATIC CONST TLS_CIPHER_MAPPING TlsCipherMappingTable[] = { - { 0x0001, "NULL-MD5" }, /// TLS_RSA_WITH_NULL_MD5 - { 0x0002, "NULL-SHA" }, /// TLS_RSA_WITH_NULL_SHA - { 0x0004, "RC4-MD5" }, /// TLS_RSA_WITH_RC4_128_MD5 - { 0x0005, "RC4-SHA" }, /// TLS_RSA_WITH_RC4_128_SHA - { 0x000A, "DES-CBC3-SHA" }, /// TLS_RSA_WITH_3DES_EDE_CBC_SHA, mandatory TLS 1.1 - { 0x0016, "DHE-RSA-DES-CBC3-SHA" }, /// TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA - { 0x002F, "AES128-SHA" }, /// TLS_RSA_WITH_AES_128_CBC_SHA, mandatory TLS 1.2 - { 0x0030, "DH-DSS-AES128-SHA" }, /// TLS_DH_DSS_WITH_AES_128_CBC_SHA - { 0x0031, "DH-RSA-AES128-SHA" }, /// TLS_DH_RSA_WITH_AES_128_CBC_SHA - { 0x0033, "DHE-RSA-AES128-SHA" }, /// TLS_DHE_RSA_WITH_AES_128_CBC_SHA - { 0x0035, "AES256-SHA" }, /// TLS_RSA_WITH_AES_256_CBC_SHA - { 0x0036, "DH-DSS-AES256-SHA" }, /// TLS_DH_DSS_WITH_AES_256_CBC_SHA - { 0x0037, "DH-RSA-AES256-SHA" }, /// TLS_DH_RSA_WITH_AES_256_CBC_SHA - { 0x0039, "DHE-RSA-AES256-SHA" }, /// TLS_DHE_RSA_WITH_AES_256_CBC_SHA - { 0x003B, "NULL-SHA256" }, /// TLS_RSA_WITH_NULL_SHA256 - { 0x003C, "AES128-SHA256" }, /// TLS_RSA_WITH_AES_128_CBC_SHA256 - { 0x003D, "AES256-SHA256" }, /// TLS_RSA_WITH_AES_256_CBC_SHA256 - { 0x003E, "DH-DSS-AES128-SHA256" }, /// TLS_DH_DSS_WITH_AES_128_CBC_SHA256 - { 0x003F, "DH-RSA-AES128-SHA256" }, /// TLS_DH_RSA_WITH_AES_128_CBC_SHA256 - { 0x0067, "DHE-RSA-AES128-SHA256" }, /// TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 - { 0x0068, "DH-DSS-AES256-SHA256" }, /// TLS_DH_DSS_WITH_AES_256_CBC_SHA256 - { 0x0069, "DH-RSA-AES256-SHA256" }, /// TLS_DH_RSA_WITH_AES_256_CBC_SHA256 - { 0x006B, "DHE-RSA-AES256-SHA256" } /// TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 +STATIC CONST TLS_CIPHER_MAPPING TlsCipherMappingTable[] = { + MAP (0x0001, "NULL-MD5"), /// TLS_RSA_WITH_NULL_MD5 + MAP (0x0002, "NULL-SHA"), /// TLS_RSA_WITH_NULL_SHA + MAP (0x0004, "RC4-MD5"), /// TLS_RSA_WITH_RC4_128_MD5 + MAP (0x0005, "RC4-SHA"), /// TLS_RSA_WITH_RC4_128_SHA + MAP (0x000A, "DES-CBC3-SHA"), /// TLS_RSA_WITH_3DES_EDE_CBC_SHA, mandatory TLS 1.1 + MAP (0x0016, "DHE-RSA-DES-CBC3-SHA"), /// TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA + MAP (0x002F, "AES128-SHA"), /// TLS_RSA_WITH_AES_128_CBC_SHA, mandatory TLS 1.2 + MAP (0x0030, "DH-DSS-AES128-SHA"), /// TLS_DH_DSS_WITH_AES_128_CBC_SHA + MAP (0x0031, "DH-RSA-AES128-SHA"), /// TLS_DH_RSA_WITH_AES_128_CBC_SHA + MAP (0x0033, "DHE-RSA-AES128-SHA"), /// TLS_DHE_RSA_WITH_AES_128_CBC_SHA + MAP (0x0035, "AES256-SHA"), /// TLS_RSA_WITH_AES_256_CBC_SHA + MAP (0x0036, "DH-DSS-AES256-SHA"), /// TLS_DH_DSS_WITH_AES_256_CBC_SHA + MAP (0x0037, "DH-RSA-AES256-SHA"), /// TLS_DH_RSA_WITH_AES_256_CBC_SHA + MAP (0x0039, "DHE-RSA-AES256-SHA"), /// TLS_DHE_RSA_WITH_AES_256_CBC_SHA + MAP (0x003B, "NULL-SHA256"), /// TLS_RSA_WITH_NULL_SHA256 + MAP (0x003C, "AES128-SHA256"), /// TLS_RSA_WITH_AES_128_CBC_SHA256 + MAP (0x003D, "AES256-SHA256"), /// TLS_RSA_WITH_AES_256_CBC_SHA256 + MAP (0x003E, "DH-DSS-AES128-SHA256"), /// TLS_DH_DSS_WITH_AES_128_CBC_SHA256 + MAP (0x003F, "DH-RSA-AES128-SHA256"), /// TLS_DH_RSA_WITH_AES_128_CBC_SHA256 + MAP (0x0067, "DHE-RSA-AES128-SHA256"), /// TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + MAP (0x0068, "DH-DSS-AES256-SHA256"), /// TLS_DH_DSS_WITH_AES_256_CBC_SHA256 + MAP (0x0069, "DH-RSA-AES256-SHA256"), /// TLS_DH_RSA_WITH_AES_256_CBC_SHA256 + MAP (0x006B, "DHE-RSA-AES256-SHA256"), /// TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + MAP (0x009F, "DHE-RSA-AES256-GCM-SHA384"), /// TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + MAP (0xC02B, "ECDHE-ECDSA-AES128-GCM-SHA256"), /// TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + MAP (0xC02C, "ECDHE-ECDSA-AES256-GCM-SHA384"), /// TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + MAP (0xC030, "ECDHE-RSA-AES256-GCM-SHA384"), /// TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 +}; + +typedef struct { + // + // TLS Algorithm + // + UINT8 Algo; + // + // TLS Algorithm name + // + CONST CHAR8 *Name; +} TLS_ALGO_TO_NAME; + +STATIC CONST TLS_ALGO_TO_NAME TlsHashAlgoToName[] = { + { TlsHashAlgoNone, NULL }, + { TlsHashAlgoMd5, "MD5" }, + { TlsHashAlgoSha1, "SHA1" }, + { TlsHashAlgoSha224, "SHA224" }, + { TlsHashAlgoSha256, "SHA256" }, + { TlsHashAlgoSha384, "SHA384" }, + { TlsHashAlgoSha512, "SHA512" }, +}; + +STATIC CONST TLS_ALGO_TO_NAME TlsSignatureAlgoToName[] = { + { TlsSignatureAlgoAnonymous, NULL }, + { TlsSignatureAlgoRsa, "RSA" }, + { TlsSignatureAlgoDsa, "DSA" }, + { TlsSignatureAlgoEcdsa, "ECDSA" }, }; /** @@ -70,12 +108,12 @@ STATIC CONST TLS_CIPHER_MAPPING TlsCipherMappingTable[] = { STATIC CONST TLS_CIPHER_MAPPING * TlsGetCipherMapping ( - IN UINT16 CipherId + IN UINT16 CipherId ) { - INTN Left; - INTN Right; - INTN Middle; + INTN Left; + INTN Right; + INTN Middle; // // Binary Search Cipher Mapping Table for IANA-OpenSSL Cipher Translation @@ -96,7 +134,7 @@ TlsGetCipherMapping ( if (CipherId < TlsCipherMappingTable[Middle].IanaCipher) { Right = Middle - 1; } else { - Left = Middle + 1; + Left = Middle + 1; } } @@ -123,16 +161,16 @@ TlsGetCipherMapping ( EFI_STATUS EFIAPI TlsSetVersion ( - IN VOID *Tls, - IN UINT8 MajorVer, - IN UINT8 MinorVer + IN VOID *Tls, + IN UINT8 MajorVer, + IN UINT8 MinorVer ) { TLS_CONNECTION *TlsConn; UINT16 ProtoVersion; TlsConn = (TLS_CONNECTION *)Tls; - if (TlsConn == NULL || TlsConn->Ssl == NULL) { + if ((TlsConn == NULL) || (TlsConn->Ssl == NULL)) { return EFI_INVALID_PARAMETER; } @@ -142,35 +180,35 @@ TlsSetVersion ( // Bound TLS method to the particular specified version. // switch (ProtoVersion) { - case TLS1_VERSION: - // - // TLS 1.0 - // - SSL_set_min_proto_version (TlsConn->Ssl, TLS1_VERSION); - SSL_set_max_proto_version (TlsConn->Ssl, TLS1_VERSION); - break; - case TLS1_1_VERSION: - // - // TLS 1.1 - // - SSL_set_min_proto_version (TlsConn->Ssl, TLS1_1_VERSION); - SSL_set_max_proto_version (TlsConn->Ssl, TLS1_1_VERSION); - break; - case TLS1_2_VERSION: - // - // TLS 1.2 - // - SSL_set_min_proto_version (TlsConn->Ssl, TLS1_2_VERSION); - SSL_set_max_proto_version (TlsConn->Ssl, TLS1_2_VERSION); - break; - default: - // - // Unsupported Protocol Version - // - return EFI_UNSUPPORTED; + case TLS1_VERSION: + // + // TLS 1.0 + // + SSL_set_min_proto_version (TlsConn->Ssl, TLS1_VERSION); + SSL_set_max_proto_version (TlsConn->Ssl, TLS1_VERSION); + break; + case TLS1_1_VERSION: + // + // TLS 1.1 + // + SSL_set_min_proto_version (TlsConn->Ssl, TLS1_1_VERSION); + SSL_set_max_proto_version (TlsConn->Ssl, TLS1_1_VERSION); + break; + case TLS1_2_VERSION: + // + // TLS 1.2 + // + SSL_set_min_proto_version (TlsConn->Ssl, TLS1_2_VERSION); + SSL_set_max_proto_version (TlsConn->Ssl, TLS1_2_VERSION); + break; + default: + // + // Unsupported Protocol Version + // + return EFI_UNSUPPORTED; } - return EFI_SUCCESS;; + return EFI_SUCCESS; } /** @@ -189,14 +227,14 @@ TlsSetVersion ( EFI_STATUS EFIAPI TlsSetConnectionEnd ( - IN VOID *Tls, - IN BOOLEAN IsServer + IN VOID *Tls, + IN BOOLEAN IsServer ) { TLS_CONNECTION *TlsConn; - TlsConn = (TLS_CONNECTION *) Tls; - if (TlsConn == NULL || TlsConn->Ssl == NULL) { + TlsConn = (TLS_CONNECTION *)Tls; + if ((TlsConn == NULL) || (TlsConn->Ssl == NULL)) { return EFI_INVALID_PARAMETER; } @@ -210,7 +248,7 @@ TlsSetConnectionEnd ( // Set TLS to work in Server mode. // It is unsupported for UEFI version currently. // - //SSL_set_accept_state (TlsConn->Ssl); + // SSL_set_accept_state (TlsConn->Ssl); return EFI_UNSUPPORTED; } @@ -223,68 +261,226 @@ TlsSetConnectionEnd ( This function sets the ciphers for use by a specified TLS object. @param[in] Tls Pointer to a TLS object. - @param[in] CipherId Pointer to a UINT16 cipher Id. + @param[in] CipherId Array of UINT16 cipher identifiers. Each UINT16 + cipher identifier comes from the TLS Cipher Suite + Registry of the IANA, interpreting Byte1 and Byte2 + in network (big endian) byte order. @param[in] CipherNum The number of cipher in the list. @retval EFI_SUCCESS The ciphers list was set successfully. @retval EFI_INVALID_PARAMETER The parameter is invalid. - @retval EFI_UNSUPPORTED Unsupported TLS cipher in the list. + @retval EFI_UNSUPPORTED No supported TLS cipher was found in CipherId. + @retval EFI_OUT_OF_RESOURCES Memory allocation failed. **/ EFI_STATUS EFIAPI TlsSetCipherList ( - IN VOID *Tls, - IN UINT16 *CipherId, - IN UINTN CipherNum + IN VOID *Tls, + IN UINT16 *CipherId, + IN UINTN CipherNum ) { - TLS_CONNECTION *TlsConn; - UINTN Index; - CONST TLS_CIPHER_MAPPING *Mapping; - CONST CHAR8 *MappingName; - CHAR8 CipherString[500]; - - TlsConn = (TLS_CONNECTION *) Tls; - if (TlsConn == NULL || TlsConn->Ssl == NULL || CipherId == NULL) { + TLS_CONNECTION *TlsConn; + EFI_STATUS Status; + CONST TLS_CIPHER_MAPPING **MappedCipher; + UINTN MappedCipherBytes; + UINTN MappedCipherCount; + UINTN CipherStringSize; + UINTN Index; + CONST TLS_CIPHER_MAPPING *Mapping; + CHAR8 *CipherString; + CHAR8 *CipherStringPosition; + + TlsConn = (TLS_CONNECTION *)Tls; + if ((TlsConn == NULL) || (TlsConn->Ssl == NULL) || (CipherId == NULL)) { return EFI_INVALID_PARAMETER; } - Mapping = NULL; - MappingName = NULL; + // + // Allocate the MappedCipher array for recording the mappings that we find + // for the input IANA identifiers in CipherId. + // + Status = SafeUintnMult ( + CipherNum, + sizeof (*MappedCipher), + &MappedCipherBytes + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } - memset (CipherString, 0, sizeof (CipherString)); + MappedCipher = AllocatePool (MappedCipherBytes); + if (MappedCipher == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Map the cipher IDs, and count the number of bytes for the full + // CipherString. + // + MappedCipherCount = 0; + CipherStringSize = 0; for (Index = 0; Index < CipherNum; Index++) { // - // Handling OpenSSL / RFC Cipher name mapping. + // Look up the IANA-to-OpenSSL mapping. // - Mapping = TlsGetCipherMapping (*(CipherId + Index)); + Mapping = TlsGetCipherMapping (CipherId[Index]); if (Mapping == NULL) { - return EFI_UNSUPPORTED; - } - MappingName = Mapping->OpensslCipher; - - if (Index != 0) { + DEBUG (( + DEBUG_VERBOSE, + "%a:%a: skipping CipherId=0x%04x\n", + gEfiCallerBaseName, + __FUNCTION__, + CipherId[Index] + )); // - // The ciphers were separated by a colon. + // Skipping the cipher is valid because CipherId is an ordered + // preference list of ciphers, thus we can filter it as long as we + // don't change the relative order of elements on it. // - AsciiStrCatS (CipherString, sizeof (CipherString), ":"); + continue; + } + + // + // Accumulate Mapping->OpensslCipherLength into CipherStringSize. If this + // is not the first successful mapping, account for a colon (":") prefix + // too. + // + if (MappedCipherCount > 0) { + Status = SafeUintnAdd (CipherStringSize, 1, &CipherStringSize); + if (EFI_ERROR (Status)) { + Status = EFI_OUT_OF_RESOURCES; + goto FreeMappedCipher; + } + } + + Status = SafeUintnAdd ( + CipherStringSize, + Mapping->OpensslCipherLength, + &CipherStringSize + ); + if (EFI_ERROR (Status)) { + Status = EFI_OUT_OF_RESOURCES; + goto FreeMappedCipher; } - AsciiStrCatS (CipherString, sizeof (CipherString), MappingName); + // + // Record the mapping. + // + MappedCipher[MappedCipherCount++] = Mapping; } - AsciiStrCatS (CipherString, sizeof (CipherString), ":@STRENGTH"); + // + // Verify that at least one IANA cipher ID could be mapped; account for the + // terminating NUL character in CipherStringSize; allocate CipherString. + // + if (MappedCipherCount == 0) { + DEBUG (( + DEBUG_ERROR, + "%a:%a: no CipherId could be mapped\n", + gEfiCallerBaseName, + __FUNCTION__ + )); + Status = EFI_UNSUPPORTED; + goto FreeMappedCipher; + } + + Status = SafeUintnAdd (CipherStringSize, 1, &CipherStringSize); + if (EFI_ERROR (Status)) { + Status = EFI_OUT_OF_RESOURCES; + goto FreeMappedCipher; + } + + CipherString = AllocatePool (CipherStringSize); + if (CipherString == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto FreeMappedCipher; + } + + // + // Go over the collected mappings and populate CipherString. + // + CipherStringPosition = CipherString; + for (Index = 0; Index < MappedCipherCount; Index++) { + Mapping = MappedCipher[Index]; + // + // Append the colon (":") prefix except for the first mapping, then append + // Mapping->OpensslCipher. + // + if (Index > 0) { + *(CipherStringPosition++) = ':'; + } + + CopyMem ( + CipherStringPosition, + Mapping->OpensslCipher, + Mapping->OpensslCipherLength + ); + CipherStringPosition += Mapping->OpensslCipherLength; + } + + // + // NUL-terminate CipherString. + // + *(CipherStringPosition++) = '\0'; + ASSERT (CipherStringPosition == CipherString + CipherStringSize); + + // + // Log CipherString for debugging. CipherString can be very long if the + // caller provided a large CipherId array, so log CipherString in segments of + // 79 non-newline characters. (MAX_DEBUG_MESSAGE_LENGTH is usually 0x100 in + // DebugLib instances.) + // + DEBUG_CODE_BEGIN (); + UINTN FullLength; + UINTN SegmentLength; + + FullLength = CipherStringSize - 1; + DEBUG (( + DEBUG_VERBOSE, + "%a:%a: CipherString={\n", + gEfiCallerBaseName, + __FUNCTION__ + )); + for (CipherStringPosition = CipherString; + CipherStringPosition < CipherString + FullLength; + CipherStringPosition += SegmentLength) + { + SegmentLength = FullLength - (CipherStringPosition - CipherString); + if (SegmentLength > 79) { + SegmentLength = 79; + } + + DEBUG ((DEBUG_VERBOSE, "%.*a\n", SegmentLength, CipherStringPosition)); + } + + DEBUG ((DEBUG_VERBOSE, "}\n")); + // + // Restore the pre-debug value of CipherStringPosition by skipping over the + // trailing NUL. + // + CipherStringPosition++; + ASSERT (CipherStringPosition == CipherString + CipherStringSize); + DEBUG_CODE_END (); // // Sets the ciphers for use by the Tls object. // if (SSL_set_cipher_list (TlsConn->Ssl, CipherString) <= 0) { - return EFI_UNSUPPORTED; + Status = EFI_UNSUPPORTED; + goto FreeCipherString; } - return EFI_SUCCESS; + Status = EFI_SUCCESS; + +FreeCipherString: + FreePool (CipherString); + +FreeMappedCipher: + FreePool ((VOID *)MappedCipher); + + return Status; } /** @@ -302,7 +498,7 @@ TlsSetCipherList ( EFI_STATUS EFIAPI TlsSetCompressionMethod ( - IN UINT8 CompMethod + IN UINT8 CompMethod ) { COMP_METHOD *Cm; @@ -319,7 +515,7 @@ TlsSetCompressionMethod ( // return EFI_SUCCESS; } else if (CompMethod == 1) { - Cm = COMP_zlib(); + Cm = COMP_zlib (); } else { return EFI_UNSUPPORTED; } @@ -348,14 +544,14 @@ TlsSetCompressionMethod ( VOID EFIAPI TlsSetVerify ( - IN VOID *Tls, - IN UINT32 VerifyMode + IN VOID *Tls, + IN UINT32 VerifyMode ) { TLS_CONNECTION *TlsConn; - TlsConn = (TLS_CONNECTION *) Tls; - if (TlsConn == NULL || TlsConn->Ssl == NULL) { + TlsConn = (TLS_CONNECTION *)Tls; + if ((TlsConn == NULL) || (TlsConn->Ssl == NULL)) { return; } @@ -365,6 +561,71 @@ TlsSetVerify ( SSL_set_verify (TlsConn->Ssl, VerifyMode, NULL); } +/** + Set the specified host name to be verified. + + @param[in] Tls Pointer to the TLS object. + @param[in] Flags The setting flags during the validation. + @param[in] HostName The specified host name to be verified. + + @retval EFI_SUCCESS The HostName setting was set successfully. + @retval EFI_INVALID_PARAMETER The parameter is invalid. + @retval EFI_ABORTED Invalid HostName setting. + +**/ +EFI_STATUS +EFIAPI +TlsSetVerifyHost ( + IN VOID *Tls, + IN UINT32 Flags, + IN CHAR8 *HostName + ) +{ + TLS_CONNECTION *TlsConn; + X509_VERIFY_PARAM *VerifyParam; + UINTN BinaryAddressSize; + UINT8 BinaryAddress[MAX (NS_INADDRSZ, NS_IN6ADDRSZ)]; + INTN ParamStatus; + + TlsConn = (TLS_CONNECTION *)Tls; + if ((TlsConn == NULL) || (TlsConn->Ssl == NULL) || (HostName == NULL)) { + return EFI_INVALID_PARAMETER; + } + + SSL_set_hostflags (TlsConn->Ssl, Flags); + + VerifyParam = SSL_get0_param (TlsConn->Ssl); + ASSERT (VerifyParam != NULL); + + BinaryAddressSize = 0; + if (inet_pton (AF_INET6, HostName, BinaryAddress) == 1) { + BinaryAddressSize = NS_IN6ADDRSZ; + } else if (inet_pton (AF_INET, HostName, BinaryAddress) == 1) { + BinaryAddressSize = NS_INADDRSZ; + } + + if (BinaryAddressSize > 0) { + DEBUG (( + DEBUG_VERBOSE, + "%a:%a: parsed \"%a\" as an IPv%c address " + "literal\n", + gEfiCallerBaseName, + __FUNCTION__, + HostName, + (UINTN)((BinaryAddressSize == NS_IN6ADDRSZ) ? '6' : '4') + )); + ParamStatus = X509_VERIFY_PARAM_set1_ip ( + VerifyParam, + BinaryAddress, + BinaryAddressSize + ); + } else { + ParamStatus = X509_VERIFY_PARAM_set1_host (VerifyParam, HostName, 0); + } + + return (ParamStatus == 1) ? EFI_SUCCESS : EFI_ABORTED; +} + /** Sets a TLS/SSL session ID to be used during TLS/SSL connect. @@ -383,18 +644,18 @@ TlsSetVerify ( EFI_STATUS EFIAPI TlsSetSessionId ( - IN VOID *Tls, - IN UINT8 *SessionId, - IN UINT16 SessionIdLen + IN VOID *Tls, + IN UINT8 *SessionId, + IN UINT16 SessionIdLen ) { TLS_CONNECTION *TlsConn; SSL_SESSION *Session; - TlsConn = (TLS_CONNECTION *) Tls; + TlsConn = (TLS_CONNECTION *)Tls; Session = NULL; - if (TlsConn == NULL || TlsConn->Ssl == NULL || SessionId == NULL) { + if ((TlsConn == NULL) || (TlsConn->Ssl == NULL) || (SessionId == NULL)) { return EFI_INVALID_PARAMETER; } @@ -428,9 +689,9 @@ TlsSetSessionId ( EFI_STATUS EFIAPI TlsSetCaCertificate ( - IN VOID *Tls, - IN VOID *Data, - IN UINTN DataSize + IN VOID *Tls, + IN VOID *Data, + IN UINTN DataSize ) { BIO *BioCert; @@ -446,10 +707,10 @@ TlsSetCaCertificate ( Cert = NULL; X509Store = NULL; Status = EFI_SUCCESS; - TlsConn = (TLS_CONNECTION *) Tls; + TlsConn = (TLS_CONNECTION *)Tls; Ret = 0; - if (TlsConn == NULL || TlsConn->Ssl == NULL || Data == NULL || DataSize == 0) { + if ((TlsConn == NULL) || (TlsConn->Ssl == NULL) || (Data == NULL) || (DataSize == 0)) { return EFI_INVALID_PARAMETER; } @@ -457,7 +718,7 @@ TlsSetCaCertificate ( // DER-encoded binary X.509 certificate or PEM-encoded X.509 certificate. // Determine whether certificate is from DER encoding, if so, translate it to X509 structure. // - Cert = d2i_X509 (NULL, (const unsigned char ** )&Data, (long) DataSize); + Cert = d2i_X509 (NULL, (const unsigned char **)&Data, (long)DataSize); if (Cert == NULL) { // // Certificate is from PEM encoding. @@ -468,7 +729,7 @@ TlsSetCaCertificate ( goto ON_EXIT; } - if (BIO_write (BioCert, Data, (UINT32) DataSize) <= 0) { + if (BIO_write (BioCert, Data, (UINT32)DataSize) <= 0) { Status = EFI_ABORTED; goto ON_EXIT; } @@ -483,8 +744,8 @@ TlsSetCaCertificate ( SslCtx = SSL_get_SSL_CTX (TlsConn->Ssl); X509Store = SSL_CTX_get_cert_store (SslCtx); if (X509Store == NULL) { - Status = EFI_ABORTED; - goto ON_EXIT; + Status = EFI_ABORTED; + goto ON_EXIT; } // @@ -496,8 +757,9 @@ TlsSetCaCertificate ( // // Ignore "already in table" errors // - if (!(ERR_GET_FUNC (ErrorCode) == X509_F_X509_STORE_ADD_CERT && - ERR_GET_REASON (ErrorCode) == X509_R_CERT_ALREADY_IN_HASH_TABLE)) { + if (!((ERR_GET_FUNC (ErrorCode) == X509_F_X509_STORE_ADD_CERT) && + (ERR_GET_REASON (ErrorCode) == X509_R_CERT_ALREADY_IN_HASH_TABLE))) + { Status = EFI_ABORTED; goto ON_EXIT; } @@ -535,9 +797,9 @@ ON_EXIT: EFI_STATUS EFIAPI TlsSetHostPublicCert ( - IN VOID *Tls, - IN VOID *Data, - IN UINTN DataSize + IN VOID *Tls, + IN VOID *Data, + IN UINTN DataSize ) { BIO *BioCert; @@ -548,9 +810,9 @@ TlsSetHostPublicCert ( BioCert = NULL; Cert = NULL; Status = EFI_SUCCESS; - TlsConn = (TLS_CONNECTION *) Tls; + TlsConn = (TLS_CONNECTION *)Tls; - if (TlsConn == NULL || TlsConn->Ssl == NULL || Data == NULL || DataSize == 0) { + if ((TlsConn == NULL) || (TlsConn->Ssl == NULL) || (Data == NULL) || (DataSize == 0)) { return EFI_INVALID_PARAMETER; } @@ -558,7 +820,7 @@ TlsSetHostPublicCert ( // DER-encoded binary X.509 certificate or PEM-encoded X.509 certificate. // Determine whether certificate is from DER encoding, if so, translate it to X509 structure. // - Cert = d2i_X509 (NULL, (const unsigned char ** )&Data, (long) DataSize); + Cert = d2i_X509 (NULL, (const unsigned char **)&Data, (long)DataSize); if (Cert == NULL) { // // Certificate is from PEM encoding. @@ -569,7 +831,7 @@ TlsSetHostPublicCert ( goto ON_EXIT; } - if (BIO_write (BioCert, Data, (UINT32) DataSize) <= 0) { + if (BIO_write (BioCert, Data, (UINT32)DataSize) <= 0) { Status = EFI_ABORTED; goto ON_EXIT; } @@ -601,11 +863,107 @@ ON_EXIT: /** Adds the local private key to the specified TLS object. - This function adds the local private key (PEM-encoded RSA or PKCS#8 private + This function adds the local private key (DER-encoded or PEM-encoded or PKCS#8 private key) into the specified TLS object for TLS negotiation. @param[in] Tls Pointer to the TLS object. - @param[in] Data Pointer to the data buffer of a PEM-encoded RSA + @param[in] Data Pointer to the data buffer of a DER-encoded or PEM-encoded + or PKCS#8 private key. + @param[in] DataSize The size of data buffer in bytes. + @param[in] Password Pointer to NULL-terminated private key password, set it to NULL + if private key not encrypted. + + @retval EFI_SUCCESS The operation succeeded. + @retval EFI_UNSUPPORTED This function is not supported. + @retval EFI_ABORTED Invalid private key data. + +**/ +EFI_STATUS +EFIAPI +TlsSetHostPrivateKeyEx ( + IN VOID *Tls, + IN VOID *Data, + IN UINTN DataSize, + IN VOID *Password OPTIONAL + ) +{ + TLS_CONNECTION *TlsConn; + BIO *Bio; + EVP_PKEY *Pkey; + BOOLEAN Verify; + + TlsConn = (TLS_CONNECTION *)Tls; + + if ((TlsConn == NULL) || (TlsConn->Ssl == NULL) || (Data == NULL) || (DataSize == 0)) { + return EFI_INVALID_PARAMETER; + } + + // Try to parse the private key in DER format or un-encrypted PKC#8 + if (SSL_use_PrivateKey_ASN1 ( + EVP_PKEY_RSA, + TlsConn->Ssl, + Data, + (long)DataSize + ) == 1) + { + goto verify; + } + + if (SSL_use_PrivateKey_ASN1 ( + EVP_PKEY_DSA, + TlsConn->Ssl, + Data, + (long)DataSize + ) == 1) + { + goto verify; + } + + if (SSL_use_PrivateKey_ASN1 ( + EVP_PKEY_EC, + TlsConn->Ssl, + Data, + (long)DataSize + ) == 1) + { + goto verify; + } + + // Try to parse the private key in PEM format or encrypted PKC#8 + Bio = BIO_new_mem_buf (Data, (int)DataSize); + if (Bio != NULL) { + Verify = FALSE; + Pkey = PEM_read_bio_PrivateKey (Bio, NULL, NULL, Password); + if ((Pkey != NULL) && (SSL_use_PrivateKey (TlsConn->Ssl, Pkey) == 1)) { + Verify = TRUE; + } + + EVP_PKEY_free (Pkey); + BIO_free (Bio); + + if (Verify) { + goto verify; + } + } + + return EFI_ABORTED; + +verify: + if (SSL_check_private_key (TlsConn->Ssl) == 1) { + return EFI_SUCCESS; + } + + return EFI_ABORTED; +} + +/** + Adds the local private key to the specified TLS object. + + This function adds the local private key (DER-encoded or PEM-encoded or PKCS#8 private + key) into the specified TLS object for TLS negotiation. + + @param[in] Tls Pointer to the TLS object. + @param[in] Data Pointer to the data buffer of a DER-encoded or PEM-encoded or PKCS#8 private key. @param[in] DataSize The size of data buffer in bytes. @@ -617,12 +975,12 @@ ON_EXIT: EFI_STATUS EFIAPI TlsSetHostPrivateKey ( - IN VOID *Tls, - IN VOID *Data, - IN UINTN DataSize + IN VOID *Tls, + IN VOID *Data, + IN UINTN DataSize ) { - return EFI_UNSUPPORTED; + return TlsSetHostPrivateKeyEx (Tls, Data, DataSize, NULL); } /** @@ -642,13 +1000,191 @@ TlsSetHostPrivateKey ( EFI_STATUS EFIAPI TlsSetCertRevocationList ( - IN VOID *Data, - IN UINTN DataSize + IN VOID *Data, + IN UINTN DataSize ) { return EFI_UNSUPPORTED; } +/** + Set the signature algorithm list to used by the TLS object. + + This function sets the signature algorithms for use by a specified TLS object. + + @param[in] Tls Pointer to a TLS object. + @param[in] Data Array of UINT8 of signature algorithms. The array consists of + pairs of the hash algorithm and the signature algorithm as defined + in RFC 5246 + @param[in] DataSize The length the SignatureAlgoList. Must be divisible by 2. + + @retval EFI_SUCCESS The signature algorithm list was set successfully. + @retval EFI_INVALID_PARAMETER The parameters are invalid. + @retval EFI_UNSUPPORTED No supported TLS signature algorithm was found in SignatureAlgoList + @retval EFI_OUT_OF_RESOURCES Memory allocation failed. + +**/ +EFI_STATUS +EFIAPI +TlsSetSignatureAlgoList ( + IN VOID *Tls, + IN UINT8 *Data, + IN UINTN DataSize + ) +{ + TLS_CONNECTION *TlsConn; + UINTN Index; + UINTN SignAlgoStrSize; + CHAR8 *SignAlgoStr; + CHAR8 *Pos; + UINT8 *SignatureAlgoList; + EFI_STATUS Status; + + TlsConn = (TLS_CONNECTION *)Tls; + + if ((TlsConn == NULL) || (TlsConn->Ssl == NULL) || (Data == NULL) || (DataSize < 3) || + ((DataSize % 2) == 0) || (Data[0] != DataSize - 1)) + { + return EFI_INVALID_PARAMETER; + } + + SignatureAlgoList = Data + 1; + SignAlgoStrSize = 0; + for (Index = 0; Index < Data[0]; Index += 2) { + CONST CHAR8 *Tmp; + + if (SignatureAlgoList[Index] >= ARRAY_SIZE (TlsHashAlgoToName)) { + return EFI_INVALID_PARAMETER; + } + + Tmp = TlsHashAlgoToName[SignatureAlgoList[Index]].Name; + if (!Tmp) { + return EFI_INVALID_PARAMETER; + } + + // Add 1 for the '+' + SignAlgoStrSize += AsciiStrLen (Tmp) + 1; + + if (SignatureAlgoList[Index + 1] >= ARRAY_SIZE (TlsSignatureAlgoToName)) { + return EFI_INVALID_PARAMETER; + } + + Tmp = TlsSignatureAlgoToName[SignatureAlgoList[Index + 1]].Name; + if (!Tmp) { + return EFI_INVALID_PARAMETER; + } + + // Add 1 for the ':' or for the NULL terminator + SignAlgoStrSize += AsciiStrLen (Tmp) + 1; + } + + if (!SignAlgoStrSize) { + return EFI_UNSUPPORTED; + } + + SignAlgoStr = AllocatePool (SignAlgoStrSize); + if (SignAlgoStr == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Pos = SignAlgoStr; + for (Index = 0; Index < Data[0]; Index += 2) { + CONST CHAR8 *Tmp; + + Tmp = TlsHashAlgoToName[SignatureAlgoList[Index]].Name; + CopyMem (Pos, Tmp, AsciiStrLen (Tmp)); + Pos += AsciiStrLen (Tmp); + *Pos++ = '+'; + + Tmp = TlsSignatureAlgoToName[SignatureAlgoList[Index + 1]].Name; + CopyMem (Pos, Tmp, AsciiStrLen (Tmp)); + Pos += AsciiStrLen (Tmp); + *Pos++ = ':'; + } + + *(Pos - 1) = '\0'; + + if (SSL_set1_sigalgs_list (TlsConn->Ssl, SignAlgoStr) < 1) { + Status = EFI_INVALID_PARAMETER; + } else { + Status = EFI_SUCCESS; + } + + FreePool (SignAlgoStr); + return Status; +} + +/** + Set the EC curve to be used for TLS flows + + This function sets the EC curve to be used for TLS flows. + + @param[in] Tls Pointer to a TLS object. + @param[in] Data An EC named curve as defined in section 5.1.1 of RFC 4492. + @param[in] DataSize Size of Data, it should be sizeof (UINT32) + + @retval EFI_SUCCESS The EC curve was set successfully. + @retval EFI_INVALID_PARAMETER The parameters are invalid. + @retval EFI_UNSUPPORTED The requested TLS EC curve is not supported + +**/ +EFI_STATUS +EFIAPI +TlsSetEcCurve ( + IN VOID *Tls, + IN UINT8 *Data, + IN UINTN DataSize + ) +{ + TLS_CONNECTION *TlsConn; + EC_KEY *EcKey; + INT32 Nid; + INT32 Ret; + + TlsConn = (TLS_CONNECTION *)Tls; + + if ((TlsConn == NULL) || (TlsConn->Ssl == NULL) || (Data == NULL) || (DataSize != sizeof (UINT32))) { + return EFI_INVALID_PARAMETER; + } + + switch (*((UINT32 *)Data)) { + case TlsEcNamedCurveSecp256r1: + return EFI_UNSUPPORTED; + case TlsEcNamedCurveSecp384r1: + Nid = NID_secp384r1; + break; + case TlsEcNamedCurveSecp521r1: + Nid = NID_secp521r1; + break; + case TlsEcNamedCurveX25519: + Nid = NID_X25519; + break; + case TlsEcNamedCurveX448: + Nid = NID_X448; + break; + default: + return EFI_UNSUPPORTED; + } + + if (SSL_set1_curves (TlsConn->Ssl, &Nid, 1) != 1) { + return EFI_UNSUPPORTED; + } + + EcKey = EC_KEY_new_by_curve_name (Nid); + if (EcKey == NULL) { + return EFI_UNSUPPORTED; + } + + Ret = SSL_set_tmp_ecdh (TlsConn->Ssl, EcKey); + EC_KEY_free (EcKey); + + if (Ret != 1) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + /** Gets the protocol version used by the specified TLS connection. @@ -665,12 +1201,12 @@ TlsSetCertRevocationList ( UINT16 EFIAPI TlsGetVersion ( - IN VOID *Tls + IN VOID *Tls ) { TLS_CONNECTION *TlsConn; - TlsConn = (TLS_CONNECTION *) Tls; + TlsConn = (TLS_CONNECTION *)Tls; ASSERT (TlsConn != NULL); @@ -693,12 +1229,12 @@ TlsGetVersion ( UINT8 EFIAPI TlsGetConnectionEnd ( - IN VOID *Tls + IN VOID *Tls ) { TLS_CONNECTION *TlsConn; - TlsConn = (TLS_CONNECTION *) Tls; + TlsConn = (TLS_CONNECTION *)Tls; ASSERT (TlsConn != NULL); @@ -722,17 +1258,17 @@ TlsGetConnectionEnd ( EFI_STATUS EFIAPI TlsGetCurrentCipher ( - IN VOID *Tls, - IN OUT UINT16 *CipherId + IN VOID *Tls, + IN OUT UINT16 *CipherId ) { TLS_CONNECTION *TlsConn; CONST SSL_CIPHER *Cipher; - TlsConn = (TLS_CONNECTION *) Tls; + TlsConn = (TLS_CONNECTION *)Tls; Cipher = NULL; - if (TlsConn == NULL || TlsConn->Ssl == NULL || CipherId == NULL) { + if ((TlsConn == NULL) || (TlsConn->Ssl == NULL) || (CipherId == NULL)) { return EFI_INVALID_PARAMETER; } @@ -765,8 +1301,8 @@ TlsGetCurrentCipher ( EFI_STATUS EFIAPI TlsGetCurrentCompressionId ( - IN VOID *Tls, - IN OUT UINT8 *CompressionId + IN VOID *Tls, + IN OUT UINT8 *CompressionId ) { return EFI_UNSUPPORTED; @@ -788,12 +1324,12 @@ TlsGetCurrentCompressionId ( UINT32 EFIAPI TlsGetVerify ( - IN VOID *Tls + IN VOID *Tls ) { TLS_CONNECTION *TlsConn; - TlsConn = (TLS_CONNECTION *) Tls; + TlsConn = (TLS_CONNECTION *)Tls; ASSERT (TlsConn != NULL); @@ -818,19 +1354,19 @@ TlsGetVerify ( EFI_STATUS EFIAPI TlsGetSessionId ( - IN VOID *Tls, - IN OUT UINT8 *SessionId, - IN OUT UINT16 *SessionIdLen + IN VOID *Tls, + IN OUT UINT8 *SessionId, + IN OUT UINT16 *SessionIdLen ) { TLS_CONNECTION *TlsConn; SSL_SESSION *Session; CONST UINT8 *SslSessionId; - TlsConn = (TLS_CONNECTION *) Tls; + TlsConn = (TLS_CONNECTION *)Tls; Session = NULL; - if (TlsConn == NULL || TlsConn->Ssl == NULL || SessionId == NULL || SessionIdLen == NULL) { + if ((TlsConn == NULL) || (TlsConn->Ssl == NULL) || (SessionId == NULL) || (SessionIdLen == NULL)) { return EFI_INVALID_PARAMETER; } @@ -859,15 +1395,15 @@ TlsGetSessionId ( VOID EFIAPI TlsGetClientRandom ( - IN VOID *Tls, - IN OUT UINT8 *ClientRandom + IN VOID *Tls, + IN OUT UINT8 *ClientRandom ) { TLS_CONNECTION *TlsConn; - TlsConn = (TLS_CONNECTION *) Tls; + TlsConn = (TLS_CONNECTION *)Tls; - if (TlsConn == NULL || TlsConn->Ssl == NULL || ClientRandom == NULL) { + if ((TlsConn == NULL) || (TlsConn->Ssl == NULL) || (ClientRandom == NULL)) { return; } @@ -888,15 +1424,15 @@ TlsGetClientRandom ( VOID EFIAPI TlsGetServerRandom ( - IN VOID *Tls, - IN OUT UINT8 *ServerRandom + IN VOID *Tls, + IN OUT UINT8 *ServerRandom ) { TLS_CONNECTION *TlsConn; - TlsConn = (TLS_CONNECTION *) Tls; + TlsConn = (TLS_CONNECTION *)Tls; - if (TlsConn == NULL || TlsConn->Ssl == NULL || ServerRandom == NULL) { + if ((TlsConn == NULL) || (TlsConn->Ssl == NULL) || (ServerRandom == NULL)) { return; } @@ -920,17 +1456,17 @@ TlsGetServerRandom ( EFI_STATUS EFIAPI TlsGetKeyMaterial ( - IN VOID *Tls, - IN OUT UINT8 *KeyMaterial + IN VOID *Tls, + IN OUT UINT8 *KeyMaterial ) { TLS_CONNECTION *TlsConn; SSL_SESSION *Session; - TlsConn = (TLS_CONNECTION *) Tls; + TlsConn = (TLS_CONNECTION *)Tls; Session = NULL; - if (TlsConn == NULL || TlsConn->Ssl == NULL || KeyMaterial == NULL) { + if ((TlsConn == NULL) || (TlsConn->Ssl == NULL) || (KeyMaterial == NULL)) { return EFI_INVALID_PARAMETER; } @@ -964,9 +1500,9 @@ TlsGetKeyMaterial ( EFI_STATUS EFIAPI TlsGetCaCertificate ( - IN VOID *Tls, - OUT VOID *Data, - IN OUT UINTN *DataSize + IN VOID *Tls, + OUT VOID *Data, + IN OUT UINTN *DataSize ) { return EFI_UNSUPPORTED; @@ -992,22 +1528,22 @@ TlsGetCaCertificate ( EFI_STATUS EFIAPI TlsGetHostPublicCert ( - IN VOID *Tls, - OUT VOID *Data, - IN OUT UINTN *DataSize + IN VOID *Tls, + OUT VOID *Data, + IN OUT UINTN *DataSize ) { X509 *Cert; TLS_CONNECTION *TlsConn; Cert = NULL; - TlsConn = (TLS_CONNECTION *) Tls; + TlsConn = (TLS_CONNECTION *)Tls; - if (TlsConn == NULL || TlsConn->Ssl == NULL || DataSize == NULL || (*DataSize != 0 && Data == NULL)) { + if ((TlsConn == NULL) || (TlsConn->Ssl == NULL) || (DataSize == NULL) || ((*DataSize != 0) && (Data == NULL))) { return EFI_INVALID_PARAMETER; } - Cert = SSL_get_certificate(TlsConn->Ssl); + Cert = SSL_get_certificate (TlsConn->Ssl); if (Cert == NULL) { return EFI_NOT_FOUND; } @@ -1015,12 +1551,12 @@ TlsGetHostPublicCert ( // // Only DER encoding is supported currently. // - if (*DataSize < (UINTN) i2d_X509 (Cert, NULL)) { - *DataSize = (UINTN) i2d_X509 (Cert, NULL); + if (*DataSize < (UINTN)i2d_X509 (Cert, NULL)) { + *DataSize = (UINTN)i2d_X509 (Cert, NULL); return EFI_BUFFER_TOO_SMALL; } - *DataSize = (UINTN) i2d_X509 (Cert, (unsigned char **) &Data); + *DataSize = (UINTN)i2d_X509 (Cert, (unsigned char **)&Data); return EFI_SUCCESS; } @@ -1044,9 +1580,9 @@ TlsGetHostPublicCert ( EFI_STATUS EFIAPI TlsGetHostPrivateKey ( - IN VOID *Tls, - OUT VOID *Data, - IN OUT UINTN *DataSize + IN VOID *Tls, + OUT VOID *Data, + IN OUT UINTN *DataSize ) { return EFI_UNSUPPORTED; @@ -1070,10 +1606,59 @@ TlsGetHostPrivateKey ( EFI_STATUS EFIAPI TlsGetCertRevocationList ( - OUT VOID *Data, - IN OUT UINTN *DataSize + OUT VOID *Data, + IN OUT UINTN *DataSize ) { return EFI_UNSUPPORTED; } +/** + Derive keying material from a TLS connection. + + This function exports keying material using the mechanism described in RFC + 5705. + + @param[in] Tls Pointer to the TLS object + @param[in] Label Description of the key for the PRF function + @param[in] Context Optional context + @param[in] ContextLen The length of the context value in bytes + @param[out] KeyBuffer Buffer to hold the output of the TLS-PRF + @param[in] KeyBufferLen The length of the KeyBuffer + + @retval EFI_SUCCESS The operation succeeded. + @retval EFI_INVALID_PARAMETER The TLS object is invalid. + @retval EFI_PROTOCOL_ERROR Some other error occurred. + +**/ +EFI_STATUS +EFIAPI +TlsGetExportKey ( + IN VOID *Tls, + IN CONST VOID *Label, + IN CONST VOID *Context, + IN UINTN ContextLen, + OUT VOID *KeyBuffer, + IN UINTN KeyBufferLen + ) +{ + TLS_CONNECTION *TlsConn; + + TlsConn = (TLS_CONNECTION *)Tls; + + if ((TlsConn == NULL) || (TlsConn->Ssl == NULL)) { + return EFI_INVALID_PARAMETER; + } + + return SSL_export_keying_material ( + TlsConn->Ssl, + KeyBuffer, + KeyBufferLen, + Label, + AsciiStrLen (Label), + Context, + ContextLen, + Context != NULL + ) == 1 ? + EFI_SUCCESS : EFI_PROTOCOL_ERROR; +}