1 /*
2  * Copyright (c) 2003, 2014, 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  */
23 
24 /**
25  * @test
26  * @bug 4776466 8032573
27  * @summary check that CertificateFactory rejects invalid encoded X.509 certs
28  */
29 
30 import java.io.*;
31 import java.util.Collection;
32 import java.util.List;
33 import java.util.LinkedList;
34 import javax.security.auth.x500.X500Principal;
35 import java.security.GeneralSecurityException;
36 import java.security.cert.*;
37 
38 public class DetectInvalidEncoding {
39 
40     // Originally found in the test file:
41     // java/security/cert/CertificateFactory/invalidEncodedCerts/invalidcert.pem
42     // The first character of the PEM encoding has been changed from "M" to
43     // "X" to force a failure during decoding.
44     private static final String INVALID_CERT =
45         "-----BEGIN CERTIFICATE-----\n" +
46         "XIICJjCCAdCgAwIBAgIBITANBgkqhkiG9w0BAQQFADCBqTELMAkGA1UEBhMCVVMx\n" +
47         "EzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xFTAT\n" +
48         "BgNVBAoTDEJFQSBXZWJMb2dpYzERMA8GA1UECxMIU2VjdXJpdHkxIzAhBgNVBAMT\n" +
49         "GkRlbW8gQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9zdXBw\n" +
50         "b3J0QGJlYS5jb20wHhcNMDAwNTMwMjEzODAxWhcNMDQwNTEzMjEzODAxWjCBjDEL\n" +
51         "MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG\n" +
52         "cmFuY2lzY28xFTATBgNVBAoTDEJFQSBXZWJMb2dpYzEZMBcGA1UEAxMQd2VibG9n\n" +
53         "aWMuYmVhLmNvbTEeMBwGCSqGSIb3DQEJARYPc3VwcG9ydEBiZWEuY29tMFwwDQYJ\n" +
54         "KoZIhvcNAQEBBQADSwAwSAJBALdsXEHqKHgs6zj0hU5sXMAUHzoT8kgWXmNkKHXH\n" +
55         "79qbPh6EfdlriW9G/AbRF/pKrCQu7hhllAxREbqTuSlf2EMCAwEAATANBgkqhkiG\n" +
56         "9w0BAQQFAANBACgmqflL5m5LNeJGpWx9aIoABCiuDcpw1fFyegsqGX7CBhffcruS\n" +
57         "1p8h5vkHVbMu1frD1UgGnPlOO/K7Ig/KrsU=\n" +
58         "-----END CERTIFICATE-----";
59 
60     // Created with keytool:
61     // keytool -genkeypair -keyalg rsa -keysize 2048 -keystore <KS_FILE>
62     //      -alias root -sigalg SHA256withRSA -dname "CN=Root, O=SomeCompany"
63     //      -validity 730 -ext bc:critical=ca:true
64     //      -ext ku:critical=keyCertSign,cRLSign
65     private static final String SINGLE_ROOT_CERT =
66         "-----BEGIN CERTIFICATE-----\n" +
67         "MIIDCjCCAfKgAwIBAgIEDUiw+DANBgkqhkiG9w0BAQsFADAlMRQwEgYDVQQKEwtT\n" +
68         "b21lQ29tcGFueTENMAsGA1UEAxMEUm9vdDAeFw0xNDA4MjgyMTI5MjZaFw0xNjA4\n" +
69         "MjcyMTI5MjZaMCUxFDASBgNVBAoTC1NvbWVDb21wYW55MQ0wCwYDVQQDEwRSb290\n" +
70         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0VFecSNdH6CJhPOSG127\n" +
71         "tuvld4y7GGJ0kQf3Q0b8qgprsXAmn0/bQR+YX7PfS408cFW+q2SWXeY2kC/3chvi\n" +
72         "2syMsGdUJrDzuMbYsbvKPKyuJ2GJskX3mSbLMJj5Tzhg4qmwbzDTFIJ51yGa1Wmh\n" +
73         "i2+4PhltqT0TohvSVJlBrOWNhmvwv5UWsF4e2i04rebDZQoWkmD3MpImZXF/HYre\n" +
74         "9P8NP97vN0xZmh5PySHy2ILXN3ZhTn3tq0YxNSQTaMUfhgoyzWFvZKAnm/tZIh/1\n" +
75         "oswwEQPIZJ25AUTm9r3YPQXl1hsNdLU0asEVYRsgzGSTX5gCuUY+KzhStzisOcUY\n" +
76         "uQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV\n" +
77         "HQ4EFgQUz1FBNixG/KCgcn6FOWzxP1hujG0wDQYJKoZIhvcNAQELBQADggEBAL60\n" +
78         "ZaNc6eIMbKntGVE/pdxxyKwPdDyAAeEevX23KRWoLbQjHXo5jrfDPhI5k45ztlyU\n" +
79         "+tIQbc81LlCl88I4dIx0fvEbxjNaAYhFNXwwSQBs2CuEAdRK8hodXbRcEeI+G10F\n" +
80         "ARIVs2C7JNm/RhxskCWgj6tFIOGaTZ9gHyvlQUEM18sr5fXZlXTqspZCmz3t5XPi\n" +
81         "5/wYLv6vk7k3G8WzMHbBE0bYI+61cCc8rbMHldtymbwSwiqfKC9y7oPEfRCbzVUe\n" +
82         "fgrKcOyVWDuw0y0hhsQL/oONjPp4uK/bl9B7T84t4+ihxdocWKx6eyhFvOvZH9t2\n" +
83         "kUylb9yBUYStwGExMHg=\n" +
84         "-----END CERTIFICATE-----";
85 
86     // Created with keytool:
87     // keytool -genkeypair -keyalg rsa -keysize 2048 -keystore <KS_FILE>
88     //      -alias root -sigalg SHA256withRSA
89     //      -dname "CN=Intermed, O=SomeCompany" -validity 730
90     //      -ext bc:critical=ca:true -ext ku:critical=keyCertSign,cRLSign
91     // keytool -certreq -keystore <KS_FILE> -sigalg SHA256withRSA
92     //      -alias intermed -dname "CN=Intermed, O=SomeCompany"
93     // keytool -gencert -keystore <KS_FILE> -alias intermed
94     //      -sigalg SHA256withRSA -validity 730
95     //      -ext bc:critical=ca:true -ext ku:critical=keyCertSign,cRLSign
96     private static final String INTERMED_CA_CERT =
97         "-----BEGIN CERTIFICATE-----\n" +
98         "MIIDLzCCAhegAwIBAgIEIIgOyDANBgkqhkiG9w0BAQsFADAlMRQwEgYDVQQKEwtT\n" +
99         "b21lQ29tcGFueTENMAsGA1UEAxMEUm9vdDAeFw0xNDA4MjgyMjUyNDJaFw0xNjA4\n" +
100         "MDcyMjUyNDJaMCkxFDASBgNVBAoTC1NvbWVDb21wYW55MREwDwYDVQQDEwhJbnRl\n" +
101         "cm1lZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJEecvTWla8kdWx+\n" +
102         "HHu5ryfBpJ95I7V4MEajnmzJVZcwvKhDjlDgABDMuVwFEUUSyeOdbWJF3DLKnyMD\n" +
103         "KTx6/58kuVak3NX2TJ8cmmIlKf1upFbdrEtjYViSnNrApprfO8B3ORdBbO6QDYza\n" +
104         "IkAWdI5GllFnVkb4yhMUBg3zfhglF+bl3D3lVRlp9bCrUZoNRs+mZjhVbcMn22ej\n" +
105         "TfG5Y3VpNM4SN8dFIxPQLLk/aao+cmWEQdbQ0R6ydemRukqrw170olSVLeoGGala\n" +
106         "3D4oJckde8EgNPcghcsdQ6tpGhkpFhmoyzEsuToR7Gq9UT5V2kkqJneiKXqQg4wz\n" +
107         "vMAlUGECAwEAAaNjMGEwHwYDVR0jBBgwFoAUOw+92bevFoJz96pR1DrAkPPUKb0w\n" +
108         "DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFLbnErBs\n" +
109         "q/Mhci5XElfjjLZp3GRyMA0GCSqGSIb3DQEBCwUAA4IBAQAq8y2DpkSV31IXZ1vr\n" +
110         "/Ye+Nj/2NvBydFeHVRGMAN1LJv6/Q42TCSXbr6cDQ4NWQUtPm90yZBYJSznkbShx\n" +
111         "HOJEE6R8PRJvoUtMm7fJrNtkybTt6jX4j50Lw8gdYB/rgZb4z8ZQZVEo/0zpW4HV\n" +
112         "Gs+q4z8TkdmLR18hl39sUEsxt99AOBk8NtKKVNfBWq9b0QDhRkXfmqhyeXdDsHOV\n" +
113         "8ksulsa7hseheHhdjziEOpQugh8qzSea2kFPrLB53VjWfa4qDzEPaNhahho9piCu\n" +
114         "82XDnOrcEk9KyHWM7sa7vtK7++W+0MXD/p9nkZ6NHrJXweLriU0DXO6ZY3mzNKJK\n" +
115         "435M\n" +
116         "-----END CERTIFICATE-----";
117 
118     // Subordinate cert created using keytool, both certs exported to
119     // files individually, then use openssl to place in a PKCS#7:
120     // openssl crl2pkcs7 -nocrl -certfile <INTERMED-CERT-PEM>
121     //      -certfile <ROOT-CERT-PEM> -out <P7-DEST-PEM-FILE>
122     private static final String PKCS7_INTERMED_ROOT_CERTS =
123         "-----BEGIN PKCS7-----\n" +
124         "MIIGbgYJKoZIhvcNAQcCoIIGXzCCBlsCAQExADALBgkqhkiG9w0BBwGgggZBMIID\n" +
125         "LzCCAhegAwIBAgIEIIgOyDANBgkqhkiG9w0BAQsFADAlMRQwEgYDVQQKEwtTb21l\n" +
126         "Q29tcGFueTENMAsGA1UEAxMEUm9vdDAeFw0xNDA4MjgyMjUyNDJaFw0xNjA4MDcy\n" +
127         "MjUyNDJaMCkxFDASBgNVBAoTC1NvbWVDb21wYW55MREwDwYDVQQDEwhJbnRlcm1l\n" +
128         "ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJEecvTWla8kdWx+HHu5\n" +
129         "ryfBpJ95I7V4MEajnmzJVZcwvKhDjlDgABDMuVwFEUUSyeOdbWJF3DLKnyMDKTx6\n" +
130         "/58kuVak3NX2TJ8cmmIlKf1upFbdrEtjYViSnNrApprfO8B3ORdBbO6QDYzaIkAW\n" +
131         "dI5GllFnVkb4yhMUBg3zfhglF+bl3D3lVRlp9bCrUZoNRs+mZjhVbcMn22ejTfG5\n" +
132         "Y3VpNM4SN8dFIxPQLLk/aao+cmWEQdbQ0R6ydemRukqrw170olSVLeoGGala3D4o\n" +
133         "Jckde8EgNPcghcsdQ6tpGhkpFhmoyzEsuToR7Gq9UT5V2kkqJneiKXqQg4wzvMAl\n" +
134         "UGECAwEAAaNjMGEwHwYDVR0jBBgwFoAUOw+92bevFoJz96pR1DrAkPPUKb0wDwYD\n" +
135         "VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFLbnErBsq/Mh\n" +
136         "ci5XElfjjLZp3GRyMA0GCSqGSIb3DQEBCwUAA4IBAQAq8y2DpkSV31IXZ1vr/Ye+\n" +
137         "Nj/2NvBydFeHVRGMAN1LJv6/Q42TCSXbr6cDQ4NWQUtPm90yZBYJSznkbShxHOJE\n" +
138         "E6R8PRJvoUtMm7fJrNtkybTt6jX4j50Lw8gdYB/rgZb4z8ZQZVEo/0zpW4HVGs+q\n" +
139         "4z8TkdmLR18hl39sUEsxt99AOBk8NtKKVNfBWq9b0QDhRkXfmqhyeXdDsHOV8ksu\n" +
140         "lsa7hseheHhdjziEOpQugh8qzSea2kFPrLB53VjWfa4qDzEPaNhahho9piCu82XD\n" +
141         "nOrcEk9KyHWM7sa7vtK7++W+0MXD/p9nkZ6NHrJXweLriU0DXO6ZY3mzNKJK435M\n" +
142         "MIIDCjCCAfKgAwIBAgIEdffjKTANBgkqhkiG9w0BAQsFADAlMRQwEgYDVQQKEwtT\n" +
143         "b21lQ29tcGFueTENMAsGA1UEAxMEUm9vdDAeFw0xNDA4MjgyMjQ2MzZaFw0xNjA4\n" +
144         "MjcyMjQ2MzZaMCUxFDASBgNVBAoTC1NvbWVDb21wYW55MQ0wCwYDVQQDEwRSb290\n" +
145         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhnXc8Avv54Gk2xjVa2yA\n" +
146         "lBL/Cug1nyvKl5wqmN+foT6cMOX6bneCkJOJ4lSbch3gvl4ctlX/9hm3pB/+HhSr\n" +
147         "em2NcLQrLEq8l9Ar4RnqfoXQR4Uy+4P6wj9OcVV7e/v/+ZPnStOoEAtb5nAwsR2b\n" +
148         "hOC/tIFNwflrsmsmtMSoOiNftpYLFF4eOAdpDrXYMrqNu6ZxZsOQ7WZl4SsVOx1N\n" +
149         "/IINXwBLyoHJDzLZ0iJEV0O6mh846s0n6QXeK1P5d0uLcoZaZ1k8Q4sRcdoLA6rS\n" +
150         "e1WffipBFMvIuoDIigkHZIKVYRLG828rO+PFnRah0ybybkVsN6s3oLxfhswZDvut\n" +
151         "OwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV\n" +
152         "HQ4EFgQUOw+92bevFoJz96pR1DrAkPPUKb0wDQYJKoZIhvcNAQELBQADggEBACBN\n" +
153         "wEaV70FKKBINHtNwesd7TB6fgSaVgDZOO08aseHbXnm7AUhtDV3P5rQR2AsKtbg4\n" +
154         "COhlKw2/Ki18D4DfdCccFKFTRZBjqj2PxNmn6C68l1/bT4PuUXuM7rW++53RcOA7\n" +
155         "TbgLuzA25kSz7XinRvR8L4VwHtppu5tSYEthMIMgLZLGGV9r7kBfpY8lXdxQM8vb\n" +
156         "xZUIysasvVtVUFPOTV6g2dfn8QCoqLOmxyzTLdXe4M6acP6f7lmhgr3LMqDtB6K9\n" +
157         "pN+OImr77zNdZ+jTB+5e9a8gAvc5ZfG7Nk5RfwUatYTAFZ6Uggy2cKmIRpXCia18\n" +
158         "If78mc7goS1+lHkGCs2hADEA\n" +
159         "-----END PKCS7-----";
160 
161     // Empty PKCS#7 in DER form can be created with openssl:
162     // openssl crl2pkcs7 -nocrl -outform DER
163     private static final byte[] PKCS7_BER_EMPTY = {
164           48,   39,    6,    9,   42, -122,   72, -122,
165           -9,   13,    1,    7,    2,  -96,   26,   48,
166           24,    2,    1,    1,   49,    0,   48,   11,
167            6,    9,   42, -122,   72, -122,   -9,   13,
168            1,    7,    1,  -96,    0,  -95,    0,   49,
169            0
170     };
171 
172     private static final String JTEST_ROOT_CRL =
173         "-----BEGIN X509 CRL-----\n" +
174         "MIICoTCBigIBATANBgkqhkiG9w0BAQsFADA1MQ4wDAYDVQQKEwVKVGVzdDELMAkG\n" +
175         "A1UECxMCSVQxFjAUBgNVBAMTDUpUZXN0IFJvb3QgQ0EXDTE0MDkwNDE4NDIyMVqg\n" +
176         "MDAuMB8GA1UdIwQYMBaAFO6bllCV6kctH77MfqAtefNeRdsmMAsGA1UdFAQEAgIA\n" +
177         "jjANBgkqhkiG9w0BAQsFAAOCAgEAmp8ihtiRthknDC+VzehmlQw5u8MftMZYQYk5\n" +
178         "EI04SwyzY9JTL8QHb4u7fXjnZAyN89aYPypI5OSyDsyyGP/JDNsBt2Um/fl0aaCl\n" +
179         "Z4Np6x+dB9+oIU1XY7y2+uyQUC5MHivQ5ddbGPoAvK/msbugTGAjHvZpM+l0okiV\n" +
180         "3SofDrii5BSosFEkXfkf2oG9ZLO3YamsFMEZaOj/eWDyGhTyJMGsq2/8NeTF21Tp\n" +
181         "YkeDcTHqR5KHoYXjOIaS7NjmErm+uDpKH9Lq+JUcYrbUhmjnq5z04EsPF2F2L7Vb\n" +
182         "THI+awQAUQit16lXGuz7fFRZi2vPyiaRP5n2QT5D+ac1dAs+oWLDJw6Tf2v9KVTe\n" +
183         "OmW62yd6zQqCwBg+n57UcNu3sv/Sq3t7iRuN0AmWlIhu659POPQv7Np6bEo6dIpp\n" +
184         "u7Ze6D2KPtM177ETHYlCx2a3g9VEZYKrVhQ2749St0Cp5szVq691jFZAWYOzcfEO\n" +
185         "XfK1y25pmlBjvhNIIVRlU+T5rjNb8GaleYKVYnKOcv700K32QxFzcPf7nbNKwW99\n" +
186         "tcaNHFNP+LW/XP8I3CJ8toXLLcOITKVwMA+0GlO5eL7eX5POc+vE9+7IzGuybmU4\n" +
187         "uslxoLdJ0NSZWpYmf6a6qrJ67cj5i3706H+eBsWQcShfSYreh+TyWQaGk+fkEiUV\n" +
188         "iy4QdJ0=\n" +
189         "-----END X509 CRL-----";
190 
191     private static final String JTEST_INTERMED_CRL =
192         "-----BEGIN X509 CRL-----\n" +
193         "MIICzzCBuAIBATANBgkqhkiG9w0BAQsFADA/MQ4wDAYDVQQKEwVKVGVzdDELMAkG\n" +
194         "A1UECxMCSVQxIDAeBgNVBAMTF0pUZXN0IEludGVybWVkaWF0ZSBDQSAxFw0xNDA5\n" +
195         "MDQyMjE2NTRaMCIwIAIBBhcNMTQwOTA0MjIxNjU0WjAMMAoGA1UdFQQDCgEFoDAw\n" +
196         "LjAfBgNVHSMEGDAWgBSvRdjbkSMJ3A7s5H6EWghQ+lkw/zALBgNVHRQEBAICAJsw\n" +
197         "DQYJKoZIhvcNAQELBQADggIBALJmikMwil8oywhenoO8o9xxCOIU0xrt3KdfiSXw\n" +
198         "8MtQXZHT9d1C6tlLAsYkWAfmfTvM2OU6wquFCLLsFmDZszbbCqmn4JhYBSKQMqlm\n" +
199         "IHnsiOFPvITW2FU08fWNLM+FtQzPnTFmx/CJo+wfGpq5tZMIbsccsCJ5uvZVAWGh\n" +
200         "0KbPmYcJG/O384+kzr/2H2IaoZoMMABec5c5FEF/tpp8jawzY+0VFyaVrumKWdan\n" +
201         "+3OvRQxT1wLxfNi2vdxB2rmNPo423qanXZAoVv260um3LYlmXBNK1jwQ9lp78jkT\n" +
202         "B7zMVa4hOUWVxdWc/LE6fUYgPsNqZd+hWy/PolIRp5TS21B5hkc5K87LT59GkexK\n" +
203         "vNVKQennOLGtH+Q7htK4UeY4Gm/W7UydOQ0k7hZzyfMDkCfLfNfK0l63qKwUku36\n" +
204         "UdeI1LXqulPEvb/d7rRAAM9p5Sm+RsECj2bcrZBMdIGXcSo26A5tzZpTEC79i4S1\n" +
205         "yxYIooeBnouUkDJ9+VBsJTSKY5fpU8JSkQPRyHKt+trGAkBt2Ka5MqrHtITzQ1vP\n" +
206         "5q4tNr45JGEXllH83NlBpWURfsdtkDHa3lxTD/pkrywOCyzz7wQ22D8Kul7EN8nT\n" +
207         "7LDbN+O3G9GHICxvWlJHp6HMsqGTuH1MIUR+5uZFOJa1S0IzorUIEieLncDUPgzO\n" +
208         "M4JA\n" +
209         "-----END X509 CRL-----";
210 
211     // PKCS#7 CRL Set containing JTEST root and intermediate CRLs
212     private static final String PKCS7_CRL_SET =
213         "-----BEGIN PKCS7-----\n" +
214         "MIIFpQYJKoZIhvcNAQcCoIIFljCCBZICAQExADALBgkqhkiG9w0BBwGgAKGCBXgw\n" +
215         "ggKhMIGKAgEBMA0GCSqGSIb3DQEBCwUAMDUxDjAMBgNVBAoTBUpUZXN0MQswCQYD\n" +
216         "VQQLEwJJVDEWMBQGA1UEAxMNSlRlc3QgUm9vdCBDQRcNMTQwOTA0MTg0MjIxWqAw\n" +
217         "MC4wHwYDVR0jBBgwFoAU7puWUJXqRy0fvsx+oC15815F2yYwCwYDVR0UBAQCAgCO\n" +
218         "MA0GCSqGSIb3DQEBCwUAA4ICAQCanyKG2JG2GScML5XN6GaVDDm7wx+0xlhBiTkQ\n" +
219         "jThLDLNj0lMvxAdvi7t9eOdkDI3z1pg/Kkjk5LIOzLIY/8kM2wG3ZSb9+XRpoKVn\n" +
220         "g2nrH50H36ghTVdjvLb67JBQLkweK9Dl11sY+gC8r+axu6BMYCMe9mkz6XSiSJXd\n" +
221         "Kh8OuKLkFKiwUSRd+R/agb1ks7dhqawUwRlo6P95YPIaFPIkwayrb/w15MXbVOli\n" +
222         "R4NxMepHkoehheM4hpLs2OYSub64Okof0ur4lRxittSGaOernPTgSw8XYXYvtVtM\n" +
223         "cj5rBABRCK3XqVca7Pt8VFmLa8/KJpE/mfZBPkP5pzV0Cz6hYsMnDpN/a/0pVN46\n" +
224         "ZbrbJ3rNCoLAGD6fntRw27ey/9Kre3uJG43QCZaUiG7rn0849C/s2npsSjp0imm7\n" +
225         "tl7oPYo+0zXvsRMdiULHZreD1URlgqtWFDbvj1K3QKnmzNWrr3WMVkBZg7Nx8Q5d\n" +
226         "8rXLbmmaUGO+E0ghVGVT5PmuM1vwZqV5gpVico5y/vTQrfZDEXNw9/uds0rBb321\n" +
227         "xo0cU0/4tb9c/wjcIny2hcstw4hMpXAwD7QaU7l4vt5fk85z68T37sjMa7JuZTi6\n" +
228         "yXGgt0nQ1JlaliZ/prqqsnrtyPmLfvTof54GxZBxKF9Jit6H5PJZBoaT5+QSJRWL\n" +
229         "LhB0nTCCAs8wgbgCAQEwDQYJKoZIhvcNAQELBQAwPzEOMAwGA1UEChMFSlRlc3Qx\n" +
230         "CzAJBgNVBAsTAklUMSAwHgYDVQQDExdKVGVzdCBJbnRlcm1lZGlhdGUgQ0EgMRcN\n" +
231         "MTQwOTA0MjIxNjU0WjAiMCACAQYXDTE0MDkwNDIyMTY1NFowDDAKBgNVHRUEAwoB\n" +
232         "BaAwMC4wHwYDVR0jBBgwFoAUr0XY25EjCdwO7OR+hFoIUPpZMP8wCwYDVR0UBAQC\n" +
233         "AgCbMA0GCSqGSIb3DQEBCwUAA4ICAQCyZopDMIpfKMsIXp6DvKPccQjiFNMa7dyn\n" +
234         "X4kl8PDLUF2R0/XdQurZSwLGJFgH5n07zNjlOsKrhQiy7BZg2bM22wqpp+CYWAUi\n" +
235         "kDKpZiB57IjhT7yE1thVNPH1jSzPhbUMz50xZsfwiaPsHxqaubWTCG7HHLAiebr2\n" +
236         "VQFhodCmz5mHCRvzt/OPpM6/9h9iGqGaDDAAXnOXORRBf7aafI2sM2PtFRcmla7p\n" +
237         "ilnWp/tzr0UMU9cC8XzYtr3cQdq5jT6ONt6mp12QKFb9utLpty2JZlwTStY8EPZa\n" +
238         "e/I5Ewe8zFWuITlFlcXVnPyxOn1GID7DamXfoVsvz6JSEaeU0ttQeYZHOSvOy0+f\n" +
239         "RpHsSrzVSkHp5zixrR/kO4bSuFHmOBpv1u1MnTkNJO4Wc8nzA5Any3zXytJet6is\n" +
240         "FJLt+lHXiNS16rpTxL2/3e60QADPaeUpvkbBAo9m3K2QTHSBl3EqNugObc2aUxAu\n" +
241         "/YuEtcsWCKKHgZ6LlJAyfflQbCU0imOX6VPCUpED0chyrfraxgJAbdimuTKqx7SE\n" +
242         "80Nbz+auLTa+OSRhF5ZR/NzZQaVlEX7HbZAx2t5cUw/6ZK8sDgss8+8ENtg/Crpe\n" +
243         "xDfJ0+yw2zfjtxvRhyAsb1pSR6ehzLKhk7h9TCFEfubmRTiWtUtCM6K1CBIni53A\n" +
244         "1D4MzjOCQDEA\n" +
245         "-----END PKCS7-----";
246 
main(String[] args)247     public static void main(String[] args) throws Exception {
248         CertificateFactory cf = CertificateFactory.getInstance("X.509");
249         List<DecodeTest> validTests = new LinkedList<>();
250         List<DecodeTest> invalidTests = new LinkedList<>();
251 
252         // Load up positive test cases (for sanity checks)
253         StringBuilder sb = new StringBuilder();
254 
255         validTests.add(new GenMultiCertTest("Single, valid certificate",
256                     SINGLE_ROOT_CERT.getBytes(), null,
257                     new X500Principal("CN=Root, O=SomeCompany")));
258         validTests.add(new GenMultiCertTest("PEM-encoded PKCS#7 chain",
259                     PKCS7_INTERMED_ROOT_CERTS.getBytes(), null,
260                     new X500Principal("CN=Intermed, O=SomeCompany"),
261                     new X500Principal("CN=Root, O=SomeCompany")));
262         validTests.add(new GenMultiCertTest("Two PEM-encoded X509 certs",
263                     (INTERMED_CA_CERT + "\n" + SINGLE_ROOT_CERT).getBytes(),
264                     null,
265                     new X500Principal("CN=Intermed, O=SomeCompany"),
266                     new X500Principal("CN=Root, O=SomeCompany")));
267         validTests.add(new GenMultiCertTest("Empty data", new byte[0], null));
268 
269         sb.append("Certificate 1: CN=Root, O=SomeCompany\n");
270         sb.append(SINGLE_ROOT_CERT).append("\n");
271         sb.append("Certificate 2: CN=Intermed, O=SomeCompany\n");
272         sb.append(INTERMED_CA_CERT).append("\n");
273         sb.append("Extra trailing data\n");
274         validTests.add(new GenMultiCertTest(
275                     "Two PEM-encoded certs with leading/trailing " +
276                     "text data around each.", sb.toString().getBytes(), null,
277                     new X500Principal("CN=Root, O=SomeCompany"),
278                     new X500Principal("CN=Intermed, O=SomeCompany")));
279         validTests.add(new GenMultiCertTest(
280                     "BER-encoded PKCS#7 with empty certificates segment",
281                     PKCS7_BER_EMPTY, null));
282         validTests.add(new GenMultiCRLTest(
283                     "CRL with leading and trailing text data",
284                     ("This is a CRL\n" + JTEST_ROOT_CRL +
285                      "\nSee? Told you so\n\n").getBytes(), null,
286                     new X500Principal("CN=JTest Root CA,OU=IT,O=JTest")));
287         validTests.add(new GenMultiCRLTest(
288                     "Two CRLs, one after the other with leading/trailing text",
289                     ("This is a CRL\n" + JTEST_ROOT_CRL +
290                      "\nAnd this is another CRL\n" + JTEST_INTERMED_CRL +
291                      "\nAnd this is trailing text\n").getBytes(), null,
292                     new X500Principal("CN=JTest Root CA,OU=IT,O=JTest"),
293                     new X500Principal(
294                         "CN=JTest Intermediate CA 1,OU=IT,O=JTest")));
295         validTests.add(new GenMultiCRLTest("Two CRLs in a PKCS#7 CRL set",
296                 PKCS7_CRL_SET.getBytes(), null,
297                 new X500Principal("CN=JTest Root CA,OU=IT,O=JTest"),
298                 new X500Principal("CN=JTest Intermediate CA 1,OU=IT,O=JTest")));
299 
300         // Load up all test cases where we expect failures
301         invalidTests.add(new GenSingleCertTest("Invalid PEM encoding",
302                     INVALID_CERT.getBytes(),
303                     new CertificateParsingException()));
304         invalidTests.add(new GenMultiCertTest("Invalid PEM encoding",
305                     INVALID_CERT.getBytes(),
306                     new CertificateParsingException()));
307         invalidTests.add(new GenMultiCertTest(
308                     "Two cert sequence, one valid and one invalid",
309                     (INTERMED_CA_CERT + "\n" + INVALID_CERT).getBytes(),
310                     new CertificateParsingException()));
311         invalidTests.add(new GenMultiCertTest("Non-certificate text",
312                     "This is not a certificate".getBytes(),
313                     new CertificateException()));
314         invalidTests.add(new GenMultiCertTest(
315                     "Non-certificate text with partial PEM header (4 hyphens)",
316                     "----This is not a valid x509 certificate".getBytes(),
317                     new CertificateException()));
318         invalidTests.add(new GenMultiCertTest(
319                     "Leading non-certificate text plus valid PEM header, " +
320                     "but not on new line",
321                     "This is not valid -----BEGIN CERTIFICATE-----".getBytes(),
322                     new CertificateException()));
323         byte[] emptyCString = {0};
324         invalidTests.add(new GenMultiCertTest("Empty C-style string",
325                     emptyCString, new CertificateException()));
326         invalidTests.add(new GenMultiCRLTest("Non-CRL text",
327                     "This is not a CRL".getBytes(), new CRLException()));
328         invalidTests.add(new GenMultiCRLTest("Valid headers, but not a CRL",
329                     INTERMED_CA_CERT.getBytes(), new CRLException()));
330 
331         System.out.println("===== Valid Tests =====");
332         for (DecodeTest dt : validTests) {
333             dt.passTest();
334         }
335         System.out.print("\n");
336 
337         System.out.println("===== Invalid Tests =====");
338         for (DecodeTest dt : invalidTests) {
339             dt.failTest();
340         }
341     }
342 
343     public static abstract class DecodeTest {
344         protected String testName;
345         protected byte[] testData;
346         protected Throwable expectedException;
347         protected X500Principal[] principals;
348         protected CertificateFactory cf;
349 
350         /**
351          * Construct a DecodeTest
352          *
353          * @param name The test name
354          * @param input A byte array consisting of the input for this test
355          * @param failType An exception whose class should match the expected
356          *        exception that will be thrown when this test is run
357          * @param princs Zero of more X500Principals which will be used
358          *        to compare the output in a success case.
359          */
DecodeTest(String name, byte[] input, Throwable failType, X500Principal... princs)360         DecodeTest(String name, byte[] input, Throwable failType,
361                 X500Principal... princs) throws CertificateException {
362             testName = name;
363             testData = input.clone();
364             expectedException = failType;
365             principals = princs;
366             cf = CertificateFactory.getInstance("X.509");
367         }
368 
passTest()369         public abstract void passTest() throws GeneralSecurityException;
370 
failTest()371         public abstract void failTest() throws GeneralSecurityException;
372     }
373 
374     public static class GenMultiCertTest extends DecodeTest {
GenMultiCertTest(String name, byte[] input, Throwable failType, X500Principal... princs)375         public GenMultiCertTest(String name, byte[] input, Throwable failType,
376                 X500Principal... princs) throws CertificateException {
377             super(name, input, failType, princs);
378         }
379 
380         @Override
passTest()381         public void passTest() throws GeneralSecurityException {
382             Collection<? extends Certificate> certs;
383 
384             System.out.println("generateCertificates(): " + testName);
385             certs = cf.generateCertificates(new ByteArrayInputStream(testData));
386 
387             // Walk the certs Collection and do a comparison of subject names
388             int i = 0;
389             if (certs.size() == principals.length) {
390                 for (Certificate crt : certs) {
391                     X509Certificate xc = (X509Certificate)crt;
392                     if (!xc.getSubjectX500Principal().equals(
393                                 principals[i])) {
394                         throw new RuntimeException("Name mismatch: " +
395                                 "cert: " + xc.getSubjectX500Principal() +
396                                 ", expected: " + principals[i]);
397                     }
398                     i++;
399                 }
400             } else {
401                 throw new RuntimeException("Size mismatch: certs = " +
402                         certs.size() + ", expected = " +
403                         principals.length);
404             }
405         }
406 
407         @Override
failTest()408         public void failTest() throws GeneralSecurityException {
409             Throwable caughtException = null;
410             Collection<? extends Certificate> certs = null;
411 
412             System.out.println("generateCertificates(): " + testName);
413             if (expectedException == null) {
414                 throw new RuntimeException("failTest requires non-null " +
415                         "expectedException");
416             }
417 
418             try {
419                 certs =
420                     cf.generateCertificates(new ByteArrayInputStream(testData));
421             } catch (CertificateException ce) {
422                 caughtException = ce;
423             }
424 
425             if (caughtException != null) {
426                 // It has to be the right kind of exception though...
427                 if (!caughtException.getClass().equals(
428                         expectedException.getClass())) {
429                     System.err.println("Unexpected exception thrown. " +
430                             "Received: " + caughtException + ", Expected: " +
431                             expectedException.getClass());
432                     throw new RuntimeException(caughtException);
433                 }
434             } else {
435                 // For a failure test, we'd expect some kind of exception
436                 // to be thrown.
437                 throw new RuntimeException("Failed to catch expected " +
438                         "exception " + expectedException.getClass());
439             }
440         }
441     }
442 
443     public static class GenSingleCertTest extends DecodeTest {
GenSingleCertTest(String name, byte[] input, Throwable failType, X500Principal... princs)444         public GenSingleCertTest(String name, byte[] input, Throwable failType,
445                 X500Principal... princs) throws CertificateException {
446             super(name, input, failType, princs);
447         }
448 
449         @Override
passTest()450         public void passTest() throws GeneralSecurityException {
451             X509Certificate cert;
452 
453             System.out.println("generateCertificate(): " + testName);
454             cert = (X509Certificate)cf.generateCertificate(
455                     new ByteArrayInputStream(testData));
456 
457             // Compare the cert's subject name against the expected value
458             // provided in the test.  If multiple X500Principals were provided
459             // just use the first one as the expected value.
460             if (!cert.getSubjectX500Principal().equals(principals[0])) {
461                 throw new RuntimeException("Name mismatch: " +
462                         "cert: " + cert.getSubjectX500Principal() +
463                         ", expected: " + principals[0]);
464             }
465         }
466 
467         @Override
failTest()468         public void failTest() throws GeneralSecurityException {
469             Throwable caughtException = null;
470             X509Certificate cert = null;
471             System.out.println("generateCertificate(): " + testName);
472 
473             if (expectedException == null) {
474                 throw new RuntimeException("failTest requires non-null " +
475                         "expectedException");
476             }
477 
478             try {
479                 cert = (X509Certificate)cf.generateCertificate(
480                         new ByteArrayInputStream(testData));
481             } catch (CertificateException e) {
482                 caughtException = e;
483             }
484 
485             if (caughtException != null) {
486                 // It has to be the right kind of exception though...
487                 if (!caughtException.getClass().equals(
488                         expectedException.getClass())) {
489                     System.err.println("Unexpected exception thrown. " +
490                             "Received: " + caughtException + ", Expected: " +
491                             expectedException.getClass());
492                     throw new RuntimeException(caughtException);
493                 }
494             } else {
495                 // For a failure test, we'd expect some kind of exception
496                 // to be thrown.
497                 throw new RuntimeException("Failed to catch expected " +
498                         "exception " + expectedException.getClass());
499             }
500         }
501     }
502 
503     public static class GenMultiCRLTest extends DecodeTest {
GenMultiCRLTest(String name, byte[] input, Throwable failType, X500Principal... princs)504         public GenMultiCRLTest(String name, byte[] input, Throwable failType,
505                 X500Principal... princs) throws CertificateException {
506             super(name, input, failType, princs);
507         }
508 
509         @Override
passTest()510         public void passTest() throws GeneralSecurityException {
511             Collection<? extends CRL> crls;
512 
513             System.out.println("generateCRLs(): " + testName);
514             crls = cf.generateCRLs(new ByteArrayInputStream(testData));
515 
516             // Walk the crls Collection and do a comparison of issuer names
517             int i = 0;
518             if (crls.size() == principals.length) {
519                 for (CRL revlist : crls) {
520                     X509CRL xc = (X509CRL)revlist;
521                     if (!xc.getIssuerX500Principal().equals(principals[i])) {
522                         throw new RuntimeException("Name mismatch: " +
523                                 "CRL: " + xc.getIssuerX500Principal() +
524                                 ", expected: " + principals[i]);
525                     }
526                     i++;
527                 }
528             } else {
529                 throw new RuntimeException("Size mismatch: crls = " +
530                         crls.size() + ", expected = " +
531                         principals.length);
532             }
533         }
534 
535         @Override
failTest()536         public void failTest() throws GeneralSecurityException {
537             Throwable caughtException = null;
538             Collection<? extends CRL> crls = null;
539 
540             System.out.println("generateCRLs(): " + testName);
541             if (expectedException == null) {
542                 throw new RuntimeException("failTest requires non-null " +
543                         "expectedException");
544             }
545 
546             try {
547                 crls =
548                     cf.generateCRLs(new ByteArrayInputStream(testData));
549             } catch (CRLException e) {
550                 caughtException = e;
551             }
552 
553             if (caughtException != null) {
554                 // It has to be the right kind of exception though...
555                 if (!caughtException.getClass().equals(
556                         expectedException.getClass())) {
557                     System.err.println("Unexpected exception thrown. " +
558                             "Received: " + caughtException + ", Expected: " +
559                             expectedException.getClass());
560                     throw new RuntimeException(caughtException);
561                 }
562             } else {
563                 // For a failure test, we'd expect some kind of exception
564                 // to be thrown.
565                 throw new RuntimeException("Failed to catch expected " +
566                         "exception " + expectedException.getClass());
567             }
568         }
569     }
570 }
571