Revert "Imported Upstream version 3.4.11"
[platform/upstream/gnutls.git] / lib / system.c
1 /*
2  * Copyright (C) 2010-2012 Free Software Foundation, Inc.
3  *
4  * Author: Nikos Mavrogiannopoulos
5  *
6  * This file is part of GnuTLS.
7  *
8  * The GnuTLS is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>
20  *
21  */
22
23 #include <config.h>
24 #include <system.h>
25 #include <gnutls_int.h>
26 #include <gnutls_errors.h>
27
28 #include <sys/socket.h>
29 #include <errno.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <c-ctype.h>
33
34 #ifdef _WIN32
35 # include <windows.h>
36 # include <wincrypt.h>
37 # if defined(__MINGW32__) && !defined(__MINGW64__) && __MINGW32_MAJOR_VERSION <= 3 && __MINGW32_MINOR_VERSION <= 20
38 typedef PCCRL_CONTEXT WINAPI(*Type_CertEnumCRLsInStore) (HCERTSTORE
39                                                          hCertStore,
40                                                          PCCRL_CONTEXT
41                                                          pPrevCrlContext);
42 static Type_CertEnumCRLsInStore Loaded_CertEnumCRLsInStore;
43 static HMODULE Crypt32_dll;
44 # else
45 #  define Loaded_CertEnumCRLsInStore CertEnumCRLsInStore
46 # endif
47
48 #else /* _WIN32 */
49 # include <sys/select.h>
50
51 # ifdef HAVE_PTHREAD_LOCKS
52 #  include <pthread.h>
53 # endif
54
55 # if defined(HAVE_GETPWUID_R)
56 #  include <pwd.h>
57 # endif
58 #endif
59
60 /* System specific function wrappers.
61  */
62
63 #ifdef _WIN32
64 /* Do not use the gnulib functions for sending and receiving data.
65  * Using them makes gnutls only working with gnulib applications.
66  */
67 #undef send
68 #undef recv
69 #undef select
70
71 int system_errno(gnutls_transport_ptr p)
72 {
73         int tmperr = WSAGetLastError();
74         int ret = 0;
75         switch (tmperr) {
76         case WSAEWOULDBLOCK:
77                 ret = EAGAIN;
78                 break;
79         case NO_ERROR:
80                 ret = 0;
81                 break;
82         case WSAEINTR:
83                 ret = EINTR;
84                 break;
85         case WSAEMSGSIZE:
86                 ret = EMSGSIZE;
87                 break;
88         default:
89                 ret = EIO;
90                 break;
91         }
92         WSASetLastError(tmperr);
93
94         return ret;
95 }
96
97 ssize_t
98 system_write(gnutls_transport_ptr ptr, const void *data, size_t data_size)
99 {
100         return send(GNUTLS_POINTER_TO_INT(ptr), data, data_size, 0);
101 }
102 #else                           /* POSIX */
103 int system_errno(gnutls_transport_ptr_t ptr)
104 {
105 #if defined(_AIX) || defined(AIX)
106         if (errno == 0)
107                 errno = EAGAIN;
108 #endif
109
110         return errno;
111 }
112
113 ssize_t
114 system_writev(gnutls_transport_ptr_t ptr, const giovec_t * iovec,
115               int iovec_cnt)
116 {
117         return writev(GNUTLS_POINTER_TO_INT(ptr), (struct iovec *) iovec,
118                       iovec_cnt);
119
120 }
121 #endif
122
123 ssize_t
124 system_read(gnutls_transport_ptr_t ptr, void *data, size_t data_size)
125 {
126         return recv(GNUTLS_POINTER_TO_INT(ptr), data, data_size, 0);
127 }
128
129 /* Wait for data to be received within a timeout period in milliseconds.
130  * To catch a termination it will also try to receive 0 bytes from the
131  * socket if select reports to proceed.
132  *
133  * Returns -1 on error, 0 on timeout, positive value if data are available for reading.
134  */
135 int system_recv_timeout(gnutls_transport_ptr_t ptr, unsigned int ms)
136 {
137         fd_set rfds;
138         struct timeval tv;
139         int ret;
140         int fd = GNUTLS_POINTER_TO_INT(ptr);
141
142         FD_ZERO(&rfds);
143         FD_SET(fd, &rfds);
144
145         tv.tv_sec = 0;
146         tv.tv_usec = ms * 1000;
147
148         while (tv.tv_usec >= 1000000) {
149                 tv.tv_usec -= 1000000;
150                 tv.tv_sec++;
151         }
152
153         ret = select(fd + 1, &rfds, NULL, NULL, &tv);
154         if (ret <= 0)
155                 return ret;
156
157         return ret;
158 }
159
160 /* Thread stuff */
161
162 #ifdef HAVE_WIN32_LOCKS
163 static int gnutls_system_mutex_init(void **priv)
164 {
165         CRITICAL_SECTION *lock = malloc(sizeof(CRITICAL_SECTION));
166
167         if (lock == NULL)
168                 return GNUTLS_E_MEMORY_ERROR;
169
170         InitializeCriticalSection(lock);
171
172         *priv = lock;
173
174         return 0;
175 }
176
177 static int gnutls_system_mutex_deinit(void **priv)
178 {
179         DeleteCriticalSection((CRITICAL_SECTION *) * priv);
180         free(*priv);
181
182         return 0;
183 }
184
185 static int gnutls_system_mutex_lock(void **priv)
186 {
187         EnterCriticalSection((CRITICAL_SECTION *) * priv);
188         return 0;
189 }
190
191 static int gnutls_system_mutex_unlock(void **priv)
192 {
193         LeaveCriticalSection((CRITICAL_SECTION *) * priv);
194         return 0;
195 }
196
197 #endif                          /* WIN32_LOCKS */
198
199 #ifdef HAVE_PTHREAD_LOCKS
200
201 static int gnutls_system_mutex_init(void **priv)
202 {
203         pthread_mutex_t *lock = malloc(sizeof(pthread_mutex_t));
204         int ret;
205
206         if (lock == NULL)
207                 return GNUTLS_E_MEMORY_ERROR;
208
209         ret = pthread_mutex_init(lock, NULL);
210         if (ret) {
211                 free(lock);
212                 gnutls_assert();
213                 return GNUTLS_E_LOCKING_ERROR;
214         }
215
216         *priv = lock;
217
218         return 0;
219 }
220
221 static int gnutls_system_mutex_deinit(void **priv)
222 {
223         pthread_mutex_destroy((pthread_mutex_t *) * priv);
224         free(*priv);
225         return 0;
226 }
227
228 static int gnutls_system_mutex_lock(void **priv)
229 {
230         if (pthread_mutex_lock((pthread_mutex_t *) * priv)) {
231                 gnutls_assert();
232                 return GNUTLS_E_LOCKING_ERROR;
233         }
234
235         return 0;
236 }
237
238 static int gnutls_system_mutex_unlock(void **priv)
239 {
240         if (pthread_mutex_unlock((pthread_mutex_t *) * priv)) {
241                 gnutls_assert();
242                 return GNUTLS_E_LOCKING_ERROR;
243         }
244
245         return 0;
246 }
247
248 #endif                          /* PTHREAD_LOCKS */
249
250 #ifdef HAVE_NO_LOCKS
251
252 static int gnutls_system_mutex_init(void **priv)
253 {
254         return 0;
255 }
256
257 static int gnutls_system_mutex_deinit(void **priv)
258 {
259         return 0;
260 }
261
262 static int gnutls_system_mutex_lock(void **priv)
263 {
264         return 0;
265 }
266
267 static int gnutls_system_mutex_unlock(void **priv)
268 {
269         return 0;
270 }
271
272 #endif                          /* NO_LOCKS */
273
274 gnutls_time_func gnutls_time = time;
275 mutex_init_func gnutls_mutex_init = gnutls_system_mutex_init;
276 mutex_deinit_func gnutls_mutex_deinit = gnutls_system_mutex_deinit;
277 mutex_lock_func gnutls_mutex_lock = gnutls_system_mutex_lock;
278 mutex_unlock_func gnutls_mutex_unlock = gnutls_system_mutex_unlock;
279
280 int gnutls_system_global_init()
281 {
282 #ifdef _WIN32
283 #if defined(__MINGW32__) && !defined(__MINGW64__) && __MINGW32_MAJOR_VERSION <= 3 && __MINGW32_MINOR_VERSION <= 20
284         HMODULE crypto;
285         crypto = LoadLibraryA("Crypt32.dll");
286
287         if (crypto == NULL)
288                 return GNUTLS_E_CRYPTO_INIT_FAILED;
289
290         Loaded_CertEnumCRLsInStore =
291             (Type_CertEnumCRLsInStore) GetProcAddress(crypto,
292                                                       "CertEnumCRLsInStore");
293         if (Loaded_CertEnumCRLsInStore == NULL) {
294                 FreeLibrary(crypto);
295                 return GNUTLS_E_CRYPTO_INIT_FAILED;
296         }
297
298         Crypt32_dll = crypto;
299 #endif
300 #endif
301         return 0;
302 }
303
304 void gnutls_system_global_deinit()
305 {
306 #ifdef _WIN32
307 #if defined(__MINGW32__) && !defined(__MINGW64__) && __MINGW32_MAJOR_VERSION <= 3 && __MINGW32_MINOR_VERSION <= 20
308         FreeLibrary(Crypt32_dll);
309 #endif
310 #endif
311 }
312
313
314 #define CONFIG_PATH ".gnutls"
315
316 /* Returns a path to store user-specific configuration
317  * data.
318  */
319 int _gnutls_find_config_path(char *path, size_t max_size)
320 {
321         const char *home_dir = getenv("HOME");
322
323         if (home_dir != NULL && home_dir[0] != 0) {
324                 snprintf(path, max_size, "%s/" CONFIG_PATH, home_dir);
325                 return 0;
326         }
327
328 #ifdef _WIN32
329         if (home_dir == NULL || home_dir[0] == '\0') {
330                 const char *home_drive = getenv("HOMEDRIVE");
331                 const char *home_path = getenv("HOMEPATH");
332
333                 if (home_drive != NULL && home_path != NULL) {
334                         snprintf(path, max_size, "%s%s/" CONFIG_PATH, home_drive, home_path);
335                 } else {
336                         path[0] = 0;
337                 }
338         }
339 #elif defined(HAVE_GETPWUID_R)
340         if (home_dir == NULL || home_dir[0] == '\0') {
341                 struct passwd *pwd;
342                 struct passwd _pwd;
343                 int ret;
344                 char tmp[512];
345
346                 ret = getpwuid_r(getuid(), &_pwd, tmp, sizeof(tmp), &pwd);
347                 if (ret == 0 && pwd != NULL) {
348                         snprintf(path, max_size, "%s/" CONFIG_PATH, pwd->pw_dir);
349                 } else {
350                         path[0] = 0;
351                 }
352         }
353 #else
354         if (home_dir == NULL || home_dir[0] == '\0') {
355                         path[0] = 0;
356         }
357 #endif
358
359         return 0;
360 }
361
362 #if defined(DEFAULT_TRUST_STORE_FILE) || (defined(DEFAULT_TRUST_STORE_PKCS11) && defined(ENABLE_PKCS11))
363 static
364 int
365 add_system_trust(gnutls_x509_trust_list_t list,
366                  unsigned int tl_flags, unsigned int tl_vflags)
367 {
368         int ret, r = 0;
369         const char *crl_file =
370 #ifdef DEFAULT_CRL_FILE
371             DEFAULT_CRL_FILE;
372 #else
373             NULL;
374 #endif
375
376 #if defined(ENABLE_PKCS11) && defined(DEFAULT_TRUST_STORE_PKCS11)
377         ret =
378             gnutls_x509_trust_list_add_trust_file(list,
379                                                   DEFAULT_TRUST_STORE_PKCS11,
380                                                   crl_file,
381                                                   GNUTLS_X509_FMT_DER,
382                                                   tl_flags, tl_vflags);
383         if (ret > 0)
384                 r += ret;
385 #endif
386
387 #ifdef DEFAULT_TRUST_STORE_FILE
388         ret =
389             gnutls_x509_trust_list_add_trust_file(list,
390                                                   DEFAULT_TRUST_STORE_FILE,
391                                                   crl_file,
392                                                   GNUTLS_X509_FMT_PEM,
393                                                   tl_flags, tl_vflags);
394         if (ret > 0)
395                 r += ret;
396 #endif
397
398 #ifdef DEFAULT_BLACKLIST_FILE
399         ret = gnutls_x509_trust_list_remove_trust_file(list, DEFAULT_BLACKLIST_FILE, GNUTLS_X509_FMT_PEM);
400         if (ret < 0) {
401                 _gnutls_debug_log("Could not load blacklist file '%s'\n", DEFAULT_BLACKLIST_FILE);
402         }
403 #endif
404
405         return r;
406 }
407 #elif defined(_WIN32)
408 static
409 int add_system_trust(gnutls_x509_trust_list_t list, unsigned int tl_flags,
410                      unsigned int tl_vflags)
411 {
412         char path[GNUTLS_PATH_MAX];
413         unsigned int i;
414         int r = 0;
415
416         for (i = 0; i < 2; i++) {
417                 HCERTSTORE store;
418                 const CERT_CONTEXT *cert;
419                 const CRL_CONTEXT *crl;
420                 gnutls_datum_t data;
421
422                 if (i == 0)
423                         store = CertOpenSystemStore(0, "ROOT");
424                 else
425                         store = CertOpenSystemStore(0, "CA");
426
427                 if (store == NULL)
428                         return GNUTLS_E_FILE_ERROR;
429
430                 cert = CertEnumCertificatesInStore(store, NULL);
431                 crl = Loaded_CertEnumCRLsInStore(store, NULL);
432
433                 while (cert != NULL) {
434                         if (cert->dwCertEncodingType == X509_ASN_ENCODING) {
435                                 data.data = cert->pbCertEncoded;
436                                 data.size = cert->cbCertEncoded;
437                                 if (gnutls_x509_trust_list_add_trust_mem
438                                     (list, &data, NULL,
439                                      GNUTLS_X509_FMT_DER, tl_flags,
440                                      tl_vflags) > 0)
441                                         r++;
442                         }
443                         cert = CertEnumCertificatesInStore(store, cert);
444                 }
445
446                 while (crl != NULL) {
447                         if (crl->dwCertEncodingType == X509_ASN_ENCODING) {
448                                 data.data = crl->pbCrlEncoded;
449                                 data.size = crl->cbCrlEncoded;
450                                 gnutls_x509_trust_list_add_trust_mem(list,
451                                                                      NULL,
452                                                                      &data,
453                                                                      GNUTLS_X509_FMT_DER,
454                                                                      tl_flags,
455                                                                      tl_vflags);
456                         }
457                         crl = Loaded_CertEnumCRLsInStore(store, crl);
458                 }
459                 CertCloseStore(store, 0);
460         }
461
462 #ifdef DEFAULT_BLACKLIST_FILE
463         ret = gnutls_x509_trust_list_remove_trust_file(list, DEFAULT_BLACKLIST_FILE, GNUTLS_X509_FMT_PEM);
464         if (ret < 0) {
465                 _gnutls_debug_log("Could not load blacklist file '%s'\n", DEFAULT_BLACKLIST_FILE);
466         }
467 #endif
468
469         return r;
470 }
471 #elif defined(ANDROID) || defined(__ANDROID__)
472 #include <dirent.h>
473 #include <unistd.h>
474 static int load_dir_certs(const char *dirname,
475                           gnutls_x509_trust_list_t list,
476                           unsigned int tl_flags, unsigned int tl_vflags,
477                           unsigned type)
478 {
479         DIR *dirp;
480         struct dirent *d;
481         int ret;
482         int r = 0;
483         char path[GNUTLS_PATH_MAX];
484
485         dirp = opendir(dirname);
486         if (dirp != NULL) {
487                 do {
488                         d = readdir(dirp);
489                         if (d != NULL && d->d_type == DT_REG) {
490                                 snprintf(path, sizeof(path), "%s/%s",
491                                          dirname, d->d_name);
492
493                                 ret =
494                                     gnutls_x509_trust_list_add_trust_file
495                                     (list, path, NULL, type, tl_flags,
496                                      tl_vflags);
497                                 if (ret >= 0)
498                                         r += ret;
499                         }
500                 }
501                 while (d != NULL);
502                 closedir(dirp);
503         }
504
505         return r;
506 }
507
508 static int load_revoked_certs(gnutls_x509_trust_list_t list, unsigned type)
509 {
510         DIR *dirp;
511         struct dirent *d;
512         int ret;
513         int r = 0;
514         char path[GNUTLS_PATH_MAX];
515
516         dirp = opendir("/data/misc/keychain/cacerts-removed/");
517         if (dirp != NULL) {
518                 do {
519                         d = readdir(dirp);
520                         if (d != NULL && d->d_type == DT_REG) {
521                                 snprintf(path, sizeof(path),
522                                          "/data/misc/keychain/cacerts-removed/%s",
523                                          d->d_name);
524
525                                 ret =
526                                     gnutls_x509_trust_list_remove_trust_file
527                                     (list, path, type);
528                                 if (ret >= 0)
529                                         r += ret;
530                         }
531                 }
532                 while (d != NULL);
533                 closedir(dirp);
534         }
535
536         return r;
537 }
538
539 /* This works on android 4.x 
540  */
541 static
542 int add_system_trust(gnutls_x509_trust_list_t list, unsigned int tl_flags,
543                      unsigned int tl_vflags)
544 {
545         int r = 0, ret;
546
547         ret =
548             load_dir_certs("/system/etc/security/cacerts/", list, tl_flags,
549                            tl_vflags, GNUTLS_X509_FMT_PEM);
550         if (ret >= 0)
551                 r += ret;
552
553         ret = load_revoked_certs(list, GNUTLS_X509_FMT_DER);
554         if (ret >= 0)
555                 r -= ret;
556
557         ret =
558             load_dir_certs("/data/misc/keychain/cacerts-added/", list,
559                            tl_flags, tl_vflags, GNUTLS_X509_FMT_DER);
560         if (ret >= 0)
561                 r += ret;
562
563         return r;
564 }
565 #else
566
567 #define add_system_trust(x,y,z) GNUTLS_E_UNIMPLEMENTED_FEATURE
568
569 #endif
570
571 /**
572  * gnutls_x509_trust_list_add_system_trust:
573  * @list: The structure of the list
574  * @tl_flags: GNUTLS_TL_*
575  * @tl_vflags: gnutls_certificate_verify_flags if flags specifies GNUTLS_TL_VERIFY_CRL
576  *
577  * This function adds the system's default trusted certificate
578  * authorities to the trusted list. Note that on unsupported system
579  * this function returns %GNUTLS_E_UNIMPLEMENTED_FEATURE.
580  *
581  * Returns: The number of added elements or a negative error code on error.
582  *
583  * Since: 3.1
584  **/
585 int
586 gnutls_x509_trust_list_add_system_trust(gnutls_x509_trust_list_t list,
587                                         unsigned int tl_flags,
588                                         unsigned int tl_vflags)
589 {
590         return add_system_trust(list, tl_flags, tl_vflags);
591 }
592
593 #if defined(HAVE_ICONV) || defined(HAVE_LIBICONV)
594
595 #include <iconv.h>
596
597 int _gnutls_ucs2_to_utf8(const void *data, size_t size,
598                          gnutls_datum_t * output)
599 {
600         iconv_t conv;
601         int ret;
602         size_t orig, dstlen = size * 2;
603         char *src = (void *) data;
604         char *dst = NULL, *pdst;
605
606         if (size == 0)
607                 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
608
609         conv = iconv_open("UTF-8", "UTF-16BE");
610         if (conv == (iconv_t) - 1)
611                 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
612
613         /* Note that dstlen has enough size for every possible input characters.
614          * (remember the in UTF-16 the characters in data are at most size/2, 
615          *  and we allocate 4 bytes per character).
616          */
617         pdst = dst = gnutls_malloc(dstlen + 1);
618         if (dst == NULL) {
619                 ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
620                 goto fail;
621         }
622
623         orig = dstlen;
624         ret = iconv(conv, &src, &size, &pdst, &dstlen);
625         if (ret == -1) {
626                 ret = gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
627                 goto fail;
628         }
629
630         output->data = (void *) dst;
631         output->size = orig - dstlen;
632         output->data[output->size] = 0;
633
634         ret = 0;
635         goto cleanup;
636
637       fail:
638         gnutls_free(dst);
639
640       cleanup:
641         iconv_close(conv);
642
643         return ret;
644 }
645 #elif defined(_WIN32)
646 #include <winnls.h>
647
648 /* Can convert only english */
649 int _gnutls_ucs2_to_utf8(const void *data, size_t size,
650                          gnutls_datum_t * output)
651 {
652         int ret;
653         unsigned i;
654         int len = 0, src_len;
655         char *dst = NULL;
656         char *src = NULL;
657
658         src_len = size / 2;
659
660         src = gnutls_malloc(size);
661         if (src == NULL)
662                 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
663
664         /* convert to LE */
665         for (i = 0; i < size; i += 2) {
666                 src[i] = ((char *) data)[1 + i];
667                 src[1 + i] = ((char *) data)[i];
668         }
669
670         ret =
671             WideCharToMultiByte(CP_UTF8, MB_ERR_INVALID_CHARS,
672                                 (void *) src, src_len, NULL, 0, NULL,
673                                 NULL);
674         if (ret == 0) {
675                 ret = gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
676                 goto fail;
677         }
678
679         len = ret + 1;
680         dst = gnutls_malloc(len);
681         if (dst == NULL) {
682                 ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
683                 goto fail;
684         }
685
686         ret =
687             WideCharToMultiByte(CP_UTF8, MB_ERR_INVALID_CHARS,
688                                 (void *) src, src_len, dst, len, NULL,
689                                 NULL);
690         if (ret == 0) {
691                 ret = gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
692                 goto fail;
693         }
694
695         dst[len - 1] = 0;
696         output->data = dst;
697         output->size = ret;
698         ret = 0;
699         goto cleanup;
700
701       fail:
702         gnutls_free(dst);
703
704       cleanup:
705         gnutls_free(src);
706         return ret;
707 }
708
709 #else
710
711 /* Can convert only english (ASCII) */
712 int _gnutls_ucs2_to_utf8(const void *data, size_t size,
713                          gnutls_datum_t * output)
714 {
715         unsigned int i, j;
716         char *dst;
717         const char *src = data;
718
719         if (size == 0 || size % 2 != 0)
720                 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
721
722         dst = gnutls_malloc(size + 1);
723         if (dst == NULL)
724                 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
725
726         for (i = j = 0; i < size; i += 2, j++) {
727                 if (src[i] != 0 || !c_isascii(src[i + 1]))
728                         return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
729                 dst[j] = src[i + 1];
730         }
731
732         output->data = (void *) dst;
733         output->size = j;
734         output->data[output->size] = 0;
735
736         return 0;
737 }
738 #endif