OSDN Git Service

e0ea0b8d236185ba478431eba4c9c6664122280d
[android-x86/dalvik.git] / libcore / x-net / src / main / native / org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl.cpp
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #define LOG_TAG "OpenSSLSessionImpl"
18
19 #include "AndroidSystemNatives.h"
20 #include "JNIHelp.h"
21
22 #include <jni.h>
23
24 #include <stdio.h>
25 #include <string.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <arpa/inet.h>
29 #include <netinet/in.h>
30 #include <stdlib.h>
31 #include <errno.h>
32 #include <unistd.h>
33
34 #include <openssl/err.h>
35 #include <openssl/rand.h>
36 #include <openssl/ssl.h>
37
38 #include "org_apache_harmony_xnet_provider_jsse_common.h"
39
40 static jfieldID field_session;
41
42 static SSL_SESSION* getSslSessionPointer(JNIEnv* env, jobject object) {
43     return reinterpret_cast<SSL_SESSION*>(env->GetIntField(object, field_session));
44 }
45
46 // Fills a byte[][] with the peer certificates in the chain.
47 static jobjectArray OpenSSLSessionImpl_getPeerCertificatesImpl(JNIEnv* env,
48         jobject object, jint jssl)
49 {
50     SSL_SESSION* ssl_session = getSslSessionPointer(env, object);
51     SSL_CTX* ssl_ctx = SSL_CTX_new(SSLv23_client_method());
52     SSL* ssl = SSL_new(ssl_ctx);
53
54     SSL_set_session(ssl, ssl_session);
55
56     STACK_OF(X509)* chain = SSL_get_peer_cert_chain(ssl);
57     jobjectArray objectArray = getcertificatebytes(env, chain);
58
59     SSL_free(ssl);
60     SSL_CTX_free(ssl_ctx);
61     return objectArray;
62 }
63
64 /**
65  * Serializes the native state of the session (ID, cipher, and keys but
66  * not certificates). Returns a byte[] containing the DER-encoded state.
67  * See apache mod_ssl.
68  */
69 static jbyteArray OpenSSLSessionImpl_getEncoded(JNIEnv* env, jobject object) {
70     SSL_SESSION* ssl_session = getSslSessionPointer(env, object);
71     if (ssl_session == NULL) {
72         return NULL;
73     }
74
75     // Compute the size of the DER data
76     int size = i2d_SSL_SESSION(ssl_session, NULL);
77     if (size == 0) {
78         return NULL;
79     }
80
81     jbyteArray bytes = env->NewByteArray(size);
82     if (bytes != NULL) {
83         jbyte* tmp = env->GetByteArrayElements(bytes, NULL);
84         unsigned char* ucp = reinterpret_cast<unsigned char*>(tmp);
85         i2d_SSL_SESSION(ssl_session, &ucp);
86         env->ReleaseByteArrayElements(bytes, tmp, 0);
87     }
88
89     return bytes;
90 }
91
92 /**
93  * Deserialize the session.
94  */
95 static jint OpenSSLSessionImpl_initializeNativeImpl(JNIEnv* env, jobject object, jbyteArray bytes, jint size) {
96     if (bytes == NULL) {
97         return 0;
98     }
99
100     jbyte* tmp = env->GetByteArrayElements(bytes, NULL);
101     const unsigned char* ucp = reinterpret_cast<const unsigned char*>(tmp);
102     SSL_SESSION* ssl_session = d2i_SSL_SESSION(NULL, &ucp, size);
103     env->ReleaseByteArrayElements(bytes, tmp, 0);
104
105     return static_cast<jint>(reinterpret_cast<uintptr_t>(ssl_session));
106 }
107
108 /**
109  * Gets and returns in a byte array the ID of the actual SSL session.
110  */
111 static jbyteArray OpenSSLSessionImpl_getId(JNIEnv* env, jobject object) {
112     SSL_SESSION* ssl_session = getSslSessionPointer(env, object);
113
114     jbyteArray result = env->NewByteArray(ssl_session->session_id_length);
115     if (result != NULL) {
116         jbyte* src = reinterpret_cast<jbyte*>(ssl_session->session_id);
117         env->SetByteArrayRegion(result, 0, ssl_session->session_id_length, src);
118     }
119
120     return result;
121 }
122
123 /**
124  * Gets and returns in a long integer the creation's time of the
125  * actual SSL session.
126  */
127 static jlong OpenSSLSessionImpl_getCreationTime(JNIEnv* env, jobject object) {
128     SSL_SESSION* ssl_session = getSslSessionPointer(env, object);
129     jlong result = SSL_SESSION_get_time(ssl_session);
130     result *= 1000; // OpenSSL uses seconds, Java uses milliseconds.
131     return result;
132 }
133
134 /**
135  * Gets and returns in a string the version of the SSL protocol. If it
136  * returns the string "unknown" it means that no connection is established.
137  */
138 static jstring OpenSSLSessionImpl_getProtocol(JNIEnv* env, jobject object) {
139     SSL_SESSION* ssl_session = getSslSessionPointer(env, object);
140     SSL_CTX* ssl_ctx = SSL_CTX_new(SSLv23_client_method());
141     SSL* ssl = SSL_new(ssl_ctx);
142
143     SSL_set_session(ssl, ssl_session);
144
145     const char* protocol = SSL_get_version(ssl);
146     jstring result = env->NewStringUTF(protocol);
147
148     SSL_free(ssl);
149     SSL_CTX_free(ssl_ctx);
150     return result;
151 }
152
153 /**
154  * Gets and returns in a string the set of ciphers the actual SSL session uses.
155  */
156 static jstring OpenSSLSessionImpl_getCipherSuite(JNIEnv* env, jobject object) {
157     SSL_SESSION* ssl_session = getSslSessionPointer(env, object);
158     SSL_CTX* ssl_ctx = SSL_CTX_new(SSLv23_client_method());
159     SSL* ssl = SSL_new(ssl_ctx);
160
161     SSL_set_session(ssl, ssl_session);
162
163     SSL_CIPHER* cipher = SSL_get_current_cipher(ssl);
164     jstring result = env->NewStringUTF(SSL_CIPHER_get_name(cipher));
165
166     SSL_free(ssl);
167     SSL_CTX_free(ssl_ctx);
168     return result;
169 }
170
171 /**
172  * Frees the SSL session.
173  */
174 static void OpenSSLSessionImpl_freeImpl(JNIEnv* env, jobject object, jint session) {
175     LOGD("Freeing OpenSSL session");
176     SSL_SESSION* ssl_session = reinterpret_cast<SSL_SESSION*>(session);
177     SSL_SESSION_free(ssl_session);
178 }
179
180 static JNINativeMethod sMethods[] = {
181     { "freeImpl", "(I)V", (void*) OpenSSLSessionImpl_freeImpl },
182     { "getCipherSuite", "()Ljava/lang/String;", (void*) OpenSSLSessionImpl_getCipherSuite },
183     { "getCreationTime", "()J", (void*) OpenSSLSessionImpl_getCreationTime },
184     { "getEncoded", "()[B", (void*) OpenSSLSessionImpl_getEncoded },
185     { "getId", "()[B", (void*) OpenSSLSessionImpl_getId },
186     { "getPeerCertificatesImpl", "()[[B", (void*) OpenSSLSessionImpl_getPeerCertificatesImpl },
187     { "getProtocol", "()Ljava/lang/String;", (void*) OpenSSLSessionImpl_getProtocol },
188     { "initializeNativeImpl", "([BI)I", (void*) OpenSSLSessionImpl_initializeNativeImpl }
189 };
190
191 int register_org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl(JNIEnv* env) {
192     jclass clazz = env->FindClass("org/apache/harmony/xnet/provider/jsse/OpenSSLSessionImpl");
193     if (clazz == NULL) {
194         return -1;
195     }
196
197     field_session = env->GetFieldID(clazz, "session", "I");
198
199     return jniRegisterNativeMethods(env, "org/apache/harmony/xnet/provider/jsse/OpenSSLSessionImpl",
200             sMethods, NELEM(sMethods));
201 }