forked from aws/aws-lc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathx509_vfy.c
1760 lines (1550 loc) · 48.5 KB
/
x509_vfy.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* Copyright (C) 1995-1998 Eric Young ([email protected])
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young ([email protected]).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson ([email protected]).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young ([email protected])"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson ([email protected])"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.] */
#include <ctype.h>
#include <limits.h>
#include <string.h>
#include <time.h>
#include <openssl/asn1.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/mem.h>
#include <openssl/obj.h>
#include <openssl/thread.h>
#include <openssl/x509.h>
#include "../internal.h"
#include "internal.h"
static CRYPTO_EX_DATA_CLASS g_ex_data_class =
CRYPTO_EX_DATA_CLASS_INIT_WITH_APP_DATA;
// CRL score values
// No unhandled critical extensions
#define CRL_SCORE_NOCRITICAL 0x100
// certificate is within CRL scope
#define CRL_SCORE_SCOPE 0x080
// CRL times valid
#define CRL_SCORE_TIME 0x040
// Issuer name matches certificate
#define CRL_SCORE_ISSUER_NAME 0x020
// If this score or above CRL is probably valid
#define CRL_SCORE_VALID \
(CRL_SCORE_NOCRITICAL | CRL_SCORE_TIME | CRL_SCORE_SCOPE)
// CRL issuer is certificate issuer
#define CRL_SCORE_ISSUER_CERT 0x018
// CRL issuer is on certificate path
#define CRL_SCORE_SAME_PATH 0x008
// CRL issuer matches CRL AKID
#define CRL_SCORE_AKID 0x004
static int null_callback(int ok, X509_STORE_CTX *e);
static X509 *find_issuer(X509_STORE_CTX *ctx, STACK_OF(X509) *sk, X509 *x);
static int check_chain_extensions(X509_STORE_CTX *ctx);
static int check_name_constraints(X509_STORE_CTX *ctx);
static int check_id(X509_STORE_CTX *ctx);
static int check_trust(X509_STORE_CTX *ctx);
static int check_revocation(X509_STORE_CTX *ctx);
static int check_cert(X509_STORE_CTX *ctx);
static int check_policy(X509_STORE_CTX *ctx);
static int get_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x);
static int get_crl_score(X509_STORE_CTX *ctx, X509 **pissuer, X509_CRL *crl,
X509 *x);
static int get_crl(X509_STORE_CTX *ctx, X509_CRL **pcrl, X509 *x);
static int crl_akid_check(X509_STORE_CTX *ctx, X509_CRL *crl, X509 **pissuer,
int *pcrl_score);
static int crl_crldp_check(X509 *x, X509_CRL *crl, int crl_score);
static int cert_crl(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x);
static int internal_verify(X509_STORE_CTX *ctx);
static int null_callback(int ok, X509_STORE_CTX *e) { return ok; }
// cert_self_signed checks if |x| is self-signed. If |x| is valid, it returns
// one and sets |*out_is_self_signed| to the result. If |x| is invalid, it
// returns zero.
static int cert_self_signed(X509 *x, int *out_is_self_signed) {
if (!x509v3_cache_extensions(x)) {
return 0;
}
*out_is_self_signed = (x->ex_flags & EXFLAG_SS) != 0;
return 1;
}
static int call_verify_cb(int ok, X509_STORE_CTX *ctx) {
ok = ctx->verify_cb(ok, ctx);
// Historically, callbacks returning values like -1 would be treated as a mix
// of success or failure. Insert that callers check correctly.
//
// TODO(davidben): Also use this wrapper to constrain which errors may be
// suppressed, and ensure all |verify_cb| calls remember to fill in an error.
BSSL_CHECK(ok == 0 || ok == 1);
return ok;
}
// Given a certificate try and find an exact match in the store
static X509 *lookup_cert_match(X509_STORE_CTX *ctx, X509 *x) {
STACK_OF(X509) *certs;
X509 *xtmp = NULL;
size_t i;
// Lookup all certs with matching subject name
certs = X509_STORE_CTX_get1_certs(ctx, X509_get_subject_name(x));
if (certs == NULL) {
return NULL;
}
// Look for exact match
for (i = 0; i < sk_X509_num(certs); i++) {
xtmp = sk_X509_value(certs, i);
if (!X509_cmp(xtmp, x)) {
break;
}
}
if (i < sk_X509_num(certs)) {
X509_up_ref(xtmp);
} else {
xtmp = NULL;
}
sk_X509_pop_free(certs, X509_free);
return xtmp;
}
int X509_verify_cert(X509_STORE_CTX *ctx) {
X509 *xtmp, *xtmp2, *chain_ss = NULL;
int bad_chain = 0;
X509_VERIFY_PARAM *param = ctx->param;
int i, ok = 0;
int j, retry, trust;
STACK_OF(X509) *sktmp = NULL;
if (ctx->cert == NULL) {
OPENSSL_PUT_ERROR(X509, X509_R_NO_CERT_SET_FOR_US_TO_VERIFY);
ctx->error = X509_V_ERR_INVALID_CALL;
return -1;
}
if (ctx->chain != NULL) {
// This X509_STORE_CTX has already been used to verify a cert. We
// cannot do another one.
OPENSSL_PUT_ERROR(X509, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
ctx->error = X509_V_ERR_INVALID_CALL;
return -1;
}
if (ctx->param->flags &
(X509_V_FLAG_EXTENDED_CRL_SUPPORT | X509_V_FLAG_USE_DELTAS)) {
// We do not support indirect or delta CRLs. The flags still exist for
// compatibility with bindings libraries, but to ensure we do not
// inadvertently skip a CRL check that the caller expects, fail closed.
OPENSSL_PUT_ERROR(X509, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
ctx->error = X509_V_ERR_INVALID_CALL;
return -1;
}
// first we make sure the chain we are going to build is present and that
// the first entry is in place
ctx->chain = sk_X509_new_null();
if (ctx->chain == NULL || !sk_X509_push(ctx->chain, ctx->cert)) {
ctx->error = X509_V_ERR_OUT_OF_MEM;
goto end;
}
X509_up_ref(ctx->cert);
ctx->last_untrusted = 1;
// We use a temporary STACK so we can chop and hack at it.
if (ctx->untrusted != NULL && (sktmp = sk_X509_dup(ctx->untrusted)) == NULL) {
ctx->error = X509_V_ERR_OUT_OF_MEM;
goto end;
}
int num = (int)sk_X509_num(ctx->chain);
X509 *x = sk_X509_value(ctx->chain, num - 1);
// |param->depth| does not include the leaf certificate or the trust anchor,
// so the maximum size is 2 more.
int max_chain = param->depth >= INT_MAX - 2 ? INT_MAX : param->depth + 2;
for (;;) {
if (num >= max_chain) {
// FIXME: If this happens, we should take note of it and, if appropriate,
// use the X509_V_ERR_CERT_CHAIN_TOO_LONG error code later.
break;
}
int is_self_signed;
if (!cert_self_signed(x, &is_self_signed)) {
ctx->error = X509_V_ERR_INVALID_EXTENSION;
goto end;
}
// If we are self signed, we break
if (is_self_signed) {
break;
}
// If asked see if we can find issuer in trusted store first
if (ctx->param->flags & X509_V_FLAG_TRUSTED_FIRST) {
ok = get_issuer(&xtmp, ctx, x);
if (ok < 0) {
ctx->error = X509_V_ERR_STORE_LOOKUP;
goto end;
}
// If successful for now free up cert so it will be picked up
// again later.
if (ok > 0) {
X509_free(xtmp);
break;
}
}
// If we were passed a cert chain, use it first
if (sktmp != NULL) {
xtmp = find_issuer(ctx, sktmp, x);
if (xtmp != NULL) {
if (!sk_X509_push(ctx->chain, xtmp)) {
ctx->error = X509_V_ERR_OUT_OF_MEM;
ok = 0;
goto end;
}
X509_up_ref(xtmp);
(void)sk_X509_delete_ptr(sktmp, xtmp);
ctx->last_untrusted++;
x = xtmp;
num++;
// reparse the full chain for the next one
continue;
}
}
break;
}
// Remember how many untrusted certs we have
j = num;
// at this point, chain should contain a list of untrusted certificates.
// We now need to add at least one trusted one, if possible, otherwise we
// complain.
do {
// Examine last certificate in chain and see if it is self signed.
i = (int)sk_X509_num(ctx->chain);
x = sk_X509_value(ctx->chain, i - 1);
int is_self_signed;
if (!cert_self_signed(x, &is_self_signed)) {
ctx->error = X509_V_ERR_INVALID_EXTENSION;
goto end;
}
if (is_self_signed) {
// we have a self signed certificate
if (sk_X509_num(ctx->chain) == 1) {
// We have a single self signed certificate: see if we can
// find it in the store. We must have an exact match to avoid
// possible impersonation.
ok = get_issuer(&xtmp, ctx, x);
if ((ok <= 0) || X509_cmp(x, xtmp)) {
ctx->error = X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT;
ctx->current_cert = x;
ctx->error_depth = i - 1;
if (ok == 1) {
X509_free(xtmp);
}
bad_chain = 1;
ok = call_verify_cb(0, ctx);
if (!ok) {
goto end;
}
} else {
// We have a match: replace certificate with store
// version so we get any trust settings.
X509_free(x);
x = xtmp;
(void)sk_X509_set(ctx->chain, i - 1, x);
ctx->last_untrusted = 0;
}
} else {
// extract and save self signed certificate for later use
chain_ss = sk_X509_pop(ctx->chain);
ctx->last_untrusted--;
num--;
j--;
x = sk_X509_value(ctx->chain, num - 1);
}
}
// We now lookup certs from the certificate store
for (;;) {
if (num >= max_chain) {
// FIXME: If this happens, we should take note of it and, if
// appropriate, use the X509_V_ERR_CERT_CHAIN_TOO_LONG error code later.
break;
}
if (!cert_self_signed(x, &is_self_signed)) {
ctx->error = X509_V_ERR_INVALID_EXTENSION;
goto end;
}
// If we are self signed, we break
if (is_self_signed) {
break;
}
ok = get_issuer(&xtmp, ctx, x);
if (ok < 0) {
ctx->error = X509_V_ERR_STORE_LOOKUP;
goto end;
}
if (ok == 0) {
break;
}
x = xtmp;
if (!sk_X509_push(ctx->chain, x)) {
X509_free(xtmp);
ctx->error = X509_V_ERR_OUT_OF_MEM;
ok = 0;
goto end;
}
// OpenSSL 1.1.1 continuously re-checks for trust and breaks the loop
// as soon as trust has been established. 1.0.2 builds the chain with all
// possible certs first and only checks for trust if the final cert in
// the chain is self-signed.
// This caused additional unanticipated certs to be in the established
// certificate chain, particularly when |X509_V_FLAG_PARTIAL_CHAIN| was
// set. We try checking continuously for trust here for better 1.1.1
// compatibility.
trust = check_trust(ctx);
if (trust == X509_TRUST_TRUSTED || trust == X509_TRUST_REJECTED) {
break;
}
num++;
}
// we now have our chain, lets check it...
trust = check_trust(ctx);
// If explicitly rejected error
if (trust == X509_TRUST_REJECTED) {
ok = 0;
goto end;
}
// If it's not explicitly trusted then check if there is an alternative
// chain that could be used. We only do this if we haven't already
// checked via TRUSTED_FIRST and the user hasn't switched off alternate
// chain checking
retry = 0;
if (trust != X509_TRUST_TRUSTED &&
!(ctx->param->flags & X509_V_FLAG_TRUSTED_FIRST) &&
!(ctx->param->flags & X509_V_FLAG_NO_ALT_CHAINS)) {
while (j-- > 1) {
xtmp2 = sk_X509_value(ctx->chain, j - 1);
ok = get_issuer(&xtmp, ctx, xtmp2);
if (ok < 0) {
goto end;
}
// Check if we found an alternate chain
if (ok > 0) {
// Free up the found cert we'll add it again later
X509_free(xtmp);
// Dump all the certs above this point - we've found an
// alternate chain
while (num > j) {
xtmp = sk_X509_pop(ctx->chain);
X509_free(xtmp);
num--;
}
ctx->last_untrusted = (int)sk_X509_num(ctx->chain);
retry = 1;
break;
}
}
}
} while (retry);
// If not explicitly trusted then indicate error unless it's a single
// self signed certificate in which case we've indicated an error already
// and set bad_chain == 1
if (trust != X509_TRUST_TRUSTED && !bad_chain) {
if (chain_ss == NULL ||
!x509_check_issued_with_callback(ctx, x, chain_ss)) {
if (ctx->last_untrusted >= num) {
ctx->error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY;
} else {
ctx->error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT;
}
ctx->current_cert = x;
} else {
if (!sk_X509_push(ctx->chain, chain_ss)) {
ctx->error = X509_V_ERR_OUT_OF_MEM;
ok = 0;
goto end;
}
num++;
ctx->last_untrusted = num;
ctx->current_cert = chain_ss;
ctx->error = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
chain_ss = NULL;
}
ctx->error_depth = num - 1;
bad_chain = 1;
ok = call_verify_cb(0, ctx);
if (!ok) {
goto end;
}
}
// We have the chain complete: now we need to check its purpose
ok = check_chain_extensions(ctx);
if (!ok) {
goto end;
}
ok = check_id(ctx);
if (!ok) {
goto end;
}
// Check revocation status: we do this after copying parameters because
// they may be needed for CRL signature verification.
ok = check_revocation(ctx);
if (!ok) {
goto end;
}
// At this point, we have a chain and need to verify it
ok = internal_verify(ctx);
if (!ok) {
goto end;
}
// Check name constraints
ok = check_name_constraints(ctx);
if (!ok) {
goto end;
}
// If we get this far evaluate policies
if (!bad_chain && (ctx->param->flags & X509_V_FLAG_POLICY_CHECK)) {
ok = check_policy(ctx);
}
end:
if (sktmp != NULL) {
sk_X509_free(sktmp);
}
if (chain_ss != NULL) {
X509_free(chain_ss);
}
// Safety net, error returns must set ctx->error
if (ok <= 0 && ctx->error == X509_V_OK) {
ctx->error = X509_V_ERR_UNSPECIFIED;
}
return ok;
}
// Given a STACK_OF(X509) find the issuer of cert (if any)
//
// |find_issuer| will directly return the pointer of the corresponding index
// within |sk|. Callers of |find_issuer| should remember to bump the reference
// count of the returned |X509| if the call is successful.
static X509 *find_issuer(X509_STORE_CTX *ctx, STACK_OF(X509) *sk, X509 *x) {
size_t i;
X509 *issuer, *candidate = NULL;
for (i = 0; i < sk_X509_num(sk); i++) {
issuer = sk_X509_value(sk, i);
if (x509_check_issued_with_callback(ctx, x, issuer)) {
candidate = issuer;
if (x509_check_cert_time(ctx, candidate, /*suppress_error*/1)) {
break;
}
}
}
return candidate;
}
// Given a possible certificate and issuer check them
int x509_check_issued_with_callback(X509_STORE_CTX *ctx, X509 *x,
X509 *issuer) {
int ret;
ret = X509_check_issued(issuer, x);
if (ret == X509_V_OK) {
return 1;
}
// If we haven't asked for issuer errors don't set ctx
if (!(ctx->param->flags & X509_V_FLAG_CB_ISSUER_CHECK)) {
return 0;
}
ctx->error = ret;
ctx->current_cert = x;
ctx->current_issuer = issuer;
return call_verify_cb(0, ctx);
}
static int get_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x) {
if (ctx->trusted_stack != NULL) {
// Ignore the store and use the configured stack instead.
*issuer = find_issuer(ctx, ctx->trusted_stack, x);
if (*issuer) {
X509_up_ref(*issuer);
return 1;
}
return 0;
}
return X509_STORE_CTX_get1_issuer(issuer, ctx, x);
}
// Check a certificate chains extensions for consistency with the supplied
// purpose
static int check_chain_extensions(X509_STORE_CTX *ctx) {
int ok = 0, plen = 0;
int purpose = ctx->param->purpose;
// Check all untrusted certificates
for (int i = 0; i < ctx->last_untrusted; i++) {
X509 *x = sk_X509_value(ctx->chain, i);
if (!(ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL) &&
(x->ex_flags & EXFLAG_CRITICAL)) {
ctx->error = X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION;
ctx->error_depth = i;
ctx->current_cert = x;
ok = call_verify_cb(0, ctx);
if (!ok) {
goto end;
}
}
int must_be_ca = i > 0;
if (must_be_ca && !X509_check_ca(x)) {
ctx->error = X509_V_ERR_INVALID_CA;
ctx->error_depth = i;
ctx->current_cert = x;
ok = call_verify_cb(0, ctx);
if (!ok) {
goto end;
}
}
if (ctx->param->purpose > 0 &&
X509_check_purpose(x, purpose, must_be_ca) != 1) {
ctx->error = X509_V_ERR_INVALID_PURPOSE;
ctx->error_depth = i;
ctx->current_cert = x;
ok = call_verify_cb(0, ctx);
if (!ok) {
goto end;
}
}
// Check pathlen if not self issued
if (i > 1 && !(x->ex_flags & EXFLAG_SI) && x->ex_pathlen != -1 &&
plen > x->ex_pathlen + 1) {
ctx->error = X509_V_ERR_PATH_LENGTH_EXCEEDED;
ctx->error_depth = i;
ctx->current_cert = x;
ok = call_verify_cb(0, ctx);
if (!ok) {
goto end;
}
}
// Increment path length if not self issued
if (!(x->ex_flags & EXFLAG_SI)) {
plen++;
}
}
ok = 1;
end:
return ok;
}
static int reject_dns_name_in_common_name(X509 *x509) {
const X509_NAME *name = X509_get_subject_name(x509);
int i = -1;
for (;;) {
i = X509_NAME_get_index_by_NID(name, NID_commonName, i);
if (i == -1) {
return X509_V_OK;
}
const X509_NAME_ENTRY *entry = X509_NAME_get_entry(name, i);
const ASN1_STRING *common_name = X509_NAME_ENTRY_get_data(entry);
unsigned char *idval;
int idlen = ASN1_STRING_to_UTF8(&idval, common_name);
if (idlen < 0) {
return X509_V_ERR_OUT_OF_MEM;
}
// Only process attributes that look like host names. Note it is
// important that this check be mirrored in |X509_check_host|.
int looks_like_dns = x509v3_looks_like_dns_name(idval, (size_t)idlen);
OPENSSL_free(idval);
if (looks_like_dns) {
return X509_V_ERR_NAME_CONSTRAINTS_WITHOUT_SANS;
}
}
}
static int check_name_constraints(X509_STORE_CTX *ctx) {
int i, j, rv;
int has_name_constraints = 0;
// Check name constraints for all certificates
for (i = (int)sk_X509_num(ctx->chain) - 1; i >= 0; i--) {
X509 *x = sk_X509_value(ctx->chain, i);
// Ignore self issued certs unless last in chain
if (i && (x->ex_flags & EXFLAG_SI)) {
continue;
}
// Check against constraints for all certificates higher in chain
// including trust anchor. Trust anchor not strictly speaking needed
// but if it includes constraints it is to be assumed it expects them
// to be obeyed.
for (j = (int)sk_X509_num(ctx->chain) - 1; j > i; j--) {
NAME_CONSTRAINTS *nc = sk_X509_value(ctx->chain, j)->nc;
if (nc) {
has_name_constraints = 1;
rv = NAME_CONSTRAINTS_check(x, nc);
switch (rv) {
case X509_V_OK:
continue;
case X509_V_ERR_OUT_OF_MEM:
ctx->error = rv;
return 0;
default:
ctx->error = rv;
ctx->error_depth = i;
ctx->current_cert = x;
if (!call_verify_cb(0, ctx)) {
return 0;
}
break;
}
}
}
}
// Name constraints do not match against the common name, but
// |X509_check_host| still implements the legacy behavior where, on
// certificates lacking a SAN list, DNS-like names in the common name are
// checked instead.
//
// While we could apply the name constraints to the common name, name
// constraints are rare enough that can hold such certificates to a higher
// standard. Note this does not make "DNS-like" heuristic failures any
// worse. A decorative common-name misidentified as a DNS name would fail
// the name constraint anyway.
X509 *leaf = sk_X509_value(ctx->chain, 0);
if (has_name_constraints && leaf->altname == NULL) {
rv = reject_dns_name_in_common_name(leaf);
switch (rv) {
case X509_V_OK:
break;
case X509_V_ERR_OUT_OF_MEM:
ctx->error = rv;
return 0;
default:
ctx->error = rv;
ctx->error_depth = i;
ctx->current_cert = leaf;
if (!call_verify_cb(0, ctx)) {
return 0;
}
break;
}
}
return 1;
}
static int check_id_error(X509_STORE_CTX *ctx, int errcode) {
ctx->error = errcode;
ctx->current_cert = ctx->cert;
ctx->error_depth = 0;
return call_verify_cb(0, ctx);
}
static int check_hosts(X509 *x, X509_VERIFY_PARAM *param) {
size_t i;
size_t n = sk_OPENSSL_STRING_num(param->hosts);
char *name;
for (i = 0; i < n; ++i) {
name = sk_OPENSSL_STRING_value(param->hosts, i);
if (X509_check_host(x, name, strlen(name), param->hostflags, NULL) > 0) {
return 1;
}
}
return n == 0;
}
static int check_id(X509_STORE_CTX *ctx) {
X509_VERIFY_PARAM *vpm = ctx->param;
X509 *x = ctx->cert;
if (vpm->poison) {
if (!check_id_error(ctx, X509_V_ERR_INVALID_CALL)) {
return 0;
}
}
if (vpm->hosts && check_hosts(x, vpm) <= 0) {
if (!check_id_error(ctx, X509_V_ERR_HOSTNAME_MISMATCH)) {
return 0;
}
}
if (vpm->email && X509_check_email(x, vpm->email, vpm->emaillen, 0) <= 0) {
if (!check_id_error(ctx, X509_V_ERR_EMAIL_MISMATCH)) {
return 0;
}
}
if (vpm->ip && X509_check_ip(x, vpm->ip, vpm->iplen, 0) <= 0) {
if (!check_id_error(ctx, X509_V_ERR_IP_ADDRESS_MISMATCH)) {
return 0;
}
}
return 1;
}
static int check_trust(X509_STORE_CTX *ctx) {
int ok;
X509 *x = NULL;
// Check all trusted certificates in chain
for (size_t i = ctx->last_untrusted; i < sk_X509_num(ctx->chain); i++) {
x = sk_X509_value(ctx->chain, i);
ok = X509_check_trust(x, ctx->param->trust, 0);
// If explicitly trusted return trusted
if (ok == X509_TRUST_TRUSTED) {
return X509_TRUST_TRUSTED;
}
// If explicitly rejected notify callback and reject if not
// overridden.
if (ok == X509_TRUST_REJECTED) {
ctx->error_depth = (int)i;
ctx->current_cert = x;
ctx->error = X509_V_ERR_CERT_REJECTED;
ok = call_verify_cb(0, ctx);
if (!ok) {
return X509_TRUST_REJECTED;
}
}
}
// If we accept partial chains and have at least one trusted certificate
// return success.
if (ctx->param->flags & X509_V_FLAG_PARTIAL_CHAIN) {
X509 *mx;
if (ctx->last_untrusted < (int)sk_X509_num(ctx->chain)) {
return X509_TRUST_TRUSTED;
}
x = sk_X509_value(ctx->chain, 0);
mx = lookup_cert_match(ctx, x);
if (mx) {
(void)sk_X509_set(ctx->chain, 0, mx);
X509_free(x);
ctx->last_untrusted = 0;
return X509_TRUST_TRUSTED;
}
}
// If no trusted certs in chain at all return untrusted and allow
// standard (no issuer cert) etc errors to be indicated.
return X509_TRUST_UNTRUSTED;
}
static int check_revocation(X509_STORE_CTX *ctx) {
if (!(ctx->param->flags & X509_V_FLAG_CRL_CHECK)) {
return 1;
}
int last;
if (ctx->param->flags & X509_V_FLAG_CRL_CHECK_ALL) {
last = (int)sk_X509_num(ctx->chain) - 1;
} else {
last = 0;
}
for (int i = 0; i <= last; i++) {
ctx->error_depth = i;
int ok = check_cert(ctx);
if (!ok) {
return ok;
}
}
return 1;
}
static int check_cert(X509_STORE_CTX *ctx) {
X509_CRL *crl = NULL;
int ok = 0, cnum = ctx->error_depth;
X509 *x = sk_X509_value(ctx->chain, cnum);
ctx->current_cert = x;
ctx->current_issuer = NULL;
ctx->current_crl_score = 0;
// Try to retrieve relevant CRL
ok = ctx->get_crl(ctx, &crl, x);
// If error looking up CRL, nothing we can do except notify callback
if (!ok) {
ctx->error = X509_V_ERR_UNABLE_TO_GET_CRL;
ok = call_verify_cb(0, ctx);
goto err;
}
ctx->current_crl = crl;
ok = ctx->check_crl(ctx, crl);
if (!ok) {
goto err;
}
ok = cert_crl(ctx, crl, x);
if (!ok) {
goto err;
}
err:
X509_CRL_free(crl);
ctx->current_crl = NULL;
return ok;
}
// Check CRL times against values in X509_STORE_CTX
static int check_crl_time(X509_STORE_CTX *ctx, X509_CRL *crl, int notify) {
if (ctx->param->flags & X509_V_FLAG_NO_CHECK_TIME) {
return 1;
}
if (notify) {
ctx->current_crl = crl;
}
int64_t ptime;
if (ctx->param->flags & X509_V_FLAG_USE_CHECK_TIME) {
ptime = ctx->param->check_time;
} else {
ptime = time(NULL);
}
int i = X509_cmp_time_posix(X509_CRL_get0_lastUpdate(crl), ptime);
if (i == 0) {
if (!notify) {
return 0;
}
ctx->error = X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD;
if (!call_verify_cb(0, ctx)) {
return 0;
}
}
if (i > 0) {
if (!notify) {
return 0;
}
ctx->error = X509_V_ERR_CRL_NOT_YET_VALID;
if (!call_verify_cb(0, ctx)) {
return 0;
}
}
if (X509_CRL_get0_nextUpdate(crl)) {
i = X509_cmp_time_posix(X509_CRL_get0_nextUpdate(crl), ptime);
if (i == 0) {
if (!notify) {
return 0;
}
ctx->error = X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD;
if (!call_verify_cb(0, ctx)) {
return 0;
}
}
if (i < 0) {
if (!notify) {
return 0;
}
ctx->error = X509_V_ERR_CRL_HAS_EXPIRED;
if (!call_verify_cb(0, ctx)) {
return 0;
}
}
}
if (notify) {
ctx->current_crl = NULL;
}
return 1;
}
static int get_crl_sk(X509_STORE_CTX *ctx, X509_CRL **pcrl, X509 **pissuer,
int *pscore, STACK_OF(X509_CRL) *crls) {
int crl_score, best_score = *pscore;
X509 *x = ctx->current_cert;
X509_CRL *best_crl = NULL;
X509 *crl_issuer = NULL, *best_crl_issuer = NULL;
for (size_t i = 0; i < sk_X509_CRL_num(crls); i++) {
X509_CRL *crl = sk_X509_CRL_value(crls, i);
crl_score = get_crl_score(ctx, &crl_issuer, crl, x);
if (crl_score < best_score || crl_score == 0) {
continue;
}
// If current CRL is equivalent use it if it is newer
if (crl_score == best_score && best_crl != NULL) {
int day, sec;
if (ASN1_TIME_diff(&day, &sec, X509_CRL_get0_lastUpdate(best_crl),
X509_CRL_get0_lastUpdate(crl)) == 0) {
continue;
}
// ASN1_TIME_diff never returns inconsistent signs for |day|
// and |sec|.
if (day <= 0 && sec <= 0) {
continue;
}
}
best_crl = crl;
best_crl_issuer = crl_issuer;
best_score = crl_score;
}
if (best_crl) {
if (*pcrl) {
X509_CRL_free(*pcrl);
}
*pcrl = best_crl;
*pissuer = best_crl_issuer;
*pscore = best_score;
X509_CRL_up_ref(best_crl);
}
if (best_score >= CRL_SCORE_VALID) {
return 1;
}
return 0;
}
// For a given CRL return how suitable it is for the supplied certificate
// 'x'. The return value is a mask of several criteria. If the issuer is not
// the certificate issuer this is returned in *pissuer.
static int get_crl_score(X509_STORE_CTX *ctx, X509 **pissuer, X509_CRL *crl,
X509 *x) {
int crl_score = 0;
// First see if we can reject CRL straight away
// Invalid IDP cannot be processed
if (crl->idp_flags & IDP_INVALID) {
return 0;
}
// Reason codes and indirect CRLs are not supported.
if (crl->idp_flags & (IDP_INDIRECT | IDP_REASONS)) {
return 0;
}
// We do not support indirect CRLs, so the issuer names must match.