Refactoring session management (#172)
This change breaks session management into two distinct types:
- SslSessionWrapper: These are created as BoringSSL calls back the new session handler, allowing the application to cache sessions. Clients will also offer these to BoringSSL for reuse if a compatible session was found. BoringSSL is free to use it or not, but the Conscrypt code no longer makes assumptions here. Instead, it always uses the ActiveSession.
- ActiveSession: This is a session that wraps the SSL instance (rather than the SSL_SESSION wherever possible). That way no concern has to be paid to what BoringSSL is doing with sessions under the covers.
Fixes #98
diff --git a/android/lint.xml b/android/lint.xml
index d899843..0f057a9 100644
--- a/android/lint.xml
+++ b/android/lint.xml
@@ -2,7 +2,7 @@
<lint>
<!-- ExtendedSSLSession only gets instantiated in new APIs on Android. -->
<issue id="NewApi">
- <ignore path="**/org/conscrypt/OpenSSLExtendedSessionImpl.java" />
+ <ignore path="**/org/conscrypt/DelegatingExtendedSSLSession.java" />
</issue>
<!-- Android SparseArrays can't be used in common directory. -->
diff --git a/android/src/main/java/org/conscrypt/Platform.java b/android/src/main/java/org/conscrypt/Platform.java
index be8eba6..32b4b6d 100644
--- a/android/src/main/java/org/conscrypt/Platform.java
+++ b/android/src/main/java/org/conscrypt/Platform.java
@@ -696,12 +696,12 @@
* Pre-Java 8 backward compatibility.
*/
- public static SSLSession wrapSSLSession(AbstractOpenSSLSession sslSession) {
+ public static SSLSession wrapSSLSession(ActiveSession sslSession) {
if (Build.VERSION.SDK_INT <= 23) {
return sslSession;
}
- return new OpenSSLExtendedSessionImpl(sslSession);
+ return new DelegatingExtendedSSLSession(sslSession);
}
public static SSLSession unwrapSSLSession(SSLSession sslSession) {
@@ -709,9 +709,10 @@
return sslSession;
}
- if (sslSession instanceof OpenSSLExtendedSessionImpl) {
- return ((OpenSSLExtendedSessionImpl) sslSession).getDelegate();
+ if (sslSession instanceof DelegatingExtendedSSLSession) {
+ return ((DelegatingExtendedSSLSession) sslSession).getDelegate();
}
+
return sslSession;
}
diff --git a/common/src/jni/main/cpp/NativeCrypto.cpp b/common/src/jni/main/cpp/NativeCrypto.cpp
index 97aa036..02f21ee 100644
--- a/common/src/jni/main/cpp/NativeCrypto.cpp
+++ b/common/src/jni/main/cpp/NativeCrypto.cpp
@@ -981,22 +981,6 @@
return result;
}
-/**
- * private static native int EVP_PKEY_size(int pkey);
- */
-static int NativeCrypto_EVP_PKEY_size(JNIEnv* env, jclass, jobject pkeyRef) {
- EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkeyRef);
- JNI_TRACE("EVP_PKEY_size(%p)", pkey);
-
- if (pkey == nullptr) {
- return -1;
- }
-
- int result = EVP_PKEY_size(pkey);
- JNI_TRACE("EVP_PKEY_size(%p) => %d", pkey, result);
- return result;
-}
-
typedef int print_func(BIO*, const EVP_PKEY*, int, ASN1_PCTX*);
static jstring evp_print_func(JNIEnv* env, jobject pkeyRef, print_func* func,
@@ -2366,23 +2350,6 @@
return result;
}
-/*
- * public static int void EVP_MD_block_size(long)
- */
-static jint NativeCrypto_EVP_MD_block_size(JNIEnv* env, jclass, jlong evpMdRef) {
- EVP_MD* evp_md = reinterpret_cast<EVP_MD*>(evpMdRef);
- JNI_TRACE("NativeCrypto_EVP_MD_block_size(%p)", evp_md);
-
- if (evp_md == nullptr) {
- Errors::jniThrowNullPointerException(env, nullptr);
- return -1;
- }
-
- jint result = static_cast<jint>(EVP_MD_block_size(evp_md));
- JNI_TRACE("NativeCrypto_EVP_MD_block_size(%p) => %d", evp_md, result);
- return result;
-}
-
static jlong evpDigestSignVerifyInit(
JNIEnv* env,
int (*init_func)(EVP_MD_CTX*, EVP_PKEY_CTX**, const EVP_MD*, ENGINE*, EVP_PKEY*),
@@ -3210,18 +3177,6 @@
return nonceLength;
}
-static jint NativeCrypto_EVP_AEAD_max_tag_len(JNIEnv* env, jclass, jlong evpAeadRef) {
- const EVP_AEAD* evpAead = reinterpret_cast<const EVP_AEAD*>(evpAeadRef);
- JNI_TRACE("EVP_AEAD_max_tag_len(%p)", evpAead);
- if (evpAead == nullptr) {
- Errors::jniThrowNullPointerException(env, "evpAead == null");
- return 0;
- }
- jint maxTagLen = static_cast<jint>(EVP_AEAD_max_tag_len(evpAead));
- JNI_TRACE("EVP_AEAD_max_tag_len(%p) => %d", evpAead, maxTagLen);
- return maxTagLen;
-}
-
typedef int (*evp_aead_ctx_op_func)(const EVP_AEAD_CTX *ctx, uint8_t *out,
size_t *out_len, size_t max_out_len,
const uint8_t *nonce, size_t nonce_len,
@@ -3471,41 +3426,6 @@
JNI_TRACE("NativeCrypto_RAND_bytes(%p) => success", output);
}
-static jint NativeCrypto_OBJ_txt2nid(JNIEnv* env, jclass, jstring oidStr) {
- JNI_TRACE("OBJ_txt2nid(%p)", oidStr);
-
- ScopedUtfChars oid(env, oidStr);
- if (oid.c_str() == nullptr) {
- return 0;
- }
-
- int nid = OBJ_txt2nid(oid.c_str());
- JNI_TRACE("OBJ_txt2nid(%s) => %d", oid.c_str(), nid);
- return nid;
-}
-
-static jstring NativeCrypto_OBJ_txt2nid_longName(JNIEnv* env, jclass, jstring oidStr) {
- JNI_TRACE("OBJ_txt2nid_longName(%p)", oidStr);
-
- ScopedUtfChars oid(env, oidStr);
- if (oid.c_str() == nullptr) {
- return nullptr;
- }
-
- JNI_TRACE("OBJ_txt2nid_longName(%s)", oid.c_str());
-
- int nid = OBJ_txt2nid(oid.c_str());
- if (nid == NID_undef) {
- JNI_TRACE("OBJ_txt2nid_longName(%s) => NID_undef", oid.c_str());
- ERR_clear_error();
- return nullptr;
- }
-
- const char* longName = OBJ_nid2ln(nid);
- JNI_TRACE("OBJ_txt2nid_longName(%s) => %s", oid.c_str(), longName);
- return env->NewStringUTF(longName);
-}
-
static jstring ASN1_OBJECT_to_OID_string(JNIEnv* env, const ASN1_OBJECT* obj) {
/*
* The OBJ_obj2txt API doesn't "measure" if you pass in nullptr as the buffer.
@@ -3566,71 +3486,6 @@
return static_cast<jlong>(reinterpret_cast<uintptr_t>(bio.release()));
}
-static int NativeCrypto_BIO_read(JNIEnv* env, jclass, jlong bioRef, jbyteArray outputJavaBytes) {
- BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef));
- JNI_TRACE("BIO_read(%p, %p)", bio, outputJavaBytes);
-
- if (outputJavaBytes == nullptr) {
- Errors::jniThrowNullPointerException(env, "output == null");
- JNI_TRACE("BIO_read(%p, %p) => output == null", bio, outputJavaBytes);
- return 0;
- }
-
- jsize outputSize = env->GetArrayLength(outputJavaBytes);
-
- std::unique_ptr<unsigned char[]> buffer(
- new unsigned char[static_cast<unsigned int>(outputSize)]);
- if (buffer.get() == nullptr) {
- Errors::jniThrowOutOfMemory(env, "Unable to allocate buffer for read");
- return 0;
- }
-
- int read = BIO_read(bio, buffer.get(), static_cast<int>(outputSize));
- if (read <= 0) {
- Errors::throwIOException(env, "BIO_read");
- JNI_TRACE("BIO_read(%p, %p) => threw IO exception", bio, outputJavaBytes);
- return 0;
- }
-
- env->SetByteArrayRegion(outputJavaBytes, 0, read, reinterpret_cast<jbyte*>(buffer.get()));
- JNI_TRACE("BIO_read(%p, %p) => %d", bio, outputJavaBytes, read);
- return read;
-}
-
-static void NativeCrypto_BIO_write(JNIEnv* env, jclass, jlong bioRef, jbyteArray inputJavaBytes,
- jint offset, jint length) {
- BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef));
- JNI_TRACE("BIO_write(%p, %p, %d, %d)", bio, inputJavaBytes, offset, length);
-
- if (inputJavaBytes == nullptr) {
- Errors::jniThrowNullPointerException(env, "input == null");
- return;
- }
-
- int inputSize = env->GetArrayLength(inputJavaBytes);
- if (offset < 0 || offset > inputSize || length < 0 || length > inputSize - offset) {
- Errors::jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", "inputJavaBytes");
- JNI_TRACE("BIO_write(%p, %p, %d, %d) => IOOB", bio, inputJavaBytes, offset, length);
- return;
- }
-
- std::unique_ptr<unsigned char[]> buffer(new unsigned char[static_cast<unsigned int>(length)]);
- if (buffer.get() == nullptr) {
- Errors::jniThrowOutOfMemory(env, "Unable to allocate buffer for write");
- return;
- }
-
- env->GetByteArrayRegion(inputJavaBytes, offset, length, reinterpret_cast<jbyte*>(buffer.get()));
- if (BIO_write(bio, buffer.get(), length) != length) {
- ERR_clear_error();
- Errors::throwIOException(env, "BIO_write");
- JNI_TRACE("BIO_write(%p, %p, %d, %d) => IO error", bio, inputJavaBytes, offset, length);
- return;
- }
-
- JNI_TRACE("BIO_write(%p, %p, %d, %d) => success", bio, inputJavaBytes, offset, length);
-}
-
static void NativeCrypto_BIO_free_all(JNIEnv* env, jclass, jlong bioRef) {
BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef));
JNI_TRACE("BIO_free_all(%p)", bio);
@@ -4456,48 +4311,6 @@
sec);
}
-static jstring NativeCrypto_OBJ_txt2nid_oid(JNIEnv* env, jclass, jstring oidStr) {
- JNI_TRACE("OBJ_txt2nid_oid(%p)", oidStr);
-
- ScopedUtfChars oid(env, oidStr);
- if (oid.c_str() == nullptr) {
- return nullptr;
- }
-
- JNI_TRACE("OBJ_txt2nid_oid(%s)", oid.c_str());
-
- int nid = OBJ_txt2nid(oid.c_str());
- if (nid == NID_undef) {
- JNI_TRACE("OBJ_txt2nid_oid(%s) => NID_undef", oid.c_str());
- ERR_clear_error();
- return nullptr;
- }
-
- const ASN1_OBJECT* obj = OBJ_nid2obj(nid);
- if (obj == nullptr) {
- Errors::throwExceptionIfNecessary(env, "OBJ_nid2obj");
- return nullptr;
- }
-
- ScopedLocalRef<jstring> ouputStr(env, ASN1_OBJECT_to_OID_string(env, obj));
- JNI_TRACE("OBJ_txt2nid_oid(%s) => %p", oid.c_str(), ouputStr.get());
- return ouputStr.release();
-}
-
-static jstring NativeCrypto_X509_NAME_print_ex(JNIEnv* env, jclass, jlong x509NameRef, jlong jflags) {
- X509_NAME* x509name = reinterpret_cast<X509_NAME*>(static_cast<uintptr_t>(x509NameRef));
- unsigned long flags = static_cast<unsigned long>(jflags);
- JNI_TRACE("X509_NAME_print_ex(%p, %ld)", x509name, flags);
-
- if (x509name == nullptr) {
- Errors::jniThrowNullPointerException(env, "x509name == null");
- JNI_TRACE("X509_NAME_print_ex(%p, %ld) => x509name == null", x509name, flags);
- return nullptr;
- }
-
- return X509_NAME_to_jstring(env, x509name, flags);
-}
-
template <typename T, T* (*d2i_func)(BIO*, T**)>
static jlong d2i_ASN1Object_to_jlong(JNIEnv* env, jlong bioRef) {
BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef));
@@ -5846,6 +5659,79 @@
return static_cast<unsigned int>(keyLen);
}
+static int new_session_callback(SSL* ssl, SSL_SESSION* session) {
+ JNI_TRACE("ssl=%p new_session_callback session=%p", ssl, session);
+
+ AppData* appData = toAppData(ssl);
+ JNIEnv* env = appData->env;
+ if (env == nullptr) {
+ ALOGE("AppData->env missing in new_session_callback");
+ JNI_TRACE("ssl=%p new_session_callback env error", ssl);
+ return 0;
+ }
+ if (env->ExceptionCheck()) {
+ JNI_TRACE("ssl=%p new_session_callback already pending exception", ssl);
+ return 0;
+ }
+
+ jobject sslHandshakeCallbacks = appData->sslHandshakeCallbacks;
+ jclass cls = env->GetObjectClass(sslHandshakeCallbacks);
+ jmethodID methodID = env->GetMethodID(cls, "onNewSessionEstablished", "(J)V");
+ JNI_TRACE("ssl=%p new_session_callback calling onNewSessionEstablished", ssl);
+ env->CallVoidMethod(sslHandshakeCallbacks, methodID, reinterpret_cast<jlong>(session));
+ if (env->ExceptionCheck()) {
+ JNI_TRACE("ssl=%p new_session_callback exception cleared", ssl);
+ env->ExceptionClear();
+ }
+ JNI_TRACE("ssl=%p new_session_callback completed", ssl);
+
+ // Always returning 0 (not taking ownership). The Java code is responsible for incrementing
+ // the reference count.
+ return 0;
+}
+
+static SSL_SESSION* server_session_requested_callback(SSL* ssl, uint8_t* id, int id_len,
+ int* out_copy) {
+ JNI_TRACE("ssl=%p server_session_requested_callback", ssl);
+
+ // Always set to out_copy to zero. The Java callback will be responsible for incrementing
+ // the reference count (and any required synchronization).
+ *out_copy = 0;
+
+ AppData* appData = toAppData(ssl);
+ JNIEnv* env = appData->env;
+ if (env == nullptr) {
+ ALOGE("AppData->env missing in server_session_requested_callback");
+ JNI_TRACE("ssl=%p server_session_requested_callback env error", ssl);
+ return 0;
+ }
+ if (env->ExceptionCheck()) {
+ JNI_TRACE("ssl=%p server_session_requested_callback already pending exception", ssl);
+ return 0;
+ }
+
+ // Copy the ID to a byte[].
+ jbyteArray id_array = env->NewByteArray(static_cast<jsize>(id_len));
+ if (id_array == nullptr) {
+ JNI_TRACE("ssl=%p id_array bytes == null => 0", ssl);
+ return 0;
+ }
+ env->SetByteArrayRegion(id_array, 0, static_cast<jsize>(id_len),
+ reinterpret_cast<const jbyte*>(id));
+
+ jobject sslHandshakeCallbacks = appData->sslHandshakeCallbacks;
+ jclass cls = env->GetObjectClass(sslHandshakeCallbacks);
+ jmethodID methodID = env->GetMethodID(cls, "serverSessionRequested", "([B)J");
+ JNI_TRACE("ssl=%p server_session_requested_callback calling serverSessionRequested", ssl);
+ jlong ssl_session_address = env->CallLongMethod(sslHandshakeCallbacks, methodID, id_array);
+ if (env->ExceptionCheck()) {
+ JNI_TRACE("ssl=%p server_session_requested_callback exception cleared", ssl);
+ env->ExceptionClear();
+ }
+ JNI_TRACE("ssl=%p server_session_requested_callback completed => %d", ssl, ssl_session_address);
+ return reinterpret_cast<SSL_SESSION*>(static_cast<uintptr_t>(ssl_session_address));
+}
+
static jint NativeCrypto_EVP_has_aes_hardware(JNIEnv*, jclass) {
int ret = 0;
ret = EVP_has_aes_hardware();
@@ -5959,6 +5845,14 @@
SSL_CTX_set_keylog_callback(sslCtx.get(), debug_print_session_key);
}
+ // By default BoringSSL will cache in server mode, but we want to get
+ // notified of new sessions being created in client mode. We set
+ // SSL_SESS_CACHE_BOTH in order to get the callback in client mode, but
+ // ignore it in server mode in favor of the internal cache.
+ SSL_CTX_set_session_cache_mode(sslCtx.get(), SSL_SESS_CACHE_BOTH);
+ SSL_CTX_sess_set_new_cb(sslCtx.get(), new_session_callback);
+ SSL_CTX_sess_set_get_cb(sslCtx.get(), server_session_requested_callback);
+
// Disable RSA-PSS deliberately until CryptoUpcalls supports it.
if (!SSL_CTX_set_signing_algorithm_prefs(
sslCtx.get(), kDefaultSignatureAlgorithms,
@@ -6016,6 +5910,18 @@
JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_CTX_set_session_id_context => ok", ssl_ctx);
}
+static jlong NativeCrypto_SSL_CTX_set_timeout(JNIEnv* env, jclass, jlong ssl_ctx_address,
+ jlong seconds)
+{
+ SSL_CTX* ssl_ctx = to_SSL_CTX(env, ssl_ctx_address, true);
+ JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_CTX_set_timeout seconds=%d", ssl_ctx, (int) seconds);
+ if (ssl_ctx == nullptr) {
+ return 0L;
+ }
+
+ return SSL_CTX_set_timeout(ssl_ctx, static_cast<uint32_t>(seconds));
+}
+
/**
* public static native int SSL_new(long ssl_ctx) throws SSLException;
*/
@@ -6315,20 +6221,6 @@
}
/**
- * public static native long SSL_get_mode(long ssl);
- */
-static jlong NativeCrypto_SSL_get_mode(JNIEnv* env, jclass, jlong ssl_address) {
- SSL* ssl = to_SSL(env, ssl_address, true);
- JNI_TRACE("ssl=%p NativeCrypto_SSL_get_mode", ssl);
- if (ssl == nullptr) {
- return 0;
- }
- long mode = static_cast<long>(SSL_get_mode(ssl));
- JNI_TRACE("ssl=%p NativeCrypto_SSL_get_mode => 0x%lx", ssl, mode);
- return mode;
-}
-
-/**
* public static native long SSL_set_mode(long ssl, long mode);
*/
static jlong NativeCrypto_SSL_set_mode(JNIEnv* env, jclass,
@@ -6344,36 +6236,6 @@
}
/**
- * public static native long SSL_clear_mode(long ssl, long mode);
- */
-static jlong NativeCrypto_SSL_clear_mode(JNIEnv* env, jclass,
- jlong ssl_address, jlong mode) {
- SSL* ssl = to_SSL(env, ssl_address, true);
- JNI_TRACE("ssl=%p NativeCrypto_SSL_clear_mode mode=0x%llx", ssl, (long long) mode);
- if (ssl == nullptr) {
- return 0;
- }
- long result = static_cast<long>(SSL_clear_mode(ssl, static_cast<uint32_t>(mode)));
- JNI_TRACE("ssl=%p NativeCrypto_SSL_clear_mode => 0x%lx", ssl, result);
- return result;
-}
-
-/**
- * public static native long SSL_get_options(long ssl);
- */
-static jlong NativeCrypto_SSL_get_options(JNIEnv* env, jclass,
- jlong ssl_address) {
- SSL* ssl = to_SSL(env, ssl_address, true);
- JNI_TRACE("ssl=%p NativeCrypto_SSL_get_options", ssl);
- if (ssl == nullptr) {
- return 0;
- }
- long options = static_cast<long>(SSL_get_options(ssl));
- JNI_TRACE("ssl=%p NativeCrypto_SSL_get_options => 0x%lx", ssl, options);
- return options;
-}
-
-/**
* public static native long SSL_set_options(long ssl, long options);
*/
static jlong NativeCrypto_SSL_set_options(JNIEnv* env, jclass,
@@ -7108,33 +6970,27 @@
JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake => success", ssl);
}
-/**
- * Perform SSL renegotiation
- */
-static void NativeCrypto_SSL_renegotiate(JNIEnv* env, jclass, jlong ssl_address)
-{
+static jstring NativeCrypto_SSL_get_current_cipher(JNIEnv* env, jclass, jlong ssl_address) {
SSL* ssl = to_SSL(env, ssl_address, true);
- JNI_TRACE("ssl=%p NativeCrypto_SSL_renegotiate", ssl);
+ JNI_TRACE("ssl=%p NativeCrypto_SSL_get_current_cipher", ssl);
if (ssl == nullptr) {
- return;
+ return nullptr;
}
- int result = SSL_renegotiate(ssl);
- if (result != 1) {
- Errors::throwSSLExceptionStr(env, "Problem with SSL_renegotiate");
- return;
+ const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl);
+ const char* name = SSL_CIPHER_get_name(cipher);
+ JNI_TRACE("ssl=%p NativeCrypto_SSL_get_current_cipher => %s", ssl, name);
+ return env->NewStringUTF(name);
+}
+
+static jstring NativeCrypto_SSL_get_version(JNIEnv* env, jclass, jlong ssl_address) {
+ SSL* ssl = to_SSL(env, ssl_address, true);
+ JNI_TRACE("ssl=%p NativeCrypto_SSL_get_version", ssl);
+ if (ssl == nullptr) {
+ return nullptr;
}
- // first call asks client to perform renegotiation
- int ret = SSL_do_handshake(ssl);
- if (ret != 1) {
- OpenSslError sslError(ssl, ret);
- Errors::throwSSLExceptionWithSslErrors(env, ssl, sslError.release(),
- "Problem with SSL_do_handshake after SSL_renegotiate");
- return;
- }
- // if client agrees, set ssl state and perform renegotiation
- SSL_set_state(ssl, SSL_ST_ACCEPT);
- SSL_do_handshake(ssl);
- JNI_TRACE("ssl=%p NativeCrypto_SSL_renegotiate =>", ssl);
+ const char* protocol = SSL_get_version(ssl);
+ JNI_TRACE("ssl=%p NativeCrypto_SSL_get_version => %s", ssl, protocol);
+ return env->NewStringUTF(protocol);
}
/**
@@ -7954,6 +7810,114 @@
}
/**
+ * Gets and returns in a long integer the creation's time of the
+ * actual SSL session.
+ */
+static jlong NativeCrypto_SSL_get_time(JNIEnv* env, jclass, jlong ssl_address) {
+ SSL* ssl = to_SSL(env, ssl_address, true);
+ JNI_TRACE("ssl=%p NativeCrypto_SSL_get_time", ssl);
+ if (ssl == nullptr) {
+ return 0;
+ }
+
+ SSL_SESSION* ssl_session = SSL_get_session(ssl);
+ JNI_TRACE("ssl_session=%p NativeCrypto_SSL_get_time", ssl_session);
+ if (ssl_session == nullptr) {
+ // BoringSSL does not protect against a NULL session.
+ return 0;
+ }
+ // result must be jlong, not long or *1000 will overflow
+ jlong result = SSL_SESSION_get_time(ssl_session);
+ result *= 1000; // OpenSSL uses seconds, Java uses milliseconds.
+ JNI_TRACE("ssl_session=%p NativeCrypto_SSL_get_time => %lld", ssl_session, (long long) result);
+ return result;
+}
+
+/**
+ * Sets the timeout on the SSL session.
+ */
+static jlong NativeCrypto_SSL_set_timeout(JNIEnv* env, jclass, jlong ssl_address, jlong millis) {
+ SSL* ssl = to_SSL(env, ssl_address, true);
+ JNI_TRACE("ssl=%p NativeCrypto_SSL_set_timeout", ssl);
+ if (ssl == nullptr) {
+ return 0;
+ }
+
+ SSL_SESSION* ssl_session = SSL_get_session(ssl);
+ JNI_TRACE("ssl_session=%p NativeCrypto_SSL_set_timeout", ssl_session);
+ if (ssl_session == nullptr) {
+ // BoringSSL does not protect against a NULL session.
+ return 0;
+ }
+
+ // Convert to seconds
+ long timeout = millis / 1000;
+ return SSL_set_timeout(ssl_session, timeout);
+}
+
+/**
+ * Gets the timeout for the SSL session.
+ */
+static jlong NativeCrypto_SSL_get_timeout(JNIEnv* env, jclass, jlong ssl_address) {
+ SSL* ssl = to_SSL(env, ssl_address, true);
+ JNI_TRACE("ssl=%p NativeCrypto_SSL_get_timeout", ssl);
+ if (ssl == nullptr) {
+ return 0;
+ }
+
+ SSL_SESSION* ssl_session = SSL_get_session(ssl);
+ JNI_TRACE("ssl_session=%p NativeCrypto_SSL_get_timeout", ssl_session);
+ if (ssl_session == nullptr) {
+ // BoringSSL does not protect against a NULL session.
+ return 0;
+ }
+
+ jlong result = SSL_get_timeout(ssl_session);
+ result *= 1000; // OpenSSL uses seconds, Java uses milliseconds.
+ JNI_TRACE("ssl_session=%p NativeCrypto_SSL_get_timeout => %lld", ssl_session, (long long) result);
+ return result;
+}
+
+/**
+ * Gets the timeout for the SSL session.
+ */
+static jlong NativeCrypto_SSL_SESSION_get_timeout(JNIEnv* env, jclass, jlong ssl_session_address) {
+ SSL_SESSION* ssl_session = to_SSL_SESSION(env, ssl_session_address, true);
+ JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_get_timeout", ssl_session);
+ if (ssl_session == nullptr) {
+ return 0;
+ }
+
+ return SSL_get_timeout(ssl_session);
+}
+
+/**
+ * Gets the ID for the SSL session, or null if no session is currently available.
+ */
+static jbyteArray NativeCrypto_SSL_session_id(JNIEnv* env, jclass, jlong ssl_address) {
+ SSL* ssl = to_SSL(env, ssl_address, true);
+ JNI_TRACE("ssl=%p NativeCrypto_SSL_session_id", ssl);
+ if (ssl == nullptr) {
+ return nullptr;
+ }
+
+ SSL_SESSION* ssl_session = SSL_get_session(ssl);
+ JNI_TRACE("ssl_session=%p NativeCrypto_SSL_session_id", ssl_session);
+ if (ssl_session == nullptr) {
+ return nullptr;
+ }
+
+ jbyteArray result = env->NewByteArray(static_cast<jsize>(ssl_session->session_id_length));
+ if (result != nullptr) {
+ jbyte* src = reinterpret_cast<jbyte*>(ssl_session->session_id);
+ env->SetByteArrayRegion(result, 0, static_cast<jsize>(ssl_session->session_id_length), src);
+ }
+ JNI_TRACE("ssl_session=%p NativeCrypto_SSL_session_id => %p session_id_length=%d",
+ ssl_session, result, ssl_session->session_id_length);
+ return result;
+}
+
+/**
* Gets and returns in a string the version of the SSL protocol. If it
* returns the string "unknown" it means that no connection is established.
*/
@@ -7983,17 +7947,16 @@
return env->NewStringUTF(name);
}
-static jstring NativeCrypto_get_SSL_SESSION_tlsext_hostname(JNIEnv* env, jclass, jlong sessionJava) {
- SSL_SESSION* ssl_session = to_SSL_SESSION(env, sessionJava, true);
- JNI_TRACE("ssl_session=%p NativeCrypto_get_SSL_SESSION_tlsext_hostname", ssl_session);
- if (ssl_session == nullptr || ssl_session->tlsext_hostname == nullptr) {
- JNI_TRACE("ssl_session=%p NativeCrypto_get_SSL_SESSION_tlsext_hostname => null",
- ssl_session);
- return nullptr;
+/**
+ * Increments the reference count of the session.
+ */
+static void NativeCrypto_SSL_SESSION_up_ref(JNIEnv* env, jclass, jlong ssl_session_address) {
+ SSL_SESSION* ssl_session = to_SSL_SESSION(env, ssl_session_address, true);
+ JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_up_ref", ssl_session);
+ if (ssl_session == nullptr) {
+ return;
}
- JNI_TRACE("ssl_session=%p NativeCrypto_get_SSL_SESSION_tlsext_hostname => \"%s\"",
- ssl_session, ssl_session->tlsext_hostname);
- return env->NewStringUTF(ssl_session->tlsext_hostname);
+ SSL_SESSION_up_ref(ssl_session);
}
/**
@@ -8389,22 +8352,6 @@
return static_cast<jint>(BIO_ctrl_pending(bio));
}
-static jlong NativeCrypto_SSL_get0_session(JNIEnv* env, jclass, jlong ssl_address) {
- SSL* ssl = to_SSL(env, ssl_address, true);
- if (ssl == nullptr) {
- return 0;
- }
- return reinterpret_cast<uintptr_t>(SSL_get0_session(ssl));
-}
-
-static jlong NativeCrypto_SSL_get1_session(JNIEnv* env, jclass, jlong ssl_address) {
- SSL* ssl = to_SSL(env, ssl_address, true);
- if (ssl == nullptr) {
- return 0;
- }
- return reinterpret_cast<uintptr_t>(SSL_get1_session(ssl));
-}
-
static jint NativeCrypto_SSL_max_seal_overhead(JNIEnv* env, jclass, jlong ssl_address) {
SSL* ssl = to_SSL(env, ssl_address, true);
if (ssl == nullptr) {
@@ -9071,7 +9018,7 @@
Errors::throwSSLExceptionStr(env, "Unable to set appdata callback");
ERR_clear_error();
safeSslClear(ssl);
- JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake_netty => exception", ssl);
+ JNI_TRACE("ssl=%p NativeCrypto_ENGINE_SSL_write_heap => exception", ssl);
return -1;
}
@@ -9087,6 +9034,156 @@
return result;
}
+// TESTING METHODS BEGIN
+
+static int NativeCrypto_BIO_read(JNIEnv* env, jclass, jlong bioRef, jbyteArray outputJavaBytes) {
+ BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef));
+ JNI_TRACE("BIO_read(%p, %p)", bio, outputJavaBytes);
+
+ if (outputJavaBytes == nullptr) {
+ Errors::jniThrowNullPointerException(env, "output == null");
+ JNI_TRACE("BIO_read(%p, %p) => output == null", bio, outputJavaBytes);
+ return 0;
+ }
+
+ jsize outputSize = env->GetArrayLength(outputJavaBytes);
+
+ std::unique_ptr<unsigned char[]> buffer(
+ new unsigned char[static_cast<unsigned int>(outputSize)]);
+ if (buffer.get() == nullptr) {
+ Errors::jniThrowOutOfMemory(env, "Unable to allocate buffer for read");
+ return 0;
+ }
+
+ int read = BIO_read(bio, buffer.get(), static_cast<int>(outputSize));
+ if (read <= 0) {
+ Errors::throwIOException(env, "BIO_read");
+ JNI_TRACE("BIO_read(%p, %p) => threw IO exception", bio, outputJavaBytes);
+ return 0;
+ }
+
+ env->SetByteArrayRegion(outputJavaBytes, 0, read, reinterpret_cast<jbyte*>(buffer.get()));
+ JNI_TRACE("BIO_read(%p, %p) => %d", bio, outputJavaBytes, read);
+ return read;
+}
+
+static void NativeCrypto_BIO_write(JNIEnv* env, jclass, jlong bioRef, jbyteArray inputJavaBytes,
+ jint offset, jint length) {
+ BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef));
+ JNI_TRACE("BIO_write(%p, %p, %d, %d)", bio, inputJavaBytes, offset, length);
+
+ if (inputJavaBytes == nullptr) {
+ Errors::jniThrowNullPointerException(env, "input == null");
+ return;
+ }
+
+ int inputSize = env->GetArrayLength(inputJavaBytes);
+ if (offset < 0 || offset > inputSize || length < 0 || length > inputSize - offset) {
+ Errors::jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", "inputJavaBytes");
+ JNI_TRACE("BIO_write(%p, %p, %d, %d) => IOOB", bio, inputJavaBytes, offset, length);
+ return;
+ }
+
+ std::unique_ptr<unsigned char[]> buffer(new unsigned char[static_cast<unsigned int>(length)]);
+ if (buffer.get() == nullptr) {
+ Errors::jniThrowOutOfMemory(env, "Unable to allocate buffer for write");
+ return;
+ }
+
+ env->GetByteArrayRegion(inputJavaBytes, offset, length, reinterpret_cast<jbyte*>(buffer.get()));
+ if (BIO_write(bio, buffer.get(), length) != length) {
+ ERR_clear_error();
+ Errors::throwIOException(env, "BIO_write");
+ JNI_TRACE("BIO_write(%p, %p, %d, %d) => IO error", bio, inputJavaBytes, offset, length);
+ return;
+ }
+
+ JNI_TRACE("BIO_write(%p, %p, %d, %d) => success", bio, inputJavaBytes, offset, length);
+}
+
+/**
+ * public static native long SSL_clear_mode(long ssl, long mode);
+ */
+static jlong NativeCrypto_SSL_clear_mode(JNIEnv* env, jclass,
+ jlong ssl_address, jlong mode) {
+ SSL* ssl = to_SSL(env, ssl_address, true);
+ JNI_TRACE("ssl=%p NativeCrypto_SSL_clear_mode mode=0x%llx", ssl, (long long) mode);
+ if (ssl == nullptr) {
+ return 0;
+ }
+ long result = static_cast<long>(SSL_clear_mode(ssl, static_cast<uint32_t>(mode)));
+ JNI_TRACE("ssl=%p NativeCrypto_SSL_clear_mode => 0x%lx", ssl, result);
+ return result;
+}
+
+/**
+ * public static native long SSL_get_mode(long ssl);
+ */
+static jlong NativeCrypto_SSL_get_mode(JNIEnv* env, jclass, jlong ssl_address) {
+ SSL* ssl = to_SSL(env, ssl_address, true);
+ JNI_TRACE("ssl=%p NativeCrypto_SSL_get_mode", ssl);
+ if (ssl == nullptr) {
+ return 0;
+ }
+ long mode = static_cast<long>(SSL_get_mode(ssl));
+ JNI_TRACE("ssl=%p NativeCrypto_SSL_get_mode => 0x%lx", ssl, mode);
+ return mode;
+}
+
+/**
+ * public static native long SSL_get_options(long ssl);
+ */
+static jlong NativeCrypto_SSL_get_options(JNIEnv* env, jclass,
+ jlong ssl_address) {
+ SSL* ssl = to_SSL(env, ssl_address, true);
+ JNI_TRACE("ssl=%p NativeCrypto_SSL_get_options", ssl);
+ if (ssl == nullptr) {
+ return 0;
+ }
+ long options = static_cast<long>(SSL_get_options(ssl));
+ JNI_TRACE("ssl=%p NativeCrypto_SSL_get_options => 0x%lx", ssl, options);
+ return options;
+}
+
+static jlong NativeCrypto_SSL_get1_session(JNIEnv* env, jclass, jlong ssl_address) {
+ SSL* ssl = to_SSL(env, ssl_address, true);
+ if (ssl == nullptr) {
+ return 0;
+ }
+ return reinterpret_cast<uintptr_t>(SSL_get1_session(ssl));
+}
+
+/**
+ * Perform SSL renegotiation
+ */
+static void NativeCrypto_SSL_renegotiate(JNIEnv* env, jclass, jlong ssl_address)
+{
+ SSL* ssl = to_SSL(env, ssl_address, true);
+ JNI_TRACE("ssl=%p NativeCrypto_SSL_renegotiate", ssl);
+ if (ssl == nullptr) {
+ return;
+ }
+ int result = SSL_renegotiate(ssl);
+ if (result != 1) {
+ Errors::throwSSLExceptionStr(env, "Problem with SSL_renegotiate");
+ return;
+ }
+ // first call asks client to perform renegotiation
+ int ret = SSL_do_handshake(ssl);
+ if (ret != 1) {
+ OpenSslError sslError(ssl, ret);
+ Errors::throwSSLExceptionWithSslErrors(env, ssl, sslError.release(),
+ "Problem with SSL_do_handshake after SSL_renegotiate");
+ return;
+ }
+ // if client agrees, set ssl state and perform renegotiation
+ SSL_set_state(ssl, SSL_ST_ACCEPT);
+ SSL_do_handshake(ssl);
+ JNI_TRACE("ssl=%p NativeCrypto_SSL_renegotiate => OK", ssl);
+}
+
+// TESTING METHODS END
+
#define CONSCRYPT_NATIVE_METHOD(className, functionName, signature) \
{ \
(char*)#functionName, (char*)(signature), \
@@ -9110,7 +9207,6 @@
CONSCRYPT_NATIVE_METHOD(NativeCrypto, EVP_PKEY_new_RSA, "([B[B[B[B[B[B[B[B)J"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, EVP_PKEY_new_EC_KEY, "(" REF_EC_GROUP REF_EC_POINT "[B)J"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, EVP_PKEY_type, "(" REF_EVP_PKEY ")I"),
- CONSCRYPT_NATIVE_METHOD(NativeCrypto, EVP_PKEY_size, "(" REF_EVP_PKEY ")I"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, EVP_PKEY_print_public, "(" REF_EVP_PKEY ")Ljava/lang/String;"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, EVP_PKEY_print_params, "(" REF_EVP_PKEY ")Ljava/lang/String;"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, EVP_PKEY_free, "(J)V"),
@@ -9165,7 +9261,6 @@
CONSCRYPT_NATIVE_METHOD(NativeCrypto, EVP_DigestUpdateDirect, "(" REF_EVP_MD_CTX "JI)V"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, EVP_DigestFinal_ex, "(" REF_EVP_MD_CTX "[BI)I"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, EVP_get_digestbyname, "(Ljava/lang/String;)J"),
- CONSCRYPT_NATIVE_METHOD(NativeCrypto, EVP_MD_block_size, "(J)I"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, EVP_MD_size, "(J)I"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, EVP_DigestSignInit, "(" REF_EVP_MD_CTX "J" REF_EVP_PKEY ")J"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, EVP_DigestSignUpdate, "(" REF_EVP_MD_CTX "[BII)V"),
@@ -9201,7 +9296,6 @@
CONSCRYPT_NATIVE_METHOD(NativeCrypto, EVP_aead_aes_256_gcm, "()J"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, EVP_AEAD_max_overhead, "(J)I"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, EVP_AEAD_nonce_length, "(J)I"),
- CONSCRYPT_NATIVE_METHOD(NativeCrypto, EVP_AEAD_max_tag_len, "(J)I"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, EVP_AEAD_CTX_seal, "(J[BI[BI[B[BII[B)I"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, EVP_AEAD_CTX_open, "(J[BI[BI[B[BII[B)I"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, HMAC_CTX_new, "()J"),
@@ -9211,15 +9305,9 @@
CONSCRYPT_NATIVE_METHOD(NativeCrypto, HMAC_UpdateDirect, "(" REF_HMAC_CTX "JI)V"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, HMAC_Final, "(" REF_HMAC_CTX ")[B"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, RAND_bytes, "([B)V"),
- CONSCRYPT_NATIVE_METHOD(NativeCrypto, OBJ_txt2nid, "(Ljava/lang/String;)I"),
- CONSCRYPT_NATIVE_METHOD(NativeCrypto, OBJ_txt2nid_longName, "(Ljava/lang/String;)Ljava/lang/String;"),
- CONSCRYPT_NATIVE_METHOD(NativeCrypto, OBJ_txt2nid_oid, "(Ljava/lang/String;)Ljava/lang/String;"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, create_BIO_InputStream, ("(" REF_BIO_IN_STREAM "Z)J")),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, create_BIO_OutputStream, "(Ljava/io/OutputStream;)J"),
- CONSCRYPT_NATIVE_METHOD(NativeCrypto, BIO_read, "(J[B)I"),
- CONSCRYPT_NATIVE_METHOD(NativeCrypto, BIO_write, "(J[BII)V"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, BIO_free_all, "(J)V"),
- CONSCRYPT_NATIVE_METHOD(NativeCrypto, X509_NAME_print_ex, "(JJ)Ljava/lang/String;"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, d2i_X509_bio, "(J)J"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, d2i_X509, "([B)J"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, i2d_X509, "(J)[B"),
@@ -9292,6 +9380,7 @@
CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_CTX_new, "()J"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_CTX_free, "(J)V"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_CTX_set_session_id_context, "(J[B)V"),
+ CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_CTX_set_timeout, "(JJ)J"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_new, "(J)J"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_enable_tls_channel_id, "(J)V"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_get_tls_channel_id, "(J)[B"),
@@ -9300,10 +9389,7 @@
CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_use_certificate, "(J[J)V"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_check_private_key, "(J)V"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_set_client_CA_list, "(J[[B)V"),
- CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_get_mode, "(J)J"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_set_mode, "(JJ)J"),
- CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_clear_mode, "(JJ)J"),
- CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_get_options, "(J)J"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_set_options, "(JJ)J"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_clear_options, "(JJ)J"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_enable_signed_cert_timestamps, "(J)V"),
@@ -9327,7 +9413,8 @@
CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_set_tlsext_host_name, "(JLjava/lang/String;)V"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_get_servername, "(J)Ljava/lang/String;"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_do_handshake, "(J" FILE_DESCRIPTOR SSL_CALLBACKS "I)V"),
- CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_renegotiate, "(J)V"),
+ CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_get_current_cipher, "(J)Ljava/lang/String;"),
+ CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_get_version, "(J)Ljava/lang/String;"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_get_certificate, "(J)[J"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_get_peer_cert_chain, "(J)[J"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_read, "(J" FILE_DESCRIPTOR SSL_CALLBACKS "[BIII)I"),
@@ -9339,9 +9426,14 @@
CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_free, "(J)V"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_SESSION_session_id, "(J)[B"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_SESSION_get_time, "(J)J"),
+ CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_get_time, "(J)J"),
+ CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_set_timeout, "(JJ)J"),
+ CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_get_timeout, "(J)J"),
+ CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_SESSION_get_timeout, "(J)J"),
+ CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_session_id, "(J)[B"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_SESSION_get_version, "(J)Ljava/lang/String;"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_SESSION_cipher, "(J)Ljava/lang/String;"),
- CONSCRYPT_NATIVE_METHOD(NativeCrypto, get_SSL_SESSION_tlsext_hostname, "(J)Ljava/lang/String;"),
+ CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_SESSION_up_ref, "(J)V"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_SESSION_free, "(J)V"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, i2d_SSL_SESSION, "(J)[B"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, d2i_SSL_SESSION, "([B)J"),
@@ -9352,8 +9444,6 @@
CONSCRYPT_NATIVE_METHOD(NativeCrypto, get_ocsp_single_extension, "([BLjava/lang/String;JJ)[B"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, getDirectBufferAddress, "(Ljava/nio/Buffer;)J"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_BIO_new, "(J)J"),
- CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_get0_session, "(J)J"),
- CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_get1_session, "(J)J"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_max_seal_overhead, "(J)I"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_clear_error, "()V"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_pending_readable_bytes, "(J)I"),
@@ -9372,6 +9462,15 @@
CONSCRYPT_NATIVE_METHOD(NativeCrypto, ENGINE_SSL_write_BIO_heap, "(JJ[BII" SSL_CALLBACKS ")I"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, ENGINE_SSL_read_BIO_heap, "(JJ[BII" SSL_CALLBACKS ")I"),
CONSCRYPT_NATIVE_METHOD(NativeCrypto, ENGINE_SSL_shutdown, "(J" SSL_CALLBACKS ")V"),
+
+ // Used for testing only.
+ CONSCRYPT_NATIVE_METHOD(NativeCrypto, BIO_read, "(J[B)I"),
+ CONSCRYPT_NATIVE_METHOD(NativeCrypto, BIO_write, "(J[BII)V"),
+ CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_clear_mode, "(JJ)J"),
+ CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_get_mode, "(J)J"),
+ CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_get_options, "(J)J"),
+ CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_get1_session, "(J)J"),
+ CONSCRYPT_NATIVE_METHOD(NativeCrypto, SSL_renegotiate, "(J)V"),
};
void NativeCrypto::registerNativeMethods(JNIEnv* env) {
diff --git a/common/src/main/java/org/conscrypt/AbstractOpenSSLSession.java b/common/src/main/java/org/conscrypt/AbstractOpenSSLSession.java
deleted file mode 100644
index e5de29a..0000000
--- a/common/src/main/java/org/conscrypt/AbstractOpenSSLSession.java
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.conscrypt;
-
-import java.security.Principal;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateEncodingException;
-import java.security.cert.X509Certificate;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import javax.net.ssl.SSLPeerUnverifiedException;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSessionBindingEvent;
-import javax.net.ssl.SSLSessionBindingListener;
-import javax.net.ssl.SSLSessionContext;
-import javax.security.cert.CertificateException;
-
-/**
- * Extends the base SSLSession with some methods used exclusively in Conscrypt.
- */
-abstract class AbstractOpenSSLSession implements SSLSession {
- private final Map<String, Object> values = new HashMap<String, Object>();
-
- private volatile javax.security.cert.X509Certificate[] peerCertificateChain;
-
- private AbstractSessionContext sessionContext;
-
- private boolean isValid = true;
-
- /**
- * Class constructor creates an SSL session context given the appropriate
- * session context.
- */
- AbstractOpenSSLSession(AbstractSessionContext sessionContext) {
- this.sessionContext = sessionContext;
- }
-
- protected abstract X509Certificate[] getX509PeerCertificates()
- throws SSLPeerUnverifiedException;
-
- protected abstract X509Certificate[] getX509LocalCertificates();
-
- /**
- * Throw SSLPeerUnverifiedException on null or empty peerCertificates array
- */
- private void checkPeerCertificatesPresent() throws SSLPeerUnverifiedException {
- X509Certificate[] peerCertificates = getX509PeerCertificates();
- if (peerCertificates == null || peerCertificates.length == 0) {
- throw new SSLPeerUnverifiedException("No peer certificates");
- }
- }
-
- /**
- * Return the identity of the peer in this SSL session
- * determined via certificate(s).
- * @return an array of X509 certificates (the peer's one first and then
- * eventually that of the certification authority) or null if no
- * certificate were used during the SSL connection.
- * @throws SSLPeerUnverifiedException if either a non-X.509 certificate
- * was used (i.e. Kerberos certificates) or the peer could not
- * be verified.
- */
- @Override
- public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
- return getX509PeerCertificates();
- }
-
- /**
- * Returns the certificate(s) of the peer in this SSL session
- * used in the handshaking phase of the connection.
- * Please notice hat this method is superseded by
- * <code>getPeerCertificates()</code>.
- * @return an array of X509 certificates (the peer's one first and then
- * eventually that of the certification authority) or null if no
- * certificate were used during the SSL connection.
- * @throws SSLPeerUnverifiedException if either a non-X.509 certificate
- * was used (i.e. Kerberos certificates) or the peer could not
- * be verified.
- */
- @Override
- public javax.security.cert.X509Certificate[] getPeerCertificateChain()
- throws SSLPeerUnverifiedException {
- checkPeerCertificatesPresent();
- javax.security.cert.X509Certificate[] result = peerCertificateChain;
- if (result == null) {
- // single-check idiom
- peerCertificateChain = result = createPeerCertificateChain();
- }
- return result;
- }
-
- /**
- * Provide a value to initialize the volatile peerCertificateChain
- * field based on the native SSL_SESSION
- */
- private javax.security.cert.X509Certificate[] createPeerCertificateChain()
- throws SSLPeerUnverifiedException {
- X509Certificate[] peerCertificates = getX509PeerCertificates();
- try {
- javax.security.cert.X509Certificate[] chain =
- new javax.security.cert.X509Certificate[peerCertificates.length];
-
- for (int i = 0; i < peerCertificates.length; i++) {
- byte[] encoded = peerCertificates[i].getEncoded();
- chain[i] = javax.security.cert.X509Certificate.getInstance(encoded);
- }
- return chain;
- } catch (CertificateEncodingException e) {
- SSLPeerUnverifiedException exception = new SSLPeerUnverifiedException(e.getMessage());
- exception.initCause(exception);
- throw exception;
- } catch (CertificateException e) {
- SSLPeerUnverifiedException exception = new SSLPeerUnverifiedException(e.getMessage());
- exception.initCause(exception);
- throw exception;
- }
- }
-
- /**
- * The identity of the principal that was used by the peer during the SSL
- * handshake phase is returned by this method.
- * @return a X500Principal of the last certificate for X509-based
- * cipher suites.
- * @throws SSLPeerUnverifiedException if either a non-X.509 certificate
- * was used (i.e. Kerberos certificates) or the peer does not exist.
- *
- */
- @Override
- public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
- checkPeerCertificatesPresent();
- return getX509PeerCertificates()[0].getSubjectX500Principal();
- }
-
- /**
- * Returns the principal (subject) of this concrete SSL session used in the
- * handshaking phase of the connection.
- * @return a X509 certificate or null if no principal was defined
- */
- @Override
- public Principal getLocalPrincipal() {
- X509Certificate[] localCertificates = getX509LocalCertificates();
- if (localCertificates != null && localCertificates.length > 0) {
- return localCertificates[0].getSubjectX500Principal();
- } else {
- return null;
- }
- }
-
- /**
- * Returns the certificate(s) of the principal (subject) of this concrete SSL
- * session used in the handshaking phase of the connection. The OpenSSL
- * native method supports only RSA certificates.
- * @return an array of certificates (the local one first and then eventually
- * that of the certification authority) or null if no certificate
- * were used during the handshaking phase.
- */
- @Override
- public Certificate[] getLocalCertificates() {
- return getX509LocalCertificates();
- }
-
- /**
- * Returns the largest buffer size for the application's data bound to this
- * concrete SSL session.
- * @return the largest buffer size
- */
- @Override
- public int getApplicationBufferSize() {
- return NativeConstants.SSL3_RT_MAX_PLAIN_LENGTH;
- }
-
- /**
- * Returns the largest SSL/TLS packet size one can expect for this concrete
- * SSL session.
- * @return the largest packet size
- */
- @Override
- public int getPacketBufferSize() {
- return NativeConstants.SSL3_RT_MAX_PACKET_SIZE;
- }
-
- /**
- * Returns the object which is bound to the the input parameter name.
- * This name is a sort of link to the data of the SSL session's application
- * layer, if any exists.
- *
- * @param name the name of the binding to find.
- * @return the value bound to that name, or null if the binding does not
- * exist.
- * @throws IllegalArgumentException if the argument is null.
- */
- @Override
- public Object getValue(String name) {
- if (name == null) {
- throw new IllegalArgumentException("name == null");
- }
- return values.get(name);
- }
-
- /**
- * Returns an array with the names (sort of links) of all the data
- * objects of the application layer bound into the SSL session.
- *
- * @return a non-null (possibly empty) array of names of the data objects
- * bound to this SSL session.
- */
- @Override
- public String[] getValueNames() {
- return values.keySet().toArray(new String[values.size()]);
- }
-
- /**
- * A link (name) with the specified value object of the SSL session's
- * application layer data is created or replaced. If the new (or existing)
- * value object implements the <code>SSLSessionBindingListener</code>
- * interface, that object will be notified in due course.
- *
- * @param name the name of the link (no null are
- * accepted!)
- * @param value data object that shall be bound to
- * name.
- * @throws IllegalArgumentException if one or both argument(s) is null.
- */
- @Override
- public void putValue(String name, Object value) {
- if (name == null || value == null) {
- throw new IllegalArgumentException("name == null || value == null");
- }
- Object old = values.put(name, value);
- if (value instanceof SSLSessionBindingListener) {
- ((SSLSessionBindingListener) value).valueBound(new SSLSessionBindingEvent(this, name));
- }
- if (old instanceof SSLSessionBindingListener) {
- ((SSLSessionBindingListener) old).valueUnbound(new SSLSessionBindingEvent(this, name));
- }
- }
-
- /**
- * Removes a link (name) with the specified value object of the SSL
- * session's application layer data.
- *
- * <p>If the value object implements the <code>SSLSessionBindingListener</code>
- * interface, the object will receive a <code>valueUnbound</code> notification.
- *
- * @param name the name of the link (no null are
- * accepted!)
- * @throws IllegalArgumentException if the argument is null.
- */
- @Override
- public void removeValue(String name) {
- if (name == null) {
- throw new IllegalArgumentException("name == null");
- }
- Object old = values.remove(name);
- if (old instanceof SSLSessionBindingListener) {
- SSLSessionBindingListener listener = (SSLSessionBindingListener) old;
- listener.valueUnbound(new SSLSessionBindingEvent(this, name));
- }
- }
-
- /**
- * Returns the context to which the actual SSL session is bound. A SSL
- * context consists of (1) a possible delegate, (2) a provider and (3) a
- * protocol.
- * @return the SSL context used for this session, or null if it is
- * unavailable.
- */
- @Override
- public SSLSessionContext getSessionContext() {
- return sessionContext;
- }
-
- /**
- * Returns a boolean flag signaling whether a SSL session is valid
- * and available for resuming or joining or not.
- *
- * @return true if this session may be resumed.
- */
- @Override
- public boolean isValid() {
- if (!isValid) {
- return false;
- }
- // The session has't yet been invalidated -- check whether it timed out.
-
- SSLSessionContext context = getSessionContext();
- if (context == null) {
- // Session not associated with a context -- no way to tell what its timeout should be.
- return true;
- }
-
- int timeoutSeconds = context.getSessionTimeout();
- if (timeoutSeconds == 0) {
- // Infinite timeout -- session still valid
- return true;
- }
-
- long creationTimestampMillis = getCreationTime();
- long ageSeconds = (System.currentTimeMillis() - creationTimestampMillis) / 1000;
- // NOTE: The age might be negative if something was/is wrong with the system clock. We time
- // out such sessions to be safe.
- if ((ageSeconds >= timeoutSeconds) || (ageSeconds < 0)) {
- // Session timed out -- no longer valid
- isValid = false;
- return false;
- }
-
- // Session still valid
- return true;
- }
-
- /**
- * It invalidates a SSL session forbidding any resumption.
- */
- @Override
- public void invalidate() {
- isValid = false;
- sessionContext = null;
- }
-
- /**
- * Returns the name requested by the SNI extension.
- */
- public abstract String getRequestedServerName();
-
- /**
- * Returns the OCSP stapled response.
- */
- public abstract List<byte[]> getStatusResponses();
-
- /**
- * Returns the TLS Stapled Certificate Transparency data.
- */
- public abstract byte[] getTlsSctData();
-
- /**
- * Sets the last accessed time for this session in milliseconds since Jan 1,
- * 1970 00:00:00 UTC.
- */
- public abstract void setLastAccessedTime(long accessTimeMillis);
-
- /**
- * Indicates that this session's ID may have changed and should be
- * re-cached.
- */
- abstract void resetId();
-}
diff --git a/common/src/main/java/org/conscrypt/AbstractSessionContext.java b/common/src/main/java/org/conscrypt/AbstractSessionContext.java
index 61d595d..a7171f1 100644
--- a/common/src/main/java/org/conscrypt/AbstractSessionContext.java
+++ b/common/src/main/java/org/conscrypt/AbstractSessionContext.java
@@ -16,19 +16,10 @@
package org.conscrypt;
-import java.io.ByteArrayOutputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateEncodingException;
-import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedHashMap;
-import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import javax.net.ssl.SSLSession;
@@ -50,28 +41,22 @@
final long sslCtxNativePointer = NativeCrypto.SSL_CTX_new();
- /** Identifies OpenSSL sessions. */
- private static final int OPEN_SSL = 1;
-
- /** Identifies OpenSSL sessions with OCSP stapled data. */
- private static final int OPEN_SSL_WITH_OCSP = 2;
-
- /** Identifies OpenSSL sessions with TLS SCT data. */
- private static final int OPEN_SSL_WITH_TLS_SCT = 3;
-
@SuppressWarnings("serial")
- private final Map<ByteArray, SSLSession> sessions = new LinkedHashMap<ByteArray, SSLSession>() {
- @Override
- protected boolean removeEldestEntry(
- Map.Entry<ByteArray, SSLSession> eldest) {
- boolean remove = maximumSize > 0 && size() > maximumSize;
- if (remove) {
- remove(eldest.getKey());
- sessionRemoved(eldest.getValue());
- }
- return false;
- }
- };
+ private final Map<ByteArray, SslSessionWrapper> sessions =
+ new LinkedHashMap<ByteArray, SslSessionWrapper>() {
+ @Override
+ protected boolean removeEldestEntry(
+ Map.Entry<ByteArray, SslSessionWrapper> eldest) {
+ // NOTE: does not take into account any session that may have become
+ // invalid.
+ if (maximumSize > 0 && size() > maximumSize) {
+ // Let the subclass know.
+ onBeforeRemoveSession(eldest.getValue());
+ return true;
+ }
+ return false;
+ }
+ };
/**
* Constructs a new session context.
@@ -83,29 +68,27 @@
}
/**
- * Returns the collection of sessions ordered from oldest to newest
+ * This method is provided for API-compatibility only, not intended for use. No guarantees
+ * are made WRT performance.
*/
- private Iterator<SSLSession> sessionIterator() {
- synchronized (sessions) {
- SSLSession[] array = sessions.values().toArray(
- new SSLSession[sessions.size()]);
- return Arrays.asList(array).iterator();
- }
- }
-
@Override
public final Enumeration<byte[]> getIds() {
- final Iterator<SSLSession> i = sessionIterator();
+ // Make a copy of the IDs.
+ final Iterator<SslSessionWrapper> iter;
+ synchronized (sessions) {
+ iter = Arrays.asList(sessions.values().toArray(new SslSessionWrapper[sessions.size()]))
+ .iterator();
+ }
return new Enumeration<byte[]>() {
- private SSLSession next;
+ private SslSessionWrapper next;
@Override
public boolean hasMoreElements() {
if (next != null) {
return true;
}
- while (i.hasNext()) {
- SSLSession session = i.next();
+ while (iter.hasNext()) {
+ SslSessionWrapper session = iter.next();
if (session.isValid()) {
next = session;
return true;
@@ -127,6 +110,26 @@
};
}
+ /**
+ * This is provided for API-compatibility only, not intended for use. No guarantees are
+ * made WRT performance or the validity of the returned session.
+ */
+ @Override
+ public final SSLSession getSession(byte[] sessionId) {
+ if (sessionId == null) {
+ throw new NullPointerException("sessionId");
+ }
+ ByteArray key = new ByteArray(sessionId);
+ SslSessionWrapper session;
+ synchronized (sessions) {
+ session = sessions.get(key);
+ }
+ if (session != null && session.isValid()) {
+ return session.toSSLSession();
+ }
+ return null;
+ }
+
@Override
public final int getSessionCacheSize() {
return maximumSize;
@@ -137,55 +140,33 @@
return timeout;
}
- /**
- * Makes sure cache size is < maximumSize.
- */
- private void trimToSize() {
- synchronized (sessions) {
- int size = sessions.size();
- if (size > maximumSize) {
- int removals = size - maximumSize;
- Iterator<SSLSession> i = sessions.values().iterator();
- do {
- SSLSession session = i.next();
- i.remove();
- sessionRemoved(session);
- } while (--removals > 0);
- }
- }
- }
-
@Override
- public void setSessionTimeout(int seconds)
- throws IllegalArgumentException {
+ public final void setSessionTimeout(int seconds) throws IllegalArgumentException {
if (seconds < 0) {
throw new IllegalArgumentException("seconds < 0");
}
- timeout = seconds;
synchronized (sessions) {
- Iterator<SSLSession> i = sessions.values().iterator();
+ // Set the timeout on this context.
+ timeout = seconds;
+ NativeCrypto.SSL_CTX_set_timeout(sslCtxNativePointer, seconds);
+
+ Iterator<SslSessionWrapper> i = sessions.values().iterator();
while (i.hasNext()) {
- SSLSession session = i.next();
+ SslSessionWrapper session = i.next();
// SSLSession's know their context and consult the
// timeout as part of their validity condition.
if (!session.isValid()) {
+ // Let the subclass know.
+ onBeforeRemoveSession(session);
i.remove();
- sessionRemoved(session);
}
}
}
}
- /**
- * Called when a session is removed. Used by ClientSessionContext
- * to update its host-and-port based cache.
- */
- protected abstract void sessionRemoved(SSLSession session);
-
@Override
- public final void setSessionCacheSize(int size)
- throws IllegalArgumentException {
+ public final void setSessionCacheSize(int size) throws IllegalArgumentException {
if (size < 0) {
throw new IllegalArgumentException("size < 0");
}
@@ -199,202 +180,6 @@
}
}
- /**
- * Converts the given session to bytes.
- *
- * @return session data as bytes or null if the session can't be converted
- */
- byte[] toBytes(SSLSession session) {
- // TODO: Support SSLSessionImpl, too.
- if (!(session instanceof OpenSSLSessionImpl)) {
- return null;
- }
-
- OpenSSLSessionImpl sslSession = (OpenSSLSessionImpl) session;
- try {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- DataOutputStream daos = new DataOutputStream(baos);
-
- daos.writeInt(OPEN_SSL_WITH_TLS_SCT); // session type ID
-
- // Session data.
- byte[] data = sslSession.getEncoded();
- daos.writeInt(data.length);
- daos.write(data);
-
- // Certificates.
- Certificate[] certs = session.getPeerCertificates();
- daos.writeInt(certs.length);
-
- for (Certificate cert : certs) {
- data = cert.getEncoded();
- daos.writeInt(data.length);
- daos.write(data);
- }
-
- List<byte[]> ocspResponses = sslSession.getStatusResponses();
- daos.writeInt(ocspResponses.size());
- for (byte[] ocspResponse : ocspResponses) {
- daos.writeInt(ocspResponse.length);
- daos.write(ocspResponse);
- }
-
- byte[] tlsSctData = sslSession.getTlsSctData();
- if (tlsSctData != null) {
- daos.writeInt(tlsSctData.length);
- daos.write(tlsSctData);
- } else {
- daos.writeInt(0);
- }
-
- // TODO: local certificates?
-
- return baos.toByteArray();
- } catch (IOException e) {
- System.err.println("Failed to convert saved SSL Session: " + e.getMessage());
- return null;
- } catch (CertificateEncodingException e) {
- log(e);
- return null;
- }
- }
-
- private static void checkRemaining(ByteBuffer buf, int length) throws IOException {
- if (length < 0) {
- throw new IOException("Length is negative: " + length);
- }
- if (length > buf.remaining()) {
- throw new IOException(
- "Length of blob is longer than available: " + length + " > " + buf.remaining());
- }
- }
-
- /**
- * Creates a session from the given bytes.
- *
- * @return a session or null if the session can't be converted
- */
- OpenSSLSessionImpl toSession(byte[] data, String host, int port) {
- ByteBuffer buf = ByteBuffer.wrap(data);
- try {
- int type = buf.getInt();
- if (type != OPEN_SSL && type != OPEN_SSL_WITH_OCSP && type != OPEN_SSL_WITH_TLS_SCT) {
- throw new IOException("Unexpected type ID: " + type);
- }
-
- int length = buf.getInt();
- checkRemaining(buf, length);
-
- byte[] sessionData = new byte[length];
- buf.get(sessionData);
-
- int count = buf.getInt();
- checkRemaining(buf, count);
-
- X509Certificate[] certs = new X509Certificate[count];
- for (int i = 0; i < count; i++) {
- length = buf.getInt();
- checkRemaining(buf, length);
-
- byte[] certData = new byte[length];
- buf.get(certData);
- try {
- certs[i] = OpenSSLX509Certificate.fromX509Der(certData);
- } catch (Exception e) {
- throw new IOException("Can not read certificate " + i + "/" + count);
- }
- }
-
- byte[] ocspData = null;
- if (type >= OPEN_SSL_WITH_OCSP) {
- // We only support one OCSP response now, but in the future
- // we may support RFC 6961 which has multiple.
- int countOcspResponses = buf.getInt();
- checkRemaining(buf, countOcspResponses);
-
- if (countOcspResponses >= 1) {
- int ocspLength = buf.getInt();
- checkRemaining(buf, ocspLength);
-
- ocspData = new byte[ocspLength];
- buf.get(ocspData);
-
- // Skip the rest of the responses.
- for (int i = 1; i < countOcspResponses; i++) {
- ocspLength = buf.getInt();
- checkRemaining(buf, ocspLength);
- buf.position(buf.position() + ocspLength);
- }
- }
- }
-
- byte[] tlsSctData = null;
- if (type == OPEN_SSL_WITH_TLS_SCT) {
- int tlsSctDataLength = buf.getInt();
- checkRemaining(buf, tlsSctDataLength);
-
- if (tlsSctDataLength > 0) {
- tlsSctData = new byte[tlsSctDataLength];
- buf.get(tlsSctData);
- }
- }
-
- if (buf.remaining() != 0) {
- log(new AssertionError("Read entire session, but data still remains; rejecting"));
- return null;
- }
-
- return new OpenSSLSessionImpl(sessionData, host, port, certs, ocspData, tlsSctData,
- this);
- } catch (IOException e) {
- log(e);
- return null;
- } catch (BufferUnderflowException e) {
- log(e);
- return null;
- }
- }
-
- SSLSession wrapSSLSessionIfNeeded(SSLSession session) {
- if (session instanceof AbstractOpenSSLSession) {
- return Platform.wrapSSLSession((AbstractOpenSSLSession) session);
- } else {
- return session;
- }
- }
-
- @Override
- public SSLSession getSession(byte[] sessionId) {
- if (sessionId == null) {
- throw new NullPointerException("sessionId == null");
- }
- ByteArray key = new ByteArray(sessionId);
- SSLSession session;
- synchronized (sessions) {
- session = sessions.get(key);
- }
- if (session != null && session.isValid()) {
- return wrapSSLSessionIfNeeded(session);
- }
- return null;
- }
-
- void putSession(SSLSession session) {
- byte[] id = session.getId();
- if (id.length == 0) {
- return;
- }
- ByteArray key = new ByteArray(id);
- synchronized (sessions) {
- sessions.put(key, session);
- }
- }
-
- private static void log(Throwable t) {
- System.out.println("Error inflating SSL session: "
- + (t.getMessage() != null ? t.getMessage() : t.getClass().getName()));
- }
-
@Override
protected void finalize() throws Throwable {
try {
@@ -403,4 +188,85 @@
super.finalize();
}
}
+
+ /**
+ * Adds the given session to the cache.
+ */
+ final void cacheSession(SslSessionWrapper session) {
+ byte[] id = session.getId();
+ if (id == null || id.length == 0) {
+ return;
+ }
+
+ // Let the subclass know.
+ onBeforeAddSession(session);
+
+ ByteArray key = new ByteArray(id);
+ synchronized (sessions) {
+ sessions.put(key, session);
+ }
+ }
+
+ /**
+ * Called for server sessions only. Retrieves the session by its ID. Overridden by
+ * {@link ServerSessionContext} to
+ */
+ final SslSessionWrapper getSessionFromCache(byte[] sessionId) {
+ if (sessionId == null) {
+ return null;
+ }
+
+ // First, look in the in-memory cache.
+ SslSessionWrapper session;
+ synchronized (sessions) {
+ session = sessions.get(new ByteArray(sessionId));
+ }
+ if (session != null && session.isValid()) {
+ return session;
+ }
+
+ // Not found in-memory - look it up in the persistent cache.
+ return getSessionFromPersistentCache(sessionId);
+ }
+
+ /**
+ * Called when the given session is about to be added. Used by {@link ClientSessionContext} to
+ * update its host-and-port based cache.
+ *
+ * <p>Visible for extension only, not intended to be called directly.
+ */
+ abstract void onBeforeAddSession(SslSessionWrapper session);
+
+ /**
+ * Called when a session is about to be removed. Used by {@link ClientSessionContext}
+ * to update its host-and-port based cache.
+ *
+ * <p>Visible for extension only, not intended to be called directly.
+ */
+ abstract void onBeforeRemoveSession(SslSessionWrapper session);
+
+ /**
+ * Called for server sessions only. Retrieves the session by ID from the persistent cache.
+ *
+ * <p>Visible for extension only, not intended to be called directly.
+ */
+ abstract SslSessionWrapper getSessionFromPersistentCache(byte[] sessionId);
+
+ /**
+ * Makes sure cache size is < maximumSize.
+ */
+ private void trimToSize() {
+ synchronized (sessions) {
+ int size = sessions.size();
+ if (size > maximumSize) {
+ int removals = size - maximumSize;
+ Iterator<SslSessionWrapper> i = sessions.values().iterator();
+ while (removals-- > 0) {
+ SslSessionWrapper session = i.next();
+ onBeforeRemoveSession(session);
+ i.remove();
+ }
+ }
+ }
+ }
}
diff --git a/common/src/main/java/org/conscrypt/ActiveSession.java b/common/src/main/java/org/conscrypt/ActiveSession.java
new file mode 100644
index 0000000..c7f6431
--- /dev/null
+++ b/common/src/main/java/org/conscrypt/ActiveSession.java
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.conscrypt;
+
+import static org.conscrypt.Preconditions.checkNotNull;
+
+import java.security.Principal;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionBindingEvent;
+import javax.net.ssl.SSLSessionBindingListener;
+import javax.net.ssl.SSLSessionContext;
+
+/**
+ * A session that is dedicated a single connection and operates directly on the underlying
+ * {@code SSL}.
+ */
+final class ActiveSession implements SSLSession {
+ private final SslWrapper ssl;
+ private AbstractSessionContext sessionContext;
+ private byte[] id;
+ private long creationTime;
+ private String cipherSuite;
+ private String protocol;
+ private String peerHost;
+ private int peerPort = -1;
+ private long lastAccessedTime = 0;
+ private volatile javax.security.cert.X509Certificate[] peerCertificateChain;
+ private X509Certificate[] localCertificates;
+ private X509Certificate[] peerCertificates;
+ private byte[] peerCertificateOcspData;
+ private byte[] peerTlsSctData;
+
+ // lazy init for memory reasons
+ private Map<String, Object> values;
+
+ ActiveSession(SslWrapper ssl, AbstractSessionContext sessionContext) {
+ this.ssl = checkNotNull(ssl, "ssl");
+ this.sessionContext = checkNotNull(sessionContext, "sessionContext");
+ }
+
+ @Override
+ public byte[] getId() {
+ if (id == null) {
+ id = ssl.getSessionId();
+ }
+ return id != null ? id.clone() : EmptyArray.BYTE;
+ }
+
+ /**
+ * Indicates that this session's ID may have changed and should be re-cached.
+ */
+ void resetId() {
+ id = null;
+ }
+
+ @Override
+ public SSLSessionContext getSessionContext() {
+ return isValid() ? sessionContext : null;
+ }
+
+ @Override
+ public long getCreationTime() {
+ if (creationTime == 0) {
+ creationTime = ssl.getTime();
+ }
+ return creationTime;
+ }
+
+ /**
+ * Returns the last time this SSL session was accessed. Accessing
+ * here is to mean that a new connection with the same SSL context data was
+ * established.
+ *
+ * @return the session's last access time in milliseconds since the epoch
+ */
+ // TODO(nathanmittler): Does lastAccessedTime need to account for session reuse?
+ @Override
+ public long getLastAccessedTime() {
+ return lastAccessedTime == 0 ? getCreationTime() : lastAccessedTime;
+ }
+
+ void setLastAccessedTime(long accessTimeMillis) {
+ lastAccessedTime = accessTimeMillis;
+ }
+
+ /**
+ * Returns the OCSP stapled response. Returns a copy of the internal arrays.
+ *
+ * The method signature matches
+ * <a
+ * href="http://download.java.net/java/jdk9/docs/api/javax/net/ssl/ExtendedSSLSession.html#getStatusResponses--">Java
+ * 9</a>.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc6066">RFC 6066</a>
+ * @see <a href="https://tools.ietf.org/html/rfc6961">RFC 6961</a>
+ */
+ /* @Override */
+ @SuppressWarnings("MissingOverride") // For Pre-Java9 compatibility.
+ public List<byte[]> getStatusResponses() {
+ if (peerCertificateOcspData == null) {
+ return Collections.<byte[]>emptyList();
+ }
+
+ return Collections.singletonList(peerCertificateOcspData.clone());
+ }
+
+ /**
+ * Returns the signed certificate timestamp (SCT) received from the peer. Returns a
+ * copy of the internal array.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc6962">RFC 6962</a>
+ */
+ byte[] getPeerSignedCertificateTimestamp() {
+ if (peerTlsSctData == null) {
+ return null;
+ }
+ return peerTlsSctData.clone();
+ }
+
+ String getRequestedServerName() {
+ return ssl.getRequestedServerName();
+ }
+
+ @Override
+ public void invalidate() {
+ ssl.setTimeout(0L);
+ }
+
+ @Override
+ public boolean isValid() {
+ long creationTimeMillis = ssl.getTime();
+ long timeoutMillis = ssl.getTimeout();
+ return (System.currentTimeMillis() - timeoutMillis) < creationTimeMillis;
+ }
+
+ @Override
+ public void putValue(String name, Object value) {
+ if (name == null) {
+ throw new NullPointerException("name");
+ }
+ if (value == null) {
+ throw new NullPointerException("value");
+ }
+ Map<String, Object> values = this.values;
+ if (values == null) {
+ // Use size of 2 to keep the memory overhead small
+ values = this.values = new HashMap<String, Object>(2);
+ }
+ Object old = values.put(name, value);
+ if (value instanceof SSLSessionBindingListener) {
+ ((SSLSessionBindingListener) value).valueBound(new SSLSessionBindingEvent(this, name));
+ }
+ if (old instanceof SSLSessionBindingListener) {
+ ((SSLSessionBindingListener) old).valueUnbound(new SSLSessionBindingEvent(this, name));
+ }
+ notifyUnbound(old, name);
+ }
+
+ @Override
+ public Object getValue(String name) {
+ if (name == null) {
+ throw new NullPointerException("name");
+ }
+ if (values == null) {
+ return null;
+ }
+ return values.get(name);
+ }
+
+ @Override
+ public void removeValue(String name) {
+ if (name == null) {
+ throw new NullPointerException("name");
+ }
+ Map<String, Object> values = this.values;
+ if (values == null) {
+ return;
+ }
+ Object old = values.remove(name);
+ notifyUnbound(old, name);
+ }
+
+ @Override
+ public String[] getValueNames() {
+ Map<String, Object> values = this.values;
+ if (values == null || values.isEmpty()) {
+ return EmptyArray.STRING;
+ }
+ return values.keySet().toArray(new String[values.size()]);
+ }
+
+ @Override
+ public X509Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
+ checkPeerCertificatesPresent();
+ return peerCertificates.clone();
+ }
+
+ @Override
+ public Certificate[] getLocalCertificates() {
+ return localCertificates == null ? null : localCertificates.clone();
+ }
+
+ /**
+ * Returns the certificate(s) of the peer in this SSL session
+ * used in the handshaking phase of the connection.
+ * Please notice hat this method is superseded by
+ * <code>getPeerCertificates()</code>.
+ * @return an array of X509 certificates (the peer's one first and then
+ * eventually that of the certification authority) or null if no
+ * certificate were used during the SSL connection.
+ * @throws SSLPeerUnverifiedException if either a non-X.509 certificate
+ * was used (i.e. Kerberos certificates) or the peer could not
+ * be verified.
+ */
+ @Override
+ public javax.security.cert.X509Certificate[] getPeerCertificateChain()
+ throws SSLPeerUnverifiedException {
+ checkPeerCertificatesPresent();
+ // TODO(nathanmittler): Should we clone?
+ javax.security.cert.X509Certificate[] result = peerCertificateChain;
+ if (result == null) {
+ // single-check idiom
+ peerCertificateChain = result = SSLUtils.toCertificateChain(peerCertificates);
+ }
+ return result;
+ }
+
+ @Override
+ public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
+ checkPeerCertificatesPresent();
+ return peerCertificates[0].getSubjectX500Principal();
+ }
+
+ @Override
+ public Principal getLocalPrincipal() {
+ if (localCertificates != null && localCertificates.length > 0) {
+ return localCertificates[0].getSubjectX500Principal();
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public String getCipherSuite() {
+ if (cipherSuite == null) {
+ cipherSuite = ssl.getCipherSuite();
+ }
+ return cipherSuite;
+ }
+
+ @Override
+ public String getProtocol() {
+ String protocol = this.protocol;
+ if (protocol == null) {
+ protocol = ssl.getVersion();
+ this.protocol = protocol;
+ }
+ return protocol;
+ }
+
+ @Override
+ public String getPeerHost() {
+ return peerHost;
+ }
+
+ @Override
+ public int getPeerPort() {
+ return peerPort;
+ }
+
+ @Override
+ public int getPacketBufferSize() {
+ return NativeConstants.SSL3_RT_MAX_PACKET_SIZE;
+ }
+
+ @Override
+ public int getApplicationBufferSize() {
+ return NativeConstants.SSL3_RT_MAX_PLAIN_LENGTH;
+ }
+
+ /**
+ * Configures the peer information once it has been received by the handshake.
+ */
+ void onPeerCertificatesReceived(
+ String peerHost, int peerPort, OpenSSLX509Certificate[] peerCertificates) {
+ configurePeer(peerHost, peerPort, peerCertificates);
+ }
+
+ /**
+ * Configures the peer and local state from a newly created BoringSSL session.
+ */
+ void onSessionEstablished(String peerHost, int peerPort) {
+ id = null;
+ this.localCertificates = ssl.getLocalCertificates();
+ configurePeer(peerHost, peerPort, ssl.getPeerCertificates());
+ }
+
+ private void configurePeer(
+ String peerHost, int peerPort, OpenSSLX509Certificate[] peerCertificates) {
+ this.peerHost = peerHost;
+ this.peerPort = peerPort;
+ this.peerCertificates = peerCertificates;
+ this.peerCertificateOcspData = ssl.getPeerCertificateOcspData();
+ this.peerTlsSctData = ssl.getPeerTlsSctData();
+ }
+
+ private X509Certificate[] getX509PeerCertificates() throws SSLPeerUnverifiedException {
+ if (peerCertificates == null || peerCertificates.length == 0) {
+ throw new SSLPeerUnverifiedException("No peer certificates");
+ }
+ return peerCertificates;
+ }
+
+ /**
+ * Throw SSLPeerUnverifiedException on null or empty peerCertificates array
+ */
+ private void checkPeerCertificatesPresent() throws SSLPeerUnverifiedException {
+ if (peerCertificates == null || peerCertificates.length == 0) {
+ throw new SSLPeerUnverifiedException("No peer certificates");
+ }
+ }
+
+ private void notifyUnbound(Object value, String name) {
+ if (value instanceof SSLSessionBindingListener) {
+ ((SSLSessionBindingListener) value)
+ .valueUnbound(new SSLSessionBindingEvent(this, name));
+ }
+ }
+}
diff --git a/common/src/main/java/org/conscrypt/ClientSessionContext.java b/common/src/main/java/org/conscrypt/ClientSessionContext.java
index 48bbe8e..6265a7b 100644
--- a/common/src/main/java/org/conscrypt/ClientSessionContext.java
+++ b/common/src/main/java/org/conscrypt/ClientSessionContext.java
@@ -17,7 +17,8 @@
package org.conscrypt;
import java.util.HashMap;
-import javax.net.ssl.SSLSession;
+import java.util.Map;
+import javax.net.ssl.SSLContext;
/**
* Caches client sessions. Indexes by host and port. Users are typically
@@ -26,39 +27,70 @@
* @hide
*/
@Internal
-public class ClientSessionContext extends AbstractSessionContext {
-
+public final class ClientSessionContext extends AbstractSessionContext {
/**
* Sessions indexed by host and port. Protect from concurrent
* access by holding a lock on sessionsByHostAndPort.
*/
- private final HashMap<HostAndPort, SSLSession> sessionsByHostAndPort = new HashMap<>();
+ @SuppressWarnings("serial")
+ private final Map<HostAndPort, SslSessionWrapper> sessionsByHostAndPort = new HashMap<>();
private SSLClientSessionCache persistentCache;
- public ClientSessionContext() {
+ ClientSessionContext() {
super(10);
}
- public int size() {
- return sessionsByHostAndPort.size();
- }
-
+ /**
+ * Applications should not use this method. Instead use {@link
+ * Conscrypt.Contexts#setClientSessionCache(SSLContext, SSLClientSessionCache)}.
+ */
public void setPersistentCache(SSLClientSessionCache persistentCache) {
this.persistentCache = persistentCache;
}
- @Override
- protected void sessionRemoved(SSLSession session) {
- String host = session.getPeerHost();
- int port = session.getPeerPort();
- if (host == null) {
- return;
+ /**
+ * Gets the suitable session reference from the session cache container.
+ */
+ SslSessionWrapper getCachedSession(String hostName, int port, SSLParametersImpl sslParameters) {
+ if (hostName == null) {
+ return null;
}
- HostAndPort hostAndPortKey = new HostAndPort(host, port);
- synchronized (sessionsByHostAndPort) {
- sessionsByHostAndPort.remove(hostAndPortKey);
+
+ SslSessionWrapper session = getSession(hostName, port);
+ if (session == null) {
+ return null;
}
+
+ String protocol = session.getProtocol();
+ boolean protocolFound = false;
+ for (String enabledProtocol : sslParameters.enabledProtocols) {
+ if (protocol.equals(enabledProtocol)) {
+ protocolFound = true;
+ break;
+ }
+ }
+ if (!protocolFound) {
+ return null;
+ }
+
+ String cipherSuite = session.getCipherSuite();
+ boolean cipherSuiteFound = false;
+ for (String enabledCipherSuite : sslParameters.enabledCipherSuites) {
+ if (cipherSuite.equals(enabledCipherSuite)) {
+ cipherSuiteFound = true;
+ break;
+ }
+ }
+ if (!cipherSuiteFound) {
+ return null;
+ }
+
+ return session;
+ }
+
+ int size() {
+ return sessionsByHostAndPort.size();
}
/**
@@ -68,30 +100,30 @@
* @param port of server
* @return cached session or null if none found
*/
- public SSLSession getSession(String host, int port) {
+ private SslSessionWrapper getSession(String host, int port) {
if (host == null) {
return null;
}
- SSLSession session;
- HostAndPort hostAndPortKey = new HostAndPort(host, port);
+
+ HostAndPort key = new HostAndPort(host, port);
+ SslSessionWrapper session;
synchronized (sessionsByHostAndPort) {
- session = sessionsByHostAndPort.get(hostAndPortKey);
+ session = sessionsByHostAndPort.get(key);
}
if (session != null && session.isValid()) {
- return wrapSSLSessionIfNeeded(session);
+ return session;
}
// Look in persistent cache.
if (persistentCache != null) {
byte[] data = persistentCache.getSessionData(host, port);
if (data != null) {
- session = toSession(data, host, port);
+ session = SslSessionWrapper.newInstance(this, data, host, port);
if (session != null && session.isValid()) {
- super.putSession(session);
synchronized (sessionsByHostAndPort) {
- sessionsByHostAndPort.put(hostAndPortKey, session);
+ sessionsByHostAndPort.put(key, session);
}
- return wrapSSLSessionIfNeeded(session);
+ return session;
}
}
}
@@ -100,30 +132,47 @@
}
@Override
- public void putSession(SSLSession session) {
- super.putSession(session);
-
+ void onBeforeAddSession(SslSessionWrapper session) {
String host = session.getPeerHost();
int port = session.getPeerPort();
if (host == null) {
return;
}
- HostAndPort hostAndPortKey = new HostAndPort(host, port);
+ HostAndPort key = new HostAndPort(host, port);
synchronized (sessionsByHostAndPort) {
- sessionsByHostAndPort.put(hostAndPortKey, session);
+ sessionsByHostAndPort.put(key, session);
}
- // TODO: This in a background thread.
+ // TODO: Do this in a background thread.
if (persistentCache != null) {
- byte[] data = toBytes(session);
+ byte[] data = session.toBytes();
if (data != null) {
- persistentCache.putSessionData(session, data);
+ persistentCache.putSessionData(session.toSSLSession(), data);
}
}
}
- static class HostAndPort {
+ @Override
+ void onBeforeRemoveSession(SslSessionWrapper session) {
+ String host = session.getPeerHost();
+ if (host == null) {
+ return;
+ }
+ int port = session.getPeerPort();
+ HostAndPort hostAndPortKey = new HostAndPort(host, port);
+ synchronized (sessionsByHostAndPort) {
+ sessionsByHostAndPort.remove(hostAndPortKey);
+ }
+ }
+
+ @Override
+ SslSessionWrapper getSessionFromPersistentCache(byte[] sessionId) {
+ // Not implemented for clients.
+ return null;
+ }
+
+ private static final class HostAndPort {
final String host;
final int port;
diff --git a/common/src/main/java/org/conscrypt/Conscrypt.java b/common/src/main/java/org/conscrypt/Conscrypt.java
index 10d23d1..3db8e9e 100644
--- a/common/src/main/java/org/conscrypt/Conscrypt.java
+++ b/common/src/main/java/org/conscrypt/Conscrypt.java
@@ -20,11 +20,13 @@
import java.security.KeyManagementException;
import java.security.PrivateKey;
import java.security.Provider;
+import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLContextSpi;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSessionContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;
@@ -80,6 +82,44 @@
}
/**
+ * Utility methods for configuring Conscrypt {@link SSLContext} instances.
+ */
+ public static final class Contexts {
+ private Contexts() {}
+
+ /**
+ * Indicates whether the given object is a Conscrypt client-side session context.
+ */
+ public static boolean isConscrypt(SSLContext context) {
+ return context.getProvider() instanceof OpenSSLProvider;
+ }
+
+ /**
+ * Sets the client-side persistent cache to be used by the context.
+ */
+ public static void setClientSessionCache(SSLContext context, SSLClientSessionCache cache) {
+ SSLSessionContext clientContext = context.getClientSessionContext();
+ if (!(clientContext instanceof ClientSessionContext)) {
+ throw new IllegalArgumentException(
+ "Not a conscrypt client context: " + clientContext.getClass().getName());
+ }
+ ((ClientSessionContext) clientContext).setPersistentCache(cache);
+ }
+
+ /**
+ * Sets the server-side persistent cache to be used by the context.
+ */
+ public static void setServerSessionCache(SSLContext context, SSLServerSessionCache cache) {
+ SSLSessionContext serverContext = context.getServerSessionContext();
+ if (!(serverContext instanceof ServerSessionContext)) {
+ throw new IllegalArgumentException(
+ "Not a conscrypt client context: " + serverContext.getClass().getName());
+ }
+ ((ServerSessionContext) serverContext).setPersistentCache(cache);
+ }
+ }
+
+ /**
* Utility methods for configuring Conscrypt socket factories.
*/
public static final class SocketFactories {
diff --git a/common/src/main/java/org/conscrypt/ConscryptEngine.java b/common/src/main/java/org/conscrypt/ConscryptEngine.java
index d7b6d12..258d9bf 100644
--- a/common/src/main/java/org/conscrypt/ConscryptEngine.java
+++ b/common/src/main/java/org/conscrypt/ConscryptEngine.java
@@ -48,8 +48,6 @@
import static org.conscrypt.NativeConstants.SSL_ERROR_WANT_READ;
import static org.conscrypt.NativeConstants.SSL_ERROR_WANT_WRITE;
import static org.conscrypt.NativeConstants.SSL_ERROR_ZERO_RETURN;
-import static org.conscrypt.NativeConstants.SSL_RECEIVED_SHUTDOWN;
-import static org.conscrypt.NativeConstants.SSL_SENT_SHUTDOWN;
import static org.conscrypt.Preconditions.checkArgument;
import static org.conscrypt.Preconditions.checkNotNull;
import static org.conscrypt.SSLUtils.EngineStates.STATE_CLOSED;
@@ -88,6 +86,8 @@
import javax.net.ssl.X509KeyManager;
import javax.net.ssl.X509TrustManager;
import javax.security.auth.x500.X500Principal;
+import org.conscrypt.NativeRef.SSL_SESSION;
+import org.conscrypt.SslWrapper.BioWrapper;
/**
* Implements the {@link SSLEngine} API using OpenSSL's non-blocking interfaces.
@@ -114,12 +114,12 @@
private final SSLParametersImpl sslParameters;
/**
- * Protects {@link #engineState} and {@link #handshakeFinished}.
+ * Protects {@link #state} and {@link #handshakeFinished}.
*/
private final Object stateLock = new Object();
// @GuardedBy("stateLock");
- private int engineState = STATE_NEW;
+ private int state = STATE_NEW;
private boolean handshakeFinished;
/**
@@ -127,24 +127,18 @@
* close.
*/
// @GuardedBy("stateLock");
- private long sslNativePointer;
+ private final SslWrapper ssl;
/**
- * Protected by synchronizing on stateLock. Starts as 0, set by startHandshake, reset to 0 on
- * close.
+ * The BIO used for reading/writing encrypted bytes.
*/
// @GuardedBy("stateLock");
- private long networkBio;
+ private final BioWrapper networkBio;
/**
* Set during startHandshake.
*/
- private AbstractOpenSSLSession sslSession;
-
- /**
- * Used during handshake callbacks.
- */
- private AbstractOpenSSLSession handshakeSession;
+ private final ActiveSession sslSession;
/**
* Private key for the TLS Channel ID extension. This field is client-side only. Set during
@@ -165,16 +159,33 @@
ConscryptEngine(SSLParametersImpl sslParameters) {
this.sslParameters = sslParameters;
peerInfoProvider = PeerInfoProvider.nullProvider();
+ this.ssl = newSsl(sslParameters, this);
+ this.networkBio = ssl.newBio();
+ sslSession = new ActiveSession(ssl, sslParameters.getSessionContext());
}
ConscryptEngine(final String host, final int port, SSLParametersImpl sslParameters) {
this.sslParameters = sslParameters;
this.peerInfoProvider = PeerInfoProvider.forHostAndPort(host, port);
+ this.ssl = newSsl(sslParameters, this);
+ this.networkBio = ssl.newBio();
+ sslSession = new ActiveSession(ssl, sslParameters.getSessionContext());
}
ConscryptEngine(SSLParametersImpl sslParameters, PeerInfoProvider peerInfoProvider) {
this.sslParameters = sslParameters;
this.peerInfoProvider = checkNotNull(peerInfoProvider, "peerInfoProvider");
+ this.ssl = newSsl(sslParameters, this);
+ this.networkBio = ssl.newBio();
+ sslSession = new ActiveSession(ssl, sslParameters.getSessionContext());
+ }
+
+ private static SslWrapper newSsl(SSLParametersImpl sslParameters, ConscryptEngine engine) {
+ try {
+ return SslWrapper.newInstance(sslParameters, engine, engine, engine);
+ } catch (SSLException e) {
+ throw new RuntimeException(e);
+ }
}
/**
@@ -225,7 +236,7 @@
throw new IllegalStateException(
"Channel ID is only available after handshake completes");
}
- return NativeCrypto.SSL_get_tls_channel_id(sslNativePointer);
+ return ssl.getTlsChannelId();
}
}
@@ -291,7 +302,7 @@
}
private boolean isHandshakeStarted() {
- switch (engineState) {
+ switch (state) {
case STATE_NEW:
case STATE_MODE_SET:
return false;
@@ -336,7 +347,7 @@
}
private void beginHandshakeInternal() throws SSLException {
- switch (engineState) {
+ switch (state) {
case STATE_MODE_SET:
// This is the only allowed state.
break;
@@ -350,44 +361,24 @@
throw new IllegalStateException("Client/server mode must be set before handshake");
}
- engineState = STATE_HANDSHAKE_STARTED;
+ state = STATE_HANDSHAKE_STARTED;
boolean releaseResources = true;
try {
- final AbstractSessionContext sessionContext = sslParameters.getSessionContext();
- sslNativePointer = NativeCrypto.SSL_new(sessionContext.sslCtxNativePointer);
- networkBio = NativeCrypto.SSL_BIO_new(sslNativePointer);
+ // Prepare the SSL object for the handshake.
+ ssl.initialize(getHostname(), channelIdPrivateKey);
- // Allow servers to trigger renegotiation. Some inadvisable server
- // configurations cause them to attempt to renegotiate during
- // certain protocols.
- NativeCrypto.SSL_accept_renegotiations(sslNativePointer);
-
+ // For clients, offer to resume a previously cached session to avoid the
+ // full TLS handshake.
if (getUseClientMode()) {
- NativeCrypto.SSL_set_connect_state(sslNativePointer);
-
- // Configure OCSP and CT extensions for client
- NativeCrypto.SSL_enable_ocsp_stapling(sslNativePointer);
- if (sslParameters.isCTVerificationEnabled(getHostname())) {
- NativeCrypto.SSL_enable_signed_cert_timestamps(sslNativePointer);
- }
- } else {
- NativeCrypto.SSL_set_accept_state(sslNativePointer);
-
- // Configure OCSP for server
- if (sslParameters.getOCSPResponse() != null) {
- NativeCrypto.SSL_enable_ocsp_stapling(sslNativePointer);
+ SslSessionWrapper cachedSession = clientSessionContext().getCachedSession(
+ getHostname(), getPeerPort(), sslParameters);
+ if (cachedSession != null) {
+ cachedSession.offerToResume(ssl);
}
}
- sslSession =
- sslParameters.getSessionToReuse(sslNativePointer, getPeerHost(), getPeerPort());
-
- sslParameters.setSSLParameters(sslNativePointer, this, this, getHostname());
- sslParameters.setCertificateValidation(sslNativePointer);
- sslParameters.setTlsChannelId(sslNativePointer, channelIdPrivateKey);
-
- maxSealOverhead = NativeCrypto.SSL_max_seal_overhead(sslNativePointer);
+ maxSealOverhead = ssl.getMaxSealOverhead();
handshake();
releaseResources = false;
} catch (IOException e) {
@@ -401,7 +392,7 @@
throw SSLUtils.toSSLHandshakeException(e);
} finally {
if (releaseResources) {
- engineState = STATE_CLOSED;
+ state = STATE_CLOSED;
shutdownAndFreeSslNative();
}
}
@@ -410,13 +401,13 @@
@Override
public void closeInbound() throws SSLException {
synchronized (stateLock) {
- if (engineState == STATE_CLOSED) {
+ if (state == STATE_CLOSED) {
return;
}
- if (engineState == STATE_CLOSED_OUTBOUND) {
- engineState = STATE_CLOSED;
+ if (state == STATE_CLOSED_OUTBOUND) {
+ state = STATE_CLOSED;
} else {
- engineState = STATE_CLOSED_INBOUND;
+ state = STATE_CLOSED_INBOUND;
}
}
// TODO anything else to notify OpenSSL layer?
@@ -425,16 +416,16 @@
@Override
public void closeOutbound() {
synchronized (stateLock) {
- if (engineState == STATE_CLOSED || engineState == STATE_CLOSED_OUTBOUND) {
+ if (state == STATE_CLOSED || state == STATE_CLOSED_OUTBOUND) {
return;
}
if (isHandshakeStarted()) {
shutdownAndFreeSslNative();
}
- if (engineState == STATE_CLOSED_INBOUND) {
- engineState = STATE_CLOSED;
+ if (state == STATE_CLOSED_INBOUND) {
+ state = STATE_CLOSED;
} else {
- engineState = STATE_CLOSED_OUTBOUND;
+ state = STATE_CLOSED_OUTBOUND;
}
}
shutdown();
@@ -485,7 +476,7 @@
if (handshakeFinished) {
return HandshakeStatus.NOT_HANDSHAKING;
}
- switch (engineState) {
+ switch (state) {
case STATE_HANDSHAKE_STARTED:
return pendingStatus(pendingOutboundEncryptedBytes());
case STATE_HANDSHAKE_COMPLETED:
@@ -501,15 +492,15 @@
default:
break;
}
- throw new IllegalStateException("Unexpected engine state: " + engineState);
+ throw new IllegalStateException("Unexpected engine state: " + state);
}
private int pendingOutboundEncryptedBytes() {
- return NativeCrypto.SSL_pending_written_bytes_in_BIO(networkBio);
+ return networkBio.getPendingWrittenBytes();
}
private int pendingInboundCleartextBytes() {
- return NativeCrypto.SSL_pending_readable_bytes(sslNativePointer);
+ return ssl.getPendingReadableBytes();
}
private static SSLEngineResult.HandshakeStatus pendingStatus(int pendingOutboundBytes) {
@@ -522,13 +513,30 @@
return sslParameters.getNeedClientAuth();
}
+ /* @Override */
+ @SuppressWarnings("MissingOverride") // For compilation with Java 6.
+ public SSLSession getHandshakeSession() {
+ return handshakeSession();
+ }
+
+ /**
+ * Work-around to allow this method to be called on older versions of Android.
+ */
+ SSLSession handshakeSession() {
+ synchronized (stateLock) {
+ return state >= STATE_HANDSHAKE_STARTED && state < STATE_READY ? sslSession : null;
+ }
+ }
+
@Override
public SSLSession getSession() {
- if (sslSession == null) {
- return handshakeSession != null ? Platform.wrapSSLSession(handshakeSession)
- : SSLNullSession.getNullSession();
+ synchronized (stateLock) {
+ if (state < STATE_HANDSHAKE_COMPLETED) {
+ // Return an invalid session with invalid cipher suite of "SSL_NULL_WITH_NULL_NULL"
+ return SSLNullSession.getNullSession();
+ }
+ return Platform.wrapSSLSession(sslSession);
}
- return Platform.wrapSSLSession(sslSession);
}
@Override
@@ -553,22 +561,22 @@
@Override
public boolean isInboundDone() {
- if (sslNativePointer == 0) {
+ if (ssl.isClosed()) {
synchronized (stateLock) {
- return engineState == STATE_CLOSED || engineState == STATE_CLOSED_INBOUND;
+ return state == STATE_CLOSED || state == STATE_CLOSED_INBOUND;
}
}
- return (NativeCrypto.SSL_get_shutdown(sslNativePointer) & SSL_RECEIVED_SHUTDOWN) != 0;
+ return ssl.wasShutdownReceived();
}
@Override
public boolean isOutboundDone() {
- if (sslNativePointer == 0) {
+ if (ssl.isClosed()) {
synchronized (stateLock) {
- return engineState == STATE_CLOSED || engineState == STATE_CLOSED_OUTBOUND;
+ return state == STATE_CLOSED || state == STATE_CLOSED_OUTBOUND;
}
}
- return (NativeCrypto.SSL_get_shutdown(sslNativePointer) & SSL_SENT_SHUTDOWN) != 0;
+ return ssl.wasShutdownSent();
}
@Override
@@ -596,9 +604,9 @@
synchronized (stateLock) {
if (isHandshakeStarted()) {
throw new IllegalArgumentException(
- "Can not change mode after handshake: engineState == " + engineState);
+ "Can not change mode after handshake: state == " + state);
}
- engineState = STATE_MODE_SET;
+ state = STATE_MODE_SET;
}
sslParameters.setUseClientMode(mode);
}
@@ -666,7 +674,7 @@
final long srcLength = calcSrcsLength(srcs, srcsOffset, srcsEndOffset);
synchronized (stateLock) {
- switch (engineState) {
+ switch (state) {
case STATE_MODE_SET:
// Begin the handshake implicitly.
beginHandshakeInternal();
@@ -688,7 +696,7 @@
if (handshakeStatus == NEED_WRAP) {
return NEED_WRAP_OK;
}
- if (engineState == STATE_CLOSED) {
+ if (state == STATE_CLOSED) {
return NEED_WRAP_CLOSED;
}
// NEED_UNWRAP - just fall through to perform the unwrap.
@@ -872,7 +880,6 @@
}
private SSLEngineResult.HandshakeStatus handshake() throws SSLException {
- long sslSessionCtx = 0L;
try {
// Only actually perform the handshake if we haven't already just completed it
// via BIO operations.
@@ -890,7 +897,7 @@
throw e;
}
- int ssl_error_code = NativeCrypto.ENGINE_SSL_do_handshake(sslNativePointer, this);
+ int ssl_error_code = ssl.doHandshake();
switch (ssl_error_code) {
case SSL_ERROR_WANT_READ:
return pendingStatus(pendingOutboundEncryptedBytes());
@@ -917,28 +924,15 @@
throw e;
}
- // Handshake is finished!
- sslSessionCtx = NativeCrypto.SSL_get1_session(sslNativePointer);
- if (sslSessionCtx == 0) {
- // TODO(nathanmittler): Should we throw here?
- // return pendingStatus(pendingOutboundBytes());
- throw shutdownWithError("Failed to obtain session after handshake completed");
- }
- sslSession = sslParameters.setupSession(sslSessionCtx, sslNativePointer, sslSession,
- getPeerHost(), getPeerPort(), true);
- if (sslSession != null && engineState == STATE_HANDSHAKE_STARTED) {
- engineState = STATE_READY_HANDSHAKE_CUT_THROUGH;
- } else {
- engineState = STATE_READY;
- }
+ // The handshake has completed successfully...
+
+ // Update the session from the current state of the SSL object.
+ sslSession.onSessionEstablished(getPeerHost(), getPeerPort());
+
finishHandshake();
return FINISHED;
} catch (Exception e) {
throw toSSLHandshakeException(e);
- } finally {
- if (sslSession == null && sslSessionCtx != 0) {
- NativeCrypto.SSL_SESSION_free(sslSessionCtx);
- }
}
}
@@ -949,6 +943,7 @@
handshakeListener.onHandshakeFinished();
}
}
+
/**
* Write plaintext data to the OpenSSL internal BIO
*
@@ -961,11 +956,11 @@
if (src.isDirect()) {
long addr = NativeCrypto.getDirectBufferAddress(src) + pos;
- sslWrote = NativeCrypto.ENGINE_SSL_write_direct(sslNativePointer, addr, len, this);
+ sslWrote = ssl.writeDirectByteBuffer(addr, len);
} else {
ByteBuffer heapSrc = toHeapBuffer(src, len);
- sslWrote = NativeCrypto.ENGINE_SSL_write_heap(sslNativePointer, heapSrc.array(),
- heapSrc.arrayOffset() + heapSrc.position(), len, this);
+ sslWrote = ssl.writeArray(
+ heapSrc.array(), heapSrc.arrayOffset() + heapSrc.position(), len);
}
if (sslWrote > 0) {
src.position(pos + sslWrote);
@@ -987,19 +982,18 @@
final int len = Math.min(SSL3_RT_MAX_PACKET_SIZE, limit - pos);
if (dst.isDirect()) {
long addr = NativeCrypto.getDirectBufferAddress(dst) + pos;
- sslRead = NativeCrypto.ENGINE_SSL_read_direct(sslNativePointer, addr, len, this);
+ sslRead = ssl.readDirectByteBuffer(addr, len);
if (sslRead > 0) {
dst.position(pos + sslRead);
}
} else if (dst.hasArray()) {
- sslRead = NativeCrypto.ENGINE_SSL_read_heap(
- sslNativePointer, dst.array(), dst.arrayOffset() + pos, len, this);
+ sslRead = ssl.readArray(dst.array(), dst.arrayOffset() + pos, len);
if (sslRead > 0) {
dst.position(pos + sslRead);
}
} else {
byte[] data = new byte[len];
- sslRead = NativeCrypto.ENGINE_SSL_read_heap(sslNativePointer, data, 0, len, this);
+ sslRead = ssl.readArray(data, 0, len);
if (sslRead > 0) {
dst.put(data, 0, sslRead);
}
@@ -1026,12 +1020,11 @@
final int netWrote;
if (src.isDirect()) {
long addr = NativeCrypto.getDirectBufferAddress(src) + pos;
- netWrote = NativeCrypto.ENGINE_SSL_write_BIO_direct(
- sslNativePointer, networkBio, addr, len, this);
+ netWrote = networkBio.writeDirectByteBuffer(addr, len);
} else {
ByteBuffer heapSrc = toHeapBuffer(src, len);
- netWrote = NativeCrypto.ENGINE_SSL_write_BIO_heap(sslNativePointer, networkBio,
- heapSrc.array(), heapSrc.arrayOffset() + heapSrc.position(), len, this);
+ netWrote = networkBio.writeArray(
+ heapSrc.array(), heapSrc.arrayOffset() + heapSrc.position(), len);
}
if (netWrote >= 0) {
@@ -1095,23 +1088,20 @@
final int len = Math.min(pending, limit - pos);
if (dst.isDirect()) {
long addr = NativeCrypto.getDirectBufferAddress(dst) + pos;
- bioRead = NativeCrypto.ENGINE_SSL_read_BIO_direct(
- sslNativePointer, networkBio, addr, len, this);
+ bioRead = networkBio.readDirectByteBuffer(addr, len);
if (bioRead > 0) {
dst.position(pos + bioRead);
return bioRead;
}
} else if (dst.hasArray()) {
- bioRead = NativeCrypto.ENGINE_SSL_read_BIO_heap(sslNativePointer, networkBio,
- dst.array(), dst.arrayOffset() + pos, pending, this);
+ bioRead = networkBio.readArray(dst.array(), dst.arrayOffset() + pos, pending);
if (bioRead > 0) {
dst.position(pos + bioRead);
return bioRead;
}
} else {
byte[] data = new byte[len];
- bioRead = NativeCrypto.ENGINE_SSL_read_BIO_heap(
- sslNativePointer, networkBio, data, 0, pending, this);
+ bioRead = networkBio.readArray(data, 0, pending);
if (bioRead > 0) {
dst.put(data, 0, bioRead);
return bioRead;
@@ -1140,7 +1130,7 @@
}
private SSLEngineResult.Status getEngineStatus() {
- switch (engineState) {
+ switch (state) {
case STATE_CLOSED_INBOUND:
case STATE_CLOSED_OUTBOUND:
case STATE_CLOSED:
@@ -1155,14 +1145,6 @@
closeInbound();
}
- private SSLEngineResult sslReadErrorResult(int err, int bytesConsumed, int bytesProduced)
- throws SSLException {
- if (!handshakeFinished && pendingOutboundEncryptedBytes() > 0) {
- return new SSLEngineResult(OK, NEED_WRAP, bytesConsumed, bytesProduced);
- }
- throw shutdownWithError(NativeCrypto.SSL_get_error_string(err));
- }
-
private SSLException shutdownWithError(String err) {
// There was an internal error -- shutdown
shutdown();
@@ -1201,7 +1183,7 @@
}
synchronized (stateLock) {
- switch (engineState) {
+ switch (state) {
case STATE_MODE_SET:
// Begin the handshake implicitly.
beginHandshakeInternal();
@@ -1225,7 +1207,7 @@
return NEED_UNWRAP_OK;
}
- if (engineState == STATE_CLOSED) {
+ if (state == STATE_CLOSED) {
return NEED_UNWRAP_CLOSED;
}
// NEED_WRAP - just fall through to perform the wrap.
@@ -1285,7 +1267,7 @@
break loop;
}
} else {
- int sslError = NativeCrypto.SSL_get_error(sslNativePointer, result);
+ int sslError = ssl.getError(result);
switch (sslError) {
case SSL_ERROR_ZERO_RETURN:
// This means the connection was shutdown correctly, close inbound
@@ -1358,12 +1340,12 @@
@Override
public int clientPSKKeyRequested(String identityHint, byte[] identity, byte[] key) {
- return sslParameters.clientPSKKeyRequested(identityHint, identity, key, this);
+ return ssl.clientPSKKeyRequested(identityHint, identity, key);
}
@Override
public int serverPSKKeyRequested(String identityHint, String identity, byte[] key) {
- return sslParameters.serverPSKKeyRequested(identityHint, identity, key, this);
+ return ssl.serverPSKKeyRequested(identityHint, identity, key);
}
@Override
@@ -1373,16 +1355,16 @@
case SSL_CB_HANDSHAKE_START: {
// For clients, this will allow the NEED_UNWRAP status to be
// returned.
- engineState = STATE_HANDSHAKE_STARTED;
+ state = STATE_HANDSHAKE_STARTED;
break;
}
case SSL_CB_HANDSHAKE_DONE: {
- if (engineState != STATE_HANDSHAKE_STARTED
- && engineState != STATE_READY_HANDSHAKE_CUT_THROUGH) {
+ if (state != STATE_HANDSHAKE_STARTED
+ && state != STATE_READY_HANDSHAKE_CUT_THROUGH) {
throw new IllegalStateException(
- "Completed handshake while in mode " + engineState);
+ "Completed handshake while in mode " + state);
}
- engineState = STATE_HANDSHAKE_COMPLETED;
+ state = STATE_HANDSHAKE_COMPLETED;
break;
}
}
@@ -1390,6 +1372,33 @@
}
@Override
+ public void onNewSessionEstablished(long sslSessionNativePtr) {
+ try {
+ // Increment the reference count to "take ownership" of the session resource.
+ NativeCrypto.SSL_SESSION_up_ref(sslSessionNativePtr);
+
+ // Create a native reference which will release the SSL_SESSION in its finalizer.
+ // This constructor will only throw if the native pointer passed in is NULL, which
+ // BoringSSL guarantees will not happen.
+ NativeRef.SSL_SESSION ref = new SSL_SESSION(sslSessionNativePtr);
+
+ SslSessionWrapper sessionWrapper = SslSessionWrapper.newInstance(ref, sslSession);
+
+ // Cache the newly established session.
+ AbstractSessionContext ctx = sessionContext();
+ ctx.cacheSession(sessionWrapper);
+ } catch (Exception ignored) {
+ // Ignore.
+ }
+ }
+
+ @Override
+ public long serverSessionRequested(byte[] id) {
+ // TODO(nathanmittler): Implement server-side caching for TLS < 1.3
+ return 0;
+ }
+
+ @Override
public void verifyCertificateChain(long[] certRefs, String authMethod)
throws CertificateException {
try {
@@ -1403,13 +1412,8 @@
OpenSSLX509Certificate[] peerCertChain =
OpenSSLX509Certificate.createCertChain(certRefs);
- byte[] ocspData = NativeCrypto.SSL_get_ocsp_response(sslNativePointer);
- byte[] tlsSctData = NativeCrypto.SSL_get_signed_cert_timestamp_list(sslNativePointer);
-
- // Used for verifyCertificateChain callback
- handshakeSession = new OpenSSLSessionImpl(
- NativeCrypto.SSL_get1_session(sslNativePointer), null, peerCertChain, ocspData,
- tlsSctData, getPeerHost(), getPeerPort(), null);
+ // Update the peer information on the session.
+ sslSession.onPeerCertificatesReceived(getPeerHost(), getPeerPort(), peerCertChain);
if (getUseClientMode()) {
Platform.checkServerTrusted(x509tm, peerCertChain, authMethod, this);
@@ -1421,21 +1425,18 @@
throw e;
} catch (Exception e) {
throw new CertificateException(e);
- } finally {
- handshakeSession = null;
}
}
@Override
public void clientCertificateRequested(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals)
throws CertificateEncodingException, SSLException {
- sslParameters.chooseClientCertificate(
- keyTypeBytes, asn1DerEncodedPrincipals, sslNativePointer, this);
+ ssl.chooseClientCertificate(keyTypeBytes, asn1DerEncodedPrincipals);
}
private void shutdown() {
try {
- NativeCrypto.ENGINE_SSL_shutdown(sslNativePointer, this);
+ ssl.shutdown();
} catch (IOException ignored) {
// TODO: The RI ignores close failures in SSLSocket, but need to
// investigate whether it does for SSLEngine.
@@ -1451,13 +1452,10 @@
}
private void free() {
- if (sslNativePointer == 0) {
- return;
+ if (!ssl.isClosed()) {
+ ssl.close();
+ networkBio.close();
}
- NativeCrypto.SSL_free(sslNativePointer);
- NativeCrypto.BIO_free_all(networkBio);
- sslNativePointer = 0;
- networkBio = 0;
}
@Override
@@ -1469,22 +1467,6 @@
}
}
- /* @Override */
- @SuppressWarnings("MissingOverride") // For compilation with Java 6.
- public SSLSession getHandshakeSession() {
- return handshakeSession;
- }
-
- /**
- * Work-around to allow this method to be called on older versions of Android.
- */
- SSLSession handshakeSession() {
- if (handshakeSession != null) {
- return Platform.wrapSSLSession(handshakeSession);
- }
- return null;
- }
-
@Override
public String chooseServerAlias(X509KeyManager keyManager, String keyType) {
if (keyManager instanceof X509ExtendedKeyManager) {
@@ -1556,7 +1538,7 @@
* agreed upon.
*/
byte[] getAlpnSelectedProtocol() {
- return NativeCrypto.SSL_get0_alpn_selected(sslNativePointer);
+ return ssl.getAlpnSelectedProtocol();
}
private ByteBuffer toHeapBuffer(ByteBuffer buffer, int len) {
@@ -1597,6 +1579,14 @@
singleDstBuffer[0] = null;
}
+ private ClientSessionContext clientSessionContext() {
+ return sslParameters.getClientSessionContext();
+ }
+
+ private AbstractSessionContext sessionContext() {
+ return sslParameters.getSessionContext();
+ }
+
private static void checkIndex(int arrayLength, int offset, int length, String arrayName) {
if ((offset | length) < 0 || offset + length > arrayLength) {
throw new IndexOutOfBoundsException("offset: " + offset + ", length: " + length
diff --git a/common/src/main/java/org/conscrypt/ConscryptEngineSocket.java b/common/src/main/java/org/conscrypt/ConscryptEngineSocket.java
index 433a6bc..f40efdd 100644
--- a/common/src/main/java/org/conscrypt/ConscryptEngineSocket.java
+++ b/common/src/main/java/org/conscrypt/ConscryptEngineSocket.java
@@ -34,19 +34,15 @@
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.security.PrivateKey;
-import javax.crypto.SecretKey;
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSession;
-import javax.net.ssl.X509KeyManager;
-import javax.security.auth.x500.X500Principal;
/**
* Implements crypto handling by delegating to {@link ConscryptEngine}.
*/
-final class ConscryptEngineSocket extends OpenSSLSocketImpl
- implements SSLParametersImpl.AliasChooser, SSLParametersImpl.PSKCallbacks {
+final class ConscryptEngineSocket extends OpenSSLSocketImpl {
private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocate(0);
private final ConscryptEngine engine;
@@ -225,7 +221,7 @@
@Override
public SSLSession getSession() {
SSLSession session = engine.getSession();
- if (session == null) {
+ if (SSLNullSession.isNullSession(session)) {
boolean handshakeCompleted = false;
try {
if (isConnected()) {
@@ -237,9 +233,8 @@
}
if (!handshakeCompleted) {
- // return an invalid session with
- // invalid cipher suite of "SSL_NULL_WITH_NULL_NULL"
- return SSLNullSession.getNullSession();
+ // Return an invalid session with invalid cipher suite of "SSL_NULL_WITH_NULL_NULL"
+ return session;
}
session = engine.getSession();
}
@@ -391,35 +386,6 @@
engine.setAlpnProtocols(alpnProtocols);
}
- @Override
- public String chooseServerAlias(X509KeyManager keyManager, String keyType) {
- return engine.chooseServerAlias(keyManager, keyType);
- }
-
- @Override
- public String chooseClientAlias(
- X509KeyManager keyManager, X500Principal[] issuers, String[] keyTypes) {
- return engine.chooseClientAlias(keyManager, issuers, keyTypes);
- }
-
- @Override
- @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package
- public String chooseServerPSKIdentityHint(PSKKeyManager keyManager) {
- return engine.chooseServerPSKIdentityHint(keyManager);
- }
-
- @Override
- @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package
- public String chooseClientPSKIdentity(PSKKeyManager keyManager, String identityHint) {
- return engine.chooseClientPSKIdentity(keyManager, identityHint);
- }
-
- @Override
- @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package
- public SecretKey getPSKKey(PSKKeyManager keyManager, String identityHint, String identity) {
- return engine.getPSKKey(keyManager, identityHint, identity);
- }
-
private boolean isHandshakeFinished() {
return state >= STATE_READY_HANDSHAKE_CUT_THROUGH;
}
diff --git a/common/src/main/java/org/conscrypt/ConscryptFileDescriptorSocket.java b/common/src/main/java/org/conscrypt/ConscryptFileDescriptorSocket.java
index 34f23c7..7db8654 100644
--- a/common/src/main/java/org/conscrypt/ConscryptFileDescriptorSocket.java
+++ b/common/src/main/java/org/conscrypt/ConscryptFileDescriptorSocket.java
@@ -17,7 +17,6 @@
package org.conscrypt;
import static org.conscrypt.SSLUtils.EngineStates.STATE_CLOSED;
-import static org.conscrypt.SSLUtils.EngineStates.STATE_HANDSHAKE_COMPLETED;
import static org.conscrypt.SSLUtils.EngineStates.STATE_HANDSHAKE_STARTED;
import static org.conscrypt.SSLUtils.EngineStates.STATE_NEW;
import static org.conscrypt.SSLUtils.EngineStates.STATE_READY;
@@ -44,6 +43,7 @@
import javax.net.ssl.X509KeyManager;
import javax.net.ssl.X509TrustManager;
import javax.security.auth.x500.X500Principal;
+import org.conscrypt.NativeRef.SSL_SESSION;
/**
* Implementation of the class OpenSSLSocketImpl based on OpenSSL.
@@ -73,7 +73,7 @@
* startHandshake, reset to 0 on close.
*/
// @GuardedBy("stateLock");
- private long sslNativePointer;
+ private final SslWrapper ssl;
/**
* Protected by synchronizing on stateLock. Starts as null, set by
@@ -102,47 +102,64 @@
*/
private OpenSSLKey channelIdPrivateKey;
- /** Set during startHandshake. */
- private AbstractOpenSSLSession sslSession;
-
- /** Used during handshake callbacks. */
- private AbstractOpenSSLSession handshakeSession;
+ private final ActiveSession sslSession;
private int writeTimeoutMilliseconds = 0;
private int handshakeTimeoutMilliseconds = -1; // -1 = same as timeout; 0 = infinite
ConscryptFileDescriptorSocket(SSLParametersImpl sslParameters) throws IOException {
this.sslParameters = sslParameters;
+ this.ssl = newSsl(sslParameters, this);
+ sslSession = new ActiveSession(ssl, sslParameters.getSessionContext());
}
ConscryptFileDescriptorSocket(String hostname, int port, SSLParametersImpl sslParameters)
throws IOException {
super(hostname, port);
this.sslParameters = sslParameters;
+ this.ssl = newSsl(sslParameters, this);
+ sslSession = new ActiveSession(ssl, sslParameters.getSessionContext());
}
ConscryptFileDescriptorSocket(InetAddress address, int port, SSLParametersImpl sslParameters)
throws IOException {
super(address, port);
this.sslParameters = sslParameters;
+ this.ssl = newSsl(sslParameters, this);
+ sslSession = new ActiveSession(ssl, sslParameters.getSessionContext());
}
ConscryptFileDescriptorSocket(String hostname, int port, InetAddress clientAddress,
int clientPort, SSLParametersImpl sslParameters) throws IOException {
super(hostname, port, clientAddress, clientPort);
this.sslParameters = sslParameters;
+ this.ssl = newSsl(sslParameters, this);
+ sslSession = new ActiveSession(ssl, sslParameters.getSessionContext());
}
ConscryptFileDescriptorSocket(InetAddress address, int port, InetAddress clientAddress,
int clientPort, SSLParametersImpl sslParameters) throws IOException {
super(address, port, clientAddress, clientPort);
this.sslParameters = sslParameters;
+ this.ssl = newSsl(sslParameters, this);
+ sslSession = new ActiveSession(ssl, sslParameters.getSessionContext());
}
ConscryptFileDescriptorSocket(Socket socket, String hostname, int port, boolean autoClose,
SSLParametersImpl sslParameters) throws IOException {
super(socket, hostname, port, autoClose);
this.sslParameters = sslParameters;
+ this.ssl = newSsl(sslParameters, this);
+ sslSession = new ActiveSession(ssl, sslParameters.getSessionContext());
+ }
+
+ private static SslWrapper newSsl(SSLParametersImpl sslParameters,
+ ConscryptFileDescriptorSocket engine) {
+ try {
+ return SslWrapper.newInstance(sslParameters, engine, engine, engine);
+ } catch (SSLException e) {
+ throw new RuntimeException(e);
+ }
}
/**
@@ -165,49 +182,23 @@
}
}
- final boolean client = sslParameters.getUseClientMode();
-
- sslNativePointer = 0;
boolean releaseResources = true;
try {
- final AbstractSessionContext sessionContext = sslParameters.getSessionContext();
- sslNativePointer = NativeCrypto.SSL_new(sessionContext.sslCtxNativePointer);
Platform.closeGuardOpen(guard, "close");
- boolean enableSessionCreation = getEnableSessionCreation();
- if (!enableSessionCreation) {
- NativeCrypto.SSL_set_session_creation_enabled(sslNativePointer,
- enableSessionCreation);
- }
+ // Prepare the SSL object for the handshake.
+ ssl.initialize(getHostname(), channelIdPrivateKey);
- // Allow servers to trigger renegotiation. Some inadvisable server
- // configurations cause them to attempt to renegotiate during
- // certain protocols.
- NativeCrypto.SSL_accept_renegotiations(sslNativePointer);
-
- if (client) {
- NativeCrypto.SSL_set_connect_state(sslNativePointer);
-
- // Configure OCSP and CT extensions for client
- NativeCrypto.SSL_enable_ocsp_stapling(sslNativePointer);
- if (sslParameters.isCTVerificationEnabled(getHostname())) {
- NativeCrypto.SSL_enable_signed_cert_timestamps(sslNativePointer);
- }
- } else {
- NativeCrypto.SSL_set_accept_state(sslNativePointer);
-
- // Configure OCSP for server
- if (sslParameters.getOCSPResponse() != null) {
- NativeCrypto.SSL_enable_ocsp_stapling(sslNativePointer);
+ // For clients, offer to resume a previously cached session to avoid the
+ // full TLS handshake.
+ if (getUseClientMode()) {
+ SslSessionWrapper cachedSession = clientSessionContext().getCachedSession(
+ getHostnameOrIP(), getPort(), sslParameters);
+ if (cachedSession != null) {
+ cachedSession.offerToResume(ssl);
}
}
- final AbstractOpenSSLSession sessionToReuse =
- sslParameters.getSessionToReuse(sslNativePointer, getHostnameOrIP(), getPort());
- sslParameters.setSSLParameters(sslNativePointer, this, this, getHostname());
- sslParameters.setCertificateValidation(sslNativePointer);
- sslParameters.setTlsChannelId(sslNativePointer, channelIdPrivateKey);
-
// Temporarily use a different timeout for the handshake process
int savedReadTimeoutMilliseconds = getSoTimeout();
int savedWriteTimeoutMilliseconds = getSoWriteTimeout();
@@ -222,11 +213,8 @@
}
}
- long sslSessionNativePointer;
try {
- NativeCrypto.SSL_do_handshake(
- sslNativePointer, Platform.getFileDescriptor(socket), this, getSoTimeout());
- sslSessionNativePointer = NativeCrypto.SSL_get1_session(sslNativePointer);
+ ssl.doHandshake(Platform.getFileDescriptor(socket), getSoTimeout());
} catch (CertificateException e) {
SSLHandshakeException wrapper = new SSLHandshakeException(e.getMessage());
wrapper.initCause(e);
@@ -249,43 +237,32 @@
String message = e.getMessage();
// Must match error string of SSL_R_UNEXPECTED_CCS
if (message.contains("unexpected CCS")) {
- String logMessage = String.format("ssl_unexpected_ccs: host=%s",
- getHostnameOrIP());
+ String logMessage =
+ String.format("ssl_unexpected_ccs: host=%s", getHostnameOrIP());
Platform.logEvent(logMessage);
}
throw e;
}
- boolean handshakeCompleted = false;
synchronized (stateLock) {
- if (state == STATE_HANDSHAKE_COMPLETED) {
- handshakeCompleted = true;
- } else if (state == STATE_CLOSED) {
+ if (state == STATE_CLOSED) {
return;
}
}
- sslSession = sslParameters.setupSession(sslSessionNativePointer, sslNativePointer,
- sessionToReuse, getHostnameOrIP(), getPort(), handshakeCompleted);
-
// Restore the original timeout now that the handshake is complete
if (handshakeTimeoutMilliseconds >= 0) {
setSoTimeout(savedReadTimeoutMilliseconds);
setSoWriteTimeout(savedWriteTimeoutMilliseconds);
}
- // if not, notifyHandshakeCompletedListeners later in handshakeCompleted() callback
- if (handshakeCompleted) {
- notifyHandshakeCompletedListeners();
- }
-
synchronized (stateLock) {
releaseResources = (state == STATE_CLOSED);
if (state == STATE_HANDSHAKE_STARTED) {
state = STATE_READY_HANDSHAKE_CUT_THROUGH;
- } else if (state == STATE_HANDSHAKE_COMPLETED) {
+ } else {
state = STATE_READY;
}
@@ -296,8 +273,7 @@
}
}
} catch (SSLProtocolException e) {
- throw (SSLHandshakeException) new SSLHandshakeException("Handshake failed")
- .initCause(e);
+ throw(SSLHandshakeException) new SSLHandshakeException("Handshake failed").initCause(e);
} finally {
// on exceptional exit, treat the socket as closed
if (releaseResources) {
@@ -324,70 +300,83 @@
@SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / client_cert_cb
public void clientCertificateRequested(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals)
throws CertificateEncodingException, SSLException {
- sslParameters.chooseClientCertificate(keyTypeBytes, asn1DerEncodedPrincipals,
- sslNativePointer, this);
+ ssl.chooseClientCertificate(keyTypeBytes, asn1DerEncodedPrincipals);
}
@Override
@SuppressWarnings("unused") // used by native psk_client_callback
public int clientPSKKeyRequested(String identityHint, byte[] identity, byte[] key) {
- return sslParameters.clientPSKKeyRequested(identityHint, identity, key, this);
+ return ssl.clientPSKKeyRequested(identityHint, identity, key);
}
@Override
@SuppressWarnings("unused") // used by native psk_server_callback
public int serverPSKKeyRequested(String identityHint, String identity, byte[] key) {
- return sslParameters.serverPSKKeyRequested(identityHint, identity, key, this);
+ return ssl.serverPSKKeyRequested(identityHint, identity, key);
}
@Override
@SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / info_callback
public void onSSLStateChange(int type, int val) {
if (type != NativeConstants.SSL_CB_HANDSHAKE_DONE) {
+ // We only care about successful completion.
return;
}
- synchronized (stateLock) {
- if (state == STATE_HANDSHAKE_STARTED) {
- // If sslSession is null, the handshake was completed during
- // the call to NativeCrypto.SSL_do_handshake and not during a
- // later read operation. That means we do not need to fix up
- // the SSLSession and session cache or notify
- // HandshakeCompletedListeners, it will be done in
- // startHandshake.
+ // The handshake has completed successfully ...
- state = STATE_HANDSHAKE_COMPLETED;
- return;
- } else if (state == STATE_READY_HANDSHAKE_CUT_THROUGH) {
- // We've returned from startHandshake, which means we've set a sslSession etc.
- // we need to fix them up, which we'll do outside this lock.
- } else if (state == STATE_CLOSED) {
+ // Update the session from the current state of the SSL object.
+ sslSession.onSessionEstablished(getHostnameOrIP(), getPort());
+
+ // First, update the state.
+ synchronized (stateLock) {
+ if (state == STATE_CLOSED) {
// Someone called "close" but the handshake hasn't been interrupted yet.
return;
}
- }
- // reset session id from the native pointer and update the
- // appropriate cache.
- sslSession.resetId();
- AbstractSessionContext sessionContext =
- (sslParameters.getUseClientMode())
- ? sslParameters.getClientSessionContext()
- : sslParameters.getServerSessionContext();
- sessionContext.putSession(sslSession);
-
- // let listeners know we are finally done
- notifyHandshakeCompletedListeners();
-
- synchronized (stateLock) {
// Now that we've fixed up our state, we can tell waiting threads that
// we're ready.
state = STATE_READY;
+ }
+
+ // Let listeners know we are finally done
+ notifyHandshakeCompletedListeners();
+
+ synchronized (stateLock) {
// Notify all threads waiting for the handshake to complete.
stateLock.notifyAll();
}
}
+ @Override
+ @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / new_session_callback
+ public void onNewSessionEstablished(long sslSessionNativePtr) {
+ try {
+ // Increment the reference count to "take ownership" of the session resource.
+ NativeCrypto.SSL_SESSION_up_ref(sslSessionNativePtr);
+
+ // Create a native reference which will release the SSL_SESSION in its finalizer.
+ // This constructor will only throw if the native pointer passed in is NULL, which
+ // BoringSSL guarantees will not happen.
+ NativeRef.SSL_SESSION ref = new SSL_SESSION(sslSessionNativePtr);
+
+ SslSessionWrapper sessionWrapper = SslSessionWrapper.newInstance(ref, sslSession);
+
+ // Cache the newly established session.
+ AbstractSessionContext ctx = sessionContext();
+ ctx.cacheSession(sessionWrapper);
+ } catch (Exception ignored) {
+ // Ignore.
+ }
+ }
+
+ @Override
+ public long serverSessionRequested(byte[] id) {
+ // TODO(nathanmittler): Implement server-side caching for TLS < 1.3
+ return 0;
+ }
+
@SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks
@Override
public void verifyCertificateChain(long[] certRefs, String authMethod)
@@ -403,16 +392,10 @@
OpenSSLX509Certificate[] peerCertChain =
OpenSSLX509Certificate.createCertChain(certRefs);
- byte[] ocspData = NativeCrypto.SSL_get_ocsp_response(sslNativePointer);
- byte[] tlsSctData = NativeCrypto.SSL_get_signed_cert_timestamp_list(sslNativePointer);
+ // Update the peer information on the session.
+ sslSession.onPeerCertificatesReceived(getHostnameOrIP(), getPort(), peerCertChain);
- // Used for verifyCertificateChain callback
- handshakeSession = new OpenSSLSessionImpl(
- NativeCrypto.SSL_get1_session(sslNativePointer), null, peerCertChain, ocspData,
- tlsSctData, getHostnameOrIP(), getPort(), null);
-
- boolean client = sslParameters.getUseClientMode();
- if (client) {
+ if (getUseClientMode()) {
Platform.checkServerTrusted(x509tm, peerCertChain, authMethod, this);
} else {
String authType = peerCertChain[0].getPublicKey().getAlgorithm();
@@ -422,9 +405,6 @@
throw e;
} catch (Exception e) {
throw new CertificateException(e);
- } finally {
- // Clear this before notifying handshake completed listeners
- handshakeSession = null;
}
}
@@ -553,11 +533,13 @@
throw new SocketException("socket is closed");
}
- if (DBG_STATE) assertReadableOrWriteableState();
+ if (DBG_STATE) {
+ assertReadableOrWriteableState();
+ }
}
- int ret = NativeCrypto.SSL_read(sslNativePointer, Platform.getFileDescriptor(socket),
- ConscryptFileDescriptorSocket.this, buf, offset, byteCount, getSoTimeout());
+ int ret = ssl.read(
+ Platform.getFileDescriptor(socket), buf, offset, byteCount, getSoTimeout());
if (ret == -1) {
synchronized (stateLock) {
if (state == STATE_CLOSED) {
@@ -572,11 +554,13 @@
void awaitPendingOps() {
if (DBG_STATE) {
synchronized (stateLock) {
- if (state != STATE_CLOSED) throw new AssertionError("State is: " + state);
+ if (state != STATE_CLOSED) {
+ throw new AssertionError("State is: " + state);
+ }
}
}
- synchronized (readLock) { }
+ synchronized (readLock) {}
}
}
@@ -626,11 +610,12 @@
throw new SocketException("socket is closed");
}
- if (DBG_STATE) assertReadableOrWriteableState();
+ if (DBG_STATE) {
+ assertReadableOrWriteableState();
+ }
}
- NativeCrypto.SSL_write(sslNativePointer, Platform.getFileDescriptor(socket),
- ConscryptFileDescriptorSocket.this, buf, offset, byteCount,
+ ssl.write(Platform.getFileDescriptor(socket), buf, offset, byteCount,
writeTimeoutMilliseconds);
synchronized (stateLock) {
@@ -644,7 +629,9 @@
void awaitPendingOps() {
if (DBG_STATE) {
synchronized (stateLock) {
- if (state != STATE_CLOSED) throw new AssertionError("State is: " + state);
+ if (state != STATE_CLOSED) {
+ throw new AssertionError("State is: " + state);
+ }
}
}
@@ -654,23 +641,25 @@
@Override
public SSLSession getSession() {
- if (sslSession == null) {
- boolean handshakeCompleted = false;
+ boolean handshakeCompleted = false;
+ synchronized (stateLock) {
try {
- if (isConnected()) {
+ handshakeCompleted = state >= STATE_READY;
+ if (!handshakeCompleted && isConnected()) {
waitForHandshake();
handshakeCompleted = true;
}
} catch (IOException e) {
// Fall through.
}
-
- if (!handshakeCompleted) {
- // return an invalid session with
- // invalid cipher suite of "SSL_NULL_WITH_NULL_NULL"
- return SSLNullSession.getNullSession();
- }
}
+
+ if (!handshakeCompleted) {
+ // return an invalid session with
+ // invalid cipher suite of "SSL_NULL_WITH_NULL_NULL"
+ return SSLNullSession.getNullSession();
+ }
+
return Platform.wrapSSLSession(sslSession);
}
@@ -681,7 +670,9 @@
@Override
public SSLSession getHandshakeSession() {
- return handshakeSession;
+ synchronized (stateLock) {
+ return state >= STATE_HANDSHAKE_STARTED && state < STATE_READY ? sslSession : null;
+ }
}
@Override
@@ -791,7 +782,7 @@
"Channel ID is only available after handshake completes");
}
}
- return NativeCrypto.SSL_get_tls_channel_id(sslNativePointer);
+ return ssl.getTlsChannelId();
}
/**
@@ -938,7 +929,7 @@
// We call SSL_interrupt so that we can interrupt SSL_do_handshake and then
// set the state to STATE_CLOSED. startHandshake will handle all cleanup
// after SSL_do_handshake returns, so we don't have anything to do here.
- NativeCrypto.SSL_interrupt(sslNativePointer);
+ ssl.interrupt();
stateLock.notifyAll();
return;
@@ -953,7 +944,7 @@
// Don't bother interrupting unless we have something to interrupt.
if (sslInputStream != null || sslOutputStream != null) {
- NativeCrypto.SSL_interrupt(sslNativePointer);
+ ssl.interrupt();
}
// Wait for the input and output streams to finish any reads they have in
@@ -972,8 +963,7 @@
private void shutdownAndFreeSslNative() throws IOException {
try {
Platform.blockGuardOnNetwork();
- NativeCrypto.SSL_shutdown(sslNativePointer, Platform.getFileDescriptor(socket),
- this);
+ ssl.shutdown(Platform.getFileDescriptor(socket));
} catch (IOException ignored) {
/*
* Note that although close() can throw
@@ -992,12 +982,10 @@
}
private void free() {
- if (sslNativePointer == 0) {
- return;
+ if (!ssl.isClosed()) {
+ ssl.close();
+ Platform.closeGuardClose(guard);
}
- NativeCrypto.SSL_free(sslNativePointer);
- sslNativePointer = 0;
- Platform.closeGuardClose(guard);
}
@Override
@@ -1034,7 +1022,7 @@
*/
@Override
public byte[] getAlpnSelectedProtocol() {
- return NativeCrypto.SSL_get0_alpn_selected(sslNativePointer);
+ return ssl.getAlpnSelectedProtocol();
}
/**
@@ -1103,4 +1091,12 @@
public SecretKey getPSKKey(PSKKeyManager keyManager, String identityHint, String identity) {
return keyManager.getKey(identityHint, identity, this);
}
+
+ private ClientSessionContext clientSessionContext() {
+ return sslParameters.getClientSessionContext();
+ }
+
+ private AbstractSessionContext sessionContext() {
+ return sslParameters.getSessionContext();
+ }
}
diff --git a/common/src/main/java/org/conscrypt/OpenSSLExtendedSessionImpl.java b/common/src/main/java/org/conscrypt/DelegatingExtendedSSLSession.java
similarity index 81%
rename from common/src/main/java/org/conscrypt/OpenSSLExtendedSessionImpl.java
rename to common/src/main/java/org/conscrypt/DelegatingExtendedSSLSession.java
index dead13d..e0114fd 100644
--- a/common/src/main/java/org/conscrypt/OpenSSLExtendedSessionImpl.java
+++ b/common/src/main/java/org/conscrypt/DelegatingExtendedSSLSession.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 The Android Open Source Project
+ * Copyright 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,44 +30,46 @@
* Implementation of the ExtendedSSLSession class for OpenSSL. Uses a delegate to maintain backward
* compatibility with previous versions of Android which don't have ExtendedSSLSession.
*/
-final class OpenSSLExtendedSessionImpl extends ExtendedSSLSession {
- private final AbstractOpenSSLSession delegate;
+final class DelegatingExtendedSSLSession extends ExtendedSSLSession {
+ // TODO: use BoringSSL API to actually fetch the real data
+ private static final String[] LOCAL_SUPPORTED_SIGNATURE_ALGORITHMS = new String[] {
+ "SHA512withRSA",
+ "SHA512withECDSA",
+ "SHA384withRSA",
+ "SHA384withECDSA",
+ "SHA256withRSA",
+ "SHA256withECDSA",
+ "SHA224withRSA",
+ "SHA224withECDSA",
+ "SHA1withRSA",
+ "SHA1withECDSA",
+ };
+ // TODO: use BoringSSL API to actually fetch the real data
+ private static final String[] PEER_SUPPORTED_SIGNATURE_ALGORITHMS = new String[] {
+ "SHA1withRSA",
+ "SHA1withECDSA"
+ };
- OpenSSLExtendedSessionImpl(AbstractOpenSSLSession delegate) {
+ private final ActiveSession delegate;
+
+ DelegatingExtendedSSLSession(ActiveSession delegate) {
this.delegate = delegate;
}
- AbstractOpenSSLSession getDelegate() {
+ ActiveSession getDelegate() {
return delegate;
}
/* @Override */
@SuppressWarnings("MissingOverride") // For Android backward-compatibility.
public String[] getLocalSupportedSignatureAlgorithms() {
- // From src/ssl/t1_lib.c tls12_sigalgs
- // TODO: use BoringSSL API to actually fetch the real data
- return new String[] {
- "SHA512withRSA",
- "SHA512withECDSA",
- "SHA384withRSA",
- "SHA384withECDSA",
- "SHA256withRSA",
- "SHA256withECDSA",
- "SHA224withRSA",
- "SHA224withECDSA",
- "SHA1withRSA",
- "SHA1withECDSA",
- };
+ return LOCAL_SUPPORTED_SIGNATURE_ALGORITHMS.clone();
}
/* @Override */
@SuppressWarnings("MissingOverride") // For Android backward-compatibility.
public String[] getPeerSupportedSignatureAlgorithms() {
- // TODO: use BoringSSL API to actually fetch the real data
- return new String[] {
- "SHA1withRSA",
- "SHA1withECDSA",
- };
+ return PEER_SUPPORTED_SIGNATURE_ALGORITHMS.clone();
}
/* @Override */
diff --git a/common/src/main/java/org/conscrypt/NativeCrypto.java b/common/src/main/java/org/conscrypt/NativeCrypto.java
index e0ad406..6cd9f4d 100644
--- a/common/src/main/java/org/conscrypt/NativeCrypto.java
+++ b/common/src/main/java/org/conscrypt/NativeCrypto.java
@@ -64,8 +64,6 @@
static native long EVP_PKEY_new_RSA(byte[] n, byte[] e, byte[] d, byte[] p, byte[] q,
byte[] dmp1, byte[] dmq1, byte[] iqmp);
- static native int EVP_PKEY_size(NativeRef.EVP_PKEY pkey);
-
static native int EVP_PKEY_type(NativeRef.EVP_PKEY pkey);
static native String EVP_PKEY_print_public(NativeRef.EVP_PKEY pkeyRef);
@@ -118,10 +116,6 @@
*/
static native byte[][] get_RSA_private_params(NativeRef.EVP_PKEY rsa);
- static native byte[] i2d_RSAPublicKey(NativeRef.EVP_PKEY rsa);
-
- static native byte[] i2d_RSAPrivateKey(NativeRef.EVP_PKEY rsa);
-
// --- EC functions --------------------------
static native long EVP_PKEY_new_EC_KEY(
@@ -180,8 +174,6 @@
static native int EVP_MD_size(long evp_md_const);
- static native int EVP_MD_block_size(long evp_md_const);
-
// --- Message digest context functions --------------
static native long EVP_MD_CTX_create();
@@ -294,8 +286,6 @@
static native int EVP_AEAD_nonce_length(long evpAead);
- static native int EVP_AEAD_max_tag_len(long evpAead);
-
static native int EVP_AEAD_CTX_seal(long evpAead, byte[] key, int tagLengthInBytes, byte[] out,
int outOffset, byte[] nonce, byte[] in, int inOffset, int inLength, byte[] ad)
throws BadPaddingException;
@@ -322,14 +312,6 @@
static native void RAND_bytes(byte[] output);
- // --- ASN.1 objects -------------------------------------------------------
-
- static native int OBJ_txt2nid(String oid);
-
- static native String OBJ_txt2nid_longName(String oid);
-
- static native String OBJ_txt2nid_oid(String oid);
-
// --- X509_NAME -----------------------------------------------------------
static int X509_NAME_hash(X500Principal principal) {
@@ -350,8 +332,6 @@
}
}
- static native String X509_NAME_print_ex(long x509nameCtx, long flags);
-
// --- X509 ----------------------------------------------------------------
/** Used to request get_X509_GENERAL_NAME_stack get the "altname" field. */
@@ -542,11 +522,6 @@
static native long create_BIO_OutputStream(OutputStream os);
- static native int BIO_read(long bioRef, byte[] buffer);
-
- static native void BIO_write(long bioRef, byte[] buffer, int offset, int length)
- throws IOException;
-
static native void BIO_free_all(long bioRef);
// --- SSL handling --------------------------------------------------------
@@ -782,6 +757,8 @@
static native void SSL_CTX_set_session_id_context(long ssl_ctx, byte[] sid_ctx);
+ static native long SSL_CTX_set_timeout(long ssl_ctx, long seconds);
+
static native long SSL_new(long ssl_ctx) throws SSLException;
static native void SSL_enable_tls_channel_id(long ssl) throws SSLException;
@@ -798,14 +775,8 @@
static native void SSL_set_client_CA_list(long ssl, byte[][] asn1DerEncodedX500Principals);
- static native long SSL_get_mode(long ssl);
-
static native long SSL_set_mode(long ssl, long mode);
- static native long SSL_clear_mode(long ssl, long mode);
-
- static native long SSL_get_options(long ssl);
-
static native long SSL_set_options(long ssl, long options);
static native long SSL_clear_options(long ssl, long options);
@@ -830,25 +801,29 @@
/** Protocols to enable by default when "TLSv1.2" is requested. */
static final String[] TLSV12_PROTOCOLS = new String[] {
- SUPPORTED_PROTOCOL_TLSV1, SUPPORTED_PROTOCOL_TLSV1_1, SUPPORTED_PROTOCOL_TLSV1_2,
+ SUPPORTED_PROTOCOL_TLSV1,
+ SUPPORTED_PROTOCOL_TLSV1_1,
+ SUPPORTED_PROTOCOL_TLSV1_2,
};
/** Protocols to enable by default when "TLSv1.1" is requested. */
static final String[] TLSV11_PROTOCOLS = new String[] {
- SUPPORTED_PROTOCOL_TLSV1, SUPPORTED_PROTOCOL_TLSV1_1, SUPPORTED_PROTOCOL_TLSV1_2,
+ SUPPORTED_PROTOCOL_TLSV1,
+ SUPPORTED_PROTOCOL_TLSV1_1,
+ SUPPORTED_PROTOCOL_TLSV1_2,
};
/** Protocols to enable by default when "TLSv1" is requested. */
static final String[] TLSV1_PROTOCOLS = new String[] {
- SUPPORTED_PROTOCOL_TLSV1, SUPPORTED_PROTOCOL_TLSV1_1, SUPPORTED_PROTOCOL_TLSV1_2,
+ SUPPORTED_PROTOCOL_TLSV1,
+ SUPPORTED_PROTOCOL_TLSV1_1,
+ SUPPORTED_PROTOCOL_TLSV1_2,
};
static final String[] DEFAULT_PROTOCOLS = TLSV12_PROTOCOLS;
static String[] getSupportedProtocols() {
- return new String[] {
- SUPPORTED_PROTOCOL_TLSV1, SUPPORTED_PROTOCOL_TLSV1_1, SUPPORTED_PROTOCOL_TLSV1_2,
- };
+ return TLSV12_PROTOCOLS.clone();
}
static void setEnabledProtocols(long ssl, String[] protocols) {
@@ -996,11 +971,9 @@
long sslNativePointer, FileDescriptor fd, SSLHandshakeCallbacks shc, int timeoutMillis)
throws SSLException, SocketTimeoutException, CertificateException;
- /**
- * Currently only intended for forcing renegotiation for testing.
- * Not used within OpenSSLSocketImpl.
- */
- static native void SSL_renegotiate(long sslNativePointer) throws SSLException;
+ public static native String SSL_get_current_cipher(long sslNativePointer);
+
+ public static native String SSL_get_version(long sslNativePointer);
/**
* Returns the local X509 certificate references. Must X509_free when done.
@@ -1041,11 +1014,21 @@
static native long SSL_SESSION_get_time(long sslSessionNativePointer);
+ static native long SSL_get_time(long sslNativePointer);
+
+ static native long SSL_set_timeout(long sslNativePointer, long millis);
+
+ static native long SSL_get_timeout(long sslNativePointer);
+
+ static native long SSL_SESSION_get_timeout(long sslSessionNativePointer);
+
+ static native byte[] SSL_session_id(long sslNativePointer);
+
static native String SSL_SESSION_get_version(long sslSessionNativePointer);
static native String SSL_SESSION_cipher(long sslSessionNativePointer);
- static native String get_SSL_SESSION_tlsext_hostname(long sslSessionNativePointer);
+ static native void SSL_SESSION_up_ref(long sslSessionNativePointer);
static native void SSL_SESSION_free(long sslSessionNativePointer);
@@ -1116,9 +1099,26 @@
* Called when SSL state changes. This could be handshake completion.
*/
void onSSLStateChange(int type, int val);
- }
- static native long ERR_peek_last_error();
+ /**
+ * Called when a new session has been established and may be added to the session cache.
+ * The callee is responsible for incrementing the reference count on the returned session.
+ */
+ void onNewSessionEstablished(long sslSessionNativePtr);
+
+ /**
+ * Called for servers where TLS < 1.3 (TLS 1.3 uses session tickets rather than
+ * application session caches).
+ *
+ * <p/>Looks up the session by ID in the application's session cache. If a valid session
+ * is returned, this callback is responsible for incrementing the reference count (and any
+ * required synchronization).
+ *
+ * @param id the ID of the session to find.
+ * @return the cached session or {@code 0} if no session was found matching the given ID.
+ */
+ long serverSessionRequested(byte[] id);
+ }
static native String SSL_CIPHER_get_kx_name(long cipherAddress);
@@ -1150,10 +1150,6 @@
static native int SSL_pending_written_bytes_in_BIO(long bio);
- static native long SSL_get0_session(long ssl);
-
- static native long SSL_get1_session(long ssl);
-
/**
* Returns the maximum overhead, in bytes, of sealing a record with SSL.
*/
@@ -1256,4 +1252,17 @@
*/
static native void ENGINE_SSL_shutdown(long sslNativePointer, SSLHandshakeCallbacks shc)
throws IOException;
+
+ /**
+ * Used for testing only.
+ */
+ static native int BIO_read(long bioRef, byte[] buffer);
+ static native void BIO_write(long bioRef, byte[] buffer, int offset, int length)
+ throws IOException;
+ static native long ERR_peek_last_error();
+ static native long SSL_clear_mode(long ssl, long mode);
+ static native long SSL_get_mode(long ssl);
+ static native long SSL_get_options(long ssl);
+ static native long SSL_get1_session(long ssl);
+ static native void SSL_renegotiate(long sslNativePointer) throws SSLException;
}
diff --git a/common/src/main/java/org/conscrypt/NativeRef.java b/common/src/main/java/org/conscrypt/NativeRef.java
index ccc7cc0..62e9bd6 100644
--- a/common/src/main/java/org/conscrypt/NativeRef.java
+++ b/common/src/main/java/org/conscrypt/NativeRef.java
@@ -23,12 +23,12 @@
abstract class NativeRef {
final long context;
- NativeRef(long ctx) {
- if (ctx == 0) {
- throw new NullPointerException("ctx == 0");
+ NativeRef(long context) {
+ if (context == 0) {
+ throw new NullPointerException("context == 0");
}
- this.context = ctx;
+ this.context = context;
}
@Override
@@ -45,108 +45,104 @@
return (int) context;
}
- static class EC_GROUP extends NativeRef {
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ if (context != 0) {
+ doFree(context);
+ }
+ } finally {
+ super.finalize();
+ }
+ }
+
+ abstract void doFree(long context);
+
+ static final class EC_GROUP extends NativeRef {
EC_GROUP(long ctx) {
super(ctx);
}
@Override
- protected void finalize() throws Throwable {
- try {
- NativeCrypto.EC_GROUP_clear_free(context);
- } finally {
- super.finalize();
- }
+ void doFree(long context) {
+ NativeCrypto.EC_GROUP_clear_free(context);
}
}
- static class EC_POINT extends NativeRef {
- EC_POINT(long ctx) {
- super(ctx);
+ static final class EC_POINT extends NativeRef {
+ EC_POINT(long nativePointer) {
+ super(nativePointer);
}
@Override
- protected void finalize() throws Throwable {
- try {
- NativeCrypto.EC_POINT_clear_free(context);
- } finally {
- super.finalize();
- }
+ void doFree(long context) {
+ NativeCrypto.EC_POINT_clear_free(context);
}
}
- static class EVP_CIPHER_CTX extends NativeRef {
- EVP_CIPHER_CTX(long ctx) {
- super(ctx);
+ static final class EVP_CIPHER_CTX extends NativeRef {
+ EVP_CIPHER_CTX(long nativePointer) {
+ super(nativePointer);
}
@Override
- protected void finalize() throws Throwable {
- try {
- NativeCrypto.EVP_CIPHER_CTX_free(context);
- } finally {
- super.finalize();
- }
+ void doFree(long context) {
+ NativeCrypto.EVP_CIPHER_CTX_free(context);
}
}
- static class EVP_MD_CTX extends NativeRef {
- EVP_MD_CTX(long ctx) {
- super(ctx);
+ static final class EVP_MD_CTX extends NativeRef {
+ EVP_MD_CTX(long nativePointer) {
+ super(nativePointer);
}
@Override
- protected void finalize() throws Throwable {
- try {
- NativeCrypto.EVP_MD_CTX_destroy(context);
- } finally {
- super.finalize();
- }
+ void doFree(long context) {
+ NativeCrypto.EVP_MD_CTX_destroy(context);
}
}
- static class EVP_PKEY extends NativeRef {
- EVP_PKEY(long ctx) {
- super(ctx);
+ static final class EVP_PKEY extends NativeRef {
+ EVP_PKEY(long nativePointer) {
+ super(nativePointer);
}
@Override
- protected void finalize() throws Throwable {
- try {
- NativeCrypto.EVP_PKEY_free(context);
- } finally {
- super.finalize();
- }
+ void doFree(long context) {
+ NativeCrypto.EVP_PKEY_free(context);
}
}
- static class EVP_PKEY_CTX extends NativeRef {
- EVP_PKEY_CTX(long ctx) {
- super(ctx);
+ static final class EVP_PKEY_CTX extends NativeRef {
+ EVP_PKEY_CTX(long nativePointer) {
+ super(nativePointer);
}
@Override
- protected void finalize() throws Throwable {
- try {
- NativeCrypto.EVP_PKEY_CTX_free(context);
- } finally {
- super.finalize();
- }
+ void doFree(long context) {
+ NativeCrypto.EVP_PKEY_CTX_free(context);
}
}
- static class HMAC_CTX extends NativeRef {
- HMAC_CTX(long ctx) {
- super(ctx);
+ static final class HMAC_CTX extends NativeRef {
+ HMAC_CTX(long nativePointer) {
+ super(nativePointer);
}
@Override
- protected void finalize() throws Throwable {
- try {
- NativeCrypto.HMAC_CTX_free(context);
- } finally {
- super.finalize();
- }
+ void doFree(long context) {
+ NativeCrypto.HMAC_CTX_free(context);
+ }
+ }
+
+ static final class SSL_SESSION extends NativeRef {
+ SSL_SESSION(long nativePointer) {
+ super(nativePointer);
+ }
+
+ @Override
+ void doFree(long context) {
+ NativeCrypto.SSL_SESSION_free(context);
}
}
}
diff --git a/common/src/main/java/org/conscrypt/OpenSSLContextImpl.java b/common/src/main/java/org/conscrypt/OpenSSLContextImpl.java
index c1865a1..143f481 100644
--- a/common/src/main/java/org/conscrypt/OpenSSLContextImpl.java
+++ b/common/src/main/java/org/conscrypt/OpenSSLContextImpl.java
@@ -30,11 +30,12 @@
/**
* OpenSSL-backed SSLContext service provider interface.
*
+ * <p>Public to allow contruction via the provider framework.
+ *
* @hide
*/
@Internal
public abstract class OpenSSLContextImpl extends SSLContextSpi {
-
/**
* The default SSLContextImpl for use with
* SSLContext.getInstance("Default"). Protected by the
@@ -97,8 +98,8 @@
@Override
public void engineInit(KeyManager[] kms, TrustManager[] tms, SecureRandom sr)
throws KeyManagementException {
- sslParameters = new SSLParametersImpl(kms, tms, sr, clientSessionContext,
- serverSessionContext, algorithms);
+ sslParameters = new SSLParametersImpl(
+ kms, tms, sr, clientSessionContext, serverSessionContext, algorithms);
}
@Override
@@ -147,18 +148,27 @@
return clientSessionContext;
}
+ /**
+ * Public to allow construction via the provider framework.
+ */
public static final class TLSv12 extends OpenSSLContextImpl {
public TLSv12() {
super(NativeCrypto.TLSV12_PROTOCOLS);
}
}
+ /**
+ * Public to allow construction via the provider framework.
+ */
public static final class TLSv11 extends OpenSSLContextImpl {
public TLSv11() {
super(NativeCrypto.TLSV11_PROTOCOLS);
}
}
+ /**
+ * Public to allow construction via the provider framework.
+ */
public static final class TLSv1 extends OpenSSLContextImpl {
public TLSv1() {
super(NativeCrypto.TLSV1_PROTOCOLS);
diff --git a/common/src/main/java/org/conscrypt/OpenSSLSessionImpl.java b/common/src/main/java/org/conscrypt/OpenSSLSessionImpl.java
deleted file mode 100644
index d94252b..0000000
--- a/common/src/main/java/org/conscrypt/OpenSSLSessionImpl.java
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.conscrypt;
-
-import java.io.IOException;
-import java.security.cert.X509Certificate;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import javax.net.ssl.SSLPeerUnverifiedException;
-import javax.net.ssl.SSLSessionBindingEvent;
-import javax.net.ssl.SSLSessionBindingListener;
-
-/**
- * Implementation of the class OpenSSLSessionImpl
- * based on BoringSSL.
- */
-class OpenSSLSessionImpl extends AbstractOpenSSLSession {
- private long creationTime = 0;
- long lastAccessedTime = 0;
- final X509Certificate[] localCertificates;
- final X509Certificate[] peerCertificates;
-
- private final Map<String, Object> values = new HashMap<String, Object>();
- private byte[] peerCertificateOcspData;
- private byte[] peerTlsSctData;
- long sslSessionNativePointer;
- private String peerHost;
- private int peerPort = -1;
- private String cipherSuite;
- private String protocol;
- private byte[] id;
-
- /**
- * Class constructor creates an SSL session context given the appropriate
- * SSL parameters.
- */
- OpenSSLSessionImpl(long sslSessionNativePointer, X509Certificate[] localCertificates,
- X509Certificate[] peerCertificates, byte[] peerCertificateOcspData,
- byte[] peerTlsSctData, String peerHost, int peerPort,
- AbstractSessionContext sessionContext) {
- super(sessionContext);
- this.sslSessionNativePointer = sslSessionNativePointer;
- this.localCertificates = localCertificates;
- this.peerCertificates = peerCertificates;
- this.peerCertificateOcspData = peerCertificateOcspData;
- this.peerTlsSctData = peerTlsSctData;
- this.peerHost = peerHost;
- this.peerPort = peerPort;
- }
-
- /**
- * Constructs a session from a byte[] containing an SSL session serialized with DER encoding.
- * This allows loading of a previously saved OpenSSLSessionImpl.
- *
- * @throws IOException if the serialized session data can not be parsed
- */
- OpenSSLSessionImpl(byte[] derData, String peerHost, int peerPort,
- X509Certificate[] peerCertificates, byte[] peerCertificateOcspData,
- byte[] peerTlsSctData, AbstractSessionContext sessionContext)
- throws IOException {
- this(NativeCrypto.d2i_SSL_SESSION(derData), null, peerCertificates,
- peerCertificateOcspData, peerTlsSctData, peerHost, peerPort, sessionContext);
- }
-
- /**
- * Gets the identifier of the actual SSL session
- * @return array of sessions' identifiers.
- */
- @Override
- public byte[] getId() {
- if (id == null) {
- resetId();
- }
- return id;
- }
-
- /**
- * Reset the id field to the current value found in the native
- * SSL_SESSION. It can change during the lifetime of the session
- * because while a session is created during initial handshake,
- * with handshake_cutthrough, the SSL_do_handshake may return
- * before we have read the session ticket from the server side and
- * therefore have computed no id based on the SHA of the ticket.
- */
- @Override
- void resetId() {
- id = NativeCrypto.SSL_SESSION_session_id(sslSessionNativePointer);
- }
-
- /**
- * Get the session object in DER format. This allows saving the session
- * data or sharing it with other processes.
- */
- public byte[] getEncoded() {
- return NativeCrypto.i2d_SSL_SESSION(sslSessionNativePointer);
- }
-
- /**
- * Gets the creation time of the SSL session.
- * @return the session's creation time in milliseconds since the epoch
- */
- @Override
- public long getCreationTime() {
- if (creationTime == 0) {
- creationTime = NativeCrypto.SSL_SESSION_get_time(sslSessionNativePointer);
- }
- return creationTime;
- }
-
- /**
- * Returns the last time this concrete SSL session was accessed. Accessing
- * here is to mean that a new connection with the same SSL context data was
- * established.
- *
- * @return the session's last access time in milliseconds since the epoch
- */
- @Override
- public long getLastAccessedTime() {
- return (lastAccessedTime == 0) ? getCreationTime() : lastAccessedTime;
- }
-
- @Override
- public void setLastAccessedTime(long accessTimeMillis) {
- lastAccessedTime = accessTimeMillis;
- }
-
- @Override
- protected X509Certificate[] getX509LocalCertificates() {
- return localCertificates;
- }
-
- @Override
- protected X509Certificate[] getX509PeerCertificates() throws SSLPeerUnverifiedException {
- if (peerCertificates == null || peerCertificates.length == 0) {
- throw new SSLPeerUnverifiedException("No peer certificates");
- }
- return peerCertificates;
- }
-
- /**
- * The peer's host name used in this SSL session is returned. It is the host
- * name of the client for the server; and that of the server for the client.
- * It is not a reliable way to get a fully qualified host name: it is mainly
- * used internally to implement links for a temporary cache of SSL sessions.
- *
- * @return the host name of the peer, or {@code null} if no information is
- * available.
- */
- @Override
- public String getPeerHost() {
- return peerHost;
- }
-
- /**
- * Returns the peer's port number for the actual SSL session. It is the port
- * number of the client for the server; and that of the server for the
- * client. It is not a reliable way to get a peer's port number: it is
- * mainly used internally to implement links for a temporary cache of SSL
- * sessions.
- *
- * @return the peer's port number, or {@code -1} if no one is available.
- */
- @Override
- public int getPeerPort() {
- return peerPort;
- }
-
- /**
- * Returns a string identifier of the crypto tools used in the actual SSL
- * session. For example AES_256_WITH_MD5.
- */
- @Override
- public String getCipherSuite() {
- if (cipherSuite == null) {
- String name = NativeCrypto.SSL_SESSION_cipher(sslSessionNativePointer);
- cipherSuite = NativeCrypto.OPENSSL_TO_STANDARD_CIPHER_SUITES.get(name);
- if (cipherSuite == null) {
- cipherSuite = name;
- }
- }
- return cipherSuite;
- }
-
- /**
- * Returns the standard version name of the SSL protocol used in all
- * connections pertaining to this SSL session.
- */
- @Override
- public String getProtocol() {
- if (protocol == null) {
- protocol = NativeCrypto.SSL_SESSION_get_version(sslSessionNativePointer);
- }
- return protocol;
- }
-
- /**
- * Returns the object which is bound to the the input parameter name.
- * This name is a sort of link to the data of the SSL session's application
- * layer, if any exists.
- *
- * @param name the name of the binding to find.
- * @return the value bound to that name, or null if the binding does not
- * exist.
- * @throws IllegalArgumentException if the argument is null.
- */
- @Override
- public Object getValue(String name) {
- if (name == null) {
- throw new IllegalArgumentException("name == null");
- }
- return values.get(name);
- }
-
- /**
- * Returns an array with the names (sort of links) of all the data
- * objects of the application layer bound into the SSL session.
- *
- * @return a non-null (possibly empty) array of names of the data objects
- * bound to this SSL session.
- */
- @Override
- public String[] getValueNames() {
- return values.keySet().toArray(new String[values.size()]);
- }
-
- /**
- * A link (name) with the specified value object of the SSL session's
- * application layer data is created or replaced. If the new (or existing)
- * value object implements the <code>SSLSessionBindingListener</code>
- * interface, that object will be notified in due course.
- *
- * @param name the name of the link (no null are
- * accepted!)
- * @param value data object that shall be bound to
- * name.
- * @throws IllegalArgumentException if one or both argument(s) is null.
- */
- @Override
- public void putValue(String name, Object value) {
- if (name == null || value == null) {
- throw new IllegalArgumentException("name == null || value == null");
- }
- Object old = values.put(name, value);
- if (value instanceof SSLSessionBindingListener) {
- ((SSLSessionBindingListener) value)
- .valueBound(new SSLSessionBindingEvent(this, name));
- }
- if (old instanceof SSLSessionBindingListener) {
- ((SSLSessionBindingListener) old)
- .valueUnbound(new SSLSessionBindingEvent(this, name));
- }
- }
-
- /**
- * Removes a link (name) with the specified value object of the SSL
- * session's application layer data.
- *
- * <p>If the value object implements the <code>SSLSessionBindingListener</code>
- * interface, the object will receive a <code>valueUnbound</code> notification.
- *
- * @param name the name of the link (no null are
- * accepted!)
- * @throws IllegalArgumentException if the argument is null.
- */
- @Override
- public void removeValue(String name) {
- if (name == null) {
- throw new IllegalArgumentException("name == null");
- }
- Object old = values.remove(name);
- if (old instanceof SSLSessionBindingListener) {
- SSLSessionBindingListener listener = (SSLSessionBindingListener) old;
- listener.valueUnbound(new SSLSessionBindingEvent(this, name));
- }
- }
-
- /**
- * Returns the name requested by the SNI extension.
- */
- @Override
- public String getRequestedServerName() {
- return NativeCrypto.get_SSL_SESSION_tlsext_hostname(sslSessionNativePointer);
- }
-
- /**
- * Returns the OCSP stapled response.
- */
- @Override
- public List<byte[]> getStatusResponses() {
- if (peerCertificateOcspData == null) {
- return Collections.<byte[]>emptyList();
- }
-
- return Collections.singletonList(peerCertificateOcspData.clone());
- }
-
- @Override
- public byte[] getTlsSctData() {
- if (peerTlsSctData == null) {
- return null;
- }
- return peerTlsSctData.clone();
- }
-
- @Override
- protected void finalize() throws Throwable {
- try {
- // The constructor can throw an exception if this object is constructed from invalid
- // saved session data.
- if (sslSessionNativePointer != 0) {
- NativeCrypto.SSL_SESSION_free(sslSessionNativePointer);
- }
- } finally {
- super.finalize();
- }
- }
-}
diff --git a/common/src/main/java/org/conscrypt/SSLNullSession.java b/common/src/main/java/org/conscrypt/SSLNullSession.java
index 88a0a9c..93650d6 100644
--- a/common/src/main/java/org/conscrypt/SSLNullSession.java
+++ b/common/src/main/java/org/conscrypt/SSLNullSession.java
@@ -28,6 +28,7 @@
* SSLSocket#getSession()} before {@link SSLSocket#startHandshake()} is called.
*/
final class SSLNullSession implements SSLSession, Cloneable {
+ static final String INVALID_CIPHER = "SSL_NULL_WITH_NULL_NULL";
/*
* Holds default instances so class preloading doesn't create an instance of
@@ -46,7 +47,11 @@
return DefaultHolder.NULL_SESSION;
}
- SSLNullSession() {
+ static boolean isNullSession(SSLSession session) {
+ return session == DefaultHolder.NULL_SESSION;
+ }
+
+ private SSLNullSession() {
creationTime = System.currentTimeMillis();
lastAccessedTime = creationTime;
}
@@ -58,7 +63,7 @@
@Override
public String getCipherSuite() {
- return "SSL_NULL_WITH_NULL_NULL";
+ return INVALID_CIPHER;
}
@Override
diff --git a/common/src/main/java/org/conscrypt/SSLParametersImpl.java b/common/src/main/java/org/conscrypt/SSLParametersImpl.java
index 939401e..33e4c78 100644
--- a/common/src/main/java/org/conscrypt/SSLParametersImpl.java
+++ b/common/src/main/java/org/conscrypt/SSLParametersImpl.java
@@ -17,29 +17,17 @@
package org.conscrypt;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.security.InvalidKeyException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
-import java.security.cert.CertificateEncodingException;
-import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
import javax.crypto.SecretKey;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLHandshakeException;
-import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509ExtendedKeyManager;
@@ -61,8 +49,6 @@
private static volatile X509KeyManager defaultX509KeyManager;
// default source of X.509 certificate based authentication trust decisions
private static volatile X509TrustManager defaultX509TrustManager;
- // default source of random numbers
- private static volatile SecureRandom defaultSecureRandom;
// default SSL parameters
private static volatile SSLParametersImpl defaultParameters;
@@ -83,11 +69,11 @@
private SecureRandom secureRandom;
// protocols enabled for SSL connection
- private String[] enabledProtocols;
+ String[] enabledProtocols;
// set to indicate when obsolete protocols are filtered
- private boolean isEnabledProtocolsFiltered;
+ boolean isEnabledProtocolsFiltered;
// cipher suites enabled for SSL connection
- private String[] enabledCipherSuites;
+ String[] enabledCipherSuites;
// if the peer with this parameters tuned to work in client mode
private boolean client_mode = true;
@@ -106,11 +92,11 @@
private boolean ctVerificationEnabled;
// server-side only. SCT and OCSP data to send to clients which request it
- private byte[] sctExtension;
- private byte[] ocspResponse;
+ byte[] sctExtension;
+ byte[] ocspResponse;
- private byte[] alpnProtocols;
- private boolean useSessionTickets;
+ byte[] alpnProtocols;
+ boolean useSessionTickets;
private Boolean useSni;
/**
@@ -189,13 +175,6 @@
}
/**
- * @return server session context
- */
- ServerSessionContext getServerSessionContext() {
- return serverSessionContext;
- }
-
- /**
* @return client session context
*/
ClientSessionContext getClientSessionContext() {
@@ -225,29 +204,6 @@
}
/**
- * @return secure random
- */
- SecureRandom getSecureRandom() {
- if (secureRandom != null) {
- return secureRandom;
- }
- SecureRandom result = defaultSecureRandom;
- if (result == null) {
- // single-check idiom
- defaultSecureRandom = result = new SecureRandom();
- }
- secureRandom = result;
- return secureRandom;
- }
-
- /**
- * @return the secure random member reference, even it is null
- */
- SecureRandom getSecureRandomMember() {
- return secureRandom;
- }
-
- /**
* @return the names of enabled cipher suites
*/
String[] getEnabledCipherSuites() {
@@ -308,6 +264,10 @@
this.alpnProtocols = alpnProtocols;
}
+ byte[] getAlpnProtocols() {
+ return alpnProtocols;
+ }
+
/**
* Tunes the peer holding this parameters to work in client mode.
* @param mode if the peer is configured to work in client mode
@@ -383,7 +343,7 @@
* extension Server Name Indication (SNI).
*/
void setUseSni(boolean flag) {
- useSni = Boolean.valueOf(flag);
+ useSni = flag;
}
/**
@@ -391,17 +351,26 @@
* extension Server Name Indication (SNI).
*/
boolean getUseSni() {
- return useSni != null ? useSni.booleanValue() : isSniEnabledByDefault();
+ return useSni != null ? useSni : isSniEnabledByDefault();
}
+ /**
+ * For testing only.
+ */
void setCTVerificationEnabled(boolean enabled) {
ctVerificationEnabled = enabled;
}
+ /**
+ * For testing only.
+ */
void setSCTExtension(byte[] extension) {
sctExtension = extension;
}
+ /**
+ * For testing only.
+ */
void setOCSPResponse(byte[] response) {
ocspResponse = response;
}
@@ -410,111 +379,6 @@
return ocspResponse;
}
- static byte[][] encodeIssuerX509Principals(X509Certificate[] certificates)
- throws CertificateEncodingException {
- byte[][] principalBytes = new byte[certificates.length][];
- for (int i = 0; i < certificates.length; i++) {
- principalBytes[i] = certificates[i].getIssuerX500Principal().getEncoded();
- }
- return principalBytes;
- }
-
- AbstractOpenSSLSession getSessionToReuse(long sslNativePointer, String hostname, int port)
- throws SSLException {
- OpenSSLSessionImpl sessionToReuse = null;
-
- if (client_mode) {
- // look for client session to reuse
- SSLSession cachedSession = getCachedClientSession(clientSessionContext, hostname, port);
- if (cachedSession != null) {
- // The native pointer is used here, so we have to make sure it's not a delegate
- // SSLSession class.
- cachedSession = Platform.unwrapSSLSession(cachedSession);
-
- if (cachedSession instanceof OpenSSLSessionImpl) {
- sessionToReuse = (OpenSSLSessionImpl) cachedSession;
- NativeCrypto.SSL_set_session(sslNativePointer,
- sessionToReuse.sslSessionNativePointer);
- }
- }
- }
-
- return sessionToReuse;
- }
-
- void setTlsChannelId(long sslNativePointer, OpenSSLKey channelIdPrivateKey)
- throws SSLHandshakeException, SSLException {
- // TLS Channel ID
- if (channelIdEnabled) {
- if (client_mode) {
- // Client-side TLS Channel ID
- if (channelIdPrivateKey == null) {
- throw new SSLHandshakeException("Invalid TLS channel ID key specified");
- }
- NativeCrypto.SSL_set1_tls_channel_id(sslNativePointer,
- channelIdPrivateKey.getNativeRef());
- } else {
- // Server-side TLS Channel ID
- NativeCrypto.SSL_enable_tls_channel_id(sslNativePointer);
- }
- }
- }
-
- void setCertificate(long sslNativePointer, String alias) throws CertificateEncodingException,
- SSLException {
- if (alias == null) {
- return;
- }
- X509KeyManager keyManager = getX509KeyManager();
- if (keyManager == null) {
- return;
- }
- PrivateKey privateKey = keyManager.getPrivateKey(alias);
- if (privateKey == null) {
- return;
- }
- X509Certificate[] certificates = keyManager.getCertificateChain(alias);
- if (certificates == null) {
- return;
- }
- PublicKey publicKey = (certificates.length > 0) ? certificates[0].getPublicKey() : null;
-
- /*
- * Make sure we keep a reference to the OpenSSLX509Certificate by using
- * this array. Otherwise, if they're not OpenSSLX509Certificate
- * instances originally, they may be garbage collected before we
- * complete our JNI calls.
- */
- OpenSSLX509Certificate[] openSslCerts = new OpenSSLX509Certificate[certificates.length];
- long[] x509refs = new long[certificates.length];
- for (int i = 0; i < certificates.length; i++) {
- OpenSSLX509Certificate openSslCert = OpenSSLX509Certificate
- .fromCertificate(certificates[i]);
- openSslCerts[i] = openSslCert;
- x509refs[i] = openSslCert.getContext();
- }
-
- // Note that OpenSSL says to use SSL_use_certificate before
- // SSL_use_PrivateKey.
- NativeCrypto.SSL_use_certificate(sslNativePointer, x509refs);
-
- final OpenSSLKey key;
- try {
- key = OpenSSLKey.fromPrivateKeyForTLSStackOnly(privateKey, publicKey);
- NativeCrypto.SSL_use_PrivateKey(sslNativePointer, key.getNativeRef());
- } catch (InvalidKeyException e) {
- throw new SSLException(e);
- }
-
- // We may not have access to all the information to check the private key
- // if it's a wrapped platform key, so skip this check.
- if (!key.isWrapped()) {
- // Makes sure the set PrivateKey and X509Certificate refer to the same
- // key by comparing the public values.
- NativeCrypto.SSL_check_private_key(sslNativePointer);
- }
- }
-
/**
* This filters {@code obsoleteProtocol} from the list of {@code protocols}
* down to help with app compatibility.
@@ -535,95 +399,6 @@
private static final String[] EMPTY_STRING_ARRAY = new String[0];
- void setSSLParameters(long sslNativePointer, AliasChooser chooser, PSKCallbacks pskCallbacks,
- String sniHostname) throws SSLException, IOException {
- if (enabledProtocols.length == 0 && isEnabledProtocolsFiltered) {
- throw new SSLHandshakeException("No enabled protocols; "
- + NativeCrypto.OBSOLETE_PROTOCOL_SSLV3
- + " is no longer supported and was filtered from the list");
- }
- NativeCrypto.SSL_configure_alpn(sslNativePointer, client_mode, alpnProtocols);
- NativeCrypto.setEnabledProtocols(sslNativePointer, enabledProtocols);
- NativeCrypto.setEnabledCipherSuites(sslNativePointer, enabledCipherSuites);
-
- // setup server certificates and private keys.
- // clients will receive a call back to request certificates.
- if (!client_mode) {
- Set<String> keyTypes = new HashSet<String>();
- for (long sslCipherNativePointer : NativeCrypto.SSL_get_ciphers(sslNativePointer)) {
- String keyType = getServerX509KeyType(sslCipherNativePointer);
- if (keyType != null) {
- keyTypes.add(keyType);
- }
- }
- X509KeyManager keyManager = getX509KeyManager();
- if (keyManager != null) {
- for (String keyType : keyTypes) {
- try {
- setCertificate(sslNativePointer,
- chooser.chooseServerAlias(x509KeyManager, keyType));
- } catch (CertificateEncodingException e) {
- throw new IOException(e);
- }
- }
- }
-
- NativeCrypto.SSL_set_options(sslNativePointer,
- NativeConstants.SSL_OP_CIPHER_SERVER_PREFERENCE);
-
- if (sctExtension != null) {
- NativeCrypto.SSL_set_signed_cert_timestamp_list(sslNativePointer, sctExtension);
- }
-
- if (ocspResponse != null) {
- NativeCrypto.SSL_set_ocsp_response(sslNativePointer, ocspResponse);
- }
- }
-
- enablePSKKeyManagerIfRequested(sslNativePointer, pskCallbacks);
-
- if (useSessionTickets) {
- NativeCrypto.SSL_clear_options(sslNativePointer, NativeConstants.SSL_OP_NO_TICKET);
- }
- if (getUseSni() && AddressUtils.isValidSniHostname(sniHostname)) {
- NativeCrypto.SSL_set_tlsext_host_name(sslNativePointer, sniHostname);
- }
-
- // BEAST attack mitigation (1/n-1 record splitting for CBC cipher suites
- // with TLSv1 and SSLv3).
- NativeCrypto.SSL_set_mode(sslNativePointer, NativeConstants.SSL_MODE_CBC_RECORD_SPLITTING);
-
- boolean enableSessionCreation = getEnableSessionCreation();
- if (!enableSessionCreation) {
- NativeCrypto.SSL_set_session_creation_enabled(sslNativePointer, enableSessionCreation);
- }
- }
-
- @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package
- private void enablePSKKeyManagerIfRequested(long sslNativePointer, PSKCallbacks pskCallbacks)
- throws SSLException {
- // Enable Pre-Shared Key (PSK) key exchange if requested
- PSKKeyManager pskKeyManager = getPSKKeyManager();
- if (pskKeyManager != null) {
- boolean pskEnabled = false;
- for (String enabledCipherSuite : enabledCipherSuites) {
- if ((enabledCipherSuite != null) && (enabledCipherSuite.contains("PSK"))) {
- pskEnabled = true;
- break;
- }
- }
- if (pskEnabled) {
- if (client_mode) {
- NativeCrypto.set_SSL_psk_client_callback_enabled(sslNativePointer, true);
- } else {
- NativeCrypto.set_SSL_psk_server_callback_enabled(sslNativePointer, true);
- String identityHint = pskCallbacks.chooseServerPSKIdentityHint(pskKeyManager);
- NativeCrypto.SSL_use_psk_identity_hint(sslNativePointer, identityHint);
- }
- }
- }
- }
-
/**
* Returns whether Server Name Indication (SNI) is enabled by default for
* sockets. For more information on SNI, see RFC 6066 section 3.
@@ -644,202 +419,6 @@
}
}
- void setCertificateValidation(long sslNativePointer) throws IOException {
- // setup peer certificate verification
- if (!client_mode) {
- // needing client auth takes priority...
- boolean certRequested;
- if (getNeedClientAuth()) {
- NativeCrypto.SSL_set_verify(sslNativePointer,
- NativeCrypto.SSL_VERIFY_PEER
- | NativeCrypto.SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
- certRequested = true;
- // ... over just wanting it...
- } else if (getWantClientAuth()) {
- NativeCrypto.SSL_set_verify(sslNativePointer, NativeCrypto.SSL_VERIFY_PEER);
- certRequested = true;
- // ... and we must disable verification if we don't want client auth.
- } else {
- NativeCrypto.SSL_set_verify(sslNativePointer, NativeCrypto.SSL_VERIFY_NONE);
- certRequested = false;
- }
-
- if (certRequested) {
- X509TrustManager trustManager = getX509TrustManager();
- X509Certificate[] issuers = trustManager.getAcceptedIssuers();
- if (issuers != null && issuers.length != 0) {
- byte[][] issuersBytes;
- try {
- issuersBytes = encodeIssuerX509Principals(issuers);
- } catch (CertificateEncodingException e) {
- throw new IOException("Problem encoding principals", e);
- }
- NativeCrypto.SSL_set_client_CA_list(sslNativePointer, issuersBytes);
- }
- }
- }
- }
-
- AbstractOpenSSLSession setupSession(long sslSessionNativePointer, long sslNativePointer,
- final AbstractOpenSSLSession sessionToReuse, String hostname, int port,
- boolean handshakeCompleted) throws IOException {
- AbstractOpenSSLSession sslSession = null;
- if (sessionToReuse != null && NativeCrypto.SSL_session_reused(sslNativePointer)) {
- sslSession = sessionToReuse;
- sslSession.setLastAccessedTime(System.currentTimeMillis());
- NativeCrypto.SSL_SESSION_free(sslSessionNativePointer);
- } else {
- if (!getEnableSessionCreation()) {
- // Should have been prevented by
- // NativeCrypto.SSL_set_session_creation_enabled
- throw new IllegalStateException("SSL Session may not be created");
- }
- X509Certificate[] localCertificates = OpenSSLX509Certificate.createCertChain(
- NativeCrypto.SSL_get_certificate(sslNativePointer));
- X509Certificate[] peerCertificates = OpenSSLX509Certificate.createCertChain(
- NativeCrypto.SSL_get_peer_cert_chain(sslNativePointer));
- byte[] ocspData = NativeCrypto.SSL_get_ocsp_response(sslNativePointer);
- byte[] tlsSctData = NativeCrypto.SSL_get_signed_cert_timestamp_list(sslNativePointer);
- sslSession = new OpenSSLSessionImpl(sslSessionNativePointer, localCertificates,
- peerCertificates, ocspData, tlsSctData, hostname, port, getSessionContext());
- // if not, putSession later in handshakeCompleted() callback
- if (handshakeCompleted) {
- getSessionContext().putSession(sslSession);
- }
- }
- return sslSession;
- }
-
- void chooseClientCertificate(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals,
- long sslNativePointer, AliasChooser chooser) throws SSLException,
- CertificateEncodingException {
- Set<String> keyTypesSet = getSupportedClientKeyTypes(keyTypeBytes);
- String[] keyTypes = keyTypesSet.toArray(new String[keyTypesSet.size()]);
-
- X500Principal[] issuers;
- if (asn1DerEncodedPrincipals == null) {
- issuers = null;
- } else {
- issuers = new X500Principal[asn1DerEncodedPrincipals.length];
- for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) {
- issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]);
- }
- }
- X509KeyManager keyManager = getX509KeyManager();
- String alias = (keyManager != null) ? chooser.chooseClientAlias(keyManager, issuers,
- keyTypes) : null;
- setCertificate(sslNativePointer, alias);
- }
-
- /**
- * @see NativeCrypto.SSLHandshakeCallbacks#clientPSKKeyRequested(String, byte[], byte[])
- */
- @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package
- int clientPSKKeyRequested(
- String identityHint, byte[] identityBytesOut, byte[] key, PSKCallbacks pskCallbacks) {
- PSKKeyManager pskKeyManager = getPSKKeyManager();
- if (pskKeyManager == null) {
- return 0;
- }
-
- String identity = pskCallbacks.chooseClientPSKIdentity(pskKeyManager, identityHint);
- // Store identity in NULL-terminated modified UTF-8 representation into ientityBytesOut
- byte[] identityBytes;
- if (identity == null) {
- identity = "";
- identityBytes = EmptyArray.BYTE;
- } else if (identity.isEmpty()) {
- identityBytes = EmptyArray.BYTE;
- } else {
- try {
- identityBytes = identity.getBytes("UTF-8");
- } catch (UnsupportedEncodingException e) {
- throw new RuntimeException("UTF-8 encoding not supported", e);
- }
- }
- if (identityBytes.length + 1 > identityBytesOut.length) {
- // Insufficient space in the output buffer
- return 0;
- }
- if (identityBytes.length > 0) {
- System.arraycopy(identityBytes, 0, identityBytesOut, 0, identityBytes.length);
- }
- identityBytesOut[identityBytes.length] = 0;
-
- SecretKey secretKey = pskCallbacks.getPSKKey(pskKeyManager, identityHint, identity);
- byte[] secretKeyBytes = secretKey.getEncoded();
- if (secretKeyBytes == null) {
- return 0;
- } else if (secretKeyBytes.length > key.length) {
- // Insufficient space in the output buffer
- return 0;
- }
- System.arraycopy(secretKeyBytes, 0, key, 0, secretKeyBytes.length);
- return secretKeyBytes.length;
- }
-
- /**
- * @see NativeCrypto.SSLHandshakeCallbacks#serverPSKKeyRequested(String, String, byte[])
- */
- @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package
- int serverPSKKeyRequested(
- String identityHint, String identity, byte[] key, PSKCallbacks pskCallbacks) {
- PSKKeyManager pskKeyManager = getPSKKeyManager();
- if (pskKeyManager == null) {
- return 0;
- }
- SecretKey secretKey = pskCallbacks.getPSKKey(pskKeyManager, identityHint, identity);
- byte[] secretKeyBytes = secretKey.getEncoded();
- if (secretKeyBytes == null) {
- return 0;
- } else if (secretKeyBytes.length > key.length) {
- return 0;
- }
- System.arraycopy(secretKeyBytes, 0, key, 0, secretKeyBytes.length);
- return secretKeyBytes.length;
- }
-
- /**
- * Gets the suitable session reference from the session cache container.
- */
- SSLSession getCachedClientSession(ClientSessionContext sessionContext, String hostName,
- int port) {
- if (hostName == null) {
- return null;
- }
-
- SSLSession session = sessionContext.getSession(hostName, port);
- if (session == null) {
- return null;
- }
-
- String protocol = session.getProtocol();
- boolean protocolFound = false;
- for (String enabledProtocol : enabledProtocols) {
- if (protocol.equals(enabledProtocol)) {
- protocolFound = true;
- break;
- }
- }
- if (!protocolFound) {
- return null;
- }
-
- String cipherSuite = session.getCipherSuite();
- boolean cipherSuiteFound = false;
- for (String enabledCipherSuite : enabledCipherSuites) {
- if (cipherSuite.equals(enabledCipherSuite)) {
- cipherSuiteFound = true;
- break;
- }
- }
- if (!cipherSuiteFound) {
- return null;
- }
-
- return session;
- }
-
/**
* For abstracting the X509KeyManager calls between
* {@link X509KeyManager#chooseClientAlias(String[], java.security.Principal[], java.net.Socket)}
@@ -1004,93 +583,6 @@
this.useCipherSuitesOrder = useCipherSuitesOrder;
}
- /** Key type: RSA certificate. */
- private static final String KEY_TYPE_RSA = "RSA";
-
- /** Key type: Diffie-Hellman certificate signed by issuer with RSA signature. */
- private static final String KEY_TYPE_DH_RSA = "DH_RSA";
-
- /** Key type: Elliptic Curve certificate. */
- private static final String KEY_TYPE_EC = "EC";
-
- /** Key type: Elliptic Curve certificate signed by issuer with ECDSA signature. */
- private static final String KEY_TYPE_EC_EC = "EC_EC";
-
- /** Key type: Elliptic Curve certificate signed by issuer with RSA signature. */
- private static final String KEY_TYPE_EC_RSA = "EC_RSA";
-
- /**
- * Returns key type constant suitable for calling X509KeyManager.chooseServerAlias or
- * X509ExtendedKeyManager.chooseEngineServerAlias. Returns {@code null} for key exchanges that
- * do not use X.509 for server authentication.
- */
- private static String getServerX509KeyType(long sslCipherNative) throws SSLException {
- String kx_name = NativeCrypto.SSL_CIPHER_get_kx_name(sslCipherNative);
- if (kx_name.equals("RSA") || kx_name.equals("DHE_RSA") || kx_name.equals("ECDHE_RSA")) {
- return KEY_TYPE_RSA;
- } else if (kx_name.equals("ECDHE_ECDSA")) {
- return KEY_TYPE_EC;
- } else if (kx_name.equals("ECDH_RSA")) {
- return KEY_TYPE_EC_RSA;
- } else if (kx_name.equals("ECDH_ECDSA")) {
- return KEY_TYPE_EC_EC;
- } else if (kx_name.equals("DH_RSA")) {
- return KEY_TYPE_DH_RSA;
- } else {
- return null;
- }
- }
-
- /**
- * Similar to getServerKeyType, but returns value given TLS
- * ClientCertificateType byte values from a CertificateRequest
- * message for use with X509KeyManager.chooseClientAlias or
- * X509ExtendedKeyManager.chooseEngineClientAlias.
- * <p>
- * Visible for testing.
- */
- static String getClientKeyType(byte clientCertificateType) {
- // See also http://www.ietf.org/assignments/tls-parameters/tls-parameters.xml
- switch (clientCertificateType) {
- case NativeConstants.TLS_CT_RSA_SIGN:
- return KEY_TYPE_RSA; // RFC rsa_sign
- case NativeConstants.TLS_CT_RSA_FIXED_DH:
- return KEY_TYPE_DH_RSA; // RFC rsa_fixed_dh
- case NativeConstants.TLS_CT_ECDSA_SIGN:
- return KEY_TYPE_EC; // RFC ecdsa_sign
- case NativeConstants.TLS_CT_RSA_FIXED_ECDH:
- return KEY_TYPE_EC_RSA; // RFC rsa_fixed_ecdh
- case NativeConstants.TLS_CT_ECDSA_FIXED_ECDH:
- return KEY_TYPE_EC_EC; // RFC ecdsa_fixed_ecdh
- default:
- return null;
- }
- }
-
- /**
- * Gets the supported key types for client certificates based on the
- * {@code ClientCertificateType} values provided by the server.
- *
- * @param clientCertificateTypes {@code ClientCertificateType} values provided by the server.
- * See https://www.ietf.org/assignments/tls-parameters/tls-parameters.xml.
- * @return supported key types that can be used in {@code X509KeyManager.chooseClientAlias} and
- * {@code X509ExtendedKeyManager.chooseEngineClientAlias}.
- *
- * Visible for testing.
- */
- static Set<String> getSupportedClientKeyTypes(byte[] clientCertificateTypes) {
- Set<String> result = new HashSet<String>(clientCertificateTypes.length);
- for (byte keyTypeCode : clientCertificateTypes) {
- String keyType = getClientKeyType(keyTypeCode);
- if (keyType == null) {
- // Unsupported client key type -- ignore
- continue;
- }
- result.add(keyType);
- }
- return result;
- }
-
private static String[] getDefaultCipherSuites(
boolean x509CipherSuitesNeeded,
boolean pskCipherSuitesNeeded) {
diff --git a/common/src/main/java/org/conscrypt/SSLUtils.java b/common/src/main/java/org/conscrypt/SSLUtils.java
index 74e6cc5..806d0fb 100644
--- a/common/src/main/java/org/conscrypt/SSLUtils.java
+++ b/common/src/main/java/org/conscrypt/SSLUtils.java
@@ -41,8 +41,14 @@
import static org.conscrypt.NativeConstants.SSL3_RT_MAX_PACKET_SIZE;
import java.nio.ByteBuffer;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.HashSet;
+import java.util.Set;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.security.cert.CertificateException;
/**
* Utility methods for SSL packet processing. Copied from the Netty project.
@@ -54,6 +60,35 @@
System.getProperty("org.conscrypt.useEngineSocketByDefault", "false"));
private static final int MAX_PROTOCOL_LENGTH = 255;
+ // TODO(nathanmittler): Should these be in NativeConstants?
+ enum SessionType {
+ /**
+ * Identifies OpenSSL sessions.
+ */
+ OPEN_SSL(1),
+
+ /**
+ * Identifies OpenSSL sessions with OCSP stapled data.
+ */
+ OPEN_SSL_WITH_OCSP(2),
+
+ /**
+ * Identifies OpenSSL sessions with TLS SCT data.
+ */
+ OPEN_SSL_WITH_TLS_SCT(3);
+
+ SessionType(int value) {
+ this.value = value;
+ }
+
+ static final boolean isSupportedType(int type) {
+ return type == OPEN_SSL.value || type == OPEN_SSL_WITH_OCSP.value
+ || type == OPEN_SSL_WITH_TLS_SCT.value;
+ }
+
+ final int value;
+ }
+
/**
* States for SSL engines.
*/
@@ -130,6 +165,135 @@
private static final int MAX_ENCRYPTION_OVERHEAD_DIFF =
Integer.MAX_VALUE - MAX_ENCRYPTION_OVERHEAD_LENGTH;
+ /** Key type: RSA certificate. */
+ private static final String KEY_TYPE_RSA = "RSA";
+
+ /** Key type: Diffie-Hellman certificate signed by issuer with RSA signature. */
+ private static final String KEY_TYPE_DH_RSA = "DH_RSA";
+
+ /** Key type: Elliptic Curve certificate. */
+ private static final String KEY_TYPE_EC = "EC";
+
+ /** Key type: Elliptic Curve certificate signed by issuer with ECDSA signature. */
+ private static final String KEY_TYPE_EC_EC = "EC_EC";
+
+ /** Key type: Elliptic Curve certificate signed by issuer with RSA signature. */
+ private static final String KEY_TYPE_EC_RSA = "EC_RSA";
+
+ /**
+ * Returns key type constant suitable for calling X509KeyManager.chooseServerAlias or
+ * X509ExtendedKeyManager.chooseEngineServerAlias. Returns {@code null} for key exchanges that
+ * do not use X.509 for server authentication.
+ */
+ static String getServerX509KeyType(long sslCipherNative) throws SSLException {
+ String kx_name = NativeCrypto.SSL_CIPHER_get_kx_name(sslCipherNative);
+ if (kx_name.equals("RSA") || kx_name.equals("DHE_RSA") || kx_name.equals("ECDHE_RSA")) {
+ return KEY_TYPE_RSA;
+ } else if (kx_name.equals("ECDHE_ECDSA")) {
+ return KEY_TYPE_EC;
+ } else if (kx_name.equals("ECDH_RSA")) {
+ return KEY_TYPE_EC_RSA;
+ } else if (kx_name.equals("ECDH_ECDSA")) {
+ return KEY_TYPE_EC_EC;
+ } else if (kx_name.equals("DH_RSA")) {
+ return KEY_TYPE_DH_RSA;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Similar to getServerKeyType, but returns value given TLS
+ * ClientCertificateType byte values from a CertificateRequest
+ * message for use with X509KeyManager.chooseClientAlias or
+ * X509ExtendedKeyManager.chooseEngineClientAlias.
+ * <p>
+ * Visible for testing.
+ */
+ static String getClientKeyType(byte clientCertificateType) {
+ // See also http://www.ietf.org/assignments/tls-parameters/tls-parameters.xml
+ switch (clientCertificateType) {
+ case NativeConstants.TLS_CT_RSA_SIGN:
+ return KEY_TYPE_RSA; // RFC rsa_sign
+ case NativeConstants.TLS_CT_RSA_FIXED_DH:
+ return KEY_TYPE_DH_RSA; // RFC rsa_fixed_dh
+ case NativeConstants.TLS_CT_ECDSA_SIGN:
+ return KEY_TYPE_EC; // RFC ecdsa_sign
+ case NativeConstants.TLS_CT_RSA_FIXED_ECDH:
+ return KEY_TYPE_EC_RSA; // RFC rsa_fixed_ecdh
+ case NativeConstants.TLS_CT_ECDSA_FIXED_ECDH:
+ return KEY_TYPE_EC_EC; // RFC ecdsa_fixed_ecdh
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Gets the supported key types for client certificates based on the
+ * {@code ClientCertificateType} values provided by the server.
+ *
+ * @param clientCertificateTypes {@code ClientCertificateType} values provided by the server.
+ * See https://www.ietf.org/assignments/tls-parameters/tls-parameters.xml.
+ * @return supported key types that can be used in {@code X509KeyManager.chooseClientAlias} and
+ * {@code X509ExtendedKeyManager.chooseEngineClientAlias}.
+ *
+ * Visible for testing.
+ */
+ static Set<String> getSupportedClientKeyTypes(byte[] clientCertificateTypes) {
+ Set<String> result = new HashSet<String>(clientCertificateTypes.length);
+ for (byte keyTypeCode : clientCertificateTypes) {
+ String keyType = SSLUtils.getClientKeyType(keyTypeCode);
+ if (keyType == null) {
+ // Unsupported client key type -- ignore
+ continue;
+ }
+ result.add(keyType);
+ }
+ return result;
+ }
+
+ static byte[][] encodeIssuerX509Principals(X509Certificate[] certificates)
+ throws CertificateEncodingException {
+ byte[][] principalBytes = new byte[certificates.length][];
+ for (int i = 0; i < certificates.length; i++) {
+ principalBytes[i] = certificates[i].getIssuerX500Principal().getEncoded();
+ }
+ return principalBytes;
+ }
+
+ static String getCipherSuiteFromName(String name) {
+ String cipherSuite = name;
+ if (name != null) {
+ cipherSuite = NativeCrypto.OPENSSL_TO_STANDARD_CIPHER_SUITES.get(name);
+ }
+ return cipherSuite != null ? cipherSuite : SSLNullSession.INVALID_CIPHER;
+ }
+
+ /**
+ * Converts the peer certificates into a cert chain.
+ */
+ static javax.security.cert.X509Certificate[] toCertificateChain(X509Certificate[] certificates)
+ throws SSLPeerUnverifiedException {
+ try {
+ javax.security.cert.X509Certificate[] chain =
+ new javax.security.cert.X509Certificate[certificates.length];
+
+ for (int i = 0; i < certificates.length; i++) {
+ byte[] encoded = certificates[i].getEncoded();
+ chain[i] = javax.security.cert.X509Certificate.getInstance(encoded);
+ }
+ return chain;
+ } catch (CertificateEncodingException e) {
+ SSLPeerUnverifiedException exception = new SSLPeerUnverifiedException(e.getMessage());
+ exception.initCause(exception);
+ throw exception;
+ } catch (CertificateException e) {
+ SSLPeerUnverifiedException exception = new SSLPeerUnverifiedException(e.getMessage());
+ exception.initCause(exception);
+ throw exception;
+ }
+ }
+
/**
* Calculates the minimum bytes required in the encrypted output buffer for the given number of
* plaintext source bytes.
diff --git a/common/src/main/java/org/conscrypt/ServerSessionContext.java b/common/src/main/java/org/conscrypt/ServerSessionContext.java
index 20fc3ae..dc4cafb 100644
--- a/common/src/main/java/org/conscrypt/ServerSessionContext.java
+++ b/common/src/main/java/org/conscrypt/ServerSessionContext.java
@@ -16,7 +16,7 @@
package org.conscrypt;
-import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLContext;
/**
* Caches server sessions. Indexes by session ID. Users typically look up
@@ -26,10 +26,9 @@
*/
@Internal
public final class ServerSessionContext extends AbstractSessionContext {
-
private SSLServerSessionCache persistentCache;
- public ServerSessionContext() {
+ ServerSessionContext() {
super(100);
// TODO make sure SSL_CTX does not automaticaly clear sessions we want it to cache
@@ -48,30 +47,23 @@
NativeCrypto.SSL_CTX_set_session_id_context(sslCtxNativePointer, new byte[] { ' ' });
}
+ /**
+ * Applications should not use this method. Instead use {@link
+ * Conscrypt.Contexts#setServerSessionCache(SSLContext, SSLServerSessionCache)}.
+ */
public void setPersistentCache(SSLServerSessionCache persistentCache) {
this.persistentCache = persistentCache;
}
@Override
- protected void sessionRemoved(SSLSession session) {}
-
- @Override
- public SSLSession getSession(byte[] sessionId) {
- // First see if AbstractSessionContext can satisfy the request.
- SSLSession cachedSession = super.getSession(sessionId);
- if (cachedSession != null) {
- // This will already have gone through Platform#wrapSSLSession
- return cachedSession;
- }
-
- // Then check the persistent cache.
+ SslSessionWrapper getSessionFromPersistentCache(byte[] sessionId) {
if (persistentCache != null) {
byte[] data = persistentCache.getSessionData(sessionId);
if (data != null) {
- OpenSSLSessionImpl session = toSession(data, null, -1);
+ SslSessionWrapper session = SslSessionWrapper.newInstance(this, data, null, -1);
if (session != null && session.isValid()) {
- super.putSession(session);
- return Platform.wrapSSLSession(session);
+ cacheSession(session);
+ return session;
}
}
}
@@ -80,15 +72,18 @@
}
@Override
- void putSession(SSLSession session) {
- super.putSession(session);
-
- // TODO: In background thread.
+ void onBeforeAddSession(SslSessionWrapper session) {
+ // TODO: Do this in background thread.
if (persistentCache != null) {
- byte[] data = toBytes(session);
+ byte[] data = session.toBytes();
if (data != null) {
- persistentCache.putSessionData(session, data);
+ persistentCache.putSessionData(session.toSSLSession(), data);
}
}
}
+
+ @Override
+ void onBeforeRemoveSession(SslSessionWrapper session) {
+ // Do nothing.
+ }
}
diff --git a/common/src/main/java/org/conscrypt/SslSessionWrapper.java b/common/src/main/java/org/conscrypt/SslSessionWrapper.java
new file mode 100644
index 0000000..497df1c
--- /dev/null
+++ b/common/src/main/java/org/conscrypt/SslSessionWrapper.java
@@ -0,0 +1,472 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License", "www.google.com", 443);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.conscrypt;
+
+import static org.conscrypt.SSLUtils.SessionType.OPEN_SSL_WITH_OCSP;
+import static org.conscrypt.SSLUtils.SessionType.OPEN_SSL_WITH_TLS_SCT;
+import static org.conscrypt.SSLUtils.SessionType.isSupportedType;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.security.Principal;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.util.List;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionContext;
+import javax.security.cert.X509Certificate;
+
+/**
+ * A utility wrapper that abstracts operations on the underlying native SSL_SESSION instance.
+ *
+ * This is abstract only to support mocking for tests.
+ */
+abstract class SslSessionWrapper {
+ /**
+ * Creates a new instance. Since BoringSSL does not provide an API to get access to all
+ * session information via the SSL_SESSION, we get some values (e.g. peer certs) from
+ * the active session instead (i.e. the SSL object).
+ */
+ static SslSessionWrapper newInstance(NativeRef.SSL_SESSION ref, ActiveSession activeSession)
+ throws SSLPeerUnverifiedException {
+ AbstractSessionContext context = (AbstractSessionContext) activeSession.getSessionContext();
+ if (context instanceof ClientSessionContext) {
+ return new Impl(context, ref, activeSession.getPeerHost(),
+ activeSession.getPeerPort(), activeSession.getPeerCertificates(),
+ getOcspResponse(activeSession),
+ activeSession.getPeerSignedCertificateTimestamp());
+ }
+
+ // Server's will be cached by ID and won't have any of the extra fields.
+ return new Impl(context, ref, null, -1, null, null, null);
+ }
+
+ private static byte[] getOcspResponse(ActiveSession activeSession) {
+ List<byte[]> ocspResponseList = activeSession.getStatusResponses();
+ if (ocspResponseList.size() >= 1) {
+ return ocspResponseList.get(0);
+ }
+ return null;
+ }
+
+ /**
+ * Creates a new {@link SslSessionWrapper} instance from the provided serialized bytes, which
+ * were generated by {@link #toBytes()}.
+ *
+ * @return The new instance if successful. If unable to parse the bytes for any reason, returns
+ * {@code null}.
+ */
+ static SslSessionWrapper newInstance(
+ AbstractSessionContext context, byte[] data, String host, int port) {
+ ByteBuffer buf = ByteBuffer.wrap(data);
+ try {
+ int type = buf.getInt();
+ if (!isSupportedType(type)) {
+ throw new IOException("Unexpected type ID: " + type);
+ }
+
+ int length = buf.getInt();
+ checkRemaining(buf, length);
+
+ byte[] sessionData = new byte[length];
+ buf.get(sessionData);
+
+ int count = buf.getInt();
+ checkRemaining(buf, count);
+
+ java.security.cert.X509Certificate[] peerCerts =
+ new java.security.cert.X509Certificate[count];
+ for (int i = 0; i < count; i++) {
+ length = buf.getInt();
+ checkRemaining(buf, length);
+
+ byte[] certData = new byte[length];
+ buf.get(certData);
+ try {
+ peerCerts[i] = OpenSSLX509Certificate.fromX509Der(certData);
+ } catch (Exception e) {
+ throw new IOException("Can not read certificate " + i + "/" + count);
+ }
+ }
+
+ byte[] ocspData = null;
+ if (type >= OPEN_SSL_WITH_OCSP.value) {
+ // We only support one OCSP response now, but in the future
+ // we may support RFC 6961 which has multiple.
+ int countOcspResponses = buf.getInt();
+ checkRemaining(buf, countOcspResponses);
+
+ if (countOcspResponses >= 1) {
+ int ocspLength = buf.getInt();
+ checkRemaining(buf, ocspLength);
+
+ ocspData = new byte[ocspLength];
+ buf.get(ocspData);
+
+ // Skip the rest of the responses.
+ for (int i = 1; i < countOcspResponses; i++) {
+ ocspLength = buf.getInt();
+ checkRemaining(buf, ocspLength);
+ buf.position(buf.position() + ocspLength);
+ }
+ }
+ }
+
+ byte[] tlsSctData = null;
+ if (type == OPEN_SSL_WITH_TLS_SCT.value) {
+ int tlsSctDataLength = buf.getInt();
+ checkRemaining(buf, tlsSctDataLength);
+
+ if (tlsSctDataLength > 0) {
+ tlsSctData = new byte[tlsSctDataLength];
+ buf.get(tlsSctData);
+ }
+ }
+
+ if (buf.remaining() != 0) {
+ log(new AssertionError("Read entire session, but data still remains; rejecting"));
+ return null;
+ }
+
+ NativeRef.SSL_SESSION ref =
+ new NativeRef.SSL_SESSION(NativeCrypto.d2i_SSL_SESSION(sessionData));
+ return new Impl(context, ref, host, port, peerCerts, ocspData, tlsSctData);
+ } catch (IOException e) {
+ log(e);
+ return null;
+ } catch (BufferUnderflowException e) {
+ log(e);
+ return null;
+ }
+ }
+
+ abstract byte[] getId();
+
+ abstract boolean isValid();
+
+ abstract void offerToResume(SslWrapper ssl) throws SSLException;
+
+ abstract String getCipherSuite();
+
+ abstract String getProtocol();
+
+ abstract String getPeerHost();
+
+ abstract int getPeerPort();
+
+ /**
+ * Returns the OCSP stapled response. The returned array is not copied; the caller must
+ * either not modify the returned array or make a copy.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc6066">RFC 6066</a>
+ * @see <a href="https://tools.ietf.org/html/rfc6961">RFC 6961</a>
+ */
+ abstract byte[] getPeerOcspStapledResponse();
+
+ /**
+ * Returns the signed certificate timestamp (SCT) received from the peer. The returned array
+ * is not copied; the caller must either not modify the returned array or make a copy.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc6962">RFC 6962</a>
+ */
+ abstract byte[] getPeerSignedCertificateTimestamp();
+
+ /**
+ * Converts the given session to bytes.
+ *
+ * @return session data as bytes or null if the session can't be converted
+ */
+ abstract byte[] toBytes();
+
+ /**
+ * Converts this object to a {@link SSLSession}. The returned session will support only a
+ * subset of the {@link SSLSession} API.
+ */
+ abstract SSLSession toSSLSession();
+
+ /**
+ * The session wrapper implementation.
+ */
+ private static final class Impl extends SslSessionWrapper {
+ private final NativeRef.SSL_SESSION ref;
+
+ // BoringSSL offers no API to obtain these values directly from the SSL_SESSION.
+ private final AbstractSessionContext context;
+ private final String host;
+ private final int port;
+ private final String protocol;
+ private final String cipherSuite;
+ private final java.security.cert.X509Certificate[] peerCertificates;
+ private final byte[] peerOcspStapledResponse;
+ private final byte[] peerSignedCertificateTimestamp;
+
+ private Impl(AbstractSessionContext context, NativeRef.SSL_SESSION ref, String host,
+ int port, java.security.cert.X509Certificate[] peerCertificates,
+ byte[] peerOcspStapledResponse, byte[] peerSignedCertificateTimestamp) {
+ this.context = context;
+ this.host = host;
+ this.port = port;
+ this.peerCertificates = peerCertificates;
+ this.peerOcspStapledResponse = peerOcspStapledResponse;
+ this.peerSignedCertificateTimestamp = peerSignedCertificateTimestamp;
+ this.protocol = NativeCrypto.SSL_SESSION_get_version(ref.context);
+ this.cipherSuite = SSLUtils.getCipherSuiteFromName(
+ NativeCrypto.SSL_SESSION_cipher(ref.context));
+ this.ref = ref;
+ }
+
+ @Override
+ byte[] getId() {
+ return NativeCrypto.SSL_SESSION_session_id(ref.context);
+ }
+
+ private long getCreationTime() {
+ return NativeCrypto.SSL_SESSION_get_time(ref.context);
+ }
+
+ @Override
+ boolean isValid() {
+ long creationTimeMillis = getCreationTime();
+ // Use the minimum of the timeout from the context and the session.
+ long timeoutMillis =
+ Math.max(0,
+ Math.min(context.getSessionTimeout(),
+ NativeCrypto.SSL_SESSION_get_timeout(ref.context)))
+ * 1000;
+ return (System.currentTimeMillis() - timeoutMillis) < creationTimeMillis;
+ }
+
+ @Override
+ void offerToResume(SslWrapper ssl) throws SSLException {
+ ssl.offerToResumeSession(ref.context);
+ }
+
+ @Override
+ String getCipherSuite() {
+ return cipherSuite;
+ }
+
+ @Override
+ String getProtocol() {
+ return protocol;
+ }
+
+ @Override
+ String getPeerHost() {
+ return host;
+ }
+
+ @Override
+ int getPeerPort() {
+ return port;
+ }
+
+ @Override
+ byte[] getPeerOcspStapledResponse() {
+ return peerOcspStapledResponse;
+ }
+
+ @Override
+ byte[] getPeerSignedCertificateTimestamp() {
+ return peerSignedCertificateTimestamp;
+ }
+
+ @Override
+ byte[] toBytes() {
+ try {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DataOutputStream daos = new DataOutputStream(baos);
+
+ daos.writeInt(OPEN_SSL_WITH_TLS_SCT.value); // session type ID
+
+ // Session data.
+ byte[] data = NativeCrypto.i2d_SSL_SESSION(ref.context);
+ daos.writeInt(data.length);
+ daos.write(data);
+
+ // Certificates.
+ daos.writeInt(peerCertificates.length);
+
+ for (Certificate cert : peerCertificates) {
+ data = cert.getEncoded();
+ daos.writeInt(data.length);
+ daos.write(data);
+ }
+
+ if (peerOcspStapledResponse != null) {
+ daos.writeInt(1);
+ daos.writeInt(peerOcspStapledResponse.length);
+ daos.write(peerOcspStapledResponse);
+ } else {
+ daos.writeInt(0);
+ }
+
+ if (peerSignedCertificateTimestamp != null) {
+ daos.writeInt(peerSignedCertificateTimestamp.length);
+ daos.write(peerSignedCertificateTimestamp);
+ } else {
+ daos.writeInt(0);
+ }
+
+ // TODO: local certificates?
+
+ return baos.toByteArray();
+ } catch (IOException e) {
+ // TODO(nathanmittler): Better error handling?
+ System.err.println("Failed to convert saved SSL Session: " + e.getMessage());
+ return null;
+ } catch (CertificateEncodingException e) {
+ log(e);
+ return null;
+ }
+ }
+
+ @Override
+ SSLSession toSSLSession() {
+ return new SSLSession() {
+ @Override
+ public byte[] getId() {
+ return Impl.this.getId();
+ }
+
+ @Override
+ public String getCipherSuite() {
+ return Impl.this.getCipherSuite();
+ }
+
+ @Override
+ public String getProtocol() {
+ return Impl.this.getProtocol();
+ }
+
+ @Override
+ public String getPeerHost() {
+ return Impl.this.getPeerHost();
+ }
+
+ @Override
+ public int getPeerPort() {
+ return Impl.this.getPeerPort();
+ }
+
+ @Override
+ public long getCreationTime() {
+ return Impl.this.getCreationTime();
+ }
+
+ @Override
+ public boolean isValid() {
+ return Impl.this.isValid();
+ }
+
+ // UNSUPPORTED OPERATIONS
+
+ @Override
+ public SSLSessionContext getSessionContext() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long getLastAccessedTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void invalidate() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void putValue(String s, Object o) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object getValue(String s) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void removeValue(String s) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String[] getValueNames() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Certificate[] getLocalCertificates() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public X509Certificate[] getPeerCertificateChain()
+ throws SSLPeerUnverifiedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Principal getLocalPrincipal() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getPacketBufferSize() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getApplicationBufferSize() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+ }
+
+ private static void log(Throwable t) {
+ // TODO(nathanmittler): Better error handling?
+ System.out.println("Error inflating SSL session: "
+ + (t.getMessage() != null ? t.getMessage() : t.getClass().getName()));
+ }
+
+ private static void checkRemaining(ByteBuffer buf, int length) throws IOException {
+ if (length < 0) {
+ throw new IOException("Length is negative: " + length);
+ }
+ if (length > buf.remaining()) {
+ throw new IOException(
+ "Length of blob is longer than available: " + length + " > " + buf.remaining());
+ }
+ }
+}
diff --git a/common/src/main/java/org/conscrypt/SslWrapper.java b/common/src/main/java/org/conscrypt/SslWrapper.java
new file mode 100644
index 0000000..b396aa9
--- /dev/null
+++ b/common/src/main/java/org/conscrypt/SslWrapper.java
@@ -0,0 +1,581 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.conscrypt;
+
+import static org.conscrypt.NativeConstants.SSL_RECEIVED_SHUTDOWN;
+import static org.conscrypt.NativeConstants.SSL_SENT_SHUTDOWN;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.SocketTimeoutException;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.HashSet;
+import java.util.Set;
+import javax.crypto.SecretKey;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.X509KeyManager;
+import javax.net.ssl.X509TrustManager;
+import javax.security.auth.x500.X500Principal;
+import org.conscrypt.NativeCrypto.SSLHandshakeCallbacks;
+import org.conscrypt.SSLParametersImpl.AliasChooser;
+import org.conscrypt.SSLParametersImpl.PSKCallbacks;
+
+/**
+ * A utility wrapper that abstracts operations on the underlying native SSL instance.
+ */
+final class SslWrapper {
+ private final SSLParametersImpl parameters;
+ private final SSLHandshakeCallbacks handshakeCallbacks;
+ private final AliasChooser aliasChooser;
+ private final PSKCallbacks pskCallbacks;
+ private long ssl;
+
+ static SslWrapper newInstance(SSLParametersImpl parameters,
+ SSLHandshakeCallbacks handshakeCallbacks, AliasChooser chooser,
+ PSKCallbacks pskCallbacks) throws SSLException {
+ long ctx = parameters.getSessionContext().sslCtxNativePointer;
+ long ssl = NativeCrypto.SSL_new(ctx);
+ return new SslWrapper(ssl, parameters, handshakeCallbacks, chooser, pskCallbacks);
+ }
+
+ private SslWrapper(long ssl, SSLParametersImpl parameters,
+ SSLHandshakeCallbacks handshakeCallbacks, AliasChooser aliasChooser,
+ PSKCallbacks pskCallbacks) {
+ this.ssl = ssl;
+ this.parameters = parameters;
+ this.handshakeCallbacks = handshakeCallbacks;
+ this.aliasChooser = aliasChooser;
+ this.pskCallbacks = pskCallbacks;
+ }
+
+ long ssl() {
+ return ssl;
+ }
+
+ BioWrapper newBio() {
+ try {
+ return new BioWrapper();
+ } catch (SSLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ void offerToResumeSession(long sslSessionNativePointer) throws SSLException {
+ NativeCrypto.SSL_set_session(ssl, sslSessionNativePointer);
+ }
+
+ byte[] getSessionId() {
+ return NativeCrypto.SSL_session_id(ssl);
+ }
+
+ long getTime() {
+ return NativeCrypto.SSL_get_time(ssl);
+ }
+
+ long getTimeout() {
+ return NativeCrypto.SSL_get_timeout(ssl);
+ }
+
+ void setTimeout(long millis) {
+ NativeCrypto.SSL_set_timeout(ssl, millis);
+ }
+
+ String getCipherSuite() {
+ String name = NativeCrypto.SSL_get_current_cipher(ssl);
+ return SSLUtils.getCipherSuiteFromName(name);
+ }
+
+ OpenSSLX509Certificate[] getLocalCertificates() {
+ return OpenSSLX509Certificate.createCertChain(NativeCrypto.SSL_get_certificate(ssl));
+ }
+
+ OpenSSLX509Certificate[] getPeerCertificates() {
+ return OpenSSLX509Certificate.createCertChain(NativeCrypto.SSL_get_peer_cert_chain(ssl));
+ }
+
+ byte[] getPeerCertificateOcspData() {
+ return NativeCrypto.SSL_get_ocsp_response(ssl);
+ }
+
+ byte[] getPeerTlsSctData() {
+ return NativeCrypto.SSL_get_signed_cert_timestamp_list(ssl);
+ }
+
+ /**
+ * @see NativeCrypto.SSLHandshakeCallbacks#clientPSKKeyRequested(String, byte[], byte[])
+ */
+ @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package
+ int clientPSKKeyRequested(String identityHint, byte[] identityBytesOut, byte[] key) {
+ PSKKeyManager pskKeyManager = parameters.getPSKKeyManager();
+ if (pskKeyManager == null) {
+ return 0;
+ }
+
+ String identity = pskCallbacks.chooseClientPSKIdentity(pskKeyManager, identityHint);
+ // Store identity in NULL-terminated modified UTF-8 representation into ientityBytesOut
+ byte[] identityBytes;
+ if (identity == null) {
+ identity = "";
+ identityBytes = EmptyArray.BYTE;
+ } else if (identity.isEmpty()) {
+ identityBytes = EmptyArray.BYTE;
+ } else {
+ try {
+ identityBytes = identity.getBytes("UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException("UTF-8 encoding not supported", e);
+ }
+ }
+ if (identityBytes.length + 1 > identityBytesOut.length) {
+ // Insufficient space in the output buffer
+ return 0;
+ }
+ if (identityBytes.length > 0) {
+ System.arraycopy(identityBytes, 0, identityBytesOut, 0, identityBytes.length);
+ }
+ identityBytesOut[identityBytes.length] = 0;
+
+ SecretKey secretKey = pskCallbacks.getPSKKey(pskKeyManager, identityHint, identity);
+ byte[] secretKeyBytes = secretKey.getEncoded();
+ if (secretKeyBytes == null) {
+ return 0;
+ } else if (secretKeyBytes.length > key.length) {
+ // Insufficient space in the output buffer
+ return 0;
+ }
+ System.arraycopy(secretKeyBytes, 0, key, 0, secretKeyBytes.length);
+ return secretKeyBytes.length;
+ }
+
+ /**
+ * @see NativeCrypto.SSLHandshakeCallbacks#serverPSKKeyRequested(String, String, byte[])
+ */
+ @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package
+ int serverPSKKeyRequested(String identityHint, String identity, byte[] key) {
+ PSKKeyManager pskKeyManager = parameters.getPSKKeyManager();
+ if (pskKeyManager == null) {
+ return 0;
+ }
+ SecretKey secretKey = pskCallbacks.getPSKKey(pskKeyManager, identityHint, identity);
+ byte[] secretKeyBytes = secretKey.getEncoded();
+ if (secretKeyBytes == null) {
+ return 0;
+ } else if (secretKeyBytes.length > key.length) {
+ return 0;
+ }
+ System.arraycopy(secretKeyBytes, 0, key, 0, secretKeyBytes.length);
+ return secretKeyBytes.length;
+ }
+
+ void chooseClientCertificate(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals)
+ throws SSLException, CertificateEncodingException {
+ Set<String> keyTypesSet = SSLUtils.getSupportedClientKeyTypes(keyTypeBytes);
+ String[] keyTypes = keyTypesSet.toArray(new String[keyTypesSet.size()]);
+
+ X500Principal[] issuers;
+ if (asn1DerEncodedPrincipals == null) {
+ issuers = null;
+ } else {
+ issuers = new X500Principal[asn1DerEncodedPrincipals.length];
+ for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) {
+ issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]);
+ }
+ }
+ X509KeyManager keyManager = parameters.getX509KeyManager();
+ String alias = (keyManager != null)
+ ? aliasChooser.chooseClientAlias(keyManager, issuers, keyTypes)
+ : null;
+ setCertificate(alias);
+ }
+
+ void setCertificate(String alias) throws CertificateEncodingException, SSLException {
+ if (alias == null) {
+ return;
+ }
+ X509KeyManager keyManager = parameters.getX509KeyManager();
+ if (keyManager == null) {
+ return;
+ }
+ PrivateKey privateKey = keyManager.getPrivateKey(alias);
+ if (privateKey == null) {
+ return;
+ }
+ X509Certificate[] certificates = keyManager.getCertificateChain(alias);
+ if (certificates == null) {
+ return;
+ }
+ PublicKey publicKey = (certificates.length > 0) ? certificates[0].getPublicKey() : null;
+
+ /*
+ * Make sure we keep a reference to the OpenSSLX509Certificate by using
+ * this array. Otherwise, if they're not OpenSSLX509Certificate
+ * instances originally, they may be garbage collected before we
+ * complete our JNI calls.
+ */
+ OpenSSLX509Certificate[] openSslCerts = new OpenSSLX509Certificate[certificates.length];
+ long[] x509refs = new long[certificates.length];
+ for (int i = 0; i < certificates.length; i++) {
+ OpenSSLX509Certificate openSslCert =
+ OpenSSLX509Certificate.fromCertificate(certificates[i]);
+ openSslCerts[i] = openSslCert;
+ x509refs[i] = openSslCert.getContext();
+ }
+
+ // Note that OpenSSL says to use SSL_use_certificate before
+ // SSL_use_PrivateKey.
+ NativeCrypto.SSL_use_certificate(ssl, x509refs);
+
+ final OpenSSLKey key;
+ try {
+ key = OpenSSLKey.fromPrivateKeyForTLSStackOnly(privateKey, publicKey);
+ NativeCrypto.SSL_use_PrivateKey(ssl, key.getNativeRef());
+ } catch (InvalidKeyException e) {
+ throw new SSLException(e);
+ }
+
+ // We may not have access to all the information to check the private key
+ // if it's a wrapped platform key, so skip this check.
+ if (!key.isWrapped()) {
+ // Makes sure the set PrivateKey and X509Certificate refer to the same
+ // key by comparing the public values.
+ NativeCrypto.SSL_check_private_key(ssl);
+ }
+ }
+
+ String getVersion() {
+ return NativeCrypto.SSL_get_version(ssl);
+ }
+
+ boolean isReused() {
+ return NativeCrypto.SSL_session_reused(ssl);
+ }
+
+ String getRequestedServerName() {
+ return NativeCrypto.SSL_get_servername(ssl);
+ }
+
+ byte[] getTlsChannelId() throws SSLException {
+ return NativeCrypto.SSL_get_tls_channel_id(ssl);
+ }
+
+ void initialize(String hostname, OpenSSLKey channelIdPrivateKey) throws IOException {
+ boolean enableSessionCreation = parameters.getEnableSessionCreation();
+ if (!enableSessionCreation) {
+ NativeCrypto.SSL_set_session_creation_enabled(ssl, false);
+ }
+
+ // Allow servers to trigger renegotiation. Some inadvisable server
+ // configurations cause them to attempt to renegotiate during
+ // certain protocols.
+ NativeCrypto.SSL_accept_renegotiations(ssl);
+
+ if (isClient()) {
+ NativeCrypto.SSL_set_connect_state(ssl);
+
+ // Configure OCSP and CT extensions for client
+ NativeCrypto.SSL_enable_ocsp_stapling(ssl);
+ if (parameters.isCTVerificationEnabled(hostname)) {
+ NativeCrypto.SSL_enable_signed_cert_timestamps(ssl);
+ }
+ } else {
+ NativeCrypto.SSL_set_accept_state(ssl);
+
+ // Configure OCSP for server
+ if (parameters.getOCSPResponse() != null) {
+ NativeCrypto.SSL_enable_ocsp_stapling(ssl);
+ }
+ }
+
+ if (parameters.getEnabledProtocols().length == 0 && parameters.isEnabledProtocolsFiltered) {
+ throw new SSLHandshakeException("No enabled protocols; "
+ + NativeCrypto.OBSOLETE_PROTOCOL_SSLV3
+ + " is no longer supported and was filtered from the list");
+ }
+ NativeCrypto.SSL_configure_alpn(ssl, isClient(), parameters.alpnProtocols);
+ NativeCrypto.setEnabledProtocols(ssl, parameters.enabledProtocols);
+ NativeCrypto.setEnabledCipherSuites(ssl, parameters.enabledCipherSuites);
+
+ // setup server certificates and private keys.
+ // clients will receive a call back to request certificates.
+ if (!isClient()) {
+ Set<String> keyTypes = new HashSet<String>();
+ for (long sslCipherNativePointer : NativeCrypto.SSL_get_ciphers(ssl)) {
+ String keyType = SSLUtils.getServerX509KeyType(sslCipherNativePointer);
+ if (keyType != null) {
+ keyTypes.add(keyType);
+ }
+ }
+ X509KeyManager keyManager = parameters.getX509KeyManager();
+ if (keyManager != null) {
+ for (String keyType : keyTypes) {
+ try {
+ setCertificate(aliasChooser.chooseServerAlias(keyManager, keyType));
+ } catch (CertificateEncodingException e) {
+ throw new IOException(e);
+ }
+ }
+ }
+
+ NativeCrypto.SSL_set_options(ssl, NativeConstants.SSL_OP_CIPHER_SERVER_PREFERENCE);
+
+ if (parameters.sctExtension != null) {
+ NativeCrypto.SSL_set_signed_cert_timestamp_list(ssl, parameters.sctExtension);
+ }
+
+ if (parameters.ocspResponse != null) {
+ NativeCrypto.SSL_set_ocsp_response(ssl, parameters.ocspResponse);
+ }
+ }
+
+ enablePSKKeyManagerIfRequested();
+
+ if (parameters.useSessionTickets) {
+ NativeCrypto.SSL_clear_options(ssl, NativeConstants.SSL_OP_NO_TICKET);
+ } else {
+ NativeCrypto.SSL_set_options(
+ ssl, NativeCrypto.SSL_get_options(ssl) | NativeConstants.SSL_OP_NO_TICKET);
+ }
+
+ if (parameters.getUseSni() && AddressUtils.isValidSniHostname(hostname)) {
+ NativeCrypto.SSL_set_tlsext_host_name(ssl, hostname);
+ }
+
+ // BEAST attack mitigation (1/n-1 record splitting for CBC cipher suites
+ // with TLSv1 and SSLv3).
+ NativeCrypto.SSL_set_mode(ssl, NativeConstants.SSL_MODE_CBC_RECORD_SPLITTING);
+
+ setCertificateValidation(ssl);
+ setTlsChannelId(channelIdPrivateKey);
+ }
+
+ // TODO(nathanmittler): Remove once after we switch to the engine socket.
+ void doHandshake(FileDescriptor fd, int timeoutMillis)
+ throws CertificateException, SocketTimeoutException, SSLException {
+ NativeCrypto.SSL_do_handshake(ssl, fd, handshakeCallbacks, timeoutMillis);
+ }
+
+ int doHandshake() throws IOException {
+ return NativeCrypto.ENGINE_SSL_do_handshake(ssl, handshakeCallbacks);
+ }
+
+ // TODO(nathanmittler): Remove once after we switch to the engine socket.
+ int read(FileDescriptor fd, byte[] buf, int offset, int len, int timeoutMillis)
+ throws IOException {
+ return NativeCrypto.SSL_read(ssl, fd, handshakeCallbacks, buf, offset, len, timeoutMillis);
+ }
+
+ // TODO(nathanmittler): Remove once after we switch to the engine socket.
+ void write(FileDescriptor fd, byte[] buf, int offset, int len, int timeoutMillis)
+ throws IOException {
+ NativeCrypto.SSL_write(ssl, fd, handshakeCallbacks, buf, offset, len, timeoutMillis);
+ }
+
+ @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package
+ private void enablePSKKeyManagerIfRequested() throws SSLException {
+ // Enable Pre-Shared Key (PSK) key exchange if requested
+ PSKKeyManager pskKeyManager = parameters.getPSKKeyManager();
+ if (pskKeyManager != null) {
+ boolean pskEnabled = false;
+ for (String enabledCipherSuite : parameters.enabledCipherSuites) {
+ if ((enabledCipherSuite != null) && (enabledCipherSuite.contains("PSK"))) {
+ pskEnabled = true;
+ break;
+ }
+ }
+ if (pskEnabled) {
+ if (isClient()) {
+ NativeCrypto.set_SSL_psk_client_callback_enabled(ssl, true);
+ } else {
+ NativeCrypto.set_SSL_psk_server_callback_enabled(ssl, true);
+ String identityHint = pskCallbacks.chooseServerPSKIdentityHint(pskKeyManager);
+ NativeCrypto.SSL_use_psk_identity_hint(ssl, identityHint);
+ }
+ }
+ }
+ }
+
+ private void setTlsChannelId(OpenSSLKey channelIdPrivateKey) throws SSLException {
+ if (!parameters.channelIdEnabled) {
+ return;
+ }
+
+ if (parameters.getUseClientMode()) {
+ // Client-side TLS Channel ID
+ if (channelIdPrivateKey == null) {
+ throw new SSLHandshakeException("Invalid TLS channel ID key specified");
+ }
+ NativeCrypto.SSL_set1_tls_channel_id(ssl, channelIdPrivateKey.getNativeRef());
+ } else {
+ // Server-side TLS Channel ID
+ NativeCrypto.SSL_enable_tls_channel_id(ssl);
+ }
+ }
+
+ private void setCertificateValidation(long sslNativePointer) throws SSLException {
+ // setup peer certificate verification
+ if (!isClient()) {
+ // needing client auth takes priority...
+ boolean certRequested;
+ if (parameters.getNeedClientAuth()) {
+ NativeCrypto.SSL_set_verify(sslNativePointer, NativeCrypto.SSL_VERIFY_PEER
+ | NativeCrypto.SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
+ certRequested = true;
+ // ... over just wanting it...
+ } else if (parameters.getWantClientAuth()) {
+ NativeCrypto.SSL_set_verify(sslNativePointer, NativeCrypto.SSL_VERIFY_PEER);
+ certRequested = true;
+ // ... and we must disable verification if we don't want client auth.
+ } else {
+ NativeCrypto.SSL_set_verify(sslNativePointer, NativeCrypto.SSL_VERIFY_NONE);
+ certRequested = false;
+ }
+
+ if (certRequested) {
+ X509TrustManager trustManager = parameters.getX509TrustManager();
+ X509Certificate[] issuers = trustManager.getAcceptedIssuers();
+ if (issuers != null && issuers.length != 0) {
+ byte[][] issuersBytes;
+ try {
+ issuersBytes = SSLUtils.encodeIssuerX509Principals(issuers);
+ } catch (CertificateEncodingException e) {
+ throw new SSLException("Problem encoding principals", e);
+ }
+ NativeCrypto.SSL_set_client_CA_list(sslNativePointer, issuersBytes);
+ }
+ }
+ }
+ }
+
+ void interrupt() {
+ NativeCrypto.SSL_interrupt(ssl);
+ }
+
+ // TODO(nathanmittler): Remove once after we switch to the engine socket.
+ void shutdown(FileDescriptor fd) throws IOException {
+ NativeCrypto.SSL_shutdown(ssl, fd, handshakeCallbacks);
+ }
+
+ void shutdown() throws IOException {
+ NativeCrypto.ENGINE_SSL_shutdown(ssl, handshakeCallbacks);
+ }
+
+ boolean wasShutdownReceived() {
+ return (NativeCrypto.SSL_get_shutdown(ssl) & SSL_RECEIVED_SHUTDOWN) != 0;
+ }
+
+ boolean wasShutdownSent() {
+ return (NativeCrypto.SSL_get_shutdown(ssl) & SSL_SENT_SHUTDOWN) != 0;
+ }
+
+ int readDirectByteBuffer(long destAddress, int destLength)
+ throws IOException, CertificateException {
+ return NativeCrypto.ENGINE_SSL_read_direct(
+ ssl, destAddress, destLength, handshakeCallbacks);
+ }
+
+ int readArray(byte[] destJava, int destOffset, int destLength)
+ throws IOException, CertificateException {
+ return NativeCrypto.ENGINE_SSL_read_heap(
+ ssl, destJava, destOffset, destLength, handshakeCallbacks);
+ }
+
+ int writeDirectByteBuffer(long sourceAddress, int sourceLength) throws IOException {
+ return NativeCrypto.ENGINE_SSL_write_direct(
+ ssl, sourceAddress, sourceLength, handshakeCallbacks);
+ }
+
+ int writeArray(byte[] sourceJava, int sourceOffset, int sourceLength) throws IOException {
+ return NativeCrypto.ENGINE_SSL_write_heap(
+ ssl, sourceJava, sourceOffset, sourceLength, handshakeCallbacks);
+ }
+
+ int getPendingReadableBytes() {
+ return NativeCrypto.SSL_pending_readable_bytes(ssl);
+ }
+
+ int getMaxSealOverhead() {
+ return NativeCrypto.SSL_max_seal_overhead(ssl);
+ }
+
+ void close() {
+ NativeCrypto.SSL_free(ssl);
+ ssl = 0L;
+ }
+
+ boolean isClosed() {
+ return ssl == 0L;
+ }
+
+ int getError(int result) {
+ return NativeCrypto.SSL_get_error(ssl, result);
+ }
+
+ byte[] getAlpnSelectedProtocol() {
+ return NativeCrypto.SSL_get0_alpn_selected(ssl);
+ }
+
+ private boolean isClient() {
+ return parameters.getUseClientMode();
+ }
+
+ /**
+ * A utility wrapper that abstracts operations on the underlying native BIO instance.
+ */
+ final class BioWrapper {
+ private long bio;
+
+ private BioWrapper() throws SSLException {
+ this.bio = NativeCrypto.SSL_BIO_new(ssl);
+ }
+
+ int getPendingWrittenBytes() {
+ return NativeCrypto.SSL_pending_written_bytes_in_BIO(bio);
+ }
+
+ int writeDirectByteBuffer(long address, int length) throws IOException {
+ return NativeCrypto.ENGINE_SSL_write_BIO_direct(
+ ssl, bio, address, length, handshakeCallbacks);
+ }
+
+ int writeArray(byte[] sourceJava, int sourceOffset, int sourceLength) throws IOException {
+ return NativeCrypto.ENGINE_SSL_write_BIO_heap(
+ ssl, bio, sourceJava, sourceOffset, sourceLength, handshakeCallbacks);
+ }
+
+ int readDirectByteBuffer(long destAddress, int destLength) throws IOException {
+ return NativeCrypto.ENGINE_SSL_read_BIO_direct(
+ ssl, bio, destAddress, destLength, handshakeCallbacks);
+ }
+
+ int readArray(byte[] destJava, int destOffset, int destLength) throws IOException {
+ return NativeCrypto.ENGINE_SSL_read_BIO_heap(
+ ssl, bio, destJava, destOffset, destLength, handshakeCallbacks);
+ }
+
+ void close() {
+ NativeCrypto.BIO_free_all(bio);
+ bio = 0L;
+ }
+ }
+}
diff --git a/openjdk-integ-tests/src/test/java/libcore/javax/net/ssl/SSLSessionContextTest.java b/openjdk-integ-tests/src/test/java/libcore/javax/net/ssl/SSLSessionContextTest.java
index 72de22f..91f00ba 100644
--- a/openjdk-integ-tests/src/test/java/libcore/javax/net/ssl/SSLSessionContextTest.java
+++ b/openjdk-integ-tests/src/test/java/libcore/javax/net/ssl/SSLSessionContextTest.java
@@ -39,14 +39,13 @@
@RunWith(JUnit4.class)
public class SSLSessionContextTest extends AbstractSSLTest {
-
@Test
public void test_SSLSessionContext_getIds() {
TestSSLContext c = TestSSLContext.create();
assertSSLSessionContextSize(0, c);
c.close();
- TestSSLSocketPair s = TestSSLSocketPair.create();
+ TestSSLSocketPair s = TestSSLSocketPair.create().connect();
assertSSLSessionContextSize(1, s.c);
Enumeration<byte[]> clientIds = s.c.clientContext.getClientSessionContext().getIds();
Enumeration<byte[]> serverIds = s.c.serverContext.getServerSessionContext().getIds();
@@ -83,7 +82,7 @@
assertNull(c.serverContext.getServerSessionContext().getSession(new byte[1]));
c.close();
- TestSSLSocketPair s = TestSSLSocketPair.create();
+ TestSSLSocketPair s = TestSSLSocketPair.create().connect();
SSLSessionContext client = s.c.clientContext.getClientSessionContext();
SSLSessionContext server = s.c.serverContext.getServerSessionContext();
byte[] clientId = client.getIds().nextElement();
@@ -110,7 +109,7 @@
c.serverContext.getServerSessionContext().getSessionCacheSize());
c.close();
- TestSSLSocketPair s = TestSSLSocketPair.create();
+ TestSSLSocketPair s = TestSSLSocketPair.create().connect();
assertEquals(expectedClientSessionCacheSize,
s.c.clientContext.getClientSessionContext().getSessionCacheSize());
assertEquals(expectedServerSessionCacheSize,
@@ -124,11 +123,9 @@
int expectedClientSessionCacheSize = expectedClientSslSessionCacheSize(c);
int expectedServerSessionCacheSize = expectedServerSslSessionCacheSize(c);
assertNoConnectSetSessionCacheSizeBehavior(
- expectedClientSessionCacheSize,
- c.clientContext.getClientSessionContext());
+ expectedClientSessionCacheSize, c.clientContext.getClientSessionContext());
assertNoConnectSetSessionCacheSizeBehavior(
- expectedServerSessionCacheSize,
- c.serverContext.getServerSessionContext());
+ expectedServerSessionCacheSize, c.serverContext.getServerSessionContext());
c.close();
}
@@ -147,15 +144,13 @@
@Test
public void test_SSLSessionContext_setSessionCacheSize_oneConnect() {
- TestSSLSocketPair s = TestSSLSocketPair.create();
+ TestSSLSocketPair s = TestSSLSocketPair.create().connect();
int expectedClientSessionCacheSize = expectedClientSslSessionCacheSize(s.c);
int expectedServerSessionCacheSize = expectedServerSslSessionCacheSize(s.c);
SSLSessionContext client = s.c.clientContext.getClientSessionContext();
SSLSessionContext server = s.c.serverContext.getServerSessionContext();
- assertEquals(expectedClientSessionCacheSize,
- client.getSessionCacheSize());
- assertEquals(expectedServerSessionCacheSize,
- server.getSessionCacheSize());
+ assertEquals(expectedClientSessionCacheSize, client.getSessionCacheSize());
+ assertEquals(expectedServerSessionCacheSize, server.getSessionCacheSize());
assertSSLSessionContextSize(1, s.c);
s.close();
}
@@ -212,11 +207,14 @@
String cipherSuite3 = uniqueCipherSuites.get(2);
List<SSLSocket[]> toClose = new ArrayList<>();
- toClose.add(TestSSLSocketPair.connect(c, new String[] {cipherSuite1}, null));
+ toClose.add(
+ TestSSLSocketPair.create(c).connect(new String[] {cipherSuite1}, null).sockets());
assertSSLSessionContextSize(1, c);
- toClose.add(TestSSLSocketPair.connect(c, new String[] {cipherSuite2}, null));
+ toClose.add(
+ TestSSLSocketPair.create(c).connect(new String[] {cipherSuite2}, null).sockets());
assertSSLSessionContextSize(2, c);
- toClose.add(TestSSLSocketPair.connect(c, new String[] {cipherSuite3}, null));
+ toClose.add(
+ TestSSLSocketPair.create(c).connect(new String[] {cipherSuite3}, null).sockets());
assertSSLSessionContextSize(3, c);
client.setSessionCacheSize(1);
@@ -224,14 +222,17 @@
assertEquals(1, client.getSessionCacheSize());
assertEquals(1, server.getSessionCacheSize());
assertSSLSessionContextSize(1, c);
- toClose.add(TestSSLSocketPair.connect(c, new String[] {cipherSuite1}, null));
+ toClose.add(
+ TestSSLSocketPair.create(c).connect(new String[] {cipherSuite1}, null).sockets());
assertSSLSessionContextSize(1, c);
client.setSessionCacheSize(2);
server.setSessionCacheSize(2);
- toClose.add(TestSSLSocketPair.connect(c, new String[] {cipherSuite2}, null));
+ toClose.add(
+ TestSSLSocketPair.create(c).connect(new String[] {cipherSuite2}, null).sockets());
assertSSLSessionContextSize(2, c);
- toClose.add(TestSSLSocketPair.connect(c, new String[] {cipherSuite3}, null));
+ toClose.add(
+ TestSSLSocketPair.create(c).connect(new String[] {cipherSuite3}, null).sockets());
assertSSLSessionContextSize(2, c);
for (SSLSocket[] pair : toClose) {
@@ -252,7 +253,7 @@
c.serverContext.getServerSessionContext().getSessionTimeout());
c.close();
- TestSSLSocketPair s = TestSSLSocketPair.create();
+ TestSSLSocketPair s = TestSSLSocketPair.create().connect();
assertEquals(expectedCacheTimeout,
s.c.clientContext.getClientSessionContext().getSessionTimeout());
assertEquals(expectedCacheTimeout,
@@ -287,7 +288,7 @@
}
c.close();
- TestSSLSocketPair s = TestSSLSocketPair.create();
+ TestSSLSocketPair s = TestSSLSocketPair.create().connect();
assertSSLSessionContextSize(1, s.c);
Thread.sleep(1000);
s.c.clientContext.getClientSessionContext().setSessionTimeout(1);
@@ -311,11 +312,10 @@
private static void assertSSLSessionContextSize(
int expected, SSLSessionContext s, boolean server) {
- int size = Collections.list(s.getIds()).size();
if (server && TestSSLContext.sslServerSocketSupportsSessionTickets()) {
- assertEquals(0, size);
+ assertEquals(0, numSessions(s));
} else {
- assertEquals(expected, size);
+ assertEquals(expected, numSessions(s));
}
}
@@ -331,6 +331,10 @@
return (isConscrypt(c.serverContext.getProvider())) ? 8 * 3600 : 24 * 3600;
}
+ private static int numSessions(SSLSessionContext s) {
+ return Collections.list(s.getIds()).size();
+ }
+
private boolean isConscrypt(Provider provider) {
return "AndroidOpenSSL".equals(provider.getName());
}
diff --git a/openjdk-integ-tests/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java b/openjdk-integ-tests/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
index 53f3a12..928a50a 100644
--- a/openjdk-integ-tests/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
+++ b/openjdk-integ-tests/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
@@ -234,10 +234,10 @@
}
String[] clientCipherSuiteArray =
new String[] {cipherSuite, StandardNames.CIPHER_SUITE_SECURE_RENEGOTIATION};
- SSLSocket[] pair = TestSSLSocketPair.connect(
- c, clientCipherSuiteArray, clientCipherSuiteArray);
- SSLSocket server = pair[0];
- SSLSocket client = pair[1];
+ TestSSLSocketPair socketPair = TestSSLSocketPair.create(c).connect(
+ clientCipherSuiteArray, clientCipherSuiteArray);
+ SSLSocket server = socketPair.server;
+ SSLSocket client = socketPair.client;
// Check that the client can read the message sent by the server
server.getOutputStream().write(serverToClient);
byte[] clientFromServer = new byte[serverToClient.length];
@@ -603,7 +603,6 @@
byte[] id = session.getId();
assertNotNull(id);
assertEquals(32, id.length);
- assertNotNull(c.clientContext.getClientSessionContext().getSession(id));
assertNotNull(cipherSuite);
assertTrue(Arrays.asList(client.getEnabledCipherSuites()).contains(cipherSuite));
assertTrue(Arrays.asList(c.serverSocket.getEnabledCipherSuites())
@@ -762,7 +761,7 @@
@Test
public void test_SSLSocket_setUseClientMode_afterHandshake() throws Exception {
// can't set after handshake
- TestSSLSocketPair pair = TestSSLSocketPair.create();
+ TestSSLSocketPair pair = TestSSLSocketPair.create().connect();
try {
pair.server.setUseClientMode(false);
fail();
@@ -1365,7 +1364,7 @@
@Test
public void test_SSLSocket_close() throws Exception {
- TestSSLSocketPair pair = TestSSLSocketPair.create();
+ TestSSLSocketPair pair = TestSSLSocketPair.create().connect();
SSLSocket server = pair.server;
SSLSocket client = pair.client;
assertFalse(server.isClosed());
@@ -1778,7 +1777,7 @@
@Test
public void test_TestSSLSocketPair_create() {
- TestSSLSocketPair test = TestSSLSocketPair.create();
+ TestSSLSocketPair test = TestSSLSocketPair.create().connect();
assertNotNull(test.c);
assertNotNull(test.server);
assertNotNull(test.client);
diff --git a/openjdk/src/main/java/org/conscrypt/Platform.java b/openjdk/src/main/java/org/conscrypt/Platform.java
index 7b5adb6..4bba5c8 100644
--- a/openjdk/src/main/java/org/conscrypt/Platform.java
+++ b/openjdk/src/main/java/org/conscrypt/Platform.java
@@ -362,15 +362,16 @@
* Pre-Java-8 backward compatibility.
*/
- static SSLSession wrapSSLSession(AbstractOpenSSLSession sslSession) {
- return new OpenSSLExtendedSessionImpl(sslSession);
+ static SSLSession wrapSSLSession(ActiveSession sslSession) {
+ return new DelegatingExtendedSSLSession(sslSession);
}
@SuppressWarnings("unused")
static SSLSession unwrapSSLSession(SSLSession sslSession) {
- if (sslSession instanceof OpenSSLExtendedSessionImpl) {
- return ((OpenSSLExtendedSessionImpl) sslSession).getDelegate();
+ if (sslSession instanceof DelegatingExtendedSSLSession) {
+ return ((DelegatingExtendedSSLSession) sslSession).getDelegate();
}
+
return sslSession;
}
diff --git a/openjdk/src/test/java/org/conscrypt/AbstractSessionContextTest.java b/openjdk/src/test/java/org/conscrypt/AbstractSessionContextTest.java
index 756e294..1cda6f9 100644
--- a/openjdk/src/test/java/org/conscrypt/AbstractSessionContextTest.java
+++ b/openjdk/src/test/java/org/conscrypt/AbstractSessionContextTest.java
@@ -1,7 +1,7 @@
/*
- * Copyright 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
- * Licensed under the Apache License, Version 2.0 (the "License", "www.google.com", 443);
+ * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
@@ -17,649 +17,118 @@
package org.conscrypt;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
+import java.security.cert.Certificate;
import javax.net.ssl.SSLSession;
-import org.junit.After;
-import org.junit.BeforeClass;
+import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-@RunWith(JUnit4.class)
-public class AbstractSessionContextTest {
- /*
- * Taken from external/boringssl/src/ssl/ssl_test.cc: kOpenSSLSession is a
- * serialized SSL_SESSION.
- */
- private static final byte[] kOpenSSLSession = new byte[] {(byte) 0x30, (byte) 0x82, (byte) 0x05,
- (byte) 0xAA, (byte) 0x02, (byte) 0x01, (byte) 0x01, (byte) 0x02, (byte) 0x02,
- (byte) 0x03, (byte) 0x03, (byte) 0x04, (byte) 0x02, (byte) 0xC0, (byte) 0x2F,
- (byte) 0x04, (byte) 0x20, (byte) 0x06, (byte) 0xE5, (byte) 0x0D, (byte) 0x67,
- (byte) 0x76, (byte) 0xAE, (byte) 0x18, (byte) 0x7E, (byte) 0x66, (byte) 0xDE,
- (byte) 0xA3, (byte) 0x5C, (byte) 0xF0, (byte) 0x2E, (byte) 0x43, (byte) 0x51,
- (byte) 0x2A, (byte) 0x60, (byte) 0x97, (byte) 0x19, (byte) 0xD3, (byte) 0x60,
- (byte) 0x5A, (byte) 0xF1, (byte) 0x93, (byte) 0xDD, (byte) 0xCB, (byte) 0x24,
- (byte) 0x57, (byte) 0x4C, (byte) 0x90, (byte) 0x90, (byte) 0x04, (byte) 0x30,
- (byte) 0x26, (byte) 0x5A, (byte) 0xE5, (byte) 0xCE, (byte) 0x40, (byte) 0x16,
- (byte) 0x04, (byte) 0xE5, (byte) 0xA2, (byte) 0x2E, (byte) 0x3F, (byte) 0xE3,
- (byte) 0x27, (byte) 0xBE, (byte) 0x83, (byte) 0xEE, (byte) 0x5F, (byte) 0x94,
- (byte) 0x5E, (byte) 0x88, (byte) 0xB3, (byte) 0x3F, (byte) 0x62, (byte) 0x88,
- (byte) 0xD8, (byte) 0x2E, (byte) 0xC8, (byte) 0xD8, (byte) 0x57, (byte) 0x1C,
- (byte) 0xA8, (byte) 0xC9, (byte) 0x88, (byte) 0x7C, (byte) 0x59, (byte) 0xA6,
- (byte) 0x91, (byte) 0x4C, (byte) 0xB7, (byte) 0xDA, (byte) 0x72, (byte) 0x09,
- (byte) 0xD2, (byte) 0x66, (byte) 0x47, (byte) 0x21, (byte) 0x6A, (byte) 0x09,
- (byte) 0xA1, (byte) 0x06, (byte) 0x02, (byte) 0x04, (byte) 0x54, (byte) 0x43,
- (byte) 0x3B, (byte) 0x8E, (byte) 0xA2, (byte) 0x04, (byte) 0x02, (byte) 0x02,
- (byte) 0x01, (byte) 0x2C, (byte) 0xA3, (byte) 0x82, (byte) 0x04, (byte) 0x7A,
- (byte) 0x30, (byte) 0x82, (byte) 0x04, (byte) 0x76, (byte) 0x30, (byte) 0x82,
- (byte) 0x03, (byte) 0x5E, (byte) 0xA0, (byte) 0x03, (byte) 0x02, (byte) 0x01,
- (byte) 0x02, (byte) 0x02, (byte) 0x08, (byte) 0x2B, (byte) 0xD7, (byte) 0x54,
- (byte) 0xBE, (byte) 0xC3, (byte) 0xD6, (byte) 0x4A, (byte) 0x55, (byte) 0x30,
- (byte) 0x0D, (byte) 0x06, (byte) 0x09, (byte) 0x2A, (byte) 0x86, (byte) 0x48,
- (byte) 0x86, (byte) 0xF7, (byte) 0x0D, (byte) 0x01, (byte) 0x01, (byte) 0x05,
- (byte) 0x05, (byte) 0x00, (byte) 0x30, (byte) 0x49, (byte) 0x31, (byte) 0x0B,
- (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
- (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, (byte) 0x31,
- (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55,
- (byte) 0x04, (byte) 0x0A, (byte) 0x13, (byte) 0x0A, (byte) 0x47, (byte) 0x6F,
- (byte) 0x6F, (byte) 0x67, (byte) 0x6C, (byte) 0x65, (byte) 0x20, (byte) 0x49,
- (byte) 0x6E, (byte) 0x63, (byte) 0x31, (byte) 0x25, (byte) 0x30, (byte) 0x23,
- (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x03, (byte) 0x13,
- (byte) 0x1C, (byte) 0x47, (byte) 0x6F, (byte) 0x6F, (byte) 0x67, (byte) 0x6C,
- (byte) 0x65, (byte) 0x20, (byte) 0x49, (byte) 0x6E, (byte) 0x74, (byte) 0x65,
- (byte) 0x72, (byte) 0x6E, (byte) 0x65, (byte) 0x74, (byte) 0x20, (byte) 0x41,
- (byte) 0x75, (byte) 0x74, (byte) 0x68, (byte) 0x6F, (byte) 0x72, (byte) 0x69,
- (byte) 0x74, (byte) 0x79, (byte) 0x20, (byte) 0x47, (byte) 0x32, (byte) 0x30,
- (byte) 0x1E, (byte) 0x17, (byte) 0x0D, (byte) 0x31, (byte) 0x34, (byte) 0x31,
- (byte) 0x30, (byte) 0x30, (byte) 0x38, (byte) 0x31, (byte) 0x32, (byte) 0x30,
- (byte) 0x37, (byte) 0x35, (byte) 0x37, (byte) 0x5A, (byte) 0x17, (byte) 0x0D,
- (byte) 0x31, (byte) 0x35, (byte) 0x30, (byte) 0x31, (byte) 0x30, (byte) 0x36,
- (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30,
- (byte) 0x5A, (byte) 0x30, (byte) 0x68, (byte) 0x31, (byte) 0x0B, (byte) 0x30,
- (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06,
- (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, (byte) 0x31, (byte) 0x13,
- (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
- (byte) 0x08, (byte) 0x0C, (byte) 0x0A, (byte) 0x43, (byte) 0x61, (byte) 0x6C,
- (byte) 0x69, (byte) 0x66, (byte) 0x6F, (byte) 0x72, (byte) 0x6E, (byte) 0x69,
- (byte) 0x61, (byte) 0x31, (byte) 0x16, (byte) 0x30, (byte) 0x14, (byte) 0x06,
- (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x07, (byte) 0x0C, (byte) 0x0D,
- (byte) 0x4D, (byte) 0x6F, (byte) 0x75, (byte) 0x6E, (byte) 0x74, (byte) 0x61,
- (byte) 0x69, (byte) 0x6E, (byte) 0x20, (byte) 0x56, (byte) 0x69, (byte) 0x65,
- (byte) 0x77, (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06,
- (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0A, (byte) 0x0C, (byte) 0x0A,
- (byte) 0x47, (byte) 0x6F, (byte) 0x6F, (byte) 0x67, (byte) 0x6C, (byte) 0x65,
- (byte) 0x20, (byte) 0x49, (byte) 0x6E, (byte) 0x63, (byte) 0x31, (byte) 0x17,
- (byte) 0x30, (byte) 0x15, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
- (byte) 0x03, (byte) 0x0C, (byte) 0x0E, (byte) 0x77, (byte) 0x77, (byte) 0x77,
- (byte) 0x2E, (byte) 0x67, (byte) 0x6F, (byte) 0x6F, (byte) 0x67, (byte) 0x6C,
- (byte) 0x65, (byte) 0x2E, (byte) 0x63, (byte) 0x6F, (byte) 0x6D, (byte) 0x30,
- (byte) 0x82, (byte) 0x01, (byte) 0x22, (byte) 0x30, (byte) 0x0D, (byte) 0x06,
- (byte) 0x09, (byte) 0x2A, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xF7,
- (byte) 0x0D, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00,
- (byte) 0x03, (byte) 0x82, (byte) 0x01, (byte) 0x0F, (byte) 0x00, (byte) 0x30,
- (byte) 0x82, (byte) 0x01, (byte) 0x0A, (byte) 0x02, (byte) 0x82, (byte) 0x01,
- (byte) 0x01, (byte) 0x00, (byte) 0x9C, (byte) 0x29, (byte) 0xE2, (byte) 0xEB,
- (byte) 0xA6, (byte) 0x50, (byte) 0x02, (byte) 0xF8, (byte) 0xBA, (byte) 0x1F,
- (byte) 0xCB, (byte) 0xCB, (byte) 0x7F, (byte) 0xC0, (byte) 0x3C, (byte) 0x2D,
- (byte) 0x07, (byte) 0xA7, (byte) 0xAE, (byte) 0xEF, (byte) 0x60, (byte) 0x95,
- (byte) 0xA7, (byte) 0x47, (byte) 0x09, (byte) 0xE1, (byte) 0x5D, (byte) 0xE5,
- (byte) 0x92, (byte) 0x73, (byte) 0x7A, (byte) 0x86, (byte) 0xE1, (byte) 0xFD,
- (byte) 0x72, (byte) 0xDE, (byte) 0x85, (byte) 0x16, (byte) 0x4E, (byte) 0xF4,
- (byte) 0xA1, (byte) 0x12, (byte) 0x21, (byte) 0xFD, (byte) 0x50, (byte) 0x4D,
- (byte) 0x04, (byte) 0x1C, (byte) 0xFD, (byte) 0xD3, (byte) 0x48, (byte) 0xD8,
- (byte) 0xCB, (byte) 0xEE, (byte) 0xF5, (byte) 0xD7, (byte) 0x52, (byte) 0x66,
- (byte) 0xD5, (byte) 0xBF, (byte) 0x22, (byte) 0xA8, (byte) 0xE4, (byte) 0xD0,
- (byte) 0xF5, (byte) 0xA4, (byte) 0xF9, (byte) 0x0B, (byte) 0xB4, (byte) 0x84,
- (byte) 0x84, (byte) 0xD7, (byte) 0x10, (byte) 0x14, (byte) 0x9B, (byte) 0xEA,
- (byte) 0xCC, (byte) 0x7D, (byte) 0xDE, (byte) 0x30, (byte) 0xF9, (byte) 0x1B,
- (byte) 0xE9, (byte) 0x94, (byte) 0x96, (byte) 0x1A, (byte) 0x6D, (byte) 0x72,
- (byte) 0x18, (byte) 0x5E, (byte) 0xCC, (byte) 0x09, (byte) 0x04, (byte) 0xC6,
- (byte) 0x41, (byte) 0x71, (byte) 0x76, (byte) 0xD1, (byte) 0x29, (byte) 0x3F,
- (byte) 0x3B, (byte) 0x5E, (byte) 0x85, (byte) 0x4A, (byte) 0x30, (byte) 0x32,
- (byte) 0x9D, (byte) 0x4F, (byte) 0xDB, (byte) 0xDE, (byte) 0x82, (byte) 0x66,
- (byte) 0x39, (byte) 0xCB, (byte) 0x5C, (byte) 0xC9, (byte) 0xC5, (byte) 0x98,
- (byte) 0x91, (byte) 0x8D, (byte) 0x32, (byte) 0xB5, (byte) 0x2F, (byte) 0xE4,
- (byte) 0xDC, (byte) 0xB0, (byte) 0x6E, (byte) 0x21, (byte) 0xDE, (byte) 0x39,
- (byte) 0x3C, (byte) 0x96, (byte) 0xA8, (byte) 0x32, (byte) 0xA8, (byte) 0xC1,
- (byte) 0xD1, (byte) 0x6C, (byte) 0xA9, (byte) 0xAA, (byte) 0xF3, (byte) 0x5E,
- (byte) 0x24, (byte) 0x70, (byte) 0xB7, (byte) 0xAB, (byte) 0x92, (byte) 0x63,
- (byte) 0x08, (byte) 0x1E, (byte) 0x11, (byte) 0x3F, (byte) 0xB3, (byte) 0x5F,
- (byte) 0xC7, (byte) 0x98, (byte) 0xE3, (byte) 0x1D, (byte) 0x2A, (byte) 0xC2,
- (byte) 0x32, (byte) 0x1C, (byte) 0x3C, (byte) 0x95, (byte) 0x43, (byte) 0x16,
- (byte) 0xE0, (byte) 0x46, (byte) 0x83, (byte) 0xC6, (byte) 0x36, (byte) 0x91,
- (byte) 0xF4, (byte) 0xA0, (byte) 0xE1, (byte) 0x3C, (byte) 0xB8, (byte) 0x23,
- (byte) 0xB2, (byte) 0x4F, (byte) 0x8B, (byte) 0x0C, (byte) 0x8C, (byte) 0x92,
- (byte) 0x45, (byte) 0x24, (byte) 0x43, (byte) 0x68, (byte) 0x24, (byte) 0x06,
- (byte) 0x84, (byte) 0x43, (byte) 0x96, (byte) 0x2C, (byte) 0x96, (byte) 0x55,
- (byte) 0x2F, (byte) 0x32, (byte) 0xE8, (byte) 0xE0, (byte) 0xDE, (byte) 0xBF,
- (byte) 0x52, (byte) 0x57, (byte) 0x2D, (byte) 0x08, (byte) 0x71, (byte) 0x25,
- (byte) 0x96, (byte) 0x90, (byte) 0x54, (byte) 0x4A, (byte) 0xF1, (byte) 0x0E,
- (byte) 0xC8, (byte) 0x58, (byte) 0x1A, (byte) 0xE7, (byte) 0x6A, (byte) 0xAB,
- (byte) 0xA0, (byte) 0x68, (byte) 0xE0, (byte) 0xAD, (byte) 0xFD, (byte) 0xD6,
- (byte) 0x39, (byte) 0x0F, (byte) 0x76, (byte) 0xE4, (byte) 0xC1, (byte) 0x70,
- (byte) 0xCD, (byte) 0xDE, (byte) 0x80, (byte) 0x2B, (byte) 0xE2, (byte) 0x1C,
- (byte) 0x87, (byte) 0x48, (byte) 0x03, (byte) 0x46, (byte) 0x0F, (byte) 0x2C,
- (byte) 0x41, (byte) 0xF7, (byte) 0x4B, (byte) 0x1F, (byte) 0x93, (byte) 0xAE,
- (byte) 0x3F, (byte) 0x57, (byte) 0x1F, (byte) 0x2D, (byte) 0xF5, (byte) 0x35,
- (byte) 0x02, (byte) 0x03, (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0xA3,
- (byte) 0x82, (byte) 0x01, (byte) 0x41, (byte) 0x30, (byte) 0x82, (byte) 0x01,
- (byte) 0x3D, (byte) 0x30, (byte) 0x1D, (byte) 0x06, (byte) 0x03, (byte) 0x55,
- (byte) 0x1D, (byte) 0x25, (byte) 0x04, (byte) 0x16, (byte) 0x30, (byte) 0x14,
- (byte) 0x06, (byte) 0x08, (byte) 0x2B, (byte) 0x06, (byte) 0x01, (byte) 0x05,
- (byte) 0x05, (byte) 0x07, (byte) 0x03, (byte) 0x01, (byte) 0x06, (byte) 0x08,
- (byte) 0x2B, (byte) 0x06, (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x07,
- (byte) 0x03, (byte) 0x02, (byte) 0x30, (byte) 0x19, (byte) 0x06, (byte) 0x03,
- (byte) 0x55, (byte) 0x1D, (byte) 0x11, (byte) 0x04, (byte) 0x12, (byte) 0x30,
- (byte) 0x10, (byte) 0x82, (byte) 0x0E, (byte) 0x77, (byte) 0x77, (byte) 0x77,
- (byte) 0x2E, (byte) 0x67, (byte) 0x6F, (byte) 0x6F, (byte) 0x67, (byte) 0x6C,
- (byte) 0x65, (byte) 0x2E, (byte) 0x63, (byte) 0x6F, (byte) 0x6D, (byte) 0x30,
- (byte) 0x68, (byte) 0x06, (byte) 0x08, (byte) 0x2B, (byte) 0x06, (byte) 0x01,
- (byte) 0x05, (byte) 0x05, (byte) 0x07, (byte) 0x01, (byte) 0x01, (byte) 0x04,
- (byte) 0x5C, (byte) 0x30, (byte) 0x5A, (byte) 0x30, (byte) 0x2B, (byte) 0x06,
- (byte) 0x08, (byte) 0x2B, (byte) 0x06, (byte) 0x01, (byte) 0x05, (byte) 0x05,
- (byte) 0x07, (byte) 0x30, (byte) 0x02, (byte) 0x86, (byte) 0x1F, (byte) 0x68,
- (byte) 0x74, (byte) 0x74, (byte) 0x70, (byte) 0x3A, (byte) 0x2F, (byte) 0x2F,
- (byte) 0x70, (byte) 0x6B, (byte) 0x69, (byte) 0x2E, (byte) 0x67, (byte) 0x6F,
- (byte) 0x6F, (byte) 0x67, (byte) 0x6C, (byte) 0x65, (byte) 0x2E, (byte) 0x63,
- (byte) 0x6F, (byte) 0x6D, (byte) 0x2F, (byte) 0x47, (byte) 0x49, (byte) 0x41,
- (byte) 0x47, (byte) 0x32, (byte) 0x2E, (byte) 0x63, (byte) 0x72, (byte) 0x74,
- (byte) 0x30, (byte) 0x2B, (byte) 0x06, (byte) 0x08, (byte) 0x2B, (byte) 0x06,
- (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x07, (byte) 0x30, (byte) 0x01,
- (byte) 0x86, (byte) 0x1F, (byte) 0x68, (byte) 0x74, (byte) 0x74, (byte) 0x70,
- (byte) 0x3A, (byte) 0x2F, (byte) 0x2F, (byte) 0x63, (byte) 0x6C, (byte) 0x69,
- (byte) 0x65, (byte) 0x6E, (byte) 0x74, (byte) 0x73, (byte) 0x31, (byte) 0x2E,
- (byte) 0x67, (byte) 0x6F, (byte) 0x6F, (byte) 0x67, (byte) 0x6C, (byte) 0x65,
- (byte) 0x2E, (byte) 0x63, (byte) 0x6F, (byte) 0x6D, (byte) 0x2F, (byte) 0x6F,
- (byte) 0x63, (byte) 0x73, (byte) 0x70, (byte) 0x30, (byte) 0x1D, (byte) 0x06,
- (byte) 0x03, (byte) 0x55, (byte) 0x1D, (byte) 0x0E, (byte) 0x04, (byte) 0x16,
- (byte) 0x04, (byte) 0x14, (byte) 0x3B, (byte) 0x6B, (byte) 0xE0, (byte) 0x9C,
- (byte) 0xC6, (byte) 0xC6, (byte) 0x41, (byte) 0xC8, (byte) 0xEA, (byte) 0x5C,
- (byte) 0xFB, (byte) 0x1A, (byte) 0x58, (byte) 0x15, (byte) 0xC2, (byte) 0x1B,
- (byte) 0x9D, (byte) 0x43, (byte) 0x19, (byte) 0x85, (byte) 0x30, (byte) 0x0C,
- (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1D, (byte) 0x13, (byte) 0x01,
- (byte) 0x01, (byte) 0xFF, (byte) 0x04, (byte) 0x02, (byte) 0x30, (byte) 0x00,
- (byte) 0x30, (byte) 0x1F, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1D,
- (byte) 0x23, (byte) 0x04, (byte) 0x18, (byte) 0x30, (byte) 0x16, (byte) 0x80,
- (byte) 0x14, (byte) 0x4A, (byte) 0xDD, (byte) 0x06, (byte) 0x16, (byte) 0x1B,
- (byte) 0xBC, (byte) 0xF6, (byte) 0x68, (byte) 0xB5, (byte) 0x76, (byte) 0xF5,
- (byte) 0x81, (byte) 0xB6, (byte) 0xBB, (byte) 0x62, (byte) 0x1A, (byte) 0xBA,
- (byte) 0x5A, (byte) 0x81, (byte) 0x2F, (byte) 0x30, (byte) 0x17, (byte) 0x06,
- (byte) 0x03, (byte) 0x55, (byte) 0x1D, (byte) 0x20, (byte) 0x04, (byte) 0x10,
- (byte) 0x30, (byte) 0x0E, (byte) 0x30, (byte) 0x0C, (byte) 0x06, (byte) 0x0A,
- (byte) 0x2B, (byte) 0x06, (byte) 0x01, (byte) 0x04, (byte) 0x01, (byte) 0xD6,
- (byte) 0x79, (byte) 0x02, (byte) 0x05, (byte) 0x01, (byte) 0x30, (byte) 0x30,
- (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1D, (byte) 0x1F, (byte) 0x04,
- (byte) 0x29, (byte) 0x30, (byte) 0x27, (byte) 0x30, (byte) 0x25, (byte) 0xA0,
- (byte) 0x23, (byte) 0xA0, (byte) 0x21, (byte) 0x86, (byte) 0x1F, (byte) 0x68,
- (byte) 0x74, (byte) 0x74, (byte) 0x70, (byte) 0x3A, (byte) 0x2F, (byte) 0x2F,
- (byte) 0x70, (byte) 0x6B, (byte) 0x69, (byte) 0x2E, (byte) 0x67, (byte) 0x6F,
- (byte) 0x6F, (byte) 0x67, (byte) 0x6C, (byte) 0x65, (byte) 0x2E, (byte) 0x63,
- (byte) 0x6F, (byte) 0x6D, (byte) 0x2F, (byte) 0x47, (byte) 0x49, (byte) 0x41,
- (byte) 0x47, (byte) 0x32, (byte) 0x2E, (byte) 0x63, (byte) 0x72, (byte) 0x6C,
- (byte) 0x30, (byte) 0x0D, (byte) 0x06, (byte) 0x09, (byte) 0x2A, (byte) 0x86,
- (byte) 0x48, (byte) 0x86, (byte) 0xF7, (byte) 0x0D, (byte) 0x01, (byte) 0x01,
- (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x82, (byte) 0x01,
- (byte) 0x01, (byte) 0x00, (byte) 0x9A, (byte) 0x39, (byte) 0x70, (byte) 0x81,
- (byte) 0x76, (byte) 0x8A, (byte) 0x94, (byte) 0xCB, (byte) 0x96, (byte) 0xF1,
- (byte) 0xCA, (byte) 0xAF, (byte) 0x96, (byte) 0xAE, (byte) 0x1D, (byte) 0x73,
- (byte) 0xB3, (byte) 0x2C, (byte) 0x82, (byte) 0x16, (byte) 0x29, (byte) 0xB5,
- (byte) 0x3C, (byte) 0x7E, (byte) 0x55, (byte) 0x53, (byte) 0x6F, (byte) 0xB2,
- (byte) 0xBC, (byte) 0x34, (byte) 0x96, (byte) 0xAE, (byte) 0x00, (byte) 0xD8,
- (byte) 0xF2, (byte) 0x26, (byte) 0xD1, (byte) 0x18, (byte) 0x99, (byte) 0x9F,
- (byte) 0x7D, (byte) 0xFD, (byte) 0xEB, (byte) 0xE0, (byte) 0xBB, (byte) 0x9D,
- (byte) 0xE6, (byte) 0x46, (byte) 0xA5, (byte) 0x74, (byte) 0xAB, (byte) 0x3D,
- (byte) 0x93, (byte) 0xC6, (byte) 0x25, (byte) 0x28, (byte) 0x3D, (byte) 0xC8,
- (byte) 0x4C, (byte) 0x6E, (byte) 0xCF, (byte) 0xD1, (byte) 0x84, (byte) 0xFF,
- (byte) 0x46, (byte) 0x4F, (byte) 0x21, (byte) 0x2E, (byte) 0x07, (byte) 0xC4,
- (byte) 0xB8, (byte) 0xB7, (byte) 0x2A, (byte) 0xE5, (byte) 0xC7, (byte) 0x34,
- (byte) 0xC6, (byte) 0xA9, (byte) 0x84, (byte) 0xE3, (byte) 0x6C, (byte) 0x49,
- (byte) 0xF8, (byte) 0x4A, (byte) 0x36, (byte) 0xBB, (byte) 0x3A, (byte) 0xBD,
- (byte) 0xAD, (byte) 0x8A, (byte) 0x2B, (byte) 0x73, (byte) 0x97, (byte) 0xA6,
- (byte) 0x30, (byte) 0x2C, (byte) 0x5F, (byte) 0xE4, (byte) 0xBD, (byte) 0x13,
- (byte) 0x24, (byte) 0xE5, (byte) 0xD9, (byte) 0xA8, (byte) 0x74, (byte) 0x29,
- (byte) 0x38, (byte) 0x47, (byte) 0x2E, (byte) 0xA6, (byte) 0xD6, (byte) 0x50,
- (byte) 0xE0, (byte) 0xE8, (byte) 0xDD, (byte) 0x60, (byte) 0xC7, (byte) 0xD2,
- (byte) 0xC6, (byte) 0x4E, (byte) 0x54, (byte) 0xCE, (byte) 0xE7, (byte) 0x94,
- (byte) 0x84, (byte) 0x0D, (byte) 0xE8, (byte) 0x81, (byte) 0x92, (byte) 0x91,
- (byte) 0x71, (byte) 0x19, (byte) 0x1D, (byte) 0x07, (byte) 0x75, (byte) 0x9E,
- (byte) 0x59, (byte) 0x1A, (byte) 0x7E, (byte) 0x9D, (byte) 0x84, (byte) 0x61,
- (byte) 0xC7, (byte) 0x84, (byte) 0xAD, (byte) 0xA3, (byte) 0x6A, (byte) 0xED,
- (byte) 0xD8, (byte) 0x0D, (byte) 0x0C, (byte) 0x2A, (byte) 0x66, (byte) 0x3D,
- (byte) 0xD7, (byte) 0xAE, (byte) 0x46, (byte) 0x1D, (byte) 0x4A, (byte) 0x8C,
- (byte) 0x2B, (byte) 0xD6, (byte) 0x1A, (byte) 0x69, (byte) 0x71, (byte) 0xC3,
- (byte) 0x5E, (byte) 0xA0, (byte) 0x6E, (byte) 0xED, (byte) 0x27, (byte) 0x9F,
- (byte) 0xAF, (byte) 0x5B, (byte) 0x92, (byte) 0xA0, (byte) 0x03, (byte) 0xFD,
- (byte) 0x83, (byte) 0x22, (byte) 0x09, (byte) 0x29, (byte) 0xE8, (byte) 0xA1,
- (byte) 0x32, (byte) 0x2B, (byte) 0xEC, (byte) 0x1A, (byte) 0xA2, (byte) 0x75,
- (byte) 0x4C, (byte) 0x3E, (byte) 0x99, (byte) 0x71, (byte) 0xCE, (byte) 0x8B,
- (byte) 0x31, (byte) 0xEF, (byte) 0x9D, (byte) 0x37, (byte) 0x63, (byte) 0xFC,
- (byte) 0x71, (byte) 0x91, (byte) 0x10, (byte) 0x1E, (byte) 0xD0, (byte) 0xF5,
- (byte) 0xCB, (byte) 0x6F, (byte) 0x7A, (byte) 0xBA, (byte) 0x5E, (byte) 0x0C,
- (byte) 0x8A, (byte) 0xFA, (byte) 0xA4, (byte) 0xDE, (byte) 0x36, (byte) 0xAD,
- (byte) 0x51, (byte) 0x52, (byte) 0xFC, (byte) 0xFE, (byte) 0x10, (byte) 0xB0,
- (byte) 0x81, (byte) 0xC8, (byte) 0x7D, (byte) 0x03, (byte) 0xC3, (byte) 0xB8,
- (byte) 0x3C, (byte) 0x66, (byte) 0x6A, (byte) 0xF5, (byte) 0x6A, (byte) 0x81,
- (byte) 0x7C, (byte) 0x45, (byte) 0xA6, (byte) 0x23, (byte) 0x21, (byte) 0xE1,
- (byte) 0xD5, (byte) 0xD3, (byte) 0xED, (byte) 0x6E, (byte) 0x0D, (byte) 0x65,
- (byte) 0x39, (byte) 0x77, (byte) 0x58, (byte) 0x09, (byte) 0x6B, (byte) 0x63,
- (byte) 0xA4, (byte) 0x02, (byte) 0x04, (byte) 0x00, (byte) 0xA5, (byte) 0x03,
- (byte) 0x02, (byte) 0x01, (byte) 0x14, (byte) 0xA9, (byte) 0x05, (byte) 0x02,
- (byte) 0x03, (byte) 0x01, (byte) 0x89, (byte) 0xC0, (byte) 0xAA, (byte) 0x81,
- (byte) 0xA7, (byte) 0x04, (byte) 0x81, (byte) 0xA4, (byte) 0x1C, (byte) 0x14,
- (byte) 0x42, (byte) 0xFA, (byte) 0x1E, (byte) 0x3A, (byte) 0x4D, (byte) 0x0A,
- (byte) 0x83, (byte) 0x7E, (byte) 0x92, (byte) 0x61, (byte) 0x37, (byte) 0x0B,
- (byte) 0x12, (byte) 0x45, (byte) 0xEA, (byte) 0x2B, (byte) 0x03, (byte) 0x81,
- (byte) 0x7C, (byte) 0x5F, (byte) 0x6F, (byte) 0x13, (byte) 0x82, (byte) 0x97,
- (byte) 0xD0, (byte) 0xDC, (byte) 0x5E, (byte) 0x2F, (byte) 0x08, (byte) 0xDC,
- (byte) 0x0D, (byte) 0x3A, (byte) 0x6C, (byte) 0xBA, (byte) 0x1D, (byte) 0xEA,
- (byte) 0x5C, (byte) 0x46, (byte) 0x99, (byte) 0xF7, (byte) 0xDD, (byte) 0xAB,
- (byte) 0xD4, (byte) 0xDD, (byte) 0xFC, (byte) 0x54, (byte) 0x37, (byte) 0x32,
- (byte) 0x4B, (byte) 0xA3, (byte) 0xFB, (byte) 0x23, (byte) 0xA1, (byte) 0xC1,
- (byte) 0x60, (byte) 0xDF, (byte) 0x41, (byte) 0xB0, (byte) 0xD1, (byte) 0xCC,
- (byte) 0xDF, (byte) 0xAD, (byte) 0xB3, (byte) 0x66, (byte) 0x76, (byte) 0x36,
- (byte) 0xEC, (byte) 0x6A, (byte) 0x53, (byte) 0xC3, (byte) 0xE2, (byte) 0xB0,
- (byte) 0x77, (byte) 0xBE, (byte) 0x75, (byte) 0x08, (byte) 0xBA, (byte) 0x17,
- (byte) 0x14, (byte) 0xFA, (byte) 0x1A, (byte) 0x30, (byte) 0xE7, (byte) 0xB9,
- (byte) 0xED, (byte) 0xD6, (byte) 0xC1, (byte) 0xA5, (byte) 0x7A, (byte) 0x2B,
- (byte) 0xA3, (byte) 0xA3, (byte) 0xDD, (byte) 0xDC, (byte) 0x14, (byte) 0xDB,
- (byte) 0x7F, (byte) 0xF4, (byte) 0xF3, (byte) 0xAF, (byte) 0xCF, (byte) 0x0A,
- (byte) 0xD3, (byte) 0xAC, (byte) 0x84, (byte) 0x39, (byte) 0x30, (byte) 0xCA,
- (byte) 0x3C, (byte) 0xD8, (byte) 0xF7, (byte) 0xFA, (byte) 0x29, (byte) 0xDB,
- (byte) 0x31, (byte) 0xA5, (byte) 0x62, (byte) 0x82, (byte) 0xD2, (byte) 0xB8,
- (byte) 0x3C, (byte) 0xBC, (byte) 0x8F, (byte) 0xAB, (byte) 0xE4, (byte) 0xE8,
- (byte) 0xA7, (byte) 0x2C, (byte) 0xEF, (byte) 0xC7, (byte) 0xD5, (byte) 0x12,
- (byte) 0x16, (byte) 0x04, (byte) 0x6F, (byte) 0xCA, (byte) 0xEA, (byte) 0x31,
- (byte) 0x9F, (byte) 0x41, (byte) 0xE0, (byte) 0x6F, (byte) 0xE4, (byte) 0x74,
- (byte) 0x03, (byte) 0x78, (byte) 0xFA, (byte) 0x48, (byte) 0xB4, (byte) 0x6E,
- (byte) 0xC8, (byte) 0xE7, (byte) 0x40, (byte) 0x8B, (byte) 0x88, (byte) 0x2F,
- (byte) 0xED, (byte) 0x8E, (byte) 0x68, (byte) 0x96, (byte) 0x2C, (byte) 0xA7,
- (byte) 0xB6, (byte) 0x03, (byte) 0x01, (byte) 0x01, (byte) 0x00};
+public abstract class AbstractSessionContextTest<T extends AbstractSessionContext> {
+ private T context;
- private static final byte[] DUMMY_CERT =
- new byte[] {(byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x58, (byte) 0x30,
- (byte) 0x82, (byte) 0x01, (byte) 0xC1, (byte) 0xA0, (byte) 0x03, (byte) 0x02,
- (byte) 0x01, (byte) 0x02, (byte) 0x02, (byte) 0x09, (byte) 0x00, (byte) 0xFB,
- (byte) 0xB0, (byte) 0x4C, (byte) 0x2E, (byte) 0xAB, (byte) 0x10, (byte) 0x9B,
- (byte) 0x0C, (byte) 0x30, (byte) 0x0D, (byte) 0x06, (byte) 0x09, (byte) 0x2A,
- (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xF7, (byte) 0x0D, (byte) 0x01,
- (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x30, (byte) 0x45,
- (byte) 0x31, (byte) 0x0B, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03,
- (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x41,
- (byte) 0x55, (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06,
- (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x0C, (byte) 0x0A,
- (byte) 0x53, (byte) 0x6F, (byte) 0x6D, (byte) 0x65, (byte) 0x2D, (byte) 0x53,
- (byte) 0x74, (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x31, (byte) 0x21,
- (byte) 0x30, (byte) 0x1F, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
- (byte) 0x0A, (byte) 0x0C, (byte) 0x18, (byte) 0x49, (byte) 0x6E, (byte) 0x74,
- (byte) 0x65, (byte) 0x72, (byte) 0x6E, (byte) 0x65, (byte) 0x74, (byte) 0x20,
- (byte) 0x57, (byte) 0x69, (byte) 0x64, (byte) 0x67, (byte) 0x69, (byte) 0x74,
- (byte) 0x73, (byte) 0x20, (byte) 0x50, (byte) 0x74, (byte) 0x79, (byte) 0x20,
- (byte) 0x4C, (byte) 0x74, (byte) 0x64, (byte) 0x30, (byte) 0x1E, (byte) 0x17,
- (byte) 0x0D, (byte) 0x31, (byte) 0x34, (byte) 0x30, (byte) 0x34, (byte) 0x32,
- (byte) 0x33, (byte) 0x32, (byte) 0x30, (byte) 0x35, (byte) 0x30, (byte) 0x34,
- (byte) 0x30, (byte) 0x5A, (byte) 0x17, (byte) 0x0D, (byte) 0x31, (byte) 0x37,
- (byte) 0x30, (byte) 0x34, (byte) 0x32, (byte) 0x32, (byte) 0x32, (byte) 0x30,
- (byte) 0x35, (byte) 0x30, (byte) 0x34, (byte) 0x30, (byte) 0x5A, (byte) 0x30,
- (byte) 0x45, (byte) 0x31, (byte) 0x0B, (byte) 0x30, (byte) 0x09, (byte) 0x06,
- (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02,
- (byte) 0x41, (byte) 0x55, (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11,
- (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x0C,
- (byte) 0x0A, (byte) 0x53, (byte) 0x6F, (byte) 0x6D, (byte) 0x65, (byte) 0x2D,
- (byte) 0x53, (byte) 0x74, (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x31,
- (byte) 0x21, (byte) 0x30, (byte) 0x1F, (byte) 0x06, (byte) 0x03, (byte) 0x55,
- (byte) 0x04, (byte) 0x0A, (byte) 0x0C, (byte) 0x18, (byte) 0x49, (byte) 0x6E,
- (byte) 0x74, (byte) 0x65, (byte) 0x72, (byte) 0x6E, (byte) 0x65, (byte) 0x74,
- (byte) 0x20, (byte) 0x57, (byte) 0x69, (byte) 0x64, (byte) 0x67, (byte) 0x69,
- (byte) 0x74, (byte) 0x73, (byte) 0x20, (byte) 0x50, (byte) 0x74, (byte) 0x79,
- (byte) 0x20, (byte) 0x4C, (byte) 0x74, (byte) 0x64, (byte) 0x30, (byte) 0x81,
- (byte) 0x9F, (byte) 0x30, (byte) 0x0D, (byte) 0x06, (byte) 0x09, (byte) 0x2A,
- (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xF7, (byte) 0x0D, (byte) 0x01,
- (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x81,
- (byte) 0x8D, (byte) 0x00, (byte) 0x30, (byte) 0x81, (byte) 0x89, (byte) 0x02,
- (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0xD8, (byte) 0x2B, (byte) 0xC8,
- (byte) 0xA6, (byte) 0x32, (byte) 0xE4, (byte) 0x62, (byte) 0xFF, (byte) 0x4D,
- (byte) 0xF3, (byte) 0xD0, (byte) 0xAD, (byte) 0x59, (byte) 0x8B, (byte) 0x45,
- (byte) 0xA7, (byte) 0xBD, (byte) 0xF1, (byte) 0x47, (byte) 0xBF, (byte) 0x09,
- (byte) 0x58, (byte) 0x7B, (byte) 0x22, (byte) 0xBD, (byte) 0x35, (byte) 0xAE,
- (byte) 0x97, (byte) 0x25, (byte) 0x86, (byte) 0x94, (byte) 0xA0, (byte) 0x80,
- (byte) 0xC0, (byte) 0xB4, (byte) 0x1F, (byte) 0x76, (byte) 0x91, (byte) 0x67,
- (byte) 0x46, (byte) 0x31, (byte) 0xD0, (byte) 0x10, (byte) 0x84, (byte) 0xB7,
- (byte) 0x22, (byte) 0x1E, (byte) 0x70, (byte) 0x23, (byte) 0x91, (byte) 0x72,
- (byte) 0xC8, (byte) 0xE9, (byte) 0x6D, (byte) 0x79, (byte) 0x3A, (byte) 0x85,
- (byte) 0x77, (byte) 0x80, (byte) 0x0F, (byte) 0xC4, (byte) 0x95, (byte) 0x16,
- (byte) 0x75, (byte) 0xC5, (byte) 0x4A, (byte) 0x71, (byte) 0x4C, (byte) 0xC8,
- (byte) 0x63, (byte) 0x3F, (byte) 0xA3, (byte) 0xF2, (byte) 0x63, (byte) 0x9C,
- (byte) 0x2A, (byte) 0x4F, (byte) 0x9A, (byte) 0xFA, (byte) 0xCB, (byte) 0xC1,
- (byte) 0x71, (byte) 0x6E, (byte) 0x28, (byte) 0x85, (byte) 0x28, (byte) 0xA0,
- (byte) 0x27, (byte) 0x1E, (byte) 0x65, (byte) 0x1C, (byte) 0xAE, (byte) 0x07,
- (byte) 0xD5, (byte) 0x5B, (byte) 0x6F, (byte) 0x2D, (byte) 0x43, (byte) 0xED,
- (byte) 0x2B, (byte) 0x90, (byte) 0xB1, (byte) 0x8C, (byte) 0xAF, (byte) 0x24,
- (byte) 0x6D, (byte) 0xAE, (byte) 0xE9, (byte) 0x17, (byte) 0x3A, (byte) 0x05,
- (byte) 0xC1, (byte) 0xBF, (byte) 0xB8, (byte) 0x1C, (byte) 0xAE, (byte) 0x65,
- (byte) 0x3B, (byte) 0x1B, (byte) 0x58, (byte) 0xC2, (byte) 0xD9, (byte) 0xAE,
- (byte) 0xD6, (byte) 0xAA, (byte) 0x67, (byte) 0x88, (byte) 0xF1, (byte) 0x02,
- (byte) 0x03, (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0xA3, (byte) 0x50,
- (byte) 0x30, (byte) 0x4E, (byte) 0x30, (byte) 0x1D, (byte) 0x06, (byte) 0x03,
- (byte) 0x55, (byte) 0x1D, (byte) 0x0E, (byte) 0x04, (byte) 0x16, (byte) 0x04,
- (byte) 0x14, (byte) 0x8B, (byte) 0x75, (byte) 0xD5, (byte) 0xAC, (byte) 0xCB,
- (byte) 0x08, (byte) 0xBE, (byte) 0x0E, (byte) 0x1F, (byte) 0x65, (byte) 0xB7,
- (byte) 0xFA, (byte) 0x56, (byte) 0xBE, (byte) 0x6C, (byte) 0xA7, (byte) 0x75,
- (byte) 0xDA, (byte) 0x85, (byte) 0xAF, (byte) 0x30, (byte) 0x1F, (byte) 0x06,
- (byte) 0x03, (byte) 0x55, (byte) 0x1D, (byte) 0x23, (byte) 0x04, (byte) 0x18,
- (byte) 0x30, (byte) 0x16, (byte) 0x80, (byte) 0x14, (byte) 0x8B, (byte) 0x75,
- (byte) 0xD5, (byte) 0xAC, (byte) 0xCB, (byte) 0x08, (byte) 0xBE, (byte) 0x0E,
- (byte) 0x1F, (byte) 0x65, (byte) 0xB7, (byte) 0xFA, (byte) 0x56, (byte) 0xBE,
- (byte) 0x6C, (byte) 0xA7, (byte) 0x75, (byte) 0xDA, (byte) 0x85, (byte) 0xAF,
- (byte) 0x30, (byte) 0x0C, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1D,
- (byte) 0x13, (byte) 0x04, (byte) 0x05, (byte) 0x30, (byte) 0x03, (byte) 0x01,
- (byte) 0x01, (byte) 0xFF, (byte) 0x30, (byte) 0x0D, (byte) 0x06, (byte) 0x09,
- (byte) 0x2A, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xF7, (byte) 0x0D,
- (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x03,
- (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0x3B, (byte) 0xE8, (byte) 0x78,
- (byte) 0x6D, (byte) 0x95, (byte) 0xD6, (byte) 0x3D, (byte) 0x6A, (byte) 0xF7,
- (byte) 0x13, (byte) 0x19, (byte) 0x2C, (byte) 0x1B, (byte) 0xC2, (byte) 0x88,
- (byte) 0xAE, (byte) 0x22, (byte) 0xAB, (byte) 0xF4, (byte) 0x8D, (byte) 0x32,
- (byte) 0xF5, (byte) 0x7C, (byte) 0x71, (byte) 0x67, (byte) 0xCF, (byte) 0x2D,
- (byte) 0xD1, (byte) 0x1C, (byte) 0xC2, (byte) 0xC3, (byte) 0x87, (byte) 0xE2,
- (byte) 0xE9, (byte) 0xBE, (byte) 0x89, (byte) 0x5C, (byte) 0xE4, (byte) 0x34,
- (byte) 0xAB, (byte) 0x48, (byte) 0x91, (byte) 0xC2, (byte) 0x3F, (byte) 0x95,
- (byte) 0xAE, (byte) 0x2B, (byte) 0x47, (byte) 0x9E, (byte) 0x25, (byte) 0x78,
- (byte) 0x6B, (byte) 0x4F, (byte) 0x9A, (byte) 0x10, (byte) 0xA4, (byte) 0x72,
- (byte) 0xFD, (byte) 0xCF, (byte) 0xF7, (byte) 0x02, (byte) 0x0C, (byte) 0xB0,
- (byte) 0x0A, (byte) 0x08, (byte) 0xA4, (byte) 0x5A, (byte) 0xE2, (byte) 0xE5,
- (byte) 0x74, (byte) 0x7E, (byte) 0x11, (byte) 0x1D, (byte) 0x39, (byte) 0x60,
- (byte) 0x6A, (byte) 0xC9, (byte) 0x1F, (byte) 0x69, (byte) 0xF3, (byte) 0x2E,
- (byte) 0x63, (byte) 0x26, (byte) 0xDC, (byte) 0x9E, (byte) 0xEF, (byte) 0x6B,
- (byte) 0x7A, (byte) 0x0A, (byte) 0xE1, (byte) 0x54, (byte) 0x57, (byte) 0x98,
- (byte) 0xAA, (byte) 0x72, (byte) 0x91, (byte) 0x78, (byte) 0x04, (byte) 0x7E,
- (byte) 0x1F, (byte) 0x8F, (byte) 0x65, (byte) 0x4D, (byte) 0x1F, (byte) 0x0B,
- (byte) 0x12, (byte) 0xAC, (byte) 0x9C, (byte) 0x24, (byte) 0x0F, (byte) 0x84,
- (byte) 0x14, (byte) 0x1A, (byte) 0x55, (byte) 0x2D, (byte) 0x1F, (byte) 0xBB,
- (byte) 0xF0, (byte) 0x9D, (byte) 0x09, (byte) 0xB2, (byte) 0x08, (byte) 0x5C,
- (byte) 0x59, (byte) 0x32, (byte) 0x65, (byte) 0x80, (byte) 0x26};
-
- private static final byte[] DUMMY_OCSP_DATA = new byte[1];
-
- private static final byte[] DUMMY_TLS_SCT_DATA = new byte[1];
-
- private static ClientSessionContext clientCtx;
-
- @BeforeClass
- public static void setup() {
- clientCtx = new ClientSessionContext();
+ @Before
+ public void setup() {
+ context = newContext();
}
- @After
- public void tearDown() throws Exception {
- assertEquals(0, NativeCrypto.ERR_peek_last_error());
- }
+ abstract T newContext();
+ abstract int size(T context);
+ abstract SslSessionWrapper getCachedSession(T context, SslSessionWrapper s);
- private static TestSessionBuilder getType1() {
- return new TestSessionBuilder()
- .setType(0x01)
- .setSessionData(kOpenSSLSession)
- .addCertificate(DUMMY_CERT);
- }
+ @Test
+ public void testSimpleAddition() {
+ SslSessionWrapper a = newSession("a");
+ SslSessionWrapper b = newSession("b");
- private static TestSessionBuilder getType2() {
- return new TestSessionBuilder()
- .setType(0x02)
- .setSessionData(kOpenSSLSession)
- .addCertificate(DUMMY_CERT)
- .addOcspData(DUMMY_OCSP_DATA);
- }
+ context.cacheSession(a);
+ assertSessionContextContents(toArray(a), toArray(b));
- private static TestSessionBuilder getType3() {
- return new TestSessionBuilder()
- .setType(0x03)
- .setSessionData(kOpenSSLSession)
- .addCertificate(DUMMY_CERT)
- .addOcspData(DUMMY_OCSP_DATA)
- .setTlsSctData(DUMMY_TLS_SCT_DATA);
+ context.cacheSession(b);
+ assertSessionContextContents(toArray(a, b), toArray());
}
@Test
- public void toSession_EmptyArray_Invalid_Failure() throws Exception {
- assertInvalidSession(new byte[0]);
+ public void testTrimToSize() {
+ SslSessionWrapper a = newSession("a");
+ SslSessionWrapper b = newSession("b");
+ SslSessionWrapper c = newSession("c");
+ SslSessionWrapper d = newSession("d");
+
+ context.cacheSession(a);
+ context.cacheSession(b);
+ context.cacheSession(c);
+ context.cacheSession(d);
+ assertSessionContextContents(toArray(a, b, c, d), toArray());
+
+ context.setSessionCacheSize(2);
+ assertSessionContextContents(toArray(c, d), toArray(a, b));
}
@Test
- public void toSession_Type1_Valid_Success() throws Exception {
- assertValidSession(getType1().build());
+ public void testImplicitRemovalOfOldest() {
+ context.setSessionCacheSize(2);
+ SslSessionWrapper a = newSession("a");
+ SslSessionWrapper b = newSession("b");
+ SslSessionWrapper c = newSession("c");
+ SslSessionWrapper d = newSession("d");
+
+ context.cacheSession(a);
+ assertSessionContextContents(toArray(a), toArray(b, c, d));
+
+ context.cacheSession(b);
+ assertSessionContextContents(toArray(a, b), toArray(c, d));
+
+ context.cacheSession(c);
+ assertSessionContextContents(toArray(b, c), toArray(a, d));
+
+ context.cacheSession(d);
+ assertSessionContextContents(toArray(c, d), toArray(a, b));
}
@Test
- public void toSession_Type2_Valid_Success() throws Exception {
- assertValidSession(getType2().build());
+ public void testSerializeSession() throws Exception {
+ Certificate mockCert = mock(Certificate.class);
+ when(mockCert.getEncoded()).thenReturn(new byte[] {0x05, 0x06, 0x07, 0x10});
+
+ byte[] encodedBytes = new byte[] {0x01, 0x02, 0x03};
+ SslSessionWrapper session = new MockSessionBuilder()
+ .id(new byte[] {0x11, 0x09, 0x03, 0x20})
+ .host("ssl.example.com")
+ .encodedBytes(encodedBytes)
+ .build();
+
+ SSLClientSessionCache mockCache = mock(SSLClientSessionCache.class);
+ ClientSessionContext context = new ClientSessionContext();
+ context.setPersistentCache(mockCache);
+
+ context.cacheSession(session);
+ verify(mockCache).putSessionData(any(SSLSession.class), same(encodedBytes));
}
- @Test
- public void toSession_Type3_Valid_Success() throws Exception {
- assertValidSession(getType3().build());
- }
+ private void assertSessionContextContents(
+ SslSessionWrapper[] contains, SslSessionWrapper[] exludes) {
+ assertEquals(contains.length, size(context));
- private void assertTruncatedSessionFails(byte[] validSession) {
- for (int i = 0; i < validSession.length - 1; i++) {
- byte[] truncatedSession = new byte[i];
- System.arraycopy(validSession, 0, truncatedSession, 0, i);
- assertNull("Truncating to " + i + " bytes of " + validSession.length
- + " should not succeed",
- clientCtx.toSession(truncatedSession, "www.google.com", 443));
+ for (SslSessionWrapper s : contains) {
+ assertSame(s.getPeerHost(), s, getCachedSession(context, s));
+ }
+ for (SslSessionWrapper s : exludes) {
+ assertNull(s.getPeerHost(), getCachedSession(context, s));
}
}
- @Test
- public void toSession_Type3_Truncated_Failure() throws Exception {
- assertTruncatedSessionFails(getType3().build());
+ private static SslSessionWrapper[] toArray(SslSessionWrapper... sessions) {
+ return sessions;
}
- private static void assertValidSession(byte[] data) {
- assertNotNull(clientCtx.toSession(data, "www.google.com", 443));
- }
-
- private static void assertInvalidSession(byte[] data) {
- assertNull(clientCtx.toSession(data, "www.google.com", 443));
- }
-
- @Test
- public void toSession_UnknownType_Failure() throws Exception {
- assertInvalidSession(getType3().setType((byte) 0xEE).build());
- }
-
- @Test
- public void toSession_CertificatesCountTooLarge_Failure() throws Exception {
- assertInvalidSession(getType3().setCertificatesLength(16834).build());
- }
-
- @Test
- public void toSession_CertificatesCountNegative_Failure() throws Exception {
- assertInvalidSession(getType3().setCertificatesLength(-1).build());
- }
-
- @Test
- public void toSession_CertificateSizeNegative_Failure() throws Exception {
- assertInvalidSession(getType3().setCertificateLength(0, -1).build());
- }
-
- @Test
- public void toSession_CertificateSizeTooLarge_Failure() throws Exception {
- assertInvalidSession(getType3().setCertificateLength(0, 16834).build());
- }
-
- @Test
- public void toSession_SessionDataSizeTooLarge_Failure() throws Exception {
- assertInvalidSession(getType3().setSessionDataLength(16834).build());
- }
-
- @Test
- public void toSession_SessionDataSizeNegative_Failure() throws Exception {
- assertInvalidSession(getType3().setSessionDataLength(-1).build());
- }
-
- @Test
- public void toSession_OcspDatasNumberTooMany_Failure() throws Exception {
- assertInvalidSession(getType3().setOcspDatasLength(32791).build());
- }
-
- @Test
- public void toSession_OcspDatasNumberNegative_Failure() throws Exception {
- assertInvalidSession(getType3().setOcspDatasLength(-1).build());
- }
-
- @Test
- public void toSession_OcspDataSizeNegative_Failure() throws Exception {
- assertInvalidSession(getType3().setOcspDataLength(0, -1).build());
- }
-
- @Test
- public void toSession_OcspDataSizeTooLarge_Failure() throws Exception {
- assertInvalidSession(getType3().setOcspDataLength(0, 92948).build());
- }
-
- @Test
- public void toSession_TlsSctDataSizeNegative_Failure() throws Exception {
- assertInvalidSession(getType3().setTlsSctDataLength(-1).build());
- }
-
- @Test
- public void toSession_TlsSctDataSizeTooLarge_Failure() throws Exception {
- assertInvalidSession(getType3().setTlsSctDataLength(931148).build());
- }
-
- @Test
- public void toSession_Type2OcspDataEmpty_Success() throws Exception {
- assertValidSession(getType1().setType(0x02).setOcspDataEmpty().build());
- }
-
- @Test
- public void toSession_Type3TlsSctDataEmpty_Success() throws Exception {
- assertValidSession(getType2().setType(0x03).setTlsSctDataEmpty().build());
- }
-
- @Test
- public void toSession_Type3OcspAndTlsSctDataEmpty_Success() throws Exception {
- assertValidSession(
- getType1().setType(0x03).setOcspDataEmpty().setTlsSctDataEmpty().build());
- }
-
- private static void assertTrailingDataFails(byte[] validSession) {
- byte[] invalidSession = new byte[validSession.length + 1];
- System.arraycopy(validSession, 0, invalidSession, 0, validSession.length);
- assertInvalidSession(invalidSession);
- }
-
- @Test
- public void toSession_Type1TrailingData_Failure() throws Exception {
- assertTrailingDataFails(getType1().build());
- }
-
- @Test
- public void toSession_Type2TrailingData_Failure() throws Exception {
- assertTrailingDataFails(getType2().build());
- }
-
- @Test
- public void toSession_Type3TrailingData_Failure() throws Exception {
- assertTrailingDataFails(getType3().build());
- }
-
- @Test
- public void test_reserializableFromByteArray_roundTrip_type1() throws Exception {
- // Converting OPEN_SSL (type 1) -> OPEN_SSL_WITH_TLS_SCT (type 3) adds
- // eight zero-bytes:
- // 1.) 4 bytes for int32 value 0 == countOcspResponses
- // 2.) 4 bytes for int32 value 0 == tlsSctDataLength
- // since OPEN_SSL (type 1) cannot contain OSCP or TLS SCT data.
- check_reserializableFromByteArray_roundTrip(getType1().build(), new byte[8]);
- }
-
- @Test
- public void test_reserializableFromByteArray_roundTrip_type2() throws Exception {
- // Converting OPEN_SSL_WITH_OCSP (type 2) -> OPEN_SSL_WITH_TLS_SCT (type 3) adds
- // four zero-bytes for int32 value 0 == tlsSctDataLength
- // since OPEN_SSL_WITH_OCSP (type 2) cannot contain TLS SCT data.
- check_reserializableFromByteArray_roundTrip(getType2().build(), new byte[4]);
- }
-
- @Test
- public void test_reserializableFromByteArray_roundTrip_type3() throws Exception {
- check_reserializableFromByteArray_roundTrip(getType3().build(), new byte[0]);
- }
-
- private static void check_reserializableFromByteArray_roundTrip(
- byte[] data, byte[] expectedTrailingBytesAfterReserialization) throws Exception {
- SSLSession session = clientCtx.toSession(data, "www.example.com", 12345);
- byte[] sessionBytes = clientCtx.toBytes(session);
-
- SSLSession session2 = clientCtx.toSession(sessionBytes, "www.example.com", 12345);
- byte[] sessionBytes2 = clientCtx.toBytes(session);
-
- assertSSLSessionEquals(session, session2);
- assertByteArrayEquals(sessionBytes, sessionBytes2);
-
- assertEquals("www.example.com", session.getPeerHost());
- assertEquals(12345, session.getPeerPort());
- assertTrue(sessionBytes.length >= data.length);
-
- byte[] expectedReserializedData = concat(data, expectedTrailingBytesAfterReserialization);
- // AbstractSessionContext.toBytes() always writes type 3 == OPEN_SSL_WITH_TLS_SCT
- expectedReserializedData[3] = 3;
- assertByteArrayEquals(expectedReserializedData, sessionBytes);
- }
-
- private static byte[] concat(byte[] a, byte[] b) {
- byte[] result = new byte[a.length + b.length];
- System.arraycopy(a, 0, result, 0, a.length);
- System.arraycopy(b, 0, result, a.length, b.length);
- return result;
- }
-
- private static void assertSSLSessionEquals(SSLSession a, SSLSession b) throws Exception {
- assertEquals(a.getApplicationBufferSize(), b.getApplicationBufferSize());
- assertEquals(a.getCipherSuite(), b.getCipherSuite());
- assertEquals(a.getCreationTime(), b.getCreationTime());
- assertByteArrayEquals(a.getId(), b.getId());
- assertEquals(a.getLastAccessedTime(), b.getLastAccessedTime());
- assertArrayEquals(a.getLocalCertificates(), b.getLocalCertificates());
- assertEquals(a.getLocalPrincipal(), b.getLocalPrincipal());
- assertArrayEquals(a.getPeerCertificateChain(), b.getPeerCertificateChain());
- assertArrayEquals(a.getPeerCertificates(), b.getPeerCertificates());
- assertEquals(a.getPeerHost(), b.getPeerHost());
- assertEquals(a.getPeerPort(), b.getPeerPort());
- assertEquals(a.getPeerPrincipal(), b.getPeerPrincipal());
- assertEquals(a.getProtocol(), b.getProtocol());
- assertEquals(getValueMap(a), getValueMap(b));
- assertEquals(a.isValid(), b.isValid());
-
- assertEquals(a.getClass(), b.getClass());
-
- // Could potentially cast to AbstractOpenSSLSession here and compare additional fields.
- }
-
- private static Map<String, Object> getValueMap(SSLSession sslSession) {
- Map<String, Object> result = new HashMap<>();
- for (String valueName : sslSession.getValueNames()) {
- result.put(valueName, sslSession.getValue(valueName));
- }
- return Collections.unmodifiableMap(result);
- }
-
- private static <T> void assertArrayEquals(T[] expected, T[] actual) {
- assertTrue("Expected " + Arrays.toString(expected) + ", got " + Arrays.toString(actual),
- Arrays.equals(expected, actual));
- }
-
- private static void assertByteArrayEquals(byte[] expected, byte[] actual) {
- // If running on OpenJDK 8+, could use java.util.Base64 for better failure messages:
- // assertEquals(Base64.encode(expected), Base64.encode(actual));
- assertTrue("Expected " + Arrays.toString(expected) + ", got " + Arrays.toString(actual),
- Arrays.equals(expected, actual));
+ private SslSessionWrapper newSession(String host) {
+ return new MockSessionBuilder().host(host).build();
}
}
diff --git a/openjdk/src/test/java/org/conscrypt/ClientSessionContextTest.java b/openjdk/src/test/java/org/conscrypt/ClientSessionContextTest.java
index f214d7b..709b893 100644
--- a/openjdk/src/test/java/org/conscrypt/ClientSessionContextTest.java
+++ b/openjdk/src/test/java/org/conscrypt/ClientSessionContextTest.java
@@ -16,135 +16,36 @@
package org.conscrypt;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import static org.conscrypt.MockSessionBuilder.DEFAULT_PORT;
-import java.security.cert.Certificate;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.HashSet;
-import java.util.Set;
-import javax.net.ssl.SSLSession;
-import junit.framework.TestCase;
-import libcore.javax.net.ssl.FakeSSLSession;
+import java.security.KeyManagementException;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
-public final class ClientSessionContextTest extends TestCase {
+@RunWith(JUnit4.class)
+public class ClientSessionContextTest extends AbstractSessionContextTest<ClientSessionContext> {
- public void testSimpleAddition() {
- ClientSessionContext context = new ClientSessionContext();
- SSLSession a = new ValidSSLSession("a");
- SSLSession b = new ValidSSLSession("b");
-
- context.putSession(a);
- assertSessionContextContents(context, new SSLSession[] { a }, new SSLSession[] { b });
-
- context.putSession(b);
- assertSessionContextContents(context, new SSLSession[] { a, b }, new SSLSession[0]);
+ @Override
+ ClientSessionContext newContext() {
+ return new ClientSessionContext();
}
- public void testTrimToSize() {
- ClientSessionContext context = new ClientSessionContext();
- ValidSSLSession a = new ValidSSLSession("a");
- ValidSSLSession b = new ValidSSLSession("b");
- ValidSSLSession c = new ValidSSLSession("c");
- ValidSSLSession d = new ValidSSLSession("d");
-
- context.putSession(a);
- assertSessionContextContents(context, new SSLSession[] { a }, new SSLSession[] { b, c, d });
-
- context.putSession(b);
- assertSessionContextContents(context, new SSLSession[] { a, b }, new SSLSession[] { c, d });
-
- context.putSession(c);
- assertSessionContextContents(context, new SSLSession[] { a, b, c }, new SSLSession[] { d });
-
- context.putSession(d);
- assertSessionContextContents(context, new SSLSession[] { a, b, c, d }, new SSLSession[0]);
-
- context.setSessionCacheSize(2);
- assertSessionContextContents(context, new SSLSession[] { c, d }, new SSLSession[] { a, b });
+ @Override
+ SslSessionWrapper getCachedSession(ClientSessionContext context, SslSessionWrapper s) {
+ return context.getCachedSession(s.getPeerHost(), DEFAULT_PORT,
+ getDefaultSSLParameters());
}
- public void testImplicitRemovalOfOldest() {
- ClientSessionContext context = new ClientSessionContext();
- context.setSessionCacheSize(2);
- ValidSSLSession a = new ValidSSLSession("a");
- ValidSSLSession b = new ValidSSLSession("b");
- ValidSSLSession c = new ValidSSLSession("c");
- ValidSSLSession d = new ValidSSLSession("d");
-
- context.putSession(a);
- assertSessionContextContents(context, new SSLSession[] { a }, new SSLSession[] { b, c, d });
-
- context.putSession(b);
- assertSessionContextContents(context, new SSLSession[] { a, b }, new SSLSession[] { c, d });
-
- context.putSession(c);
- assertSessionContextContents(context, new SSLSession[] { b, c }, new SSLSession[] { a, d });
-
- context.putSession(d);
- assertSessionContextContents(context, new SSLSession[] { c, d }, new SSLSession[] { a, b });
+ @Override
+ int size(ClientSessionContext context) {
+ return context.size();
}
- public void testSerializeSession_NoStatusResponses() throws Exception {
- OpenSSLSessionImpl mockSession = mock(OpenSSLSessionImpl.class);
- when(mockSession.getId()).thenReturn(new byte[] { 0x11, 0x09, 0x03, 0x20 });
- when(mockSession.getPeerHost()).thenReturn("ssl.example.com");
- when(mockSession.getPeerPort()).thenReturn(443);
- when(mockSession.getEncoded()).thenReturn(new byte[] { 0x01, 0x02, 0x03 });
- when(mockSession.getStatusResponses()).thenReturn(Collections.<byte[]>emptyList());
-
- Certificate mockCert = mock(Certificate.class);
- when(mockCert.getEncoded()).thenReturn(new byte[] { 0x05, 0x06, 0x07, 0x10 });
-
- when(mockSession.getPeerCertificates()).thenReturn(new Certificate[] { mockCert });
-
- SSLClientSessionCache mockCache = mock(SSLClientSessionCache.class);
- ClientSessionContext context = new ClientSessionContext();
- context.setPersistentCache(mockCache);
-
- context.putSession(mockSession);
- verify(mockCache).putSessionData(eq(mockSession), any(byte[].class));
- }
-
-
- private static void assertSessionContextContents(ClientSessionContext context,
- SSLSession[] contains,
- SSLSession[] exludes) {
- assertEquals(contains.length, context.size());
-
- for (SSLSession s : contains) {
- assertSame(s.getPeerHost(), s, context.getSession(s.getId()));
- assertSame(s.getPeerHost(), s, context.getSession(s.getPeerHost(), 443));
- }
- for (SSLSession s : exludes) {
- assertNull(s.getPeerHost(), context.getSession(s.getId()));
- assertNull(s.getPeerHost(), context.getSession(s.getPeerHost(), 443));
- }
-
- Set<SSLSession> sessions = new HashSet<SSLSession>();
- Enumeration<byte[]> ids = context.getIds();
- while (ids.hasMoreElements()) {
- byte[] id = ids.nextElement();
- sessions.add(context.getSession(id));
- }
-
- Set<SSLSession> expected = new HashSet<SSLSession>();
- for (SSLSession s : sessions) {
- expected.add(s);
- }
- assertEquals(expected, sessions);
- }
-
- static class ValidSSLSession extends FakeSSLSession {
- ValidSSLSession(String host) {
- super(host);
- }
- @Override public boolean isValid() {
- return true;
+ private static SSLParametersImpl getDefaultSSLParameters() {
+ try {
+ return SSLParametersImpl.getDefault();
+ } catch (KeyManagementException e) {
+ throw new RuntimeException(e);
}
}
}
diff --git a/openjdk/src/test/java/org/conscrypt/MockSessionBuilder.java b/openjdk/src/test/java/org/conscrypt/MockSessionBuilder.java
new file mode 100644
index 0000000..5fb4caa
--- /dev/null
+++ b/openjdk/src/test/java/org/conscrypt/MockSessionBuilder.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.conscrypt;
+
+import static org.conscrypt.TestUtils.UTF_8;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * Utility class for constructing mock sessions.
+ */
+final class MockSessionBuilder {
+ static final String DEFAULT_CIPHER_SUITE = "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256";
+ static final String DEFAULT_PROTOCOL = TestUtils.PROTOCOL_TLS_V1_2;
+ static final int DEFAULT_PORT = 443;
+
+ private byte[] id;
+ private boolean valid = true;
+ private String host;
+ private int port = DEFAULT_PORT;
+ private String cipherSuite = DEFAULT_CIPHER_SUITE;
+ private String protocol = DEFAULT_PROTOCOL;
+ private byte[] encodedBytes = EmptyArray.BYTE;
+
+ MockSessionBuilder id(byte[] id) {
+ this.id = id;
+ return this;
+ }
+
+ MockSessionBuilder protocol(String protocol) {
+ this.protocol = protocol;
+ return this;
+ }
+
+ MockSessionBuilder host(String host) {
+ this.host = host;
+ return this;
+ }
+
+ MockSessionBuilder port(int port) {
+ this.port = port;
+ return this;
+ }
+
+ MockSessionBuilder valid(boolean valid) {
+ this.valid = valid;
+ return this;
+ }
+
+ MockSessionBuilder cipherSuite(String cipherSuite) {
+ this.cipherSuite = cipherSuite;
+ return this;
+ }
+
+ MockSessionBuilder encodedBytes(byte[] encodedBytes) {
+ this.encodedBytes = encodedBytes;
+ return this;
+ }
+
+ SslSessionWrapper build() {
+ SslSessionWrapper session = mock(SslSessionWrapper.class);
+ byte[] id = this.id == null ? host.getBytes(UTF_8) : this.id;
+ when(session.getId()).thenReturn(id);
+ when(session.isValid()).thenReturn(valid);
+ when(session.getProtocol()).thenReturn(protocol);
+ when(session.getPeerHost()).thenReturn(host);
+ when(session.getPeerPort()).thenReturn(port);
+ when(session.getCipherSuite()).thenReturn(cipherSuite);
+ when(session.toBytes()).thenReturn(encodedBytes);
+ return session;
+ }
+}
diff --git a/openjdk/src/test/java/org/conscrypt/NativeCryptoTest.java b/openjdk/src/test/java/org/conscrypt/NativeCryptoTest.java
index 66faca4..62594bf 100644
--- a/openjdk/src/test/java/org/conscrypt/NativeCryptoTest.java
+++ b/openjdk/src/test/java/org/conscrypt/NativeCryptoTest.java
@@ -35,6 +35,7 @@
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.math.BigInteger;
+import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
@@ -53,6 +54,7 @@
import java.security.spec.ECPrivateKeySpec;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.Callable;
@@ -251,6 +253,14 @@
NativeCrypto.EVP_PKEY_cmp(null, null);
}
+ @Test(expected = NullPointerException.class)
+ public void EVP_PKEY_cmp_withNullShouldThrow() throws Exception {
+ RSAPrivateCrtKey privKey1 = generateRsaKey();
+ NativeRef.EVP_PKEY pkey1 = getRsaPkey(privKey1);
+ assertNotSame(NULL, pkey1);
+ NativeCrypto.EVP_PKEY_cmp(pkey1, null);
+ }
+
@Test
public void test_EVP_PKEY_cmp() throws Exception {
RSAPrivateCrtKey privKey1 = generateRsaKey();
@@ -264,12 +274,6 @@
NativeRef.EVP_PKEY pkey2 = getRsaPkey(generateRsaKey());
assertNotSame(NULL, pkey2);
- try {
- NativeCrypto.EVP_PKEY_cmp(pkey1, null);
- fail("Should throw NullPointerException when arguments are NULL");
- } catch (NullPointerException expected) {
- }
-
assertEquals("Same keys should be the equal", 1, NativeCrypto.EVP_PKEY_cmp(pkey1, pkey1));
assertEquals(
@@ -305,7 +309,7 @@
}
@Test(expected = NullPointerException.class)
- public void SSL_CTX_set_session_id_context_NullSessionIdArgument() throws Exception {
+ public void SSL_CTX_set_session_id_context_withNullShouldThrow() throws Exception {
long c = NativeCrypto.SSL_CTX_new();
try {
NativeCrypto.SSL_CTX_set_session_id_context(c, null);
@@ -314,6 +318,16 @@
}
}
+ @Test(expected = IllegalArgumentException.class)
+ public void test_SSL_CTX_set_session_id_context_withInvalidIdShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ try {
+ NativeCrypto.SSL_CTX_set_session_id_context(c, new byte[33]);
+ } finally {
+ NativeCrypto.SSL_CTX_free(c);
+ }
+ }
+
@Test
public void test_SSL_CTX_set_session_id_context() throws Exception {
byte[] empty = new byte[0];
@@ -322,12 +336,6 @@
try {
NativeCrypto.SSL_CTX_set_session_id_context(c, empty);
NativeCrypto.SSL_CTX_set_session_id_context(c, new byte[32]);
- try {
- NativeCrypto.SSL_CTX_set_session_id_context(c, new byte[33]);
- fail("Expected IllegalArgumentException");
- } catch (IllegalArgumentException expected) {
- // Expected.
- }
} finally {
NativeCrypto.SSL_CTX_free(c);
}
@@ -357,42 +365,55 @@
NativeCrypto.SSL_use_certificate(NULL, null);
}
+ @Test(expected = NullPointerException.class)
+ public void SSL_use_certificate_withNullShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c);
+ try {
+ NativeCrypto.SSL_use_certificate(s, null);
+ } finally {
+ NativeCrypto.SSL_free(s);
+ NativeCrypto.SSL_CTX_free(c);
+ }
+ }
+
@Test
public void test_SSL_use_certificate() throws Exception {
long c = NativeCrypto.SSL_CTX_new();
long s = NativeCrypto.SSL_new(c);
- try {
- NativeCrypto.SSL_use_certificate(s, null);
- fail();
- } catch (NullPointerException expected) {
- }
-
NativeCrypto.SSL_use_certificate(s, getServerCertificates());
NativeCrypto.SSL_free(s);
NativeCrypto.SSL_CTX_free(c);
}
+ @Test(expected = NullPointerException.class)
+ public void SSL_set1_tls_channel_id_withNullChannelShouldThrow() throws Exception {
+ NativeCrypto.SSL_set1_tls_channel_id(NULL, null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_set1_tls_channel_id_withNullKeyShouldThrow() throws Exception {
+ initChannelIdKey();
+
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c);
+ try {
+ NativeCrypto.SSL_set1_tls_channel_id(s, null);
+ } finally {
+ NativeCrypto.SSL_free(s);
+ NativeCrypto.SSL_CTX_free(c);
+ }
+ }
+
@Test
public void test_SSL_use_PrivateKey_for_tls_channel_id() throws Exception {
initChannelIdKey();
- try {
- NativeCrypto.SSL_set1_tls_channel_id(NULL, null);
- fail();
- } catch (NullPointerException expected) {
- }
-
long c = NativeCrypto.SSL_CTX_new();
long s = NativeCrypto.SSL_new(c);
- try {
- NativeCrypto.SSL_set1_tls_channel_id(s, null);
- fail();
- } catch (NullPointerException expected) {
- }
-
// Use the key natively. This works because the initChannelIdKey method ensures that the
// key is backed by OpenSSL.
NativeCrypto.SSL_set1_tls_channel_id(s, CHANNEL_ID_PRIVATE_KEY.getNativeRef());
@@ -401,21 +422,21 @@
NativeCrypto.SSL_CTX_free(c);
}
- @Test
- public void test_SSL_use_PrivateKey() throws Exception {
- try {
- NativeCrypto.SSL_use_PrivateKey(NULL, null);
- fail();
- } catch (NullPointerException expected) {
- }
+ @Test(expected = NullPointerException.class)
+ public void SSL_use_PrivateKey_withNullSslShouldThrow() throws Exception {
+ NativeCrypto.SSL_use_PrivateKey(NULL, null);
+ }
+ @Test(expected = NullPointerException.class)
+ public void SSL_use_PrivateKeyWithNullKeyShouldThrow() throws Exception {
long c = NativeCrypto.SSL_CTX_new();
long s = NativeCrypto.SSL_new(c);
try {
NativeCrypto.SSL_use_PrivateKey(s, null);
- fail();
- } catch (NullPointerException expected) {
+ } finally {
+ NativeCrypto.SSL_free(s);
+ NativeCrypto.SSL_CTX_free(c);
}
NativeCrypto.SSL_use_PrivateKey(s, getServerPrivateKey().getNativeRef());
@@ -424,63 +445,74 @@
NativeCrypto.SSL_CTX_free(c);
}
+ @Test
+ public void test_SSL_use_PrivateKey() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c);
+
+ NativeCrypto.SSL_use_PrivateKey(s, getServerPrivateKey().getNativeRef());
+
+ NativeCrypto.SSL_free(s);
+ NativeCrypto.SSL_CTX_free(c);
+ }
+
@Test(expected = NullPointerException.class)
- public void SSL_check_private_key_NullArgument() throws Exception {
+ public void SSL_check_private_key_withNullShouldThrow() throws Exception {
NativeCrypto.SSL_check_private_key(NULL);
}
- @Test
- public void test_SSL_check_private_key_no_key_no_cert() throws Exception {
+ @Test(expected = SSLException.class)
+ public void SSL_check_private_key_withNoKeyOrCertShouldThrow() throws Exception {
long c = NativeCrypto.SSL_CTX_new();
long s = NativeCrypto.SSL_new(c);
// neither private or certificate set
try {
NativeCrypto.SSL_check_private_key(s);
- fail();
- } catch (SSLException expected) {
+ } finally {
+ NativeCrypto.SSL_free(s);
+ NativeCrypto.SSL_CTX_free(c);
}
-
- NativeCrypto.SSL_free(s);
- NativeCrypto.SSL_CTX_free(c);
}
- @Test
- public void test_SSL_check_private_key_cert_then_key() throws Exception {
+ @Test(expected = SSLException.class)
+ public void SSL_check_private_key_withNoKeyShouldThrow() throws Exception {
long c = NativeCrypto.SSL_CTX_new();
long s = NativeCrypto.SSL_new(c);
- // first certificate, then private
+ // Certificate but no private key
NativeCrypto.SSL_use_certificate(s, getServerCertificates());
try {
NativeCrypto.SSL_check_private_key(s);
- fail();
- } catch (SSLException expected) {
+ } finally {
+ NativeCrypto.SSL_free(s);
+ NativeCrypto.SSL_CTX_free(c);
}
-
- NativeCrypto.SSL_use_PrivateKey(s, getServerPrivateKey().getNativeRef());
- NativeCrypto.SSL_check_private_key(s);
-
- NativeCrypto.SSL_free(s);
- NativeCrypto.SSL_CTX_free(c);
}
- @Test
- public void test_SSL_check_private_key_key_then_cert() throws Exception {
+ @Test(expected = SSLException.class)
+ public void test_SSL_check_private_NoCertificateShouldThrow() throws Exception {
long c = NativeCrypto.SSL_CTX_new();
long s = NativeCrypto.SSL_new(c);
// first private, then certificate
NativeCrypto.SSL_use_PrivateKey(s, getServerPrivateKey().getNativeRef());
-
try {
NativeCrypto.SSL_check_private_key(s);
- fail();
- } catch (SSLException expected) {
+ } finally {
+ NativeCrypto.SSL_free(s);
+ NativeCrypto.SSL_CTX_free(c);
}
+ }
+
+ @Test
+ public void test_SSL_check_private_key_certThenKey() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c);
NativeCrypto.SSL_use_certificate(s, getServerCertificates());
+ NativeCrypto.SSL_use_PrivateKey(s, getServerPrivateKey().getNativeRef());
NativeCrypto.SSL_check_private_key(s);
NativeCrypto.SSL_free(s);
@@ -488,13 +520,26 @@
}
@Test
- public void test_SSL_get_mode() throws Exception {
- try {
- NativeCrypto.SSL_get_mode(NULL);
- fail();
- } catch (NullPointerException expected) {
- }
+ public void test_SSL_check_private_key_keyThenCert() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c);
+ // first private, then certificate
+ NativeCrypto.SSL_use_PrivateKey(s, getServerPrivateKey().getNativeRef());
+ NativeCrypto.SSL_use_certificate(s, getServerCertificates());
+ NativeCrypto.SSL_check_private_key(s);
+
+ NativeCrypto.SSL_free(s);
+ NativeCrypto.SSL_CTX_free(c);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_get_mode_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_get_mode(NULL);
+ }
+
+ @Test
+ public void test_SSL_get_mode() throws Exception {
long c = NativeCrypto.SSL_CTX_new();
long s = NativeCrypto.SSL_new(c);
assertTrue(NativeCrypto.SSL_get_mode(s) != 0);
@@ -502,14 +547,13 @@
NativeCrypto.SSL_CTX_free(c);
}
+ @Test(expected = NullPointerException.class)
+ public void SSL_set_mode_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_set_mode(NULL, 0);
+ }
+
@Test
public void test_SSL_set_mode_and_clear_mode() throws Exception {
- try {
- NativeCrypto.SSL_set_mode(NULL, 0);
- fail();
- } catch (NullPointerException expected) {
- }
-
long c = NativeCrypto.SSL_CTX_new();
long s = NativeCrypto.SSL_new(c);
// check SSL_MODE_ENABLE_FALSE_START on by default for BoringSSL
@@ -529,14 +573,13 @@
NativeCrypto.SSL_CTX_free(c);
}
+ @Test(expected = NullPointerException.class)
+ public void SSL_get_options_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_get_options(NULL);
+ }
+
@Test
public void test_SSL_get_options() throws Exception {
- try {
- NativeCrypto.SSL_get_options(NULL);
- fail();
- } catch (NullPointerException expected) {
- }
-
long c = NativeCrypto.SSL_CTX_new();
long s = NativeCrypto.SSL_new(c);
assertTrue(NativeCrypto.SSL_get_options(s) != 0);
@@ -544,14 +587,13 @@
NativeCrypto.SSL_CTX_free(c);
}
+ @Test(expected = NullPointerException.class)
+ public void SSL_set_options_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_set_options(NULL, 0);
+ }
+
@Test
public void test_SSL_set_options() throws Exception {
- try {
- NativeCrypto.SSL_set_options(NULL, 0);
- fail();
- } catch (NullPointerException expected) {
- }
-
long c = NativeCrypto.SSL_CTX_new();
long s = NativeCrypto.SSL_new(c);
assertTrue((NativeCrypto.SSL_get_options(s) & NativeConstants.SSL_OP_NO_SSLv3) == 0);
@@ -561,14 +603,13 @@
NativeCrypto.SSL_CTX_free(c);
}
+ @Test(expected = NullPointerException.class)
+ public void SSL_clear_options_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_clear_options(NULL, 0);
+ }
+
@Test
public void test_SSL_clear_options() throws Exception {
- try {
- NativeCrypto.SSL_clear_options(NULL, 0);
- fail();
- } catch (NullPointerException expected) {
- }
-
long c = NativeCrypto.SSL_CTX_new();
long s = NativeCrypto.SSL_new(c);
assertTrue((NativeCrypto.SSL_get_options(s) & NativeConstants.SSL_OP_NO_SSLv3) == 0);
@@ -580,32 +621,52 @@
NativeCrypto.SSL_CTX_free(c);
}
- @Test
- public void test_SSL_set_cipher_lists() throws Exception {
- try {
- NativeCrypto.SSL_set_cipher_lists(NULL, null);
- fail("Exception not thrown for null ssl and null list");
- } catch (NullPointerException expected) {
- }
+ @Test(expected = NullPointerException.class)
+ public void SSL_set_cipher_lists_withNullSslShouldThrow() throws Exception {
+ NativeCrypto.SSL_set_cipher_lists(NULL, null);
+ }
+ @Test(expected = NullPointerException.class)
+ public void SSL_set_cipher_lists_withNullCiphersShouldThrow() throws Exception {
long c = NativeCrypto.SSL_CTX_new();
long s = NativeCrypto.SSL_new(c);
-
try {
NativeCrypto.SSL_set_cipher_lists(s, null);
- fail("Exception not thrown for null list");
- } catch (NullPointerException expected) {
+ } finally {
+ NativeCrypto.SSL_free(s);
+ NativeCrypto.SSL_CTX_free(c);
}
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void test_SSL_set_cipher_lists_withNullCipherShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c);
+ try {
+ NativeCrypto.SSL_set_cipher_lists(s, new String[] {null});
+ } finally {
+ NativeCrypto.SSL_free(s);
+ NativeCrypto.SSL_CTX_free(c);
+ }
+ }
+
+ @Test
+ public void SSL_set_cipher_lists_withEmptyCiphersShouldSucceed() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c);
// Explicitly checking that the empty list is allowed.
// b/21816861
NativeCrypto.SSL_set_cipher_lists(s, new String[] {});
- try {
- NativeCrypto.SSL_set_cipher_lists(s, new String[] {null});
- fail("Exception not thrown for list with null element");
- } catch (NullPointerException expected) {
- }
+ NativeCrypto.SSL_free(s);
+ NativeCrypto.SSL_CTX_free(c);
+ }
+
+ @Test
+ public void SSL_set_cipher_lists_withIllegalCipherShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c);
// see OpenSSL ciphers man page
String[] illegals = new String[] {// empty
@@ -620,25 +681,34 @@
NativeCrypto.SSL_set_cipher_lists(s, new String[] {illegal});
fail("Exception now thrown for illegal cipher: " + illegal);
} catch (IllegalArgumentException expected) {
+ // Expected.
}
}
- List<String> ciphers =
- new ArrayList<String>(NativeCrypto.OPENSSL_TO_STANDARD_CIPHER_SUITES.keySet());
- NativeCrypto.SSL_set_cipher_lists(s, ciphers.toArray(new String[ciphers.size()]));
-
NativeCrypto.SSL_free(s);
NativeCrypto.SSL_CTX_free(c);
}
@Test
- public void test_SSL_set_verify() throws Exception {
- try {
- NativeCrypto.SSL_set_verify(NULL, 0);
- fail();
- } catch (NullPointerException expected) {
- }
+ public void SSL_set_cipher_lists_withValidCiphersShouldSucceed() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c);
+ List<String> ciphers =
+ new ArrayList<>(NativeCrypto.OPENSSL_TO_STANDARD_CIPHER_SUITES.keySet());
+ NativeCrypto.SSL_set_cipher_lists(s, ciphers.toArray(new String[ciphers.size()]));
+
+ NativeCrypto.SSL_free(s);
+ NativeCrypto.SSL_CTX_free(c);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_set_verify_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_set_verify(NULL, 0);
+ }
+
+ @Test
+ public void test_SSL_set_verify() throws Exception {
long c = NativeCrypto.SSL_CTX_new();
long s = NativeCrypto.SSL_new(c);
NativeCrypto.SSL_set_verify(s, NativeCrypto.SSL_VERIFY_NONE);
@@ -653,18 +723,19 @@
private static final boolean DEBUG = false;
public static class Hooks {
- protected String negotiatedCipherSuite;
+ String negotiatedCipherSuite;
private OpenSSLKey channelIdPrivateKey;
- protected boolean pskEnabled;
- protected byte[] pskKey;
- protected List<String> enabledCipherSuites;
+ boolean pskEnabled;
+ byte[] pskKey;
+ List<String> enabledCipherSuites;
/**
- * @throws SSLException
+ * @throws SSLException if an error occurs creating the context.
*/
public long getContext() throws SSLException {
return NativeCrypto.SSL_CTX_new();
}
+
public long beforeHandshake(long context) throws SSLException {
long s = NativeCrypto.SSL_new(context);
// Limit cipher suites to a known set so authMethod is known.
@@ -700,6 +771,7 @@
try {
NativeCrypto.SSL_shutdown(ssl, fd, callback);
} catch (IOException e) {
+ // Expected.
}
NativeCrypto.SSL_free(ssl);
}
@@ -712,20 +784,20 @@
}
}
- public static class TestSSLHandshakeCallbacks implements SSLHandshakeCallbacks {
+ static class TestSSLHandshakeCallbacks implements SSLHandshakeCallbacks {
private final Socket socket;
private final long sslNativePointer;
private final Hooks hooks;
- public TestSSLHandshakeCallbacks(Socket socket, long sslNativePointer, Hooks hooks) {
+ TestSSLHandshakeCallbacks(Socket socket, long sslNativePointer, Hooks hooks) {
this.socket = socket;
this.sslNativePointer = sslNativePointer;
this.hooks = hooks;
}
- public long[] certificateChainRefs;
- public String authMethod;
- public boolean verifyCertificateChainCalled;
+ private long[] certificateChainRefs;
+ private String authMethod;
+ private boolean verifyCertificateChainCalled;
@Override
public void verifyCertificateChain(long[] certChainRefs, String authMethod)
@@ -741,9 +813,9 @@
this.verifyCertificateChainCalled = true;
}
- public byte[] keyTypes;
- public byte[][] asn1DerEncodedX500Principals;
- public boolean clientCertificateRequestedCalled;
+ private byte[] keyTypes;
+ private byte[][] asn1DerEncodedX500Principals;
+ private boolean clientCertificateRequestedCalled;
@Override
public void clientCertificateRequested(
@@ -763,7 +835,7 @@
}
}
- public boolean handshakeCompletedCalled;
+ private boolean handshakeCompletedCalled;
@Override
public void onSSLStateChange(int type, int val) {
@@ -774,7 +846,7 @@
this.handshakeCompletedCalled = true;
}
- public Socket getSocket() {
+ Socket getSocket() {
return socket;
}
@@ -810,6 +882,7 @@
private byte[] serverPSKKeyRequestedResultKey;
private String serverPSKKeyRequestedIdentityHint;
private String serverPSKKeyRequestedIdentity;
+
@Override
public int serverPSKKeyRequested(String identityHint, String identity, byte[] key) {
if (DEBUG) {
@@ -827,10 +900,35 @@
}
return serverPSKKeyRequestedResult;
}
+
+ private boolean onNewSessionEstablishedInvoked;
+ private boolean onNewSessionEstablishedSaveSession;
+ private long onNewSessionEstablishedSessionNativePointer;
+
+ @Override
+ public void onNewSessionEstablished(long sslSessionNativePtr) {
+ if (DEBUG) {
+ System.out.println("ssl=0x" + Long.toString(sslNativePointer, 16)
+ + " onNewSessionCreated"
+ + " ssl=0x" + Long.toString(sslSessionNativePtr, 16));
+ }
+ onNewSessionEstablishedInvoked = true;
+
+ if (onNewSessionEstablishedSaveSession) {
+ NativeCrypto.SSL_SESSION_up_ref(sslSessionNativePtr);
+ onNewSessionEstablishedSessionNativePointer = sslSessionNativePtr;
+ }
+ }
+
+ @Override
+ public long serverSessionRequested(byte[] id) {
+ // TODO(nathanmittler): Implement server-side caching for TLS < 1.3
+ return 0;
+ }
}
- public static class ClientHooks extends Hooks {
- protected String pskIdentity;
+ static class ClientHooks extends Hooks {
+ private String pskIdentity;
@Override
public void configureCallbacks(TestSSLHandshakeCallbacks callbacks) {
@@ -861,20 +959,20 @@
}
}
- public static class ServerHooks extends Hooks {
+ static class ServerHooks extends Hooks {
private final OpenSSLKey privateKey;
private final long[] certificates;
private boolean channelIdEnabled;
private byte[] channelIdAfterHandshake;
private Throwable channelIdAfterHandshakeException;
- protected String pskIdentityHint;
+ private String pskIdentityHint;
public ServerHooks() {
this(null, null);
}
- public ServerHooks(OpenSSLKey privateKey, long[] certificates) {
+ ServerHooks(OpenSSLKey privateKey, long[] certificates) {
this.privateKey = privateKey;
this.certificates = certificates;
}
@@ -935,45 +1033,53 @@
executor.submit(new Callable<TestSSLHandshakeCallbacks>() {
@Override
public TestSSLHandshakeCallbacks call() throws Exception {
- @SuppressWarnings("resource")
- // Socket needs to remain open after the handshake
- Socket socket = (client ? new Socket(listener.getInetAddress(),
- listener.getLocalPort())
- : listener.accept());
- if (timeout == -1) {
- return new TestSSLHandshakeCallbacks(socket, 0, null);
- }
- FileDescriptor fd =
- (FileDescriptor) m_Platform_getFileDescriptor.invoke(null, socket);
- long c = hooks.getContext();
- long s = hooks.beforeHandshake(c);
- TestSSLHandshakeCallbacks callback =
- new TestSSLHandshakeCallbacks(socket, s, hooks);
- hooks.configureCallbacks(callback);
- if (DEBUG) {
- System.out.println("ssl=0x" + Long.toString(s, 16) + " handshake"
- + " context=0x" + Long.toString(c, 16) + " socket=" + socket
- + " fd=" + fd + " timeout=" + timeout + " client=" + client);
- }
- long session = NULL;
try {
- if (client) {
- NativeCrypto.SSL_set_connect_state(s);
- } else {
- NativeCrypto.SSL_set_accept_state(s);
+ @SuppressWarnings("resource")
+ // Socket needs to remain open after the handshake
+ Socket socket = (client ? new Socket(listener.getInetAddress(),
+ listener.getLocalPort())
+ : listener.accept());
+ if (timeout == -1) {
+ return new TestSSLHandshakeCallbacks(socket, 0, null);
}
- NativeCrypto.SSL_configure_alpn(s, client, alpnProtocols);
- NativeCrypto.SSL_do_handshake(s, fd, callback, timeout);
- session = NativeCrypto.SSL_get1_session(s);
+ FileDescriptor fd =
+ (FileDescriptor) m_Platform_getFileDescriptor
+ .invoke(null, socket);
+ long c = hooks.getContext();
+ long s = hooks.beforeHandshake(c);
+ TestSSLHandshakeCallbacks callback =
+ new TestSSLHandshakeCallbacks(socket, s, hooks);
+ hooks.configureCallbacks(callback);
if (DEBUG) {
System.out.println("ssl=0x" + Long.toString(s, 16) + " handshake"
- + " session=0x" + Long.toString(session, 16));
+ + " context=0x" + Long.toString(c, 16) + " socket=" + socket
+ + " fd=" + fd + " timeout=" + timeout + " client="
+ + client);
}
- } finally {
- // Ensure afterHandshake is called to free resources
- hooks.afterHandshake(session, s, c, socket, fd, callback);
+ long session = NULL;
+ try {
+ if (client) {
+ NativeCrypto.SSL_set_connect_state(s);
+ } else {
+ NativeCrypto.SSL_set_accept_state(s);
+ }
+ NativeCrypto.SSL_configure_alpn(s, client, alpnProtocols);
+ NativeCrypto.SSL_do_handshake(s, fd, callback, timeout);
+ session = NativeCrypto.SSL_get1_session(s);
+ if (DEBUG) {
+ System.out
+ .println("ssl=0x" + Long.toString(s, 16) + " handshake"
+ + " session=0x" + Long.toString(session, 16));
+ }
+ } finally {
+ // Ensure afterHandshake is called to free resources
+ hooks.afterHandshake(session, s, c, socket, fd, callback);
+ }
+ return callback;
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw e;
}
- return callback;
}
});
executor.shutdown();
@@ -985,32 +1091,36 @@
NativeCrypto.SSL_do_handshake(NULL, null, null, 0);
}
- @Test
- public void test_SSL_do_handshake_null_args() throws Exception {
+ @Test(expected = NullPointerException.class)
+ public void test_SSL_do_handshake_withNullFdShouldThrow() throws Exception {
long c = NativeCrypto.SSL_CTX_new();
long s = NativeCrypto.SSL_new(c);
NativeCrypto.SSL_set_connect_state(s);
-
try {
NativeCrypto.SSL_do_handshake(s, null, null, 0);
- fail();
- } catch (NullPointerException expected) {
+ } finally {
+ NativeCrypto.SSL_free(s);
+ NativeCrypto.SSL_CTX_free(c);
}
+ }
+ @Test(expected = NullPointerException.class)
+ public void test_SSL_do_handshake_withNullShcShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c);
+ NativeCrypto.SSL_set_connect_state(s);
try {
NativeCrypto.SSL_do_handshake(s, INVALID_FD, null, 0);
- fail();
- } catch (NullPointerException expected) {
+ } finally {
+ NativeCrypto.SSL_free(s);
+ NativeCrypto.SSL_CTX_free(c);
}
-
- NativeCrypto.SSL_free(s);
- NativeCrypto.SSL_CTX_free(c);
}
@Test
public void test_SSL_do_handshake_normal() throws Exception {
// normal client and server case
- final ServerSocket listener = new ServerSocket(0);
+ final ServerSocket listener = newServerSocket();
Hooks cHooks = new Hooks();
Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates());
Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null);
@@ -1027,14 +1137,96 @@
assertFalse(serverCallback.clientPSKKeyRequestedInvoked);
assertFalse(clientCallback.serverPSKKeyRequestedInvoked);
assertFalse(serverCallback.serverPSKKeyRequestedInvoked);
+ assertTrue(clientCallback.onNewSessionEstablishedInvoked);
+ assertTrue(serverCallback.onNewSessionEstablishedInvoked);
assertTrue(clientCallback.handshakeCompletedCalled);
assertTrue(serverCallback.handshakeCompletedCalled);
}
@Test
+ public void test_SSL_do_handshake_reusedSession() throws Exception {
+ // normal client and server case
+ final ServerSocket listener = newServerSocket();
+
+ Future<TestSSLHandshakeCallbacks> client1 =
+ handshake(listener, 0, true, new ClientHooks() {
+ @Override
+ public void configureCallbacks(TestSSLHandshakeCallbacks callbacks) {
+ callbacks.onNewSessionEstablishedSaveSession = true;
+ }
+ }, null);
+ Future<TestSSLHandshakeCallbacks> server1 = handshake(listener, 0,
+ false, new ServerHooks(getServerPrivateKey(), getServerCertificates()) {
+ @Override
+ public void configureCallbacks(TestSSLHandshakeCallbacks callbacks) {
+ callbacks.onNewSessionEstablishedSaveSession = true;
+ }
+ }, null);
+ TestSSLHandshakeCallbacks clientCallback1 = client1.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ TestSSLHandshakeCallbacks serverCallback1 = server1.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ assertTrue(clientCallback1.verifyCertificateChainCalled);
+ assertEqualCertificateChains(getServerCertificates(), clientCallback1.certificateChainRefs);
+ assertEquals("ECDHE_RSA", clientCallback1.authMethod);
+ assertFalse(serverCallback1.verifyCertificateChainCalled);
+ assertFalse(clientCallback1.clientCertificateRequestedCalled);
+ assertFalse(serverCallback1.clientCertificateRequestedCalled);
+ assertFalse(clientCallback1.clientPSKKeyRequestedInvoked);
+ assertFalse(serverCallback1.clientPSKKeyRequestedInvoked);
+ assertFalse(clientCallback1.serverPSKKeyRequestedInvoked);
+ assertFalse(serverCallback1.serverPSKKeyRequestedInvoked);
+ assertTrue(clientCallback1.onNewSessionEstablishedInvoked);
+ assertTrue(serverCallback1.onNewSessionEstablishedInvoked);
+ assertTrue(clientCallback1.handshakeCompletedCalled);
+ assertTrue(serverCallback1.handshakeCompletedCalled);
+
+ final long clientSessionContext =
+ clientCallback1.onNewSessionEstablishedSessionNativePointer;
+ final long serverSessionContext =
+ serverCallback1.onNewSessionEstablishedSessionNativePointer;
+
+ Future<TestSSLHandshakeCallbacks> client2 =
+ handshake(listener, 0, true, new ClientHooks() {
+ @Override
+ public long beforeHandshake(long c) throws SSLException {
+ long sslNativePtr = super.beforeHandshake(c);
+ NativeCrypto.SSL_set_session(sslNativePtr, clientSessionContext);
+ return sslNativePtr;
+ }
+ }, null);
+ Future<TestSSLHandshakeCallbacks> server2 = handshake(listener, 0,
+ false, new ServerHooks(getServerPrivateKey(), getServerCertificates()) {
+ @Override
+ public long beforeHandshake(long c) throws SSLException {
+ long sslNativePtr = super.beforeHandshake(c);
+ NativeCrypto.SSL_set_session(sslNativePtr, serverSessionContext);
+ return sslNativePtr;
+ }
+ }, null);
+ TestSSLHandshakeCallbacks clientCallback2 = client2.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ TestSSLHandshakeCallbacks serverCallback2 = server2.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ assertTrue(clientCallback2.verifyCertificateChainCalled);
+ assertEqualCertificateChains(getServerCertificates(), clientCallback2.certificateChainRefs);
+ assertEquals("ECDHE_RSA", clientCallback2.authMethod);
+ assertFalse(serverCallback2.verifyCertificateChainCalled);
+ assertFalse(clientCallback2.clientCertificateRequestedCalled);
+ assertFalse(serverCallback2.clientCertificateRequestedCalled);
+ assertFalse(clientCallback2.clientPSKKeyRequestedInvoked);
+ assertFalse(serverCallback2.clientPSKKeyRequestedInvoked);
+ assertFalse(clientCallback2.serverPSKKeyRequestedInvoked);
+ assertFalse(serverCallback2.serverPSKKeyRequestedInvoked);
+ assertTrue(clientCallback2.onNewSessionEstablishedInvoked);
+ assertTrue(serverCallback2.onNewSessionEstablishedInvoked);
+ assertTrue(clientCallback2.handshakeCompletedCalled);
+ assertTrue(serverCallback2.handshakeCompletedCalled);
+
+ NativeCrypto.SSL_SESSION_free(clientSessionContext);
+ NativeCrypto.SSL_SESSION_free(serverSessionContext);
+ }
+
+ @Test
public void test_SSL_do_handshake_optional_client_certificate() throws Exception {
// optional client certificate case
- final ServerSocket listener = new ServerSocket(0);
+ final ServerSocket listener = newServerSocket();
Hooks cHooks = new Hooks() {
@Override
@@ -1066,8 +1258,8 @@
assertTrue(clientCallback.clientCertificateRequestedCalled);
assertNotNull(clientCallback.keyTypes);
- assertEquals(new HashSet<String>(Arrays.asList("EC", "RSA")),
- SSLParametersImpl.getSupportedClientKeyTypes(clientCallback.keyTypes));
+ assertEquals(new HashSet<>(Arrays.asList("EC", "RSA")),
+ SSLUtils.getSupportedClientKeyTypes(clientCallback.keyTypes));
assertEqualPrincipals(getCaPrincipals(), clientCallback.asn1DerEncodedX500Principals);
assertFalse(serverCallback.clientCertificateRequestedCalled);
@@ -1075,7 +1267,8 @@
assertFalse(serverCallback.clientPSKKeyRequestedInvoked);
assertFalse(clientCallback.serverPSKKeyRequestedInvoked);
assertFalse(serverCallback.serverPSKKeyRequestedInvoked);
-
+ assertTrue(clientCallback.onNewSessionEstablishedInvoked);
+ assertTrue(serverCallback.onNewSessionEstablishedInvoked);
assertTrue(clientCallback.handshakeCompletedCalled);
assertTrue(serverCallback.handshakeCompletedCalled);
}
@@ -1083,7 +1276,7 @@
@Test
public void test_SSL_do_handshake_missing_required_certificate() throws Exception {
// required client certificate negative case
- final ServerSocket listener = new ServerSocket(0);
+ final ServerSocket listener = newServerSocket();
try {
Hooks cHooks = new Hooks();
Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) {
@@ -1091,8 +1284,7 @@
public long beforeHandshake(long c) throws SSLException {
long s = super.beforeHandshake(c);
NativeCrypto.SSL_set_client_CA_list(s, getCaPrincipals());
- NativeCrypto.SSL_set_verify(s,
- NativeCrypto.SSL_VERIFY_PEER
+ NativeCrypto.SSL_set_verify(s, NativeCrypto.SSL_VERIFY_PEER
| NativeCrypto.SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
return s;
}
@@ -1120,7 +1312,7 @@
@Test
public void test_SSL_do_handshake_clientCertificateRequested_throws_after_renegotiate()
throws Exception {
- final ServerSocket listener = new ServerSocket(0);
+ final ServerSocket listener = newServerSocket();
Hooks cHooks = new Hooks() {
@Override
@@ -1154,6 +1346,7 @@
NativeCrypto.SSL_write(s, fd, callback, new byte[] {42}, 0, 1,
(int) ((TIMEOUT_SECONDS * 1000) / 2));
} catch (IOException expected) {
+ // Ignored.
} finally {
super.afterHandshake(session, s, c, sock, fd, callback);
}
@@ -1174,7 +1367,7 @@
@Test
public void test_SSL_do_handshake_client_timeout() throws Exception {
// client timeout
- final ServerSocket listener = new ServerSocket(0);
+ final ServerSocket listener = newServerSocket();
Socket serverSocket = null;
try {
Hooks cHooks = new Hooks();
@@ -1198,7 +1391,7 @@
@Test
public void test_SSL_do_handshake_server_timeout() throws Exception {
// server timeout
- final ServerSocket listener = new ServerSocket(0);
+ final ServerSocket listener = newServerSocket();
Socket clientSocket = null;
try {
Hooks cHooks = new Hooks();
@@ -1221,11 +1414,11 @@
initChannelIdKey();
// Normal handshake with TLS Channel ID.
- final ServerSocket listener = new ServerSocket(0);
+ final ServerSocket listener = newServerSocket();
Hooks cHooks = new Hooks();
cHooks.channelIdPrivateKey = CHANNEL_ID_PRIVATE_KEY;
// TLS Channel ID currently requires ECDHE-based key exchanges.
- cHooks.enabledCipherSuites = Arrays.asList(new String[] {"ECDHE-RSA-AES128-SHA"});
+ cHooks.enabledCipherSuites = Collections.singletonList("ECDHE-RSA-AES128-SHA");
ServerHooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates());
sHooks.channelIdEnabled = true;
sHooks.enabledCipherSuites = cHooks.enabledCipherSuites;
@@ -1243,6 +1436,8 @@
assertFalse(serverCallback.clientPSKKeyRequestedInvoked);
assertFalse(clientCallback.serverPSKKeyRequestedInvoked);
assertFalse(serverCallback.serverPSKKeyRequestedInvoked);
+ assertTrue(clientCallback.onNewSessionEstablishedInvoked);
+ assertTrue(serverCallback.onNewSessionEstablishedInvoked);
assertTrue(clientCallback.handshakeCompletedCalled);
assertTrue(serverCallback.handshakeCompletedCalled);
assertNull(sHooks.channelIdAfterHandshakeException);
@@ -1254,11 +1449,11 @@
initChannelIdKey();
// Client tries to use TLS Channel ID but the server does not enable/offer the extension.
- final ServerSocket listener = new ServerSocket(0);
+ final ServerSocket listener = newServerSocket();
Hooks cHooks = new Hooks();
cHooks.channelIdPrivateKey = CHANNEL_ID_PRIVATE_KEY;
// TLS Channel ID currently requires ECDHE-based key exchanges.
- cHooks.enabledCipherSuites = Arrays.asList(new String[] {"ECDHE-RSA-AES128-SHA"});
+ cHooks.enabledCipherSuites = Collections.singletonList("ECDHE-RSA-AES128-SHA");
ServerHooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates());
sHooks.channelIdEnabled = false;
sHooks.enabledCipherSuites = cHooks.enabledCipherSuites;
@@ -1276,6 +1471,8 @@
assertFalse(serverCallback.clientPSKKeyRequestedInvoked);
assertFalse(clientCallback.serverPSKKeyRequestedInvoked);
assertFalse(serverCallback.serverPSKKeyRequestedInvoked);
+ assertTrue(clientCallback.onNewSessionEstablishedInvoked);
+ assertTrue(serverCallback.onNewSessionEstablishedInvoked);
assertTrue(clientCallback.handshakeCompletedCalled);
assertTrue(serverCallback.handshakeCompletedCalled);
assertNull(sHooks.channelIdAfterHandshakeException);
@@ -1287,11 +1484,11 @@
initChannelIdKey();
// Client does not use TLS Channel ID when the server has the extension enabled/offered.
- final ServerSocket listener = new ServerSocket(0);
+ final ServerSocket listener = newServerSocket();
Hooks cHooks = new Hooks();
cHooks.channelIdPrivateKey = null;
// TLS Channel ID currently requires ECDHE-based key exchanges.
- cHooks.enabledCipherSuites = Arrays.asList(new String[] {"ECDHE-RSA-AES128-SHA"});
+ cHooks.enabledCipherSuites = Collections.singletonList("ECDHE-RSA-AES128-SHA");
ServerHooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates());
sHooks.channelIdEnabled = true;
sHooks.enabledCipherSuites = cHooks.enabledCipherSuites;
@@ -1309,6 +1506,8 @@
assertFalse(serverCallback.clientPSKKeyRequestedInvoked);
assertFalse(clientCallback.serverPSKKeyRequestedInvoked);
assertFalse(serverCallback.serverPSKKeyRequestedInvoked);
+ assertTrue(clientCallback.onNewSessionEstablishedInvoked);
+ assertTrue(serverCallback.onNewSessionEstablishedInvoked);
assertTrue(clientCallback.handshakeCompletedCalled);
assertTrue(serverCallback.handshakeCompletedCalled);
assertNull(sHooks.channelIdAfterHandshakeException);
@@ -1318,7 +1517,7 @@
@Test
public void test_SSL_do_handshake_with_psk_normal() throws Exception {
// normal TLS-PSK client and server case
- final ServerSocket listener = new ServerSocket(0);
+ final ServerSocket listener = newServerSocket();
Hooks cHooks = new ClientHooks();
ServerHooks sHooks = new ServerHooks();
cHooks.pskEnabled = true;
@@ -1333,6 +1532,8 @@
assertFalse(serverCallback.verifyCertificateChainCalled);
assertFalse(clientCallback.clientCertificateRequestedCalled);
assertFalse(serverCallback.clientCertificateRequestedCalled);
+ assertTrue(clientCallback.onNewSessionEstablishedInvoked);
+ assertTrue(serverCallback.onNewSessionEstablishedInvoked);
assertTrue(clientCallback.handshakeCompletedCalled);
assertTrue(serverCallback.handshakeCompletedCalled);
assertTrue(clientCallback.clientPSKKeyRequestedInvoked);
@@ -1350,7 +1551,7 @@
public void test_SSL_do_handshake_with_psk_with_identity_and_hint() throws Exception {
// normal TLS-PSK client and server case where the server provides the client with a PSK
// identity hint, and the client provides the server with a PSK identity.
- final ServerSocket listener = new ServerSocket(0);
+ final ServerSocket listener = newServerSocket();
ClientHooks cHooks = new ClientHooks();
ServerHooks sHooks = new ServerHooks();
cHooks.pskEnabled = true;
@@ -1367,6 +1568,8 @@
assertFalse(serverCallback.verifyCertificateChainCalled);
assertFalse(clientCallback.clientCertificateRequestedCalled);
assertFalse(serverCallback.clientCertificateRequestedCalled);
+ assertTrue(clientCallback.onNewSessionEstablishedInvoked);
+ assertTrue(serverCallback.onNewSessionEstablishedInvoked);
assertTrue(clientCallback.handshakeCompletedCalled);
assertTrue(serverCallback.handshakeCompletedCalled);
assertTrue(clientCallback.clientPSKKeyRequestedInvoked);
@@ -1386,7 +1589,7 @@
throws Exception {
// normal TLS-PSK client and server case where the server provides the client with a PSK
// identity hint, and the client provides the server with a PSK identity.
- final ServerSocket listener = new ServerSocket(0);
+ final ServerSocket listener = newServerSocket();
ClientHooks cHooks = new ClientHooks();
ServerHooks sHooks = new ServerHooks();
cHooks.pskEnabled = true;
@@ -1422,7 +1625,7 @@
@Test
public void test_SSL_do_handshake_with_psk_key_mismatch() throws Exception {
- final ServerSocket listener = new ServerSocket(0);
+ final ServerSocket listener = newServerSocket();
ClientHooks cHooks = new ClientHooks();
ServerHooks sHooks = new ServerHooks();
cHooks.pskEnabled = true;
@@ -1442,7 +1645,7 @@
@Test
public void test_SSL_do_handshake_with_psk_with_no_client_key() throws Exception {
- final ServerSocket listener = new ServerSocket(0);
+ final ServerSocket listener = newServerSocket();
ClientHooks cHooks = new ClientHooks();
ServerHooks sHooks = new ServerHooks();
cHooks.pskEnabled = true;
@@ -1462,7 +1665,7 @@
@Test
public void test_SSL_do_handshake_with_psk_with_no_server_key() throws Exception {
- final ServerSocket listener = new ServerSocket(0);
+ final ServerSocket listener = newServerSocket();
ClientHooks cHooks = new ClientHooks();
ServerHooks sHooks = new ServerHooks();
cHooks.pskEnabled = true;
@@ -1483,7 +1686,7 @@
@Test
@SuppressWarnings("deprecation")
public void test_SSL_do_handshake_with_psk_key_too_long() throws Exception {
- final ServerSocket listener = new ServerSocket(0);
+ final ServerSocket listener = newServerSocket();
ClientHooks cHooks = new ClientHooks() {
@Override
public void configureCallbacks(TestSSLHandshakeCallbacks callbacks) {
@@ -1511,7 +1714,7 @@
public void test_SSL_do_handshake_with_ocsp_response() throws Exception {
final byte[] OCSP_TEST_DATA = new byte[] {1, 2, 3, 4};
- final ServerSocket listener = new ServerSocket(0);
+ final ServerSocket listener = newServerSocket();
Hooks cHooks = new Hooks() {
@Override
public long beforeHandshake(long c) throws SSLException {
@@ -1552,7 +1755,7 @@
// Each SCT entry has a length (unsigned 16-bit) and data.
final byte[] SCT_TEST_DATA = new byte[] {0, 6, 0, 4, 1, 2, 3, 4};
- final ServerSocket listener = new ServerSocket(0);
+ final ServerSocket listener = newServerSocket();
Hooks cHooks = new Hooks() {
@Override
public long beforeHandshake(long c) throws SSLException {
@@ -1584,6 +1787,8 @@
TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ assertTrue(clientCallback.onNewSessionEstablishedInvoked);
+ assertTrue(serverCallback.onNewSessionEstablishedInvoked);
assertTrue(clientCallback.handshakeCompletedCalled);
assertTrue(serverCallback.handshakeCompletedCalled);
}
@@ -1607,6 +1812,7 @@
NativeCrypto.SSL_use_psk_identity_hint(s, pskIdentityHint.toString());
fail();
} catch (SSLException expected) {
+ // Expected.
}
} finally {
NativeCrypto.SSL_free(s);
@@ -1614,26 +1820,23 @@
}
}
+ @Test(expected = NullPointerException.class)
+ public void SSL_set_session_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_set_session(NULL, NULL);
+ }
+
@Test
public void test_SSL_set_session() throws Exception {
- try {
- NativeCrypto.SSL_set_session(NULL, NULL);
- fail();
- } catch (NullPointerException expected) {
- }
-
- {
- long c = NativeCrypto.SSL_CTX_new();
- long s = NativeCrypto.SSL_new(c);
- NativeCrypto.SSL_set_session(s, NULL);
- NativeCrypto.SSL_free(s);
- NativeCrypto.SSL_CTX_free(c);
- }
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c);
+ NativeCrypto.SSL_set_session(s, NULL);
+ NativeCrypto.SSL_free(s);
+ NativeCrypto.SSL_CTX_free(c);
{
final long clientContext = NativeCrypto.SSL_CTX_new();
final long serverContext = NativeCrypto.SSL_CTX_new();
- final ServerSocket listener = new ServerSocket(0);
+ final ServerSocket listener = newServerSocket();
final long[] clientSession = new long[] {NULL};
final long[] serverSession = new long[] {NULL};
{
@@ -1714,24 +1917,21 @@
}
}
+ @Test(expected = NullPointerException.class)
+ public void SSL_set_session_creation_enabled_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_set_session_creation_enabled(NULL, false);
+ }
+
@Test
public void test_SSL_set_session_creation_enabled() throws Exception {
- try {
- NativeCrypto.SSL_set_session_creation_enabled(NULL, false);
- fail();
- } catch (NullPointerException expected) {
- }
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c);
+ NativeCrypto.SSL_set_session_creation_enabled(s, false);
+ NativeCrypto.SSL_set_session_creation_enabled(s, true);
+ NativeCrypto.SSL_free(s);
+ NativeCrypto.SSL_CTX_free(c);
- {
- long c = NativeCrypto.SSL_CTX_new();
- long s = NativeCrypto.SSL_new(c);
- NativeCrypto.SSL_set_session_creation_enabled(s, false);
- NativeCrypto.SSL_set_session_creation_enabled(s, true);
- NativeCrypto.SSL_free(s);
- NativeCrypto.SSL_CTX_free(c);
- }
-
- final ServerSocket listener = new ServerSocket(0);
+ final ServerSocket listener = newServerSocket();
// negative test case for SSL_set_session_creation_enabled(false) on client
{
@@ -1790,46 +1990,53 @@
}
}
- @Test
- public void test_SSL_set_tlsext_host_name() throws Exception {
- // NULL SSL
+ @Test(expected = NullPointerException.class)
+ public void SSL_set_tlsext_host_name_withNullSslShouldThrow() throws Exception {
+ NativeCrypto.SSL_set_tlsext_host_name(NULL, null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_set_tlsext_host_name_withNullHostnameShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c);
+
try {
- NativeCrypto.SSL_set_tlsext_host_name(NULL, null);
- fail();
- } catch (NullPointerException expected) {
- }
-
- final String hostname = "www.android.com";
-
- {
- long c = NativeCrypto.SSL_CTX_new();
- long s = NativeCrypto.SSL_new(c);
-
- // null hostname
- try {
- NativeCrypto.SSL_set_tlsext_host_name(s, null);
- fail();
- } catch (NullPointerException expected) {
- }
-
- // too long hostname
- try {
- char[] longHostname = new char[256];
- Arrays.fill(longHostname, 'w');
- NativeCrypto.SSL_set_tlsext_host_name(s, new String(longHostname));
- fail();
- } catch (SSLException expected) {
- }
-
- assertNull(NativeCrypto.SSL_get_servername(s));
- NativeCrypto.SSL_set_tlsext_host_name(s, new String(hostname));
- assertEquals(hostname, NativeCrypto.SSL_get_servername(s));
-
+ NativeCrypto.SSL_set_tlsext_host_name(s, null);
+ } finally {
NativeCrypto.SSL_free(s);
NativeCrypto.SSL_CTX_free(c);
}
+ }
- final ServerSocket listener = new ServerSocket(0);
+ @Test(expected = SSLException.class)
+ public void SSL_set_tlsext_host_name_withTooLongHostnameShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c);
+
+ try {
+ char[] longHostname = new char[256];
+ Arrays.fill(longHostname, 'w');
+ NativeCrypto.SSL_set_tlsext_host_name(s, new String(longHostname));
+ } finally {
+ NativeCrypto.SSL_free(s);
+ NativeCrypto.SSL_CTX_free(c);
+ }
+ }
+
+ @Test
+ public void test_SSL_set_tlsext_host_name() throws Exception {
+ final String hostname = "www.android.com";
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c);
+
+ assertNull(NativeCrypto.SSL_get_servername(s));
+ NativeCrypto.SSL_set_tlsext_host_name(s, hostname);
+ assertEquals(hostname, NativeCrypto.SSL_get_servername(s));
+
+ NativeCrypto.SSL_free(s);
+ NativeCrypto.SSL_CTX_free(c);
+
+ final ServerSocket listener = newServerSocket();
// normal
Hooks cHooks = new Hooks() {
@@ -1883,7 +2090,7 @@
}
};
- ServerSocket listener = new ServerSocket(0);
+ ServerSocket listener = newServerSocket();
Future<TestSSLHandshakeCallbacks> client =
handshake(listener, 0, true, cHooks, clientAlpnProtocols);
Future<TestSSLHandshakeCallbacks> server =
@@ -1892,15 +2099,13 @@
server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
- @Test
- public void test_SSL_get_servername_null() throws Exception {
- // NULL SSL
- try {
- NativeCrypto.SSL_get_servername(NULL);
- fail();
- } catch (NullPointerException expected) {
- }
+ @Test(expected = NullPointerException.class)
+ public void test_SSL_get_servername_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_get_servername(NULL);
+ }
+ @Test
+ public void SSL_get_servername_shouldReturnNull() throws Exception {
long c = NativeCrypto.SSL_CTX_new();
long s = NativeCrypto.SSL_new(c);
assertNull(NativeCrypto.SSL_get_servername(s));
@@ -1910,16 +2115,15 @@
// additional positive testing by test_SSL_set_tlsext_host_name
}
+ @Test(expected = NullPointerException.class)
+ public void SSL_renegotiate_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_renegotiate(NULL);
+ }
+
@Ignore("TODO(nathanmittler): Determine why this doesn't pass on openjdk")
@Test
- public void test_SSL_renegotiate() throws Exception {
- try {
- NativeCrypto.SSL_renegotiate(NULL);
- fail();
- } catch (NullPointerException expected) {
- }
-
- final ServerSocket listener = new ServerSocket(0);
+ public void test_SSL_renegotiate_fails() throws Exception {
+ final ServerSocket listener = newServerSocket();
Hooks cHooks = new Hooks() {
@Override
public void afterHandshake(long session, long s, long c, Socket sock, FileDescriptor fd,
@@ -1934,7 +2138,17 @@
@Override
public void afterHandshake(long session, long s, long c, Socket sock, FileDescriptor fd,
SSLHandshakeCallbacks callback) throws Exception {
- NativeCrypto.SSL_renegotiate(s);
+ try {
+ // Ensure that BoringSSL throws an exception if you try to manually trigger
+ // SSL renegotiation, which is what we expect. The fail() may not directly
+ // cause the test to fail, because we may be in a separate thread from the main
+ // test thread, but the SSL_write() call that follows is required for the
+ // test to pass.
+ NativeCrypto.SSL_renegotiate(s);
+ fail("Expected SSLException");
+ } catch (SSLException expected) {
+ // Expected.
+ }
NativeCrypto.SSL_write(s, fd, callback, new byte[] {42}, 0, 1, 0);
super.afterHandshake(session, s, c, sock, fd, callback);
}
@@ -1945,15 +2159,14 @@
server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
+ @Test(expected = NullPointerException.class)
+ public void SSL_get_certificate_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_get_certificate(NULL);
+ }
+
@Test
public void test_SSL_get_certificate() throws Exception {
- try {
- NativeCrypto.SSL_get_certificate(NULL);
- fail();
- } catch (NullPointerException expected) {
- }
-
- final ServerSocket listener = new ServerSocket(0);
+ final ServerSocket listener = newServerSocket();
Hooks cHooks = new Hooks() {
@Override
public void afterHandshake(long session, long s, long c, Socket sock, FileDescriptor fd,
@@ -1977,15 +2190,14 @@
server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
+ @Test(expected = NullPointerException.class)
+ public void SSL_get_peer_cert_chain_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_get_peer_cert_chain(NULL);
+ }
+
@Test
public void test_SSL_get_peer_cert_chain() throws Exception {
- try {
- NativeCrypto.SSL_get_peer_cert_chain(NULL);
- fail();
- } catch (NullPointerException expected) {
- }
-
- final ServerSocket listener = new ServerSocket(0);
+ final ServerSocket listener = newServerSocket();
Hooks cHooks = new Hooks() {
@Override
@@ -2006,70 +2218,64 @@
server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
- final byte[] BYTES = new byte[] {2, -3, 5, 127, 0, -128};
+ private final byte[] BYTES = new byte[] {2, -3, 5, 127, 0, -128};
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_read_withNullSslShouldThrow() throws Exception {
+ NativeCrypto.SSL_read(NULL, null, null, null, 0, 0, 0);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_read_withNullFdShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c);
+ try {
+ NativeCrypto.SSL_read(s, null, DUMMY_CB, null, 0, 0, 0);
+ } finally {
+ NativeCrypto.SSL_free(s);
+ NativeCrypto.SSL_CTX_free(c);
+ }
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_read_withNullCallbacksShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c);
+ try {
+ NativeCrypto.SSL_read(s, INVALID_FD, null, null, 0, 0, 0);
+ } finally {
+ NativeCrypto.SSL_free(s);
+ NativeCrypto.SSL_CTX_free(c);
+ }
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_read_withNullBytesShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c);
+ try {
+ NativeCrypto.SSL_read(s, INVALID_FD, DUMMY_CB, null, 0, 0, 0);
+ } finally {
+ NativeCrypto.SSL_free(s);
+ NativeCrypto.SSL_CTX_free(c);
+ }
+ }
+
+ @Test(expected = SSLException.class)
+ public void SSL_read_beforeHandshakeShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c);
+ try {
+ NativeCrypto.SSL_read(s, INVALID_FD, DUMMY_CB, new byte[1], 0, 1, 0);
+ } finally {
+ NativeCrypto.SSL_free(s);
+ NativeCrypto.SSL_CTX_free(c);
+ }
+ }
@Test
public void test_SSL_read() throws Exception {
- // NULL ssl
- try {
- NativeCrypto.SSL_read(NULL, null, null, null, 0, 0, 0);
- fail();
- } catch (NullPointerException expected) {
- }
-
- // null FileDescriptor
- {
- long c = NativeCrypto.SSL_CTX_new();
- long s = NativeCrypto.SSL_new(c);
- try {
- NativeCrypto.SSL_read(s, null, DUMMY_CB, null, 0, 0, 0);
- fail();
- } catch (NullPointerException expected) {
- }
- NativeCrypto.SSL_free(s);
- NativeCrypto.SSL_CTX_free(c);
- }
-
- // null SSLHandshakeCallbacks
- {
- long c = NativeCrypto.SSL_CTX_new();
- long s = NativeCrypto.SSL_new(c);
- try {
- NativeCrypto.SSL_read(s, INVALID_FD, null, null, 0, 0, 0);
- fail();
- } catch (NullPointerException expected) {
- }
- NativeCrypto.SSL_free(s);
- NativeCrypto.SSL_CTX_free(c);
- }
-
- // null byte array
- {
- long c = NativeCrypto.SSL_CTX_new();
- long s = NativeCrypto.SSL_new(c);
- try {
- NativeCrypto.SSL_read(s, INVALID_FD, DUMMY_CB, null, 0, 0, 0);
- fail();
- } catch (NullPointerException expected) {
- }
- NativeCrypto.SSL_free(s);
- NativeCrypto.SSL_CTX_free(c);
- }
-
- // handshaking not yet performed
- {
- long c = NativeCrypto.SSL_CTX_new();
- long s = NativeCrypto.SSL_new(c);
- try {
- NativeCrypto.SSL_read(s, INVALID_FD, DUMMY_CB, new byte[1], 0, 1, 0);
- fail();
- } catch (SSLException expected) {
- }
- NativeCrypto.SSL_free(s);
- NativeCrypto.SSL_CTX_free(c);
- }
-
- final ServerSocket listener = new ServerSocket(0);
+ final ServerSocket listener = newServerSocket();
// normal case
{
@@ -2128,84 +2334,78 @@
}
}
- @Test
- public void test_SSL_write() throws Exception {
+ @Test(expected = NullPointerException.class)
+ public void SSL_write_withNullSslShouldThrow() throws Exception {
+ NativeCrypto.SSL_write(NULL, null, null, null, 0, 0, 0);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void SSL_write_withNullFdShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c);
try {
- NativeCrypto.SSL_write(NULL, null, null, null, 0, 0, 0);
- fail();
- } catch (NullPointerException expected) {
- }
-
- // null FileDescriptor
- {
- long c = NativeCrypto.SSL_CTX_new();
- long s = NativeCrypto.SSL_new(c);
- try {
- NativeCrypto.SSL_write(s, null, DUMMY_CB, null, 0, 1, 0);
- fail();
- } catch (NullPointerException expected) {
- }
+ NativeCrypto.SSL_write(s, null, DUMMY_CB, null, 0, 1, 0);
+ } finally {
NativeCrypto.SSL_free(s);
NativeCrypto.SSL_CTX_free(c);
}
+ }
- // null SSLHandshakeCallbacks
- {
- long c = NativeCrypto.SSL_CTX_new();
- long s = NativeCrypto.SSL_new(c);
- try {
- NativeCrypto.SSL_write(s, INVALID_FD, null, null, 0, 1, 0);
- fail();
- } catch (NullPointerException expected) {
- }
+ @Test(expected = NullPointerException.class)
+ public void SSL_write_withNullCallbacksShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c);
+ try {
+ NativeCrypto.SSL_write(s, INVALID_FD, null, null, 0, 1, 0);
+ } finally {
NativeCrypto.SSL_free(s);
NativeCrypto.SSL_CTX_free(c);
}
+ }
- // null byte array
- {
- long c = NativeCrypto.SSL_CTX_new();
- long s = NativeCrypto.SSL_new(c);
- try {
- NativeCrypto.SSL_write(s, INVALID_FD, DUMMY_CB, null, 0, 1, 0);
- fail();
- } catch (NullPointerException expected) {
- }
+ @Test(expected = NullPointerException.class)
+ public void SSL_write_withNullBytesShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c);
+ try {
+ NativeCrypto.SSL_write(s, INVALID_FD, DUMMY_CB, null, 0, 1, 0);
+ } finally {
NativeCrypto.SSL_free(s);
NativeCrypto.SSL_CTX_free(c);
}
+ }
- // handshaking not yet performed
- {
- long c = NativeCrypto.SSL_CTX_new();
- long s = NativeCrypto.SSL_new(c);
- try {
- NativeCrypto.SSL_write(s, INVALID_FD, DUMMY_CB, new byte[1], 0, 1, 0);
- fail();
- } catch (SSLException expected) {
- }
+ @Test(expected = SSLException.class)
+ public void SSL_write_beforeHandshakeShouldThrow() throws Exception {
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c);
+ try {
+ NativeCrypto.SSL_write(s, INVALID_FD, DUMMY_CB, new byte[1], 0, 1, 0);
+ } finally {
NativeCrypto.SSL_free(s);
NativeCrypto.SSL_CTX_free(c);
}
+ }
- // positively tested by test_SSL_read
+ @Test
+ public void SSL_interrupt_withNullShouldSucceed() {
+ // SSL_interrupt is a rare case that tolerates a null SSL argument
+ NativeCrypto.SSL_interrupt(NULL);
+ }
+
+ @Test
+ public void SSL_interrupt_withoutHandshakeShouldSucceed() throws Exception {
+ // also works without handshaking
+ long c = NativeCrypto.SSL_CTX_new();
+ long s = NativeCrypto.SSL_new(c);
+ NativeCrypto.SSL_interrupt(s);
+ NativeCrypto.SSL_free(s);
+ NativeCrypto.SSL_CTX_free(c);
}
@Test
public void test_SSL_interrupt() throws Exception {
- // SSL_interrupt is a rare case that tolerates a null SSL argument
- NativeCrypto.SSL_interrupt(NULL);
-
- // also works without handshaking
- {
- long c = NativeCrypto.SSL_CTX_new();
- long s = NativeCrypto.SSL_new(c);
- NativeCrypto.SSL_interrupt(s);
- NativeCrypto.SSL_free(s);
- NativeCrypto.SSL_CTX_free(c);
- }
-
- final ServerSocket listener = new ServerSocket(0);
+ final ServerSocket listener = newServerSocket();
Hooks cHooks = new Hooks() {
@Override
@@ -2223,9 +2423,10 @@
@Override
public void run() {
try {
- Thread.sleep(1 * 1000);
+ Thread.sleep(1000);
NativeCrypto.SSL_interrupt(s);
} catch (Exception e) {
+ // Expected.
}
}
}.start();
@@ -2255,7 +2456,7 @@
}
@Test
- public void test_SSL_shutdown() throws Exception {
+ public void SSL_shutdown_withNullFdShouldSucceed() throws Exception {
// We tolerate a null FileDescriptor
wrapWithSSLSession(new SSLSessionWrappedTask() {
@Override
@@ -2263,32 +2464,31 @@
NativeCrypto.SSL_shutdown(sslSession, null, DUMMY_CB);
}
});
+ }
- // null SSLHandshakeCallbacks
+ @Test(expected = NullPointerException.class)
+ public void SSL_shutdown_withNullCallbacksShouldThrow() throws Exception {
wrapWithSSLSession(new SSLSessionWrappedTask() {
@Override
public void run(long sslSession) throws Exception {
- try {
- NativeCrypto.SSL_shutdown(sslSession, INVALID_FD, null);
- fail();
- } catch (NullPointerException expected) {
- // Ignored.
- }
+ NativeCrypto.SSL_shutdown(sslSession, INVALID_FD, null);
}
});
+ }
+ @Test
+ public void SSL_shutdown_withNullSslShouldSucceed() throws Exception {
// SSL_shutdown is a rare case that tolerates a null SSL argument
NativeCrypto.SSL_shutdown(NULL, INVALID_FD, DUMMY_CB);
+ }
+ @Test(expected = SocketException.class)
+ public void SSL_shutdown_beforeHandshakeShouldThrow() throws Exception {
// handshaking not yet performed
wrapWithSSLSession(new SSLSessionWrappedTask() {
@Override
public void run(long sslSession) throws Exception {
- try {
- NativeCrypto.SSL_shutdown(sslSession, INVALID_FD, DUMMY_CB);
- fail();
- } catch (SocketException expected) {
- }
+ NativeCrypto.SSL_shutdown(sslSession, INVALID_FD, DUMMY_CB);
}
});
@@ -2296,14 +2496,13 @@
// SSL_shutdown to ensure SSL_SESSIONs are reused.
}
+ @Test(expected = NullPointerException.class)
+ public void SSL_free_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_free(NULL);
+ }
+
@Test
public void test_SSL_free() throws Exception {
- try {
- NativeCrypto.SSL_free(NULL);
- fail();
- } catch (NullPointerException expected) {
- }
-
long c = NativeCrypto.SSL_CTX_new();
NativeCrypto.SSL_free(NativeCrypto.SSL_new(c));
NativeCrypto.SSL_CTX_free(c);
@@ -2312,15 +2511,14 @@
// uses use SSL_free to cleanup in afterHandshake.
}
+ @Test(expected = NullPointerException.class)
+ public void SSL_SESSION_session_id_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_SESSION_session_id(NULL);
+ }
+
@Test
public void test_SSL_SESSION_session_id() throws Exception {
- try {
- NativeCrypto.SSL_SESSION_session_id(NULL);
- fail();
- } catch (NullPointerException expected) {
- }
-
- final ServerSocket listener = new ServerSocket(0);
+ final ServerSocket listener = newServerSocket();
Hooks cHooks = new Hooks() {
@Override
@@ -2339,15 +2537,14 @@
server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
+ @Test(expected = NullPointerException.class)
+ public void SSL_SESSION_get_time_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_SESSION_get_time(NULL);
+ }
+
@Test
public void test_SSL_SESSION_get_time() throws Exception {
- try {
- NativeCrypto.SSL_SESSION_get_time(NULL);
- fail();
- } catch (NullPointerException expected) {
- }
-
- final ServerSocket listener = new ServerSocket(0);
+ final ServerSocket listener = newServerSocket();
{
Hooks cHooks = new Hooks() {
@@ -2368,15 +2565,14 @@
}
}
+ @Test(expected = NullPointerException.class)
+ public void SSL_SESSION_get_version_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_SESSION_get_version(NULL);
+ }
+
@Test
public void test_SSL_SESSION_get_version() throws Exception {
- try {
- NativeCrypto.SSL_SESSION_get_version(NULL);
- fail();
- } catch (NullPointerException expected) {
- }
-
- final ServerSocket listener = new ServerSocket(0);
+ final ServerSocket listener = newServerSocket();
Hooks cHooks = new Hooks() {
@Override
@@ -2394,15 +2590,14 @@
server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
+ @Test(expected = NullPointerException.class)
+ public void SSL_SESSION_cipher_withNullShouldThrow() throws Exception {
+ NativeCrypto.SSL_SESSION_cipher(NULL);
+ }
+
@Test
public void test_SSL_SESSION_cipher() throws Exception {
- try {
- NativeCrypto.SSL_SESSION_cipher(NULL);
- fail();
- } catch (NullPointerException expected) {
- }
-
- final ServerSocket listener = new ServerSocket(0);
+ final ServerSocket listener = newServerSocket();
Hooks cHooks = new Hooks() {
@Override
@@ -2429,15 +2624,14 @@
NativeCrypto.SSL_SESSION_free(NULL);
}
+ @Test(expected = NullPointerException.class)
+ public void i2d_SSL_Session_WithNullSessionShouldThrow() throws Exception {
+ NativeCrypto.i2d_SSL_SESSION(NULL);
+ }
+
@Test
public void test_i2d_SSL_SESSION() throws Exception {
- try {
- NativeCrypto.i2d_SSL_SESSION(NULL);
- fail();
- } catch (NullPointerException expected) {
- }
-
- final ServerSocket listener = new ServerSocket(0);
+ final ServerSocket listener = newServerSocket();
Hooks cHooks = new Hooks() {
@Override
@@ -2495,8 +2689,8 @@
NativeCrypto.RAND_bytes(output);
boolean isZero = true;
- for (int i = 0; i < output.length; i++) {
- isZero &= (output[i] == 0);
+ for (byte anOutput : output) {
+ isZero &= (anOutput == 0);
}
assertFalse("Random output was zero. This is a very low probability event (1 in 2^128) "
@@ -2504,14 +2698,9 @@
isZero);
}
- @Test
- public void test_RAND_bytes_Null_Failure() throws Exception {
- byte[] output = null;
- try {
- NativeCrypto.RAND_bytes(output);
- fail("Should be an error on null buffer input");
- } catch (RuntimeException expected) {
- }
+ @Test(expected = RuntimeException.class)
+ public void RAND_bytes_withNullShouldThrow() throws Exception {
+ NativeCrypto.RAND_bytes(null);
}
@Test(expected = NullPointerException.class)
@@ -2519,16 +2708,19 @@
NativeCrypto.EVP_get_digestbyname(null);
}
+ @Test(expected = RuntimeException.class)
+ public void EVP_get_digestbyname_withEmptyShouldThrow() throws Exception {
+ NativeCrypto.EVP_get_digestbyname("");
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void EVP_get_digestbyname_withInvalidDigestShouldThrow() throws Exception {
+ NativeCrypto.EVP_get_digestbyname("foobar");
+ }
+
@Test
public void test_EVP_get_digestbyname() throws Exception {
assertTrue(NativeCrypto.EVP_get_digestbyname("sha256") != NULL);
-
- try {
- NativeCrypto.EVP_get_digestbyname("");
- NativeCrypto.EVP_get_digestbyname("foobar");
- fail();
- } catch (RuntimeException expected) {
- }
}
@Test
@@ -2556,12 +2748,14 @@
NativeCrypto.EVP_DigestSignInit(ctx, 0, pkey);
fail();
} catch (RuntimeException expected) {
+ // Expected.
}
try {
NativeCrypto.EVP_DigestSignInit(ctx, evpMd, null);
fail();
} catch (RuntimeException expected) {
+ // Expected.
}
}
@@ -2570,18 +2764,14 @@
NativeCrypto.get_RSA_private_params(null);
}
- @Test
+ @Test(expected = RuntimeException.class)
public void test_get_RSA_private_params() throws Exception {
// Test getting params for the wrong kind of key.
final long groupCtx = NativeCrypto.EC_GROUP_new_by_curve_name("prime256v1");
assertFalse(groupCtx == NULL);
NativeRef.EC_GROUP group = new NativeRef.EC_GROUP(groupCtx);
NativeRef.EVP_PKEY ctx = new NativeRef.EVP_PKEY(NativeCrypto.EC_KEY_generate_key(group));
- try {
- NativeCrypto.get_RSA_private_params(ctx);
- fail();
- } catch (RuntimeException expected) {
- }
+ NativeCrypto.get_RSA_private_params(ctx);
}
@Test(expected = NullPointerException.class)
@@ -2589,18 +2779,14 @@
NativeCrypto.get_RSA_public_params(null);
}
- @Test
+ @Test(expected = RuntimeException.class)
public void test_get_RSA_public_params() throws Exception {
// Test getting params for the wrong kind of key.
final long groupCtx = NativeCrypto.EC_GROUP_new_by_curve_name("prime256v1");
assertFalse(groupCtx == NULL);
NativeRef.EC_GROUP group = new NativeRef.EC_GROUP(groupCtx);
NativeRef.EVP_PKEY ctx = new NativeRef.EVP_PKEY(NativeCrypto.EC_KEY_generate_key(group));
- try {
- NativeCrypto.get_RSA_public_params(ctx);
- fail();
- } catch (RuntimeException expected) {
- }
+ NativeCrypto.get_RSA_public_params(ctx);
}
@Test(expected = NullPointerException.class)
@@ -2655,8 +2841,6 @@
long groupRef = NativeCrypto.EC_GROUP_new_by_curve_name(name);
assertFalse(groupRef == NULL);
NativeRef.EC_GROUP group = new NativeRef.EC_GROUP(groupRef);
- assertEquals(NativeCrypto.OBJ_txt2nid_longName(name),
- NativeCrypto.EC_GROUP_get_curve_name(group));
// prime
BigInteger p = new BigInteger(pStr, 16);
@@ -2745,6 +2929,7 @@
NativeCrypto.ECDH_compute_key(out, outOffset, null, pkey2Ref);
fail();
} catch (NullPointerException expected) {
+ // Expected.
}
// Assert that it fails when only the second key is null
@@ -2752,21 +2937,22 @@
NativeCrypto.ECDH_compute_key(out, outOffset, pkey1Ref, null);
fail();
} catch (NullPointerException expected) {
+ // Expected.
}
}
+ @Test(expected = NullPointerException.class)
+ public void EVP_CipherInit_ex_withNullCtxShouldThrow() throws Exception {
+ final long evpCipher = NativeCrypto.EVP_get_cipherbyname("aes-128-ecb");
+ NativeCrypto.EVP_CipherInit_ex(null, evpCipher, null, null, true);
+ }
+
@Test
public void test_EVP_CipherInit_ex_Null_Failure() throws Exception {
final NativeRef.EVP_CIPHER_CTX ctx =
new NativeRef.EVP_CIPHER_CTX(NativeCrypto.EVP_CIPHER_CTX_new());
final long evpCipher = NativeCrypto.EVP_get_cipherbyname("aes-128-ecb");
- try {
- NativeCrypto.EVP_CipherInit_ex(null, evpCipher, null, null, true);
- fail("Null context should throw NullPointerException");
- } catch (NullPointerException expected) {
- }
-
/* Initialize encrypting. */
NativeCrypto.EVP_CipherInit_ex(ctx, evpCipher, null, null, true);
NativeCrypto.EVP_CipherInit_ex(ctx, NULL, null, null, true);
@@ -2937,7 +3123,7 @@
@Test(expected = NullPointerException.class)
public void EVP_PKEY_CTX_set_rsa_oaep_md_NullMdCtx() throws Exception {
long pkeyCtx = getRawPkeyCtxForEncrypt();
- NativeRef.EVP_PKEY_CTX holder = new NativeRef.EVP_PKEY_CTX(pkeyCtx);
+ new NativeRef.EVP_PKEY_CTX(pkeyCtx);
NativeCrypto.EVP_PKEY_CTX_set_rsa_oaep_md(pkeyCtx, NULL);
}
@@ -2955,4 +3141,8 @@
}
fail("\"" + actualValue + "\" does not contain \"" + expectedSubstring + "\"");
}
+
+ private static ServerSocket newServerSocket() throws IOException {
+ return new ServerSocket(0, 50, InetAddress.getLoopbackAddress());
+ }
}
diff --git a/openjdk/src/test/java/org/conscrypt/NativeRefTest.java b/openjdk/src/test/java/org/conscrypt/NativeRefTest.java
index ed84813..e13297b 100644
--- a/openjdk/src/test/java/org/conscrypt/NativeRefTest.java
+++ b/openjdk/src/test/java/org/conscrypt/NativeRefTest.java
@@ -21,7 +21,11 @@
public class NativeRefTest extends TestCase {
public void test_zeroContextThrowsNullPointException() {
try {
- new NativeRef(0) {};
+ new NativeRef(0) {
+ @Override
+ void doFree(long context) {
+ }
+ };
fail("Should throw NullPointerException when arguments are NULL");
} catch (NullPointerException expected) {
}
diff --git a/openjdk/src/test/java/org/conscrypt/OpenSSLExtendedSessionImplTest.java b/openjdk/src/test/java/org/conscrypt/OpenSSLExtendedSessionImplTest.java
deleted file mode 100644
index f3414a9..0000000
--- a/openjdk/src/test/java/org/conscrypt/OpenSSLExtendedSessionImplTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli$
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.conscrypt;
-
-import java.util.List;
-import javax.net.ssl.ExtendedSSLSession;
-import javax.net.ssl.SNIHostName;
-import javax.net.ssl.SNIServerName;
-import junit.framework.TestCase;
-
-/**
- * Test for OpenSSLExtendedSessionImpl
- */
-public class OpenSSLExtendedSessionImplTest extends TestCase {
- static class MockSSLSession extends OpenSSLSessionImpl {
- MockSSLSession() {
- super(0, null, null, null, null, null, 0, null);
- }
-
- @Override
- public String getRequestedServerName() {
- return "server.name";
- }
- }
-
- public void test_getRequestedServerNames() {
- AbstractOpenSSLSession session = new MockSSLSession();
- ExtendedSSLSession extendedSession = new OpenSSLExtendedSessionImpl(session);
- List<SNIServerName> names = extendedSession.getRequestedServerNames();
- assertEquals("server.name", ((SNIHostName) names.get(0)).getAsciiName());
- }
-}
diff --git a/openjdk/src/test/java/org/conscrypt/SSLParametersImplTest.java b/openjdk/src/test/java/org/conscrypt/SSLParametersImplTest.java
deleted file mode 100644
index 47837c7..0000000
--- a/openjdk/src/test/java/org/conscrypt/SSLParametersImplTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.conscrypt;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import junit.framework.TestCase;
-
-public class SSLParametersImplTest extends TestCase {
-
- public void testGetClientKeyType() throws Exception {
- // See http://www.ietf.org/assignments/tls-parameters/tls-parameters.xml
- byte b = Byte.MIN_VALUE;
- do {
- String byteString = Byte.toString(b);
- String keyType = SSLParametersImpl.getClientKeyType(b);
- switch (b) {
- case 1:
- assertEquals(byteString, "RSA", keyType);
- break;
- case 3:
- assertEquals(byteString, "DH_RSA", keyType);
- break;
- case 64:
- assertEquals(byteString, "EC", keyType);
- break;
- case 65:
- assertEquals(byteString, "EC_RSA", keyType);
- break;
- case 66:
- assertEquals(byteString, "EC_EC", keyType);
- break;
- default:
- assertNull(byteString, keyType);
- }
- b++;
- } while (b != Byte.MIN_VALUE);
- }
-
- public void testGetSupportedClientKeyTypes() throws Exception {
- // Create an array with all possible values. Also, duplicate all values.
- byte[] allClientCertificateTypes = new byte[512];
- for (int i = 0; i < allClientCertificateTypes.length; i++) {
- allClientCertificateTypes[i] = (byte) i;
- }
- assertEquals(
- new HashSet<String>(Arrays.asList("RSA", "DH_RSA", "EC", "EC_RSA", "EC_EC")),
- SSLParametersImpl.getSupportedClientKeyTypes(allClientCertificateTypes));
- }
-}
diff --git a/openjdk/src/test/java/org/conscrypt/SSLUtilsTest.java b/openjdk/src/test/java/org/conscrypt/SSLUtilsTest.java
index c7f4d9d..73fcfb3 100644
--- a/openjdk/src/test/java/org/conscrypt/SSLUtilsTest.java
+++ b/openjdk/src/test/java/org/conscrypt/SSLUtilsTest.java
@@ -18,7 +18,11 @@
import static org.conscrypt.TestUtils.UTF_8;
import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import java.util.Arrays;
+import java.util.HashSet;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -62,6 +66,48 @@
assertArrayEquals(expected, actual);
}
+ @Test
+ public void testGetClientKeyType() throws Exception {
+ // See http://www.ietf.org/assignments/tls-parameters/tls-parameters.xml
+ byte b = Byte.MIN_VALUE;
+ do {
+ String byteString = Byte.toString(b);
+ String keyType = SSLUtils.getClientKeyType(b);
+ switch (b) {
+ case 1:
+ assertEquals(byteString, "RSA", keyType);
+ break;
+ case 3:
+ assertEquals(byteString, "DH_RSA", keyType);
+ break;
+ case 64:
+ assertEquals(byteString, "EC", keyType);
+ break;
+ case 65:
+ assertEquals(byteString, "EC_RSA", keyType);
+ break;
+ case 66:
+ assertEquals(byteString, "EC_EC", keyType);
+ break;
+ default:
+ assertNull(byteString, keyType);
+ }
+ b++;
+ } while (b != Byte.MIN_VALUE);
+ }
+
+ @Test
+ public void testGetSupportedClientKeyTypes() throws Exception {
+ // Create an array with all possible values. Also, duplicate all values.
+ byte[] allClientCertificateTypes = new byte[512];
+ for (int i = 0; i < allClientCertificateTypes.length; i++) {
+ allClientCertificateTypes[i] = (byte) i;
+ }
+ assertEquals(
+ new HashSet<String>(Arrays.asList("RSA", "DH_RSA", "EC", "EC_RSA", "EC_EC")),
+ SSLUtils.getSupportedClientKeyTypes(allClientCertificateTypes));
+ }
+
private static String[] toStrings(byte[][] protocols) {
int numProtocols = protocols.length;
String[] out = new String[numProtocols];
diff --git a/openjdk/src/test/java/org/conscrypt/ServerSessionContextTest.java b/openjdk/src/test/java/org/conscrypt/ServerSessionContextTest.java
new file mode 100644
index 0000000..7d1a8ce
--- /dev/null
+++ b/openjdk/src/test/java/org/conscrypt/ServerSessionContextTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.conscrypt;
+
+import java.util.Enumeration;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class ServerSessionContextTest extends AbstractSessionContextTest<ServerSessionContext> {
+
+ @Override
+ ServerSessionContext newContext() {
+ return new ServerSessionContext();
+ }
+
+ @Override
+ SslSessionWrapper getCachedSession(ServerSessionContext context, SslSessionWrapper s) {
+ return context.getSessionFromCache(s.getId());
+ }
+
+ @Override
+ int size(ServerSessionContext context) {
+ int count = 0;
+ Enumeration<byte[]> ids = context.getIds();
+ while (ids.hasMoreElements()) {
+ ids.nextElement();
+ count++;
+ }
+ return count;
+ }
+}
diff --git a/openjdk/src/test/java/org/conscrypt/SslSessionWrapperTest.java b/openjdk/src/test/java/org/conscrypt/SslSessionWrapperTest.java
new file mode 100644
index 0000000..dc600d4
--- /dev/null
+++ b/openjdk/src/test/java/org/conscrypt/SslSessionWrapperTest.java
@@ -0,0 +1,629 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License", "www.google.com", 443);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.conscrypt;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class SslSessionWrapperTest {
+ /*
+ * Taken from external/boringssl/src/ssl/ssl_test.cc: kOpenSSLSession is a
+ * serialized SSL_SESSION.
+ */
+ private static final byte[] kOpenSSLSession = new byte[] {(byte) 0x30, (byte) 0x82, (byte) 0x05,
+ (byte) 0xAA, (byte) 0x02, (byte) 0x01, (byte) 0x01, (byte) 0x02, (byte) 0x02,
+ (byte) 0x03, (byte) 0x03, (byte) 0x04, (byte) 0x02, (byte) 0xC0, (byte) 0x2F,
+ (byte) 0x04, (byte) 0x20, (byte) 0x06, (byte) 0xE5, (byte) 0x0D, (byte) 0x67,
+ (byte) 0x76, (byte) 0xAE, (byte) 0x18, (byte) 0x7E, (byte) 0x66, (byte) 0xDE,
+ (byte) 0xA3, (byte) 0x5C, (byte) 0xF0, (byte) 0x2E, (byte) 0x43, (byte) 0x51,
+ (byte) 0x2A, (byte) 0x60, (byte) 0x97, (byte) 0x19, (byte) 0xD3, (byte) 0x60,
+ (byte) 0x5A, (byte) 0xF1, (byte) 0x93, (byte) 0xDD, (byte) 0xCB, (byte) 0x24,
+ (byte) 0x57, (byte) 0x4C, (byte) 0x90, (byte) 0x90, (byte) 0x04, (byte) 0x30,
+ (byte) 0x26, (byte) 0x5A, (byte) 0xE5, (byte) 0xCE, (byte) 0x40, (byte) 0x16,
+ (byte) 0x04, (byte) 0xE5, (byte) 0xA2, (byte) 0x2E, (byte) 0x3F, (byte) 0xE3,
+ (byte) 0x27, (byte) 0xBE, (byte) 0x83, (byte) 0xEE, (byte) 0x5F, (byte) 0x94,
+ (byte) 0x5E, (byte) 0x88, (byte) 0xB3, (byte) 0x3F, (byte) 0x62, (byte) 0x88,
+ (byte) 0xD8, (byte) 0x2E, (byte) 0xC8, (byte) 0xD8, (byte) 0x57, (byte) 0x1C,
+ (byte) 0xA8, (byte) 0xC9, (byte) 0x88, (byte) 0x7C, (byte) 0x59, (byte) 0xA6,
+ (byte) 0x91, (byte) 0x4C, (byte) 0xB7, (byte) 0xDA, (byte) 0x72, (byte) 0x09,
+ (byte) 0xD2, (byte) 0x66, (byte) 0x47, (byte) 0x21, (byte) 0x6A, (byte) 0x09,
+ (byte) 0xA1, (byte) 0x06, (byte) 0x02, (byte) 0x04, (byte) 0x54, (byte) 0x43,
+ (byte) 0x3B, (byte) 0x8E, (byte) 0xA2, (byte) 0x04, (byte) 0x02, (byte) 0x02,
+ (byte) 0x01, (byte) 0x2C, (byte) 0xA3, (byte) 0x82, (byte) 0x04, (byte) 0x7A,
+ (byte) 0x30, (byte) 0x82, (byte) 0x04, (byte) 0x76, (byte) 0x30, (byte) 0x82,
+ (byte) 0x03, (byte) 0x5E, (byte) 0xA0, (byte) 0x03, (byte) 0x02, (byte) 0x01,
+ (byte) 0x02, (byte) 0x02, (byte) 0x08, (byte) 0x2B, (byte) 0xD7, (byte) 0x54,
+ (byte) 0xBE, (byte) 0xC3, (byte) 0xD6, (byte) 0x4A, (byte) 0x55, (byte) 0x30,
+ (byte) 0x0D, (byte) 0x06, (byte) 0x09, (byte) 0x2A, (byte) 0x86, (byte) 0x48,
+ (byte) 0x86, (byte) 0xF7, (byte) 0x0D, (byte) 0x01, (byte) 0x01, (byte) 0x05,
+ (byte) 0x05, (byte) 0x00, (byte) 0x30, (byte) 0x49, (byte) 0x31, (byte) 0x0B,
+ (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
+ (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, (byte) 0x31,
+ (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55,
+ (byte) 0x04, (byte) 0x0A, (byte) 0x13, (byte) 0x0A, (byte) 0x47, (byte) 0x6F,
+ (byte) 0x6F, (byte) 0x67, (byte) 0x6C, (byte) 0x65, (byte) 0x20, (byte) 0x49,
+ (byte) 0x6E, (byte) 0x63, (byte) 0x31, (byte) 0x25, (byte) 0x30, (byte) 0x23,
+ (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x03, (byte) 0x13,
+ (byte) 0x1C, (byte) 0x47, (byte) 0x6F, (byte) 0x6F, (byte) 0x67, (byte) 0x6C,
+ (byte) 0x65, (byte) 0x20, (byte) 0x49, (byte) 0x6E, (byte) 0x74, (byte) 0x65,
+ (byte) 0x72, (byte) 0x6E, (byte) 0x65, (byte) 0x74, (byte) 0x20, (byte) 0x41,
+ (byte) 0x75, (byte) 0x74, (byte) 0x68, (byte) 0x6F, (byte) 0x72, (byte) 0x69,
+ (byte) 0x74, (byte) 0x79, (byte) 0x20, (byte) 0x47, (byte) 0x32, (byte) 0x30,
+ (byte) 0x1E, (byte) 0x17, (byte) 0x0D, (byte) 0x31, (byte) 0x34, (byte) 0x31,
+ (byte) 0x30, (byte) 0x30, (byte) 0x38, (byte) 0x31, (byte) 0x32, (byte) 0x30,
+ (byte) 0x37, (byte) 0x35, (byte) 0x37, (byte) 0x5A, (byte) 0x17, (byte) 0x0D,
+ (byte) 0x31, (byte) 0x35, (byte) 0x30, (byte) 0x31, (byte) 0x30, (byte) 0x36,
+ (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30,
+ (byte) 0x5A, (byte) 0x30, (byte) 0x68, (byte) 0x31, (byte) 0x0B, (byte) 0x30,
+ (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06,
+ (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, (byte) 0x31, (byte) 0x13,
+ (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
+ (byte) 0x08, (byte) 0x0C, (byte) 0x0A, (byte) 0x43, (byte) 0x61, (byte) 0x6C,
+ (byte) 0x69, (byte) 0x66, (byte) 0x6F, (byte) 0x72, (byte) 0x6E, (byte) 0x69,
+ (byte) 0x61, (byte) 0x31, (byte) 0x16, (byte) 0x30, (byte) 0x14, (byte) 0x06,
+ (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x07, (byte) 0x0C, (byte) 0x0D,
+ (byte) 0x4D, (byte) 0x6F, (byte) 0x75, (byte) 0x6E, (byte) 0x74, (byte) 0x61,
+ (byte) 0x69, (byte) 0x6E, (byte) 0x20, (byte) 0x56, (byte) 0x69, (byte) 0x65,
+ (byte) 0x77, (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06,
+ (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0A, (byte) 0x0C, (byte) 0x0A,
+ (byte) 0x47, (byte) 0x6F, (byte) 0x6F, (byte) 0x67, (byte) 0x6C, (byte) 0x65,
+ (byte) 0x20, (byte) 0x49, (byte) 0x6E, (byte) 0x63, (byte) 0x31, (byte) 0x17,
+ (byte) 0x30, (byte) 0x15, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
+ (byte) 0x03, (byte) 0x0C, (byte) 0x0E, (byte) 0x77, (byte) 0x77, (byte) 0x77,
+ (byte) 0x2E, (byte) 0x67, (byte) 0x6F, (byte) 0x6F, (byte) 0x67, (byte) 0x6C,
+ (byte) 0x65, (byte) 0x2E, (byte) 0x63, (byte) 0x6F, (byte) 0x6D, (byte) 0x30,
+ (byte) 0x82, (byte) 0x01, (byte) 0x22, (byte) 0x30, (byte) 0x0D, (byte) 0x06,
+ (byte) 0x09, (byte) 0x2A, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xF7,
+ (byte) 0x0D, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00,
+ (byte) 0x03, (byte) 0x82, (byte) 0x01, (byte) 0x0F, (byte) 0x00, (byte) 0x30,
+ (byte) 0x82, (byte) 0x01, (byte) 0x0A, (byte) 0x02, (byte) 0x82, (byte) 0x01,
+ (byte) 0x01, (byte) 0x00, (byte) 0x9C, (byte) 0x29, (byte) 0xE2, (byte) 0xEB,
+ (byte) 0xA6, (byte) 0x50, (byte) 0x02, (byte) 0xF8, (byte) 0xBA, (byte) 0x1F,
+ (byte) 0xCB, (byte) 0xCB, (byte) 0x7F, (byte) 0xC0, (byte) 0x3C, (byte) 0x2D,
+ (byte) 0x07, (byte) 0xA7, (byte) 0xAE, (byte) 0xEF, (byte) 0x60, (byte) 0x95,
+ (byte) 0xA7, (byte) 0x47, (byte) 0x09, (byte) 0xE1, (byte) 0x5D, (byte) 0xE5,
+ (byte) 0x92, (byte) 0x73, (byte) 0x7A, (byte) 0x86, (byte) 0xE1, (byte) 0xFD,
+ (byte) 0x72, (byte) 0xDE, (byte) 0x85, (byte) 0x16, (byte) 0x4E, (byte) 0xF4,
+ (byte) 0xA1, (byte) 0x12, (byte) 0x21, (byte) 0xFD, (byte) 0x50, (byte) 0x4D,
+ (byte) 0x04, (byte) 0x1C, (byte) 0xFD, (byte) 0xD3, (byte) 0x48, (byte) 0xD8,
+ (byte) 0xCB, (byte) 0xEE, (byte) 0xF5, (byte) 0xD7, (byte) 0x52, (byte) 0x66,
+ (byte) 0xD5, (byte) 0xBF, (byte) 0x22, (byte) 0xA8, (byte) 0xE4, (byte) 0xD0,
+ (byte) 0xF5, (byte) 0xA4, (byte) 0xF9, (byte) 0x0B, (byte) 0xB4, (byte) 0x84,
+ (byte) 0x84, (byte) 0xD7, (byte) 0x10, (byte) 0x14, (byte) 0x9B, (byte) 0xEA,
+ (byte) 0xCC, (byte) 0x7D, (byte) 0xDE, (byte) 0x30, (byte) 0xF9, (byte) 0x1B,
+ (byte) 0xE9, (byte) 0x94, (byte) 0x96, (byte) 0x1A, (byte) 0x6D, (byte) 0x72,
+ (byte) 0x18, (byte) 0x5E, (byte) 0xCC, (byte) 0x09, (byte) 0x04, (byte) 0xC6,
+ (byte) 0x41, (byte) 0x71, (byte) 0x76, (byte) 0xD1, (byte) 0x29, (byte) 0x3F,
+ (byte) 0x3B, (byte) 0x5E, (byte) 0x85, (byte) 0x4A, (byte) 0x30, (byte) 0x32,
+ (byte) 0x9D, (byte) 0x4F, (byte) 0xDB, (byte) 0xDE, (byte) 0x82, (byte) 0x66,
+ (byte) 0x39, (byte) 0xCB, (byte) 0x5C, (byte) 0xC9, (byte) 0xC5, (byte) 0x98,
+ (byte) 0x91, (byte) 0x8D, (byte) 0x32, (byte) 0xB5, (byte) 0x2F, (byte) 0xE4,
+ (byte) 0xDC, (byte) 0xB0, (byte) 0x6E, (byte) 0x21, (byte) 0xDE, (byte) 0x39,
+ (byte) 0x3C, (byte) 0x96, (byte) 0xA8, (byte) 0x32, (byte) 0xA8, (byte) 0xC1,
+ (byte) 0xD1, (byte) 0x6C, (byte) 0xA9, (byte) 0xAA, (byte) 0xF3, (byte) 0x5E,
+ (byte) 0x24, (byte) 0x70, (byte) 0xB7, (byte) 0xAB, (byte) 0x92, (byte) 0x63,
+ (byte) 0x08, (byte) 0x1E, (byte) 0x11, (byte) 0x3F, (byte) 0xB3, (byte) 0x5F,
+ (byte) 0xC7, (byte) 0x98, (byte) 0xE3, (byte) 0x1D, (byte) 0x2A, (byte) 0xC2,
+ (byte) 0x32, (byte) 0x1C, (byte) 0x3C, (byte) 0x95, (byte) 0x43, (byte) 0x16,
+ (byte) 0xE0, (byte) 0x46, (byte) 0x83, (byte) 0xC6, (byte) 0x36, (byte) 0x91,
+ (byte) 0xF4, (byte) 0xA0, (byte) 0xE1, (byte) 0x3C, (byte) 0xB8, (byte) 0x23,
+ (byte) 0xB2, (byte) 0x4F, (byte) 0x8B, (byte) 0x0C, (byte) 0x8C, (byte) 0x92,
+ (byte) 0x45, (byte) 0x24, (byte) 0x43, (byte) 0x68, (byte) 0x24, (byte) 0x06,
+ (byte) 0x84, (byte) 0x43, (byte) 0x96, (byte) 0x2C, (byte) 0x96, (byte) 0x55,
+ (byte) 0x2F, (byte) 0x32, (byte) 0xE8, (byte) 0xE0, (byte) 0xDE, (byte) 0xBF,
+ (byte) 0x52, (byte) 0x57, (byte) 0x2D, (byte) 0x08, (byte) 0x71, (byte) 0x25,
+ (byte) 0x96, (byte) 0x90, (byte) 0x54, (byte) 0x4A, (byte) 0xF1, (byte) 0x0E,
+ (byte) 0xC8, (byte) 0x58, (byte) 0x1A, (byte) 0xE7, (byte) 0x6A, (byte) 0xAB,
+ (byte) 0xA0, (byte) 0x68, (byte) 0xE0, (byte) 0xAD, (byte) 0xFD, (byte) 0xD6,
+ (byte) 0x39, (byte) 0x0F, (byte) 0x76, (byte) 0xE4, (byte) 0xC1, (byte) 0x70,
+ (byte) 0xCD, (byte) 0xDE, (byte) 0x80, (byte) 0x2B, (byte) 0xE2, (byte) 0x1C,
+ (byte) 0x87, (byte) 0x48, (byte) 0x03, (byte) 0x46, (byte) 0x0F, (byte) 0x2C,
+ (byte) 0x41, (byte) 0xF7, (byte) 0x4B, (byte) 0x1F, (byte) 0x93, (byte) 0xAE,
+ (byte) 0x3F, (byte) 0x57, (byte) 0x1F, (byte) 0x2D, (byte) 0xF5, (byte) 0x35,
+ (byte) 0x02, (byte) 0x03, (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0xA3,
+ (byte) 0x82, (byte) 0x01, (byte) 0x41, (byte) 0x30, (byte) 0x82, (byte) 0x01,
+ (byte) 0x3D, (byte) 0x30, (byte) 0x1D, (byte) 0x06, (byte) 0x03, (byte) 0x55,
+ (byte) 0x1D, (byte) 0x25, (byte) 0x04, (byte) 0x16, (byte) 0x30, (byte) 0x14,
+ (byte) 0x06, (byte) 0x08, (byte) 0x2B, (byte) 0x06, (byte) 0x01, (byte) 0x05,
+ (byte) 0x05, (byte) 0x07, (byte) 0x03, (byte) 0x01, (byte) 0x06, (byte) 0x08,
+ (byte) 0x2B, (byte) 0x06, (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x07,
+ (byte) 0x03, (byte) 0x02, (byte) 0x30, (byte) 0x19, (byte) 0x06, (byte) 0x03,
+ (byte) 0x55, (byte) 0x1D, (byte) 0x11, (byte) 0x04, (byte) 0x12, (byte) 0x30,
+ (byte) 0x10, (byte) 0x82, (byte) 0x0E, (byte) 0x77, (byte) 0x77, (byte) 0x77,
+ (byte) 0x2E, (byte) 0x67, (byte) 0x6F, (byte) 0x6F, (byte) 0x67, (byte) 0x6C,
+ (byte) 0x65, (byte) 0x2E, (byte) 0x63, (byte) 0x6F, (byte) 0x6D, (byte) 0x30,
+ (byte) 0x68, (byte) 0x06, (byte) 0x08, (byte) 0x2B, (byte) 0x06, (byte) 0x01,
+ (byte) 0x05, (byte) 0x05, (byte) 0x07, (byte) 0x01, (byte) 0x01, (byte) 0x04,
+ (byte) 0x5C, (byte) 0x30, (byte) 0x5A, (byte) 0x30, (byte) 0x2B, (byte) 0x06,
+ (byte) 0x08, (byte) 0x2B, (byte) 0x06, (byte) 0x01, (byte) 0x05, (byte) 0x05,
+ (byte) 0x07, (byte) 0x30, (byte) 0x02, (byte) 0x86, (byte) 0x1F, (byte) 0x68,
+ (byte) 0x74, (byte) 0x74, (byte) 0x70, (byte) 0x3A, (byte) 0x2F, (byte) 0x2F,
+ (byte) 0x70, (byte) 0x6B, (byte) 0x69, (byte) 0x2E, (byte) 0x67, (byte) 0x6F,
+ (byte) 0x6F, (byte) 0x67, (byte) 0x6C, (byte) 0x65, (byte) 0x2E, (byte) 0x63,
+ (byte) 0x6F, (byte) 0x6D, (byte) 0x2F, (byte) 0x47, (byte) 0x49, (byte) 0x41,
+ (byte) 0x47, (byte) 0x32, (byte) 0x2E, (byte) 0x63, (byte) 0x72, (byte) 0x74,
+ (byte) 0x30, (byte) 0x2B, (byte) 0x06, (byte) 0x08, (byte) 0x2B, (byte) 0x06,
+ (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x07, (byte) 0x30, (byte) 0x01,
+ (byte) 0x86, (byte) 0x1F, (byte) 0x68, (byte) 0x74, (byte) 0x74, (byte) 0x70,
+ (byte) 0x3A, (byte) 0x2F, (byte) 0x2F, (byte) 0x63, (byte) 0x6C, (byte) 0x69,
+ (byte) 0x65, (byte) 0x6E, (byte) 0x74, (byte) 0x73, (byte) 0x31, (byte) 0x2E,
+ (byte) 0x67, (byte) 0x6F, (byte) 0x6F, (byte) 0x67, (byte) 0x6C, (byte) 0x65,
+ (byte) 0x2E, (byte) 0x63, (byte) 0x6F, (byte) 0x6D, (byte) 0x2F, (byte) 0x6F,
+ (byte) 0x63, (byte) 0x73, (byte) 0x70, (byte) 0x30, (byte) 0x1D, (byte) 0x06,
+ (byte) 0x03, (byte) 0x55, (byte) 0x1D, (byte) 0x0E, (byte) 0x04, (byte) 0x16,
+ (byte) 0x04, (byte) 0x14, (byte) 0x3B, (byte) 0x6B, (byte) 0xE0, (byte) 0x9C,
+ (byte) 0xC6, (byte) 0xC6, (byte) 0x41, (byte) 0xC8, (byte) 0xEA, (byte) 0x5C,
+ (byte) 0xFB, (byte) 0x1A, (byte) 0x58, (byte) 0x15, (byte) 0xC2, (byte) 0x1B,
+ (byte) 0x9D, (byte) 0x43, (byte) 0x19, (byte) 0x85, (byte) 0x30, (byte) 0x0C,
+ (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1D, (byte) 0x13, (byte) 0x01,
+ (byte) 0x01, (byte) 0xFF, (byte) 0x04, (byte) 0x02, (byte) 0x30, (byte) 0x00,
+ (byte) 0x30, (byte) 0x1F, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1D,
+ (byte) 0x23, (byte) 0x04, (byte) 0x18, (byte) 0x30, (byte) 0x16, (byte) 0x80,
+ (byte) 0x14, (byte) 0x4A, (byte) 0xDD, (byte) 0x06, (byte) 0x16, (byte) 0x1B,
+ (byte) 0xBC, (byte) 0xF6, (byte) 0x68, (byte) 0xB5, (byte) 0x76, (byte) 0xF5,
+ (byte) 0x81, (byte) 0xB6, (byte) 0xBB, (byte) 0x62, (byte) 0x1A, (byte) 0xBA,
+ (byte) 0x5A, (byte) 0x81, (byte) 0x2F, (byte) 0x30, (byte) 0x17, (byte) 0x06,
+ (byte) 0x03, (byte) 0x55, (byte) 0x1D, (byte) 0x20, (byte) 0x04, (byte) 0x10,
+ (byte) 0x30, (byte) 0x0E, (byte) 0x30, (byte) 0x0C, (byte) 0x06, (byte) 0x0A,
+ (byte) 0x2B, (byte) 0x06, (byte) 0x01, (byte) 0x04, (byte) 0x01, (byte) 0xD6,
+ (byte) 0x79, (byte) 0x02, (byte) 0x05, (byte) 0x01, (byte) 0x30, (byte) 0x30,
+ (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1D, (byte) 0x1F, (byte) 0x04,
+ (byte) 0x29, (byte) 0x30, (byte) 0x27, (byte) 0x30, (byte) 0x25, (byte) 0xA0,
+ (byte) 0x23, (byte) 0xA0, (byte) 0x21, (byte) 0x86, (byte) 0x1F, (byte) 0x68,
+ (byte) 0x74, (byte) 0x74, (byte) 0x70, (byte) 0x3A, (byte) 0x2F, (byte) 0x2F,
+ (byte) 0x70, (byte) 0x6B, (byte) 0x69, (byte) 0x2E, (byte) 0x67, (byte) 0x6F,
+ (byte) 0x6F, (byte) 0x67, (byte) 0x6C, (byte) 0x65, (byte) 0x2E, (byte) 0x63,
+ (byte) 0x6F, (byte) 0x6D, (byte) 0x2F, (byte) 0x47, (byte) 0x49, (byte) 0x41,
+ (byte) 0x47, (byte) 0x32, (byte) 0x2E, (byte) 0x63, (byte) 0x72, (byte) 0x6C,
+ (byte) 0x30, (byte) 0x0D, (byte) 0x06, (byte) 0x09, (byte) 0x2A, (byte) 0x86,
+ (byte) 0x48, (byte) 0x86, (byte) 0xF7, (byte) 0x0D, (byte) 0x01, (byte) 0x01,
+ (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x82, (byte) 0x01,
+ (byte) 0x01, (byte) 0x00, (byte) 0x9A, (byte) 0x39, (byte) 0x70, (byte) 0x81,
+ (byte) 0x76, (byte) 0x8A, (byte) 0x94, (byte) 0xCB, (byte) 0x96, (byte) 0xF1,
+ (byte) 0xCA, (byte) 0xAF, (byte) 0x96, (byte) 0xAE, (byte) 0x1D, (byte) 0x73,
+ (byte) 0xB3, (byte) 0x2C, (byte) 0x82, (byte) 0x16, (byte) 0x29, (byte) 0xB5,
+ (byte) 0x3C, (byte) 0x7E, (byte) 0x55, (byte) 0x53, (byte) 0x6F, (byte) 0xB2,
+ (byte) 0xBC, (byte) 0x34, (byte) 0x96, (byte) 0xAE, (byte) 0x00, (byte) 0xD8,
+ (byte) 0xF2, (byte) 0x26, (byte) 0xD1, (byte) 0x18, (byte) 0x99, (byte) 0x9F,
+ (byte) 0x7D, (byte) 0xFD, (byte) 0xEB, (byte) 0xE0, (byte) 0xBB, (byte) 0x9D,
+ (byte) 0xE6, (byte) 0x46, (byte) 0xA5, (byte) 0x74, (byte) 0xAB, (byte) 0x3D,
+ (byte) 0x93, (byte) 0xC6, (byte) 0x25, (byte) 0x28, (byte) 0x3D, (byte) 0xC8,
+ (byte) 0x4C, (byte) 0x6E, (byte) 0xCF, (byte) 0xD1, (byte) 0x84, (byte) 0xFF,
+ (byte) 0x46, (byte) 0x4F, (byte) 0x21, (byte) 0x2E, (byte) 0x07, (byte) 0xC4,
+ (byte) 0xB8, (byte) 0xB7, (byte) 0x2A, (byte) 0xE5, (byte) 0xC7, (byte) 0x34,
+ (byte) 0xC6, (byte) 0xA9, (byte) 0x84, (byte) 0xE3, (byte) 0x6C, (byte) 0x49,
+ (byte) 0xF8, (byte) 0x4A, (byte) 0x36, (byte) 0xBB, (byte) 0x3A, (byte) 0xBD,
+ (byte) 0xAD, (byte) 0x8A, (byte) 0x2B, (byte) 0x73, (byte) 0x97, (byte) 0xA6,
+ (byte) 0x30, (byte) 0x2C, (byte) 0x5F, (byte) 0xE4, (byte) 0xBD, (byte) 0x13,
+ (byte) 0x24, (byte) 0xE5, (byte) 0xD9, (byte) 0xA8, (byte) 0x74, (byte) 0x29,
+ (byte) 0x38, (byte) 0x47, (byte) 0x2E, (byte) 0xA6, (byte) 0xD6, (byte) 0x50,
+ (byte) 0xE0, (byte) 0xE8, (byte) 0xDD, (byte) 0x60, (byte) 0xC7, (byte) 0xD2,
+ (byte) 0xC6, (byte) 0x4E, (byte) 0x54, (byte) 0xCE, (byte) 0xE7, (byte) 0x94,
+ (byte) 0x84, (byte) 0x0D, (byte) 0xE8, (byte) 0x81, (byte) 0x92, (byte) 0x91,
+ (byte) 0x71, (byte) 0x19, (byte) 0x1D, (byte) 0x07, (byte) 0x75, (byte) 0x9E,
+ (byte) 0x59, (byte) 0x1A, (byte) 0x7E, (byte) 0x9D, (byte) 0x84, (byte) 0x61,
+ (byte) 0xC7, (byte) 0x84, (byte) 0xAD, (byte) 0xA3, (byte) 0x6A, (byte) 0xED,
+ (byte) 0xD8, (byte) 0x0D, (byte) 0x0C, (byte) 0x2A, (byte) 0x66, (byte) 0x3D,
+ (byte) 0xD7, (byte) 0xAE, (byte) 0x46, (byte) 0x1D, (byte) 0x4A, (byte) 0x8C,
+ (byte) 0x2B, (byte) 0xD6, (byte) 0x1A, (byte) 0x69, (byte) 0x71, (byte) 0xC3,
+ (byte) 0x5E, (byte) 0xA0, (byte) 0x6E, (byte) 0xED, (byte) 0x27, (byte) 0x9F,
+ (byte) 0xAF, (byte) 0x5B, (byte) 0x92, (byte) 0xA0, (byte) 0x03, (byte) 0xFD,
+ (byte) 0x83, (byte) 0x22, (byte) 0x09, (byte) 0x29, (byte) 0xE8, (byte) 0xA1,
+ (byte) 0x32, (byte) 0x2B, (byte) 0xEC, (byte) 0x1A, (byte) 0xA2, (byte) 0x75,
+ (byte) 0x4C, (byte) 0x3E, (byte) 0x99, (byte) 0x71, (byte) 0xCE, (byte) 0x8B,
+ (byte) 0x31, (byte) 0xEF, (byte) 0x9D, (byte) 0x37, (byte) 0x63, (byte) 0xFC,
+ (byte) 0x71, (byte) 0x91, (byte) 0x10, (byte) 0x1E, (byte) 0xD0, (byte) 0xF5,
+ (byte) 0xCB, (byte) 0x6F, (byte) 0x7A, (byte) 0xBA, (byte) 0x5E, (byte) 0x0C,
+ (byte) 0x8A, (byte) 0xFA, (byte) 0xA4, (byte) 0xDE, (byte) 0x36, (byte) 0xAD,
+ (byte) 0x51, (byte) 0x52, (byte) 0xFC, (byte) 0xFE, (byte) 0x10, (byte) 0xB0,
+ (byte) 0x81, (byte) 0xC8, (byte) 0x7D, (byte) 0x03, (byte) 0xC3, (byte) 0xB8,
+ (byte) 0x3C, (byte) 0x66, (byte) 0x6A, (byte) 0xF5, (byte) 0x6A, (byte) 0x81,
+ (byte) 0x7C, (byte) 0x45, (byte) 0xA6, (byte) 0x23, (byte) 0x21, (byte) 0xE1,
+ (byte) 0xD5, (byte) 0xD3, (byte) 0xED, (byte) 0x6E, (byte) 0x0D, (byte) 0x65,
+ (byte) 0x39, (byte) 0x77, (byte) 0x58, (byte) 0x09, (byte) 0x6B, (byte) 0x63,
+ (byte) 0xA4, (byte) 0x02, (byte) 0x04, (byte) 0x00, (byte) 0xA5, (byte) 0x03,
+ (byte) 0x02, (byte) 0x01, (byte) 0x14, (byte) 0xA9, (byte) 0x05, (byte) 0x02,
+ (byte) 0x03, (byte) 0x01, (byte) 0x89, (byte) 0xC0, (byte) 0xAA, (byte) 0x81,
+ (byte) 0xA7, (byte) 0x04, (byte) 0x81, (byte) 0xA4, (byte) 0x1C, (byte) 0x14,
+ (byte) 0x42, (byte) 0xFA, (byte) 0x1E, (byte) 0x3A, (byte) 0x4D, (byte) 0x0A,
+ (byte) 0x83, (byte) 0x7E, (byte) 0x92, (byte) 0x61, (byte) 0x37, (byte) 0x0B,
+ (byte) 0x12, (byte) 0x45, (byte) 0xEA, (byte) 0x2B, (byte) 0x03, (byte) 0x81,
+ (byte) 0x7C, (byte) 0x5F, (byte) 0x6F, (byte) 0x13, (byte) 0x82, (byte) 0x97,
+ (byte) 0xD0, (byte) 0xDC, (byte) 0x5E, (byte) 0x2F, (byte) 0x08, (byte) 0xDC,
+ (byte) 0x0D, (byte) 0x3A, (byte) 0x6C, (byte) 0xBA, (byte) 0x1D, (byte) 0xEA,
+ (byte) 0x5C, (byte) 0x46, (byte) 0x99, (byte) 0xF7, (byte) 0xDD, (byte) 0xAB,
+ (byte) 0xD4, (byte) 0xDD, (byte) 0xFC, (byte) 0x54, (byte) 0x37, (byte) 0x32,
+ (byte) 0x4B, (byte) 0xA3, (byte) 0xFB, (byte) 0x23, (byte) 0xA1, (byte) 0xC1,
+ (byte) 0x60, (byte) 0xDF, (byte) 0x41, (byte) 0xB0, (byte) 0xD1, (byte) 0xCC,
+ (byte) 0xDF, (byte) 0xAD, (byte) 0xB3, (byte) 0x66, (byte) 0x76, (byte) 0x36,
+ (byte) 0xEC, (byte) 0x6A, (byte) 0x53, (byte) 0xC3, (byte) 0xE2, (byte) 0xB0,
+ (byte) 0x77, (byte) 0xBE, (byte) 0x75, (byte) 0x08, (byte) 0xBA, (byte) 0x17,
+ (byte) 0x14, (byte) 0xFA, (byte) 0x1A, (byte) 0x30, (byte) 0xE7, (byte) 0xB9,
+ (byte) 0xED, (byte) 0xD6, (byte) 0xC1, (byte) 0xA5, (byte) 0x7A, (byte) 0x2B,
+ (byte) 0xA3, (byte) 0xA3, (byte) 0xDD, (byte) 0xDC, (byte) 0x14, (byte) 0xDB,
+ (byte) 0x7F, (byte) 0xF4, (byte) 0xF3, (byte) 0xAF, (byte) 0xCF, (byte) 0x0A,
+ (byte) 0xD3, (byte) 0xAC, (byte) 0x84, (byte) 0x39, (byte) 0x30, (byte) 0xCA,
+ (byte) 0x3C, (byte) 0xD8, (byte) 0xF7, (byte) 0xFA, (byte) 0x29, (byte) 0xDB,
+ (byte) 0x31, (byte) 0xA5, (byte) 0x62, (byte) 0x82, (byte) 0xD2, (byte) 0xB8,
+ (byte) 0x3C, (byte) 0xBC, (byte) 0x8F, (byte) 0xAB, (byte) 0xE4, (byte) 0xE8,
+ (byte) 0xA7, (byte) 0x2C, (byte) 0xEF, (byte) 0xC7, (byte) 0xD5, (byte) 0x12,
+ (byte) 0x16, (byte) 0x04, (byte) 0x6F, (byte) 0xCA, (byte) 0xEA, (byte) 0x31,
+ (byte) 0x9F, (byte) 0x41, (byte) 0xE0, (byte) 0x6F, (byte) 0xE4, (byte) 0x74,
+ (byte) 0x03, (byte) 0x78, (byte) 0xFA, (byte) 0x48, (byte) 0xB4, (byte) 0x6E,
+ (byte) 0xC8, (byte) 0xE7, (byte) 0x40, (byte) 0x8B, (byte) 0x88, (byte) 0x2F,
+ (byte) 0xED, (byte) 0x8E, (byte) 0x68, (byte) 0x96, (byte) 0x2C, (byte) 0xA7,
+ (byte) 0xB6, (byte) 0x03, (byte) 0x01, (byte) 0x01, (byte) 0x00};
+
+ private static final byte[] DUMMY_CERT =
+ new byte[] {(byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x58, (byte) 0x30,
+ (byte) 0x82, (byte) 0x01, (byte) 0xC1, (byte) 0xA0, (byte) 0x03, (byte) 0x02,
+ (byte) 0x01, (byte) 0x02, (byte) 0x02, (byte) 0x09, (byte) 0x00, (byte) 0xFB,
+ (byte) 0xB0, (byte) 0x4C, (byte) 0x2E, (byte) 0xAB, (byte) 0x10, (byte) 0x9B,
+ (byte) 0x0C, (byte) 0x30, (byte) 0x0D, (byte) 0x06, (byte) 0x09, (byte) 0x2A,
+ (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xF7, (byte) 0x0D, (byte) 0x01,
+ (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x30, (byte) 0x45,
+ (byte) 0x31, (byte) 0x0B, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03,
+ (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x41,
+ (byte) 0x55, (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06,
+ (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x0C, (byte) 0x0A,
+ (byte) 0x53, (byte) 0x6F, (byte) 0x6D, (byte) 0x65, (byte) 0x2D, (byte) 0x53,
+ (byte) 0x74, (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x31, (byte) 0x21,
+ (byte) 0x30, (byte) 0x1F, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
+ (byte) 0x0A, (byte) 0x0C, (byte) 0x18, (byte) 0x49, (byte) 0x6E, (byte) 0x74,
+ (byte) 0x65, (byte) 0x72, (byte) 0x6E, (byte) 0x65, (byte) 0x74, (byte) 0x20,
+ (byte) 0x57, (byte) 0x69, (byte) 0x64, (byte) 0x67, (byte) 0x69, (byte) 0x74,
+ (byte) 0x73, (byte) 0x20, (byte) 0x50, (byte) 0x74, (byte) 0x79, (byte) 0x20,
+ (byte) 0x4C, (byte) 0x74, (byte) 0x64, (byte) 0x30, (byte) 0x1E, (byte) 0x17,
+ (byte) 0x0D, (byte) 0x31, (byte) 0x34, (byte) 0x30, (byte) 0x34, (byte) 0x32,
+ (byte) 0x33, (byte) 0x32, (byte) 0x30, (byte) 0x35, (byte) 0x30, (byte) 0x34,
+ (byte) 0x30, (byte) 0x5A, (byte) 0x17, (byte) 0x0D, (byte) 0x31, (byte) 0x37,
+ (byte) 0x30, (byte) 0x34, (byte) 0x32, (byte) 0x32, (byte) 0x32, (byte) 0x30,
+ (byte) 0x35, (byte) 0x30, (byte) 0x34, (byte) 0x30, (byte) 0x5A, (byte) 0x30,
+ (byte) 0x45, (byte) 0x31, (byte) 0x0B, (byte) 0x30, (byte) 0x09, (byte) 0x06,
+ (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02,
+ (byte) 0x41, (byte) 0x55, (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11,
+ (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x0C,
+ (byte) 0x0A, (byte) 0x53, (byte) 0x6F, (byte) 0x6D, (byte) 0x65, (byte) 0x2D,
+ (byte) 0x53, (byte) 0x74, (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x31,
+ (byte) 0x21, (byte) 0x30, (byte) 0x1F, (byte) 0x06, (byte) 0x03, (byte) 0x55,
+ (byte) 0x04, (byte) 0x0A, (byte) 0x0C, (byte) 0x18, (byte) 0x49, (byte) 0x6E,
+ (byte) 0x74, (byte) 0x65, (byte) 0x72, (byte) 0x6E, (byte) 0x65, (byte) 0x74,
+ (byte) 0x20, (byte) 0x57, (byte) 0x69, (byte) 0x64, (byte) 0x67, (byte) 0x69,
+ (byte) 0x74, (byte) 0x73, (byte) 0x20, (byte) 0x50, (byte) 0x74, (byte) 0x79,
+ (byte) 0x20, (byte) 0x4C, (byte) 0x74, (byte) 0x64, (byte) 0x30, (byte) 0x81,
+ (byte) 0x9F, (byte) 0x30, (byte) 0x0D, (byte) 0x06, (byte) 0x09, (byte) 0x2A,
+ (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xF7, (byte) 0x0D, (byte) 0x01,
+ (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x81,
+ (byte) 0x8D, (byte) 0x00, (byte) 0x30, (byte) 0x81, (byte) 0x89, (byte) 0x02,
+ (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0xD8, (byte) 0x2B, (byte) 0xC8,
+ (byte) 0xA6, (byte) 0x32, (byte) 0xE4, (byte) 0x62, (byte) 0xFF, (byte) 0x4D,
+ (byte) 0xF3, (byte) 0xD0, (byte) 0xAD, (byte) 0x59, (byte) 0x8B, (byte) 0x45,
+ (byte) 0xA7, (byte) 0xBD, (byte) 0xF1, (byte) 0x47, (byte) 0xBF, (byte) 0x09,
+ (byte) 0x58, (byte) 0x7B, (byte) 0x22, (byte) 0xBD, (byte) 0x35, (byte) 0xAE,
+ (byte) 0x97, (byte) 0x25, (byte) 0x86, (byte) 0x94, (byte) 0xA0, (byte) 0x80,
+ (byte) 0xC0, (byte) 0xB4, (byte) 0x1F, (byte) 0x76, (byte) 0x91, (byte) 0x67,
+ (byte) 0x46, (byte) 0x31, (byte) 0xD0, (byte) 0x10, (byte) 0x84, (byte) 0xB7,
+ (byte) 0x22, (byte) 0x1E, (byte) 0x70, (byte) 0x23, (byte) 0x91, (byte) 0x72,
+ (byte) 0xC8, (byte) 0xE9, (byte) 0x6D, (byte) 0x79, (byte) 0x3A, (byte) 0x85,
+ (byte) 0x77, (byte) 0x80, (byte) 0x0F, (byte) 0xC4, (byte) 0x95, (byte) 0x16,
+ (byte) 0x75, (byte) 0xC5, (byte) 0x4A, (byte) 0x71, (byte) 0x4C, (byte) 0xC8,
+ (byte) 0x63, (byte) 0x3F, (byte) 0xA3, (byte) 0xF2, (byte) 0x63, (byte) 0x9C,
+ (byte) 0x2A, (byte) 0x4F, (byte) 0x9A, (byte) 0xFA, (byte) 0xCB, (byte) 0xC1,
+ (byte) 0x71, (byte) 0x6E, (byte) 0x28, (byte) 0x85, (byte) 0x28, (byte) 0xA0,
+ (byte) 0x27, (byte) 0x1E, (byte) 0x65, (byte) 0x1C, (byte) 0xAE, (byte) 0x07,
+ (byte) 0xD5, (byte) 0x5B, (byte) 0x6F, (byte) 0x2D, (byte) 0x43, (byte) 0xED,
+ (byte) 0x2B, (byte) 0x90, (byte) 0xB1, (byte) 0x8C, (byte) 0xAF, (byte) 0x24,
+ (byte) 0x6D, (byte) 0xAE, (byte) 0xE9, (byte) 0x17, (byte) 0x3A, (byte) 0x05,
+ (byte) 0xC1, (byte) 0xBF, (byte) 0xB8, (byte) 0x1C, (byte) 0xAE, (byte) 0x65,
+ (byte) 0x3B, (byte) 0x1B, (byte) 0x58, (byte) 0xC2, (byte) 0xD9, (byte) 0xAE,
+ (byte) 0xD6, (byte) 0xAA, (byte) 0x67, (byte) 0x88, (byte) 0xF1, (byte) 0x02,
+ (byte) 0x03, (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0xA3, (byte) 0x50,
+ (byte) 0x30, (byte) 0x4E, (byte) 0x30, (byte) 0x1D, (byte) 0x06, (byte) 0x03,
+ (byte) 0x55, (byte) 0x1D, (byte) 0x0E, (byte) 0x04, (byte) 0x16, (byte) 0x04,
+ (byte) 0x14, (byte) 0x8B, (byte) 0x75, (byte) 0xD5, (byte) 0xAC, (byte) 0xCB,
+ (byte) 0x08, (byte) 0xBE, (byte) 0x0E, (byte) 0x1F, (byte) 0x65, (byte) 0xB7,
+ (byte) 0xFA, (byte) 0x56, (byte) 0xBE, (byte) 0x6C, (byte) 0xA7, (byte) 0x75,
+ (byte) 0xDA, (byte) 0x85, (byte) 0xAF, (byte) 0x30, (byte) 0x1F, (byte) 0x06,
+ (byte) 0x03, (byte) 0x55, (byte) 0x1D, (byte) 0x23, (byte) 0x04, (byte) 0x18,
+ (byte) 0x30, (byte) 0x16, (byte) 0x80, (byte) 0x14, (byte) 0x8B, (byte) 0x75,
+ (byte) 0xD5, (byte) 0xAC, (byte) 0xCB, (byte) 0x08, (byte) 0xBE, (byte) 0x0E,
+ (byte) 0x1F, (byte) 0x65, (byte) 0xB7, (byte) 0xFA, (byte) 0x56, (byte) 0xBE,
+ (byte) 0x6C, (byte) 0xA7, (byte) 0x75, (byte) 0xDA, (byte) 0x85, (byte) 0xAF,
+ (byte) 0x30, (byte) 0x0C, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1D,
+ (byte) 0x13, (byte) 0x04, (byte) 0x05, (byte) 0x30, (byte) 0x03, (byte) 0x01,
+ (byte) 0x01, (byte) 0xFF, (byte) 0x30, (byte) 0x0D, (byte) 0x06, (byte) 0x09,
+ (byte) 0x2A, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xF7, (byte) 0x0D,
+ (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x03,
+ (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0x3B, (byte) 0xE8, (byte) 0x78,
+ (byte) 0x6D, (byte) 0x95, (byte) 0xD6, (byte) 0x3D, (byte) 0x6A, (byte) 0xF7,
+ (byte) 0x13, (byte) 0x19, (byte) 0x2C, (byte) 0x1B, (byte) 0xC2, (byte) 0x88,
+ (byte) 0xAE, (byte) 0x22, (byte) 0xAB, (byte) 0xF4, (byte) 0x8D, (byte) 0x32,
+ (byte) 0xF5, (byte) 0x7C, (byte) 0x71, (byte) 0x67, (byte) 0xCF, (byte) 0x2D,
+ (byte) 0xD1, (byte) 0x1C, (byte) 0xC2, (byte) 0xC3, (byte) 0x87, (byte) 0xE2,
+ (byte) 0xE9, (byte) 0xBE, (byte) 0x89, (byte) 0x5C, (byte) 0xE4, (byte) 0x34,
+ (byte) 0xAB, (byte) 0x48, (byte) 0x91, (byte) 0xC2, (byte) 0x3F, (byte) 0x95,
+ (byte) 0xAE, (byte) 0x2B, (byte) 0x47, (byte) 0x9E, (byte) 0x25, (byte) 0x78,
+ (byte) 0x6B, (byte) 0x4F, (byte) 0x9A, (byte) 0x10, (byte) 0xA4, (byte) 0x72,
+ (byte) 0xFD, (byte) 0xCF, (byte) 0xF7, (byte) 0x02, (byte) 0x0C, (byte) 0xB0,
+ (byte) 0x0A, (byte) 0x08, (byte) 0xA4, (byte) 0x5A, (byte) 0xE2, (byte) 0xE5,
+ (byte) 0x74, (byte) 0x7E, (byte) 0x11, (byte) 0x1D, (byte) 0x39, (byte) 0x60,
+ (byte) 0x6A, (byte) 0xC9, (byte) 0x1F, (byte) 0x69, (byte) 0xF3, (byte) 0x2E,
+ (byte) 0x63, (byte) 0x26, (byte) 0xDC, (byte) 0x9E, (byte) 0xEF, (byte) 0x6B,
+ (byte) 0x7A, (byte) 0x0A, (byte) 0xE1, (byte) 0x54, (byte) 0x57, (byte) 0x98,
+ (byte) 0xAA, (byte) 0x72, (byte) 0x91, (byte) 0x78, (byte) 0x04, (byte) 0x7E,
+ (byte) 0x1F, (byte) 0x8F, (byte) 0x65, (byte) 0x4D, (byte) 0x1F, (byte) 0x0B,
+ (byte) 0x12, (byte) 0xAC, (byte) 0x9C, (byte) 0x24, (byte) 0x0F, (byte) 0x84,
+ (byte) 0x14, (byte) 0x1A, (byte) 0x55, (byte) 0x2D, (byte) 0x1F, (byte) 0xBB,
+ (byte) 0xF0, (byte) 0x9D, (byte) 0x09, (byte) 0xB2, (byte) 0x08, (byte) 0x5C,
+ (byte) 0x59, (byte) 0x32, (byte) 0x65, (byte) 0x80, (byte) 0x26};
+
+ private static final byte[] DUMMY_OCSP_DATA = new byte[1];
+
+ private static final byte[] DUMMY_TLS_SCT_DATA = new byte[1];
+
+ @After
+ public void tearDown() throws Exception {
+ assertEquals(0, NativeCrypto.ERR_peek_last_error());
+ }
+
+ private static TestSessionBuilder getType1() {
+ return new TestSessionBuilder()
+ .setType(0x01)
+ .setSessionData(kOpenSSLSession)
+ .addCertificate(DUMMY_CERT);
+ }
+
+ private static TestSessionBuilder getType2() {
+ return new TestSessionBuilder()
+ .setType(0x02)
+ .setSessionData(kOpenSSLSession)
+ .addCertificate(DUMMY_CERT)
+ .addOcspData(DUMMY_OCSP_DATA);
+ }
+
+ private static TestSessionBuilder getType3() {
+ return new TestSessionBuilder()
+ .setType(0x03)
+ .setSessionData(kOpenSSLSession)
+ .addCertificate(DUMMY_CERT)
+ .addOcspData(DUMMY_OCSP_DATA)
+ .setTlsSctData(DUMMY_TLS_SCT_DATA);
+ }
+
+ @Test
+ public void toSession_EmptyArray_Invalid_Failure() throws Exception {
+ assertInvalidSession(new byte[0]);
+ }
+
+ @Test
+ public void toSession_Type1_Valid_Success() throws Exception {
+ assertValidSession(getType1().build());
+ }
+
+ @Test
+ public void toSession_Type2_Valid_Success() throws Exception {
+ assertValidSession(getType2().build());
+ }
+
+ @Test
+ public void toSession_Type3_Valid_Success() throws Exception {
+ assertValidSession(getType3().build());
+ }
+
+ private void assertTruncatedSessionFails(byte[] validSession) {
+ for (int i = 0; i < validSession.length - 1; i++) {
+ byte[] truncatedSession = new byte[i];
+ System.arraycopy(validSession, 0, truncatedSession, 0, i);
+ assertNull("Truncating to " + i + " bytes of " + validSession.length
+ + " should not succeed",
+ SslSessionWrapper.newInstance(null, truncatedSession, "www.google.com", 443));
+ }
+ }
+
+ @Test
+ public void toSession_Type3_Truncated_Failure() throws Exception {
+ assertTruncatedSessionFails(getType3().build());
+ }
+
+ private static void assertValidSession(byte[] data) {
+ assertNotNull(SslSessionWrapper.newInstance(null, data, "www.google.com", 443));
+ }
+
+ private static void assertInvalidSession(byte[] data) {
+ assertNull(SslSessionWrapper.newInstance(null, data, "www.google.com", 443));
+ }
+
+ @Test
+ public void toSession_UnknownType_Failure() throws Exception {
+ assertInvalidSession(getType3().setType((byte) 0xEE).build());
+ }
+
+ @Test
+ public void toSession_CertificatesCountTooLarge_Failure() throws Exception {
+ assertInvalidSession(getType3().setCertificatesLength(16834).build());
+ }
+
+ @Test
+ public void toSession_CertificatesCountNegative_Failure() throws Exception {
+ assertInvalidSession(getType3().setCertificatesLength(-1).build());
+ }
+
+ @Test
+ public void toSession_CertificateSizeNegative_Failure() throws Exception {
+ assertInvalidSession(getType3().setCertificateLength(0, -1).build());
+ }
+
+ @Test
+ public void toSession_CertificateSizeTooLarge_Failure() throws Exception {
+ assertInvalidSession(getType3().setCertificateLength(0, 16834).build());
+ }
+
+ @Test
+ public void toSession_SessionDataSizeTooLarge_Failure() throws Exception {
+ assertInvalidSession(getType3().setSessionDataLength(16834).build());
+ }
+
+ @Test
+ public void toSession_SessionDataSizeNegative_Failure() throws Exception {
+ assertInvalidSession(getType3().setSessionDataLength(-1).build());
+ }
+
+ @Test
+ public void toSession_OcspDatasNumberTooMany_Failure() throws Exception {
+ assertInvalidSession(getType3().setOcspDatasLength(32791).build());
+ }
+
+ @Test
+ public void toSession_OcspDatasNumberNegative_Failure() throws Exception {
+ assertInvalidSession(getType3().setOcspDatasLength(-1).build());
+ }
+
+ @Test
+ public void toSession_OcspDataSizeNegative_Failure() throws Exception {
+ assertInvalidSession(getType3().setOcspDataLength(0, -1).build());
+ }
+
+ @Test
+ public void toSession_OcspDataSizeTooLarge_Failure() throws Exception {
+ assertInvalidSession(getType3().setOcspDataLength(0, 92948).build());
+ }
+
+ @Test
+ public void toSession_TlsSctDataSizeNegative_Failure() throws Exception {
+ assertInvalidSession(getType3().setTlsSctDataLength(-1).build());
+ }
+
+ @Test
+ public void toSession_TlsSctDataSizeTooLarge_Failure() throws Exception {
+ assertInvalidSession(getType3().setTlsSctDataLength(931148).build());
+ }
+
+ @Test
+ public void toSession_Type2OcspDataEmpty_Success() throws Exception {
+ assertValidSession(getType1().setType(0x02).setOcspDataEmpty().build());
+ }
+
+ @Test
+ public void toSession_Type3TlsSctDataEmpty_Success() throws Exception {
+ assertValidSession(getType2().setType(0x03).setTlsSctDataEmpty().build());
+ }
+
+ @Test
+ public void toSession_Type3OcspAndTlsSctDataEmpty_Success() throws Exception {
+ assertValidSession(
+ getType1().setType(0x03).setOcspDataEmpty().setTlsSctDataEmpty().build());
+ }
+
+ private static void assertTrailingDataFails(byte[] validSession) {
+ byte[] invalidSession = new byte[validSession.length + 1];
+ System.arraycopy(validSession, 0, invalidSession, 0, validSession.length);
+ assertInvalidSession(invalidSession);
+ }
+
+ @Test
+ public void toSession_Type1TrailingData_Failure() throws Exception {
+ assertTrailingDataFails(getType1().build());
+ }
+
+ @Test
+ public void toSession_Type2TrailingData_Failure() throws Exception {
+ assertTrailingDataFails(getType2().build());
+ }
+
+ @Test
+ public void toSession_Type3TrailingData_Failure() throws Exception {
+ assertTrailingDataFails(getType3().build());
+ }
+
+ @Test
+ public void test_reserializableFromByteArray_roundTrip_type1() throws Exception {
+ // Converting OPEN_SSL (type 1) -> OPEN_SSL_WITH_TLS_SCT (type 3) adds
+ // eight zero-bytes:
+ // 1.) 4 bytes for int32 value 0 == countOcspResponses
+ // 2.) 4 bytes for int32 value 0 == tlsSctDataLength
+ // since OPEN_SSL (type 1) cannot contain OSCP or TLS SCT data.
+ check_reserializableFromByteArray_roundTrip(getType1().build(), new byte[8]);
+ }
+
+ @Test
+ public void test_reserializableFromByteArray_roundTrip_type2() throws Exception {
+ // Converting OPEN_SSL_WITH_OCSP (type 2) -> OPEN_SSL_WITH_TLS_SCT (type 3) adds
+ // four zero-bytes for int32 value 0 == tlsSctDataLength
+ // since OPEN_SSL_WITH_OCSP (type 2) cannot contain TLS SCT data.
+ check_reserializableFromByteArray_roundTrip(getType2().build(), new byte[4]);
+ }
+
+ @Test
+ public void test_reserializableFromByteArray_roundTrip_type3() throws Exception {
+ check_reserializableFromByteArray_roundTrip(getType3().build(), new byte[0]);
+ }
+
+ private static void check_reserializableFromByteArray_roundTrip(
+ byte[] data, byte[] expectedTrailingBytesAfterReserialization) throws Exception {
+ SslSessionWrapper session =
+ SslSessionWrapper.newInstance(null, data, "www.example.com", 12345);
+ byte[] sessionBytes = session.toBytes();
+
+ SslSessionWrapper session2 =
+ SslSessionWrapper.newInstance(null, sessionBytes, "www.example.com", 12345);
+ byte[] sessionBytes2 = session2.toBytes();
+
+ assertSSLSessionEquals(session, session2);
+ assertByteArrayEquals(sessionBytes, sessionBytes2);
+
+ assertEquals("www.example.com", session.getPeerHost());
+ assertEquals(12345, session.getPeerPort());
+ assertTrue(sessionBytes.length >= data.length);
+
+ byte[] expectedReserializedData = concat(data, expectedTrailingBytesAfterReserialization);
+ // AbstractSessionContext.toBytes() always writes type 3 == OPEN_SSL_WITH_TLS_SCT
+ expectedReserializedData[3] = 3;
+ assertByteArrayEquals(expectedReserializedData, sessionBytes);
+ }
+
+ private static byte[] concat(byte[] a, byte[] b) {
+ byte[] result = new byte[a.length + b.length];
+ System.arraycopy(a, 0, result, 0, a.length);
+ System.arraycopy(b, 0, result, a.length, b.length);
+ return result;
+ }
+
+ private static void assertSSLSessionEquals(SslSessionWrapper a, SslSessionWrapper b)
+ throws Exception {
+ assertEquals(a.getCipherSuite(), b.getCipherSuite());
+ assertByteArrayEquals(a.getId(), b.getId());
+ assertEquals(a.getPeerHost(), b.getPeerHost());
+ assertEquals(a.getPeerPort(), b.getPeerPort());
+ assertEquals(a.getProtocol(), b.getProtocol());
+ }
+
+ private static void assertByteArrayEquals(byte[] expected, byte[] actual) {
+ // If running on OpenJDK 8+, could use java.util.Base64 for better failure messages:
+ // assertEquals(Base64.encode(expected), Base64.encode(actual));
+ assertTrue("Expected " + Arrays.toString(expected) + ", got " + Arrays.toString(actual),
+ Arrays.equals(expected, actual));
+ }
+}
diff --git a/platform/src/main/java/org/conscrypt/Platform.java b/platform/src/main/java/org/conscrypt/Platform.java
index 5a62468..d53e69a 100644
--- a/platform/src/main/java/org/conscrypt/Platform.java
+++ b/platform/src/main/java/org/conscrypt/Platform.java
@@ -334,14 +334,15 @@
* Pre-Java 8 backward compatibility.
*/
- static SSLSession wrapSSLSession(AbstractOpenSSLSession sslSession) {
- return new OpenSSLExtendedSessionImpl(sslSession);
+ static SSLSession wrapSSLSession(ActiveSession sslSession) {
+ return new DelegatingExtendedSSLSession(sslSession);
}
static SSLSession unwrapSSLSession(SSLSession sslSession) {
- if (sslSession instanceof OpenSSLExtendedSessionImpl) {
- return ((OpenSSLExtendedSessionImpl) sslSession).getDelegate();
+ if (sslSession instanceof DelegatingExtendedSSLSession) {
+ return ((DelegatingExtendedSSLSession) sslSession).getDelegate();
}
+
return sslSession;
}
diff --git a/platform/src/main/java/org/conscrypt/TrustManagerImpl.java b/platform/src/main/java/org/conscrypt/TrustManagerImpl.java
index 010c75a..95f7f48 100644
--- a/platform/src/main/java/org/conscrypt/TrustManagerImpl.java
+++ b/platform/src/main/java/org/conscrypt/TrustManagerImpl.java
@@ -420,8 +420,8 @@
private byte[] getOcspDataFromSession(SSLSession session) {
List<byte[]> ocspResponses = null;
- if (session instanceof AbstractOpenSSLSession) {
- AbstractOpenSSLSession opensslSession = (AbstractOpenSSLSession) session;
+ if (session instanceof ActiveSession) {
+ ActiveSession opensslSession = (ActiveSession) session;
ocspResponses = opensslSession.getStatusResponses();
} else {
Method m_getResponses;
@@ -447,14 +447,14 @@
}
private byte[] getTlsSctDataFromSession(SSLSession session) {
- if (session instanceof AbstractOpenSSLSession) {
- AbstractOpenSSLSession opensslSession = (AbstractOpenSSLSession) session;
- return opensslSession.getTlsSctData();
+ if (session instanceof ActiveSession) {
+ ActiveSession opensslSession = (ActiveSession) session;
+ return opensslSession.getPeerSignedCertificateTimestamp();
}
byte[] data = null;
try {
- Method m_getTlsSctData = session.getClass().getDeclaredMethod("getTlsSctData");
+ Method m_getTlsSctData = session.getClass().getDeclaredMethod("getPeerSignedCertificateTimestamp");
m_getTlsSctData.setAccessible(true);
Object rawData = m_getTlsSctData.invoke(session);
if (rawData instanceof byte[]) {
@@ -789,7 +789,7 @@
/**
- * Comparator for sorting {@link TrustAnchor}s using a {@link CertificateComparator}.
+ * Comparator for sorting {@link TrustAnchor}s using a {@link CertificatePriorityComparator}.
*/
private static class TrustAnchorComparator implements Comparator<TrustAnchor> {
private static final CertificatePriorityComparator CERT_COMPARATOR =
diff --git a/testing/src/main/java/libcore/javax/net/ssl/TestSSLSessions.java b/testing/src/main/java/libcore/javax/net/ssl/TestSSLSessions.java
index 34596bc..8f45a2e 100644
--- a/testing/src/main/java/libcore/javax/net/ssl/TestSSLSessions.java
+++ b/testing/src/main/java/libcore/javax/net/ssl/TestSSLSessions.java
@@ -27,19 +27,23 @@
* An invalid session that is not connected
*/
public final SSLSession invalid;
+
/**
* The server side of a connected session
*/
public final SSLSession server;
+
/**
* The client side of a connected session
*/
public final SSLSession client;
+
/**
* The associated SSLSocketTest.Helper that is the source of
* the client and server SSLSessions.
*/
public final TestSSLSocketPair s;
+
private TestSSLSessions(SSLSession invalid,
SSLSession server,
SSLSession client,
@@ -49,15 +53,17 @@
this.client = client;
this.s = s;
}
+
public void close() {
s.close();
}
- public static final TestSSLSessions create() {
+
+ public static TestSSLSessions create() {
try {
SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket ssl = (SSLSocket) sf.createSocket();
SSLSession invalid = ssl.getSession();
- TestSSLSocketPair s = TestSSLSocketPair.create();
+ TestSSLSocketPair s = TestSSLSocketPair.create().connect();
return new TestSSLSessions(invalid, s.server.getSession(), s.client.getSession(), s);
} catch (Exception e) {
throw new RuntimeException(e);
diff --git a/testing/src/main/java/libcore/javax/net/ssl/TestSSLSocketPair.java b/testing/src/main/java/libcore/javax/net/ssl/TestSSLSocketPair.java
index 66e7ac7..c6d59fe 100644
--- a/testing/src/main/java/libcore/javax/net/ssl/TestSSLSocketPair.java
+++ b/testing/src/main/java/libcore/javax/net/ssl/TestSSLSocketPair.java
@@ -15,6 +15,7 @@
*/
package libcore.javax.net.ssl;
+import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -31,9 +32,7 @@
public final TestSSLContext c;
public final SSLSocket server;
public final SSLSocket client;
- private TestSSLSocketPair (TestSSLContext c,
- SSLSocket server,
- SSLSocket client) {
+ private TestSSLSocketPair(TestSSLContext c, SSLSocket server, SSLSocket client) {
this.c = c;
this.server = server;
this.client = client;
@@ -47,14 +46,15 @@
throw new RuntimeException(e);
}
}
- /**
- * based on test_SSLSocket_startHandshake
- */
- public static TestSSLSocketPair create () {
- TestSSLContext c = TestSSLContext.create();
- SSLSocket[] sockets = connect(c, null, null);
- return new TestSSLSocketPair(c, sockets[0], sockets[1]);
+
+ public SSLSocket[] sockets() {
+ return new SSLSocket[] {server, client};
}
+
+ public TestSSLSocketPair connect() {
+ return connect(null, null);
+ }
+
/**
* Create a new connected server/client socket pair within a
* existing SSLContext. Optionally specify clientCipherSuites to
@@ -62,13 +62,9 @@
* caching. Optionally specify serverCipherSuites for testing
* cipher suite negotiation.
*/
- public static SSLSocket[] connect (final TestSSLContext context,
- final String[] clientCipherSuites,
- final String[] serverCipherSuites) {
+ public TestSSLSocketPair connect(
+ final String[] clientCipherSuites, final String[] serverCipherSuites) {
try {
- final SSLSocket client = (SSLSocket)
- context.clientContext.getSocketFactory().createSocket(context.host, context.port);
- final SSLSocket server = (SSLSocket) context.serverSocket.accept();
ExecutorService executor = Executors.newFixedThreadPool(2);
Future<Void> s = executor.submit(new Callable<Void>() {
@Override
@@ -115,11 +111,29 @@
if (clientException != null) {
throw clientException;
}
- return new SSLSocket[] { server, client };
+ return this;
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
+
+ public static TestSSLSocketPair create() {
+ return create(TestSSLContext.create());
+ }
+
+ /**
+ * based on test_SSLSocket_startHandshake
+ */
+ public static TestSSLSocketPair create(TestSSLContext context) {
+ try {
+ SSLSocket client = (SSLSocket) context.clientContext.getSocketFactory().createSocket(
+ context.host, context.port);
+ SSLSocket server = (SSLSocket) context.serverSocket.accept();
+ return new TestSSLSocketPair(context, server, client);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
}