1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package libcore.java.security.cert;
18
19import tests.support.resource.Support_Resources;
20
21import java.io.BufferedInputStream;
22import java.io.BufferedReader;
23import java.io.ByteArrayInputStream;
24import java.io.ByteArrayOutputStream;
25import java.io.DataInputStream;
26import java.io.IOException;
27import java.io.InputStream;
28import java.io.InputStreamReader;
29import java.io.ObjectInputStream;
30import java.io.ObjectOutputStream;
31import java.io.PrintStream;
32import java.math.BigInteger;
33import java.security.KeyFactory;
34import java.security.KeyPair;
35import java.security.KeyPairGenerator;
36import java.security.Principal;
37import java.security.Provider;
38import java.security.PublicKey;
39import java.security.Security;
40import java.security.SignatureException;
41import java.security.cert.Certificate;
42import java.security.cert.CertificateException;
43import java.security.cert.CertificateExpiredException;
44import java.security.cert.CertificateFactory;
45import java.security.cert.CertificateNotYetValidException;
46import java.security.cert.CertificateParsingException;
47import java.security.cert.X509Certificate;
48import java.security.spec.X509EncodedKeySpec;
49import java.text.SimpleDateFormat;
50import java.util.ArrayList;
51import java.util.Arrays;
52import java.util.Calendar;
53import java.util.Collection;
54import java.util.Date;
55import java.util.HashSet;
56import java.util.List;
57import java.util.Locale;
58import java.util.Set;
59
60import javax.security.auth.x500.X500Principal;
61
62import junit.framework.TestCase;
63import libcore.java.security.StandardNames;
64
65public class X509CertificateTest extends TestCase {
66    private Provider[] mX509Providers;
67
68    private static final String CERT_RSA = "x509/cert-rsa.der";
69
70    private static final String CERT_DSA = "x509/cert-dsa.der";
71
72    private static final String CERT_EC = "x509/cert-ec.der";
73
74    private static final String CERT_KEYUSAGE_EXTRALONG = "x509/cert-keyUsage-extraLong.der";
75
76    private static final String CERT_EXTENDEDKEYUSAGE = "x509/cert-extendedKeyUsage.der";
77
78    private final static String CERT_RSA_TBS = "x509/cert-rsa-tbs.der";
79
80    private final static String CERT_RSA_SIGNATURE = "x509/cert-rsa-sig.der";
81
82    private static final String CERT_USERWITHPATHLEN = "x509/cert-userWithPathLen.der";
83
84    private static final String CERT_CA = "x509/cert-ca.der";
85
86    private static final String CERT_CAWITHPATHLEN = "x509/cert-caWithPathLen.der";
87
88    private static final String CERT_INVALIDIP = "x509/cert-invalidip.der";
89
90    private static final String CERT_IPV6 = "x509/cert-ipv6.der";
91
92    private static final String CERT_ALT_OTHER = "x509/cert-alt-other.der";
93
94    private static final String CERT_ALT_EMAIL = "x509/cert-alt-email.der";
95
96    private static final String CERT_ALT_DNS = "x509/cert-alt-dns.der";
97
98    private static final String CERT_ALT_DIRNAME = "x509/cert-alt-dirname.der";
99
100    private static final String CERT_ALT_URI = "x509/cert-alt-uri.der";
101
102    private static final String CERT_ALT_RID = "x509/cert-alt-rid.der";
103
104    private static final String CERT_ALT_NONE = "x509/cert-alt-none.der";
105
106    private static final String CERT_UNSUPPORTED = "x509/cert-unsupported.der";
107
108    private static final String CERT_SIGOPT = "x509/cert-sigopt.der";
109
110    private static final String CERTS_X509_PEM = "x509/certs.pem";
111
112    private static final String CERTS_X509_DER = "x509/certs.der";
113
114    private static final String CERTS_PKCS7_PEM = "x509/certs-pk7.pem";
115
116    private static final String CERTS_PKCS7_DER = "x509/certs-pk7.der";
117
118    /** A list of certs that are all slightly different. */
119    private static final String[] VARIOUS_CERTS = new String[] {
120            CERT_RSA, CERT_DSA, CERT_EC,
121    };
122
123    private final X509Certificate getCertificate(CertificateFactory f, String name)
124            throws Exception {
125        final InputStream is = Support_Resources.getStream(name);
126        assertNotNull("File does not exist: " + name, is);
127        try {
128            return (X509Certificate) f.generateCertificate(is);
129        } finally {
130            try {
131                is.close();
132            } catch (IOException ignored) {
133            }
134        }
135    }
136
137    private final Collection<? extends X509Certificate> getCertificates(CertificateFactory f, String name)
138            throws Exception {
139        final InputStream is = Support_Resources.getStream(name);
140        assertNotNull("File does not exist: " + name, is);
141        try {
142            return (Collection<? extends X509Certificate>) f.generateCertificates(is);
143        } finally {
144            try {
145                is.close();
146            } catch (IOException ignored) {
147            }
148        }
149    }
150
151    private PublicKey getRsaCertificatePublicKey() throws Exception {
152        final InputStream ris = Support_Resources.getStream("x509/cert-rsa-pubkey.der");
153        try {
154            final int size = ris.available();
155            final DataInputStream is = new DataInputStream(ris);
156            final byte[] keyBytes = new byte[size];
157            is.readFully(keyBytes);
158
159            final KeyFactory kf = KeyFactory.getInstance("RSA");
160            return kf.generatePublic(new X509EncodedKeySpec(keyBytes));
161        } finally {
162            try {
163                ris.close();
164            } catch (IOException ignored) {
165            }
166        }
167    }
168
169    private Date[] getRsaCertificateDates() throws Exception {
170        final InputStream ris = Support_Resources.getStream("x509/cert-rsa-dates.txt");
171        try {
172            // notBefore=Dec 26 00:19:14 2012 GMT
173            final SimpleDateFormat sdf =
174                    new SimpleDateFormat("MMM dd HH:mm:ss yyyy zzz", Locale.US);
175
176            final BufferedReader buf = new BufferedReader(new InputStreamReader(ris));
177            String line = buf.readLine();
178            int index = line.indexOf('=');
179            assertEquals("notBefore", line.substring(0, index));
180            final Date startDate = sdf.parse(line.substring(index + 1));
181
182            line = buf.readLine();
183            index = line.indexOf('=');
184            assertEquals("notAfter", line.substring(0, index));
185            final Date endDate = sdf.parse(line.substring(index + 1));
186
187            assertTrue(startDate.before(endDate));
188            assertTrue(endDate.after(startDate));
189
190            return new Date[] { startDate, endDate };
191        } finally {
192            try {
193                ris.close();
194            } catch (IOException ignored) {
195            }
196        }
197    }
198
199    private BigInteger getRsaCertificateSerial() throws Exception {
200        final InputStream ris = Support_Resources.getStream("x509/cert-rsa-serial.txt");
201        try {
202            final BufferedReader buf = new BufferedReader(new InputStreamReader(ris));
203
204            String line = buf.readLine();
205            int index = line.indexOf('=');
206            assertEquals("serial", line.substring(0, index));
207
208            return new BigInteger(line.substring(index + 1), 16);
209        } finally {
210            try {
211                ris.close();
212            } catch (IOException ignored) {
213            }
214        }
215    }
216
217    private byte[] getResourceAsBytes(String name) throws Exception {
218        final InputStream ris = Support_Resources.getStream(name);
219        try {
220            DataInputStream dis = new DataInputStream(ris);
221            byte[] buf = new byte[ris.available()];
222            dis.readFully(buf);
223            return buf;
224        } finally {
225            try {
226                ris.close();
227            } catch (IOException ignored) {
228            }
229        }
230    }
231
232    private byte[] getRsaCertificateSignature() throws Exception {
233        return getResourceAsBytes(CERT_RSA_SIGNATURE);
234    }
235
236    private byte[] getRsaCertificateTbs() throws Exception {
237        return getResourceAsBytes(CERT_RSA_TBS);
238    }
239
240    public void test_Provider() throws Exception {
241        final ByteArrayOutputStream errBuffer = new ByteArrayOutputStream();
242        PrintStream out = new PrintStream(errBuffer);
243
244        for (Provider p : mX509Providers) {
245            try {
246                CertificateFactory f = CertificateFactory.getInstance("X.509", p);
247                getPublicKey(f);
248                getType(f);
249                check_equals(f);
250                check_toString(f);
251                check_hashCode(f);
252                checkValidity(f);
253                getVersion(f);
254                getSerialNumber(f);
255                getIssuerDN(f);
256                getIssuerX500Principal(f);
257                getSubjectDN(f);
258                getSubjectUniqueID(f);
259                getSubjectX500Principal(f);
260                getNotBeforeAndNotAfterDates(f);
261                getSigAlgName(f);
262                getSigAlgOID(f);
263                getSigAlgParams(f);
264                getIssuerUniqueID(f);
265                getSubjectUniqueID(f);
266                getKeyUsage(f);
267                getExtendedKeyUsage(f);
268                getBasicConstraints(f);
269                getSubjectAlternativeNames(f);
270                getSubjectAlternativeNames_IPV6(f);
271                getSubjectAlternativeNames_InvalidIP(f);
272                getSubjectAlternativeNames_Other(f);
273                getSubjectAlternativeNames_Email(f);
274                getSubjectAlternativeNames_DNS(f);
275                getSubjectAlternativeNames_DirName(f);
276                getSubjectAlternativeNames_URI(f);
277                getSubjectAlternativeNames_RID(f);
278                getSubjectAlternativeNames_None(f);
279                getIssuerAlternativeNames(f);
280                getTBSCertificate(f);
281                getSignature(f);
282                hasUnsupportedCriticalExtension(f);
283                getEncoded(f);
284                verify(f);
285                generateCertificate_PEM_TrailingData(f);
286                generateCertificate_DER_TrailingData(f);
287                generateCertificates_X509_PEM(f);
288                generateCertificates_X509_DER(f);
289                generateCertificates_PKCS7_PEM(f);
290                generateCertificates_PKCS7_DER(f);
291                generateCertificates_Empty(f);
292                generateCertificates_X509_PEM_TrailingData(f);
293                generateCertificates_X509_DER_TrailingData(f);
294                generateCertificates_PKCS7_PEM_TrailingData(f);
295                generateCertificates_PKCS7_DER_TrailingData(f);
296                test_Serialization(f);
297                test_UnknownUnmappedKeyOID(f);
298            } catch (Throwable e) {
299                out.append("Error encountered checking " + p.getName() + "\n");
300                e.printStackTrace(out);
301            }
302        }
303
304        out.flush();
305        if (errBuffer.size() > 0) {
306            throw new Exception("Errors encountered:\n\n" + errBuffer.toString() + "\n\n");
307        }
308    }
309
310    private void getPublicKey(CertificateFactory f) throws Exception {
311        X509Certificate c = getCertificate(f, CERT_RSA);
312        PublicKey expected = getRsaCertificatePublicKey();
313
314        PublicKey actual = c.getPublicKey();
315        assertEquals(expected, actual);
316        assertEquals(Arrays.toString(expected.getEncoded()),
317                     Arrays.toString(actual.getEncoded()));
318    }
319
320    private void getType(CertificateFactory f) throws Exception {
321        X509Certificate c = getCertificate(f, CERT_RSA);
322        assertEquals("X.509", c.getType());
323    }
324
325    private void verify(CertificateFactory f) throws Exception {
326        X509Certificate c = getCertificate(f, CERT_RSA);
327        PublicKey signer = getRsaCertificatePublicKey();
328
329        c.verify(signer);
330
331        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
332        KeyPair pair = kpg.generateKeyPair();
333        PublicKey invalidKey = pair.getPublic();
334
335        try {
336            c.verify(invalidKey);
337            fail("RSA signature should not verify");
338        } catch (SignatureException expected) {
339        }
340
341        Provider[] providers = Security.getProviders("Signature." + c.getSigAlgName());
342        for (Provider p : providers) {
343            // Do not test AndroidKeyStore Provider. It does not accept vanilla public keys for
344            // signature verification. It's OKish not to test here because it's tested by
345            // cts/tests/tests/keystore.
346            if (p.getName().startsWith("AndroidKeyStore")) {
347                continue;
348            }
349
350            c.verify(signer, p.getName());
351
352            try {
353                c.verify(invalidKey, p.getName());
354                fail("RSA signature should not verify");
355            } catch (SignatureException expected) {
356            }
357        }
358    }
359
360    private void check_equals(CertificateFactory f) throws Exception {
361        X509Certificate c1 = getCertificate(f, CERT_RSA);
362        X509Certificate c2 = getCertificate(f, CERT_RSA);
363
364        assertEquals(c1, c2);
365
366        X509Certificate c3 = getCertificate(f, CERT_DSA);
367        assertFalse(c1.equals(c3));
368        assertFalse(c3.equals(c1));
369    }
370
371    private void check_toString(CertificateFactory f) throws Exception {
372        X509Certificate c1 = getCertificate(f, CERT_RSA);
373
374        String output1 = c1.toString();
375        assertNotNull(output1);
376        assertTrue(output1.length() > 0);
377
378        X509Certificate c2 = getCertificate(f, CERT_RSA);
379        assertEquals(c1.toString(), c2.toString());
380
381        X509Certificate c3 = getCertificate(f, CERT_DSA);
382        assertFalse(c3.toString().equals(c1.toString()));
383    }
384
385    private void check_hashCode(CertificateFactory f) throws Exception {
386        X509Certificate c1 = getCertificate(f, CERT_RSA);
387        X509Certificate c2 = getCertificate(f, CERT_RSA);
388
389        assertEquals(c1.hashCode(), c2.hashCode());
390
391        X509Certificate c3 = getCertificate(f, CERT_DSA);
392        assertFalse(c3.hashCode() == c1.hashCode());
393    }
394
395    private void checkValidity(CertificateFactory f) throws Exception {
396        X509Certificate c = getCertificate(f, CERT_RSA);
397        Calendar cal = Calendar.getInstance();
398        Date[] dates = getRsaCertificateDates();
399
400        /*
401         * The certificate validity periods in the test certificate MUST lie
402         * within the tested period. The API doesn't appear to allow any other
403         * way to test this code path as an unprivileged user.
404         */
405        Date now = new Date();
406        assertTrue(now.after(dates[0]));
407        assertTrue(now.before(dates[1]));
408
409        /* This assumes the script makes a long-lived cert. */
410        c.checkValidity();
411
412        /* A day after the start date. */
413        cal.setTime(dates[0]);
414        cal.add(Calendar.DAY_OF_MONTH, 1);
415        c.checkValidity(cal.getTime());
416
417        /* A second before the start date. */
418        cal.setTime(dates[1]);
419        cal.add(Calendar.SECOND, -1);
420        c.checkValidity(cal.getTime());
421
422        try {
423            cal.setTime(dates[0]);
424            cal.add(Calendar.SECOND, -1);
425            c.checkValidity(cal.getTime());
426            fail();
427        } catch (CertificateNotYetValidException expected) {
428        }
429
430        try {
431            cal.setTime(dates[0]);
432            cal.add(Calendar.MONTH, -6);
433            c.checkValidity(cal.getTime());
434            fail();
435        } catch (CertificateNotYetValidException expected) {
436        }
437
438        try {
439            cal.setTime(dates[1]);
440            cal.add(Calendar.SECOND, 1);
441            c.checkValidity(cal.getTime());
442            fail();
443        } catch (CertificateExpiredException expected) {
444        }
445
446        try {
447            cal.setTime(dates[1]);
448            cal.add(Calendar.YEAR, 1);
449            c.checkValidity(cal.getTime());
450            fail();
451        } catch (CertificateExpiredException expected) {
452        }
453    }
454
455    private void getVersion(CertificateFactory f) throws Exception {
456        X509Certificate c = getCertificate(f, CERT_RSA);
457        assertEquals(3, c.getVersion());
458    }
459
460    private void getSerialNumber(CertificateFactory f) throws Exception {
461        X509Certificate c = getCertificate(f, CERT_RSA);
462        BigInteger actual = getRsaCertificateSerial();
463
464        assertEquals(actual, c.getSerialNumber());
465    }
466
467    private void getIssuerDN(CertificateFactory f) throws Exception {
468        X509Certificate c = getCertificate(f, CERT_RSA);
469
470        Principal princ = c.getIssuerDN();
471        if (StandardNames.IS_RI) {
472            assertEquals("OU=NetOps, O=Genius.com Inc, L=San Mateo, ST=California, C=US",
473                         princ.getName());
474        } else {
475            if ("BC".equals(f.getProvider().getName())) {
476                // TODO: is it acceptable to have this in reverse order?
477                assertEquals(f.getProvider().getName(),
478                             "C=US,ST=California,L=San Mateo,O=Genius.com Inc,OU=NetOps",
479                             princ.getName());
480            } else {
481                assertEquals("OU=NetOps,O=Genius.com Inc,L=San Mateo,ST=California,C=US",
482                             princ.getName());
483            }
484        }
485
486        X509Certificate c2 = getCertificate(f, CERT_RSA);
487        assertEquals(princ, c2.getIssuerDN());
488    }
489
490    private void getIssuerX500Principal(CertificateFactory f) throws Exception {
491        X509Certificate c = getCertificate(f, CERT_RSA);
492
493        final byte[] expected = new byte[] {
494                0x30, 0x60, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
495                0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08,
496                0x13, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61,
497                0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x09, 0x53,
498                0x61, 0x6e, 0x20, 0x4d, 0x61, 0x74, 0x65, 0x6f, 0x31, 0x17, 0x30, 0x15,
499                0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x47, 0x65, 0x6e, 0x69, 0x75,
500                0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x0f, 0x30,
501                0x0d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x06, 0x4e, 0x65, 0x74, 0x4f,
502                0x70, 0x73
503        };
504        X500Principal princ = c.getIssuerX500Principal();
505        assertEquals(Arrays.toString(expected),
506                     Arrays.toString(princ.getEncoded()));
507        assertEquals("OU=NetOps,O=Genius.com Inc,L=San Mateo,ST=California,C=US",
508                     princ.getName());
509        assertEquals("ou=netops,o=genius.com inc,l=san mateo,st=california,c=us",
510                     princ.getName(X500Principal.CANONICAL));
511        assertEquals("OU=NetOps, O=Genius.com Inc, L=San Mateo, ST=California, C=US",
512                     princ.getName(X500Principal.RFC1779));
513        assertEquals("OU=NetOps,O=Genius.com Inc,L=San Mateo,ST=California,C=US",
514                     princ.getName(X500Principal.RFC2253));
515
516        X509Certificate c2 = getCertificate(f, CERT_RSA);
517        assertEquals(princ, c2.getIssuerX500Principal());
518    }
519
520    private void getSubjectDN(CertificateFactory f) throws Exception {
521        X509Certificate c = getCertificate(f, CERT_RSA);
522
523        Principal princ = c.getSubjectDN();
524        if (StandardNames.IS_RI) {
525            assertEquals("OU=NetOps, O=Genius.com Inc, L=San Mateo, ST=California, C=US",
526                         princ.getName());
527        } else {
528            if ("BC".equals(f.getProvider().getName())) {
529                // TODO: is it acceptable to have this in reverse order?
530                assertEquals(f.getProvider().getName(),
531                             "C=US,ST=California,L=San Mateo,O=Genius.com Inc,OU=NetOps",
532                             princ.getName());
533            } else {
534                assertEquals("OU=NetOps,O=Genius.com Inc,L=San Mateo,ST=California,C=US",
535                             princ.getName());
536            }
537        }
538
539        X509Certificate c2 = getCertificate(f, CERT_RSA);
540        assertEquals(princ, c2.getSubjectDN());
541    }
542
543    private void getSubjectUniqueID(CertificateFactory f) throws Exception {
544        /* This certificate has no unique ID. */
545        X509Certificate c = getCertificate(f, CERT_RSA);
546        assertNull(c.getSubjectUniqueID());
547
548        // TODO: generate certificate that has a SubjectUniqueID field.
549    }
550
551    private void getIssuerUniqueID(CertificateFactory f) throws Exception {
552        /* This certificate has no unique ID. */
553        X509Certificate c = getCertificate(f, CERT_RSA);
554        assertNull(c.getIssuerUniqueID());
555
556        // TODO: generate certificate that has a IssuerUniqueID field.
557    }
558
559    private void getSubjectX500Principal(CertificateFactory f) throws Exception {
560        X509Certificate c = getCertificate(f, CERT_RSA);
561
562        final byte[] expected = new byte[] {
563                0x30, 0x60, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
564                0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08,
565                0x13, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61,
566                0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x09, 0x53,
567                0x61, 0x6e, 0x20, 0x4d, 0x61, 0x74, 0x65, 0x6f, 0x31, 0x17, 0x30, 0x15,
568                0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x47, 0x65, 0x6e, 0x69, 0x75,
569                0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x0f, 0x30,
570                0x0d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x06, 0x4e, 0x65, 0x74, 0x4f,
571                0x70, 0x73
572        };
573        X500Principal princ = c.getSubjectX500Principal();
574        assertEquals(Arrays.toString(expected),
575                     Arrays.toString(princ.getEncoded()));
576        assertEquals("OU=NetOps,O=Genius.com Inc,L=San Mateo,ST=California,C=US",
577                     princ.getName());
578        assertEquals("ou=netops,o=genius.com inc,l=san mateo,st=california,c=us",
579                     princ.getName(X500Principal.CANONICAL));
580        assertEquals("OU=NetOps, O=Genius.com Inc, L=San Mateo, ST=California, C=US",
581                     princ.getName(X500Principal.RFC1779));
582        assertEquals("OU=NetOps,O=Genius.com Inc,L=San Mateo,ST=California,C=US",
583                     princ.getName(X500Principal.RFC2253));
584
585        X509Certificate c2 = getCertificate(f, CERT_RSA);
586        assertEquals(princ, c2.getSubjectX500Principal());
587    }
588
589    private static void assertDateEquals(Date date1, Date date2) throws Exception {
590        SimpleDateFormat formatter = new SimpleDateFormat("dd MMM yyyy HH:mm:ss");
591
592        String result1 = formatter.format(date1);
593        String result2 = formatter.format(date2);
594
595        assertEquals(result1, result2);
596    }
597
598    private void getNotBeforeAndNotAfterDates(CertificateFactory f) throws Exception {
599        X509Certificate c = getCertificate(f, CERT_RSA);
600        Date[] dates = getRsaCertificateDates();
601
602        assertDateEquals(dates[0], c.getNotBefore());
603        assertDateEquals(dates[1], c.getNotAfter());
604    }
605
606    private void getSigAlgName(CertificateFactory f) throws Exception {
607        {
608            /* The test certificate is sha1WithRSAEncryption */
609            X509Certificate c = getCertificate(f, CERT_RSA);
610            assertEquals("SHA1WITHRSA", c.getSigAlgName().toUpperCase(Locale.US));
611        }
612
613        {
614            /* The test certificate is sha1WithRSAEncryption */
615            X509Certificate c = getCertificate(f, CERT_DSA);
616            assertEquals("SHA1WITHDSA", c.getSigAlgName().toUpperCase(Locale.US));
617        }
618
619        {
620            /* The test certificate is sha1WithRSAEncryption */
621            X509Certificate c = getCertificate(f, CERT_EC);
622            assertEquals("SHA1WITHECDSA", c.getSigAlgName().toUpperCase(Locale.US));
623        }
624    }
625
626    private void getSigAlgOID(CertificateFactory f) throws Exception {
627        {
628            /* The test certificate is sha1WithRSAEncryption */
629            X509Certificate c = getCertificate(f, CERT_RSA);
630            assertEquals("1.2.840.113549.1.1.5", c.getSigAlgOID());
631        }
632
633        {
634            /* The test certificate is sha1WithRSAEncryption */
635            X509Certificate c = getCertificate(f, CERT_DSA);
636            assertEquals("1.2.840.10040.4.3", c.getSigAlgOID());
637        }
638
639        {
640            /* The test certificate is sha1WithRSAEncryption */
641            X509Certificate c = getCertificate(f, CERT_EC);
642            assertEquals("1.2.840.10045.4.1", c.getSigAlgOID());
643        }
644    }
645
646    private void getSigAlgParams(CertificateFactory f) throws Exception {
647        {
648            X509Certificate c = getCertificate(f, CERT_RSA);
649            // RI appears to disagree
650            if (StandardNames.IS_RI) {
651                assertNull(f.getProvider().getName(), c.getSigAlgParams());
652            } else {
653                assertNotNull(f.getProvider().getName(), c.getSigAlgParams());
654            }
655        }
656
657        {
658            X509Certificate c = getCertificate(f, CERT_DSA);
659            assertNull(f.getProvider().getName(), c.getSigAlgParams());
660        }
661
662        {
663            X509Certificate c = getCertificate(f, CERT_EC);
664            assertNull(f.getProvider().getName(), c.getSigAlgParams());
665        }
666
667        {
668            X509Certificate c = getCertificate(f, CERT_SIGOPT);
669
670            /* SEQUENCE, INTEGER 1 */
671            final byte[] expected = new byte[] {
672                    /* SEQUENCE, constructed, len=5 */
673                    (byte) 0x30, (byte) 0x05,
674                    /* Type=2, constructed, context-specific, len=3 */
675                    (byte) 0xA2, (byte) 0x03,
676                    /* INTEGER, len=1, value=1 */
677                    (byte) 0x02, (byte) 0x01, (byte) 0x01,
678            };
679
680            final byte[] params = c.getSigAlgParams();
681            assertNotNull(f.getProvider().getName(), params);
682            assertEquals(Arrays.toString(expected), Arrays.toString(params));
683        }
684    }
685
686    private void getKeyUsage(CertificateFactory f) throws Exception {
687        {
688            /* The test certificate is sha1WithRSAEncryption */
689            X509Certificate c = getCertificate(f, CERT_RSA);
690            boolean[] expected = new boolean[] {
691                    true,  /* digitalSignature (0) */
692                    true,  /* nonRepudiation   (1) */
693                    true,  /* keyEncipherment  (2) */
694                    false, /* dataEncipherment (3) */
695                    false, /* keyAgreement     (4) */
696                    false, /* keyCertSign      (5) */
697                    false, /* cRLSign          (6) */
698                    false, /* encipherOnly     (7) */
699                    false, /* decipherOnly     (8) */
700            };
701            assertEquals(Arrays.toString(expected), Arrays.toString(c.getKeyUsage()));
702        }
703
704        {
705            /* The test certificate is sha1WithRSAEncryption */
706            X509Certificate c = getCertificate(f, CERT_DSA);
707            boolean[] expected = new boolean[] {
708                    false, /* digitalSignature (0) */
709                    false, /* nonRepudiation   (1) */
710                    true,  /* keyEncipherment  (2) */
711                    true,  /* dataEncipherment (3) */
712                    false, /* keyAgreement     (4) */
713                    true,  /* keyCertSign      (5) */
714                    true,  /* cRLSign          (6) */
715                    true,  /* encipherOnly     (7) */
716                    false, /* decipherOnly     (8) */
717            };
718            boolean[] actual = c.getKeyUsage();
719            assertEquals(9, actual.length);
720            assertEquals(Arrays.toString(expected), Arrays.toString(actual));
721        }
722
723        {
724            /* The test certificate is sha1WithRSAEncryption */
725            X509Certificate c = getCertificate(f, CERT_EC);
726            boolean[] expected = new boolean[] {
727                    false, /* digitalSignature (0) */
728                    false, /* nonRepudiation   (1) */
729                    false, /* keyEncipherment  (2) */
730                    false, /* dataEncipherment (3) */
731                    true,  /* keyAgreement     (4) */
732                    false, /* keyCertSign      (5) */
733                    false, /* cRLSign          (6) */
734                    false, /* encipherOnly     (7) */
735                    true,  /* decipherOnly     (8) */
736            };
737            boolean[] actual = c.getKeyUsage();
738            assertEquals(9, actual.length);
739            assertEquals(Arrays.toString(expected), Arrays.toString(actual));
740        }
741
742        {
743            /* All the bits are set in addition to some extra ones. */
744            X509Certificate c = getCertificate(f, CERT_KEYUSAGE_EXTRALONG);
745            boolean[] expected = new boolean[] {
746                    true,  /* digitalSignature (0) */
747                    true,  /* nonRepudiation   (1) */
748                    true,  /* keyEncipherment  (2) */
749                    true,  /* dataEncipherment (3) */
750                    true,  /* keyAgreement     (4) */
751                    true,  /* keyCertSign      (5) */
752                    true,  /* cRLSign          (6) */
753                    true,  /* encipherOnly     (7) */
754                    true,  /* decipherOnly     (8) */
755                    true,  /* ?????            (9) */
756                    true,  /* ?????           (10) */
757            };
758            boolean[] actual = c.getKeyUsage();
759            assertEquals(11, actual.length);
760            assertEquals(Arrays.toString(expected), Arrays.toString(actual));
761        }
762    }
763
764    private void getExtendedKeyUsage(CertificateFactory f) throws Exception {
765        {
766            /* No ExtendedKeyUsage section */
767            final X509Certificate c = getCertificate(f, CERT_RSA);
768            List<String> actual = c.getExtendedKeyUsage();
769            assertNull(actual);
770        }
771
772        {
773            /* ExtendedKeyUsage section with one entry of OID 1.2.3.4 */
774            final X509Certificate c = getCertificate(f, CERT_EXTENDEDKEYUSAGE);
775            List<String> actual = c.getExtendedKeyUsage();
776            assertNotNull(actual);
777            assertEquals(1, actual.size());
778            assertEquals("1.2.3.4", actual.get(0));
779        }
780    }
781
782    private void getBasicConstraints(CertificateFactory f) throws Exception {
783        /* Non-CA cert with no pathLenConstraint */
784        {
785            final X509Certificate c = getCertificate(f, CERT_RSA);
786            assertEquals(f.getProvider().getName(), -1, c.getBasicConstraints());
787        }
788
789        /* Non-CA cert with pathLenConstraint */
790        {
791            final X509Certificate c = getCertificate(f, CERT_USERWITHPATHLEN);
792            assertEquals(f.getProvider().getName(), -1, c.getBasicConstraints());
793        }
794
795        /* CA cert with no pathLenConstraint */
796        {
797            final X509Certificate c = getCertificate(f, CERT_CA);
798            assertEquals(f.getProvider().getName(), Integer.MAX_VALUE, c.getBasicConstraints());
799        }
800
801        /* CA cert with pathLenConstraint=10 */
802        {
803            final X509Certificate c = getCertificate(f, CERT_CAWITHPATHLEN);
804            assertEquals(f.getProvider().getName(), 10, c.getBasicConstraints());
805        }
806    }
807
808    /** Encoding of:  OID:1.2.3.4, UTF8:test1 */
809    private static byte[] getOIDTestBytes() {
810        if (StandardNames.IS_RI) {
811            return new byte[] { 0x30, 0x10, 0x06, 0x03, 0x2a, 0x03, 0x04, (byte) 0xa0,
812                    0x09, (byte) 0xa0, 0x07, 0x0c, 0x05, 0x74, 0x65, 0x73, 0x74, 0x31 };
813        } else {
814            return new byte[] { (byte) 0xa0, 0x0e, 0x06, 0x03, 0x2a, 0x03, 0x04,
815                    (byte) 0xa0, 0x07, 0x0c, 0x05, 0x74, 0x65, 0x73, 0x74, 0x31 };
816        }
817    }
818
819    private void getSubjectAlternativeNames(CertificateFactory f) throws Exception {
820        X509Certificate c = getCertificate(f, CERT_RSA);
821        Collection<List<?>> col = c.getSubjectAlternativeNames();
822
823        checkAlternativeNames(f, col);
824    }
825
826    private void checkAlternativeNames(CertificateFactory f, Collection<List<?>> col) throws Exception {
827        assertNotNull(col);
828
829        /* Check to see that the Collection is unmodifiable. */
830        {
831            try {
832                col.add(new ArrayList<Object>());
833                fail("should be an unmodifiable list");
834            } catch (UnsupportedOperationException expected) {
835            }
836        }
837
838        /*
839         * There should be 9 types of alternative names in this test
840         * certificate.
841         */
842        boolean[] typesFound = new boolean[9];
843
844        for (List<?> item : col) {
845            /* Check to see that the List is unmodifiable. */
846            {
847                try {
848                    item.remove(0);
849                    fail("should be an unmodifiable list");
850                } catch (UnsupportedOperationException expected) {
851                }
852            }
853
854            assertTrue(item.get(0) instanceof Integer);
855            int type = (Integer) item.get(0);
856            typesFound[type] = true;
857
858            switch (type) {
859            case 0: /* OtherName */
860                final byte[] der = getOIDTestBytes();
861                assertEquals(Arrays.toString(der), Arrays.toString((byte[]) item.get(1)));
862                break;
863            case 1: /* rfc822Name: IA5String */
864                assertEquals("x509@example.com", (String) item.get(1));
865                break;
866            case 2: /* dNSName: IA5String */
867                assertEquals("x509.example.com", (String) item.get(1));
868                break;
869            case 3: /* x400Address: ORAddress */
870                assertEquals("UNSUPPORTED", (String) item.get(1));
871                break;
872            case 4: /* directoryName: Name */
873                if ("BC".equals(f.getProvider().getName())) {
874                    // Bouncycastle doesn't parse T61String as UTF-8 like the RI, libcore, or OpenSSL.
875                    byte[] bytes = "CN=∆ƒ,OU=Über Frîends,O=Awesome Dudes,C=US".getBytes("UTF-8");
876                    String string = new String(bytes, 0);
877                    assertEquals(string, (String) item.get(1));
878                } else {
879                    assertEquals("CN=∆ƒ,OU=Über Frîends,O=Awesome Dudes,C=US", (String) item.get(1));
880                }
881                break;
882            case 5: /* ediPartyName */
883                assertEquals("UNSUPPORTED", Arrays.toString((byte[]) item.get(1)));
884                break;
885            case 6: /* uniformResourceIdentifier: IA5String */
886                assertEquals("http://www.example.com/?q=awesomeness", (String) item.get(1));
887                break;
888            case 7: /* iPAddress */
889                assertEquals("192.168.0.1", (String) item.get(1));
890                break;
891            case 8:
892                assertEquals("1.2.3.4", (String) item.get(1));
893                break;
894            }
895        }
896
897        Set<Integer> missing = new HashSet<Integer>();
898        for (int i = 0; i < typesFound.length; i++) {
899            if (!typesFound[i]) {
900                missing.add(i);
901            }
902        }
903
904        // TODO: fix X.400 names and ediPartyName
905        missing.remove(3);
906        missing.remove(5);
907
908        if (!missing.isEmpty()) {
909            fail("Missing types: " + Arrays.toString(missing.toArray(new Integer[missing.size()])));
910        }
911    }
912
913    private void getSubjectAlternativeNames_IPV6(CertificateFactory f) throws Exception {
914        X509Certificate c = getCertificate(f, CERT_IPV6);
915        Collection<List<?>> col = c.getSubjectAlternativeNames();
916
917        assertNotNull(f.getProvider().getName(), col);
918
919        assertEquals(1, col.size());
920        List<?> item = col.iterator().next();
921
922        assertTrue(item.get(0) instanceof Integer);
923        assertTrue(7 == (Integer) item.get(0));
924
925        assertTrue(item.get(1) instanceof String);
926        // RI doesn't apply all the IPv6 shortening rules
927        if (StandardNames.IS_RI) {
928            assertEquals("2001:db8:0:0:0:ff00:42:8329", (String) item.get(1));
929        } else {
930            assertEquals("2001:db8::ff00:42:8329", (String) item.get(1));
931        }
932    }
933
934    private void getSubjectAlternativeNames_InvalidIP(CertificateFactory f) throws Exception {
935        X509Certificate c = getCertificate(f, CERT_INVALIDIP);
936        Collection<List<?>> col = c.getSubjectAlternativeNames();
937        assertNull(col);
938    }
939
940    private void getSubjectAlternativeNames_Other(CertificateFactory f) throws Exception {
941        X509Certificate c = getCertificate(f, CERT_ALT_OTHER);
942        Collection<List<?>> col = c.getSubjectAlternativeNames();
943
944        assertNotNull(f.getProvider().getName(), col);
945
946        assertEquals(1, col.size());
947        List<?> item = col.iterator().next();
948
949        assertTrue(item.get(0) instanceof Integer);
950        assertTrue(0 == (Integer) item.get(0));
951
952        /* OID:1.2.3.4, UTF8:test1 */
953        final byte[] der = getOIDTestBytes();
954        final byte[] actual = (byte[]) item.get(1);
955        assertEquals(Arrays.toString(der), Arrays.toString(actual));
956
957        /* Make sure the byte[] array isn't modified by our test. */
958        {
959            actual[0] ^= (byte) 0xFF;
960            byte[] actual2 = (byte[]) c.getSubjectAlternativeNames().iterator().next().get(1);
961
962            if (!StandardNames.IS_RI) {
963                assertEquals(Arrays.toString(der), Arrays.toString(actual2));
964            } else {
965                /* RI is broken here. */
966                assertEquals(Arrays.toString(actual), Arrays.toString(actual2));
967            }
968        }
969    }
970
971    private void getSubjectAlternativeNames_Email(CertificateFactory f) throws Exception {
972        X509Certificate c = getCertificate(f, CERT_ALT_EMAIL);
973        Collection<List<?>> col = c.getSubjectAlternativeNames();
974
975        assertNotNull(f.getProvider().getName(), col);
976
977        assertEquals(1, col.size());
978        List<?> item = col.iterator().next();
979
980        assertTrue(item.get(0) instanceof Integer);
981        assertTrue(1 == (Integer) item.get(0));
982
983        assertTrue(item.get(1) instanceof String);
984        assertEquals("x509@example.com", (String) item.get(1));
985    }
986
987    private void getSubjectAlternativeNames_DNS(CertificateFactory f) throws Exception {
988        X509Certificate c = getCertificate(f, CERT_ALT_DNS);
989        Collection<List<?>> col = c.getSubjectAlternativeNames();
990
991        assertNotNull(f.getProvider().getName(), col);
992
993        assertEquals(1, col.size());
994        List<?> item = col.iterator().next();
995
996        assertTrue(item.get(0) instanceof Integer);
997        assertTrue(2 == (Integer) item.get(0));
998
999        assertTrue(item.get(1) instanceof String);
1000        assertEquals("x509.example.com", (String) item.get(1));
1001    }
1002
1003    private void getSubjectAlternativeNames_DirName(CertificateFactory f) throws Exception {
1004        X509Certificate c = getCertificate(f, CERT_ALT_DIRNAME);
1005        Collection<List<?>> col = c.getSubjectAlternativeNames();
1006
1007        assertNotNull(f.getProvider().getName(), col);
1008
1009        assertEquals(1, col.size());
1010        List<?> item = col.iterator().next();
1011
1012        assertTrue(item.get(0) instanceof Integer);
1013        assertTrue(String.valueOf((Integer) item.get(0)), 4 == (Integer) item.get(0));
1014
1015        assertTrue(item.get(1) instanceof String);
1016        if ("BC".equals(f.getProvider().getName())) {
1017            // Bouncycastle doesn't parse T61String as UTF-8 like the RI, libcore, or OpenSSL.
1018            byte[] bytes = "CN=∆ƒ,OU=Über Frîends,O=Awesome Dudes,C=US".getBytes("UTF-8");
1019            String string = new String(bytes, 0);
1020            assertEquals(string, (String) item.get(1));
1021        } else {
1022            assertEquals("CN=∆ƒ,OU=Über Frîends,O=Awesome Dudes,C=US", (String) item.get(1));
1023        }
1024    }
1025
1026    private void getSubjectAlternativeNames_URI(CertificateFactory f) throws Exception {
1027        X509Certificate c = getCertificate(f, CERT_ALT_URI);
1028        Collection<List<?>> col = c.getSubjectAlternativeNames();
1029
1030        assertNotNull(f.getProvider().getName(), col);
1031
1032        assertEquals(1, col.size());
1033        List<?> item = col.iterator().next();
1034
1035        assertTrue(item.get(0) instanceof Integer);
1036        assertTrue(6 == (Integer) item.get(0));
1037
1038        assertTrue(item.get(1) instanceof String);
1039        assertEquals("http://www.example.com/?q=awesomeness", (String) item.get(1));
1040    }
1041
1042    private void getSubjectAlternativeNames_RID(CertificateFactory f) throws Exception {
1043        X509Certificate c = getCertificate(f, CERT_ALT_RID);
1044        Collection<List<?>> col = c.getSubjectAlternativeNames();
1045
1046        assertNotNull(f.getProvider().getName(), col);
1047
1048        assertEquals(1, col.size());
1049        List<?> item = col.iterator().next();
1050
1051        assertTrue(item.get(0) instanceof Integer);
1052        assertTrue(8 == (Integer) item.get(0));
1053
1054        assertTrue(item.get(1) instanceof String);
1055        assertEquals("1.2.3.4", (String) item.get(1));
1056    }
1057
1058    private void getSubjectAlternativeNames_None(CertificateFactory f) throws Exception {
1059        X509Certificate c = getCertificate(f, CERT_ALT_NONE);
1060        Collection<List<?>> col = c.getSubjectAlternativeNames();
1061        assertNull(col);
1062    }
1063
1064    private void getIssuerAlternativeNames(CertificateFactory f) throws Exception {
1065        X509Certificate c = getCertificate(f, CERT_RSA);
1066        Collection<List<?>> col = c.getIssuerAlternativeNames();
1067
1068        checkAlternativeNames(f, col);
1069    }
1070
1071    private void getSignature(CertificateFactory f) throws Exception {
1072        X509Certificate c = getCertificate(f, CERT_RSA);
1073
1074        assertEquals(Arrays.toString(getRsaCertificateSignature()),
1075                     Arrays.toString(c.getSignature()));
1076    }
1077
1078    private void getTBSCertificate(CertificateFactory f) throws Exception {
1079        X509Certificate c = getCertificate(f, CERT_RSA);
1080
1081        assertEquals(Arrays.toString(getRsaCertificateTbs()),
1082                     Arrays.toString(c.getTBSCertificate()));
1083    }
1084
1085    private void hasUnsupportedCriticalExtension(CertificateFactory f) throws Exception {
1086        X509Certificate c = getCertificate(f, CERT_RSA);
1087        assertFalse(c.hasUnsupportedCriticalExtension());
1088
1089        X509Certificate unsupported = getCertificate(f, CERT_UNSUPPORTED);
1090        assertTrue(unsupported.hasUnsupportedCriticalExtension());
1091    }
1092
1093    private void getEncoded(CertificateFactory f) throws Exception {
1094        X509Certificate c = getCertificate(f, CERT_RSA);
1095
1096        byte[] cBytes = getResourceAsBytes(CERT_RSA);
1097
1098        assertEquals(Arrays.toString(cBytes), Arrays.toString(c.getEncoded()));
1099    }
1100
1101    private void generateCertificate_PEM_TrailingData(CertificateFactory f) throws Exception {
1102        byte[] certsBytes = getResourceAsBytes(CERTS_X509_PEM);
1103        byte[] certsTwice = new byte[certsBytes.length * 2];
1104        System.arraycopy(certsBytes, 0, certsTwice, 0, certsBytes.length);
1105        System.arraycopy(certsBytes, 0, certsTwice, certsBytes.length, certsBytes.length);
1106        ByteArrayInputStream bais = new ByteArrayInputStream(certsTwice);
1107
1108        assertEquals(certsBytes.length * 2, bais.available());
1109        X509Certificate cert1 = (X509Certificate) f.generateCertificate(bais);
1110        // TODO: If we had a single PEM certificate, we could know exact bytes.
1111        assertTrue(certsBytes.length < bais.available());
1112    }
1113
1114    private void generateCertificate_DER_TrailingData(CertificateFactory f) throws Exception {
1115        byte[] cert1Bytes = getResourceAsBytes(CERT_RSA);
1116        byte[] cert1WithTrailing = new byte[cert1Bytes.length * 2];
1117        System.arraycopy(cert1Bytes, 0, cert1WithTrailing, 0, cert1Bytes.length);
1118        System.arraycopy(cert1Bytes, 0, cert1WithTrailing, cert1Bytes.length, cert1Bytes.length);
1119        ByteArrayInputStream bais = new ByteArrayInputStream(cert1WithTrailing);
1120
1121        assertEquals(cert1Bytes.length * 2, bais.available());
1122        X509Certificate cert1 = (X509Certificate) f.generateCertificate(bais);
1123        assertEquals(cert1Bytes.length, bais.available());
1124    }
1125
1126    private void generateCertificates_X509_DER(CertificateFactory f) throws Exception {
1127        /* DER-encoded list of certificates */
1128        Collection<? extends X509Certificate> certs = getCertificates(f, CERTS_X509_DER);
1129        assertNotNull(certs);
1130        assertEquals(2, certs.size());
1131    }
1132
1133    private void generateCertificates_X509_PEM(CertificateFactory f) throws Exception {
1134        /* PEM-encoded list of certificates */
1135        Collection<? extends X509Certificate> certs = getCertificates(f, CERTS_X509_PEM);
1136        assertNotNull(certs);
1137        assertEquals(2, certs.size());
1138    }
1139
1140    private void generateCertificates_PKCS7_PEM(CertificateFactory f) throws Exception {
1141        /* PEM-encoded PKCS7 bag of certificates */
1142        Collection<? extends X509Certificate> certs = getCertificates(f, CERTS_PKCS7_PEM);
1143        assertNotNull(certs);
1144        if ("BC".equals(f.getProvider().getName())) {
1145            // Bouncycastle is broken
1146            assertEquals(0, certs.size());
1147        } else {
1148            assertEquals(2, certs.size());
1149        }
1150    }
1151
1152    private void generateCertificates_PKCS7_DER(CertificateFactory f) throws Exception {
1153        /* DER-encoded PKCS7 bag of certificates */
1154        Collection<? extends X509Certificate> certs = getCertificates(f, CERTS_PKCS7_DER);
1155        assertNotNull(certs);
1156        assertEquals(2, certs.size());
1157    }
1158
1159    private void generateCertificates_Empty(CertificateFactory f) throws Exception {
1160        final InputStream is = new ByteArrayInputStream(new byte[0]);
1161
1162        final Collection<? extends Certificate> certs = f.generateCertificates(is);
1163
1164        assertNotNull(certs);
1165        assertEquals(0, certs.size());
1166    }
1167
1168    private void generateCertificates_X509_PEM_TrailingData(CertificateFactory f) throws Exception {
1169        byte[] certBytes = getResourceAsBytes(CERTS_X509_PEM);
1170        byte[] certsPlusExtra = new byte[certBytes.length + 4096];
1171        System.arraycopy(certBytes, 0, certsPlusExtra, 0, certBytes.length);
1172        ByteArrayInputStream bais = new ByteArrayInputStream(certsPlusExtra);
1173
1174        assertEquals(certsPlusExtra.length, bais.available());
1175
1176        // RI is broken
1177        try {
1178            Collection<? extends X509Certificate> certs = (Collection<? extends X509Certificate>)
1179                    f.generateCertificates(bais);
1180            if (StandardNames.IS_RI) {
1181                return;
1182            }
1183        } catch (CertificateParsingException e) {
1184            if (StandardNames.IS_RI) {
1185                return;
1186            }
1187            throw e;
1188        }
1189
1190        // Bouncycastle is broken
1191        if ("BC".equals(f.getProvider().getName())) {
1192            assertEquals(0, bais.available());
1193        } else {
1194            assertEquals(4096, bais.available());
1195        }
1196    }
1197
1198    private void generateCertificates_X509_DER_TrailingData(CertificateFactory f) throws Exception {
1199        byte[] certBytes = getResourceAsBytes(CERTS_X509_DER);
1200        byte[] certsPlusExtra = new byte[certBytes.length + 4096];
1201        System.arraycopy(certBytes, 0, certsPlusExtra, 0, certBytes.length);
1202        ByteArrayInputStream bais = new ByteArrayInputStream(certsPlusExtra);
1203
1204        assertEquals(certsPlusExtra.length, bais.available());
1205
1206        // RI is broken
1207        try {
1208            Collection<? extends X509Certificate> certs = (Collection<? extends X509Certificate>)
1209                    f.generateCertificates(bais);
1210            if (StandardNames.IS_RI) {
1211                return;
1212            }
1213        } catch (CertificateParsingException e) {
1214            if (StandardNames.IS_RI) {
1215                return;
1216            }
1217            throw e;
1218        }
1219
1220        // Bouncycastle is broken
1221        if ("BC".equals(f.getProvider().getName())) {
1222            assertEquals(0, bais.available());
1223        } else {
1224            assertEquals(4096, bais.available());
1225        }
1226    }
1227
1228    private void generateCertificates_PKCS7_PEM_TrailingData(CertificateFactory f) throws Exception {
1229        byte[] certBytes = getResourceAsBytes(CERTS_PKCS7_PEM);
1230        byte[] certsPlusExtra = new byte[certBytes.length + 4096];
1231        System.arraycopy(certBytes, 0, certsPlusExtra, 0, certBytes.length);
1232        ByteArrayInputStream bais = new ByteArrayInputStream(certsPlusExtra);
1233
1234        assertEquals(certsPlusExtra.length, bais.available());
1235        Collection<? extends X509Certificate> certs = (Collection<? extends X509Certificate>)
1236                f.generateCertificates(bais);
1237
1238        // Bouncycastle is broken
1239        if ("BC".equals(f.getProvider().getName())) {
1240            assertEquals(0, bais.available());
1241        } else {
1242            assertEquals(4096, bais.available());
1243        }
1244    }
1245
1246    private void generateCertificates_PKCS7_DER_TrailingData(CertificateFactory f) throws Exception {
1247        byte[] certBytes = getResourceAsBytes(CERTS_PKCS7_DER);
1248        byte[] certsPlusExtra = new byte[certBytes.length + 4096];
1249        System.arraycopy(certBytes, 0, certsPlusExtra, 0, certBytes.length);
1250        ByteArrayInputStream bais = new ByteArrayInputStream(certsPlusExtra);
1251
1252        assertEquals(certsPlusExtra.length, bais.available());
1253        Collection<? extends X509Certificate> certs = (Collection<? extends X509Certificate>)
1254                f.generateCertificates(bais);
1255
1256        assertEquals(4096, bais.available());
1257    }
1258
1259    private void test_Serialization(CertificateFactory f) throws Exception {
1260        for (String certName : VARIOUS_CERTS) {
1261            X509Certificate expected = getCertificate(f, certName);
1262
1263            ByteArrayOutputStream baos = new ByteArrayOutputStream();
1264            ObjectOutputStream oos = new ObjectOutputStream(baos);
1265            try {
1266                oos.writeObject(expected);
1267            } finally {
1268                oos.close();
1269            }
1270
1271            byte[] certBytes = baos.toByteArray();
1272
1273            ByteArrayInputStream bais = new ByteArrayInputStream(certBytes);
1274            try {
1275                ObjectInputStream ois = new ObjectInputStream(bais);
1276
1277                X509Certificate actual = (X509Certificate) ois.readObject();
1278
1279                assertEquals(certName, expected, actual);
1280            } finally {
1281                bais.close();
1282            }
1283        }
1284    }
1285
1286    private void test_UnknownUnmappedKeyOID(CertificateFactory f) throws Exception {
1287        byte[] certBytes = generateFakeOidCertificate();
1288
1289        {
1290            X509Certificate cert = (X509Certificate) f
1291                    .generateCertificate(new ByteArrayInputStream(certBytes));
1292            assertEquals(FakeOidProvider.SIGALG_OID, cert.getSigAlgOID());
1293            assertEquals(FakeOidProvider.SIGALG_OID, cert.getSigAlgName());
1294        }
1295    }
1296
1297    private byte[] generateFakeOidCertificate() throws IOException {
1298        byte[] certBytes;
1299
1300        // Read in the original cert.
1301        {
1302            InputStream is = null;
1303            try {
1304                is = Support_Resources.getStream(CERT_RSA);
1305
1306                ByteArrayOutputStream baos = new ByteArrayOutputStream();
1307                byte[] buffer = new byte[2048];
1308                int numRead;
1309                while ((numRead = is.read(buffer, 0, buffer.length)) != -1) {
1310                    baos.write(buffer, 0, numRead);
1311                }
1312                certBytes = baos.toByteArray();
1313            } finally {
1314                if (is != null) {
1315                    try {
1316                        is.close();
1317                    } catch (IOException ignored) {
1318                    }
1319                }
1320            }
1321        }
1322
1323        // Fix the OID for the certificate.
1324        {
1325            int numFixed = 0;
1326            for (int i = 0; i < certBytes.length - 5; i++) {
1327                if (certBytes[i] == (byte) 0x2A && certBytes[i + 1] == (byte) 0x86
1328                        && certBytes[i + 2] == (byte) 0x48 && certBytes[i + 3] == (byte) 0x86
1329                        && certBytes[i + 4] == (byte) 0xF7) {
1330                    certBytes[i + 1] = (byte) 0xFF;
1331                    certBytes[i + 2] = (byte) 0xFF;
1332                    certBytes[i + 3] = (byte) 0xFF;
1333                    i += 4;
1334                    numFixed++;
1335                }
1336            }
1337            assertEquals(3, numFixed);
1338        }
1339        return certBytes;
1340    }
1341
1342    @Override
1343    protected void setUp() throws Exception {
1344        super.setUp();
1345
1346        mX509Providers = Security.getProviders("CertificateFactory.X509");
1347    }
1348}
1349