blob: 324dacf2567d283aca3873e480a1eeda80eae069 [file] [log] [blame]
/*
* 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.
*/
#define LOG_TAG "OpenSSLSessionImpl"
#include <jni.h>
#include <JNIHelp.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include <openssl/ssl.h>
#include "org_apache_harmony_xnet_provider_jsse_common.h"
/**
* Module scope variables initialized during JNI registration.
*/
static jfieldID field_session;
static SSL_SESSION *getSslSessionPointer(JNIEnv* env, jobject object) {
SSL_SESSION* session = (SSL_SESSION *)env->GetIntField(object, field_session);
return session;
}
/**
* Gets the peer certificate in the chain and fills a byte array with the
* information therein.
*/
static jobjectArray org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getpeercertificates(JNIEnv* env,
jobject object, jint jssl)
{
SSL_SESSION *ssl_session;
SSL_CTX* ssl_ctx;
SSL* ssl;
STACK_OF(X509) *chain;
jobjectArray objectArray;
ssl_session = getSslSessionPointer(env, object);
ssl_ctx = SSL_CTX_new(SSLv23_client_method());
ssl = SSL_new(ssl_ctx);
SSL_set_session(ssl, ssl_session);
chain = SSL_get_peer_cert_chain(ssl);
objectArray = getcertificatebytes(env, chain);
SSL_free(ssl);
SSL_CTX_free(ssl_ctx);
return objectArray;
}
/**
* Serialize the session.
* See apache mod_ssl
*/
static jbyteArray org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_serialize(JNIEnv* env, jobject object)
{
SSL_SESSION * ssl_session;
jbyteArray bytes = NULL;
jbyte *tmp;
int size;
unsigned char *ucp;
ssl_session = getSslSessionPointer(env, object);
if (ssl_session == NULL) {
return NULL;
}
// Compute the size of the DER data
size = i2d_SSL_SESSION(ssl_session, NULL);
if (size == 0) {
return NULL;
}
bytes = env->NewByteArray(size);
if (bytes != NULL) {
tmp = env->GetByteArrayElements(bytes, NULL);
ucp = (unsigned char *) tmp;
i2d_SSL_SESSION(ssl_session, &ucp);
env->ReleaseByteArrayElements(bytes, tmp, 0);
}
return bytes;
}
/**
* Deserialize the session.
*/
static jint org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_deserialize(JNIEnv* env, jobject object, jbyteArray bytes, jint size)
{
const unsigned char *ucp;
jbyte *tmp;
SSL_SESSION *ssl_session;
if (bytes != NULL) {
tmp = env->GetByteArrayElements(bytes, NULL);
ucp = (const unsigned char *) tmp;
ssl_session = d2i_SSL_SESSION(NULL, &ucp, (long) size);
env->ReleaseByteArrayElements(bytes, tmp, 0);
return (jint) ssl_session;
}
return 0;
}
/**
* Gets and returns in a byte array the ID of the actual SSL session.
*/
static jbyteArray org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getid(JNIEnv* env, jobject object)
{
SSL_SESSION* ssl_session = getSslSessionPointer(env, object);
jbyteArray result = env->NewByteArray(ssl_session->session_id_length);
if (result != NULL) {
jbyte* src = reinterpret_cast<jbyte*>(ssl_session->session_id);
env->SetByteArrayRegion(result, 0, ssl_session->session_id_length, src);
}
return result;
}
/**
* Gets and returns in a long integer the creation's time of the
* actual SSL session.
*/
static jlong org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getcreationtime(JNIEnv* env, jobject object)
{
SSL_SESSION * ssl_session;
ssl_session = getSslSessionPointer(env, object);
// convert the creation time from seconds to milliseconds
return (jlong)(1000L * ssl_session->time);
}
/**
* Gets and returns in a string the peer's host's name.
*/
static jstring org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getpeerhost(JNIEnv* env, jobject object)
{
SSL_CTX *ssl_ctx;
SSL *ssl;
SSL_SESSION *ssl_session;
BIO *bio;
char* hostname;
jstring result;
ssl_session = getSslSessionPointer(env, object);
ssl_ctx = SSL_CTX_new(SSLv23_client_method());
ssl = SSL_new(ssl_ctx);
SSL_set_session(ssl, ssl_session);
bio = SSL_get_rbio(ssl);
hostname = BIO_get_conn_hostname(bio);
/* Notice: hostname can be NULL */
result = env->NewStringUTF(hostname);
SSL_free(ssl);
SSL_CTX_free(ssl_ctx);
return result;
}
/**
* Gets and returns in a string the peer's port name (https, ftp, etc.).
*/
static jstring org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getpeerport(JNIEnv* env, jobject object)
{
SSL_CTX *ssl_ctx;
SSL *ssl;
SSL_SESSION *ssl_session;
BIO *bio;
char *port;
jstring result;
ssl_session = getSslSessionPointer(env, object);
ssl_ctx = SSL_CTX_new(SSLv23_client_method());
ssl = SSL_new(ssl_ctx);
SSL_set_session(ssl, ssl_session);
bio = SSL_get_rbio(ssl);
port = BIO_get_conn_port(bio);
/* Notice: port name can be NULL */
result = env->NewStringUTF(port);
SSL_free(ssl);
SSL_CTX_free(ssl_ctx);
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.
*/
static jstring org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getprotocol(JNIEnv* env, jobject object)
{
SSL_CTX *ssl_ctx;
SSL *ssl;
SSL_SESSION *ssl_session;
const char* protocol;
jstring result;
ssl_session = getSslSessionPointer(env, object);
ssl_ctx = SSL_CTX_new(SSLv23_client_method());
ssl = SSL_new(ssl_ctx);
SSL_set_session(ssl, ssl_session);
protocol = SSL_get_version(ssl);
result = env->NewStringUTF(protocol);
SSL_free(ssl);
SSL_CTX_free(ssl_ctx);
return result;
}
/**
* Gets and returns in a string the set of ciphers the actual SSL session uses.
*/
static jstring org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getciphersuite(JNIEnv* env, jobject object)
{
SSL_CTX *ssl_ctx;
SSL *ssl;
SSL_SESSION *ssl_session;
ssl_session = getSslSessionPointer(env, object);
ssl_ctx = SSL_CTX_new(SSLv23_client_method());
ssl = SSL_new(ssl_ctx);
SSL_set_session(ssl, ssl_session);
SSL_CIPHER *cipher = SSL_get_current_cipher(ssl);
jstring result = env->NewStringUTF(SSL_CIPHER_get_name(cipher));
SSL_free(ssl);
SSL_CTX_free(ssl_ctx);
return result;
}
/**
* Frees the SSL session.
*/
static void org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_free(JNIEnv* env, jobject object, jint session)
{
LOGD("Freeing OpenSSL session");
SSL_SESSION* ssl_session;
ssl_session = (SSL_SESSION*) session;
SSL_SESSION_free(ssl_session);
}
/**
* The actual JNI methods' mapping table for the class OpenSSLSessionImpl.
*/
static JNINativeMethod sMethods[] =
{
{"nativegetid", "()[B", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getid},
{"nativegetcreationtime", "()J", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getcreationtime},
{"nativegetpeerhost", "()Ljava/lang/String;", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getpeerhost},
{"nativegetpeerport", "()Ljava/lang/String;", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getpeerport},
{"nativegetprotocol", "()Ljava/lang/String;", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getprotocol},
{"nativegetciphersuite", "()Ljava/lang/String;", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getciphersuite},
{"nativegetpeercertificates", "()[[B", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getpeercertificates},
{"nativefree", "(I)V", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_free},
{"nativeserialize", "()[B", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_serialize},
{"nativedeserialize", "([BI)I", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_deserialize}
};
/**
* Register the native methods with JNI for the class OpenSSLSessionImpl.
*/
extern "C" int register_org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl(JNIEnv* env)
{
int ret;
jclass clazz;
clazz = env->FindClass("org/apache/harmony/xnet/provider/jsse/OpenSSLSessionImpl");
if (clazz == NULL) {
LOGE("Can't find org/apache/harmony/xnet/provider/jsse/OpenSSLSessionImpl");
return -1;
}
field_session = env->GetFieldID(clazz, "session", "I");
ret = jniRegisterNativeMethods(env, "org/apache/harmony/xnet/provider/jsse/OpenSSLSessionImpl",
sMethods, NELEM(sMethods));
return ret;
}