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