/** @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, | |
__func__, | |
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, | |
__func__ | |
)); | |
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, | |
__func__ | |
)); | |
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, | |
__func__, | |
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; | |
} |