Merge "Add dbus method for getting wifi passphrase" into tizen
[platform/core/connectivity/net-config.git] / src / wifi-key-encryption.c
1 /*
2  * Network Configuration Module
3  *
4  * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20 #include <stdlib.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <fcntl.h>
24 #include <glib.h>
25 #include <ckmc/ckmc-type.h>
26 #include <ckmc/ckmc-manager.h>
27 #include <tizen.h>
28
29 #include "log.h"
30 #include "util.h"
31 #include "wifi-key-encryption.h"
32
33 #define KEY_ALIAS       "connman_wifi_passphrase"
34 #define IV_ALIAS        "connman_wifi_enciv"
35 #define AAD_ALIAS       "connman_wifi_gcmaad"
36 #define URANDOM         "/dev/urandom"
37
38 #define PASSPHRASE      "Passphrase"
39 #define RND_LENGTH      32
40 #define AES_KEY_SIZE    256
41 #define CKMC_ERROR_HANDLING(expression, release) err = expression; \
42         if (CKMC_ERROR_NONE != err) { \
43                 err_str = get_error_message(err); \
44                 ERR(#expression " : %s", err_str); \
45                 release; \
46                 return NULL; \
47         } \
48         DBG(#expression " success");
49
50 static char* err_str;
51 static int err;
52
53
54 static int __netconfig_generate_random_bytes(unsigned char* bytes, int len)
55 {
56         int urfd = -1;
57         int r;
58
59         if (len <= 0)
60                 return 0;
61
62         urfd = open(URANDOM, O_RDONLY);
63         if (urfd < 0) {
64                 ERR("Could not open "URANDOM);
65                 return 0;
66         } else {
67                 r = read(urfd, bytes, len);
68                 if (r < 0) {
69                         ERR("Could not read from "URANDOM);
70                         close(urfd);
71                         return 0;
72                 } else if (r != len) {
73                         ERR("Short read from "URANDOM);
74                         close(urfd);
75                         return 0;
76                 }
77         }
78
79         close(urfd);
80         return 1;
81 }
82
83 static void __netconfig_convert_hexstr_to_bytes(gchar* hexstr, int hlen, gchar* bin)
84 {
85         hlen = hlen / 2;
86
87         while (hlen) {
88                 if (*hexstr >= '0' && *hexstr <= '9')
89                         *bin = (*hexstr - '0') << 4;
90                 else if (*hexstr >= 'a' && *hexstr <= 'f')
91                         *bin = (*hexstr - 'a' + 10) << 4;
92
93                 hexstr++;
94
95                 if (*hexstr >= '0' && *hexstr <= '9')
96                         *bin |= (*hexstr - '0') & 0x0f;
97                 else if (*hexstr >= 'a' && *hexstr <= 'f')
98                         *bin |= (*hexstr - 'a' + 10) & 0x0f;
99
100                 hexstr++;
101                 bin++;
102                 hlen--;
103         }
104 }
105
106 static int __netconfig_generate_aes_key()
107 {
108         ckmc_policy_s pol;
109         pol.extractable = false;
110         pol.password = NULL;
111         int err;
112
113         err = ckmc_create_key_aes(AES_KEY_SIZE, KEY_ALIAS, pol);
114
115         if (err != CKMC_ERROR_NONE && err != CKMC_ERROR_DB_ALIAS_EXISTS)
116                 return err;
117
118         return CKMC_ERROR_NONE;
119 }
120
121 static void*  __netconfig_set_param_list_aes_gcm(ckmc_param_list_h param)
122 {
123         ckmc_raw_buffer_s *iv_buf = NULL;
124         unsigned char rnd[RND_LENGTH];
125         ckmc_raw_buffer_s *aad_buf = NULL;
126         unsigned char aad[RND_LENGTH];
127
128         err = ckmc_get_data(IV_ALIAS, NULL, &iv_buf);
129
130         if (err == CKMC_ERROR_DB_ALIAS_UNKNOWN) {
131                 ckmc_policy_s policy;
132                 policy.extractable = true;
133                 policy.password = NULL;
134
135                 if (!__netconfig_generate_random_bytes(rnd, RND_LENGTH))
136                         return NULL;
137
138                 CKMC_ERROR_HANDLING(
139                                 ckmc_buffer_new(rnd, RND_LENGTH, &iv_buf),
140                                 NULL);
141
142                 CKMC_ERROR_HANDLING(
143                                 ckmc_save_data(IV_ALIAS, *iv_buf, policy),
144                                 ckmc_buffer_free(iv_buf));
145         }
146
147         err = ckmc_get_data(AAD_ALIAS, NULL, &aad_buf);
148
149         if (err == CKMC_ERROR_DB_ALIAS_UNKNOWN) {
150                 ckmc_policy_s policy;
151                 policy.extractable = true;
152                 policy.password = NULL;
153
154                 if (!__netconfig_generate_random_bytes(aad, RND_LENGTH)) {
155                         ckmc_buffer_free(iv_buf);
156                         return NULL;
157                 }
158
159                 CKMC_ERROR_HANDLING(
160                                 ckmc_buffer_new(aad, RND_LENGTH, &aad_buf),
161                                 ckmc_buffer_free(iv_buf));
162
163                 CKMC_ERROR_HANDLING(
164                                 ckmc_save_data(AAD_ALIAS, *aad_buf, policy),
165                                 ckmc_buffer_free(iv_buf);\
166                                 ckmc_buffer_free(aad_buf));
167         }
168
169         CKMC_ERROR_HANDLING(
170                         ckmc_param_list_set_buffer(param, CKMC_PARAM_ED_IV, iv_buf),
171                         ckmc_buffer_free(iv_buf);\
172                         ckmc_buffer_free(aad_buf));
173
174         CKMC_ERROR_HANDLING(
175                         ckmc_param_list_set_buffer(param, CKMC_PARAM_ED_AAD, aad_buf),
176                         ckmc_buffer_free(iv_buf);\
177                         ckmc_buffer_free(aad_buf));
178
179         return GINT_TO_POINTER(1);
180 }
181
182 gchar* _netconfig_encrypt_passphrase(const gchar *passphrase)
183 {
184         gchar* origin_value = NULL;
185         gchar* encrypted_value = NULL;
186
187         ckmc_param_list_h param = NULL;
188         ckmc_raw_buffer_s *ptext = NULL;
189         ckmc_raw_buffer_s *ctext = NULL;
190
191         if (!passphrase)
192                 return NULL;
193
194         origin_value = g_strdup(passphrase);
195
196         CKMC_ERROR_HANDLING(
197                         __netconfig_generate_aes_key(),
198                         g_free(origin_value));
199
200         CKMC_ERROR_HANDLING(
201                         ckmc_generate_new_params(CKMC_ALGO_AES_GCM, &param),
202                         g_free(origin_value));
203
204         if (__netconfig_set_param_list_aes_gcm(param) == NULL) {
205                 ckmc_param_list_free(param);
206                 g_free(origin_value);
207                 return NULL;
208         }
209
210         CKMC_ERROR_HANDLING(
211                         ckmc_buffer_new((unsigned char*)origin_value,
212                                 strlen((char*)origin_value) + 1, &ptext),
213                         ckmc_param_list_free(param);\
214                         g_free(origin_value));
215
216         CKMC_ERROR_HANDLING(
217                         ckmc_encrypt_data(param, KEY_ALIAS, NULL, *ptext, &ctext),
218                         ckmc_param_list_free(param);\
219                         ckmc_buffer_free(ptext);\
220                         g_free(origin_value));
221
222         if (ctext == NULL ||
223                 (encrypted_value = g_try_malloc0(ctext->size * 2 + 1)) == NULL) {
224                 DBG(" encrypted_value allocation failed");
225                 ckmc_param_list_free(param);
226                 ckmc_buffer_free(ptext);
227                 ckmc_buffer_free(ctext);
228                 g_free(origin_value);
229                 return NULL;
230         }
231
232         netconfig_convert_bytes_to_hexstr((const char *)ctext->data, ctext->size, encrypted_value);
233
234         g_free(origin_value);
235
236         ckmc_param_list_free(param);
237         ckmc_buffer_free(ptext);
238         ckmc_buffer_free(ctext);
239
240         return encrypted_value;
241 }
242
243 gchar* _netconfig_decrypt_passphrase(const gchar *enc_data)
244 {
245         gchar *ehexstr = NULL;
246         gchar *encrypted_value = NULL;
247         gchar *passphrase = NULL;
248
249         ckmc_param_list_h param = NULL;
250         ckmc_raw_buffer_s *ptext = NULL;
251         ckmc_raw_buffer_s *ctext = NULL;
252
253         if (!enc_data)
254                 return NULL;
255
256         ehexstr = g_strdup(enc_data);
257
258         CKMC_ERROR_HANDLING(
259                         ckmc_generate_new_params(CKMC_ALGO_AES_GCM, &param),
260                         g_free(ehexstr));
261
262         if (__netconfig_set_param_list_aes_gcm(param) == NULL) {
263                 ckmc_param_list_free(param);
264                 g_free(ehexstr);
265                 return NULL;
266         }
267
268         if ((encrypted_value = g_try_malloc0(strlen((char*)ehexstr)/2)) == NULL) {
269                 DBG(" encrypted_value allocation failed");
270                 ckmc_param_list_free(param);
271                 g_free(ehexstr);
272                 return NULL;
273         }
274
275         __netconfig_convert_hexstr_to_bytes(ehexstr, strlen((char*)ehexstr), encrypted_value);
276
277         CKMC_ERROR_HANDLING(
278                         ckmc_buffer_new((unsigned char*)encrypted_value,
279                                         strlen((char*)ehexstr)/2, &ctext),
280                         ckmc_param_list_free(param);\
281                         g_free(encrypted_value);\
282                         g_free(ehexstr));
283
284         g_free(ehexstr);
285
286         CKMC_ERROR_HANDLING(
287                         ckmc_decrypt_data(param, KEY_ALIAS, NULL, *ctext, &ptext),
288                         ckmc_param_list_free(param);\
289                         ckmc_buffer_free(ctext);\
290                         g_free(encrypted_value));
291
292         if (ptext != NULL)
293                 passphrase = g_strdup((const gchar*)ptext->data);
294
295         ckmc_param_list_free(param);
296         ckmc_buffer_free(ctext);
297         ckmc_buffer_free(ptext);
298         g_free(encrypted_value);
299
300         return passphrase;
301 }
302
303 gboolean handle_encrypt_passphrase(Wifi *wifi, GDBusMethodInvocation *context, const gchar *passphrase)
304 {
305         gchar *enc_data = NULL;
306
307         if ((wifi == NULL) || (passphrase == NULL)) {
308                 ERR("Invalid parameter");
309                 netconfig_error_invalid_parameter(context);
310                 return TRUE;
311         }
312
313         enc_data = _netconfig_encrypt_passphrase(passphrase);
314
315         if (!enc_data) {
316                 ERR("Failed to encrypt the passphrase");
317                 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "OperationFailed");
318                 return TRUE;
319         }
320
321         wifi_complete_encrypt_passphrase(wifi, context, enc_data);
322         g_free(enc_data);
323
324         return TRUE;
325 }
326
327 gboolean handle_decrypt_passphrase(Wifi *wifi, GDBusMethodInvocation *context, const gchar *enc_data)
328 {
329         gchar *passphrase = NULL;
330
331         if ((wifi == NULL) || (enc_data == NULL)) {
332                 ERR("Invalid parameter");
333                 netconfig_error_invalid_parameter(context);
334                 return TRUE;
335         }
336
337         passphrase = _netconfig_decrypt_passphrase(enc_data);
338
339         if (!passphrase) {
340                 ERR("Failed to decrypt the passphrase");
341                 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "OperationFailed");
342                 return TRUE;
343         }
344
345         wifi_complete_decrypt_passphrase(wifi, context, passphrase);
346         g_free(passphrase);
347
348         return TRUE;
349 }
350
351 gboolean handle_decrypt_conf_obj(Wifi *wifi, GDBusMethodInvocation *context,
352                 const gchar *enc_connector,
353                 const gchar *enc_c_sign_key,
354                 const gchar *enc_net_access_key)
355 {
356         GVariantBuilder *builder = NULL;
357         gchar *connector = NULL;
358         gchar *c_sign_key = NULL;
359         gchar *net_access_key = NULL;
360
361         DBG("");
362         if (!wifi || !enc_connector || !enc_c_sign_key || !enc_net_access_key) {
363                 ERR("Invalid parameter");
364                 netconfig_error_invalid_parameter(context);
365                 return TRUE;
366         }
367
368         connector = _netconfig_decrypt_passphrase(enc_connector);
369         c_sign_key = _netconfig_decrypt_passphrase(enc_c_sign_key);
370         net_access_key = _netconfig_decrypt_passphrase(enc_net_access_key);
371
372         if (!connector || !c_sign_key || !net_access_key) {
373                 ERR("Failed to decrypt the configuration object");
374                 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "OperationFailed");
375                 g_free(connector);
376                 g_free(c_sign_key);
377                 g_free(net_access_key);
378                 return TRUE;
379         }
380
381         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
382         g_variant_builder_add(builder, "{sv}", "connector",
383                         g_variant_new_string(connector));
384         g_variant_builder_add(builder, "{sv}", "c_sign_key",
385                         g_variant_new_string(c_sign_key));
386         g_variant_builder_add(builder, "{sv}", "net_access_key",
387                         g_variant_new_string(net_access_key));
388
389         wifi_complete_decrypt_conf_obj(wifi, context, g_variant_builder_end(builder));
390         g_variant_builder_unref(builder);
391         g_free(connector);
392         g_free(c_sign_key);
393         g_free(net_access_key);
394
395         return TRUE;
396 }
397