Add WiFi passphrase encryption routine 25/162025/3 accepted/tizen/unified/20171213.153205 submit/tizen/20171212.235218
authorJaehyun Kim <jeik01.kim@samsung.com>
Wed, 6 Dec 2017 11:52:04 +0000 (20:52 +0900)
committerJaehyun Kim <jeik01.kim@samsung.com>
Wed, 6 Dec 2017 12:33:34 +0000 (21:33 +0900)
Change-Id: I40c60b60fe9bfdca68bb78685cc5f57dd4c9f64c
Signed-off-by: Jaehyun Kim <jeik01.kim@samsung.com>
CMakeLists.txt
include/util.h
include/wifi-key-encryption.h [new file with mode: 0755]
interfaces/netconfig-iface-wifi.xml
packaging/net-config.spec
src/utils/util.c
src/wifi-agent.c
src/wifi-config.c
src/wifi-key-encryption.c [new file with mode: 0755]
src/wifi.c

index 960c0b1..c7e44a0 100755 (executable)
@@ -32,6 +32,7 @@ SET(SRCS
        src/network-monitor.c
        src/wifi-firmware.c
        src/wifi-indicator.c
+       src/wifi-key-encryption.c
        src/signal-handler.c
        src/utils/emulator.c
        src/wifi-eap-config.c
@@ -86,6 +87,7 @@ PKG_CHECK_MODULES(pkgs REQUIRED
        glib-2.0
        gio-unix-2.0
        capi-system-info
+       key-manager
        libtzplatform-config
        libnl-2.0
        ${P2P_REQUIRED_PKGS}
index cc8a1a8..c017276 100755 (executable)
@@ -33,6 +33,7 @@ extern "C" {
 
 #define MAX_SIZE_ERROR_BUFFER 256
 
+gboolean netconfig_check_passphrase(const gchar *service, const char *passphrase);
 GKeyFile *netconfig_keyfile_load(const char *pathname);
 void netconfig_keyfile_save(GKeyFile *keyfile, const char *pathname);
 
diff --git a/include/wifi-key-encryption.h b/include/wifi-key-encryption.h
new file mode 100755 (executable)
index 0000000..8c20687
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Network Configuration Module
+ *
+ * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __NETCONFIG_WIFI_KEY_ENCRYPTION_H__
+#define __NETCONFIG_WIFI_KEY_ENCRYPTION_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "wifi.h"
+
+gboolean handle_encrypt_passphrase(Wifi *wifi, GDBusMethodInvocation *context, const gchar *passphrase);
+gboolean handle_decrypt_passphrase(Wifi *wifi, GDBusMethodInvocation *context, const gchar *enc_data);
+gchar* _netconfig_encrypt_passphrase(const gchar *passphrase);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __NETCONFIG_WIFI_KEY_ENCRYPTION_H__ */
index 1065910..590c886 100755 (executable)
                        <arg type='i' name='frame_id' direction='in'/>
                        <arg type='s' name='vsie' direction='in'/>
                </method>
+               <method name="EncryptPassphrase">
+                       <arg type="s" name="passphrase" direction="in"/>
+                       <arg type="s" name="enc_data" direction="out"/>
+               </method>
+               <method name="DecryptPassphrase">
+                       <arg type="s" name="enc_data" direction="in"/>
+                       <arg type="s" name="passphrase" direction="out"/>
+               </method>
                <signal name="PowerOnCompleted"></signal>
                <signal name="PowerOffCompleted"></signal>
                <signal name="PowerOperationFailed"></signal>
index 4b1b85b..ea37156 100755 (executable)
@@ -1,6 +1,6 @@
 Name:          net-config
 Summary:       TIZEN Network Configuration service
-Version:       1.1.118
+Version:       1.1.119
 Release:       2
 Group:         System/Network
 License:       Apache-2.0
@@ -14,6 +14,7 @@ BuildRequires:        pkgconfig(capi-vpnsvc)
 BuildRequires: cmake
 BuildRequires: pkgconfig(sqlite3)
 BuildRequires: pkgconfig(libtzplatform-config)
+BuildRequires:  pkgconfig(key-manager)
 BuildRequires:  pkgconfig(libnl-2.0)
 Requires:              vconf
 Requires:              connman
index 77c2d2d..dc41472 100755 (executable)
@@ -30,6 +30,7 @@
 #include <sys/wait.h>
 #include <sys/stat.h>
 #include <sys/ioctl.h>
+#include <ctype.h>
 #include <vconf-keys.h>
 #include <tzplatform_config.h>
 #include <system_info.h>
@@ -62,6 +63,34 @@ static void *handle_telephony;
 static struct netconfig_headed_plugin_t *headed_plugin;
 static struct netconfig_telephony_plugin_t *telephony_plugin;
 
+gboolean netconfig_check_passphrase(const gchar *service, const char *passphrase)
+{
+       gsize length;
+
+       if (!passphrase)
+               return FALSE;
+
+       length = strlen(passphrase);
+
+       if (g_str_has_suffix(service, "psk") == TRUE) {
+               if (length == 64) {
+                       for (int i = 0; i < 64; i++)
+                               if (!isxdigit((unsigned char)passphrase[i]))
+                                       return FALSE;
+               } else if (length < 8 || length > 63)
+                       return FALSE;
+       } else if (g_str_has_suffix(service, "wep") == TRUE) {
+               if (length == 10 || length == 26) {
+                       for (int i = 0; i < length; i++)
+                               if (!isxdigit((unsigned char)passphrase[i]))
+                                       return FALSE;
+               } else if (length != 5 && length != 13)
+                       return FALSE;
+       }
+
+       return TRUE;
+}
+
 GKeyFile *netconfig_keyfile_load(const char *pathname)
 {
        GKeyFile *keyfile = NULL;
index 2f0c50d..f8c317e 100755 (executable)
@@ -32,6 +32,7 @@
 #include "wifi-eap-config.h"
 #include "network-state.h"
 #include "network-accessibility.h"
+#include "wifi-key-encryption.h"
 
 #define NETCONFIG_AGENT_FIELD_NAME                             "Name"
 #define NETCONFIG_AGENT_FIELD_SSID                             "SSID"
@@ -136,6 +137,16 @@ gboolean netconfig_wifi_set_agent_field_for_eap_network(
        if (passphrase)
                agent.passphrase = g_strdup(passphrase);
 
+       gchar *enc_data = NULL;
+       enc_data = _netconfig_encrypt_passphrase(agent.passphrase);
+
+       if (!enc_data) {
+               ERR("Failed to encrypt the passphrase");
+       } else {
+               g_free(agent.passphrase);
+               agent.passphrase = enc_data;
+       }
+
        DBG("Successfully configured for EAP network");
 
        return TRUE;
@@ -175,6 +186,30 @@ gboolean handle_set_field(NetConnmanAgent *connman_agent,
                                updated = TRUE;
 
                                DBG("Field [%s] - []", field);
+
+                               if (agent.passphrase == NULL)
+                                       continue;
+
+                               if (netconfig_check_passphrase(service, agent.passphrase) == FALSE) {
+                                       ERR("Invalid passphrase");
+
+                                       g_free(agent.passphrase);
+                                       agent.passphrase = NULL;
+
+                                       updated = FALSE;
+                                       continue;
+                               }
+
+                               gchar *enc_data = NULL;
+                               enc_data = _netconfig_encrypt_passphrase(agent.passphrase);
+
+                               if (!enc_data) {
+                                       ERR("Failed to encrypt the passphrase");
+                                       continue;
+                               }
+
+                               g_free(agent.passphrase);
+                               agent.passphrase = enc_data;
                        }
                } else if (g_strcmp0(field, NETCONFIG_AGENT_FIELD_WPS_PBC) == 0) {
                        if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING) &&
index 72914a6..0caf71c 100755 (executable)
@@ -33,6 +33,7 @@
 #include "neterror.h"
 #include "wifi-config.h"
 #include "netsupplicant.h"
+#include "wifi-key-encryption.h"
 
 #define CONNMAN_STORAGE         "/var/lib/connman"
 
@@ -1068,8 +1069,19 @@ gboolean handle_save_configuration(Wifi *wifi, GDBusMethodInvocation *context,
        g_key_file_set_string(keyfile, group_name, WIFI_CONFIG_NAME, conf->name);
        g_key_file_set_string(keyfile, group_name, WIFI_CONFIG_SSID, conf->ssid);
 
-       if (conf->passphrase != NULL)
+       if (conf->passphrase != NULL) {
+               gchar *enc_data = NULL;
+               enc_data = _netconfig_encrypt_passphrase(conf->passphrase);
+
+               if (!enc_data) {
+                       ERR("Failed to encrypt the passphrase");
+               } else {
+                       g_free(conf->passphrase);
+                       conf->passphrase = enc_data;
+               }
+
                g_key_file_set_string(keyfile, group_name, WIFI_CONFIG_PASSPHRASE, conf->passphrase);
+       }
 
        g_key_file_set_boolean(keyfile, group_name, WIFI_CONFIG_FAVORITE, conf->favorite);
        g_key_file_set_boolean(keyfile, group_name, WIFI_CONFIG_AUTOCONNECT, conf->autoconnect);
@@ -1323,8 +1335,18 @@ gboolean handle_save_eap_configuration(Wifi *wifi, GDBusMethodInvocation *contex
        g_key_file_set_string(keyfile, group_name, WIFI_CONFIG_NAME, conf->name);
        g_key_file_set_string(keyfile, group_name, WIFI_CONFIG_SSID, conf->ssid);
 
-       if (conf->passphrase != NULL)
+       if (conf->passphrase != NULL) {
+               gchar *enc_data = NULL;
+               enc_data = _netconfig_encrypt_passphrase(conf->passphrase);
+
+               if (!enc_data) {
+                       ERR("Failed to encrypt the passphrase");
+               } else {
+                       g_free(conf->passphrase);
+                       conf->passphrase = enc_data;
+               }
                g_key_file_set_string(keyfile, group_name, WIFI_CONFIG_PASSPHRASE, conf->passphrase);
+       }
 
        g_key_file_set_boolean(keyfile, group_name, WIFI_CONFIG_FAVORITE, conf->favorite);
        g_key_file_set_boolean(keyfile, group_name, WIFI_CONFIG_AUTOCONNECT, conf->autoconnect);
diff --git a/src/wifi-key-encryption.c b/src/wifi-key-encryption.c
new file mode 100755 (executable)
index 0000000..9091ddb
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * Network Configuration Module
+ *
+ * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#include <stdlib.h>
+#include <glib.h>
+#include <ckmc/ckmc-type.h>
+#include <ckmc/ckmc-manager.h>
+#include <tizen.h>
+
+#include "log.h"
+#include "util.h"
+#include "wifi-key-encryption.h"
+
+#define KEY_ALIAS      "connman_wifi_passphrase"
+#define IV_ALIAS       "connman_wifi_enciv"
+#define AAD_ALIAS      "connman_wifi_gcmaad"
+
+#define PASSPHRASE     "Passphrase"
+#define RND_LENGTH     32
+#define AES_KEY_SIZE   256
+#define CKMC_ERROR_HANDLING(expression, release) err = expression; \
+       if (CKMC_ERROR_NONE != err) { \
+               err_str = get_error_message(err); \
+               ERR(#expression " : %s", err_str); \
+               release; \
+               return NULL; \
+       } \
+       DBG(#expression " success");
+
+static char* err_str;
+static int err;
+
+
+static void __netconfig_generate_random_bytes(unsigned char* bytes, int len)
+{
+       int i = 0;
+
+       srandom(time(NULL));
+
+       while (len--)
+               bytes[i++] = (unsigned char)random();
+
+}
+
+static void __netconfig_convert_hexstr_to_bytes(gchar* hexstr, int hlen, gchar* bin)
+{
+       hlen = hlen / 2;
+
+       while (hlen) {
+               if (*hexstr >= '0' && *hexstr <= '9')
+                       *bin = (*hexstr - '0') << 4;
+               else if (*hexstr >= 'a' && *hexstr <= 'f')
+                       *bin = (*hexstr - 'a' + 10) << 4;
+
+               hexstr++;
+
+               if (*hexstr >= '0' && *hexstr <= '9')
+                       *bin |= (*hexstr - '0') & 0x0f;
+               else if (*hexstr >= 'a' && *hexstr <= 'f')
+                       *bin |= (*hexstr - 'a' + 10) & 0x0f;
+
+               hexstr++;
+               bin++;
+               hlen--;
+       }
+}
+
+static void __netconfig_convert_bytes_to_hexstr(char* bin, int blen, gchar* hexstr)
+{
+       char t;
+
+       while (blen) {
+               t = (*bin >> 4) & 0x0f;
+
+               if (t >= 0 && t <= 9)
+                       *hexstr = t + '0';
+               else if (t >= 10 && t <= 16)
+                       *hexstr = (t - 10) + 'a';
+
+               hexstr++;
+
+               t = *bin & 0x0f;
+
+               if (t >= 0 && t <= 9)
+                       *hexstr = t + '0';
+               else if (t >= 10 && t <= 16)
+                       *hexstr = (t - 10) + 'a';
+
+               hexstr++;
+               bin++;
+               blen--;
+       }
+
+       *hexstr = '\0';
+}
+
+static int __netconfig_generate_aes_key()
+{
+       ckmc_policy_s pol;
+       pol.extractable = false;
+       pol.password = NULL;
+       int err;
+
+       err = ckmc_create_key_aes(AES_KEY_SIZE, KEY_ALIAS, pol);
+
+       if (err != CKMC_ERROR_NONE && err != CKMC_ERROR_DB_ALIAS_EXISTS)
+               return err;
+
+       return CKMC_ERROR_NONE;
+}
+
+static void*  __netconfig_set_param_list_aes_gcm(ckmc_param_list_h param)
+{
+       ckmc_raw_buffer_s *iv_buf;
+       unsigned char rnd[RND_LENGTH];
+       ckmc_raw_buffer_s *aad_buf;
+       unsigned char aad[RND_LENGTH];
+
+       err = ckmc_get_data(IV_ALIAS, NULL, &iv_buf);
+
+       if (err == CKMC_ERROR_DB_ALIAS_UNKNOWN) {
+               ckmc_policy_s policy;
+               policy.extractable = true;
+               policy.password = NULL;
+
+               __netconfig_generate_random_bytes(rnd, RND_LENGTH);
+
+               CKMC_ERROR_HANDLING(
+                               ckmc_buffer_new(rnd, RND_LENGTH, &iv_buf),
+                               NULL);
+
+               CKMC_ERROR_HANDLING(
+                               ckmc_save_data(IV_ALIAS, *iv_buf, policy),
+                               ckmc_buffer_free(iv_buf));
+       }
+
+       err = ckmc_get_data(AAD_ALIAS, NULL, &aad_buf);
+
+       if (err == CKMC_ERROR_DB_ALIAS_UNKNOWN) {
+               ckmc_policy_s policy;
+               policy.extractable = true;
+               policy.password = NULL;
+
+               __netconfig_generate_random_bytes(aad, RND_LENGTH);
+
+               CKMC_ERROR_HANDLING(
+                               ckmc_buffer_new(aad, RND_LENGTH, &aad_buf),
+                               ckmc_buffer_free(iv_buf));
+
+               CKMC_ERROR_HANDLING(
+                               ckmc_save_data(AAD_ALIAS, *aad_buf, policy),
+                               ckmc_buffer_free(iv_buf);\
+                               ckmc_buffer_free(aad_buf));
+       }
+
+       CKMC_ERROR_HANDLING(
+                       ckmc_param_list_set_buffer(param, CKMC_PARAM_ED_IV, iv_buf),
+                       ckmc_buffer_free(iv_buf);\
+                       ckmc_buffer_free(aad_buf));
+
+       CKMC_ERROR_HANDLING(
+                       ckmc_param_list_set_buffer(param, CKMC_PARAM_ED_AAD, aad_buf),
+                       ckmc_buffer_free(iv_buf);\
+                       ckmc_buffer_free(aad_buf));
+
+       return GINT_TO_POINTER(1);
+}
+
+gchar* _netconfig_encrypt_passphrase(const gchar *passphrase)
+{
+       gchar* origin_value = NULL;
+       gchar* encrypted_value = NULL;
+
+       ckmc_param_list_h param;
+       ckmc_raw_buffer_s *ptext;
+       ckmc_raw_buffer_s *ctext;
+
+       if (!passphrase)
+               return NULL;
+
+       origin_value = g_strdup(passphrase);
+
+       CKMC_ERROR_HANDLING(
+                       __netconfig_generate_aes_key(),
+                       g_free(origin_value));
+
+       CKMC_ERROR_HANDLING(
+                       ckmc_generate_new_params(CKMC_ALGO_AES_GCM, &param),
+                       g_free(origin_value));
+
+       if (__netconfig_set_param_list_aes_gcm(param) == NULL) {
+               g_free(origin_value);
+               return NULL;
+       }
+
+       CKMC_ERROR_HANDLING(
+                       ckmc_buffer_new((unsigned char*)origin_value,
+                               strlen((char*)origin_value) + 1, &ptext),
+                       ckmc_param_list_free(param);\
+                       g_free(origin_value));
+
+       CKMC_ERROR_HANDLING(
+                       ckmc_encrypt_data(param, KEY_ALIAS, NULL, *ptext, &ctext),
+                       ckmc_param_list_free(param);\
+                       ckmc_buffer_free(ptext);\
+                       g_free(origin_value));
+
+       if ((encrypted_value = g_try_malloc0(ctext->size * 2 + 1)) == NULL) {
+               DBG(" encrypted_value allocation failed");
+               ckmc_param_list_free(param);
+               ckmc_buffer_free(ptext);
+               ckmc_buffer_free(ctext);
+               g_free(origin_value);
+               return NULL;
+       }
+
+       __netconfig_convert_bytes_to_hexstr((char*)ctext->data, ctext->size, encrypted_value);
+
+       g_free(origin_value);
+
+       ckmc_param_list_free(param);
+       ckmc_buffer_free(ptext);
+       ckmc_buffer_free(ctext);
+
+       return encrypted_value;
+}
+
+static gchar* _netconfig_decrypt_passphrase(const gchar *enc_data)
+{
+       gchar *ehexstr = NULL;
+       gchar *encrypted_value = NULL;
+       gchar *passphrase = NULL;
+
+       ckmc_param_list_h param = NULL;
+       ckmc_raw_buffer_s *ptext;
+       ckmc_raw_buffer_s *ctext;
+
+       if (!enc_data)
+               return NULL;
+
+       ehexstr = g_strdup(enc_data);
+
+       CKMC_ERROR_HANDLING(
+                       ckmc_generate_new_params(CKMC_ALGO_AES_GCM, &param),
+                       g_free(ehexstr));
+
+       if (__netconfig_set_param_list_aes_gcm(param) == NULL) {
+               g_free(ehexstr);
+               return NULL;
+       }
+
+       if ((encrypted_value = g_try_malloc0(strlen((char*)ehexstr)/2)) == NULL) {
+               DBG(" encrypted_value allocation failed");
+               ckmc_param_list_free(param);
+               g_free(ehexstr);
+               return NULL;
+       }
+
+       __netconfig_convert_hexstr_to_bytes(ehexstr, strlen((char*)ehexstr), encrypted_value);
+
+       CKMC_ERROR_HANDLING(
+                       ckmc_buffer_new((unsigned char*)encrypted_value,
+                                       strlen((char*)ehexstr)/2, &ctext),
+                       ckmc_param_list_free(param);\
+                       g_free(encrypted_value);\
+                       g_free(ehexstr));
+
+       g_free(ehexstr);
+
+       CKMC_ERROR_HANDLING(
+                       ckmc_decrypt_data(param, KEY_ALIAS, NULL, *ctext, &ptext),
+                       ckmc_param_list_free(param);\
+                       ckmc_buffer_free(ctext);\
+                       g_free(encrypted_value));
+
+       passphrase = g_strdup((const gchar*)ptext->data);
+
+       ckmc_param_list_free(param);
+       ckmc_buffer_free(ctext);
+       ckmc_buffer_free(ptext);
+       g_free(encrypted_value);
+
+       return passphrase;
+}
+
+gboolean handle_encrypt_passphrase(Wifi *wifi, GDBusMethodInvocation *context, const gchar *passphrase)
+{
+       gchar *enc_data = NULL;
+
+       if ((wifi == NULL) || (passphrase == NULL)) {
+               ERR("Invalid parameter");
+               netconfig_error_invalid_parameter(context);
+               return FALSE;
+       }
+
+       enc_data = _netconfig_encrypt_passphrase(passphrase);
+
+       if (!enc_data) {
+               ERR("Failed to encrypt the passphrase");
+               netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "OperationFailed");
+               return FALSE;
+       }
+
+       wifi_complete_encrypt_passphrase(wifi, context, enc_data);
+       g_free(enc_data);
+
+       return TRUE;
+}
+
+gboolean handle_decrypt_passphrase(Wifi *wifi, GDBusMethodInvocation *context, const gchar *enc_data)
+{
+       gchar *passphrase = NULL;
+
+       if ((wifi == NULL) || (enc_data == NULL)) {
+               ERR("Invalid parameter");
+               netconfig_error_invalid_parameter(context);
+               return FALSE;
+       }
+
+       passphrase = _netconfig_decrypt_passphrase(enc_data);
+
+       if (!passphrase) {
+               ERR("Failed to decrypt the passphrase");
+               netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "OperationFailed");
+               return FALSE;
+       }
+
+       wifi_complete_decrypt_passphrase(wifi, context, passphrase);
+       g_free(passphrase);
+
+       return TRUE;
+}
+
index a50f8bd..d47a352 100755 (executable)
@@ -42,6 +42,7 @@
 #include "ip-conflict-detect.h"
 #include "wifi-config.h"
 #include "wifi-tdls.h"
+#include "wifi-key-encryption.h"
 #include "wifi-extension.h"
 
 #define SPRD_CP2_FIRMWARE_PATH "/usr/bin/cp2-downloader"
@@ -282,6 +283,12 @@ void wifi_object_create_and_init(void)
        g_signal_connect(wifi_object, "handle-tdls-cancel-channel-switch",
                        G_CALLBACK(handle_tdls_cancel_channel_switch), NULL);
 
+       /* Passphrase Encryption */
+       g_signal_connect(wifi_object, "handle-encrypt-passphrase",
+                       G_CALLBACK(handle_encrypt_passphrase), NULL);
+       g_signal_connect(wifi_object, "handle-decrypt-passphrase",
+                       G_CALLBACK(handle_decrypt_passphrase), NULL);
+
        if (!g_dbus_interface_skeleton_export(interface_wifi, connection,
                        NETCONFIG_WIFI_PATH, NULL)) {
                ERR("Export WIFI_PATH for wifi failed");