| /** @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 { | |
| // | |
| // 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" }, | |
| }; | |
| /** | |
| 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 SSL_CIPHER **MappedCipher; | |
| UINTN MappedCipherBytes; | |
| UINTN MappedCipherCount; | |
| UINTN CipherStringSize; | |
| UINTN Index; | |
| INT32 StackIdx; | |
| CHAR8 *CipherString; | |
| CHAR8 *CipherStringPosition; | |
| STACK_OF (SSL_CIPHER) *OpensslCipherStack; | |
| CONST SSL_CIPHER *OpensslCipher; | |
| CONST CHAR8 *OpensslCipherName; | |
| UINTN OpensslCipherNameLength; | |
| 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; | |
| } | |
| OpensslCipherStack = SSL_get_ciphers (TlsConn->Ssl); | |
| // | |
| // Map the cipher IDs, and count the number of bytes for the full | |
| // CipherString. | |
| // | |
| MappedCipherCount = 0; | |
| CipherStringSize = 0; | |
| for (Index = 0; OpensslCipherStack != NULL && Index < CipherNum; Index++) { | |
| // | |
| // Look up the IANA-to-OpenSSL mapping. | |
| // | |
| for (StackIdx = 0; StackIdx < sk_SSL_CIPHER_num (OpensslCipherStack); StackIdx++) { | |
| OpensslCipher = sk_SSL_CIPHER_value (OpensslCipherStack, StackIdx); | |
| if (CipherId[Index] == SSL_CIPHER_get_protocol_id (OpensslCipher)) { | |
| break; | |
| } | |
| } | |
| if (StackIdx == sk_SSL_CIPHER_num (OpensslCipherStack)) { | |
| 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 cipher name string length 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, | |
| AsciiStrLen (SSL_CIPHER_get_name (OpensslCipher)), | |
| &CipherStringSize | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto FreeMappedCipher; | |
| } | |
| // | |
| // Record the mapping. | |
| // | |
| MappedCipher[MappedCipherCount++] = OpensslCipher; | |
| } | |
| // | |
| // 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++) { | |
| OpensslCipher = MappedCipher[Index]; | |
| OpensslCipherName = SSL_CIPHER_get_name (OpensslCipher); | |
| OpensslCipherNameLength = AsciiStrLen (OpensslCipherName); | |
| // | |
| // Append the colon (":") prefix except for the first mapping, then append | |
| // OpensslCipherName. | |
| // | |
| if (Index > 0) { | |
| *(CipherStringPosition++) = ':'; | |
| } | |
| CopyMem ( | |
| CipherStringPosition, | |
| OpensslCipherName, | |
| OpensslCipherNameLength | |
| ); | |
| CipherStringPosition += OpensslCipherNameLength; | |
| } | |
| // | |
| // 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; | |
| } | |
| DEBUG (( | |
| DEBUG_VERBOSE, | |
| "%a:%a: SNI hostname: %a\n", | |
| gEfiCallerBaseName, | |
| __func__, | |
| HostName | |
| )); | |
| if (!SSL_set_tlsext_host_name (TlsConn->Ssl, HostName)) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "%a:%a: Could not set hostname %a for SNI\n", | |
| gEfiCallerBaseName, | |
| __func__, | |
| HostName | |
| )); | |
| } | |
| 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; | |
| } | |
| /** | |
| Callback function to get the server name. | |
| @param[in] SSL | |
| @param[in] INT32 | |
| @param[in] Arg | |
| @retval INT32 | |
| **/ | |
| STATIC | |
| INT32 | |
| SslServerNameCallback ( | |
| SSL *Ssl, | |
| INT32 *Ad, | |
| VOID *Arg | |
| ) | |
| { | |
| const CHAR8 *HostName = NULL; | |
| TLS_EXT_CTX *TlsCtx = (TLS_EXT_CTX *)Arg; | |
| HostName = SSL_get_servername (Ssl, TLSEXT_NAMETYPE_host_name); | |
| if (SSL_get_servername_type (Ssl) != -1) { | |
| TlsCtx->Ack = !SSL_session_reused (Ssl) && HostName != NULL; | |
| } | |
| return SSL_TLSEXT_ERR_OK; | |
| } | |
| /** | |
| Set the specified server name in Server/Client. | |
| @param[in] Tls Pointer to the TLS object. | |
| @param[in] SslCtx Pointer to the SSL object. | |
| @param[in] HostName The specified server name to be set. | |
| @retval EFI_SUCCESS The Server Name was set successfully. | |
| @retval EFI_UNSUPPORTED Failed to set the Server Name. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| TlsSetServerName ( | |
| VOID *Tls, | |
| VOID *SslCtx, | |
| CHAR8 *HostName | |
| ) | |
| { | |
| SSL_CTX *Ctx; | |
| TLS_CONNECTION *TlsConn; | |
| UINT32 RetVal; | |
| TLS_EXT_CTX *TlsExtCtx = NULL; | |
| TlsConn = (TLS_CONNECTION *)Tls; | |
| Ctx = (SSL_CTX *)SslCtx; | |
| if (TlsConn == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| TlsExtCtx = AllocateZeroPool (sizeof (TLS_EXT_CTX)); | |
| if (TlsExtCtx == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| RetVal = SSL_CTX_set_tlsext_servername_callback (Ctx, SslServerNameCallback); | |
| if (!RetVal) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| RetVal = SSL_CTX_set_tlsext_servername_arg (Ctx, TlsExtCtx); | |
| if (!RetVal) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| RetVal = SSL_set_tlsext_host_name (TlsConn->Ssl, HostName); | |
| if (!RetVal) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| 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; | |
| 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) { | |
| unsigned long ErrorCode; | |
| ErrorCode = ERR_peek_last_error (); | |
| // | |
| // Ignore "already in table" errors | |
| // | |
| if (!((ERR_GET_LIB (ErrorCode) == ERR_LIB_X509) && | |
| (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; | |
| } | |
| /** | |
| Set the Tls security level. | |
| This function Set the Tls security level. | |
| If Tls is NULL, nothing is done. | |
| @param[in] Tls Pointer to the TLS object. | |
| @param[in] Level Tls Security level need to set. | |
| @retval EFI_SUCCESS The Tls security level was set successfully. | |
| @retval EFI_INVALID_PARAMETER The parameters are invalid. | |
| @retval EFI_UNSUPPORTED The requested TLS set security level is not supported. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| TlsSetSecurityLevel ( | |
| IN VOID *Tls, | |
| IN UINT8 Level | |
| ) | |
| { | |
| TLS_CONNECTION *TlsConn; | |
| TlsConn = (TLS_CONNECTION *)Tls; | |
| if ((TlsConn == NULL) || (TlsConn->Ssl == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // Check if the security level is within the valid range (2 to 5). | |
| // Return EFI_INVALID_PARAMETER if the level is out of bounds. | |
| if ((Level < MIN_SECURITY_LEVEL) || (Level > MAX_SECURITY_LEVEL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| SSL_set_security_level (TlsConn->Ssl, Level); | |
| 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; | |
| if (TlsConn == NULL) { | |
| return 0; | |
| } | |
| 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; | |
| if (TlsConn == NULL) { | |
| return 0; | |
| } | |
| 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; | |
| if (TlsConn == NULL) { | |
| return 0; | |
| } | |
| 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; | |
| } |