1/*
2 * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23import static sun.security.x509.GeneralNameInterface.NAME_DIRECTORY;
24import static sun.security.x509.NameConstraintsExtension.EXCLUDED_SUBTREES;
25import static sun.security.x509.NameConstraintsExtension.PERMITTED_SUBTREES;
26
27import java.io.ByteArrayInputStream;
28import java.io.ByteArrayOutputStream;
29import java.io.IOException;
30import java.io.InputStream;
31import java.math.BigInteger;
32import java.security.GeneralSecurityException;
33import java.security.KeyFactory;
34import java.security.PublicKey;
35import java.security.cert.CertificateException;
36import java.security.cert.CertificateFactory;
37import java.security.cert.X509CertSelector;
38import java.security.cert.X509Certificate;
39import java.security.spec.X509EncodedKeySpec;
40import java.util.Base64;
41import java.util.Calendar;
42import java.util.Date;
43import java.util.HashSet;
44import java.util.Iterator;
45import java.util.List;
46import java.util.Set;
47
48import sun.security.util.DerInputStream;
49import sun.security.util.DerOutputStream;
50import sun.security.util.DerValue;
51import sun.security.util.ObjectIdentifier;
52import sun.security.x509.AlgorithmId;
53import sun.security.x509.AuthorityKeyIdentifierExtension;
54import sun.security.x509.CertificatePoliciesExtension;
55import sun.security.x509.DNSName;
56import sun.security.x509.GeneralName;
57import sun.security.x509.GeneralNameInterface;
58import sun.security.x509.GeneralNames;
59import sun.security.x509.GeneralSubtree;
60import sun.security.x509.GeneralSubtrees;
61import sun.security.x509.KeyIdentifier;
62import sun.security.x509.NameConstraintsExtension;
63import sun.security.x509.PolicyInformation;
64import sun.security.x509.PrivateKeyUsageExtension;
65import sun.security.x509.SubjectAlternativeNameExtension;
66import sun.security.x509.X500Name;
67
68/*
69 * @test
70 * @bug 8074931
71 * @summary This class tests the X509CertSelector. The tests check particular criteria
72 *          by setting them to a value that should match our test certificate and
73 *          ensuring that they do match, then setting them to a value that should not
74 *          match our test certificate and ensuring that they do not match.
75 * @modules java.base/sun.security.x509
76 *          java.base/sun.security.util
77 */
78public class X509CertSelectorTest {
79    /*
80            Certificate:
81                Data:
82                    Version: 3 (0x2)
83                    Serial Number: 954172088 (0x38df82b8)
84                Signature Algorithm: dsaWithSHA1
85                    Issuer: C=us, O=sun, OU=testing
86                    Validity
87                        Not Before: Mar 27 15:48:08 2000 GMT
88                        Not After : Jun 25 14:48:08 2000 GMT
89                    Subject: C=us, O=sun, OU=testing, CN=mullan
90                    Subject Public Key Info:
91                        Public Key Algorithm: dsaEncryption
92                            pub:  0
93                            P:    0
94                            Q:    0
95                            G:    0
96                    X509v3 extensions:
97                        X509v3 Name Constraints: critical
98                            0D.B0@.>1.0...U....us1.0
99            ..U.
100            ..sun1.0...U....testing1.0
101            ..U....mullan
102                        X509v3 Subject Key Identifier:
103                            56:E8:88:AE:9D:B5:3F:2B:CB:A0:4C:4B:E2:87:53:07:33:77:1B:DF
104                        X509v3 Authority Key Identifier:
105                            keyid:8E:DD:AF:6F:EE:02:12:F4:61:E9:2F:E3:64:1A:6F:71:32:25:20:C0
106
107                        X509v3 Subject Alternative Name:
108                            email:mullan@east.sun.com
109                        X509v3 Private Key Usage Period:
110                            Not Before: Jan  1 05:00:00 2000 GMT, Not After: Jan  1 05:00:00 2001 GMT
111                        X509v3 Key Usage: critical
112                            Digital Signature
113                        X509v3 Certificate Policies:
114                            0$0\..*...0.0...+.......0..
115            Testing...
116                Signature Algorithm: dsaWithSHA1
117                     r:
118                         44:c7:35:40:5d:6c:28:75:7f:73:b2:f8:0d:72:6c:
119                         09:65:b8:81:14
120                     s:
121                         76:79:f5:c7:37:3b:0d:9b:db:70:2f:20:80:36:e3:
122                         80:e8:a6:c6:71
123    */
124    private static final String testCert =
125            "-----BEGIN CERTIFICATE-----\n" +
126            "MIICLjCCAeygAwIBAgIEON+CuDALBgcqhkjOOAQDBQAwLTELMAkGA1UEBhMCdXMx\n" +
127            "DDAKBgNVBAoTA3N1bjEQMA4GA1UECxMHdGVzdGluZzAeFw0wMDAzMjcxNTQ4MDha\n" +
128            "Fw0wMDA2MjUxNDQ4MDhaMD4xCzAJBgNVBAYTAnVzMQwwCgYDVQQKEwNzdW4xEDAO\n" +
129            "BgNVBAsTB3Rlc3RpbmcxDzANBgNVBAMTBm11bGxhbjAcMBQGByqGSM44BAEwCQIB\n" +
130            "AAIBAAIBAAMEAAIBAKOCASMwggEfMFAGA1UdHgEB/wRGMESgQjBApD4xCzAJBgNV\n" +
131            "BAYTAnVzMQwwCgYDVQQKEwNzdW4xEDAOBgNVBAsTB3Rlc3RpbmcxDzANBgNVBAMT\n" +
132            "Bm11bGxhbjAdBgNVHQ4EFgQUVuiIrp21PyvLoExL4odTBzN3G98wHwYDVR0jBBgw\n" +
133            "FoAUjt2vb+4CEvRh6S/jZBpvcTIlIMAwHgYDVR0RBBcwFYETbXVsbGFuQGVhc3Qu\n" +
134            "c3VuLmNvbTArBgNVHRAEJDAigA8yMDAwMDEwMTA1MDAwMFqBDzIwMDEwMTAxMDUw\n" +
135            "MDAwWjAPBgNVHQ8BAf8EBQMDB4AAMC0GA1UdIAQmMCQwIgYEKoSAADAaMBgGCCsG\n" +
136            "AQUFBwICMAwSClRlc3RpbmcuLi4wCwYHKoZIzjgEAwUAAy8AMCwCFETHNUBdbCh1\n" +
137            "f3Oy+A1ybAlluIEUAhR2efXHNzsNm9twLyCANuOA6KbGcQ==\n" +
138            "-----END CERTIFICATE-----\n" +
139            "";
140
141    private static final String testKey =
142            "MIIBtjCCASsGByqGSM44BAEwggEeAoGBAIVWPEkcxbxhQRCqVzg55tNqbP5j0K4kdu4bkmXvfqC5\n" +
143            "+qA75DvnfzsOJseb+9AuKXWk/DvCzFDmrY1YaU3scZC3OQEO9lEO3F4VDKOaudY6OT1SI22pAIwz\n" +
144            "j5pvq+i7zOp4xUqkQUeh/4iQSfxOT5UrFGjkcbnbpVkCXD/GxAz7AhUAjtnm3dVIddUUHl6wxpZ7\n" +
145            "GcA6gSsCgYAf/PXzQtemgIDjpFrNNSgTEKkLposBXKatAM+gUKlMUjf8SQvquqPxDtRrscGjXkoL\n" +
146            "oTkaR7/akULYFpBvUcFkeIFiCnJg8M9XhCWdLvn9MPt+jR2oxookvCb9xLtD6WvIM/wd/nZ1iK4u\n" +
147            "iY1+q85xvns/Awbtwl7oZDAwE2TUKAOBhAACgYBDc9UZ+3xsZubUZvRG5cpyJceYpJp2exOPVJXn\n" +
148            "jR4CcR+cT9bAJpFSxqE/8KtNHXxHdu4f3DU67IMOVDpugzihyzXJvNm3w2H9x+6xczHG2wjvAJeh\n" +
149            "X62EWbUatxPXFAoVKZWuUbaYaZzdWBDtNRrCuKKsLo0GFy8g2BZISuD3jw==\n" +
150            "";
151
152    // Certificate to run tests on
153    private final X509Certificate cert;
154
155    public static void main(String[] args) throws Exception {
156        X509CertSelectorTest test = new X509CertSelectorTest();
157        test.doTest();
158    }
159
160    public X509CertSelectorTest() throws CertificateException, IOException {
161        cert = (X509Certificate) CertificateFactory.getInstance("X.509")
162                .generateCertificate(new ByteArrayInputStream(testCert.getBytes()));
163    }
164
165    // Runs the test.
166    private void doTest() throws Exception {
167        System.out.println("START OF TESTS FOR " + "X509CertSelector");
168
169        testSerialNumber();
170        testIssuer();
171        testSubjectKeyIdentifier();
172        testAuthorityKeyIdentifier();
173        testCertificateValid();
174        testPrivateKeyValid();
175        testSubjectPublicKeyAlgID();
176        testKeyUsage();
177        testSubjectAltName();
178        testPolicy();
179        testPathToName();
180        testSubject();
181        testSubjectPublicKey();
182        testNameConstraints();
183        testBasicConstraints();
184        testCertificate();
185    }
186
187    // Tests matching on the serial number contained in the certificate.
188    private void testSerialNumber() {
189        System.out.println("X.509 Certificate Match on serialNumber");
190        // bad match
191        X509CertSelector selector = new X509CertSelector();
192        selector.setSerialNumber(new BigInteger("999999999"));
193        checkMatch(selector, cert, false);
194
195        // good match
196        selector.setSerialNumber(cert.getSerialNumber());
197        checkMatch(selector, cert, true);
198    }
199
200    // Tests matching on the issuer name contained in the certificate.
201    private void testIssuer() throws IOException {
202        System.out.println("X.509 Certificate Match on issuer");
203        // bad match
204        X509CertSelector selector = new X509CertSelector();
205        selector.setIssuer("ou=bogus,ou=east,o=sun,c=us");
206        checkMatch(selector, cert, false);
207
208        // good match
209        selector.setIssuer((cert.getIssuerX500Principal()).getName("RFC2253"));
210        checkMatch(selector, cert, true);
211    }
212
213    /*
214     * Tests matching on the subject key identifier contained in the
215     * certificate.
216     */
217    private void testSubjectKeyIdentifier() throws IOException {
218        System.out.println("X.509 Certificate Match on subjectKeyIdentifier");
219        // bad match
220        X509CertSelector selector = new X509CertSelector();
221        byte[] b = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
222        selector.setSubjectKeyIdentifier(b);
223        checkMatch(selector, cert, false);
224
225        // good match
226        DerInputStream in = new DerInputStream(cert.getExtensionValue("2.5.29.14"));
227        byte[] encoded = in.getOctetString();
228        selector.setSubjectKeyIdentifier(encoded);
229        checkMatch(selector, cert, true);
230    }
231
232    /*
233     * Tests matching on the authority key identifier contained in the
234     * certificate.
235     */
236    private void testAuthorityKeyIdentifier() throws IOException {
237        System.out.println("X.509 Certificate Match on authorityKeyIdentifier");
238        // bad match
239        X509CertSelector selector = new X509CertSelector();
240        byte[] b = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
241        AuthorityKeyIdentifierExtension a = new AuthorityKeyIdentifierExtension(new KeyIdentifier(b), null, null);
242        selector.setAuthorityKeyIdentifier(a.getExtensionValue());
243        checkMatch(selector, cert, false);
244
245        // good match
246        DerInputStream in = new DerInputStream(cert.getExtensionValue("2.5.29.35"));
247        byte[] encoded = in.getOctetString();
248        selector.setAuthorityKeyIdentifier(encoded);
249        checkMatch(selector, cert, true);
250    }
251
252    /*
253     * Tests matching on the certificate validity component contained in the
254     * certificate.
255     */
256    private void testCertificateValid() {
257        System.out.println("X.509 Certificate Match on certificateValid");
258        // bad match
259        X509CertSelector selector = new X509CertSelector();
260        Calendar cal = Calendar.getInstance();
261        cal.set(1968, 12, 31);
262        selector.setCertificateValid(cal.getTime());
263        checkMatch(selector, cert, false);
264
265        // good match
266        selector.setCertificateValid(cert.getNotBefore());
267        checkMatch(selector, cert, true);
268    }
269
270    /*
271     * Tests matching on the private key validity component contained in the
272     * certificate.
273     */
274    private void testPrivateKeyValid() throws IOException, CertificateException {
275        System.out.println("X.509 Certificate Match on privateKeyValid");
276        // bad match
277        X509CertSelector selector = new X509CertSelector();
278        Calendar cal = Calendar.getInstance();
279        cal.set(1968, 12, 31);
280        selector.setPrivateKeyValid(cal.getTime());
281        checkMatch(selector, cert, false);
282
283        // good match
284        DerInputStream in = new DerInputStream(cert.getExtensionValue("2.5.29.16"));
285        byte[] encoded = in.getOctetString();
286        PrivateKeyUsageExtension ext = new PrivateKeyUsageExtension(false, encoded);
287        Date validDate = (Date) ext.get(PrivateKeyUsageExtension.NOT_BEFORE);
288        selector.setPrivateKeyValid(validDate);
289        checkMatch(selector, cert, true);
290
291    }
292
293    private ObjectIdentifier getCertPubKeyAlgOID(X509Certificate xcert) throws IOException {
294        byte[] encodedKey = xcert.getPublicKey().getEncoded();
295        DerValue val = new DerValue(encodedKey);
296        if (val.tag != DerValue.tag_Sequence) {
297            throw new RuntimeException("invalid key format");
298        }
299
300        return AlgorithmId.parse(val.data.getDerValue()).getOID();
301    }
302
303    /*
304     * Tests matching on the subject public key algorithm ID component contained
305     * in the certificate.
306     */
307    private void testSubjectPublicKeyAlgID() throws IOException {
308        System.out.println("X.509 Certificate Match on subjectPublicKeyAlgID");
309        // bad match
310        X509CertSelector selector = new X509CertSelector();
311        selector.setSubjectPublicKeyAlgID("2.5.29.14");
312        checkMatch(selector, cert, false);
313
314        // good match
315        selector.setSubjectPublicKeyAlgID(getCertPubKeyAlgOID(cert).toString());
316        checkMatch(selector, cert, true);
317
318    }
319
320    // Tests matching on the key usage extension contained in the certificate.
321    private void testKeyUsage() {
322        System.out.println("X.509 Certificate Match on keyUsage");
323        // bad match
324        X509CertSelector selector = new X509CertSelector();
325        boolean[] keyUsage = { true, false, true, false, true, false, true, false };
326        selector.setKeyUsage(keyUsage);
327        System.out.println("Selector = " + selector.toString());
328        checkMatch(selector, cert, false);
329
330        // good match
331        selector.setKeyUsage(cert.getKeyUsage());
332        System.out.println("Selector = " + selector.toString());
333        checkMatch(selector, cert, true);
334    }
335
336    /*
337     * Tests matching on the subject alternative name extension contained in the
338     * certificate.
339     */
340    private void testSubjectAltName() throws IOException {
341        System.out.println("X.509 Certificate Match on subjectAltName");
342        // bad match
343        X509CertSelector selector = new X509CertSelector();
344        GeneralNameInterface dnsName = new DNSName("foo.com");
345        DerOutputStream tmp = new DerOutputStream();
346        dnsName.encode(tmp);
347        selector.addSubjectAlternativeName(2, tmp.toByteArray());
348        checkMatch(selector, cert, false);
349
350        // good match
351        DerInputStream in = new DerInputStream(cert.getExtensionValue("2.5.29.17"));
352        byte[] encoded = in.getOctetString();
353        SubjectAlternativeNameExtension ext = new SubjectAlternativeNameExtension(false, encoded);
354        GeneralNames names = (GeneralNames) ext.get(SubjectAlternativeNameExtension.SUBJECT_NAME);
355        GeneralName name = (GeneralName) names.get(0);
356        selector.setSubjectAlternativeNames(null);
357        DerOutputStream tmp2 = new DerOutputStream();
358        name.getName().encode(tmp2);
359        selector.addSubjectAlternativeName(name.getType(), tmp2.toByteArray());
360        checkMatch(selector, cert, true);
361
362        // good match 2 (matches at least one)
363        selector.setMatchAllSubjectAltNames(false);
364        selector.addSubjectAlternativeName(2, "foo.com");
365        checkMatch(selector, cert, true);
366    }
367
368    /*
369     * Tests matching on the policy constraints extension contained in the
370     * certificate.
371     */
372    private void testPolicy() throws IOException {
373        System.out.println("X.509 Certificate Match on certificatePolicies");
374        // test encoding of CertificatePoliciesExtension because we wrote the
375        // code
376        // bad match
377        X509CertSelector selector = new X509CertSelector();
378        Set<String> s = new HashSet<>();
379        s.add(new String("1.2.5.7.68"));
380        selector.setPolicy(s);
381        checkMatch(selector, cert, false);
382
383        // good match
384        DerInputStream in = new DerInputStream(cert.getExtensionValue("2.5.29.32"));
385        CertificatePoliciesExtension ext = new CertificatePoliciesExtension(false, in.getOctetString());
386        List<PolicyInformation> policies = ext.get(CertificatePoliciesExtension.POLICIES);
387        // match on the first policy id
388        PolicyInformation policyInfo = (PolicyInformation) policies.get(0);
389        s.clear();
390        s.add(policyInfo.getPolicyIdentifier().getIdentifier().toString());
391        selector.setPolicy(s);
392        checkMatch(selector, cert, true);
393    }
394
395    /*
396     * Tests matching on the name constraints extension contained in the
397     * certificate.
398     */
399    private void testPathToName() throws IOException {
400        System.out.println("X.509 Certificate Match on pathToName");
401
402        X509CertSelector selector = null;
403        DerInputStream in = new DerInputStream(cert.getExtensionValue("2.5.29.30"));
404        byte[] encoded = in.getOctetString();
405        NameConstraintsExtension ext = new NameConstraintsExtension(false, encoded);
406        GeneralSubtrees permitted = (GeneralSubtrees) ext.get(PERMITTED_SUBTREES);
407        GeneralSubtrees excluded = (GeneralSubtrees) ext.get(EXCLUDED_SUBTREES);
408
409        // bad matches on pathToName within excluded subtrees
410        if (excluded != null) {
411            Iterator<GeneralSubtree> e = excluded.iterator();
412            while (e.hasNext()) {
413                GeneralSubtree tree = e.next();
414                if (tree.getName().getType() == NAME_DIRECTORY) {
415                    X500Name excludedDN1 = new X500Name(tree.getName().toString());
416                    X500Name excludedDN2 = new X500Name("CN=Bogus, " + tree.getName().toString());
417                    DerOutputStream derDN1 = new DerOutputStream();
418                    DerOutputStream derDN2 = new DerOutputStream();
419                    excludedDN1.encode(derDN1);
420                    excludedDN2.encode(derDN2);
421                    selector = new X509CertSelector();
422                    selector.addPathToName(NAME_DIRECTORY, derDN1.toByteArray());
423                    checkMatch(selector, cert, false);
424                    selector.setPathToNames(null);
425                    selector.addPathToName(NAME_DIRECTORY, derDN2.toByteArray());
426                    checkMatch(selector, cert, false);
427                }
428            }
429        }
430
431        // good matches on pathToName within permitted subtrees
432        if (permitted != null) {
433            Iterator<GeneralSubtree> e = permitted.iterator();
434            while (e.hasNext()) {
435                GeneralSubtree tree = e.next();
436                if (tree.getName().getType() == NAME_DIRECTORY) {
437                    X500Name permittedDN1 = new X500Name(tree.getName().toString());
438                    X500Name permittedDN2 = new X500Name("CN=good, " + tree.getName().toString());
439                    DerOutputStream derDN1 = new DerOutputStream();
440                    DerOutputStream derDN2 = new DerOutputStream();
441                    permittedDN1.encode(derDN1);
442                    permittedDN2.encode(derDN2);
443                    selector = new X509CertSelector();
444                    selector.addPathToName(NAME_DIRECTORY, derDN1.toByteArray());
445                    checkMatch(selector, cert, true);
446                    selector.setPathToNames(null);
447                    selector.addPathToName(NAME_DIRECTORY, derDN2.toByteArray());
448                    checkMatch(selector, cert, true);
449                }
450            }
451        }
452    }
453
454    // Tests matching on the subject name contained in the certificate.
455    private void testSubject() throws IOException {
456        System.out.println("X.509 Certificate Match on subject");
457        // bad match
458        X509CertSelector selector = new X509CertSelector();
459        selector.setSubject("ou=bogus,ou=east,o=sun,c=us");
460        checkMatch(selector, cert, false);
461
462        // good match
463        selector.setSubject(cert.getSubjectX500Principal().getName("RFC2253"));
464        checkMatch(selector, cert, true);
465    }
466
467    // Tests matching on the subject public key contained in the certificate.
468    private void testSubjectPublicKey() throws IOException, GeneralSecurityException {
469        System.out.println("X.509 Certificate Match on subject public key");
470        // bad match
471        X509CertSelector selector = new X509CertSelector();
472        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(
473                Base64.getMimeDecoder().decode(testKey.getBytes()));
474        KeyFactory keyFactory = KeyFactory.getInstance("DSA");
475        PublicKey pubKey = keyFactory.generatePublic(keySpec);
476        selector.setSubjectPublicKey(pubKey);
477        checkMatch(selector, cert, false);
478
479        // good match
480        selector.setSubjectPublicKey(cert.getPublicKey());
481        checkMatch(selector, cert, true);
482    }
483
484    // Tests matching on the name constraints contained in the certificate.
485    private void testNameConstraints() throws IOException {
486        System.out.println("X.509 Certificate Match on name constraints");
487        // bad match
488        GeneralSubtrees subjectTree = new GeneralSubtrees();
489        subjectTree.add(getGeneralSubtree((X500Name) cert.getSubjectDN()));
490        NameConstraintsExtension ext = new NameConstraintsExtension((GeneralSubtrees) null, subjectTree);
491        X509CertSelector selector = new X509CertSelector();
492        selector.setNameConstraints(ext.getExtensionValue());
493        checkMatch(selector, cert, false);
494
495        // good match
496        ext = new NameConstraintsExtension(subjectTree, null);
497        selector.setNameConstraints(ext.getExtensionValue());
498        checkMatch(selector, cert, true);
499    }
500
501    // Tests matching on basic constraints.
502    private void testBasicConstraints() {
503        System.out.println("X.509 Certificate Match on basic constraints");
504        // bad match
505        X509CertSelector selector = new X509CertSelector();
506        int mpl = cert.getBasicConstraints();
507        selector.setBasicConstraints(0);
508        checkMatch(selector, cert, false);
509
510        // good match
511        selector.setBasicConstraints(mpl);
512        checkMatch(selector, cert, true);
513    }
514
515    // Tests certificateEquals criterion
516    private void testCertificate() {
517        System.out.println("X.509 Certificate Match on certificateEquals criterion");
518
519        X509CertSelector selector = new X509CertSelector();
520        // good match
521        selector.setCertificate(cert);
522        checkMatch(selector, cert, true);
523    }
524
525    private void checkMatch(X509CertSelector selector, X509Certificate cert, boolean match) {
526        boolean result = selector.match(cert);
527        if (match != result)
528            throw new RuntimeException(selector + " match " + cert + " is " + result + ", but expect " + match);
529    }
530
531    private static GeneralSubtree getGeneralSubtree(GeneralNameInterface gni) {
532        // Create a new GeneralSubtree with the specified name, 0 base, and
533        // unlimited length
534        GeneralName gn = new GeneralName(gni);
535        GeneralSubtree subTree = new GeneralSubtree(gn, 0, -1);
536        return subTree;
537    }
538}
539