|
1 /* |
|
2 * Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: ?Description |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include "nativesecureconnection.h" |
|
20 #include "jniarrayutils.h" |
|
21 #include "logger.h" |
|
22 #include "nativecertificatemanager.h" |
|
23 |
|
24 using namespace java; |
|
25 |
|
26 NativeSecureConnection::NativeSecureConnection(const char * aName, |
|
27 int aMode, const char * aHost, int aPort) : |
|
28 NativeSocketConnection(aName, aMode, aHost, aPort) |
|
29 { |
|
30 JELOG2(ESOCKET); |
|
31 mName = NULL; |
|
32 mHost = NULL; |
|
33 mName = new char[strlen(aName) + 1]; |
|
34 strcpy(mName, aName); |
|
35 mHost = new char[strlen(aHost) + 1]; |
|
36 strcpy(mHost, aHost); |
|
37 mMode = aMode; |
|
38 mPort = aPort; |
|
39 mSecureSocketBuffer = NULL; |
|
40 } |
|
41 |
|
42 int NativeSecureConnection::doHandshake(int aSocket, int aType, int aApn, int * err1, int *err2) |
|
43 { |
|
44 JELOG2(ESOCKET); |
|
45 int ret; |
|
46 //int temp; |
|
47 mSockDesc = aSocket; |
|
48 initialiseSslConnection(); |
|
49 if (mSockDesc == -1) |
|
50 { |
|
51 mSockDesc = socketOpen(-1, aType, aApn,err1); |
|
52 } |
|
53 //LOG1(ESOCKET,EInfo ,"setdefault = %d",&temp); |
|
54 //err = &temp; |
|
55 LOG1(ESOCKET,EInfo, "setdefault = %d", *err1); |
|
56 if (mSockDesc < 0) |
|
57 { |
|
58 return mSockDesc; // error code, whie creating socket |
|
59 } |
|
60 ret = secureHandshake(); |
|
61 |
|
62 if (ret < 0) |
|
63 { |
|
64 // ssl handshake failed |
|
65 LOG(ESOCKET,EInfo,"secure handshake failed"); |
|
66 ELOG1(ESOCKET, "handshake error code = %d", |
|
67 ret); |
|
68 } |
|
69 else |
|
70 { // handshake ok, verify the certificate |
|
71 X509 * peer = SSL_get_peer_certificate(mSslObj); |
|
72 getCertificateInformation(peer); |
|
73 int validflag = NativeCertificateManager::validateX509Certificate(peer); |
|
74 LOG1(ESOCKET,EInfo, " NativeCertificateManager::validateX509Certificate returned %d",validflag); |
|
75 if (validflag < 0) |
|
76 { |
|
77 *err2 = validflag; |
|
78 return 0; |
|
79 } |
|
80 ret = SSL_get_verify_result(mSslObj); |
|
81 |
|
82 LOG1(ESOCKET,EInfo, "Secure socket is open, socket descriptor is %d", |
|
83 mSockDesc); |
|
84 } |
|
85 return ret; |
|
86 } |
|
87 |
|
88 X509* NativeSecureConnection::getCertificate() |
|
89 { |
|
90 X509 * peer = SSL_get_peer_certificate(mSslObj); |
|
91 return peer; |
|
92 } |
|
93 |
|
94 OS_EXPORT int NativeSecureConnection::readBytes(JNIEnv& aJni, |
|
95 jbyteArray aJavaBuffer) |
|
96 { |
|
97 JELOG2(ESOCKET); |
|
98 if (mSecureSocketBuffer == NULL) |
|
99 { |
|
100 /* |
|
101 Memory is allocated to mSecureSocketBuffer only once during the first call of this readBytes() function |
|
102 Since the value of mBufferSize will be unknown(uninitialized) during the constructor call, it is not |
|
103 possible to do this operation inside the constructor. |
|
104 */ |
|
105 |
|
106 mSecureSocketBuffer = new char[mBufferSize]; |
|
107 } |
|
108 // secureSocketRead() function will actually make the OpenC call to read the data from the socket |
|
109 mBytesRead = secureSocketRead(mSecureSocketBuffer, mBufferSize); |
|
110 |
|
111 /* Copy the data read from the native buffer to the java buffer. Copy only "bytesRead" number of bytes. |
|
112 Because it is possible that the java request for some 'n' bytes to be read, but actually lesser bytes of data was |
|
113 read from the socket. |
|
114 */ |
|
115 if (mBytesRead > 0) |
|
116 { |
|
117 JNIArrayUtils::CopyToJava(aJni, mSecureSocketBuffer, mBytesRead, |
|
118 aJavaBuffer, 0, mBytesRead); |
|
119 } |
|
120 else if (mBytesRead < 0) |
|
121 return mBytesRead; // holds ssl read error code |
|
122 |
|
123 return mBytesRead; |
|
124 } |
|
125 |
|
126 OS_EXPORT int NativeSecureConnection::writeBytes(JNIEnv& aJni, |
|
127 jbyteArray aJavaBuffer, int aOffset, int aLength) |
|
128 { |
|
129 JELOG2(ESOCKET); |
|
130 char* iWriteBuffer = new char[aLength + 1]; |
|
131 |
|
132 /* Copy the data to be written from java buffer to the native buffer. */ |
|
133 JNIArrayUtils::CopyToNative(aJni, aJavaBuffer, aOffset, aLength, |
|
134 iWriteBuffer); |
|
135 |
|
136 // secureSocketWrite() function will actually make the OpenC call to read the data from the socket |
|
137 int num = secureSocketWrite(iWriteBuffer, aLength); |
|
138 delete[] iWriteBuffer; |
|
139 iWriteBuffer = NULL; |
|
140 return num; |
|
141 } |
|
142 |
|
143 |
|
144 /* ------------------------------------------------------------- |
|
145 This function initialises all the SSL libraries |
|
146 |
|
147 Open C APIs used |
|
148 |
|
149 SSL_load_error_strings(): Loads and registers all the libssl error |
|
150 strings |
|
151 |
|
152 OpenSSL_add_all_algorithms(): adds all algorithms to the the internal |
|
153 table. |
|
154 |
|
155 SSL_library_init(): iniitializes SSL library by registering algorithms |
|
156 This should be called before calling any SSL apis |
|
157 |
|
158 SSL_CTX_new: creates a new context object as a framework to |
|
159 establish TLS/SSL enabled connections. |
|
160 It initializes the list of ciphers, the session cache |
|
161 setting,the callbacks, the keys and certificates, and |
|
162 the options to its default values |
|
163 |
|
164 SSL_new : SSL_new Creates a new SSL structure and inherits the settings |
|
165 of underlying ctx |
|
166 |
|
167 --------------------------------------------------------------*/ |
|
168 |
|
169 OS_EXPORT void NativeSecureConnection::initialiseSslConnection() |
|
170 { |
|
171 JELOG2(ESOCKET); |
|
172 |
|
173 |
|
174 SSL_load_error_strings(); // No return value |
|
175 |
|
176 ERR_load_BIO_strings(); // No return value |
|
177 |
|
178 OpenSSL_add_all_algorithms(); // No return value |
|
179 |
|
180 |
|
181 SSL_library_init(); |
|
182 |
|
183 |
|
184 mCtxObj = SSL_CTX_new(SSLv23_client_method()); |
|
185 if (mCtxObj == NULL) |
|
186 { |
|
187 ELOG(ESOCKET, "Initialize ssl connection, ctx is null"); |
|
188 } |
|
189 if ((mSslObj = SSL_new(mCtxObj)) == NULL) |
|
190 { |
|
191 ELOG(ESOCKET, "SSL_new failed"); |
|
192 } |
|
193 else |
|
194 { |
|
195 ILOG(ESOCKET, "SSL_new success"); |
|
196 } |
|
197 } |
|
198 |
|
199 /* ------------------------------------------------------------- |
|
200 This function performs SSL handshake with the server |
|
201 |
|
202 Open C APIs used: |
|
203 |
|
204 BIO_new_socket(): returns a socket BIO (I/O abstraction) |
|
205 |
|
206 SSL_set_bio(): connect a SSL object with a BIO |
|
207 |
|
208 SSL_connect(): SSL_connect()initiates the TLS/SSL handshake with a server. |
|
209 The communication channel must already have been set and assigned |
|
210 to the ssl by setting an underlying BIO. |
|
211 -----------------------------------------------------------------*/ |
|
212 |
|
213 OS_EXPORT int NativeSecureConnection::secureHandshake() |
|
214 { |
|
215 JELOG2(ESOCKET); |
|
216 int retVal; |
|
217 int error; |
|
218 // set up bio object |
|
219 mBio = BIO_new_socket(mSockDesc, BIO_NOCLOSE); |
|
220 if (mBio == NULL) |
|
221 { |
|
222 ELOG(ESOCKET, "BIO_new_socket failed"); |
|
223 } |
|
224 else |
|
225 { |
|
226 ILOG(ESOCKET, "BIO_new_socket success"); |
|
227 } |
|
228 |
|
229 //Set the bio object to SSL |
|
230 SSL_set_bio(mSslObj, mBio, mBio); |
|
231 retVal = SSL_connect(mSslObj); |
|
232 |
|
233 // If SSL_connect fails it returns -1. To get the error code SSL_get_error() api |
|
234 // is called along with return value and ssl object |
|
235 if (retVal < 0) |
|
236 { |
|
237 error = SSL_get_error(mSslObj, retVal); |
|
238 retVal = -error; |
|
239 |
|
240 } |
|
241 return retVal; |
|
242 |
|
243 } |
|
244 |
|
245 |
|
246 /*-------------------------------------------------------------- |
|
247 This function calls SSL_write() to send data over a secure socket |
|
248 |
|
249 ---------------------------------------------------------------*/ |
|
250 |
|
251 int NativeSecureConnection::secureSocketWrite(char *aBuf, int len) |
|
252 { |
|
253 |
|
254 ILOG1(ESOCKET, "writebuffer is %s", aBuf); |
|
255 int error; |
|
256 int retVal = SSL_write(mSslObj, aBuf, len); |
|
257 ILOG1(ESOCKET, "--NativeSecureConnection::secureSocketWrite len= %d", retVal); |
|
258 if (retVal < 0) |
|
259 { |
|
260 ELOG1(ESOCKET, "secure socket write returned %d", retVal); |
|
261 |
|
262 // If SSL_write fails it returns -1. To get the error code |
|
263 // SSL_get_error() api is called along with return value |
|
264 // and ssl object |
|
265 error = SSL_get_error(mSslObj, retVal); |
|
266 retVal = -error; |
|
267 } |
|
268 return retVal; |
|
269 } |
|
270 |
|
271 |
|
272 /*------------------------------------------------------------ |
|
273 This function calls SSL_read() to recieve data over a secure socket |
|
274 |
|
275 -------------------------------------------------------------*/ |
|
276 |
|
277 int NativeSecureConnection::secureSocketRead(char *aBuf, int len) |
|
278 { |
|
279 |
|
280 int error; |
|
281 int retVal = SSL_read(mSslObj, aBuf, len); |
|
282 ILOG1(ESOCKET, "no of bytes read is %d", retVal); |
|
283 if (retVal < 0) |
|
284 { |
|
285 // If SSL_read fails it returns -1. To get the error code |
|
286 // SSL_get_error() api is called along with return value |
|
287 // and ssl object |
|
288 error = SSL_get_error(mSslObj, retVal); |
|
289 retVal = -error; |
|
290 } |
|
291 return retVal; |
|
292 } |
|
293 |
|
294 OS_EXPORT void NativeSecureConnection::stopReading() |
|
295 { |
|
296 return; |
|
297 } |
|
298 |
|
299 OS_EXPORT void NativeSecureConnection::stopWriting() |
|
300 { |
|
301 return; |
|
302 } |
|
303 |
|
304 |
|
305 /*-------------------------------------------------------------- |
|
306 This function closes the secure socket |
|
307 |
|
308 Open C APIs used : |
|
309 |
|
310 SSL_CTX_free(): decrements the reference count of ctx |
|
311 and removes the SSL_CTX object pointed to by ctx |
|
312 and frees up the allocated memory if the reference count has reached 0. |
|
313 |
|
314 ERR_free_strings(): frees all the loaded error strings |
|
315 |
|
316 close() : closes the secure socket descriptor |
|
317 |
|
318 ---------------------------------------------------------------*/ |
|
319 int NativeSecureConnection::secureSocketClose() |
|
320 { |
|
321 JELOG2(ESOCKET); |
|
322 int retVal; |
|
323 |
|
324 SSL_CTX_free(mCtxObj); // No return value |
|
325 |
|
326 |
|
327 ERR_free_strings(); // No return value |
|
328 |
|
329 retVal = close(mSockDesc); |
|
330 if (retVal < 0) |
|
331 { |
|
332 retVal = -errno; |
|
333 } |
|
334 return retVal; |
|
335 |
|
336 } |
|
337 |
|
338 /*-------------------------------------------------------------- |
|
339 This function gets the peer certificate related information |
|
340 |
|
341 Open C APIs used |
|
342 |
|
343 X509_get_serialNumber(): gets the serial number of the certificate |
|
344 |
|
345 X509_get_subject_name(): get the certificate subject name |
|
346 |
|
347 X509_get_version(): returns certifcates version |
|
348 |
|
349 X509_get_notBefore(): get the certificate time after, value is string |
|
350 in the form of yymmddhhmmss (time w.r.t to GMT) |
|
351 |
|
352 X509_get_notAfter(): get the certificate time after, value is string |
|
353 in the form of yymmddhhmmss (time w.r.t to GMT) |
|
354 |
|
355 SSL_CIPHER_get_name(): returns the name of the SSL cipher |
|
356 |
|
357 ----------------------------------------------------------------*/ |
|
358 void NativeSecureConnection::getCertificateInformation(X509 *aPeer) |
|
359 { |
|
360 JELOG2(ESOCKET); |
|
361 ASN1_INTEGER *x1 = X509_get_serialNumber(aPeer); |
|
362 |
|
363 // conversion of serial number into a string |
|
364 BIGNUM *bntmp = ASN1_INTEGER_to_BN(x1, NULL); |
|
365 char *serial_no = BN_bn2hex(bntmp); |
|
366 |
|
367 |
|
368 char subject_name[512]; |
|
369 X509_NAME_oneline(X509_get_subject_name(aPeer), subject_name, |
|
370 sizeof(subject_name)); |
|
371 |
|
372 // get the certificate issure name, value is string |
|
373 char issuer_name[512]; |
|
374 X509_NAME_oneline(X509_get_issuer_name(aPeer), issuer_name, |
|
375 sizeof(issuer_name)); |
|
376 |
|
377 long version = X509_get_version(aPeer); |
|
378 char version_string[10]; |
|
379 sprintf(version_string,"%ld",version); |
|
380 |
|
381 |
|
382 ASN1_TIME *cert_time; |
|
383 char *time_notbef; |
|
384 cert_time = X509_get_notBefore(aPeer); |
|
385 time_notbef = (char*) cert_time->data; |
|
386 |
|
387 ASN1_TIME *cert_time_after; |
|
388 char *time_notafter; |
|
389 cert_time_after = X509_get_notAfter(aPeer); |
|
390 time_notafter = (char*) cert_time_after->data; |
|
391 |
|
392 // get the signature algorithm type, value is string. ex = sha1WithRSAEncryption |
|
393 int type = OBJ_obj2nid((aPeer)->sig_alg->algorithm); |
|
394 const char *alg_name = OBJ_nid2ln(type); |
|
395 |
|
396 //get the cipher name used by this ssl |
|
397 const char *cipher_name = SSL_CIPHER_get_name(SSL_get_current_cipher( |
|
398 mSslObj)); |
|
399 |
|
400 const char *protocol_name = SSL_get_version(mSslObj); |
|
401 |
|
402 PLOG1(ESOCKET, "Peer certificate subject name %s", subject_name); |
|
403 PLOG1(ESOCKET, "Peer certificate issuer name %s", issuer_name); |
|
404 PLOG1(ESOCKET, "Peer certificate serial number %s", serial_no); |
|
405 PLOG1(ESOCKET, "Peer certificate serial number strlen %d", strlen( |
|
406 serial_no)); |
|
407 PLOG1(ESOCKET, "Peer certificate version string %s", version_string); |
|
408 PLOG1(ESOCKET, "Peer certificate get not before time %s", time_notbef); |
|
409 PLOG1(ESOCKET, "Peer certificate get not time after %s", |
|
410 time_notafter); |
|
411 PLOG1(ESOCKET, "alg_name %s", alg_name); |
|
412 PLOG1(ESOCKET, "current cipher %s", cipher_name); |
|
413 PLOG1(ESOCKET, "current protocol %s", protocol_name); |
|
414 |
|
415 // Allocate memory for 9 string as we know that 9 certificate properties will be retrieved |
|
416 mResult = (char **) malloc(9 * sizeof(char *)); |
|
417 |
|
418 mResult[0] = (char *) malloc((strlen(subject_name) + 1) * sizeof(char)); |
|
419 strcpy(mResult[0], subject_name); |
|
420 |
|
421 mResult[1] = (char *) malloc((strlen(issuer_name) + 1) * sizeof(char)); |
|
422 strcpy(mResult[1], issuer_name); |
|
423 |
|
424 mResult[2] = (char *) malloc((strlen(serial_no) + 1) * sizeof(char)); |
|
425 strcpy(mResult[2], serial_no); |
|
426 |
|
427 mResult[3] = (char *) malloc((strlen(time_notbef) + 1) * sizeof(char)); |
|
428 strcpy(mResult[3], time_notbef); |
|
429 |
|
430 mResult[4] = (char *) malloc((strlen(time_notafter) + 1) * sizeof(char)); |
|
431 strcpy(mResult[4], time_notafter); |
|
432 |
|
433 mResult[5] = (char *) malloc((strlen(alg_name) + 1) * sizeof(char)); |
|
434 strcpy(mResult[5], alg_name); |
|
435 |
|
436 mResult[6] = (char *) malloc(20 * sizeof(char)); |
|
437 strcpy(mResult[6], version_string); |
|
438 |
|
439 mResult[7] = (char *) malloc(50 * sizeof(char)); |
|
440 strcpy(mResult[7], protocol_name); |
|
441 |
|
442 mResult[8] = (char *) malloc(50 * sizeof(char)); |
|
443 strcpy(mResult[8], cipher_name); |
|
444 } |
|
445 |
|
446 OS_EXPORT char ** NativeSecureConnection::getSecurityInfo() |
|
447 { |
|
448 JELOG2(ESOCKET); |
|
449 return mResult; |
|
450 } |
|
451 |
|
452 NativeSecureConnection::~NativeSecureConnection() |
|
453 { |
|
454 JELOG2(ESOCKET); |
|
455 if (mSecureSocketBuffer != NULL) |
|
456 { |
|
457 delete[] mSecureSocketBuffer; |
|
458 mSecureSocketBuffer = NULL; |
|
459 } |
|
460 int i; |
|
461 for (i=0; i<9; i++) |
|
462 { |
|
463 delete[] mResult[i]; |
|
464 } |
|
465 mResult = NULL; |
|
466 } |