Skip to content

Commit

Permalink
SSL improvements: rdrand, sslPeerCertificateChain, autoupdate certifi…
Browse files Browse the repository at this point in the history
…cates
  • Loading branch information
apangin committed Aug 16, 2020
1 parent 5030010 commit 9d3425f
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 22 deletions.
7 changes: 5 additions & 2 deletions src/one/nio/net/NativeSslContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ public void setProtocols(String protocols) {
setOptions(all - enabled);
}

@Override
public native void setRdrand(boolean rdrand) throws SSLException;

@Override
public native void setCiphers(String ciphers) throws SSLException;

Expand All @@ -136,9 +139,9 @@ public void setProtocols(String protocols) {
@Override
public native void setCA(String caFile) throws SSLException;

@Override
@Override
public native void setVerify(int verifyMode) throws SSLException;

@Override
public native void setTicketKeys(byte[] keys) throws SSLException;

Expand Down
13 changes: 8 additions & 5 deletions src/one/nio/net/NativeSslSocket.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,18 @@ public Object getSslOption(SslOption option) {
case 1:
return sslPeerCertificate();
case 2:
return sslCertName(0);
return sslPeerCertificateChain();
case 3:
return sslCertName(1);
return sslCertName(0);
case 4:
return sslVerifyResult();
return sslCertName(1);
case 5:
return sslSessionReused();
return sslVerifyResult();
case 6:
return sslSessionTicket();
return sslSessionReused();
case 7:
return sslSessionTicket();
case 8:
return sslCurrentCipher();
}
return null;
Expand Down Expand Up @@ -108,6 +110,7 @@ public long sendFile(RandomAccessFile file, long offset, long count) throws IOEx
public synchronized native void readFully(byte[] data, int offset, int count) throws IOException;

private synchronized native byte[] sslPeerCertificate();
private synchronized native Object[] sslPeerCertificateChain();
private synchronized native String sslCertName(int which);
private synchronized native String sslVerifyResult();

Expand Down
1 change: 1 addition & 0 deletions src/one/nio/net/SslConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public class SslConfig {
static final long DEFAULT_REFRESH_INTERVAL = 300_000;

public boolean debug;
public boolean rdrand;
public String protocols;
public String ciphers;
public String[] certFile;
Expand Down
39 changes: 39 additions & 0 deletions src/one/nio/net/SslContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public abstract class SslContext {
public static final int VERIFY_ONCE = 4; // do not verify certs on renegotiations

private final AtomicLong nextRefresh = new AtomicLong();
private long lastCertUpdate;
private long lastTicketsUpdate;
private long lastOCSPUpdate;

Expand Down Expand Up @@ -72,6 +73,10 @@ public synchronized SslContext configure(SslConfig config) throws IOException {

setDebug(config.debug);

if (config.rdrand != currentConfig.rdrand) {
setRdrand(config.rdrand);
}

if (changed(config.protocols, currentConfig.protocols)) {
setProtocols(config.protocols);
}
Expand All @@ -83,9 +88,12 @@ public synchronized SslContext configure(SslConfig config) throws IOException {
}

if (changed(config.certFile, currentConfig.certFile)) {
long lastCertUpdate = 0;
for (String certFile : config.certFile) {
setCertificate(certFile);
lastCertUpdate = Math.max(lastCertUpdate, new File(certFile).lastModified());
}
this.lastCertUpdate = lastCertUpdate;
}

if (changed(config.privateKeyFile, currentConfig.privateKeyFile)) {
Expand Down Expand Up @@ -171,6 +179,28 @@ private void inherit(SslConfig parent, SslConfig[] children) {
}
}

void updateCertificates(String[] certFiles, String[] privateKeyFiles) throws IOException {
long maxLastModified = 0;
for (String certFile : certFiles) {
long lastModified = new File(certFile).lastModified();
if (lastModified > lastCertUpdate) {
setCertificate(certFile);
maxLastModified = Math.max(maxLastModified, lastModified);
}
}

if (maxLastModified == 0) {
return;
}

for (String privateKeyFile : privateKeyFiles) {
setPrivateKey(privateKeyFile);
}

log.info("Certificates updated: " + new Date(maxLastModified));
lastCertUpdate = maxLastModified;
}

void updateTicketKeys(String ticketDir, boolean force) throws IOException {
File[] files = new File(ticketDir).listFiles();
if (files == null || files.length == 0) {
Expand Down Expand Up @@ -223,6 +253,14 @@ void refresh() {
return;
}

if (currentConfig.certFile != null && currentConfig.privateKeyFile != null) {
try {
updateCertificates(currentConfig.certFile, currentConfig.privateKeyFile);
} catch (IOException e) {
log.error("Failed to update certificates", e);
}
}

if (currentConfig.ticketDir != null) {
try {
updateTicketKeys(currentConfig.ticketDir, false);
Expand All @@ -243,6 +281,7 @@ void refresh() {
public abstract void setDebug(boolean debug);
public abstract boolean getDebug();

public abstract void setRdrand(boolean rdrand) throws SSLException;
public abstract void setProtocols(String protocols) throws SSLException;
public abstract void setCiphers(String ciphers) throws SSLException;
public abstract void setCertificate(String certFile) throws SSLException;
Expand Down
13 changes: 7 additions & 6 deletions src/one/nio/net/SslOption.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@

public class SslOption<T> {
public static final SslOption<byte[]> PEER_CERTIFICATE = new SslOption<>(1, byte[].class);
public static final SslOption<String> PEER_SUBJECT = new SslOption<>(2, String.class);
public static final SslOption<String> PEER_ISSUER = new SslOption<>(3, String.class);
public static final SslOption<String> VERIFY_RESULT = new SslOption<>(4, String.class);
public static final SslOption<Object[]> PEER_CERTIFICATE_CHAIN = new SslOption<>(2, Object[].class);
public static final SslOption<String> PEER_SUBJECT = new SslOption<>(3, String.class);
public static final SslOption<String> PEER_ISSUER = new SslOption<>(4, String.class);
public static final SslOption<String> VERIFY_RESULT = new SslOption<>(5, String.class);

public static final SslOption<Boolean> SESSION_REUSED = new SslOption<>(5, Boolean.class);
public static final SslOption<Integer> SESSION_TICKET = new SslOption<>(6, Integer.class);
public static final SslOption<Boolean> SESSION_REUSED = new SslOption<>(6, Boolean.class);
public static final SslOption<Integer> SESSION_TICKET = new SslOption<>(7, Integer.class);

public static final SslOption<String> CURRENT_CIPHER = new SslOption<>(7, String.class);
public static final SslOption<String> CURRENT_CIPHER = new SslOption<>(8, String.class);

final int id;
final Class<T> type;
Expand Down
76 changes: 67 additions & 9 deletions src/one/nio/net/native/ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@

#include <openssl/ssl.h>
#include <openssl/bio.h>
#include <openssl/crypto.h>
#include <openssl/dh.h>
#include <openssl/ec.h>
#include <openssl/engine.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
Expand Down Expand Up @@ -427,6 +429,22 @@ static void ssl_info_callback(const SSL* ssl, int cb, int ret) {
}
}

static jbyteArray X509_cert_to_jbyteArray(JNIEnv* env, X509* cert) {
jbyteArray result = NULL;

unsigned char* buf = NULL;
int len = i2d_X509(cert, &buf);
if (buf != NULL) {
result = (*env)->NewByteArray(env, len);
if (result != NULL) {
(*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)buf);
}
OPENSSL_free(buf);
}

return result;
}

JNIEXPORT void JNICALL
Java_one_nio_net_NativeSslContext_init(JNIEnv* env, jclass cls) {
if (dlopen("libssl.so", RTLD_LAZY | RTLD_GLOBAL) == NULL &&
Expand Down Expand Up @@ -513,6 +531,24 @@ Java_one_nio_net_NativeSslContext_clearOptions(JNIEnv* env, jobject self, jint o
SSL_CTX_clear_options(ctx, options);
}

JNIEXPORT void JNICALL
Java_one_nio_net_NativeSslContext_setRdrand(JNIEnv* env, jobject self, jboolean rdrand) {
if (rdrand) {
OPENSSL_init_crypto(/* OPENSSL_INIT_ENGINE_RDRAND */ 0x200L, NULL);
ENGINE* e = ENGINE_by_id("rdrand");
if (e == NULL || !ENGINE_init(e) || !ENGINE_set_default_RAND(e)) {
throw_ssl_exception(env);
}
RAND_set_rand_method(ENGINE_get_RAND(e));
} else {
ENGINE* e = ENGINE_by_id("rdrand");
if (e != NULL) {
ENGINE_unregister_RAND(e);
}
ERR_clear_error();
}
}

JNIEXPORT void JNICALL
Java_one_nio_net_NativeSslContext_setCiphers(JNIEnv* env, jobject self, jstring ciphers) {
SSL_CTX* ctx = (SSL_CTX*)(intptr_t)(*env)->GetLongField(env, self, f_ctx);
Expand Down Expand Up @@ -976,19 +1012,41 @@ Java_one_nio_net_NativeSslSocket_sslPeerCertificate(JNIEnv* env, jobject self) {
return NULL;
}

jbyteArray result = NULL;
jbyteArray result = X509_cert_to_jbyteArray(env, cert);

unsigned char* buf = NULL;
int len = i2d_X509(cert, &buf);
if (buf != NULL) {
result = (*env)->NewByteArray(env, len);
if (result != NULL) {
(*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)buf);
X509_free(cert);
return result;
}

JNIEXPORT jobjectArray JNICALL
Java_one_nio_net_NativeSslSocket_sslPeerCertificateChain(JNIEnv* env, jobject self) {
SSL* ssl = (SSL*)(intptr_t) (*env)->GetLongField(env, self, f_ssl);
if (ssl == NULL) {
return NULL;
}

STACK_OF(X509)* chain = SSL_get_peer_cert_chain(ssl);
if (chain == NULL) {
return NULL;
}

int len = OPENSSL_sk_num((OPENSSL_STACK*)chain);
jclass jbyteArrayClass = (*env)->FindClass(env, "[B");

jobjectArray result = (*env)->NewObjectArray(env, len, jbyteArrayClass, NULL);
if (result != NULL) {
int i;
for (i = 0; i < len; i++) {
X509* cert = (X509*)OPENSSL_sk_value((OPENSSL_STACK*)chain, i);
if (cert != NULL) {
jbyteArray element = X509_cert_to_jbyteArray(env, cert);
if (element != NULL) {
(*env)->SetObjectArrayElement(env, result, i, element);
}
}
}
OPENSSL_free(buf);
}

X509_free(cert);
return result;
}

Expand Down
18 changes: 18 additions & 0 deletions src/one/nio/net/native/sslcompat.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <stdio.h>
#include <pthread.h>
#include <openssl/crypto.h>
#include <openssl/engine.h>
#include <openssl/ssl.h>
#include "sslcompat.h"

Expand Down Expand Up @@ -94,6 +95,13 @@ int OPENSSL_init_ssl(unsigned long long opts, const void* settings) {
return 1;
}

// ENGINE_load_rdrand was replaced with OPENSSL_init_crypto in OpenSSL 1.1.0

int OPENSSL_init_crypto(unsigned long long opts, const void* settings) {
ENGINE_load_rdrand();
return 1;
}


// SSLv23_method() was renamed to TLS_method() in OpenSSL 1.1.0

Expand Down Expand Up @@ -137,4 +145,14 @@ void SSL_CTX_set_alpn_select_cb(SSL_CTX* ctx,
fprintf(stderr, "[WARNING] symbol not found: SSL_CTX_set_alpn_select_cb. ALPN disabled\n");
}

// The following symbols was renamed in OpenSSL 1.1.0, see openssl/stack.h for details

int OPENSSL_sk_num(const OPENSSL_STACK* st) {
return sk_num(st);
}

void* OPENSSL_sk_value(const OPENSSL_STACK* st, int i) {
return sk_value(st, i);
}

#endif // OPENSSL_VERSION_NUMBER < 0x10100000L
11 changes: 11 additions & 0 deletions src/one/nio/net/native/sslcompat.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,22 @@
#define WEAK __attribute__((weak))

#undef OPENSSL_init_ssl
#undef OPENSSL_init_crypto
#undef TLS_method
#undef DH_set0_pqg
#undef SSL_in_init
#undef SSL_CTX_set_options
#undef SSL_CTX_clear_options
#undef SSL_CTX_set_alpn_select_cb

#undef OPENSSL_STACK
#undef OPENSSL_sk_num
#undef OPENSSL_sk_value

typedef struct stack_st OPENSSL_STACK;

int OPENSSL_init_ssl(unsigned long long opts, const void* settings) WEAK;
int OPENSSL_init_crypto(unsigned long long opts, const void* settings) WEAK;
const SSL_METHOD* TLS_method() WEAK;
int DH_set0_pqg(DH* dh, BIGNUM* p, BIGNUM* q, BIGNUM* g) WEAK;
int SSL_in_init(SSL* ssl) WEAK;
Expand All @@ -39,4 +47,7 @@ void SSL_CTX_set_alpn_select_cb(SSL_CTX* ctx,
int (*cb)(SSL* ssl, const unsigned char** out, unsigned char* outlen,
const unsigned char* in, unsigned int inlen, void* arg), void* arg) WEAK;

int OPENSSL_sk_num(const OPENSSL_STACK* st) WEAK;
void* OPENSSL_sk_value(const OPENSSL_STACK* st, int i) WEAK;

#endif // OPENSSL_VERSION_NUMBER < 0x10100000L

0 comments on commit 9d3425f

Please sign in to comment.