| /** @file | |
| SSL/TLS Configuration Library Wrapper Implementation over OpenSSL. | |
| Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR> | |
| (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include "InternalTlsLib.h" | |
| typedef struct { | |
| // | |
| // IANA/IETF defined Cipher Suite ID | |
| // | |
| UINT16 IanaCipher; | |
| // | |
| // OpenSSL-used Cipher Suite String | |
| // | |
| 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[] = { | |
| 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" }, | |
| }; | |
| /** | |
| Gets the OpenSSL cipher suite mapping for the supplied IANA TLS cipher suite. | |
| @param[in] CipherId The supplied IANA TLS cipher suite ID. | |
| @return The corresponding OpenSSL cipher suite mapping if found, | |
| NULL otherwise. | |
| **/ | |
| STATIC | |
| CONST TLS_CIPHER_MAPPING * | |
| TlsGetCipherMapping ( | |
| IN UINT16 CipherId | |
| ) | |
| { | |
| INTN Left; | |
| INTN Right; | |
| INTN Middle; | |
| // | |
| // Binary Search Cipher Mapping Table for IANA-OpenSSL Cipher Translation | |
| // | |
| Left = 0; | |
| Right = ARRAY_SIZE (TlsCipherMappingTable) - 1; | |
| while (Right >= Left) { | |
| Middle = (Left + Right) / 2; | |
| if (CipherId == TlsCipherMappingTable[Middle].IanaCipher) { | |
| // | |
| // Translate IANA cipher suite ID to OpenSSL name. | |
| // | |
| return &TlsCipherMappingTable[Middle]; | |
| } | |
| if (CipherId < TlsCipherMappingTable[Middle].IanaCipher) { | |
| Right = Middle - 1; | |
| } else { | |
| Left = Middle + 1; | |
| } | |
| } | |
| // | |
| // No Cipher Mapping found, return NULL. | |
| // | |
| return NULL; | |
| } | |
| /** | |
| Set a new TLS/SSL method for a particular TLS object. | |
| This function sets a new TLS/SSL method for a particular TLS object. | |
| @param[in] Tls Pointer to a TLS object. | |
| @param[in] MajorVer Major Version of TLS/SSL Protocol. | |
| @param[in] MinorVer Minor Version of TLS/SSL Protocol. | |
| @retval EFI_SUCCESS The TLS/SSL method was set successfully. | |
| @retval EFI_INVALID_PARAMETER The parameter is invalid. | |
| @retval EFI_UNSUPPORTED Unsupported TLS/SSL method. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| TlsSetVersion ( | |
| IN VOID *Tls, | |
| IN UINT8 MajorVer, | |
| IN UINT8 MinorVer | |
| ) | |
| { | |
| TLS_CONNECTION *TlsConn; | |
| UINT16 ProtoVersion; | |
| TlsConn = (TLS_CONNECTION *)Tls; | |
| if ((TlsConn == NULL) || (TlsConn->Ssl == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| ProtoVersion = (MajorVer << 8) | MinorVer; | |
| // | |
| // 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; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Set TLS object to work in client or server mode. | |
| This function prepares a TLS object to work in client or server mode. | |
| @param[in] Tls Pointer to a TLS object. | |
| @param[in] IsServer Work in server mode. | |
| @retval EFI_SUCCESS The TLS/SSL work mode was set successfully. | |
| @retval EFI_INVALID_PARAMETER The parameter is invalid. | |
| @retval EFI_UNSUPPORTED Unsupported TLS/SSL work mode. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| TlsSetConnectionEnd ( | |
| IN VOID *Tls, | |
| IN BOOLEAN IsServer | |
| ) | |
| { | |
| TLS_CONNECTION *TlsConn; | |
| TlsConn = (TLS_CONNECTION *)Tls; | |
| if ((TlsConn == NULL) || (TlsConn->Ssl == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (!IsServer) { | |
| // | |
| // Set TLS to work in Client mode. | |
| // | |
| SSL_set_connect_state (TlsConn->Ssl); | |
| } else { | |
| // | |
| // Set TLS to work in Server mode. | |
| // It is unsupported for UEFI version currently. | |
| // | |
| // SSL_set_accept_state (TlsConn->Ssl); | |
| return EFI_UNSUPPORTED; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Set the ciphers list to be used by the TLS object. | |
| This function sets the ciphers for use by a specified TLS object. | |
| @param[in] Tls Pointer to a TLS object. | |
| @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 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 | |
| ) | |
| { | |
| 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; | |
| } | |
| // | |
| // 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; | |
| } | |
| 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++) { | |
| // | |
| // Look up the IANA-to-OpenSSL mapping. | |
| // | |
| Mapping = TlsGetCipherMapping (CipherId[Index]); | |
| if (Mapping == NULL) { | |
| DEBUG (( | |
| DEBUG_VERBOSE, | |
| "%a:%a: skipping CipherId=0x%04x\n", | |
| gEfiCallerBaseName, | |
| __FUNCTION__, | |
| CipherId[Index] | |
| )); | |
| // | |
| // 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. | |
| // | |
| 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; | |
| } | |
| // | |
| // Record the mapping. | |
| // | |
| MappedCipher[MappedCipherCount++] = Mapping; | |
| } | |
| // | |
| // 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) { | |
| Status = EFI_UNSUPPORTED; | |
| goto FreeCipherString; | |
| } | |
| Status = EFI_SUCCESS; | |
| FreeCipherString: | |
| FreePool (CipherString); | |
| FreeMappedCipher: | |
| FreePool ((VOID *)MappedCipher); | |
| return Status; | |
| } | |
| /** | |
| Set the compression method for TLS/SSL operations. | |
| This function handles TLS/SSL integrated compression methods. | |
| @param[in] CompMethod The compression method ID. | |
| @retval EFI_SUCCESS The compression method for the communication was | |
| set successfully. | |
| @retval EFI_UNSUPPORTED Unsupported compression method. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| TlsSetCompressionMethod ( | |
| IN UINT8 CompMethod | |
| ) | |
| { | |
| COMP_METHOD *Cm; | |
| INTN Ret; | |
| Cm = NULL; | |
| Ret = 0; | |
| if (CompMethod == 0) { | |
| // | |
| // TLS defines one standard compression method, CompressionMethod.null (0), | |
| // which specifies that data exchanged via the record protocol will not be compressed. | |
| // So, return EFI_SUCCESS directly (RFC 3749). | |
| // | |
| return EFI_SUCCESS; | |
| } else if (CompMethod == 1) { | |
| Cm = COMP_zlib (); | |
| } else { | |
| return EFI_UNSUPPORTED; | |
| } | |
| // | |
| // Adds the compression method to the list of available | |
| // compression methods. | |
| // | |
| Ret = SSL_COMP_add_compression_method (CompMethod, Cm); | |
| if (Ret != 0) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Set peer certificate verification mode for the TLS connection. | |
| This function sets the verification mode flags for the TLS connection. | |
| @param[in] Tls Pointer to the TLS object. | |
| @param[in] VerifyMode A set of logically or'ed verification mode flags. | |
| **/ | |
| VOID | |
| EFIAPI | |
| TlsSetVerify ( | |
| IN VOID *Tls, | |
| IN UINT32 VerifyMode | |
| ) | |
| { | |
| TLS_CONNECTION *TlsConn; | |
| TlsConn = (TLS_CONNECTION *)Tls; | |
| if ((TlsConn == NULL) || (TlsConn->Ssl == NULL)) { | |
| return; | |
| } | |
| // | |
| // Set peer certificate verification parameters with NULL callback. | |
| // | |
| 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. | |
| This function sets a session ID to be used when the TLS/SSL connection is | |
| to be established. | |
| @param[in] Tls Pointer to the TLS object. | |
| @param[in] SessionId Session ID data used for session resumption. | |
| @param[in] SessionIdLen Length of Session ID in bytes. | |
| @retval EFI_SUCCESS Session ID was set successfully. | |
| @retval EFI_INVALID_PARAMETER The parameter is invalid. | |
| @retval EFI_UNSUPPORTED No available session for ID setting. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| TlsSetSessionId ( | |
| IN VOID *Tls, | |
| IN UINT8 *SessionId, | |
| IN UINT16 SessionIdLen | |
| ) | |
| { | |
| TLS_CONNECTION *TlsConn; | |
| SSL_SESSION *Session; | |
| TlsConn = (TLS_CONNECTION *)Tls; | |
| Session = NULL; | |
| if ((TlsConn == NULL) || (TlsConn->Ssl == NULL) || (SessionId == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Session = SSL_get_session (TlsConn->Ssl); | |
| if (Session == NULL) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| SSL_SESSION_set1_id (Session, (const unsigned char *)SessionId, SessionIdLen); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Adds the CA to the cert store when requesting Server or Client authentication. | |
| This function adds the CA certificate to the list of CAs when requesting | |
| Server or Client authentication for the chosen TLS connection. | |
| @param[in] Tls Pointer to the TLS object. | |
| @param[in] Data Pointer to the data buffer of a DER-encoded binary | |
| X.509 certificate or PEM-encoded X.509 certificate. | |
| @param[in] DataSize The size of data buffer in bytes. | |
| @retval EFI_SUCCESS The operation succeeded. | |
| @retval EFI_INVALID_PARAMETER The parameter is invalid. | |
| @retval EFI_OUT_OF_RESOURCES Required resources could not be allocated. | |
| @retval EFI_ABORTED Invalid X.509 certificate. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| TlsSetCaCertificate ( | |
| IN VOID *Tls, | |
| IN VOID *Data, | |
| IN UINTN DataSize | |
| ) | |
| { | |
| BIO *BioCert; | |
| X509 *Cert; | |
| X509_STORE *X509Store; | |
| EFI_STATUS Status; | |
| TLS_CONNECTION *TlsConn; | |
| SSL_CTX *SslCtx; | |
| INTN Ret; | |
| UINTN ErrorCode; | |
| BioCert = NULL; | |
| Cert = NULL; | |
| X509Store = NULL; | |
| Status = EFI_SUCCESS; | |
| TlsConn = (TLS_CONNECTION *)Tls; | |
| Ret = 0; | |
| if ((TlsConn == NULL) || (TlsConn->Ssl == NULL) || (Data == NULL) || (DataSize == 0)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // 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); | |
| if (Cert == NULL) { | |
| // | |
| // Certificate is from PEM encoding. | |
| // | |
| BioCert = BIO_new (BIO_s_mem ()); | |
| if (BioCert == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto ON_EXIT; | |
| } | |
| if (BIO_write (BioCert, Data, (UINT32)DataSize) <= 0) { | |
| Status = EFI_ABORTED; | |
| goto ON_EXIT; | |
| } | |
| Cert = PEM_read_bio_X509 (BioCert, NULL, NULL, NULL); | |
| if (Cert == NULL) { | |
| Status = EFI_ABORTED; | |
| goto ON_EXIT; | |
| } | |
| } | |
| SslCtx = SSL_get_SSL_CTX (TlsConn->Ssl); | |
| X509Store = SSL_CTX_get_cert_store (SslCtx); | |
| if (X509Store == NULL) { | |
| Status = EFI_ABORTED; | |
| goto ON_EXIT; | |
| } | |
| // | |
| // Add certificate to X509 store | |
| // | |
| Ret = X509_STORE_add_cert (X509Store, Cert); | |
| if (Ret != 1) { | |
| ErrorCode = ERR_peek_last_error (); | |
| // | |
| // 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))) | |
| { | |
| Status = EFI_ABORTED; | |
| goto ON_EXIT; | |
| } | |
| } | |
| ON_EXIT: | |
| if (BioCert != NULL) { | |
| BIO_free (BioCert); | |
| } | |
| if (Cert != NULL) { | |
| X509_free (Cert); | |
| } | |
| return Status; | |
| } | |
| /** | |
| Loads the local public certificate into the specified TLS object. | |
| This function loads the X.509 certificate 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 binary | |
| X.509 certificate or PEM-encoded X.509 certificate. | |
| @param[in] DataSize The size of data buffer in bytes. | |
| @retval EFI_SUCCESS The operation succeeded. | |
| @retval EFI_INVALID_PARAMETER The parameter is invalid. | |
| @retval EFI_OUT_OF_RESOURCES Required resources could not be allocated. | |
| @retval EFI_ABORTED Invalid X.509 certificate. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| TlsSetHostPublicCert ( | |
| IN VOID *Tls, | |
| IN VOID *Data, | |
| IN UINTN DataSize | |
| ) | |
| { | |
| BIO *BioCert; | |
| X509 *Cert; | |
| EFI_STATUS Status; | |
| TLS_CONNECTION *TlsConn; | |
| BioCert = NULL; | |
| Cert = NULL; | |
| Status = EFI_SUCCESS; | |
| TlsConn = (TLS_CONNECTION *)Tls; | |
| if ((TlsConn == NULL) || (TlsConn->Ssl == NULL) || (Data == NULL) || (DataSize == 0)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // 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); | |
| if (Cert == NULL) { | |
| // | |
| // Certificate is from PEM encoding. | |
| // | |
| BioCert = BIO_new (BIO_s_mem ()); | |
| if (BioCert == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto ON_EXIT; | |
| } | |
| if (BIO_write (BioCert, Data, (UINT32)DataSize) <= 0) { | |
| Status = EFI_ABORTED; | |
| goto ON_EXIT; | |
| } | |
| Cert = PEM_read_bio_X509 (BioCert, NULL, NULL, NULL); | |
| if (Cert == NULL) { | |
| Status = EFI_ABORTED; | |
| goto ON_EXIT; | |
| } | |
| } | |
| if (SSL_use_certificate (TlsConn->Ssl, Cert) != 1) { | |
| Status = EFI_ABORTED; | |
| goto ON_EXIT; | |
| } | |
| ON_EXIT: | |
| if (BioCert != NULL) { | |
| BIO_free (BioCert); | |
| } | |
| if (Cert != NULL) { | |
| X509_free (Cert); | |
| } | |
| return Status; | |
| } | |
| /** | |
| 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. | |
| @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. | |
| @retval EFI_SUCCESS The operation succeeded. | |
| @retval EFI_UNSUPPORTED This function is not supported. | |
| @retval EFI_ABORTED Invalid private key data. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| TlsSetHostPrivateKey ( | |
| IN VOID *Tls, | |
| IN VOID *Data, | |
| IN UINTN DataSize | |
| ) | |
| { | |
| return TlsSetHostPrivateKeyEx (Tls, Data, DataSize, NULL); | |
| } | |
| /** | |
| Adds the CA-supplied certificate revocation list for certificate validation. | |
| This function adds the CA-supplied certificate revocation list data for | |
| certificate validity checking. | |
| @param[in] Data Pointer to the data buffer of a DER-encoded CRL data. | |
| @param[in] DataSize The size of data buffer in bytes. | |
| @retval EFI_SUCCESS The operation succeeded. | |
| @retval EFI_UNSUPPORTED This function is not supported. | |
| @retval EFI_ABORTED Invalid CRL data. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| TlsSetCertRevocationList ( | |
| 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. | |
| This function returns the protocol version used by the specified TLS | |
| connection. | |
| If Tls is NULL, then ASSERT(). | |
| @param[in] Tls Pointer to the TLS object. | |
| @return The protocol version of the specified TLS connection. | |
| **/ | |
| UINT16 | |
| EFIAPI | |
| TlsGetVersion ( | |
| IN VOID *Tls | |
| ) | |
| { | |
| TLS_CONNECTION *TlsConn; | |
| TlsConn = (TLS_CONNECTION *)Tls; | |
| ASSERT (TlsConn != NULL); | |
| return (UINT16)(SSL_version (TlsConn->Ssl)); | |
| } | |
| /** | |
| Gets the connection end of the specified TLS connection. | |
| This function returns the connection end (as client or as server) used by | |
| the specified TLS connection. | |
| If Tls is NULL, then ASSERT(). | |
| @param[in] Tls Pointer to the TLS object. | |
| @return The connection end used by the specified TLS connection. | |
| **/ | |
| UINT8 | |
| EFIAPI | |
| TlsGetConnectionEnd ( | |
| IN VOID *Tls | |
| ) | |
| { | |
| TLS_CONNECTION *TlsConn; | |
| TlsConn = (TLS_CONNECTION *)Tls; | |
| ASSERT (TlsConn != NULL); | |
| return (UINT8)SSL_is_server (TlsConn->Ssl); | |
| } | |
| /** | |
| Gets the cipher suite used by the specified TLS connection. | |
| This function returns current cipher suite used by the specified | |
| TLS connection. | |
| @param[in] Tls Pointer to the TLS object. | |
| @param[in,out] CipherId The cipher suite used by the TLS object. | |
| @retval EFI_SUCCESS The cipher suite was returned successfully. | |
| @retval EFI_INVALID_PARAMETER The parameter is invalid. | |
| @retval EFI_UNSUPPORTED Unsupported cipher suite. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| TlsGetCurrentCipher ( | |
| IN VOID *Tls, | |
| IN OUT UINT16 *CipherId | |
| ) | |
| { | |
| TLS_CONNECTION *TlsConn; | |
| CONST SSL_CIPHER *Cipher; | |
| TlsConn = (TLS_CONNECTION *)Tls; | |
| Cipher = NULL; | |
| if ((TlsConn == NULL) || (TlsConn->Ssl == NULL) || (CipherId == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Cipher = SSL_get_current_cipher (TlsConn->Ssl); | |
| if (Cipher == NULL) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| *CipherId = (SSL_CIPHER_get_id (Cipher)) & 0xFFFF; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Gets the compression methods used by the specified TLS connection. | |
| This function returns current integrated compression methods used by | |
| the specified TLS connection. | |
| @param[in] Tls Pointer to the TLS object. | |
| @param[in,out] CompressionId The current compression method used by | |
| the TLS object. | |
| @retval EFI_SUCCESS The compression method was returned successfully. | |
| @retval EFI_INVALID_PARAMETER The parameter is invalid. | |
| @retval EFI_ABORTED Invalid Compression method. | |
| @retval EFI_UNSUPPORTED This function is not supported. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| TlsGetCurrentCompressionId ( | |
| IN VOID *Tls, | |
| IN OUT UINT8 *CompressionId | |
| ) | |
| { | |
| return EFI_UNSUPPORTED; | |
| } | |
| /** | |
| Gets the verification mode currently set in the TLS connection. | |
| This function returns the peer verification mode currently set in the | |
| specified TLS connection. | |
| If Tls is NULL, then ASSERT(). | |
| @param[in] Tls Pointer to the TLS object. | |
| @return The verification mode set in the specified TLS connection. | |
| **/ | |
| UINT32 | |
| EFIAPI | |
| TlsGetVerify ( | |
| IN VOID *Tls | |
| ) | |
| { | |
| TLS_CONNECTION *TlsConn; | |
| TlsConn = (TLS_CONNECTION *)Tls; | |
| ASSERT (TlsConn != NULL); | |
| return SSL_get_verify_mode (TlsConn->Ssl); | |
| } | |
| /** | |
| Gets the session ID used by the specified TLS connection. | |
| This function returns the TLS/SSL session ID currently used by the | |
| specified TLS connection. | |
| @param[in] Tls Pointer to the TLS object. | |
| @param[in,out] SessionId Buffer to contain the returned session ID. | |
| @param[in,out] SessionIdLen The length of Session ID in bytes. | |
| @retval EFI_SUCCESS The Session ID was returned successfully. | |
| @retval EFI_INVALID_PARAMETER The parameter is invalid. | |
| @retval EFI_UNSUPPORTED Invalid TLS/SSL session. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| TlsGetSessionId ( | |
| IN VOID *Tls, | |
| IN OUT UINT8 *SessionId, | |
| IN OUT UINT16 *SessionIdLen | |
| ) | |
| { | |
| TLS_CONNECTION *TlsConn; | |
| SSL_SESSION *Session; | |
| CONST UINT8 *SslSessionId; | |
| TlsConn = (TLS_CONNECTION *)Tls; | |
| Session = NULL; | |
| if ((TlsConn == NULL) || (TlsConn->Ssl == NULL) || (SessionId == NULL) || (SessionIdLen == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Session = SSL_get_session (TlsConn->Ssl); | |
| if (Session == NULL) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| SslSessionId = SSL_SESSION_get_id (Session, (unsigned int *)SessionIdLen); | |
| CopyMem (SessionId, SslSessionId, *SessionIdLen); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Gets the client random data used in the specified TLS connection. | |
| This function returns the TLS/SSL client random data currently used in | |
| the specified TLS connection. | |
| @param[in] Tls Pointer to the TLS object. | |
| @param[in,out] ClientRandom Buffer to contain the returned client | |
| random data (32 bytes). | |
| **/ | |
| VOID | |
| EFIAPI | |
| TlsGetClientRandom ( | |
| IN VOID *Tls, | |
| IN OUT UINT8 *ClientRandom | |
| ) | |
| { | |
| TLS_CONNECTION *TlsConn; | |
| TlsConn = (TLS_CONNECTION *)Tls; | |
| if ((TlsConn == NULL) || (TlsConn->Ssl == NULL) || (ClientRandom == NULL)) { | |
| return; | |
| } | |
| SSL_get_client_random (TlsConn->Ssl, ClientRandom, SSL3_RANDOM_SIZE); | |
| } | |
| /** | |
| Gets the server random data used in the specified TLS connection. | |
| This function returns the TLS/SSL server random data currently used in | |
| the specified TLS connection. | |
| @param[in] Tls Pointer to the TLS object. | |
| @param[in,out] ServerRandom Buffer to contain the returned server | |
| random data (32 bytes). | |
| **/ | |
| VOID | |
| EFIAPI | |
| TlsGetServerRandom ( | |
| IN VOID *Tls, | |
| IN OUT UINT8 *ServerRandom | |
| ) | |
| { | |
| TLS_CONNECTION *TlsConn; | |
| TlsConn = (TLS_CONNECTION *)Tls; | |
| if ((TlsConn == NULL) || (TlsConn->Ssl == NULL) || (ServerRandom == NULL)) { | |
| return; | |
| } | |
| SSL_get_server_random (TlsConn->Ssl, ServerRandom, SSL3_RANDOM_SIZE); | |
| } | |
| /** | |
| Gets the master key data used in the specified TLS connection. | |
| This function returns the TLS/SSL master key material currently used in | |
| the specified TLS connection. | |
| @param[in] Tls Pointer to the TLS object. | |
| @param[in,out] KeyMaterial Buffer to contain the returned key material. | |
| @retval EFI_SUCCESS Key material was returned successfully. | |
| @retval EFI_INVALID_PARAMETER The parameter is invalid. | |
| @retval EFI_UNSUPPORTED Invalid TLS/SSL session. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| TlsGetKeyMaterial ( | |
| IN VOID *Tls, | |
| IN OUT UINT8 *KeyMaterial | |
| ) | |
| { | |
| TLS_CONNECTION *TlsConn; | |
| SSL_SESSION *Session; | |
| TlsConn = (TLS_CONNECTION *)Tls; | |
| Session = NULL; | |
| if ((TlsConn == NULL) || (TlsConn->Ssl == NULL) || (KeyMaterial == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Session = SSL_get_session (TlsConn->Ssl); | |
| if (Session == NULL) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| SSL_SESSION_get_master_key (Session, KeyMaterial, SSL3_MASTER_SECRET_SIZE); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Gets the CA Certificate from the cert store. | |
| This function returns the CA certificate for the chosen | |
| TLS connection. | |
| @param[in] Tls Pointer to the TLS object. | |
| @param[out] Data Pointer to the data buffer to receive the CA | |
| certificate data sent to the client. | |
| @param[in,out] DataSize The size of data buffer in bytes. | |
| @retval EFI_SUCCESS The operation succeeded. | |
| @retval EFI_UNSUPPORTED This function is not supported. | |
| @retval EFI_BUFFER_TOO_SMALL The Data is too small to hold the data. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| TlsGetCaCertificate ( | |
| IN VOID *Tls, | |
| OUT VOID *Data, | |
| IN OUT UINTN *DataSize | |
| ) | |
| { | |
| return EFI_UNSUPPORTED; | |
| } | |
| /** | |
| Gets the local public Certificate set in the specified TLS object. | |
| This function returns the local public certificate which was currently set | |
| in the specified TLS object. | |
| @param[in] Tls Pointer to the TLS object. | |
| @param[out] Data Pointer to the data buffer to receive the local | |
| public certificate. | |
| @param[in,out] DataSize The size of data buffer in bytes. | |
| @retval EFI_SUCCESS The operation succeeded. | |
| @retval EFI_INVALID_PARAMETER The parameter is invalid. | |
| @retval EFI_NOT_FOUND The certificate is not found. | |
| @retval EFI_BUFFER_TOO_SMALL The Data is too small to hold the data. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| TlsGetHostPublicCert ( | |
| IN VOID *Tls, | |
| OUT VOID *Data, | |
| IN OUT UINTN *DataSize | |
| ) | |
| { | |
| X509 *Cert; | |
| TLS_CONNECTION *TlsConn; | |
| Cert = NULL; | |
| TlsConn = (TLS_CONNECTION *)Tls; | |
| if ((TlsConn == NULL) || (TlsConn->Ssl == NULL) || (DataSize == NULL) || ((*DataSize != 0) && (Data == NULL))) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Cert = SSL_get_certificate (TlsConn->Ssl); | |
| if (Cert == NULL) { | |
| return EFI_NOT_FOUND; | |
| } | |
| // | |
| // Only DER encoding is supported currently. | |
| // | |
| 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); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Gets the local private key set in the specified TLS object. | |
| This function returns the local private key data which was currently set | |
| in the specified TLS object. | |
| @param[in] Tls Pointer to the TLS object. | |
| @param[out] Data Pointer to the data buffer to receive the local | |
| private key data. | |
| @param[in,out] DataSize The size of data buffer in bytes. | |
| @retval EFI_SUCCESS The operation succeeded. | |
| @retval EFI_UNSUPPORTED This function is not supported. | |
| @retval EFI_BUFFER_TOO_SMALL The Data is too small to hold the data. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| TlsGetHostPrivateKey ( | |
| IN VOID *Tls, | |
| OUT VOID *Data, | |
| IN OUT UINTN *DataSize | |
| ) | |
| { | |
| return EFI_UNSUPPORTED; | |
| } | |
| /** | |
| Gets the CA-supplied certificate revocation list data set in the specified | |
| TLS object. | |
| This function returns the CA-supplied certificate revocation list data which | |
| was currently set in the specified TLS object. | |
| @param[out] Data Pointer to the data buffer to receive the CRL data. | |
| @param[in,out] DataSize The size of data buffer in bytes. | |
| @retval EFI_SUCCESS The operation succeeded. | |
| @retval EFI_UNSUPPORTED This function is not supported. | |
| @retval EFI_BUFFER_TOO_SMALL The Data is too small to hold the data. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| TlsGetCertRevocationList ( | |
| 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; | |
| } |