This repository has been archived by the owner on Aug 27, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 14
/
X509CertSelector.java
2609 lines (2504 loc) · 104 KB
/
X509CertSelector.java
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) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.security.cert;
import java.io.IOException;
import java.math.BigInteger;
import java.security.PublicKey;
import java.util.*;
import javax.security.auth.x500.X500Principal;
import sun.security.util.*;
import sun.security.x509.*;
/**
* A {@code CertSelector} that selects {@code X509Certificates} that
* match all specified criteria. This class is particularly useful when
* selecting certificates from a {@code CertStore} to build a
* PKIX-compliant certification path.
* <p>
* When first constructed, an {@code X509CertSelector} has no criteria
* enabled and each of the {@code get} methods return a default value
* ({@code null}, or {@code -1} for the {@link #getBasicConstraints
* getBasicConstraints} method). Therefore, the {@link #match match}
* method would return {@code true} for any {@code X509Certificate}.
* Typically, several criteria are enabled (by calling
* {@link #setIssuer(X500Principal)} or
* {@link #setKeyUsage setKeyUsage}, for instance) and then the
* {@code X509CertSelector} is passed to
* {@link CertStore#getCertificates CertStore.getCertificates} or some similar
* method.
* <p>
* Several criteria can be enabled (by calling
* {@link #setIssuer(X500Principal)}
* and {@link #setSerialNumber setSerialNumber},
* for example) such that the {@code match} method
* usually uniquely matches a single {@code X509Certificate}. We say
* usually, since it is possible for two issuing CAs to have the same
* distinguished name and each issue a certificate with the same serial
* number. Other unique combinations include the issuer, subject,
* subjectKeyIdentifier and/or the subjectPublicKey criteria.
* <p>
* Please refer to <a href="http://tools.ietf.org/html/rfc5280">RFC 5280:
* Internet X.509 Public Key Infrastructure Certificate and CRL Profile</a> for
* definitions of the X.509 certificate extensions mentioned below.
* <p>
* <b>Concurrent Access</b>
* <p>
* Unless otherwise specified, the methods defined in this class are not
* thread-safe. Multiple threads that need to access a single
* object concurrently should synchronize amongst themselves and
* provide the necessary locking. Multiple threads each manipulating
* separate objects need not synchronize.
*
* @see CertSelector
* @see X509Certificate
*
* @since 1.4
* @author Steve Hanna
*/
public class X509CertSelector implements CertSelector {
private static final Debug debug = Debug.getInstance("certpath");
private static final ObjectIdentifier ANY_EXTENDED_KEY_USAGE =
ObjectIdentifier.of(KnownOIDs.anyExtendedKeyUsage);
static {
CertPathHelperImpl.initialize();
}
private BigInteger serialNumber;
private X500Principal issuer;
private X500Principal subject;
private byte[] subjectKeyID;
private byte[] authorityKeyID;
private Date certificateValid;
private Date privateKeyValid;
private ObjectIdentifier subjectPublicKeyAlgID;
private PublicKey subjectPublicKey;
private byte[] subjectPublicKeyBytes;
private boolean[] keyUsage;
private Set<String> keyPurposeSet;
private Set<ObjectIdentifier> keyPurposeOIDSet;
private Set<List<?>> subjectAlternativeNames;
private Set<GeneralNameInterface> subjectAlternativeGeneralNames;
private CertificatePolicySet policy;
private Set<String> policySet;
private Set<List<?>> pathToNames;
private Set<GeneralNameInterface> pathToGeneralNames;
private NameConstraintsExtension nc;
private byte[] ncBytes;
private int basicConstraints = -1;
private X509Certificate x509Cert;
private boolean matchAllSubjectAltNames = true;
private static final Boolean FALSE = Boolean.FALSE;
/* Constants representing the GeneralName types */
static final int NAME_ANY = 0;
static final int NAME_RFC822 = 1;
static final int NAME_DNS = 2;
static final int NAME_X400 = 3;
static final int NAME_DIRECTORY = 4;
static final int NAME_EDI = 5;
static final int NAME_URI = 6;
static final int NAME_IP = 7;
static final int NAME_OID = 8;
/**
* Creates an {@code X509CertSelector}. Initially, no criteria are set
* so any {@code X509Certificate} will match.
*/
public X509CertSelector() {
// empty
}
/**
* Sets the certificateEquals criterion. The specified
* {@code X509Certificate} must be equal to the
* {@code X509Certificate} passed to the {@code match} method.
* If {@code null}, then this check is not applied.
*
* <p>This method is particularly useful when it is necessary to
* match a single certificate. Although other criteria can be specified
* in conjunction with the certificateEquals criterion, it is usually not
* practical or necessary.
*
* @param cert the {@code X509Certificate} to match (or
* {@code null})
* @see #getCertificate
*/
public void setCertificate(X509Certificate cert) {
x509Cert = cert;
}
/**
* Sets the serialNumber criterion. The specified serial number
* must match the certificate serial number in the
* {@code X509Certificate}. If {@code null}, any certificate
* serial number will do.
*
* @param serial the certificate serial number to match
* (or {@code null})
* @see #getSerialNumber
*/
public void setSerialNumber(BigInteger serial) {
serialNumber = serial;
}
/**
* Sets the issuer criterion. The specified distinguished name
* must match the issuer distinguished name in the
* {@code X509Certificate}. If {@code null}, any issuer
* distinguished name will do.
*
* @param issuer a distinguished name as X500Principal
* (or {@code null})
* @since 1.5
*/
public void setIssuer(X500Principal issuer) {
this.issuer = issuer;
}
/**
* Sets the issuer criterion. The specified distinguished name
* must match the issuer distinguished name in the
* {@code X509Certificate}. If {@code null}, any issuer
* distinguished name will do.
* <p>
* If {@code issuerDN} is not {@code null}, it should contain a
* distinguished name, in
* <a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a> format.
*
* @param issuerDN a distinguished name in RFC 2253 format
* (or {@code null})
* @throws IOException if a parsing error occurs (incorrect form for DN)
*
* @deprecated Use {@link #setIssuer(X500Principal)} or
* {@link #setIssuer(byte[])} instead. This method should not be relied on
* as it can fail to match some certificates because of a loss of encoding
* information in the RFC 2253 String form of some distinguished names.
*/
@Deprecated(since="16")
public void setIssuer(String issuerDN) throws IOException {
if (issuerDN == null) {
issuer = null;
} else {
issuer = new X500Name(issuerDN).asX500Principal();
}
}
/**
* Sets the issuer criterion. The specified distinguished name
* must match the issuer distinguished name in the
* {@code X509Certificate}. If {@code null} is specified,
* the issuer criterion is disabled and any issuer distinguished name will
* do.
* <p>
* If {@code issuerDN} is not {@code null}, it should contain a
* single DER encoded distinguished name, as defined in X.501. The ASN.1
* notation for this structure is as follows.
* <pre>{@code
* Name ::= CHOICE {
* RDNSequence }
*
* RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
*
* RelativeDistinguishedName ::=
* SET SIZE (1 .. MAX) OF AttributeTypeAndValue
*
* AttributeTypeAndValue ::= SEQUENCE {
* type AttributeType,
* value AttributeValue }
*
* AttributeType ::= OBJECT IDENTIFIER
*
* AttributeValue ::= ANY DEFINED BY AttributeType
* ....
* DirectoryString ::= CHOICE {
* teletexString TeletexString (SIZE (1..MAX)),
* printableString PrintableString (SIZE (1..MAX)),
* universalString UniversalString (SIZE (1..MAX)),
* utf8String UTF8String (SIZE (1.. MAX)),
* bmpString BMPString (SIZE (1..MAX)) }
* }</pre>
* <p>
* Note that the byte array specified here is cloned to protect against
* subsequent modifications.
*
* @param issuerDN a byte array containing the distinguished name
* in ASN.1 DER encoded form (or {@code null})
* @throws IOException if an encoding error occurs (incorrect form for DN)
*/
public void setIssuer(byte[] issuerDN) throws IOException {
try {
issuer = (issuerDN == null ? null : new X500Principal(issuerDN));
} catch (IllegalArgumentException e) {
throw new IOException("Invalid name", e);
}
}
/**
* Sets the subject criterion. The specified distinguished name
* must match the subject distinguished name in the
* {@code X509Certificate}. If {@code null}, any subject
* distinguished name will do.
*
* @param subject a distinguished name as X500Principal
* (or {@code null})
* @since 1.5
*/
public void setSubject(X500Principal subject) {
this.subject = subject;
}
/**
* Sets the subject criterion. The specified distinguished name
* must match the subject distinguished name in the
* {@code X509Certificate}. If {@code null}, any subject
* distinguished name will do.
* <p>
* If {@code subjectDN} is not {@code null}, it should contain a
* distinguished name, in
* <a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a> format.
*
* @param subjectDN a distinguished name in RFC 2253 format
* (or {@code null})
* @throws IOException if a parsing error occurs (incorrect form for DN)
*
* @deprecated Use {@link #setSubject(X500Principal)} or
* {@link #setSubject(byte[])} instead. This method should not be relied
* on as it can fail to match some certificates because of a loss of
* encoding information in the RFC 2253 String form of some distinguished
* names.
*/
@Deprecated(since="16")
public void setSubject(String subjectDN) throws IOException {
if (subjectDN == null) {
subject = null;
} else {
subject = new X500Name(subjectDN).asX500Principal();
}
}
/**
* Sets the subject criterion. The specified distinguished name
* must match the subject distinguished name in the
* {@code X509Certificate}. If {@code null}, any subject
* distinguished name will do.
* <p>
* If {@code subjectDN} is not {@code null}, it should contain a
* single DER encoded distinguished name, as defined in X.501. For the ASN.1
* notation for this structure, see {@link #setIssuer(byte[])}.
*
* @param subjectDN a byte array containing the distinguished name in
* ASN.1 DER format (or {@code null})
* @throws IOException if an encoding error occurs (incorrect form for DN)
*/
public void setSubject(byte[] subjectDN) throws IOException {
try {
subject = (subjectDN == null ? null : new X500Principal(subjectDN));
} catch (IllegalArgumentException e) {
throw new IOException("Invalid name", e);
}
}
/**
* Sets the subjectKeyIdentifier criterion. The
* {@code X509Certificate} must contain a SubjectKeyIdentifier
* extension for which the contents of the extension
* matches the specified criterion value.
* If the criterion value is {@code null}, no
* subjectKeyIdentifier check will be done.
* <p>
* If {@code subjectKeyID} is not {@code null}, it
* should contain a single DER encoded value corresponding to the contents
* of the extension value (not including the object identifier,
* criticality setting, and encapsulating OCTET STRING)
* for a SubjectKeyIdentifier extension.
* The ASN.1 notation for this structure follows.
*
* <pre>{@code
* SubjectKeyIdentifier ::= KeyIdentifier
*
* KeyIdentifier ::= OCTET STRING
* }</pre>
* <p>
* Since the format of subject key identifiers is not mandated by
* any standard, subject key identifiers are not parsed by the
* {@code X509CertSelector}. Instead, the values are compared using
* a byte-by-byte comparison.
* <p>
* Note that the byte array supplied here is cloned to protect against
* subsequent modifications.
*
* @param subjectKeyID the subject key identifier (or {@code null})
* @see #getSubjectKeyIdentifier
*/
public void setSubjectKeyIdentifier(byte[] subjectKeyID) {
if (subjectKeyID == null) {
this.subjectKeyID = null;
} else {
this.subjectKeyID = subjectKeyID.clone();
}
}
/**
* Sets the authorityKeyIdentifier criterion. The
* {@code X509Certificate} must contain an
* AuthorityKeyIdentifier extension for which the contents of the
* extension value matches the specified criterion value.
* If the criterion value is {@code null}, no
* authorityKeyIdentifier check will be done.
* <p>
* If {@code authorityKeyID} is not {@code null}, it
* should contain a single DER encoded value corresponding to the contents
* of the extension value (not including the object identifier,
* criticality setting, and encapsulating OCTET STRING)
* for an AuthorityKeyIdentifier extension.
* The ASN.1 notation for this structure follows.
*
* <pre>{@code
* AuthorityKeyIdentifier ::= SEQUENCE {
* keyIdentifier [0] KeyIdentifier OPTIONAL,
* authorityCertIssuer [1] GeneralNames OPTIONAL,
* authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL }
*
* KeyIdentifier ::= OCTET STRING
* }</pre>
* <p>
* Authority key identifiers are not parsed by the
* {@code X509CertSelector}. Instead, the values are
* compared using a byte-by-byte comparison.
* <p>
* When the {@code keyIdentifier} field of
* {@code AuthorityKeyIdentifier} is populated, the value is
* usually taken from the {@code SubjectKeyIdentifier} extension
* in the issuer's certificate. Note, however, that the result of
* {@code X509Certificate.getExtensionValue(<SubjectKeyIdentifier Object
* Identifier>)} on the issuer's certificate may NOT be used
* directly as the input to {@code setAuthorityKeyIdentifier}.
* This is because the SubjectKeyIdentifier contains
* only a KeyIdentifier OCTET STRING, and not a SEQUENCE of
* KeyIdentifier, GeneralNames, and CertificateSerialNumber.
* In order to use the extension value of the issuer certificate's
* {@code SubjectKeyIdentifier}
* extension, it will be necessary to extract the value of the embedded
* {@code KeyIdentifier} OCTET STRING, then DER encode this OCTET
* STRING inside a SEQUENCE.
* For more details on SubjectKeyIdentifier, see
* {@link #setSubjectKeyIdentifier(byte[] subjectKeyID)}.
* <p>
* Note also that the byte array supplied here is cloned to protect against
* subsequent modifications.
*
* @param authorityKeyID the authority key identifier
* (or {@code null})
* @see #getAuthorityKeyIdentifier
*/
public void setAuthorityKeyIdentifier(byte[] authorityKeyID) {
if (authorityKeyID == null) {
this.authorityKeyID = null;
} else {
this.authorityKeyID = authorityKeyID.clone();
}
}
/**
* Sets the certificateValid criterion. The specified date must fall
* within the certificate validity period for the
* {@code X509Certificate}. If {@code null}, no certificateValid
* check will be done.
* <p>
* Note that the {@code Date} supplied here is cloned to protect
* against subsequent modifications.
*
* @param certValid the {@code Date} to check (or {@code null})
* @see #getCertificateValid
*/
public void setCertificateValid(Date certValid) {
if (certValid == null) {
certificateValid = null;
} else {
certificateValid = (Date)certValid.clone();
}
}
/**
* Sets the privateKeyValid criterion. The specified date must fall
* within the private key validity period for the
* {@code X509Certificate}. If {@code null}, no privateKeyValid
* check will be done.
* <p>
* Note that the {@code Date} supplied here is cloned to protect
* against subsequent modifications.
*
* @param privateKeyValid the {@code Date} to check (or
* {@code null})
* @see #getPrivateKeyValid
*/
public void setPrivateKeyValid(Date privateKeyValid) {
if (privateKeyValid == null) {
this.privateKeyValid = null;
} else {
this.privateKeyValid = (Date)privateKeyValid.clone();
}
}
/**
* Sets the subjectPublicKeyAlgID criterion. The
* {@code X509Certificate} must contain a subject public key
* with the specified algorithm. If {@code null}, no
* subjectPublicKeyAlgID check will be done.
*
* @param oid The object identifier (OID) of the algorithm to check
* for (or {@code null}). An OID is represented by a
* set of nonnegative integers separated by periods.
* @throws IOException if the OID is invalid, such as
* the first component being not 0, 1 or 2 or the second component
* being greater than 39.
*
* @see #getSubjectPublicKeyAlgID
*/
public void setSubjectPublicKeyAlgID(String oid) throws IOException {
if (oid == null) {
subjectPublicKeyAlgID = null;
} else {
subjectPublicKeyAlgID = ObjectIdentifier.of(oid);
}
}
/**
* Sets the subjectPublicKey criterion. The
* {@code X509Certificate} must contain the specified subject public
* key. If {@code null}, no subjectPublicKey check will be done.
*
* @param key the subject public key to check for (or {@code null})
* @see #getSubjectPublicKey
*/
public void setSubjectPublicKey(PublicKey key) {
if (key == null) {
subjectPublicKey = null;
subjectPublicKeyBytes = null;
} else {
subjectPublicKey = key;
subjectPublicKeyBytes = key.getEncoded();
}
}
/**
* Sets the subjectPublicKey criterion. The {@code X509Certificate}
* must contain the specified subject public key. If {@code null},
* no subjectPublicKey check will be done.
* <p>
* Because this method allows the public key to be specified as a byte
* array, it may be used for unknown key types.
* <p>
* If {@code key} is not {@code null}, it should contain a
* single DER encoded SubjectPublicKeyInfo structure, as defined in X.509.
* The ASN.1 notation for this structure is as follows.
* <pre>{@code
* SubjectPublicKeyInfo ::= SEQUENCE {
* algorithm AlgorithmIdentifier,
* subjectPublicKey BIT STRING }
*
* AlgorithmIdentifier ::= SEQUENCE {
* algorithm OBJECT IDENTIFIER,
* parameters ANY DEFINED BY algorithm OPTIONAL }
* -- contains a value of the type
* -- registered for use with the
* -- algorithm object identifier value
* }</pre>
* <p>
* Note that the byte array supplied here is cloned to protect against
* subsequent modifications.
*
* @param key a byte array containing the subject public key in ASN.1 DER
* form (or {@code null})
* @throws IOException if an encoding error occurs (incorrect form for
* subject public key)
* @see #getSubjectPublicKey
*/
public void setSubjectPublicKey(byte[] key) throws IOException {
if (key == null) {
subjectPublicKey = null;
subjectPublicKeyBytes = null;
} else {
subjectPublicKeyBytes = key.clone();
subjectPublicKey = X509Key.parse(new DerValue(subjectPublicKeyBytes));
}
}
/**
* Sets the keyUsage criterion. The {@code X509Certificate}
* must allow the specified keyUsage values. If {@code null}, no
* keyUsage check will be done. Note that an {@code X509Certificate}
* that has no keyUsage extension implicitly allows all keyUsage values.
* <p>
* Note that the boolean array supplied here is cloned to protect against
* subsequent modifications.
*
* @param keyUsage a boolean array in the same format as the boolean
* array returned by
* {@link X509Certificate#getKeyUsage() X509Certificate.getKeyUsage()}.
* Or {@code null}.
* @see #getKeyUsage
*/
public void setKeyUsage(boolean[] keyUsage) {
if (keyUsage == null) {
this.keyUsage = null;
} else {
this.keyUsage = keyUsage.clone();
}
}
/**
* Sets the extendedKeyUsage criterion. The {@code X509Certificate}
* must allow the specified key purposes in its extended key usage
* extension. If {@code keyPurposeSet} is empty or {@code null},
* no extendedKeyUsage check will be done. Note that an
* {@code X509Certificate} that has no extendedKeyUsage extension
* implicitly allows all key purposes.
* <p>
* Note that the {@code Set} is cloned to protect against
* subsequent modifications.
*
* @param keyPurposeSet a {@code Set} of key purpose OIDs in string
* format (or {@code null}). Each OID is represented by a set of
* nonnegative integers separated by periods.
* @throws IOException if the OID is invalid, such as
* the first component being not 0, 1 or 2 or the second component
* being greater than 39.
* @see #getExtendedKeyUsage
*/
public void setExtendedKeyUsage(Set<String> keyPurposeSet) throws IOException {
if ((keyPurposeSet == null) || keyPurposeSet.isEmpty()) {
this.keyPurposeSet = null;
keyPurposeOIDSet = null;
} else {
this.keyPurposeSet =
Collections.unmodifiableSet(new HashSet<>(keyPurposeSet));
keyPurposeOIDSet = new HashSet<>();
for (String s : this.keyPurposeSet) {
keyPurposeOIDSet.add(ObjectIdentifier.of(s));
}
}
}
/**
* Enables/disables matching all of the subjectAlternativeNames
* specified in the {@link #setSubjectAlternativeNames
* setSubjectAlternativeNames} or {@link #addSubjectAlternativeName
* addSubjectAlternativeName} methods. If enabled,
* the {@code X509Certificate} must contain all of the
* specified subject alternative names. If disabled, the
* {@code X509Certificate} must contain at least one of the
* specified subject alternative names.
*
* <p>The matchAllNames flag is {@code true} by default.
*
* @param matchAllNames if {@code true}, the flag is enabled;
* if {@code false}, the flag is disabled.
* @see #getMatchAllSubjectAltNames
*/
public void setMatchAllSubjectAltNames(boolean matchAllNames) {
this.matchAllSubjectAltNames = matchAllNames;
}
/**
* Sets the subjectAlternativeNames criterion. The
* {@code X509Certificate} must contain all or at least one of the
* specified subjectAlternativeNames, depending on the value of
* the matchAllNames flag (see {@link #setMatchAllSubjectAltNames
* setMatchAllSubjectAltNames}).
* <p>
* This method allows the caller to specify, with a single method call,
* the complete set of subject alternative names for the
* subjectAlternativeNames criterion. The specified value replaces
* the previous value for the subjectAlternativeNames criterion.
* <p>
* The {@code names} parameter (if not {@code null}) is a
* {@code Collection} with one
* entry for each name to be included in the subject alternative name
* criterion. Each entry is a {@code List} whose first entry is an
* {@code Integer} (the name type, 0-8) and whose second
* entry is a {@code String} or a byte array (the name, in
* string or ASN.1 DER encoded form, respectively).
* There can be multiple names of the same type. If {@code null}
* is supplied as the value for this argument, no
* subjectAlternativeNames check will be performed.
* <p>
* Each subject alternative name in the {@code Collection}
* may be specified either as a {@code String} or as an ASN.1 encoded
* byte array. For more details about the formats used, see
* {@link #addSubjectAlternativeName(int type, String name)
* addSubjectAlternativeName(int type, String name)} and
* {@link #addSubjectAlternativeName(int type, byte [] name)
* addSubjectAlternativeName(int type, byte [] name)}.
* <p>
* <strong>Note:</strong> for distinguished names, specify the byte
* array form instead of the String form. See the note in
* {@link #addSubjectAlternativeName(int, String)} for more information.
* <p>
* Note that the {@code names} parameter can contain duplicate
* names (same name and name type), but they may be removed from the
* {@code Collection} of names returned by the
* {@link #getSubjectAlternativeNames getSubjectAlternativeNames} method.
* <p>
* Note that a deep copy is performed on the {@code Collection} to
* protect against subsequent modifications.
*
* @param names a {@code Collection} of names (or {@code null})
* @throws IOException if a parsing error occurs
* @see #getSubjectAlternativeNames
*/
public void setSubjectAlternativeNames(Collection<List<?>> names)
throws IOException {
if (names == null) {
subjectAlternativeNames = null;
subjectAlternativeGeneralNames = null;
} else {
if (names.isEmpty()) {
subjectAlternativeNames = null;
subjectAlternativeGeneralNames = null;
return;
}
Set<List<?>> tempNames = cloneAndCheckNames(names);
// Ensure that we either set both of these or neither
subjectAlternativeGeneralNames = parseNames(tempNames);
subjectAlternativeNames = tempNames;
}
}
/**
* Adds a name to the subjectAlternativeNames criterion. The
* {@code X509Certificate} must contain all or at least one
* of the specified subjectAlternativeNames, depending on the value of
* the matchAllNames flag (see {@link #setMatchAllSubjectAltNames
* setMatchAllSubjectAltNames}).
* <p>
* This method allows the caller to add a name to the set of subject
* alternative names.
* The specified name is added to any previous value for the
* subjectAlternativeNames criterion. If the specified name is a
* duplicate, it may be ignored.
* <p>
* The name is provided in string format.
* <a href="http://www.ietf.org/rfc/rfc822.txt">RFC 822</a>, DNS, and URI
* names use the well-established string formats for those types (subject to
* the restrictions included in RFC 5280). IPv4 address names are
* supplied using dotted quad notation. OID address names are represented
* as a series of nonnegative integers separated by periods. And
* directory names (distinguished names) are supplied in
* <a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a> format.
* No standard string format is defined for otherNames, X.400 names,
* EDI party names, IPv6 address names, or any other type of names. They
* should be specified using the
* {@link #addSubjectAlternativeName(int type, byte [] name)
* addSubjectAlternativeName(int type, byte [] name)}
* method.
* <p>
* <strong>Note:</strong> for distinguished names, use
* {@linkplain #addSubjectAlternativeName(int, byte[])} instead.
* This method should not be relied on as it can fail to match some
* certificates because of a loss of encoding information in the RFC 2253
* String form of some distinguished names.
*
* @param type the name type (0-8, as specified in
* RFC 5280, section 4.2.1.6)
* @param name the name in string form (not {@code null})
* @throws IOException if a parsing error occurs
*/
public void addSubjectAlternativeName(int type, String name)
throws IOException {
addSubjectAlternativeNameInternal(type, name);
}
/**
* Adds a name to the subjectAlternativeNames criterion. The
* {@code X509Certificate} must contain all or at least one
* of the specified subjectAlternativeNames, depending on the value of
* the matchAllNames flag (see {@link #setMatchAllSubjectAltNames
* setMatchAllSubjectAltNames}).
* <p>
* This method allows the caller to add a name to the set of subject
* alternative names.
* The specified name is added to any previous value for the
* subjectAlternativeNames criterion. If the specified name is a
* duplicate, it may be ignored.
* <p>
* The name is provided as a byte array. This byte array should contain
* the DER encoded name, as it would appear in the GeneralName structure
* defined in RFC 5280 and X.509. The encoded byte array should only contain
* the encoded value of the name, and should not include the tag associated
* with the name in the GeneralName structure. The ASN.1 definition of this
* structure appears below.
* <pre>{@code
* GeneralName ::= CHOICE {
* otherName [0] OtherName,
* rfc822Name [1] IA5String,
* dNSName [2] IA5String,
* x400Address [3] ORAddress,
* directoryName [4] Name,
* ediPartyName [5] EDIPartyName,
* uniformResourceIdentifier [6] IA5String,
* iPAddress [7] OCTET STRING,
* registeredID [8] OBJECT IDENTIFIER}
* }</pre>
* <p>
* Note that the byte array supplied here is cloned to protect against
* subsequent modifications.
*
* @param type the name type (0-8, as listed above)
* @param name a byte array containing the name in ASN.1 DER encoded form
* @throws IOException if a parsing error occurs
*/
public void addSubjectAlternativeName(int type, byte[] name)
throws IOException {
// clone because byte arrays are modifiable
addSubjectAlternativeNameInternal(type, name.clone());
}
/**
* A private method that adds a name (String or byte array) to the
* subjectAlternativeNames criterion. The {@code X509Certificate}
* must contain the specified subjectAlternativeName.
*
* @param type the name type (0-8, as specified in
* RFC 5280, section 4.2.1.6)
* @param name the name in string or byte array form
* @throws IOException if a parsing error occurs
*/
private void addSubjectAlternativeNameInternal(int type, Object name)
throws IOException {
// First, ensure that the name parses
GeneralNameInterface tempName = makeGeneralNameInterface(type, name);
if (subjectAlternativeNames == null) {
subjectAlternativeNames = new HashSet<>();
}
if (subjectAlternativeGeneralNames == null) {
subjectAlternativeGeneralNames = new HashSet<>();
}
List<Object> list = new ArrayList<>(2);
list.add(Integer.valueOf(type));
list.add(name);
subjectAlternativeNames.add(list);
subjectAlternativeGeneralNames.add(tempName);
}
/**
* Parse an argument of the form passed to setSubjectAlternativeNames,
* returning a {@code Collection} of
* {@code GeneralNameInterface}s.
* Throw an IllegalArgumentException or a ClassCastException
* if the argument is malformed.
*
* @param names a Collection with one entry per name.
* Each entry is a {@code List} whose first entry
* is an Integer (the name type, 0-8) and whose second
* entry is a String or a byte array (the name, in
* string or ASN.1 DER encoded form, respectively).
* There can be multiple names of the same type. Null is
* not an acceptable value.
* @return a Set of {@code GeneralNameInterface}s
* @throws IOException if a parsing error occurs
*/
private static Set<GeneralNameInterface> parseNames(Collection<List<?>> names) throws IOException {
Set<GeneralNameInterface> genNames = new HashSet<>();
for (List<?> nameList : names) {
if (nameList.size() != 2) {
throw new IOException("name list size not 2");
}
Object o = nameList.get(0);
if (!(o instanceof Integer)) {
throw new IOException("expected an Integer");
}
int nameType = ((Integer)o).intValue();
o = nameList.get(1);
genNames.add(makeGeneralNameInterface(nameType, o));
}
return genNames;
}
/**
* Compare for equality two objects of the form passed to
* setSubjectAlternativeNames (or X509CRLSelector.setIssuerNames).
* Throw an {@code IllegalArgumentException} or a
* {@code ClassCastException} if one of the objects is malformed.
*
* @param object1 a Collection containing the first object to compare
* @param object2 a Collection containing the second object to compare
* @return true if the objects are equal, false otherwise
*/
static boolean equalNames(Collection<?> object1, Collection<?> object2) {
if ((object1 == null) || (object2 == null)) {
return object1 == object2;
}
return object1.equals(object2);
}
/**
* Make a {@code GeneralNameInterface} out of a name type (0-8) and an
* Object that may be a byte array holding the ASN.1 DER encoded
* name or a String form of the name. Except for X.509
* Distinguished Names, the String form of the name must not be the
* result from calling toString on an existing GeneralNameInterface
* implementing class. The output of toString is not compatible
* with the String constructors for names other than Distinguished
* Names.
*
* @param type name type (0-8)
* @param name name as ASN.1 Der-encoded byte array or String
* @return a GeneralNameInterface name
* @throws IOException if a parsing error occurs
*/
static GeneralNameInterface makeGeneralNameInterface(int type, Object name)
throws IOException {
GeneralNameInterface result;
if (debug != null) {
debug.println("X509CertSelector.makeGeneralNameInterface("
+ type + ")...");
}
if (name instanceof String) {
if (debug != null) {
debug.println("X509CertSelector.makeGeneralNameInterface() "
+ "name is String: " + name);
}
switch (type) {
case NAME_RFC822:
result = new RFC822Name((String)name);
break;
case NAME_DNS:
result = new DNSName((String)name);
break;
case NAME_DIRECTORY:
result = new X500Name((String)name);
break;
case NAME_URI:
result = new URIName((String)name);
break;
case NAME_IP:
result = new IPAddressName((String)name);
break;
case NAME_OID:
result = new OIDName((String)name);
break;
default:
throw new IOException("unable to parse String names of type "
+ type);
}
if (debug != null) {
debug.println("X509CertSelector.makeGeneralNameInterface() "
+ "result: " + result.toString());
}
} else if (name instanceof byte[]) {
DerValue val = new DerValue((byte[]) name);
if (debug != null) {
debug.println
("X509CertSelector.makeGeneralNameInterface() is byte[]");
}
switch (type) {
case NAME_ANY:
result = new OtherName(val);
break;
case NAME_RFC822:
result = new RFC822Name(val);
break;
case NAME_DNS:
result = new DNSName(val);
break;
case NAME_X400:
result = new X400Address(val);
break;
case NAME_DIRECTORY:
result = new X500Name(val);
break;
case NAME_EDI:
result = new EDIPartyName(val);
break;
case NAME_URI:
result = new URIName(val);
break;
case NAME_IP:
result = new IPAddressName(val);
break;
case NAME_OID:
result = new OIDName(val);
break;
default:
throw new IOException("unable to parse byte array names of "
+ "type " + type);
}
if (debug != null) {
debug.println("X509CertSelector.makeGeneralNameInterface() result: "
+ result.toString());
}
} else {
if (debug != null) {
debug.println("X509CertSelector.makeGeneralName() input name "
+ "not String or byte array");
}
throw new IOException("name not String or byte array");
}
return result;
}
/**
* Sets the name constraints criterion. The {@code X509Certificate}
* must have subject and subject alternative names that
* meet the specified name constraints.
* <p>
* The name constraints are specified as a byte array. This byte array
* should contain the DER encoded form of the name constraints, as they
* would appear in the NameConstraints structure defined in RFC 5280
* and X.509. The ASN.1 definition of this structure appears below.
*
* <pre>{@code
* NameConstraints ::= SEQUENCE {
* permittedSubtrees [0] GeneralSubtrees OPTIONAL,
* excludedSubtrees [1] GeneralSubtrees OPTIONAL }
*
* GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
*
* GeneralSubtree ::= SEQUENCE {
* base GeneralName,
* minimum [0] BaseDistance DEFAULT 0,
* maximum [1] BaseDistance OPTIONAL }
*
* BaseDistance ::= INTEGER (0..MAX)
*
* GeneralName ::= CHOICE {
* otherName [0] OtherName,
* rfc822Name [1] IA5String,