Coverage Report

Created: 2023-09-25 06:56

/src/FreeRDP/libfreerdp/crypto/x509_utils.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * Cryptographic Abstraction Layer
4
 *
5
 * Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 * Copyright 2023 Armin Novak <anovak@thincast.com>
7
 * Copyright 2023 Thincast Technologies GmbH
8
 *
9
 * Licensed under the Apache License, Version 2.0 (the "License");
10
 * you may not use this file except in compliance with the License.
11
 * You may obtain a copy of the License at
12
 *
13
 *   http://www.apache.org/licenses/LICENSE-2.0
14
 *
15
 * Unless required by applicable law or agreed to in writing, software
16
 * distributed under the License is distributed on an "AS IS" BASIS,
17
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
 * See the License for the specific language governing permissions and
19
 * limitations under the License.
20
 */
21
22
#include <openssl/objects.h>
23
#include <openssl/x509v3.h>
24
#include <openssl/pem.h>
25
#include <openssl/err.h>
26
27
#include <freerdp/config.h>
28
29
#include <winpr/crt.h>
30
#include <winpr/string.h>
31
#include <winpr/assert.h>
32
33
#include <freerdp/log.h>
34
35
#include "x509_utils.h"
36
37
#define TAG FREERDP_TAG("crypto")
38
39
BYTE* x509_utils_get_hash(const X509* xcert, const char* hash, size_t* length)
40
0
{
41
0
  UINT32 fp_len = EVP_MAX_MD_SIZE;
42
0
  BYTE* fp;
43
0
  const EVP_MD* md = EVP_get_digestbyname(hash);
44
0
  if (!md)
45
0
  {
46
0
    WLog_ERR(TAG, "System does not support %s hash!", hash);
47
0
    return NULL;
48
0
  }
49
0
  if (!xcert || !length)
50
0
  {
51
0
    WLog_ERR(TAG, "Invalid arugments: xcert=%p, length=%p", xcert, length);
52
0
    return NULL;
53
0
  }
54
55
0
  fp = calloc(fp_len + 1, sizeof(BYTE));
56
0
  if (!fp)
57
0
  {
58
0
    WLog_ERR(TAG, "could not allocate %" PRIuz " bytes", fp_len);
59
0
    return NULL;
60
0
  }
61
62
0
  if (X509_digest(xcert, md, fp, &fp_len) != 1)
63
0
  {
64
0
    free(fp);
65
0
    WLog_ERR(TAG, "certificate does not have a %s hash!", hash);
66
0
    return NULL;
67
0
  }
68
69
0
  *length = fp_len;
70
0
  return fp;
71
0
}
72
73
static char* crypto_print_name(const X509_NAME* name)
74
0
{
75
0
  char* buffer = NULL;
76
0
  BIO* outBIO = BIO_new(BIO_s_mem());
77
78
0
  if (X509_NAME_print_ex(outBIO, name, 0, XN_FLAG_ONELINE) > 0)
79
0
  {
80
0
    UINT64 size = BIO_number_written(outBIO);
81
0
    if (size > INT_MAX)
82
0
      return NULL;
83
0
    buffer = calloc(1, (size_t)size + 1);
84
85
0
    if (!buffer)
86
0
      return NULL;
87
88
0
    ERR_clear_error();
89
0
    BIO_read(outBIO, buffer, (int)size);
90
0
  }
91
92
0
  BIO_free_all(outBIO);
93
0
  return buffer;
94
0
}
95
96
char* x509_utils_get_subject(const X509* xcert)
97
0
{
98
0
  char* subject;
99
0
  if (!xcert)
100
0
  {
101
0
    WLog_ERR(TAG, "Invalid certificate %p", xcert);
102
0
    return NULL;
103
0
  }
104
0
  subject = crypto_print_name(X509_get_subject_name(xcert));
105
0
  if (!subject)
106
0
    WLog_WARN(TAG, "certificate does not have a subject!");
107
0
  return subject;
108
0
}
109
110
/* GENERAL_NAME type labels */
111
112
static const char* general_name_type_labels[] = { "OTHERNAME", "EMAIL    ", "DNS      ",
113
                                                "X400     ", "DIRNAME  ", "EDIPARTY ",
114
                                                "URI      ", "IPADD    ", "RID      " };
115
116
static const char* general_name_type_label(int general_name_type)
117
0
{
118
0
  if ((0 <= general_name_type) &&
119
0
      ((size_t)general_name_type < ARRAYSIZE(general_name_type_labels)))
120
0
  {
121
0
    return general_name_type_labels[general_name_type];
122
0
  }
123
0
  else
124
0
  {
125
0
    static char buffer[80];
126
0
    sprintf(buffer, "Unknown general name type (%d)", general_name_type);
127
0
    return buffer;
128
0
  }
129
0
}
130
131
/*
132
133
map_subject_alt_name(x509,  general_name_type, mapper, data)
134
135
Call the function mapper with subjectAltNames found in the x509
136
certificate and data.  if generate_name_type is GEN_ALL,  the the
137
mapper is called for all the names,  else it's called only for names
138
of the given type.
139
140
141
We implement two extractors:
142
143
 -  a string extractor that can be used to get the subjectAltNames of
144
    the following types: GEN_URI,  GEN_DNS,  GEN_EMAIL
145
146
 - a ASN1_OBJECT filter/extractor that can be used to get the
147
   subjectAltNames of OTHERNAME type.
148
149
   Note: usually, it's a string, but some type of otherNames can be
150
   associated with different classes of objects. eg. a KPN may be a
151
   sequence of realm and principal name, instead of a single string
152
   object.
153
154
Not implemented yet: extractors for the types: GEN_X400, GEN_DIRNAME,
155
GEN_EDIPARTY, GEN_RID, GEN_IPADD (the later can contain nul-bytes).
156
157
158
mapper(name, data, index, count)
159
160
The mapper is passed:
161
 - the GENERAL_NAME selected,
162
 - the data,
163
 - the index of the general name in the subjectAltNames,
164
 - the total number of names in the subjectAltNames.
165
166
The last parameter let's the mapper allocate arrays to collect objects.
167
Note: if names are filtered,  not all the indices from 0 to count-1 are
168
passed to mapper,  only the indices selected.
169
170
When the mapper returns 0, map_subject_alt_name stops the iteration immediately.
171
172
*/
173
174
0
#define GEN_ALL (-1)
175
176
typedef int (*general_name_mapper_pr)(GENERAL_NAME* name, void* data, int index, int count);
177
178
static void map_subject_alt_name(const X509* x509, int general_name_type,
179
                                 general_name_mapper_pr mapper, void* data)
180
0
{
181
0
  int i;
182
0
  int num;
183
0
  STACK_OF(GENERAL_NAME) * gens;
184
0
  gens = X509_get_ext_d2i(x509, NID_subject_alt_name, NULL, NULL);
185
186
0
  if (!gens)
187
0
  {
188
0
    return;
189
0
  }
190
191
0
  num = sk_GENERAL_NAME_num(gens);
192
193
0
  for (i = 0; (i < num); i++)
194
0
  {
195
0
    GENERAL_NAME* name = sk_GENERAL_NAME_value(gens, i);
196
197
0
    if (name)
198
0
    {
199
0
      if ((general_name_type == GEN_ALL) || (general_name_type == name->type))
200
0
      {
201
0
        if (!mapper(name, data, i, num))
202
0
        {
203
0
          break;
204
0
        }
205
0
      }
206
0
    }
207
0
  }
208
209
0
  sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
210
0
}
211
212
/*
213
extract_string  --  string extractor
214
215
- the strings array is allocated lazily, when we first have to store a
216
  string.
217
218
- allocated contains the size of the strings array, or -1 if
219
  allocation failed.
220
221
- count contains the actual count of strings in the strings array.
222
223
- maximum limits the number of strings we can store in the strings
224
  array: beyond, the extractor returns 0 to short-cut the search.
225
226
extract_string stores in the string list OPENSSL strings,
227
that must be freed with OPENSSL_free.
228
229
*/
230
231
typedef struct string_list
232
{
233
  char** strings;
234
  int allocated;
235
  int count;
236
  int maximum;
237
} string_list;
238
239
static void string_list_initialize(string_list* list)
240
0
{
241
0
  list->strings = 0;
242
0
  list->allocated = 0;
243
0
  list->count = 0;
244
0
  list->maximum = INT_MAX;
245
0
}
246
247
static void string_list_allocate(string_list* list, int allocate_count)
248
0
{
249
0
  if (!list->strings && list->allocated == 0)
250
0
  {
251
0
    list->strings = calloc((size_t)allocate_count, sizeof(char*));
252
0
    list->allocated = list->strings ? allocate_count : -1;
253
0
    list->count = 0;
254
0
  }
255
0
}
256
257
static void string_list_free(string_list* list)
258
0
{
259
  /* Note: we don't free the contents of the strings array: this */
260
  /* is handled by the caller,  either by returning this */
261
  /* content,  or freeing it itself. */
262
0
  free(list->strings);
263
0
}
264
265
static int extract_string(GENERAL_NAME* name, void* data, int index, int count)
266
0
{
267
0
  string_list* list = data;
268
0
  unsigned char* cstring = 0;
269
0
  ASN1_STRING* str;
270
271
0
  switch (name->type)
272
0
  {
273
0
    case GEN_URI:
274
0
      str = name->d.uniformResourceIdentifier;
275
0
      break;
276
277
0
    case GEN_DNS:
278
0
      str = name->d.dNSName;
279
0
      break;
280
281
0
    case GEN_EMAIL:
282
0
      str = name->d.rfc822Name;
283
0
      break;
284
285
0
    default:
286
0
      return 1;
287
0
  }
288
289
0
  if ((ASN1_STRING_to_UTF8(&cstring, str)) < 0)
290
0
  {
291
0
    WLog_ERR(TAG, "ASN1_STRING_to_UTF8() failed for %s: %s",
292
0
             general_name_type_label(name->type), ERR_error_string(ERR_get_error(), NULL));
293
0
    return 1;
294
0
  }
295
296
0
  string_list_allocate(list, count);
297
298
0
  if (list->allocated <= 0)
299
0
  {
300
0
    OPENSSL_free(cstring);
301
0
    return 0;
302
0
  }
303
304
0
  list->strings[list->count] = (char*)cstring;
305
0
  list->count++;
306
307
0
  if (list->count >= list->maximum)
308
0
  {
309
0
    return 0;
310
0
  }
311
312
0
  return 1;
313
0
}
314
315
/*
316
extract_othername_object --  object extractor.
317
318
- the objects array is allocated lazily, when we first have to store a
319
  string.
320
321
- allocated contains the size of the objects array, or -1 if
322
  allocation failed.
323
324
- count contains the actual count of objects in the objects array.
325
326
- maximum limits the number of objects we can store in the objects
327
  array: beyond, the extractor returns 0 to short-cut the search.
328
329
extract_othername_objects stores in the objects array ASN1_TYPE *
330
pointers directly obtained from the GENERAL_NAME.
331
*/
332
333
typedef struct object_list
334
{
335
  ASN1_OBJECT* type_id;
336
  char** strings;
337
  int allocated;
338
  int count;
339
  int maximum;
340
} object_list;
341
342
static void object_list_initialize(object_list* list)
343
0
{
344
0
  list->type_id = 0;
345
0
  list->strings = 0;
346
0
  list->allocated = 0;
347
0
  list->count = 0;
348
0
  list->maximum = INT_MAX;
349
0
}
350
351
static void object_list_allocate(object_list* list, int allocate_count)
352
0
{
353
0
  if (!list->strings && list->allocated == 0)
354
0
  {
355
0
    list->strings = calloc(allocate_count, sizeof(list->strings[0]));
356
0
    list->allocated = list->strings ? allocate_count : -1;
357
0
    list->count = 0;
358
0
  }
359
0
}
360
361
static char* object_string(ASN1_TYPE* object)
362
0
{
363
0
  char* result;
364
0
  unsigned char* utf8String;
365
0
  int length;
366
  /* TODO: check that object.type is a string type. */
367
0
  length = ASN1_STRING_to_UTF8(&utf8String, object->value.asn1_string);
368
369
0
  if (length < 0)
370
0
  {
371
0
    return 0;
372
0
  }
373
374
0
  result = (char*)_strdup((char*)utf8String);
375
0
  OPENSSL_free(utf8String);
376
0
  return result;
377
0
}
378
379
static void object_list_free(object_list* list)
380
0
{
381
0
  free(list->strings);
382
0
}
383
384
static int extract_othername_object_as_string(GENERAL_NAME* name, void* data, int index, int count)
385
0
{
386
0
  object_list* list = data;
387
388
0
  if (name->type != GEN_OTHERNAME)
389
0
  {
390
0
    return 1;
391
0
  }
392
393
0
  if (0 != OBJ_cmp(name->d.otherName->type_id, list->type_id))
394
0
  {
395
0
    return 1;
396
0
  }
397
398
0
  object_list_allocate(list, count);
399
400
0
  if (list->allocated <= 0)
401
0
  {
402
0
    return 0;
403
0
  }
404
405
0
  list->strings[list->count] = object_string(name->d.otherName->value);
406
407
0
  if (list->strings[list->count])
408
0
  {
409
0
    list->count++;
410
0
  }
411
412
0
  if (list->count >= list->maximum)
413
0
  {
414
0
    return 0;
415
0
  }
416
417
0
  return 1;
418
0
}
419
420
char* x509_utils_get_email(const X509* x509)
421
0
{
422
0
  char* result = 0;
423
0
  string_list list;
424
0
  string_list_initialize(&list);
425
0
  list.maximum = 1;
426
0
  map_subject_alt_name(x509, GEN_EMAIL, extract_string, &list);
427
428
0
  if (list.count == 0)
429
0
  {
430
0
    string_list_free(&list);
431
0
    return 0;
432
0
  }
433
434
0
  result = _strdup(list.strings[0]);
435
0
  OPENSSL_free(list.strings[0]);
436
0
  string_list_free(&list);
437
0
  return result;
438
0
}
439
440
char* x509_utils_get_upn(const X509* x509)
441
0
{
442
0
  char* result = 0;
443
0
  object_list list;
444
0
  object_list_initialize(&list);
445
0
  list.type_id = OBJ_nid2obj(NID_ms_upn);
446
0
  list.maximum = 1;
447
0
  map_subject_alt_name(x509, GEN_OTHERNAME, extract_othername_object_as_string, &list);
448
449
0
  if (list.count == 0)
450
0
  {
451
0
    object_list_free(&list);
452
0
    return 0;
453
0
  }
454
455
0
  result = list.strings[0];
456
0
  object_list_free(&list);
457
0
  return result;
458
0
}
459
460
void x509_utils_dns_names_free(size_t count, size_t* lengths, char** dns_names)
461
0
{
462
0
  free(lengths);
463
464
0
  if (dns_names)
465
0
  {
466
0
    for (size_t i = 0; i < count; i++)
467
0
    {
468
0
      if (dns_names[i])
469
0
      {
470
0
        OPENSSL_free(dns_names[i]);
471
0
      }
472
0
    }
473
474
0
    free(dns_names);
475
0
  }
476
0
}
477
478
char** x509_utils_get_dns_names(const X509* x509, size_t* count, size_t** lengths)
479
0
{
480
0
  char** result = 0;
481
0
  string_list list;
482
0
  string_list_initialize(&list);
483
0
  map_subject_alt_name(x509, GEN_DNS, extract_string, &list);
484
0
  (*count) = list.count;
485
486
0
  if (list.count == 0)
487
0
  {
488
0
    string_list_free(&list);
489
0
    return NULL;
490
0
  }
491
492
  /* lengths are not useful,  since we converted the
493
     strings to utf-8,  there cannot be nul-bytes in them. */
494
0
  result = calloc(list.count, sizeof(*result));
495
0
  (*lengths) = calloc(list.count, sizeof(**lengths));
496
497
0
  if (!result || !(*lengths))
498
0
  {
499
0
    string_list_free(&list);
500
0
    free(result);
501
0
    free(*lengths);
502
0
    (*lengths) = 0;
503
0
    (*count) = 0;
504
0
    return NULL;
505
0
  }
506
507
0
  for (int i = 0; i < list.count; i++)
508
0
  {
509
0
    result[i] = list.strings[i];
510
0
    (*lengths)[i] = strlen(result[i]);
511
0
  }
512
513
0
  string_list_free(&list);
514
0
  return result;
515
0
}
516
517
char* x509_utils_get_issuer(const X509* xcert)
518
0
{
519
0
  char* issuer;
520
0
  if (!xcert)
521
0
  {
522
0
    WLog_ERR(TAG, "Invalid certificate %p", xcert);
523
0
    return NULL;
524
0
  }
525
0
  issuer = crypto_print_name(X509_get_issuer_name(xcert));
526
0
  if (!issuer)
527
0
    WLog_WARN(TAG, "certificate does not have an issuer!");
528
0
  return issuer;
529
0
}
530
531
BOOL x509_utils_check_eku(const X509* xcert, int nid)
532
0
{
533
0
  BOOL ret = FALSE;
534
0
  STACK_OF(ASN1_OBJECT) * oid_stack;
535
0
  ASN1_OBJECT* oid;
536
537
0
  if (!xcert)
538
0
    return FALSE;
539
540
0
  oid = OBJ_nid2obj(nid);
541
0
  if (!oid)
542
0
    return FALSE;
543
544
0
  oid_stack = X509_get_ext_d2i(xcert, NID_ext_key_usage, NULL, NULL);
545
0
  if (!oid_stack)
546
0
    return FALSE;
547
548
0
  if (sk_ASN1_OBJECT_find(oid_stack, oid) >= 0)
549
0
    ret = TRUE;
550
551
0
  sk_ASN1_OBJECT_pop_free(oid_stack, ASN1_OBJECT_free);
552
0
  return ret;
553
0
}
554
555
void x509_utils_print_info(const X509* xcert)
556
0
{
557
0
  char* fp;
558
0
  char* issuer;
559
0
  char* subject;
560
0
  subject = x509_utils_get_subject(xcert);
561
0
  issuer = x509_utils_get_issuer(xcert);
562
0
  fp = (char*)x509_utils_get_hash(xcert, "sha256", NULL);
563
564
0
  if (!fp)
565
0
  {
566
0
    WLog_ERR(TAG, "error computing fingerprint");
567
0
    goto out_free_issuer;
568
0
  }
569
570
0
  WLog_INFO(TAG, "Certificate details:");
571
0
  WLog_INFO(TAG, "\tSubject: %s", subject);
572
0
  WLog_INFO(TAG, "\tIssuer: %s", issuer);
573
0
  WLog_INFO(TAG, "\tThumbprint: %s", fp);
574
0
  WLog_INFO(TAG,
575
0
            "The above X.509 certificate could not be verified, possibly because you do not have "
576
0
            "the CA certificate in your certificate store, or the certificate has expired. "
577
0
            "Please look at the OpenSSL documentation on how to add a private CA to the store.");
578
0
  free(fp);
579
0
out_free_issuer:
580
0
  free(issuer);
581
0
  free(subject);
582
0
}
583
584
static BYTE* x509_utils_get_pem(const X509* xcert, const STACK_OF(X509) * chain, size_t* plength)
585
0
{
586
0
  BIO* bio;
587
0
  int status, count, x;
588
0
  size_t offset;
589
0
  size_t length = 0;
590
0
  BOOL rc = FALSE;
591
0
  BYTE* pemCert = NULL;
592
0
593
0
  if (!xcert || !plength)
594
0
    return NULL;
595
0
596
0
  /**
597
0
   * Don't manage certificates internally, leave it up entirely to the external client
598
0
   * implementation
599
0
   */
600
0
  bio = BIO_new(BIO_s_mem());
601
0
602
0
  if (!bio)
603
0
  {
604
0
    WLog_ERR(TAG, "BIO_new() failure");
605
0
    return NULL;
606
0
  }
607
0
608
0
  status = PEM_write_bio_X509(bio, (X509*)xcert);
609
0
610
0
  if (status < 0)
611
0
  {
612
0
    WLog_ERR(TAG, "PEM_write_bio_X509 failure: %d", status);
613
0
    goto fail;
614
0
  }
615
0
616
0
  if (chain)
617
0
  {
618
0
    count = sk_X509_num(chain);
619
0
    for (x = 0; x < count; x++)
620
0
    {
621
0
      X509* c = sk_X509_value(chain, x);
622
0
      status = PEM_write_bio_X509(bio, c);
623
0
      if (status < 0)
624
0
      {
625
0
        WLog_ERR(TAG, "PEM_write_bio_X509 failure: %d", status);
626
0
        goto fail;
627
0
      }
628
0
    }
629
0
  }
630
0
631
0
  offset = 0;
632
0
  length = 2048;
633
0
  pemCert = (BYTE*)malloc(length + 1);
634
0
635
0
  if (!pemCert)
636
0
  {
637
0
    WLog_ERR(TAG, "error allocating pemCert");
638
0
    goto fail;
639
0
  }
640
0
641
0
  ERR_clear_error();
642
0
  status = BIO_read(bio, pemCert, length);
643
0
644
0
  if (status < 0)
645
0
  {
646
0
    WLog_ERR(TAG, "failed to read certificate");
647
0
    goto fail;
648
0
  }
649
0
650
0
  offset += (size_t)status;
651
0
652
0
  while (offset >= length)
653
0
  {
654
0
    int new_len;
655
0
    BYTE* new_cert;
656
0
    new_len = length * 2;
657
0
    new_cert = (BYTE*)realloc(pemCert, new_len + 1);
658
0
659
0
    if (!new_cert)
660
0
      goto fail;
661
0
662
0
    length = new_len;
663
0
    pemCert = new_cert;
664
0
    ERR_clear_error();
665
0
    status = BIO_read(bio, &pemCert[offset], length - offset);
666
0
667
0
    if (status < 0)
668
0
      break;
669
0
670
0
    offset += status;
671
0
  }
672
0
673
0
  if (status < 0)
674
0
  {
675
0
    WLog_ERR(TAG, "failed to read certificate");
676
0
    goto fail;
677
0
  }
678
0
679
0
  length = offset;
680
0
  pemCert[length] = '\0';
681
0
  *plength = length;
682
0
  rc = TRUE;
683
0
fail:
684
0
685
0
  if (!rc)
686
0
  {
687
0
    WLog_ERR(TAG, "Failed to extract PEM from certificate %p", xcert);
688
0
    free(pemCert);
689
0
    pemCert = NULL;
690
0
  }
691
0
692
0
  BIO_free_all(bio);
693
0
  return pemCert;
694
0
}
695
696
X509* x509_utils_from_pem(const char* data, size_t len, BOOL fromFile)
697
0
{
698
0
  X509* x509 = NULL;
699
0
  BIO* bio;
700
0
  if (fromFile)
701
0
    bio = BIO_new_file(data, "rb");
702
0
  else
703
0
    bio = BIO_new_mem_buf(data, len);
704
705
0
  if (!bio)
706
0
  {
707
0
    WLog_ERR(TAG, "BIO_new failed for certificate");
708
0
    return NULL;
709
0
  }
710
711
0
  x509 = PEM_read_bio_X509(bio, NULL, NULL, 0);
712
0
  BIO_free_all(bio);
713
0
  if (!x509)
714
0
    WLog_ERR(TAG, "PEM_read_bio_X509 returned NULL [input length %" PRIuz "]", len);
715
716
0
  return x509;
717
0
}
718
719
WINPR_MD_TYPE x509_utils_get_signature_alg(const X509* xcert)
720
0
{
721
0
  WINPR_ASSERT(xcert);
722
723
0
  EVP_PKEY* evp = X509_get0_pubkey(xcert);
724
0
  WINPR_ASSERT(evp);
725
726
0
  int nid = 0;
727
0
  const int res = EVP_PKEY_get_default_digest_nid(evp, &nid);
728
0
  if (res <= 0)
729
0
    return WINPR_MD_NONE;
730
731
0
  switch (nid)
732
0
  {
733
0
    case NID_md2:
734
0
      return WINPR_MD_MD2;
735
0
    case NID_md4:
736
0
      return WINPR_MD_MD4;
737
0
    case NID_md5:
738
0
      return WINPR_MD_MD5;
739
0
    case NID_sha1:
740
0
      return WINPR_MD_SHA1;
741
0
    case NID_sha224:
742
0
      return WINPR_MD_SHA224;
743
0
    case NID_sha256:
744
0
      return WINPR_MD_SHA256;
745
0
    case NID_sha384:
746
0
      return WINPR_MD_SHA384;
747
0
    case NID_sha512:
748
0
      return WINPR_MD_SHA512;
749
0
    case NID_ripemd160:
750
0
      return WINPR_MD_RIPEMD160;
751
0
#if (OPENSSL_VERSION_NUMBER >= 0x1010101fL) && !defined(LIBRESSL_VERSION_NUMBER)
752
0
    case NID_sha3_224:
753
0
      return WINPR_MD_SHA3_224;
754
0
    case NID_sha3_256:
755
0
      return WINPR_MD_SHA3_256;
756
0
    case NID_sha3_384:
757
0
      return WINPR_MD_SHA3_384;
758
0
    case NID_sha3_512:
759
0
      return WINPR_MD_SHA3_512;
760
0
    case NID_shake128:
761
0
      return WINPR_MD_SHAKE128;
762
0
    case NID_shake256:
763
0
      return WINPR_MD_SHAKE256;
764
0
#endif
765
0
    case NID_undef:
766
0
    default:
767
0
      return WINPR_MD_NONE;
768
0
  }
769
0
}
770
771
char* x509_utils_get_common_name(const X509* xcert, size_t* plength)
772
0
{
773
0
  X509_NAME* subject_name = X509_get_subject_name(xcert);
774
0
  if (subject_name == NULL)
775
0
    return NULL;
776
777
0
  const int index = X509_NAME_get_index_by_NID(subject_name, NID_commonName, -1);
778
0
  if (index < 0)
779
0
    return NULL;
780
781
0
  const X509_NAME_ENTRY* entry = X509_NAME_get_entry(subject_name, index);
782
0
  if (entry == NULL)
783
0
    return NULL;
784
785
0
  const ASN1_STRING* entry_data = X509_NAME_ENTRY_get_data(entry);
786
0
  if (entry_data == NULL)
787
0
    return NULL;
788
789
0
  BYTE* common_name_raw = NULL;
790
0
  const int length = ASN1_STRING_to_UTF8(&common_name_raw, entry_data);
791
0
  if (length < 0)
792
0
    return NULL;
793
794
0
  if (plength)
795
0
    *plength = (size_t)length;
796
797
0
  char* common_name = _strdup((char*)common_name_raw);
798
0
  OPENSSL_free(common_name_raw);
799
0
  return common_name;
800
0
}
801
802
static int verify_cb(int ok, X509_STORE_CTX* csc)
803
0
{
804
0
  if (ok != 1)
805
0
  {
806
0
    WINPR_ASSERT(csc);
807
0
    int err = X509_STORE_CTX_get_error(csc);
808
0
    int derr = X509_STORE_CTX_get_error_depth(csc);
809
0
    X509* where = X509_STORE_CTX_get_current_cert(csc);
810
0
    const char* what = X509_verify_cert_error_string(err);
811
0
    char* name = x509_utils_get_subject(where);
812
813
0
    WLog_WARN(TAG, "Certificate verification failure '%s (%d)' at stack position %d", what, err,
814
0
              derr);
815
0
    WLog_WARN(TAG, "%s", name);
816
817
0
    free(name);
818
0
  }
819
0
  return ok;
820
0
}
821
822
BOOL x509_utils_verify(X509* xcert, STACK_OF(X509) * chain, const char* certificate_store_path)
823
0
{
824
0
  const int purposes[3] = { X509_PURPOSE_SSL_SERVER, X509_PURPOSE_SSL_CLIENT, X509_PURPOSE_ANY };
825
0
  X509_STORE_CTX* csc = NULL;
826
0
  BOOL status = FALSE;
827
0
  X509_LOOKUP* lookup = NULL;
828
829
0
  if (!xcert)
830
0
    return FALSE;
831
832
0
  X509_STORE* cert_ctx = X509_STORE_new();
833
834
0
  if (cert_ctx == NULL)
835
0
    goto end;
836
837
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
838
  OpenSSL_add_all_algorithms();
839
#else
840
0
  OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS |
841
0
                          OPENSSL_INIT_LOAD_CONFIG,
842
0
                      NULL);
843
0
#endif
844
845
0
  if (X509_STORE_set_default_paths(cert_ctx) != 1)
846
0
    goto end;
847
848
0
  lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_hash_dir());
849
850
0
  if (lookup == NULL)
851
0
    goto end;
852
853
0
  X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT);
854
855
0
  if (certificate_store_path != NULL)
856
0
  {
857
0
    X509_LOOKUP_add_dir(lookup, certificate_store_path, X509_FILETYPE_PEM);
858
0
  }
859
860
0
  X509_STORE_set_flags(cert_ctx, 0);
861
862
0
  for (size_t i = 0; i < ARRAYSIZE(purposes); i++)
863
0
  {
864
0
    int err = -1, rc = -1;
865
0
    int purpose = purposes[i];
866
0
    csc = X509_STORE_CTX_new();
867
868
0
    if (csc == NULL)
869
0
      goto skip;
870
0
    if (!X509_STORE_CTX_init(csc, cert_ctx, xcert, chain))
871
0
      goto skip;
872
873
0
    X509_STORE_CTX_set_purpose(csc, purpose);
874
0
    X509_STORE_CTX_set_verify_cb(csc, verify_cb);
875
876
0
    rc = X509_verify_cert(csc);
877
0
    err = X509_STORE_CTX_get_error(csc);
878
0
  skip:
879
0
    X509_STORE_CTX_free(csc);
880
0
    if (rc == 1)
881
0
    {
882
0
      status = TRUE;
883
0
      break;
884
0
    }
885
0
    else if (err != X509_V_ERR_INVALID_PURPOSE)
886
0
      break;
887
0
  }
888
889
0
  X509_STORE_free(cert_ctx);
890
0
end:
891
0
  return status;
892
0
}