From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- roms/edk2/CryptoPkg/Library/TlsLib/TlsConfig.c | 1267 ++++++++++++++++++++++++ 1 file changed, 1267 insertions(+) create mode 100644 roms/edk2/CryptoPkg/Library/TlsLib/TlsConfig.c (limited to 'roms/edk2/CryptoPkg/Library/TlsLib/TlsConfig.c') diff --git a/roms/edk2/CryptoPkg/Library/TlsLib/TlsConfig.c b/roms/edk2/CryptoPkg/Library/TlsLib/TlsConfig.c new file mode 100644 index 000000000..307eb5789 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/TlsLib/TlsConfig.c @@ -0,0 +1,1267 @@ +/** @file + SSL/TLS Configuration Library Wrapper Implementation over OpenSSL. + +Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP
+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 +}; + +/** + 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 ( + 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); + ); + + // + // 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 (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 (PEM-encoded RSA 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 + 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 EFI_UNSUPPORTED; +} + +/** + 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; +} + +/** + 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; +} + -- cgit