Skip to content

Commit

Permalink
Add basic compatibility for BoringSSL
Browse files Browse the repository at this point in the history
  • Loading branch information
rmaucher committed Jul 4, 2024
1 parent ba64fe2 commit 85a25f3
Show file tree
Hide file tree
Showing 6 changed files with 284 additions and 85 deletions.
90 changes: 46 additions & 44 deletions java/org/apache/tomcat/util/net/openssl/panama/OpenSSLContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,6 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
}
}

static final boolean OPENSSL_3 = (OpenSSL_version_num() >= 0x3000000fL);

private final SSLHostConfig sslHostConfig;
private final SSLHostConfigCertificate certificate;
private final boolean alpn;
Expand Down Expand Up @@ -1053,57 +1051,61 @@ private boolean addCertificate(SSLHostConfigCertificate certificate, Arena local
// Try to read DH parameters from the (first) SSLCertificateFile
if (index == SSL_AIDX_RSA) {
BIO_reset(certificateBIO);
if (!OPENSSL_3) {
var dh = PEM_read_bio_DHparams(certificateBIO, MemorySegment.NULL, MemorySegment.NULL, MemorySegment.NULL);
if (!MemorySegment.NULL.equals(dh)) {
SSL_CTX_set_tmp_dh(state.sslCtx, dh);
DH_free(dh);
}
} else {
var pkey = PEM_read_bio_Parameters(certificateBIO, MemorySegment.NULL);
if (!MemorySegment.NULL.equals(pkey)) {
int numBits = EVP_PKEY_get_bits(pkey);
if (SSL_CTX_set0_tmp_dh_pkey(state.sslCtx, pkey) <= 0) {
EVP_PKEY_free(pkey);
} else {
log.debug(sm.getString("openssl.setCustomDHParameters", Integer.valueOf(numBits), certificate.getCertificateFile()));
if (!openssl_h_Compatibility.BORINGSSL) {
if (!openssl_h_Compatibility.OPENSSL3) {
var dh = PEM_read_bio_DHparams(certificateBIO, MemorySegment.NULL, MemorySegment.NULL, MemorySegment.NULL);
if (!MemorySegment.NULL.equals(dh)) {
SSL_CTX_set_tmp_dh(state.sslCtx, dh);
DH_free(dh);
}
} else {
String errMessage = OpenSSLLibrary.getLastError();
if (errMessage != null) {
log.debug(sm.getString("openssl.errorReadingPEMParameters", errMessage, certificate.getCertificateFile()));
var pkey = PEM_read_bio_Parameters(certificateBIO, MemorySegment.NULL);
if (!MemorySegment.NULL.equals(pkey)) {
int numBits = EVP_PKEY_get_bits(pkey);
if (SSL_CTX_set0_tmp_dh_pkey(state.sslCtx, pkey) <= 0) {
EVP_PKEY_free(pkey);
} else {
log.debug(sm.getString("openssl.setCustomDHParameters", Integer.valueOf(numBits), certificate.getCertificateFile()));
}
} else {
String errMessage = OpenSSLLibrary.getLastError();
if (errMessage != null) {
log.debug(sm.getString("openssl.errorReadingPEMParameters", errMessage, certificate.getCertificateFile()));
}
SSL_CTX_ctrl(state.sslCtx, SSL_CTRL_SET_DH_AUTO(), 1, MemorySegment.NULL);
}
SSL_CTX_ctrl(state.sslCtx, SSL_CTRL_SET_DH_AUTO(), 1, MemorySegment.NULL);
}
}
}
// Similarly, try to read the ECDH curve name from SSLCertificateFile...
BIO_reset(certificateBIO);
if (!OPENSSL_3) {
var ecparams = PEM_read_bio_ECPKParameters(certificateBIO, MemorySegment.NULL, MemorySegment.NULL, MemorySegment.NULL);
if (!MemorySegment.NULL.equals(ecparams)) {
int nid = EC_GROUP_get_curve_name(ecparams);
var eckey = EC_KEY_new_by_curve_name(nid);
SSL_CTX_set_tmp_ecdh(state.sslCtx, eckey);
EC_KEY_free(eckey);
EC_GROUP_free(ecparams);
}
// Set callback for DH parameters
SSL_CTX_set_tmp_dh_callback(state.sslCtx, SSL_CTX_set_tmp_dh_callback$dh.allocate(new TmpDHCallback(), contextArena));
} else {
var ecparams = PEM_ASN1_read_bio(d2i_ECPKParameters$SYMBOL(),
PEM_STRING_ECPARAMETERS(), certificateBIO, MemorySegment.NULL, MemorySegment.NULL, MemorySegment.NULL);
if (!MemorySegment.NULL.equals(ecparams)) {
int curveNid = EC_GROUP_get_curve_name(ecparams);
var curveNidAddress = localArena.allocateFrom(ValueLayout.JAVA_INT, curveNid);
if (SSL_CTX_set1_groups(state.sslCtx, curveNidAddress, 1) <= 0) {
curveNid = 0;
if (!openssl_h_Compatibility.BORINGSSL) {
if (!openssl_h_Compatibility.OPENSSL3) {
var ecparams = PEM_read_bio_ECPKParameters(certificateBIO, MemorySegment.NULL, MemorySegment.NULL, MemorySegment.NULL);
if (!MemorySegment.NULL.equals(ecparams)) {
int nid = EC_GROUP_get_curve_name(ecparams);
var eckey = EC_KEY_new_by_curve_name(nid);
SSL_CTX_set_tmp_ecdh(state.sslCtx, eckey);
EC_KEY_free(eckey);
EC_GROUP_free(ecparams);
}
if (log.isDebugEnabled()) {
log.debug(sm.getString("openssl.setECDHCurve", Integer.valueOf(curveNid),
certificate.getCertificateFile()));
// Set callback for DH parameters
SSL_CTX_set_tmp_dh_callback(state.sslCtx, SSL_CTX_set_tmp_dh_callback$dh.allocate(new TmpDHCallback(), contextArena));
} else {
var ecparams = PEM_ASN1_read_bio(d2i_ECPKParameters$SYMBOL(),
PEM_STRING_ECPARAMETERS(), certificateBIO, MemorySegment.NULL, MemorySegment.NULL, MemorySegment.NULL);
if (!MemorySegment.NULL.equals(ecparams)) {
int curveNid = EC_GROUP_get_curve_name(ecparams);
var curveNidAddress = localArena.allocateFrom(ValueLayout.JAVA_INT, curveNid);
if (SSL_CTX_set1_groups(state.sslCtx, curveNidAddress, 1) <= 0) {
curveNid = 0;
}
if (log.isDebugEnabled()) {
log.debug(sm.getString("openssl.setECDHCurve", Integer.valueOf(curveNid),
certificate.getCertificateFile()));
}
EC_GROUP_free(ecparams);
}
EC_GROUP_free(ecparams);
}
}
// Set certificate chain file
Expand Down Expand Up @@ -1212,7 +1214,7 @@ private boolean addCertificate(SSLHostConfigCertificate certificate, Arena local
logLastError("openssl.errorPrivateKeyCheck");
return false;
}
if (!OPENSSL_3) {
if (!openssl_h_Compatibility.OPENSSL3) {
// Set callback for DH parameters
SSL_CTX_set_tmp_dh_callback(state.sslCtx,
SSL_CTX_set_tmp_dh_callback$dh.allocate(new TmpDHCallback(), contextArena));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@
import javax.net.ssl.SSLSessionContext;

import static org.apache.tomcat.util.openssl.openssl_h.*;
import static org.apache.tomcat.util.openssl.openssl_h_Compatibility.*;
import static org.apache.tomcat.util.openssl.openssl_h_Macros.*;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
Expand Down Expand Up @@ -192,7 +191,7 @@ private enum PHAState { NONE, START, COMPLETE }
} else {
SSL_set_accept_state(ssl);
}
SSL_set_verify_result(ssl, X509_V_OK());
openssl_h_Compatibility.SSL_set_verify_result(ssl, X509_V_OK());
try (var localArena = Arena.ofConfined()) {
var internalBIOPointer = localArena.allocate(ValueLayout.ADDRESS);
var networkBIOPointer = localArena.allocate(ValueLayout.ADDRESS);
Expand Down Expand Up @@ -838,7 +837,7 @@ public synchronized void beginHandshake() throws SSLException {

private byte[] getPeerCertificate() {
try (var localArena = Arena.ofConfined()) {
MemorySegment/*(X509*)*/ x509 = (OpenSSLContext.OPENSSL_3 ? SSL_get1_peer_certificate(state.ssl) : SSL_get_peer_certificate(state.ssl));
MemorySegment/*(X509*)*/ x509 = openssl_h_Compatibility.SSL_get_peer_certificate(state.ssl);
MemorySegment bufPointer = localArena.allocateFrom(ValueLayout.ADDRESS, MemorySegment.NULL);
int length = i2d_X509(x509, bufPointer);
if (length <= 0) {
Expand Down Expand Up @@ -1154,7 +1153,7 @@ public int apply(int preverify_ok, MemorySegment /*X509_STORE_CTX*/ x509ctx) {
|| (errnum == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE());
if (verifyErrorIsOptional && (state.certificateVerifyMode == OpenSSLContext.OPTIONAL_NO_CA)) {
ok = 1;
SSL_set_verify_result(state.ssl, X509_V_OK());
openssl_h_Compatibility.SSL_set_verify_result(state.ssl, X509_V_OK());
}
/*
* Expired certificates vs. "expired" CRLs: by default, OpenSSL
Expand Down
22 changes: 11 additions & 11 deletions java/org/apache/tomcat/util/net/openssl/panama/OpenSSLLibrary.java
Original file line number Diff line number Diff line change
Expand Up @@ -182,12 +182,12 @@ public static void init() {
initLibrary();

OpenSSLStatus.setVersion(OpenSSL_version_num());

// OpenSSL 3 onwards uses providers
boolean isOpenSSL3 = (OpenSSL_version_num() >= 0x3000000fL);

// Setup engine
String engineName = "on".equalsIgnoreCase(SSLEngine) ? null : SSLEngine;
if (!isOpenSSL3 && engineName != null) {
if (!openssl_h_Compatibility.OPENSSL3 && !openssl_h_Compatibility.BORINGSSL && engineName != null) {
if ("auto".equals(engineName)) {
ENGINE_register_all_complete();
} else {
Expand Down Expand Up @@ -234,15 +234,15 @@ public static void init() {
RAND_seed(memorySession.allocateFrom(ValueLayout.JAVA_BYTE, randomBytes), 128);
}

if (!isOpenSSL3) {
if (!openssl_h_Compatibility.OPENSSL3 && !openssl_h_Compatibility.BORINGSSL) {
initDHParameters();
}

if (isOpenSSL3 || !(null == FIPSMode || "off".equalsIgnoreCase(FIPSMode))) {
if (openssl_h_Compatibility.OPENSSL3 || !(null == FIPSMode || "off".equalsIgnoreCase(FIPSMode))) {
fipsModeActive = false;
final boolean enterFipsMode;
int fipsModeState = FIPS_OFF;
if (isOpenSSL3) {
if (openssl_h_Compatibility.OPENSSL3) {
var md = EVP_MD_fetch(MemorySegment.NULL, memorySession.allocateFrom("SHA-512"), MemorySegment.NULL);
var provider = EVP_MD_get0_provider(md);
String name = OSSL_PROVIDER_get0_name(provider).getString(0);
Expand All @@ -265,13 +265,13 @@ public static void init() {
enterFipsMode = false;
} else if ("on".equalsIgnoreCase(FIPSMode)) {
if (fipsModeState == FIPS_ON) {
if (!isOpenSSL3) {
if (!openssl_h_Compatibility.OPENSSL3) {
log.info(sm.getString("openssllibrary.skipFIPSInitialization"));
}
fipsModeActive = true;
enterFipsMode = false;
} else {
if (isOpenSSL3) {
if (openssl_h_Compatibility.OPENSSL3) {
throw new IllegalStateException(sm.getString("openssllibrary.FIPSProviderNotDefault", FIPSMode));
} else {
enterFipsMode = true;
Expand All @@ -282,21 +282,21 @@ public static void init() {
fipsModeActive = true;
enterFipsMode = false;
} else {
if (isOpenSSL3) {
if (openssl_h_Compatibility.OPENSSL3) {
throw new IllegalStateException(sm.getString("openssllibrary.FIPSProviderNotDefault", FIPSMode));
} else {
throw new IllegalStateException(sm.getString("openssllibrary.requireNotInFIPSMode"));
}
}
} else if ("enter".equalsIgnoreCase(FIPSMode)) {
if (fipsModeState == FIPS_OFF) {
if (isOpenSSL3) {
if (openssl_h_Compatibility.OPENSSL3) {
throw new IllegalStateException(sm.getString("openssllibrary.FIPSProviderNotDefault", FIPSMode));
} else {
enterFipsMode = true;
}
} else {
if (isOpenSSL3) {
if (openssl_h_Compatibility.OPENSSL3) {
fipsModeActive = true;
enterFipsMode = false;
} else {
Expand Down Expand Up @@ -325,7 +325,7 @@ public static void init() {
log.info(sm.getString("openssllibrary.initializeFIPSSuccess"));
}

if (isOpenSSL3 && fipsModeActive) {
if (openssl_h_Compatibility.OPENSSL3 && fipsModeActive) {
log.info(sm.getString("aprListener.usingFIPSProvider"));
}
}
Expand Down
47 changes: 32 additions & 15 deletions java/org/apache/tomcat/util/openssl/openssl_h_Compatibility.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,22 @@
import java.lang.foreign.*;
import static java.lang.foreign.ValueLayout.*;
import static org.apache.tomcat.util.openssl.openssl_h.OpenSSL_version;
import static org.apache.tomcat.util.openssl.openssl_h.OpenSSL_version_num;
import static org.apache.tomcat.util.openssl.openssl_h.SSL_get1_peer_certificate;

/**
* Methods used present in older OpenSSL versions but not in the current major version.
* Methods used present in older OpenSSL versions but not in the current major version or OpenSSL derivatives.
*/
public class openssl_h_Compatibility {

public static final boolean OPENSSL3;
public static final boolean BORINGSSL;
public static final boolean LIBRESSL;
static {
LIBRESSL = OpenSSL_version(0).getString(0).contains("LibreSSL");
String versionString = OpenSSL_version(0).getString(0);
OPENSSL3 = versionString.contains("OpenSSL") && OpenSSL_version_num() >= 0x3000000fL;
BORINGSSL = versionString.contains("BoringSSL");
LIBRESSL = versionString.contains("LibreSSL");
}

// OpenSSL 1.1 FIPS_mode
Expand Down Expand Up @@ -106,19 +113,23 @@ class Holder {

// OpenSSL 1.1 SSL_get_peer_certificate
public static MemorySegment SSL_get_peer_certificate(MemorySegment s) {
class Holder {
static final String NAME = "SSL_get_peer_certificate";
static final FunctionDescriptor DESC = FunctionDescriptor.of(openssl_h.C_POINTER, openssl_h.C_POINTER);
static final MethodHandle MH = Linker.nativeLinker().downcallHandle(openssl_h.findOrThrow(NAME), DESC);
}
var mh$ = Holder.MH;
try {
if (openssl_h.TRACE_DOWNCALLS) {
openssl_h.traceDowncall(Holder.NAME, s);
if (OPENSSL3) {
return SSL_get1_peer_certificate(s);
} else {
class Holder {
static final String NAME = "SSL_get_peer_certificate";
static final FunctionDescriptor DESC = FunctionDescriptor.of(openssl_h.C_POINTER, openssl_h.C_POINTER);
static final MethodHandle MH = Linker.nativeLinker().downcallHandle(openssl_h.findOrThrow(NAME), DESC);
}
var mh$ = Holder.MH;
try {
if (openssl_h.TRACE_DOWNCALLS) {
openssl_h.traceDowncall(Holder.NAME, s);
}
return (java.lang.foreign.MemorySegment) mh$.invokeExact(s);
} catch (Throwable ex$) {
throw new AssertionError("should not reach here", ex$);
}
return (java.lang.foreign.MemorySegment) mh$.invokeExact(s);
} catch (Throwable ex$) {
throw new AssertionError("should not reach here", ex$);
}
}

Expand Down Expand Up @@ -217,5 +228,11 @@ class Holder {
}
}

}
// BoringSSL removed SSL_set_verify_result which does not do anything in OpenSSL
public static void SSL_set_verify_result(MemorySegment ssl, long v) {
if (!BORINGSSL) {
openssl_h.SSL_set_verify_result(ssl, v);
}
}

}
Loading

0 comments on commit 85a25f3

Please sign in to comment.