From: Jaehyun Kim Date: Wed, 6 Dec 2017 11:52:04 +0000 (+0900) Subject: Add WiFi passphrase encryption routine X-Git-Tag: accepted/tizen/unified/20171213.153205^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F25%2F162025%2F3;p=platform%2Fcore%2Fconnectivity%2Fnet-config.git Add WiFi passphrase encryption routine Change-Id: I40c60b60fe9bfdca68bb78685cc5f57dd4c9f64c Signed-off-by: Jaehyun Kim --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 960c0b1..c7e44a0 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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} diff --git a/include/util.h b/include/util.h index cc8a1a8..c017276 100755 --- a/include/util.h +++ b/include/util.h @@ -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 index 0000000..8c20687 --- /dev/null +++ b/include/wifi-key-encryption.h @@ -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__ */ diff --git a/interfaces/netconfig-iface-wifi.xml b/interfaces/netconfig-iface-wifi.xml index 1065910..590c886 100755 --- a/interfaces/netconfig-iface-wifi.xml +++ b/interfaces/netconfig-iface-wifi.xml @@ -168,6 +168,14 @@ + + + + + + + + diff --git a/packaging/net-config.spec b/packaging/net-config.spec index 4b1b85b..ea37156 100755 --- a/packaging/net-config.spec +++ b/packaging/net-config.spec @@ -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 diff --git a/src/utils/util.c b/src/utils/util.c index 77c2d2d..dc41472 100755 --- a/src/utils/util.c +++ b/src/utils/util.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -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; diff --git a/src/wifi-agent.c b/src/wifi-agent.c index 2f0c50d..f8c317e 100755 --- a/src/wifi-agent.c +++ b/src/wifi-agent.c @@ -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) && diff --git a/src/wifi-config.c b/src/wifi-config.c index 72914a6..0caf71c 100755 --- a/src/wifi-config.c +++ b/src/wifi-config.c @@ -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 index 0000000..9091ddb --- /dev/null +++ b/src/wifi-key-encryption.c @@ -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 +#include +#include +#include +#include + +#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, ¶m), + 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, ¶m), + 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; +} + diff --git a/src/wifi.c b/src/wifi.c index a50f8bd..d47a352 100755 --- a/src/wifi.c +++ b/src/wifi.c @@ -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");