javacommons/gcfprotocols/secureconnection/src/nativesecureconnection.cpp
branchRCL_3
changeset 19 04becd199f91
child 87 1627c337e51e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javacommons/gcfprotocols/secureconnection/src/nativesecureconnection.cpp	Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,466 @@
+/*
+* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  ?Description
+ *
+*/
+
+
+#include "nativesecureconnection.h"
+#include "jniarrayutils.h"
+#include "logger.h"
+#include "nativecertificatemanager.h"
+
+using namespace java;
+
+NativeSecureConnection::NativeSecureConnection(const char * aName,
+        int aMode, const char * aHost, int aPort) :
+        NativeSocketConnection(aName, aMode, aHost, aPort)
+{
+    JELOG2(ESOCKET);
+    mName = NULL;
+    mHost = NULL;
+    mName = new char[strlen(aName) + 1];
+    strcpy(mName, aName);
+    mHost = new char[strlen(aHost) + 1];
+    strcpy(mHost, aHost);
+    mMode = aMode;
+    mPort = aPort;
+    mSecureSocketBuffer = NULL;
+}
+
+int NativeSecureConnection::doHandshake(int aSocket, int aType, int aApn, int * err1, int *err2)
+{
+    JELOG2(ESOCKET);
+    int ret;
+    //int temp;
+    mSockDesc = aSocket;
+    initialiseSslConnection();
+    if (mSockDesc == -1)
+    {
+        mSockDesc = socketOpen(-1, aType, aApn,err1);
+    }
+    //LOG1(ESOCKET,EInfo ,"setdefault  =  %d",&temp);
+    //err = &temp;
+    LOG1(ESOCKET,EInfo, "setdefault  =  %d", *err1);
+    if (mSockDesc < 0)
+    {
+        return mSockDesc;      // error code, whie creating socket
+    }
+    ret = secureHandshake();
+
+    if (ret < 0)
+    {
+        // ssl handshake failed
+        LOG(ESOCKET,EInfo,"secure handshake failed");
+        ELOG1(ESOCKET, "handshake error code =  %d",
+              ret);
+    }
+    else
+    {  // handshake ok, verify the certificate
+        X509 * peer = SSL_get_peer_certificate(mSslObj);
+        getCertificateInformation(peer);
+        int validflag = NativeCertificateManager::validateX509Certificate(peer);
+        LOG1(ESOCKET,EInfo, " NativeCertificateManager::validateX509Certificate returned %d",validflag);
+        if (validflag < 0)
+        {
+            *err2 = validflag;
+            return 0;
+        }
+        ret = SSL_get_verify_result(mSslObj);
+
+        LOG1(ESOCKET,EInfo, "Secure socket is open, socket descriptor is %d",
+             mSockDesc);
+    }
+    return ret;
+}
+
+X509* NativeSecureConnection::getCertificate()
+{
+    X509 * peer = SSL_get_peer_certificate(mSslObj);
+    return peer;
+}
+
+OS_EXPORT int NativeSecureConnection::readBytes(JNIEnv& aJni,
+        jbyteArray aJavaBuffer)
+{
+    JELOG2(ESOCKET);
+    if (mSecureSocketBuffer == NULL)
+    {
+        /*
+        Memory is allocated to mSecureSocketBuffer only once during the first call of this readBytes() function
+        Since the value of mBufferSize will be unknown(uninitialized) during the constructor call, it is not
+        possible to do this operation inside the constructor.
+        */
+
+        mSecureSocketBuffer = new char[mBufferSize];
+    }
+    // secureSocketRead() function will actually make the OpenC call to read the data from the socket
+    mBytesRead = secureSocketRead(mSecureSocketBuffer, mBufferSize);
+
+    /* Copy the data read from the native buffer to the java buffer. Copy only "bytesRead" number of bytes.
+       Because it is possible that the java request for some 'n' bytes to be read, but actually lesser bytes of data was
+       read from the socket.
+    */
+    if (mBytesRead > 0)
+    {
+        JNIArrayUtils::CopyToJava(aJni, mSecureSocketBuffer, mBytesRead,
+                                  aJavaBuffer, 0, mBytesRead);
+    }
+    else if (mBytesRead < 0)
+        return mBytesRead;   // holds ssl read error code
+
+    return mBytesRead;
+}
+
+OS_EXPORT int NativeSecureConnection::writeBytes(JNIEnv& aJni,
+        jbyteArray aJavaBuffer, int aOffset, int aLength)
+{
+    JELOG2(ESOCKET);
+    char* iWriteBuffer = new char[aLength + 1];
+
+    /* Copy the data to be written from java buffer to the native buffer.  */
+    JNIArrayUtils::CopyToNative(aJni, aJavaBuffer, aOffset, aLength,
+                                iWriteBuffer);
+
+    // secureSocketWrite() function will actually make the OpenC call to read the data from the socket
+    int num = secureSocketWrite(iWriteBuffer, aLength);
+    delete[] iWriteBuffer;
+    iWriteBuffer = NULL;
+    return num;
+}
+
+
+/* -------------------------------------------------------------
+This function initialises all the SSL libraries
+
+Open C APIs used
+
+SSL_load_error_strings(): Loads and registers all the libssl error
+                          strings
+
+OpenSSL_add_all_algorithms(): adds all algorithms to the the internal
+                              table.
+
+SSL_library_init(): iniitializes SSL library by registering algorithms
+                    This should be called before calling any SSL apis
+
+SSL_CTX_new: creates a new context object as a framework to
+             establish TLS/SSL enabled connections.
+             It initializes the list of ciphers, the session cache
+             setting,the callbacks, the keys and certificates, and
+             the options to its default values
+
+SSL_new : SSL_new Creates a new SSL structure and inherits the settings
+          of underlying ctx
+
+--------------------------------------------------------------*/
+
+OS_EXPORT void NativeSecureConnection::initialiseSslConnection()
+{
+    JELOG2(ESOCKET);
+
+
+    SSL_load_error_strings(); // No return value
+
+    ERR_load_BIO_strings();   // No return value
+
+    OpenSSL_add_all_algorithms(); // No return value
+
+
+    SSL_library_init();
+
+
+    mCtxObj = SSL_CTX_new(SSLv23_client_method());
+    if (mCtxObj == NULL)
+    {
+        ELOG(ESOCKET, "Initialize ssl connection, ctx is null");
+    }
+    if ((mSslObj = SSL_new(mCtxObj)) == NULL)
+    {
+        ELOG(ESOCKET, "SSL_new failed");
+    }
+    else
+    {
+        ILOG(ESOCKET, "SSL_new success");
+    }
+}
+
+/* -------------------------------------------------------------
+This function performs SSL handshake with the server
+
+Open C APIs used:
+
+BIO_new_socket(): returns a socket BIO (I/O abstraction)
+
+SSL_set_bio(): connect a SSL object with a BIO
+
+SSL_connect(): SSL_connect()initiates the TLS/SSL handshake with a server.
+              The communication channel must already have been set and assigned
+              to the ssl by setting an underlying BIO.
+-----------------------------------------------------------------*/
+
+OS_EXPORT int NativeSecureConnection::secureHandshake()
+{
+    JELOG2(ESOCKET);
+    int retVal;
+    int error;
+    // set up bio object
+    mBio = BIO_new_socket(mSockDesc, BIO_NOCLOSE);
+    if (mBio == NULL)
+    {
+        ELOG(ESOCKET, "BIO_new_socket failed");
+    }
+    else
+    {
+        ILOG(ESOCKET, "BIO_new_socket success");
+    }
+
+    //Set the bio object to SSL
+    SSL_set_bio(mSslObj, mBio, mBio);
+    retVal = SSL_connect(mSslObj);
+
+    // If SSL_connect fails it returns -1. To get the error code SSL_get_error() api
+    // is called along with return value and ssl object
+    if (retVal < 0)
+    {
+        error = SSL_get_error(mSslObj, retVal);
+        retVal = -error;
+
+    }
+    return retVal;
+
+}
+
+
+/*--------------------------------------------------------------
+This function calls SSL_write() to send data over a secure socket
+
+---------------------------------------------------------------*/
+
+int NativeSecureConnection::secureSocketWrite(char *aBuf, int len)
+{
+
+    ILOG1(ESOCKET, "writebuffer is %s", aBuf);
+    int error;
+    int retVal = SSL_write(mSslObj, aBuf, len);
+    ILOG1(ESOCKET, "--NativeSecureConnection::secureSocketWrite len=  %d", retVal);
+    if (retVal < 0)
+    {
+        ELOG1(ESOCKET, "secure socket write returned %d", retVal);
+
+        // If SSL_write fails it returns -1. To get the error code
+        // SSL_get_error() api is called along with return value
+        // and ssl object
+        error = SSL_get_error(mSslObj, retVal);
+        retVal = -error;
+    }
+    return retVal;
+}
+
+
+/*------------------------------------------------------------
+This function calls SSL_read() to recieve data over a secure socket
+
+-------------------------------------------------------------*/
+
+int NativeSecureConnection::secureSocketRead(char *aBuf, int len)
+{
+
+    int error;
+    int retVal = SSL_read(mSslObj, aBuf, len);
+    ILOG1(ESOCKET, "no of bytes read is %d", retVal);
+    if (retVal < 0)
+    {
+        // If SSL_read fails it returns -1. To get the error code
+        // SSL_get_error() api is called along with return value
+        // and ssl object
+        error = SSL_get_error(mSslObj, retVal);
+        retVal = -error;
+    }
+    return retVal;
+}
+
+OS_EXPORT void NativeSecureConnection::stopReading()
+{
+    return;
+}
+
+OS_EXPORT void NativeSecureConnection::stopWriting()
+{
+    return;
+}
+
+
+/*--------------------------------------------------------------
+This function closes the secure socket
+
+Open C APIs used :
+
+SSL_CTX_free(): decrements the reference count of ctx
+                 and removes the SSL_CTX object pointed to by ctx
+                 and frees up the allocated memory if the reference count has reached 0.
+
+ERR_free_strings(): frees all the loaded error strings
+
+close() : closes the secure socket descriptor
+
+---------------------------------------------------------------*/
+int NativeSecureConnection::secureSocketClose()
+{
+    JELOG2(ESOCKET);
+    int retVal;
+
+    SSL_CTX_free(mCtxObj); // No return value
+
+
+    ERR_free_strings(); // No return value
+
+    retVal = close(mSockDesc);
+    if (retVal < 0)
+    {
+        retVal = -errno;
+    }
+    return retVal;
+
+}
+
+/*--------------------------------------------------------------
+This function gets the peer certificate related information
+
+Open C APIs used
+
+X509_get_serialNumber(): gets the serial number of the certificate
+
+X509_get_subject_name(): get the certificate subject name
+
+X509_get_version(): returns certifcates version
+
+X509_get_notBefore(): get the certificate time after, value is string
+                      in the form of yymmddhhmmss (time w.r.t to GMT)
+
+X509_get_notAfter(): get the certificate time after, value is string
+                     in the form of yymmddhhmmss (time w.r.t to GMT)
+
+SSL_CIPHER_get_name(): returns the name of the SSL cipher
+
+----------------------------------------------------------------*/
+void NativeSecureConnection::getCertificateInformation(X509 *aPeer)
+{
+    JELOG2(ESOCKET);
+    ASN1_INTEGER *x1 = X509_get_serialNumber(aPeer);
+
+    // conversion of serial number into a string
+    BIGNUM *bntmp = ASN1_INTEGER_to_BN(x1, NULL);
+    char *serial_no = BN_bn2hex(bntmp);
+
+
+    char subject_name[512];
+    X509_NAME_oneline(X509_get_subject_name(aPeer), subject_name,
+                      sizeof(subject_name));
+
+    // get the certificate issure name, value is string
+    char issuer_name[512];
+    X509_NAME_oneline(X509_get_issuer_name(aPeer), issuer_name,
+                      sizeof(issuer_name));
+
+    long version = X509_get_version(aPeer);
+    char version_string[10];
+    sprintf(version_string,"%ld",version);
+
+
+    ASN1_TIME *cert_time;
+    char *time_notbef;
+    cert_time = X509_get_notBefore(aPeer);
+    time_notbef = (char*) cert_time->data;
+
+    ASN1_TIME *cert_time_after;
+    char *time_notafter;
+    cert_time_after = X509_get_notAfter(aPeer);
+    time_notafter = (char*) cert_time_after->data;
+
+    // get the signature algorithm type, value is string. ex = sha1WithRSAEncryption
+    int type = OBJ_obj2nid((aPeer)->sig_alg->algorithm);
+    const char *alg_name = OBJ_nid2ln(type);
+
+    //get the cipher name used by this ssl
+    const char *cipher_name = SSL_CIPHER_get_name(SSL_get_current_cipher(
+                                  mSslObj));
+
+    const char *protocol_name = SSL_get_version(mSslObj);
+
+    PLOG1(ESOCKET, "Peer certificate subject name %s", subject_name);
+    PLOG1(ESOCKET, "Peer certificate issuer name %s", issuer_name);
+    PLOG1(ESOCKET, "Peer certificate serial number %s", serial_no);
+    PLOG1(ESOCKET, "Peer certificate serial number strlen %d", strlen(
+              serial_no));
+    PLOG1(ESOCKET, "Peer certificate version string  %s", version_string);
+    PLOG1(ESOCKET, "Peer certificate get not before time %s", time_notbef);
+    PLOG1(ESOCKET, "Peer certificate get not time after %s",
+          time_notafter);
+    PLOG1(ESOCKET, "alg_name %s", alg_name);
+    PLOG1(ESOCKET, "current cipher %s", cipher_name);
+    PLOG1(ESOCKET, "current protocol %s", protocol_name);
+
+    // Allocate memory for 9 string as we know that 9 certificate properties will be retrieved
+    mResult = (char **) malloc(9 * sizeof(char *));
+
+    mResult[0] = (char *) malloc((strlen(subject_name) + 1) * sizeof(char));
+    strcpy(mResult[0], subject_name);
+
+    mResult[1] = (char *) malloc((strlen(issuer_name) + 1) * sizeof(char));
+    strcpy(mResult[1], issuer_name);
+
+    mResult[2] = (char *) malloc((strlen(serial_no) + 1) * sizeof(char));
+    strcpy(mResult[2], serial_no);
+
+    mResult[3] = (char *) malloc((strlen(time_notbef) + 1) * sizeof(char));
+    strcpy(mResult[3], time_notbef);
+
+    mResult[4] = (char *) malloc((strlen(time_notafter) + 1) * sizeof(char));
+    strcpy(mResult[4], time_notafter);
+
+    mResult[5] = (char *) malloc((strlen(alg_name) + 1) * sizeof(char));
+    strcpy(mResult[5], alg_name);
+
+    mResult[6] = (char *) malloc(20 * sizeof(char));
+    strcpy(mResult[6], version_string);
+
+    mResult[7] = (char *) malloc(50 * sizeof(char));
+    strcpy(mResult[7], protocol_name);
+
+    mResult[8] = (char *) malloc(50 * sizeof(char));
+    strcpy(mResult[8], cipher_name);
+}
+
+OS_EXPORT char ** NativeSecureConnection::getSecurityInfo()
+{
+    JELOG2(ESOCKET);
+    return mResult;
+}
+
+NativeSecureConnection::~NativeSecureConnection()
+{
+    JELOG2(ESOCKET);
+    if (mSecureSocketBuffer != NULL)
+    {
+        delete[] mSecureSocketBuffer;
+        mSecureSocketBuffer = NULL;
+    }
+    int i;
+    for (i=0; i<9; i++)
+    {
+        delete[] mResult[i];
+    }
+    mResult = NULL;
+}