/** @file
SSL/TLS Initialization Library Wrapper Implementation over OpenSSL.
Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.
(C) Copyright 2016 Hewlett Packard Enterprise Development LP
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "InternalTlsLib.h"
/**
Initializes the OpenSSL library.
This function registers ciphers and digests used directly and indirectly
by SSL/TLS, and initializes the readable error messages.
This function must be called before any other action takes places.
@retval TRUE The OpenSSL library has been initialized.
@retval FALSE Failed to initialize the OpenSSL library.
**/
BOOLEAN
EFIAPI
TlsInitialize (
VOID
)
{
INTN Ret;
//
// Performs initialization of crypto and ssl library, and loads required
// algorithms.
//
Ret = OPENSSL_init_ssl (
OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS,
NULL
);
if (Ret != 1) {
return FALSE;
}
//
// Initialize the pseudorandom number generator.
//
return RandomSeed (NULL, 0);
}
/**
Free an allocated SSL_CTX object.
@param[in] TlsCtx Pointer to the SSL_CTX object to be released.
**/
VOID
EFIAPI
TlsCtxFree (
IN VOID *TlsCtx
)
{
if (TlsCtx == NULL) {
return;
}
if (TlsCtx != NULL) {
SSL_CTX_free ((SSL_CTX *)(TlsCtx));
}
}
/**
Creates a new SSL_CTX object as framework to establish TLS/SSL enabled
connections.
@param[in] MajorVer Major Version of TLS/SSL Protocol.
@param[in] MinorVer Minor Version of TLS/SSL Protocol.
@return Pointer to an allocated SSL_CTX object.
If the creation failed, TlsCtxNew() returns NULL.
**/
VOID *
EFIAPI
TlsCtxNew (
IN UINT8 MajorVer,
IN UINT8 MinorVer
)
{
SSL_CTX *TlsCtx;
UINT16 ProtoVersion;
ProtoVersion = (MajorVer << 8) | MinorVer;
TlsCtx = SSL_CTX_new (SSLv23_client_method ());
if (TlsCtx == NULL) {
return NULL;
}
//
// Ensure SSLv3 is disabled
//
SSL_CTX_set_options (TlsCtx, SSL_OP_NO_SSLv3);
//
// Treat as minimum accepted versions by setting the minimal bound.
// Client can use higher TLS version if server supports it
//
SSL_CTX_set_min_proto_version (TlsCtx, ProtoVersion);
return (VOID *)TlsCtx;
}
/**
Free an allocated TLS object.
This function removes the TLS object pointed to by Tls and frees up the
allocated memory. If Tls is NULL, nothing is done.
@param[in] Tls Pointer to the TLS object to be freed.
**/
VOID
EFIAPI
TlsFree (
IN VOID *Tls
)
{
TLS_CONNECTION *TlsConn;
TlsConn = (TLS_CONNECTION *)Tls;
if (TlsConn == NULL) {
return;
}
//
// Free the internal TLS and related BIO objects.
//
if (TlsConn->Ssl != NULL) {
SSL_free (TlsConn->Ssl);
}
OPENSSL_free (Tls);
}
/**
Create a new TLS object for a connection.
This function creates a new TLS object for a connection. The new object
inherits the setting of the underlying context TlsCtx: connection method,
options, verification setting.
@param[in] TlsCtx Pointer to the SSL_CTX object.
@return Pointer to an allocated SSL object.
If the creation failed, TlsNew() returns NULL.
**/
VOID *
EFIAPI
TlsNew (
IN VOID *TlsCtx
)
{
TLS_CONNECTION *TlsConn;
SSL_CTX *SslCtx;
X509_STORE *X509Store;
TlsConn = NULL;
//
// Allocate one new TLS_CONNECTION object
//
TlsConn = (TLS_CONNECTION *)OPENSSL_malloc (sizeof (TLS_CONNECTION));
if (TlsConn == NULL) {
return NULL;
}
TlsConn->Ssl = NULL;
//
// Create a new SSL Object
//
TlsConn->Ssl = SSL_new ((SSL_CTX *)TlsCtx);
if (TlsConn->Ssl == NULL) {
TlsFree ((VOID *)TlsConn);
return NULL;
}
//
// This retains compatibility with previous version of OpenSSL.
//
SSL_set_security_level (TlsConn->Ssl, 0);
//
// Initialize the created SSL Object
//
SSL_set_info_callback (TlsConn->Ssl, NULL);
TlsConn->InBio = NULL;
//
// Set up Reading BIO for TLS connection
//
TlsConn->InBio = BIO_new (BIO_s_mem ());
if (TlsConn->InBio == NULL) {
TlsFree ((VOID *)TlsConn);
return NULL;
}
//
// Sets the behaviour of memory BIO when it is empty. It will set the
// read retry flag.
//
BIO_set_mem_eof_return (TlsConn->InBio, -1);
TlsConn->OutBio = NULL;
//
// Set up Writing BIO for TLS connection
//
TlsConn->OutBio = BIO_new (BIO_s_mem ());
if (TlsConn->OutBio == NULL) {
TlsFree ((VOID *)TlsConn);
return NULL;
}
//
// Sets the behaviour of memory BIO when it is empty. It will set the
// write retry flag.
//
BIO_set_mem_eof_return (TlsConn->OutBio, -1);
ASSERT (TlsConn->Ssl != NULL && TlsConn->InBio != NULL && TlsConn->OutBio != NULL);
//
// Connects the InBio and OutBio for the read and write operations.
//
SSL_set_bio (TlsConn->Ssl, TlsConn->InBio, TlsConn->OutBio);
//
// Create new X509 store if needed
//
SslCtx = SSL_get_SSL_CTX (TlsConn->Ssl);
X509Store = SSL_CTX_get_cert_store (SslCtx);
if (X509Store == NULL) {
X509Store = X509_STORE_new ();
if (X509Store == NULL) {
TlsFree ((VOID *)TlsConn);
return NULL;
}
SSL_CTX_set1_verify_cert_store (SslCtx, X509Store);
X509_STORE_free (X509Store);
}
//
// Set X509_STORE flags used in certificate validation
//
X509_STORE_set_flags (
X509Store,
X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_NO_CHECK_TIME
);
return (VOID *)TlsConn;
}