Coverage Report

Created: 2023-03-26 08:33

/src/gnutls/lib/system/certs.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2010-2016 Free Software Foundation, Inc.
3
 * Copyright (C) 2015-2016 Red Hat, Inc.
4
 *
5
 * Author: Nikos Mavrogiannopoulos
6
 *
7
 * This file is part of GnuTLS.
8
 *
9
 * The GnuTLS is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU Lesser General Public License
11
 * as published by the Free Software Foundation; either version 2.1 of
12
 * the License, or (at your option) any later version.
13
 *
14
 * This library is distributed in the hope that it will be useful, but
15
 * WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
 * Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
21
 *
22
 */
23
24
#include <config.h>
25
#include "gnutls_int.h"
26
#include "errors.h"
27
28
#include <sys/socket.h>
29
#include <errno.h>
30
#include <sys/stat.h>
31
#include <sys/types.h>
32
#include "system.h"
33
34
#ifdef _WIN32
35
# include <windows.h>
36
# include <wincrypt.h>
37
38
#else       /* !_WIN32 */
39
40
# include <poll.h>
41
42
# if defined(HAVE_GETPWUID_R)
43
#  include <pwd.h>
44
# endif
45
#endif
46
47
#ifdef __APPLE__
48
# include <CoreFoundation/CoreFoundation.h>
49
# include <Security/Security.h>
50
# include <Availability.h>
51
#endif
52
53
/* System specific function wrappers for certificate stores.
54
 */
55
56
0
#define CONFIG_PATH ".gnutls"
57
58
/* Returns a path to store user-specific configuration
59
 * data.
60
 */
61
int _gnutls_find_config_path(char *path, size_t max_size)
62
0
{
63
0
  const char *home_dir = secure_getenv("HOME");
64
65
0
  if (home_dir != NULL && home_dir[0] != 0) {
66
0
    snprintf(path, max_size, "%s/" CONFIG_PATH, home_dir);
67
0
    return 0;
68
0
  }
69
70
#ifdef _WIN32
71
  if (home_dir == NULL || home_dir[0] == '\0') {
72
    const char *home_drive = getenv("HOMEDRIVE");
73
    const char *home_path = getenv("HOMEPATH");
74
75
    if (home_drive != NULL && home_path != NULL) {
76
      snprintf(path, max_size, "%s%s\\" CONFIG_PATH,
77
         home_drive, home_path);
78
    } else {
79
      path[0] = 0;
80
    }
81
  }
82
#elif defined(HAVE_GETPWUID_R)
83
0
  if (home_dir == NULL || home_dir[0] == '\0') {
84
0
    struct passwd *pwd;
85
0
    struct passwd _pwd;
86
0
    int ret;
87
0
    char tmp[512];
88
89
0
    ret = getpwuid_r(getuid(), &_pwd, tmp, sizeof(tmp), &pwd);
90
0
    if (ret == 0 && pwd != NULL) {
91
0
      snprintf(path, max_size, "%s/" CONFIG_PATH,
92
0
         pwd->pw_dir);
93
0
    } else {
94
0
      path[0] = 0;
95
0
    }
96
0
  }
97
#else
98
  if (home_dir == NULL || home_dir[0] == '\0') {
99
    path[0] = 0;
100
  }
101
#endif
102
103
0
  return 0;
104
0
}
105
106
#if defined(DEFAULT_TRUST_STORE_FILE) || (defined(DEFAULT_TRUST_STORE_PKCS11) && defined(ENABLE_PKCS11))
107
static
108
int
109
add_system_trust(gnutls_x509_trust_list_t list,
110
     unsigned int tl_flags, unsigned int tl_vflags)
111
0
{
112
0
  int ret, r = 0;
113
0
  const char *crl_file =
114
# ifdef DEFAULT_CRL_FILE
115
      DEFAULT_CRL_FILE;
116
# else
117
0
      NULL;
118
0
# endif
119
120
# if defined(ENABLE_PKCS11) && defined(DEFAULT_TRUST_STORE_PKCS11)
121
  ret =
122
      gnutls_x509_trust_list_add_trust_file(list,
123
              DEFAULT_TRUST_STORE_PKCS11,
124
              crl_file,
125
              GNUTLS_X509_FMT_DER,
126
              tl_flags, tl_vflags);
127
  if (ret > 0)
128
    r += ret;
129
# endif
130
131
0
# ifdef DEFAULT_TRUST_STORE_FILE
132
0
  ret =
133
0
      gnutls_x509_trust_list_add_trust_file(list,
134
0
              DEFAULT_TRUST_STORE_FILE,
135
0
              crl_file,
136
0
              GNUTLS_X509_FMT_PEM,
137
0
              tl_flags, tl_vflags);
138
0
  if (ret > 0)
139
0
    r += ret;
140
0
# endif
141
142
# ifdef DEFAULT_BLOCKLIST_FILE
143
  ret =
144
      gnutls_x509_trust_list_remove_trust_file(list,
145
                 DEFAULT_BLOCKLIST_FILE,
146
                 GNUTLS_X509_FMT_PEM);
147
  if (ret < 0) {
148
    _gnutls_debug_log("Could not load blocklist file '%s'\n",
149
          DEFAULT_BLOCKLIST_FILE);
150
  }
151
# endif
152
153
0
  return r;
154
0
}
155
#elif defined(_WIN32)
156
static
157
int add_system_trust(gnutls_x509_trust_list_t list, unsigned int tl_flags,
158
         unsigned int tl_vflags)
159
{
160
  unsigned int i;
161
  int r = 0;
162
163
  for (i = 0; i < 2; i++) {
164
    HCERTSTORE store;
165
    const CERT_CONTEXT *cert;
166
    const CRL_CONTEXT *crl;
167
    gnutls_datum_t data;
168
169
    if (i == 0)
170
      store =
171
          CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
172
            CERT_SYSTEM_STORE_CURRENT_USER,
173
            L"ROOT");
174
    else
175
      store =
176
          CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
177
            CERT_SYSTEM_STORE_CURRENT_USER,
178
            L"CA");
179
180
    if (store == NULL)
181
      return GNUTLS_E_FILE_ERROR;
182
183
    cert = CertEnumCertificatesInStore(store, NULL);
184
    crl = pCertEnumCRLsInStore(store, NULL);
185
186
    while (cert != NULL) {
187
      if (cert->dwCertEncodingType == X509_ASN_ENCODING) {
188
        data.data = cert->pbCertEncoded;
189
        data.size = cert->cbCertEncoded;
190
        if (gnutls_x509_trust_list_add_trust_mem
191
            (list, &data, NULL,
192
             GNUTLS_X509_FMT_DER, tl_flags,
193
             tl_vflags) > 0)
194
          r++;
195
      }
196
      cert = CertEnumCertificatesInStore(store, cert);
197
    }
198
199
    while (crl != NULL) {
200
      if (crl->dwCertEncodingType == X509_ASN_ENCODING) {
201
        data.data = crl->pbCrlEncoded;
202
        data.size = crl->cbCrlEncoded;
203
        gnutls_x509_trust_list_add_trust_mem(list,
204
                     NULL,
205
                     &data,
206
                     GNUTLS_X509_FMT_DER,
207
                     tl_flags,
208
                     tl_vflags);
209
      }
210
      crl = pCertEnumCRLsInStore(store, crl);
211
    }
212
    CertCloseStore(store, 0);
213
  }
214
215
# ifdef DEFAULT_BLOCKLIST_FILE
216
  ret =
217
      gnutls_x509_trust_list_remove_trust_file(list,
218
                 DEFAULT_BLOCKLIST_FILE,
219
                 GNUTLS_X509_FMT_PEM);
220
  if (ret < 0) {
221
    _gnutls_debug_log("Could not load blocklist file '%s'\n",
222
          DEFAULT_BLOCKLIST_FILE);
223
  }
224
# endif
225
226
  return r;
227
}
228
#elif defined(ANDROID) || defined(__ANDROID__) || defined(DEFAULT_TRUST_STORE_DIR)
229
230
# include <dirent.h>
231
# include <unistd.h>
232
233
# if defined(ANDROID) || defined(__ANDROID__)
234
#  define DEFAULT_TRUST_STORE_DIR "/system/etc/security/cacerts/"
235
236
#  define DEFAULT_REVOCATION_DIR "/data/misc/keychain/cacerts-removed"
237
238
static int load_revoked_certs(gnutls_x509_trust_list_t list, unsigned type)
239
{
240
  DIR *dirp;
241
  struct dirent *d;
242
  int ret;
243
  int r = 0;
244
  struct gnutls_pathbuf_st pathbuf;
245
246
  dirp = opendir(DEFAULT_REVOCATION_DIR);
247
  if (dirp != NULL) {
248
    size_t base_len;
249
250
    ret = _gnutls_pathbuf_init(&pathbuf, DEFAULT_REVOCATION_DIR);
251
    if (ret < 0) {
252
      return 0;
253
    }
254
255
    base_len = pathbuf.len;
256
    while ((d = readdir(dirp)) != NULL) {
257
      if (d->d_type != DT_REG) {
258
        continue;
259
      }
260
      ret = _gnutls_pathbuf_append(&pathbuf, d->d_name);
261
      if (ret < 0) {
262
        continue;
263
      }
264
      ret = gnutls_x509_trust_list_remove_trust_file
265
          (list, pathbuf.ptr, type);
266
      if (ret >= 0) {
267
        r += ret;
268
      }
269
      (void)_gnutls_pathbuf_truncate(&pathbuf, base_len);
270
    }
271
    _gnutls_pathbuf_deinit(&pathbuf);
272
    closedir(dirp);
273
  }
274
275
  return r;
276
}
277
# endif
278
279
/* This works on android 4.x 
280
 */
281
static
282
int add_system_trust(gnutls_x509_trust_list_t list, unsigned int tl_flags,
283
         unsigned int tl_vflags)
284
{
285
  int r = 0, ret;
286
287
  ret =
288
      gnutls_x509_trust_list_add_trust_dir(list, DEFAULT_TRUST_STORE_DIR,
289
             NULL, GNUTLS_X509_FMT_PEM,
290
             tl_flags, tl_vflags);
291
  if (ret >= 0)
292
    r += ret;
293
294
# if defined(ANDROID) || defined(__ANDROID__)
295
  ret = load_revoked_certs(list, GNUTLS_X509_FMT_DER);
296
  if (ret >= 0)
297
    r -= ret;
298
299
  ret =
300
      gnutls_x509_trust_list_add_trust_dir(list,
301
             "/data/misc/keychain/cacerts-added/",
302
             NULL, GNUTLS_X509_FMT_DER,
303
             tl_flags, tl_vflags);
304
  if (ret >= 0)
305
    r += ret;
306
# endif
307
308
  return r;
309
}
310
#elif defined(__APPLE__) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
311
static
312
int osstatus_error(status)
313
{
314
  CFStringRef err_str = SecCopyErrorMessageString(status, NULL);
315
  _gnutls_debug_log("Error loading system root certificates: %s\n",
316
        CFStringGetCStringPtr(err_str,
317
            kCFStringEncodingUTF8));
318
  CFRelease(err_str);
319
  return GNUTLS_E_FILE_ERROR;
320
}
321
322
static
323
int add_system_trust(gnutls_x509_trust_list_t list, unsigned int tl_flags,
324
         unsigned int tl_vflags)
325
{
326
  int r = 0;
327
328
  SecTrustSettingsDomain domain[] = { kSecTrustSettingsDomainUser,
329
    kSecTrustSettingsDomainAdmin,
330
    kSecTrustSettingsDomainSystem
331
  };
332
  for (size_t d = 0; d < sizeof(domain) / sizeof(*domain); d++) {
333
    CFArrayRef certs = NULL;
334
    OSStatus status = SecTrustSettingsCopyCertificates(domain[d],
335
                   &certs);
336
    if (status == errSecNoTrustSettings)
337
      continue;
338
    if (status != errSecSuccess)
339
      return osstatus_error(status);
340
341
    int cert_count = CFArrayGetCount(certs);
342
    for (int i = 0; i < cert_count; i++) {
343
      SecCertificateRef cert =
344
          (void *)CFArrayGetValueAtIndex(certs, i);
345
      CFDataRef der;
346
      status = SecItemExport(cert, kSecFormatX509Cert, 0,
347
                 NULL, &der);
348
      if (status != errSecSuccess) {
349
        CFRelease(der);
350
        CFRelease(certs);
351
        return osstatus_error(status);
352
      }
353
354
      if (gnutls_x509_trust_list_add_trust_mem(list,
355
                 &
356
                 (gnutls_datum_t)
357
                 {
358
                 .data =
359
                 (void *)
360
                 CFDataGetBytePtr(der),.size = CFDataGetLength(der),}, NULL, GNUTLS_X509_FMT_DER, tl_flags, tl_vflags) > 0)
361
        r++;
362
      CFRelease(der);
363
    }
364
    CFRelease(certs);
365
  }
366
367
# ifdef DEFAULT_BLOCKLIST_FILE
368
  ret =
369
      gnutls_x509_trust_list_remove_trust_file(list,
370
                 DEFAULT_BLOCKLIST_FILE,
371
                 GNUTLS_X509_FMT_PEM);
372
  if (ret < 0) {
373
    _gnutls_debug_log("Could not load blocklist file '%s'\n",
374
          DEFAULT_BLOCKLIST_FILE);
375
  }
376
# endif
377
378
  return r;
379
}
380
#else
381
382
# define add_system_trust(x,y,z) GNUTLS_E_UNIMPLEMENTED_FEATURE
383
384
#endif
385
386
/**
387
 * gnutls_x509_trust_list_add_system_trust:
388
 * @list: The structure of the list
389
 * @tl_flags: GNUTLS_TL_*
390
 * @tl_vflags: gnutls_certificate_verify_flags if flags specifies GNUTLS_TL_VERIFY_CRL
391
 *
392
 * This function adds the system's default trusted certificate
393
 * authorities to the trusted list. Note that on unsupported systems
394
 * this function returns %GNUTLS_E_UNIMPLEMENTED_FEATURE.
395
 *
396
 * This function implies the flag %GNUTLS_TL_NO_DUPLICATES.
397
 *
398
 * Returns: The number of added elements or a negative error code on error.
399
 *
400
 * Since: 3.1
401
 **/
402
int
403
gnutls_x509_trust_list_add_system_trust(gnutls_x509_trust_list_t list,
404
          unsigned int tl_flags,
405
          unsigned int tl_vflags)
406
0
{
407
0
  return add_system_trust(list, tl_flags | GNUTLS_TL_NO_DUPLICATES,
408
0
        tl_vflags);
409
0
}