Fix CVE-2017-6891 in minitasn1 code
[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         if (fd < 0 || fd >= FD_SETSIZE) {
143                 errno = EINVAL;
144                 return -1;
145         }
146
147         FD_ZERO(&rfds);
148         FD_SET(fd, &rfds);
149
150         tv.tv_sec = 0;
151         tv.tv_usec = ms * 1000;
152
153         while (tv.tv_usec >= 1000000) {
154                 tv.tv_usec -= 1000000;
155                 tv.tv_sec++;
156         }
157
158         ret = select(fd + 1, &rfds, NULL, NULL, &tv);
159         if (ret <= 0)
160                 return ret;
161
162         return ret;
163 }
164
165 /* Thread stuff */
166
167 #ifdef HAVE_WIN32_LOCKS
168 static int gnutls_system_mutex_init(void **priv)
169 {
170         CRITICAL_SECTION *lock = malloc(sizeof(CRITICAL_SECTION));
171
172         if (lock == NULL)
173                 return GNUTLS_E_MEMORY_ERROR;
174
175         InitializeCriticalSection(lock);
176
177         *priv = lock;
178
179         return 0;
180 }
181
182 static int gnutls_system_mutex_deinit(void **priv)
183 {
184         DeleteCriticalSection((CRITICAL_SECTION *) * priv);
185         free(*priv);
186
187         return 0;
188 }
189
190 static int gnutls_system_mutex_lock(void **priv)
191 {
192         EnterCriticalSection((CRITICAL_SECTION *) * priv);
193         return 0;
194 }
195
196 static int gnutls_system_mutex_unlock(void **priv)
197 {
198         LeaveCriticalSection((CRITICAL_SECTION *) * priv);
199         return 0;
200 }
201
202 #endif                          /* WIN32_LOCKS */
203
204 #ifdef HAVE_PTHREAD_LOCKS
205
206 static int gnutls_system_mutex_init(void **priv)
207 {
208         pthread_mutex_t *lock = malloc(sizeof(pthread_mutex_t));
209         int ret;
210
211         if (lock == NULL)
212                 return GNUTLS_E_MEMORY_ERROR;
213
214         ret = pthread_mutex_init(lock, NULL);
215         if (ret) {
216                 free(lock);
217                 gnutls_assert();
218                 return GNUTLS_E_LOCKING_ERROR;
219         }
220
221         *priv = lock;
222
223         return 0;
224 }
225
226 static int gnutls_system_mutex_deinit(void **priv)
227 {
228         pthread_mutex_destroy((pthread_mutex_t *) * priv);
229         free(*priv);
230         return 0;
231 }
232
233 static int gnutls_system_mutex_lock(void **priv)
234 {
235         if (pthread_mutex_lock((pthread_mutex_t *) * priv)) {
236                 gnutls_assert();
237                 return GNUTLS_E_LOCKING_ERROR;
238         }
239
240         return 0;
241 }
242
243 static int gnutls_system_mutex_unlock(void **priv)
244 {
245         if (pthread_mutex_unlock((pthread_mutex_t *) * priv)) {
246                 gnutls_assert();
247                 return GNUTLS_E_LOCKING_ERROR;
248         }
249
250         return 0;
251 }
252
253 #endif                          /* PTHREAD_LOCKS */
254
255 #ifdef HAVE_NO_LOCKS
256
257 static int gnutls_system_mutex_init(void **priv)
258 {
259         return 0;
260 }
261
262 static int gnutls_system_mutex_deinit(void **priv)
263 {
264         return 0;
265 }
266
267 static int gnutls_system_mutex_lock(void **priv)
268 {
269         return 0;
270 }
271
272 static int gnutls_system_mutex_unlock(void **priv)
273 {
274         return 0;
275 }
276
277 #endif                          /* NO_LOCKS */
278
279 gnutls_time_func gnutls_time = time;
280 mutex_init_func gnutls_mutex_init = gnutls_system_mutex_init;
281 mutex_deinit_func gnutls_mutex_deinit = gnutls_system_mutex_deinit;
282 mutex_lock_func gnutls_mutex_lock = gnutls_system_mutex_lock;
283 mutex_unlock_func gnutls_mutex_unlock = gnutls_system_mutex_unlock;
284
285 int gnutls_system_global_init()
286 {
287 #ifdef _WIN32
288 #if defined(__MINGW32__) && !defined(__MINGW64__) && __MINGW32_MAJOR_VERSION <= 3 && __MINGW32_MINOR_VERSION <= 20
289         HMODULE crypto;
290         crypto = LoadLibraryA("Crypt32.dll");
291
292         if (crypto == NULL)
293                 return GNUTLS_E_CRYPTO_INIT_FAILED;
294
295         Loaded_CertEnumCRLsInStore =
296             (Type_CertEnumCRLsInStore) GetProcAddress(crypto,
297                                                       "CertEnumCRLsInStore");
298         if (Loaded_CertEnumCRLsInStore == NULL) {
299                 FreeLibrary(crypto);
300                 return GNUTLS_E_CRYPTO_INIT_FAILED;
301         }
302
303         Crypt32_dll = crypto;
304 #endif
305 #endif
306         return 0;
307 }
308
309 void gnutls_system_global_deinit()
310 {
311 #ifdef _WIN32
312 #if defined(__MINGW32__) && !defined(__MINGW64__) && __MINGW32_MAJOR_VERSION <= 3 && __MINGW32_MINOR_VERSION <= 20
313         FreeLibrary(Crypt32_dll);
314 #endif
315 #endif
316 }
317
318
319 #define CONFIG_PATH ".gnutls"
320
321 /* Returns a path to store user-specific configuration
322  * data.
323  */
324 int _gnutls_find_config_path(char *path, size_t max_size)
325 {
326         const char *home_dir = secure_getenv("HOME");
327
328         if (home_dir != NULL && home_dir[0] != 0) {
329                 snprintf(path, max_size, "%s/" CONFIG_PATH, home_dir);
330                 return 0;
331         }
332
333 #ifdef _WIN32
334         if (home_dir == NULL || home_dir[0] == '\0') {
335                 const char *home_drive = getenv("HOMEDRIVE");
336                 const char *home_path = getenv("HOMEPATH");
337
338                 if (home_drive != NULL && home_path != NULL) {
339                         snprintf(path, max_size, "%s%s/" CONFIG_PATH, home_drive, home_path);
340                 } else {
341                         path[0] = 0;
342                 }
343         }
344 #elif defined(HAVE_GETPWUID_R)
345         if (home_dir == NULL || home_dir[0] == '\0') {
346                 struct passwd *pwd;
347                 struct passwd _pwd;
348                 int ret;
349                 char tmp[512];
350
351                 ret = getpwuid_r(getuid(), &_pwd, tmp, sizeof(tmp), &pwd);
352                 if (ret == 0 && pwd != NULL) {
353                         snprintf(path, max_size, "%s/" CONFIG_PATH, pwd->pw_dir);
354                 } else {
355                         path[0] = 0;
356                 }
357         }
358 #else
359         if (home_dir == NULL || home_dir[0] == '\0') {
360                         path[0] = 0;
361         }
362 #endif
363
364         return 0;
365 }
366
367 #if defined(DEFAULT_TRUST_STORE_FILE) || (defined(DEFAULT_TRUST_STORE_PKCS11) && defined(ENABLE_PKCS11))
368 static
369 int
370 add_system_trust(gnutls_x509_trust_list_t list,
371                  unsigned int tl_flags, unsigned int tl_vflags)
372 {
373         int ret, r = 0;
374         const char *crl_file =
375 #ifdef DEFAULT_CRL_FILE
376             DEFAULT_CRL_FILE;
377 #else
378             NULL;
379 #endif
380
381 #if defined(ENABLE_PKCS11) && defined(DEFAULT_TRUST_STORE_PKCS11)
382         ret =
383             gnutls_x509_trust_list_add_trust_file(list,
384                                                   DEFAULT_TRUST_STORE_PKCS11,
385                                                   crl_file,
386                                                   GNUTLS_X509_FMT_DER,
387                                                   tl_flags, tl_vflags);
388         if (ret > 0)
389                 r += ret;
390 #endif
391
392 #ifdef DEFAULT_TRUST_STORE_FILE
393         ret =
394             gnutls_x509_trust_list_add_trust_file(list,
395                                                   DEFAULT_TRUST_STORE_FILE,
396                                                   crl_file,
397                                                   GNUTLS_X509_FMT_PEM,
398                                                   tl_flags, tl_vflags);
399         if (ret > 0)
400                 r += ret;
401 #endif
402
403 #ifdef DEFAULT_BLACKLIST_FILE
404         ret = gnutls_x509_trust_list_remove_trust_file(list, DEFAULT_BLACKLIST_FILE, GNUTLS_X509_FMT_PEM);
405         if (ret < 0) {
406                 _gnutls_debug_log("Could not load blacklist file '%s'\n", DEFAULT_BLACKLIST_FILE);
407         }
408 #endif
409
410         return r;
411 }
412 #elif defined(_WIN32)
413 static
414 int add_system_trust(gnutls_x509_trust_list_t list, unsigned int tl_flags,
415                      unsigned int tl_vflags)
416 {
417         char path[GNUTLS_PATH_MAX];
418         unsigned int i;
419         int r = 0;
420
421         for (i = 0; i < 2; i++) {
422                 HCERTSTORE store;
423                 const CERT_CONTEXT *cert;
424                 const CRL_CONTEXT *crl;
425                 gnutls_datum_t data;
426
427                 if (i == 0)
428                         store = CertOpenSystemStore(0, "ROOT");
429                 else
430                         store = CertOpenSystemStore(0, "CA");
431
432                 if (store == NULL)
433                         return GNUTLS_E_FILE_ERROR;
434
435                 cert = CertEnumCertificatesInStore(store, NULL);
436                 crl = Loaded_CertEnumCRLsInStore(store, NULL);
437
438                 while (cert != NULL) {
439                         if (cert->dwCertEncodingType == X509_ASN_ENCODING) {
440                                 data.data = cert->pbCertEncoded;
441                                 data.size = cert->cbCertEncoded;
442                                 if (gnutls_x509_trust_list_add_trust_mem
443                                     (list, &data, NULL,
444                                      GNUTLS_X509_FMT_DER, tl_flags,
445                                      tl_vflags) > 0)
446                                         r++;
447                         }
448                         cert = CertEnumCertificatesInStore(store, cert);
449                 }
450
451                 while (crl != NULL) {
452                         if (crl->dwCertEncodingType == X509_ASN_ENCODING) {
453                                 data.data = crl->pbCrlEncoded;
454                                 data.size = crl->cbCrlEncoded;
455                                 gnutls_x509_trust_list_add_trust_mem(list,
456                                                                      NULL,
457                                                                      &data,
458                                                                      GNUTLS_X509_FMT_DER,
459                                                                      tl_flags,
460                                                                      tl_vflags);
461                         }
462                         crl = Loaded_CertEnumCRLsInStore(store, crl);
463                 }
464                 CertCloseStore(store, 0);
465         }
466
467 #ifdef DEFAULT_BLACKLIST_FILE
468         ret = gnutls_x509_trust_list_remove_trust_file(list, DEFAULT_BLACKLIST_FILE, GNUTLS_X509_FMT_PEM);
469         if (ret < 0) {
470                 _gnutls_debug_log("Could not load blacklist file '%s'\n", DEFAULT_BLACKLIST_FILE);
471         }
472 #endif
473
474         return r;
475 }
476 #elif defined(ANDROID) || defined(__ANDROID__) || defined(DEFAULT_TRUST_STORE_DIR)
477
478 # include <dirent.h>
479 # include <unistd.h>
480
481 # if defined(ANDROID) || defined(__ANDROID__)
482 #  define DEFAULT_TRUST_STORE_DIR "/system/etc/security/cacerts/"
483
484 static int load_revoked_certs(gnutls_x509_trust_list_t list, unsigned type)
485 {
486         DIR *dirp;
487         struct dirent *d;
488         int ret;
489         int r = 0;
490         char path[GNUTLS_PATH_MAX];
491
492         dirp = opendir("/data/misc/keychain/cacerts-removed/");
493         if (dirp != NULL) {
494                 do {
495                         d = readdir(dirp);
496                         if (d != NULL && d->d_type == DT_REG) {
497                                 snprintf(path, sizeof(path),
498                                          "/data/misc/keychain/cacerts-removed/%s",
499                                          d->d_name);
500
501                                 ret =
502                                     gnutls_x509_trust_list_remove_trust_file
503                                     (list, path, type);
504                                 if (ret >= 0)
505                                         r += ret;
506                         }
507                 }
508                 while (d != NULL);
509                 closedir(dirp);
510         }
511
512         return r;
513 }
514 # endif
515
516
517 /* This works on android 4.x 
518  */
519 static
520 int add_system_trust(gnutls_x509_trust_list_t list, unsigned int tl_flags,
521                      unsigned int tl_vflags)
522 {
523         int r = 0, ret;
524
525         ret = gnutls_x509_trust_list_add_trust_dir(list, DEFAULT_TRUST_STORE_DIR,
526                 NULL, GNUTLS_X509_FMT_PEM, tl_flags, tl_vflags);
527         if (ret >= 0)
528                 r += ret;
529
530 # if defined(ANDROID) || defined(__ANDROID__)
531         ret = load_revoked_certs(list, GNUTLS_X509_FMT_DER);
532         if (ret >= 0)
533                 r -= ret;
534
535         ret = gnutls_x509_trust_list_add_trust_dir(list, "/data/misc/keychain/cacerts-added/",
536                 NULL, GNUTLS_X509_FMT_DER, tl_flags, tl_vflags);
537         if (ret >= 0)
538                 r += ret;
539 # endif
540
541         return r;
542 }
543 #else
544
545 #define add_system_trust(x,y,z) GNUTLS_E_UNIMPLEMENTED_FEATURE
546
547 #endif
548
549 /**
550  * gnutls_x509_trust_list_add_system_trust:
551  * @list: The structure of the list
552  * @tl_flags: GNUTLS_TL_*
553  * @tl_vflags: gnutls_certificate_verify_flags if flags specifies GNUTLS_TL_VERIFY_CRL
554  *
555  * This function adds the system's default trusted certificate
556  * authorities to the trusted list. Note that on unsupported systems
557  * this function returns %GNUTLS_E_UNIMPLEMENTED_FEATURE.
558  *
559  * This function implies the flag %GNUTLS_TL_NO_DUPLICATES.
560  *
561  * Returns: The number of added elements or a negative error code on error.
562  *
563  * Since: 3.1
564  **/
565 int
566 gnutls_x509_trust_list_add_system_trust(gnutls_x509_trust_list_t list,
567                                         unsigned int tl_flags,
568                                         unsigned int tl_vflags)
569 {
570         return add_system_trust(list, tl_flags|GNUTLS_TL_NO_DUPLICATES, tl_vflags);
571 }
572
573 #if defined(_WIN32)
574 #include <winnls.h>
575
576 /* Can convert only english */
577 int _gnutls_ucs2_to_utf8(const void *data, size_t size,
578                          gnutls_datum_t * output)
579 {
580         int ret;
581         unsigned i;
582         int len = 0, src_len;
583         char *dst = NULL;
584         char *src = NULL;
585         static unsigned flags = 0;
586         static int checked = 0;
587
588         if (checked == 0) {
589                 /* Not all windows versions support MB_ERR_INVALID_CHARS */
590                 ret =
591                     WideCharToMultiByte(CP_UTF8, MB_ERR_INVALID_CHARS,
592                                 L"hello", -1, NULL, 0, NULL, NULL);
593                 if (ret > 0)
594                         flags = MB_ERR_INVALID_CHARS;
595                 checked = 1;
596         }
597
598         if (((uint8_t *) data)[size] == 0 && ((uint8_t *) data)[size+1] == 0) {
599                 size -= 2;
600         }
601
602         src = gnutls_malloc(size+2);
603         if (src == NULL)
604                 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
605
606         /* convert to LE */
607         for (i = 0; i < size; i += 2) {
608                 src[i] = ((uint8_t *) data)[1 + i];
609                 src[1 + i] = ((uint8_t *) data)[i];
610         }
611         src[size] = 0;
612         src[size+1] = 0;
613
614         src_len = wcslen(src);
615
616         ret =
617             WideCharToMultiByte(CP_UTF8, flags,
618                                 (void *) src, src_len, NULL, 0,
619                                 NULL, NULL);
620         if (ret == 0) {
621                 _gnutls_debug_log("WideCharToMultiByte: %d\n", (int)GetLastError());
622                 ret = gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
623                 goto fail;
624         }
625
626         len = ret + 1;
627         dst = gnutls_malloc(len);
628         if (dst == NULL) {
629                 ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
630                 goto fail;
631         }
632         dst[0] = 0;
633
634         ret =
635             WideCharToMultiByte(CP_UTF8, flags,
636                                 (void *) src, src_len, dst, len-1, NULL,
637                                 NULL);
638         if (ret == 0) {
639                 ret = gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
640                 goto fail;
641         }
642         dst[len - 1] = 0;
643
644         output->data = dst;
645         output->size = ret;
646
647         ret = 0;
648         goto cleanup;
649
650       fail:
651         gnutls_free(dst);
652
653       cleanup:
654         gnutls_free(src);
655         return ret;
656 }
657
658 #elif defined(HAVE_ICONV) || defined(HAVE_LIBICONV)
659
660 #include <iconv.h>
661
662 int _gnutls_ucs2_to_utf8(const void *data, size_t size,
663                          gnutls_datum_t * output)
664 {
665         iconv_t conv;
666         int ret;
667         size_t orig, dstlen = size * 2;
668         char *src = (void *) data;
669         char *dst = NULL, *pdst;
670
671         if (size == 0)
672                 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
673
674         conv = iconv_open("UTF-8", "UTF-16BE");
675         if (conv == (iconv_t) - 1)
676                 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
677
678         /* Note that dstlen has enough size for every possible input characters.
679          * (remember the in UTF-16 the characters in data are at most size/2, 
680          *  and we allocate 4 bytes per character).
681          */
682         pdst = dst = gnutls_malloc(dstlen + 1);
683         if (dst == NULL) {
684                 ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
685                 goto fail;
686         }
687
688         orig = dstlen;
689         ret = iconv(conv, &src, &size, &pdst, &dstlen);
690         if (ret == -1) {
691                 ret = gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
692                 goto fail;
693         }
694
695         output->data = (void *) dst;
696         output->size = orig - dstlen;
697         output->data[output->size] = 0;
698
699         ret = 0;
700         goto cleanup;
701
702       fail:
703         gnutls_free(dst);
704
705       cleanup:
706         iconv_close(conv);
707
708         return ret;
709 }
710
711 #else
712
713 /* Can convert only english (ASCII) */
714 int _gnutls_ucs2_to_utf8(const void *data, size_t size,
715                          gnutls_datum_t * output)
716 {
717         unsigned int i, j;
718         char *dst;
719         const char *src = data;
720
721         if (size == 0 || size % 2 != 0)
722                 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
723
724         dst = gnutls_malloc(size + 1);
725         if (dst == NULL)
726                 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
727
728         for (i = j = 0; i < size; i += 2, j++) {
729                 if (src[i] != 0 || !c_isascii(src[i + 1]))
730                         return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
731                 dst[j] = src[i + 1];
732         }
733
734         output->data = (void *) dst;
735         output->size = j;
736         output->data[output->size] = 0;
737
738         return 0;
739 }
740 #endif