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