Browse Source

[FEATURE] Secure client implementation using basic128rsa15 policy

 - The file examples/encryption/client_basic128rsa15.c provides a
   secure communication between client and server by using
   basic128rsa15 security policy.
 - The secure client-server communication is implemented
   based on the OPC UA specification Part 4, setion 6.
 - Line number 176 in file src/client/ua_client.c is commented as
   UA_SecureChannel_deleteMembers already done in
   UA_client_disconnect function.
 - Load revocation list is not supported in this commit.

Change-Id: I9aa06dce6ac000c290accc57f1147a919ec74f1e
Signed-off-by: Sharavanan A R <sharavanan.ar@kalycito.com>
Sharavanan A R 7 years ago
parent
commit
9093197f88

+ 2 - 0
examples/CMakeLists.txt

@@ -76,6 +76,8 @@ add_example(server_inheritance server_inheritance.c)
 
 if(UA_ENABLE_ENCRYPTION)
     add_example(server_basic128rsa15 encryption/server_basic128rsa15.c)
+    # Add secure client example application
+    add_example(client_basic128rsa15 encryption/client_basic128rsa15.c)
 endif()
 
 add_example(custom_datatype_client custom_datatype/client_types_custom.c)

+ 190 - 0
examples/encryption/client_basic128rsa15.c

@@ -0,0 +1,190 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ *     Copyright 2018 (c) Kalycito Infotech Private Limited
+ */
+
+#include <stdio.h>
+#include <errno.h>
+
+#include "open62541.h"
+
+#define MIN_ARGS           3
+#define FAILURE            1
+#define CONNECTION_STRING  "opc.tcp://localhost:4840"
+
+/* loadFile parses the certificate file.
+ *
+ * @param  path               specifies the file name given in argv[]
+ * @return Returns the file content after parsing */
+static UA_ByteString loadFile(const char *const path) {
+    UA_ByteString fileContents = UA_BYTESTRING_NULL;
+    if(path == NULL)
+        return fileContents;
+
+    /* Open the file */
+    FILE *fp = fopen(path, "rb");
+    if(!fp) {
+        errno = 0; /* We read errno also from the tcp layer */
+        return fileContents;
+    }
+
+    /* Get the file length, allocate the data and read */
+    fseek(fp, 0, SEEK_END);
+    fileContents.length = (size_t)ftell(fp);
+    fileContents.data = (UA_Byte*)UA_malloc(fileContents.length * sizeof(UA_Byte));
+    if(fileContents.data) {
+        fseek(fp, 0, SEEK_SET);
+        size_t read = fread(fileContents.data, sizeof(UA_Byte), fileContents.length, fp);
+        if(read != fileContents.length)
+            UA_ByteString_deleteMembers(&fileContents);
+    } else {
+        fileContents.length = 0;
+    }
+
+    fclose(fp);
+    return fileContents;
+}
+
+/* cleanupClient deletes the memory allocated for client configuration.
+ *
+ * @param  client             client configuration that need to be deleted
+ * @param  remoteCertificate  server certificate */
+static void cleanupClient(UA_Client* client, UA_ByteString* remoteCertificate) {
+    UA_ByteString_delete(remoteCertificate); /* Dereference the memory */
+    UA_Client_delete(client); /* Disconnects the client internally */
+}
+
+/* main function for secure client implementation.
+ *
+ * @param  argc               count of command line variable provided
+ * @param  argv[]             array of strings include certificate, private key,
+ *                            trust list and revocation list
+ * @return Return an integer representing success or failure of application */
+int main(int argc, char* argv[]) {
+    UA_Client*              client             = NULL;
+    UA_ByteString*          remoteCertificate  = NULL;
+    UA_StatusCode           retval             = UA_STATUSCODE_GOOD;
+    UA_ByteString*          trustList          = NULL;
+    size_t                  trustListSize      = 0;
+    UA_ByteString*          revocationList     = NULL;
+    size_t                  revocationListSize = 0;
+
+    /* endpointArray is used to hold the available endpoints in the server
+     * endpointArraySize is used to hold the number of endpoints available */
+    UA_EndpointDescription* endpointArray      = NULL;
+    size_t                  endpointArraySize  = 0;
+
+    /* Load certificate and private key */
+    UA_ByteString           certificate        = loadFile(argv[1]);
+    UA_ByteString           privateKey         = loadFile(argv[2]);
+
+    if(argc < MIN_ARGS) {
+        UA_LOG_FATAL(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                     "The Certificate and key is missing."
+                     "The required arguments are "
+                     "<client-certificate.der> <client-private-key.der> "
+                     "[<trustlist1.crl>, ...]");
+        return FAILURE;
+    }
+
+    /* The Get endpoint (discovery service) is done with
+     * security mode as none to see the server's capability
+     * and certificate */
+    client = UA_Client_new(UA_ClientConfig_default);
+    remoteCertificate = UA_ByteString_new();
+    retval = UA_Client_getEndpoints(client, CONNECTION_STRING,
+                                    &endpointArraySize, &endpointArray);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_Array_delete(endpointArray, endpointArraySize,
+                        &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
+        cleanupClient(client, remoteCertificate);
+        return (int)retval;
+    }
+
+    printf("%i endpoints found\n", (int)endpointArraySize);
+    for(size_t endPointCount = 0; endPointCount < endpointArraySize; endPointCount++) {
+        printf("URL of endpoint %i is %.*s\n", (int)endPointCount,
+               (int)endpointArray[endPointCount].endpointUrl.length,
+               endpointArray[endPointCount].endpointUrl.data);
+        if(endpointArray[endPointCount].securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
+            UA_ByteString_copy(&endpointArray[endPointCount].serverCertificate, remoteCertificate);
+    }
+
+    if(UA_ByteString_equal(remoteCertificate, &UA_BYTESTRING_NULL)) {
+        UA_LOG_FATAL(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                     "Server does not support Security Mode of"
+                     " UA_MESSAGESECURITYMODE_SIGNANDENCRYPT");
+        cleanupClient(client, remoteCertificate);
+        return FAILURE;
+    }
+
+    UA_Array_delete(endpointArray, endpointArraySize,
+                    &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
+
+    /* Load the trustList. Load revocationList is not supported now */
+    if(argc > MIN_ARGS) {
+        trustListSize = (size_t)argc-MIN_ARGS;
+        retval = UA_ByteString_allocBuffer(trustList, trustListSize);
+        if(retval != UA_STATUSCODE_GOOD) {
+            cleanupClient(client, remoteCertificate);
+            return (int)retval;
+        }
+
+        for(size_t trustListCount = 0; trustListCount < trustListSize; trustListCount++) {
+            trustList[trustListCount] = loadFile(argv[trustListCount+3]);
+        }
+    }
+
+    /* Secure client initialization */
+    client = UA_Client_secure_new(UA_ClientConfig_default,
+                                  certificate, privateKey,
+                                  remoteCertificate,
+                                  trustList, trustListSize,
+                                  revocationList, revocationListSize);
+    if(client == NULL) {
+        UA_ByteString_delete(remoteCertificate); /* Dereference the memory */
+        return FAILURE;
+    }
+
+    UA_ByteString_deleteMembers(&certificate);
+    UA_ByteString_deleteMembers(&privateKey);
+    for(size_t deleteCount = 0; deleteCount < trustListSize; deleteCount++) {
+        UA_ByteString_deleteMembers(&trustList[deleteCount]);
+    }
+
+    if(!client) {
+        UA_LOG_FATAL(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                     "Could not create the server config");
+        cleanupClient(client, remoteCertificate);
+        return FAILURE;
+    }
+
+    /* Secure client connect */
+    retval = UA_Client_connect(client, CONNECTION_STRING);
+    if(retval != UA_STATUSCODE_GOOD) {
+        cleanupClient(client, remoteCertificate);
+        return (int)retval;
+    }
+
+    UA_Variant value;
+    UA_Variant_init(&value);
+
+    /* NodeId of the variable holding the current time */
+    const UA_NodeId nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
+    retval = UA_Client_readValueAttribute(client, nodeId, &value);
+
+    if(retval == UA_STATUSCODE_GOOD &&
+       UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_DATETIME])) {
+        UA_DateTime raw_date  = *(UA_DateTime *) value.data;
+        UA_DateTimeStruct dts = UA_DateTime_toStruct(raw_date);
+        UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "date is: %u-%u-%u %u:%u:%u.%03u\n",
+                    dts.day, dts.month, dts.year, dts.hour, dts.min, dts.sec, dts.milliSec);
+    }
+
+    /* Clean up */
+    UA_Variant_deleteMembers(&value);
+    cleanupClient(client, remoteCertificate);
+    return (int)retval;
+}

+ 20 - 1
include/ua_client.h

@@ -1,6 +1,6 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  *    Copyright 2015-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
  *    Copyright 2015-2016 (c) Sten Grüner
@@ -11,6 +11,7 @@
  *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
  *    Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB
  *    Copyright 2018 (c) Thomas Stalder
+ *    Copyright 2018 (c) Kalycito Infotech Private Limited
  */
 
 #ifndef UA_CLIENT_H_
@@ -54,6 +55,24 @@ extern "C" {
 UA_Client UA_EXPORT *
 UA_Client_new(UA_ClientConfig config);
 
+/* Creates a new secure client with the required configuration, certificate
+ * privatekey, trustlist and revocation list.
+ *
+ * @param  config               new secure configuration for client
+ * @param  certificate          client certificate
+ * @param  privateKey           client's private key
+ * @param  remoteCertificate    server certificate form the endpoints
+ * @param  trustList            list of trustable certificate
+ * @param  trustListSize        count of trustList
+ * @param  revocationList       list of revoked digital certificate
+ * @param  revocationListSize   count of revocationList
+ * @return Returns a client configuration for secure channel */
+UA_Client UA_EXPORT *
+UA_Client_secure_new(UA_ClientConfig config, UA_ByteString certificate,
+                     UA_ByteString privateKey, const UA_ByteString *remoteCertificate,
+                     const UA_ByteString *trustList, size_t trustListSize,
+                     const UA_ByteString *revocationList, size_t revocationListSize);
+
 /* Get the client connection status */
 UA_ClientState UA_EXPORT
 UA_Client_getState(UA_Client *client);

+ 128 - 1
src/client/ua_client.c

@@ -14,6 +14,7 @@
  *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
  *    Copyright 2016 (c) Lykurg
  *    Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB
+ *    Copyright 2018 (c) Kalycito Infotech Private Limited
  */
 
 #include "ua_client.h"
@@ -23,6 +24,10 @@
 #include "ua_types_generated_encoding_binary.h"
 #include "ua_util.h"
 #include "ua_securitypolicy_none.h"
+#include "ua_securitypolicy_basic128rsa15.h"
+#include "ua_pki_certificate.h"
+
+#define STATUS_CODE_BAD_POINTER 0x01
 
 /********************/
 /* Client Lifecycle */
@@ -49,11 +54,126 @@ UA_Client_new(UA_ClientConfig config) {
     return client;
 }
 
+#ifdef UA_ENABLE_ENCRYPTION
+/* Initializes a secure client with the required configuration, certificate
+ * privatekey, trustlist and revocation list.
+ *
+ * @param  client               client to store configuration
+ * @param  config               new secure configuration for client
+ * @param  certificate          client certificate
+ * @param  privateKey           client's private key
+ * @param  remoteCertificate    server certificate form the endpoints
+ * @param  trustList            list of trustable certificate
+ * @param  trustListSize        count of trustList
+ * @param  revocationList       list of revoked digital certificate
+ * @param  revocationListSize   count of revocationList
+ * @return Returns a client configuration for secure channel */
+static UA_StatusCode
+UA_Client_secure_init(UA_Client* client, UA_ClientConfig config,
+                      const UA_ByteString certificate,
+                      const UA_ByteString privateKey,
+                      const UA_ByteString *remoteCertificate,
+                      const UA_ByteString *trustList, size_t trustListSize,
+                      const UA_ByteString *revocationList,
+                      size_t revocationListSize) {
+    if(client == NULL || remoteCertificate == NULL)
+        return STATUS_CODE_BAD_POINTER;
+
+    memset(client, 0, sizeof(UA_Client));
+    /* Allocate memory for certificate verification */
+    client->securityPolicy.certificateVerification =
+                           (UA_CertificateVerification *)
+                            UA_malloc(sizeof(UA_CertificateVerification));
+
+    UA_StatusCode retval =
+    UA_CertificateVerification_Trustlist(client->securityPolicy.certificateVerification,
+                                         trustList, trustListSize,
+                                         revocationList, revocationListSize);
+
+    if(retval != UA_STATUSCODE_GOOD)
+         return retval;
+
+    /* Initiate client security policy as Basic128Rsa15 */
+    UA_SecurityPolicy_Basic128Rsa15(&client->securityPolicy,
+                                    client->securityPolicy.certificateVerification,
+                                    certificate, privateKey, config.logger);
+    client->channel.securityPolicy = &client->securityPolicy;
+    client->channel.securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT;
+    client->config = config;
+    if(client->config.stateCallback)
+        client->config.stateCallback(client, client->state);
+
+    if(client->channel.securityPolicy->certificateVerification != NULL) {
+        retval = client->channel.securityPolicy->certificateVerification->
+                 verifyCertificate(client->channel.securityPolicy->certificateVerification->context,
+                                   remoteCertificate);
+    } else {
+        UA_LOG_WARNING(client->channel.securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
+                       "No PKI plugin set. Accepting all certificates");
+    }
+
+    const UA_SecurityPolicy *securityPolicy = (UA_SecurityPolicy *) &client->securityPolicy;
+    retval = client->securityPolicy.channelModule.newContext(securityPolicy, remoteCertificate,
+                                                             &client->channel.channelContext);
+
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+
+    retval = UA_ByteString_copy(remoteCertificate, &client->channel.remoteCertificate);
+
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+
+    UA_ByteString remoteCertificateThumbprint = {20, client->channel.remoteCertificateThumbprint};
+
+    /* Invoke remote certificate thumbprint */
+    retval = client->securityPolicy.asymmetricModule.
+             makeCertificateThumbprint(securityPolicy, &client->channel.remoteCertificate,
+                                       &remoteCertificateThumbprint);
+    return retval;
+}
+
+/* Creates a new secure client.
+ *
+ * @param  config               new secure configuration for client
+ * @param  certificate          client certificate
+ * @param  privateKey           client's private key
+ * @param  remoteCertificate    server certificate form the endpoints
+ * @param  trustList            list of trustable certificate
+ * @param  trustListSize        count of trustList
+ * @param  revocationList       list of revoked digital certificate
+ * @param  revocationListSize   count of revocationList
+ * @return Returns a client with secure configuration */
+UA_Client *
+UA_Client_secure_new(UA_ClientConfig config, UA_ByteString certificate,
+                     UA_ByteString privateKey, const UA_ByteString *remoteCertificate,
+                     const UA_ByteString *trustList, size_t trustListSize,
+                     const UA_ByteString *revocationList, size_t revocationListSize) {
+    if(remoteCertificate == NULL)
+        return NULL;
+
+    UA_Client *client = (UA_Client *)UA_malloc(sizeof(UA_Client));
+    if(!client)
+        return NULL;
+
+    UA_StatusCode retval = UA_Client_secure_init(client, config, certificate, privateKey,
+                                                 remoteCertificate, trustList, trustListSize,
+                                                 revocationList, revocationListSize);
+    if(retval != UA_STATUSCODE_GOOD){
+        return NULL;
+    }
+
+    return client;
+}
+#endif
+
 static void
 UA_Client_deleteMembers(UA_Client* client) {
     UA_Client_disconnect(client);
     client->securityPolicy.deleteMembers(&client->securityPolicy);
-    UA_SecureChannel_deleteMembersCleanup(&client->channel);
+    /* Commented as UA_SecureChannel_deleteMembers already done
+     * in UA_Client_disconnect function */
+    //UA_SecureChannel_deleteMembersCleanup(&client->channel);
     UA_Connection_deleteMembers(&client->connection);
     if(client->endpointUrl.data)
         UA_String_deleteMembers(&client->endpointUrl);
@@ -81,6 +201,13 @@ UA_Client_reset(UA_Client* client) {
 
 void
 UA_Client_delete(UA_Client* client) {
+    /* certificate verification is initialized for secure client
+     * which is deallocated */
+    if(client->channel.securityMode == UA_MESSAGESECURITYMODE_SIGN ||
+       client->channel.securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
+        UA_free(client->securityPolicy.certificateVerification);
+    }
+
     UA_Client_deleteMembers(client);
     UA_free(client);
 }

+ 162 - 6
src/client/ua_client_connect.c

@@ -1,11 +1,12 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  *    Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB
  *    Copyright 2017-2018 (c) Thomas Stalder, Blue Time Concept SA
  *    Copyright 2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
  *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
+ *    Copyright 2018 (c) Kalycito Infotech Private Limited
  */
 
 #include "ua_client.h"
@@ -16,8 +17,10 @@
 #include "ua_types_encoding_binary.h"
 #include "ua_types_generated_encoding_binary.h"
 
-#define UA_MINMESSAGESIZE 8192
-
+/* Size are refered in bytes */
+#define UA_MINMESSAGESIZE                8192
+#define UA_SESSION_LOCALNONCELENGTH      32
+#define MAX_DATA_SIZE                    4096
 
  /********************/
  /* Set client state */
@@ -177,7 +180,10 @@ openSecureChannel(UA_Client *client, UA_Boolean renew) {
         UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL,
                      "Requesting to open a SecureChannel");
     }
-    opnSecRq.securityMode = UA_MESSAGESECURITYMODE_NONE;
+
+    /* Set the securityMode to input securityMode from client data */
+    opnSecRq.securityMode = client->channel.securityMode;
+
     opnSecRq.clientNonce = client->channel.localNonce;
     opnSecRq.requestedLifetime = client->config.secureChannelLifeTime;
 
@@ -214,6 +220,102 @@ openSecureChannel(UA_Client *client, UA_Boolean renew) {
     return retval;
 }
 
+/* Function to verify the signature corresponds to ClientNonce
+ * using the local certificate.
+ *
+ * @param  channel      current channel in which the client runs
+ * @param  response     create session response from the server
+ * @return Returns an error code or UA_STATUSCODE_GOOD. */
+static UA_StatusCode
+checkClientSignature(const UA_SecureChannel *channel, const UA_CreateSessionResponse *response) {
+    if(channel == NULL || response == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    if(channel->securityMode != UA_MESSAGESECURITYMODE_SIGN &&
+       channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
+        return UA_STATUSCODE_GOOD;
+
+    if(!channel->securityPolicy)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    UA_ByteString dataToVerify     = {0, NULL};
+    UA_StatusCode retval           = UA_STATUSCODE_GOOD;
+    size_t        dataToVerifySize = 0;
+    const UA_SecurityPolicy* securityPolicy   = channel->securityPolicy;
+    const UA_ByteString*     localCertificate = &securityPolicy->localCertificate;
+
+    dataToVerifySize = localCertificate->length + channel->localNonce.length;
+    retval = UA_ByteString_allocBuffer(&dataToVerify, dataToVerifySize);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+
+    memcpy(dataToVerify.data, localCertificate->data, localCertificate->length);
+    memcpy(dataToVerify.data + localCertificate->length,
+           channel->localNonce.data, channel->localNonce.length);
+
+    retval = securityPolicy->
+             certificateSigningAlgorithm.verify(securityPolicy,
+                                                channel->channelContext,
+                                                &dataToVerify,
+                                                &response->serverSignature.signature);
+    UA_ByteString_deleteMembers(&dataToVerify);
+    return retval;
+}
+
+/* Function to create a signature using remote certificate and nonce
+ *
+ * @param  channel      current channel in which the client runs
+ * @param  request      activate session request message to server
+ * @return Returns an error or UA_STATUSCODE_GOOD */
+static UA_StatusCode
+signActivateSessionRequest(UA_SecureChannel *channel,
+                           UA_ActivateSessionRequest *request) {
+    if(channel == NULL || request == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    if(channel->securityMode != UA_MESSAGESECURITYMODE_SIGN &&
+       channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
+        return UA_STATUSCODE_GOOD;
+
+    const UA_SecurityPolicy *const securityPolicy = channel->securityPolicy;
+    UA_SignatureData *signatureData = &request->clientSignature;
+
+    /* Prepare the signature */
+    size_t signatureSize = securityPolicy->certificateSigningAlgorithm.
+                           getLocalSignatureSize(securityPolicy, channel->channelContext);
+    UA_StatusCode retval = UA_String_copy(&securityPolicy->certificateSigningAlgorithm.uri,
+                                          &signatureData->algorithm);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+
+    retval = UA_ByteString_allocBuffer(&signatureData->signature, signatureSize);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+
+    /* Allocate a temporary buffer */
+    size_t dataToSignSize = channel->remoteCertificate.length + channel->remoteNonce.length;
+    /* Prevent stack-smashing. TODO: Compute MaxSenderCertificateSize */
+    if(dataToSignSize > MAX_DATA_SIZE)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    UA_ByteString dataToSign;
+    retval = UA_ByteString_allocBuffer(&dataToSign, dataToSignSize);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval; /* signatureData->signature is cleaned up with the response */
+
+    /* Sign the signature */
+    memcpy(dataToSign.data, channel->remoteCertificate.data, channel->remoteCertificate.length);
+    memcpy(dataToSign.data + channel->remoteCertificate.length,
+           channel->remoteNonce.data, channel->remoteNonce.length);
+    retval = securityPolicy->certificateSigningAlgorithm.
+             sign(securityPolicy, channel->channelContext, &dataToSign,
+                  &signatureData->signature);
+
+    /* Clean up */
+    UA_ByteString_deleteMembers(&dataToSign);
+    return retval;
+}
+
 static UA_StatusCode
 activateSession(UA_Client *client) {
     UA_ActivateSessionRequest request;
@@ -241,6 +343,12 @@ activateSession(UA_Client *client) {
         request.userIdentityToken.content.decoded.data = identityToken;
     }
 
+    /* This function call is to prepare a client signature */
+    if(client->channel.securityMode == UA_MESSAGESECURITYMODE_SIGN ||
+       client->channel.securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
+        signActivateSessionRequest(&client->channel, &request);
+    }
+
     UA_ActivateSessionResponse response;
     __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST],
                         &response, &UA_TYPES[UA_TYPES_ACTIVATESESSIONRESPONSE]);
@@ -360,6 +468,23 @@ static UA_StatusCode
 createSession(UA_Client *client) {
     UA_CreateSessionRequest request;
     UA_CreateSessionRequest_init(&request);
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+
+    if(client->channel.securityMode == UA_MESSAGESECURITYMODE_SIGN ||
+       client->channel.securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
+        if(client->channel.localNonce.length != UA_SESSION_LOCALNONCELENGTH) {
+           UA_ByteString_deleteMembers(&client->channel.localNonce);
+            retval = UA_ByteString_allocBuffer(&client->channel.localNonce,
+                                               UA_SESSION_LOCALNONCELENGTH);
+            if(retval != UA_STATUSCODE_GOOD)
+               return retval;
+        }
+
+        retval = client->channel.securityPolicy->symmetricModule.
+                 generateNonce(client->channel.securityPolicy, &client->channel.localNonce);
+        if(retval != UA_STATUSCODE_GOOD)
+            return retval;
+    }
 
     request.requestHeader.timestamp = UA_DateTime_now();
     request.requestHeader.timeoutHint = 10000;
@@ -368,13 +493,34 @@ createSession(UA_Client *client) {
     request.maxResponseMessageSize = UA_INT32_MAX;
     UA_String_copy(&client->endpointUrl, &request.endpointUrl);
 
+    if(client->channel.securityMode == UA_MESSAGESECURITYMODE_SIGN ||
+       client->channel.securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
+        UA_ByteString_copy(&client->channel.securityPolicy->localCertificate,
+                           &request.clientCertificate);
+    }
+
     UA_CreateSessionResponse response;
     __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST],
                         &response, &UA_TYPES[UA_TYPES_CREATESESSIONRESPONSE]);
 
+    if(client->channel.securityMode == UA_MESSAGESECURITYMODE_SIGN ||
+       client->channel.securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
+        UA_ByteString_copy(&response.serverNonce, &client->channel.remoteNonce);
+
+        if(!UA_ByteString_equal(&response.serverCertificate,
+                                &client->channel.remoteCertificate)) {
+            return UA_STATUSCODE_BADCERTIFICATEINVALID;
+        }
+
+        /* Verify the client signature */
+        retval = checkClientSignature(&client->channel, &response);
+        if(retval != UA_STATUSCODE_GOOD)
+            return retval;
+    }
+
     UA_NodeId_copy(&response.authenticationToken, &client->authenticationToken);
 
-    UA_StatusCode retval = response.responseHeader.serviceResult;
+    retval = response.responseHeader.serviceResult;
     UA_CreateSessionRequest_deleteMembers(&request);
     UA_CreateSessionResponse_deleteMembers(&response);
     return retval;
@@ -405,6 +551,12 @@ UA_Client_connectInternal(UA_Client *client, const char *endpointUrl,
         goto cleanup;
     }
 
+    /* Local nonce set and generate sym keys */
+    retval |= UA_SecureChannel_generateLocalNonce(&client->channel);
+
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+
     /* Open a TCP connection */
     client->connection.localConf = client->config.localConnectionConfig;
     retval = HelAckHandshake(client);
@@ -419,7 +571,6 @@ UA_Client_connectInternal(UA_Client *client, const char *endpointUrl,
         goto cleanup;
     setClientState(client, UA_CLIENTSTATE_SECURECHANNEL);
 
-
     /* Delete async service. TODO: Move this from connect to the disconnect/cleanup phase */
     UA_Client_AsyncService_removeAll(client, UA_STATUSCODE_BADSHUTDOWN);
 
@@ -450,6 +601,11 @@ UA_Client_connectInternal(UA_Client *client, const char *endpointUrl,
     UA_NodeId_deleteMembers(&client->authenticationToken);
 #endif /* UA_SESSION_RECOVERY */
 
+    /* Generate new local and remote key */
+    retval |= UA_SecureChannel_generateNewKeys(&client->channel);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+
     /* Get Endpoints */
     if(endpointsHandshake) {
         retval = getEndpoints(client);