25.05.2023 18:38 R.Wieser kirjutas:
> Paavo,
>
>> OpenSSL 0.9 is seriously out of date. Currently supported stable versions
>> are 1.1.* and 3.0.*.
>
> Yeah, I know. I already downloaded v3.1.0. But up until I can find example
> and/or tutorial code about/for it its rather useless to me. And as I could
> find info about that "seriously out of date" version that became the one I'm
> working with.
>
>> This code is using OpenSSL 3.0.8 for wrapping an existing connected
>> client-side cocked into SSL (Linux and Windows):
>
> That is quite similar to the 2) code I mentioned (using a pre-created and
> connected native socket). I would like to keep everything in OpenSSL.
>
> I would like to see a solution where I can create and connect a BIO socket
> in a similar way I create a native socket (not providing hostname
> information) and than use the BIO socket in the code you have posted.
>
> The other solution I'm looking for is a full SSL_xxx one. No BIO_xxx or
> native socket.
For client sockets I do not use any BIO* functions.
>
> By the way: you use "context_->GetSSL_CTX()", but I do not see you cleanup
> the returned handle.
>
Right. The GetSSL_CTX() is my own function which returns a pointer to
shared SSL_CTX structure. This SSL_CTX is created once, is shared by all
SSL client connections and will be released only at the end of the program.
Setting up this context involves loading the trusted CA certificates
from various locations, and setting up a verify callback which logs
errors or warning, but also verifies the certificate against the Windows
system cert store, on Windows.
I can list the functions I use for setting up and releasing this
SSL_CTX, in call order (error checks omitted for brevity):
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
const SSL_METHOD* method = TLS_client_method();
SSL_CTX* context = SSL_CTX_new(method);
SSL_CTX_set_default_verify_paths(context);
// These can be called 0 or more times
SSL_CTX_load_verify_file(context, trustedCaBundleFile.c_str());
SSL_CTX_load_verify_dir(context, trustedCaCertDir.c_str())
SSL_CTX_set_verify(context, SSL_VERIFY_PEER, MySSLVerifyCallback);
***** cleanup *********
SSL_CTX_free(context);
******** callback *************
NOTE: contains my own functions, you need to adapt creatively
int MySSLVerifyCallback(int preverify_ok, X509_STORE_CTX *x509_ctx) {
try {
if (preverify_ok) {
// openssl has verified the cert, OK.
return 1; // success
}
X509* err_cert = (x509_ctx?
X509_STORE_CTX_get_current_cert(x509_ctx): nullptr);
const char* errMessage;
int err;
if (x509_ctx) {
err = X509_STORE_CTX_get_error(x509_ctx);
errMessage = X509_verify_cert_error_string(err);
} else {
err = -1;
errMessage = "x509_ctx==nullptr";
}
// Verify the cert against the global Windows certificates store
(ACINF-3817).
if (VerifyTLS(err_cert)) {
return 1; // success
}
char buf[256] = { 0 };
if (err_cert) {
X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf)
- 1);
}
std::string msg = Sprintf("SSL cert verify error: num=%d: %s:
%s")(err)(errMessage)(buf);
// handle as an error or as a warning
return 1; // success
return 0; // failure
} catch (...) {
// handle error
return 0; // failure
}
}
********** VerifyTLS() for Windows **************
NOTE: contains my own functions, you need to adapt creatively
// Need a separate function because OPENSSL_free is a macro.
void FreeOpenSslBuffer(unsigned char* buffer) {
OPENSSL_free(buffer);
}
bool VerifyTLS(X509* cert) {
// openssl failed to verify the cert.
// Try to verify the cert against Windows cert store
unsigned char* buffer = nullptr;
int len = i2d_X509(cert, &buffer);
if (len < 0) {
throw Exception(ERR_IO, "i2d_X509() failed");
}
ASSERT(buffer);
DEBUG_ASSERT(len > 0);
ON_BLOCK_EXIT(FreeOpenSslBuffer, buffer);
CERT_CHAIN_PARA thing;
::memset(&thing, 0, sizeof(thing));
thing.cbSize = sizeof(thing);
PCCERT_CONTEXT winContext =
::CertCreateCertificateContext(X509_ASN_ENCODING, buffer, len);
if (!winContext) {
syserr_t errorCode = GetLastErrorCode();
throw Exception(ERR_IO, "CertCreateCertificateContext() failed: " +
GetSysErrorString(errorCode));
}
ON_BLOCK_EXIT(::CertFreeCertificateContext, winContext);
PCCERT_CHAIN_CONTEXT chain = nullptr;
if (::CertGetCertificateChain(
nullptr,
winContext,
nullptr,
nullptr,
&thing,
CERT_CHAIN_CACHE_END_CERT|CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY,
nullptr,
&chain))
{
ON_BLOCK_EXIT(::CertFreeCertificateChain, chain);
DWORD errorStatus = chain->TrustStatus.dwErrorStatus;
if (errorStatus == 0) {
return true; // Windows approved the cert
}
}
return false;
}