| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.conscrypt.java.security.cert; |
| |
| import static org.junit.Assert.assertArrayEquals; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.assertThrows; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| import java.io.ByteArrayInputStream; |
| import java.math.BigInteger; |
| import java.nio.charset.Charset; |
| import java.security.InvalidKeyException; |
| import java.security.NoSuchAlgorithmException; |
| import java.security.Provider; |
| import java.security.SignatureException; |
| import java.security.cert.CertificateException; |
| import java.security.cert.CertificateFactory; |
| import java.security.cert.CertificateParsingException; |
| import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule; |
| import java.security.cert.X509Certificate; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Calendar; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.Date; |
| import java.util.List; |
| import java.util.TimeZone; |
| import javax.security.auth.x500.X500Principal; |
| import org.conscrypt.TestUtils; |
| import org.junit.ClassRule; |
| import org.junit.Test; |
| import org.junit.rules.TestRule; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.JUnit4; |
| import tests.util.Pair; |
| import tests.util.ServiceTester; |
| |
| @RunWith(JUnit4.class) |
| public class X509CertificateTest { |
| |
| // BEGIN Android-Added: Allow access to deprecated BC algorithms. |
| // Allow access to deprecated BC algorithms in this test, so we can ensure they |
| // continue to work |
| @ClassRule |
| public static TestRule enableDeprecatedBCAlgorithmsRule = |
| EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance(); |
| // END Android-Added: Allow access to deprecated BC algorithms. |
| |
| private static final String VALID_CERT = |
| "-----BEGIN CERTIFICATE-----\n" |
| + "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\n" |
| + "-----END CERTIFICATE-----"; |
| |
| /* |
| This certificate is a modified version of the above self-signed cert. The cert has |
| been modified to change the certificate data's signature algorithm |
| declaration from sha256withRSAEncryption to sha512withRSAEncryption. This causes |
| the signature block's algorithm (which is unmodified) to not match the cert info. |
| */ |
| private static final String MISMATCHED_ALGORITHM_CERT = |
| "-----BEGIN CERTIFICATE-----\n" |
| + "MIIFMjCCAxqgAwIBAgIJAL0mG5fOeJ7xMA0GCSqGSIb3DQEBDQUAMC0xCzAJBgNV\n" |
| + "BAYTAkdCMQ8wDQYDVQQHDAZMb25kb24xDTALBgNVBAoMBFRlc3QwIBcNMTgwOTE3\n" |
| + "MTIxNzU3WhgPMjExODA4MjQxMjE3NTdaMC0xCzAJBgNVBAYTAkdCMQ8wDQYDVQQH\n" |
| + "DAZMb25kb24xDTALBgNVBAoMBFRlc3QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw\n" |
| + "ggIKAoICAQDCMhBrRAGGw+n2GdctBr/cEK4FZA6ajiHjihgpCHoSBdyL4R2jGKLS\n" |
| + "g0WgaMXa1HpkKN7LcIySosEBPlmcRkr1RqbEvQStOSvoFCXYvtx3alM6HTbXMcDR\n" |
| + "mqoKoABP6LXsPSoMWIgqMtP2X9EOppzHVIK1yFYFfbIlvYUV2Ka+MuMe0Vh5wvD1\n" |
| + "4GanPb+cWSKgdRSVQovCCMY3yWtZKVEaxRpCsk/mYYIFWz0tcgMjIKwDx1XXgiAV\n" |
| + "nU6NK43xbaw3XhtnaD/pv9lhTTbNrlcln9LjTD097BaK4R+1AEPHnpfxA9Ui3upn\n" |
| + "kbsNUdGdOB0ksZi/vd7lh833YgquQUIAhYrbfvq/HFCpVV1gljzlS3sqULYpLE//\n" |
| + "i3OsuL2mE+CYIJGpIi2GeJJWXciNMTJDOqTn+fRDtVb4RPp4Y70DJirp7XzaBi3q\n" |
| + "H0edANCzPSRCDbZsOhzIXhXshldiXVRX666DDlbMQgLTEnNKrkwv6DmU8o15XQsb\n" |
| + "8k1Os2YwXmkEOxUQ7AJZXVTZSf6UK9Znmdq1ZrHjybMfRUkHVxJcnKvrxfryralv\n" |
| + "gzfvu+D6HuxrCo3Ojqa+nDgIbxKEBtdrcsMhq1jWPFhjwo1fSadAkKOfdCAuXJRD\n" |
| + "THg3b4Sf+W7Cpc570YHrIpBf7WFl2XsPcEM0mJZ5+yATASCubNozQwIDAQABo1Mw\n" |
| + "UTAdBgNVHQ4EFgQUES0hupZSqY21JOba10QyZuxm91EwHwYDVR0jBBgwFoAUES0h\n" |
| + "upZSqY21JOba10QyZuxm91EwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsF\n" |
| + "AAOCAgEABTN5S30ng/RMpBweDm2N561PdpaCdiRXtAFCRVWR2mkDYC/Xj9Vqe6be\n" |
| + "PyM7L/5OKYVjzF1yJu67z/dx+ja5o+41g17jdqla7hyPx+9B4uRyDh+1KJTa+duj\n" |
| + "mw/aA1LCr6O6W4WizDOsChJ6FaB2Y1+GlFnKWb5nUdhVJqXQE1WOX9dZnw8Y4Npd\n" |
| + "VmAsjWot0BZorJrt3fwfcv3QfA896twkbo7Llv/8qzg4sXZXZ4ZtgAOqnPngiSn+\n" |
| + "JT/vYCXZ406VvAFpFqMcVz2dO/VGuL8lGIMHRKNyafrsV81EzH1W/XmRWOgvgj6r\n" |
| + "yQI63ln/AMY72HQ97xLkE1xKunGz6bK5Ug5+O43Uftc4Mb6MUgzo+ZqEQ3Ob+cAV\n" |
| + "cvjmtwDaPO/O39O5Xq0tLTlkn2/cKf4OQ6S++GDxzyRVHh5JXgP4j9+jfZY57Woy\n" |
| + "R1bE7N50JjY4cDermBJKdlBIjL7UPhqmLyaG7V0hBitFlgGBUCcJtJOV0xYd5aF3\n" |
| + "pxNkvMXhBmh95fjxJ0cJjpO7tN1RAwtMMNgsl7OUbuVRQCHOPW5DgP5qY21jDeRn\n" |
| + "BY82382l+9QzykmJLI5MZnmj4BA9uIDCwMtoTTvP++SsvhUAbuvh7MOOUQL0EY4m\n" |
| + "KStYq7X9PKseN+PvmfeoffIKc5R/Ha39oi7cGMVHCr8aiEhsf94=\n" |
| + "-----END CERTIFICATE-----\n"; |
| |
| /** |
| * This cert has an EC key with curve prime256v1 encoded using explicit params. |
| */ |
| private static final String EC_EXPLICIT_KEY_CERT = |
| "-----BEGIN CERTIFICATE-----\n" |
| + "MIICAjCCAagCCQCrIzClvU58azAKBggqhkjOPQQDAjAPMQ0wCwYDVQQDDARUZXN0\n" |
| + "MB4XDTE4MTAwMjEyNDQzMloXDTE4MTEwMTEyNDQzMlowDzENMAsGA1UEAwwEVGVz\n" |
| + "dDCCAUswggEDBgcqhkjOPQIBMIH3AgEBMCwGByqGSM49AQECIQD/////AAAAAQAA\n" |
| + "AAAAAAAAAAAAAP///////////////zBbBCD/////AAAAAQAAAAAAAAAAAAAAAP//\n" |
| + "/////////////AQgWsY12Ko6k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsDFQDE\n" |
| + "nTYIhucEk2pmeOETnSa3gZ9+kARBBGsX0fLhLEJH+Lzm5WOkQPJ3A32BLeszoPSh\n" |
| + "OUXYmMKWT+NC4v4af5uO5+tKfA+eFivOM1drMV7Oy7ZAaDe/UfUCIQD/////AAAA\n" |
| + "AP//////////vOb6racXnoTzucrC/GMlUQIBAQNCAAQXU+GFdLabcY/RvzoNjLhC\n" |
| + "6uN1Yt1baN2NYyKYEhwR9nb8nLa/m7f30OOi/8OrxQhnUl5qW0I0IbHflGnsqQ6s\n" |
| + "MAoGCCqGSM49BAMCA0gAMEUCIQDRXoZwmnsIJfg4mTemkM+heMS1iXRYUO0Dar5u\n" |
| + "Qhy0YgIgYWr0qSCLqxUQv3oQHMUpSmfHtP0Pwvb3DbbH6lY7TkI=\n" |
| + "-----END CERTIFICATE-----\n"; |
| |
| /** |
| * This cert is signed with OID 1.2.840.113554.4.1.72585.2 instead of a |
| * standard one. |
| */ |
| private static final String UNKNOWN_SIGNATURE_OID = |
| "-----BEGIN CERTIFICATE-----\n" |
| + "MIIB2TCCAXugAwIBAgIJANlMBNpJfb/rMA4GDCqGSIb3EgQBhLcJAjBFMQswCQYD\n" |
| + "VQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQg\n" |
| + "V2lkZ2l0cyBQdHkgTHRkMB4XDTE0MDQyMzIzMjE1N1oXDTE0MDUyMzIzMjE1N1ow\n" |
| + "RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu\n" |
| + "dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA\n" |
| + "BOYraeK/ZZ+Xvi8eDZSKTNWXa7epHg1G+92pqR6d3LpaAefWl6gKGPnDxKMeVuJ8\n" |
| + "g0jbFhoc9R1+8ZQtS89yIsGjUDBOMB0GA1UdDgQWBBSrhNKsq5Xwgk4WeAdVV1/k\n" |
| + "Jo2C0TAfBgNVHSMEGDAWgBSrhNKsq5Xwgk4WeAdVV1/kJo2C0TAMBgNVHRMEBTAD\n" |
| + "AQH/MA4GDCqGSIb3EgQBhLcJAgNIADBFAiEA8qA1XlE6NsOCeZvuJ1CFjnAGdJVX\n" |
| + "0il0APS+FYddxAcCIHweeRRqIYPwenRoeV8UmZpotPHLnhVe5h8yUmFedckU\n" |
| + "-----END CERTIFICATE-----\n"; |
| |
| /** |
| * This cert is signed using MD5, which is no longer supported by BoringSSL. |
| */ |
| private static final String MD5_SIGNATURE = |
| "-----BEGIN CERTIFICATE-----\n" |
| + "MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx\n" |
| + "FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD\n" |
| + "VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv\n" |
| + "biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy\n" |
| + "dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t\n" |
| + "MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB\n" |
| + "MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG\n" |
| + "A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp\n" |
| + "b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl\n" |
| + "cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv\n" |
| + "bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE\n" |
| + "VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ\n" |
| + "ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR\n" |
| + "uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG\n" |
| + "9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI\n" |
| + "hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM\n" |
| + "pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg==\n" |
| + "-----END CERTIFICATE-----"; |
| |
| /** |
| * This is an X.509v1 certificatea, so most fields are missing. It exists to test accessors |
| * correctly handle the lack of fields. It was constructed by hand, so the signature itself is |
| * invalid. |
| */ |
| private static final String X509V1_CERT = "-----BEGIN CERTIFICATE-----\n" |
| + "MIIBGjCBwgIJANlMBNpJfb/rMAkGByqGSM49BAEwFjEUMBIGA1UEAwwLVGVzdCBJ\n" |
| + "c3N1ZXIwHhcNMTQwNDIzMjMyMTU3WhcNMTQwNTIzMjMyMTU3WjAXMRUwEwYDVQQD\n" |
| + "DAxUZXN0IFN1YmplY3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATmK2niv2Wf\n" |
| + "l74vHg2UikzVl2u3qR4NRvvdqakendy6WgHn1peoChj5w8SjHlbifINI2xYaHPUd\n" |
| + "fvGULUvPciLBMAkGByqGSM49BAEDSAAwRQIhAPKgNV5ROjbDgnmb7idQhY5wBnSV\n" |
| + "V9IpdAD0vhWHXcQHAiB8HnkUaiGD8Hp0aHlfFJmaaLTxy54VXuYfMlJhXnXJFA==\n" |
| + "-----END CERTIFICATE-----\n"; |
| |
| /** |
| * This is a certificate with many extensions filled it. It exists to test accessors correctly |
| * report fields. It was constructed by hand, so the signature itself is invalid. Add more |
| * fields as necessary with https://github.com/google/der-ascii. |
| */ |
| private static final String MANY_EXTENSIONS = "-----BEGIN CERTIFICATE-----\n" |
| + "MIIEADCCAuigAwIBAgIJALW2IrlaBKUhMA0GCSqGSIb3DQEBCwUAMBYxFDASBgNV\n" |
| + "BAMMC1Rlc3QgSXNzdWVyMB4XDTE2MDcwOTA0MzgwOVoXDTE2MDgwODA0MzgwOVow\n" |
| + "FzEVMBMGA1UEAwwMVGVzdCBTdWJqZWN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n" |
| + "MIIBCgKCAQEAugvahBkSAUF1fC49vb1bvlPrcl80kop1iLpiuYoz4Qptwy57+EWs\n" |
| + "sZBcHprZ5BkWf6PeGZ7F5AX1PyJbGHZLqvMCvViP6pd4MFox/igESISEHEixoiXC\n" |
| + "zepBrhtp5UQSjHD4D4hKtgdMgVxX+LRtwgW3mnu/vBu7rzpr/DS8io99p3lqZ1Ak\n" |
| + "y+aNlcMj6MYy8U+YFEevb/V0lRY9oqwmW7BHnXikm/vi6sjIS350U8zb/mRzYeIs\n" |
| + "2R65LUduTL50+UMgat9ocewI2dv8aO9Dph+8NdGtg8LFYyTTHcUxJoMr1PTOgnmE\n" |
| + "T19WJH4PrFwk7ZE1QJQQ1L4iKmPeQistuQIDAQABgQIEoIICA1CjggFGMIIBQjAP\n" |
| + "BgNVHRMECDAGAQH/AgEKMCEGA1UdJQQaMBgGCCsGAQUFBwMBBgwqhkiG9xIEAYS3\n" |
| + "CQIwfwYDVR0RBHgwdoETc3ViamVjdEBleGFtcGxlLmNvbYITc3ViamVjdC5leGFt\n" |
| + "cGxlLmNvbaQZMBcxFTATBgNVBAMMDFRlc3QgU3ViamVjdIYbaHR0cHM6Ly9leGFt\n" |
| + "cGxlLmNvbS9zdWJqZWN0hwR/AAABiAwqhkiG9xIEAYS3CQIwewYDVR0SBHQwcoES\n" |
| + "aXNzdWVyQGV4YW1wbGUuY29tghJpc3N1ZXIuZXhhbXBsZS5jb22kGDAWMRQwEgYD\n" |
| + "VQQDDAtUZXN0IElzc3VlcoYaaHR0cHM6Ly9leGFtcGxlLmNvbS9pc3N1ZXKHBH8A\n" |
| + "AAGIDCqGSIb3EgQBhLcJAjAOBgNVHQ8BAf8EBAMCBaAwDQYJKoZIhvcNAQELBQAD\n" |
| + "ggEBAD7Jg68SArYWlcoHfZAB90Pmyrt5H6D8LRi+W2Ri1fBNxREELnezWJ2scjl4\n" |
| + "UMcsKYp4Pi950gVN+62IgrImcCNvtb5I1Cfy/MNNur9ffas6X334D0hYVIQTePyF\n" |
| + "k3umI+2mJQrtZZyMPIKSY/sYGQHhGGX6wGK+GO/og0PQk/Vu6D+GU2XRnDV0YZg1\n" |
| + "lsAsHd21XryK6fDmNkEMwbIWrts4xc7scRrGHWy+iMf6/7p/Ak/SIicM4XSwmlQ8\n" |
| + "pPxAZPr+E2LoVd9pMpWUwpW2UbtO5wsGTrY5sO45tFNN/y+jtUheB1C2ijObG/tX\n" |
| + "ELaiyCdM+S/waeuv0MXtI4xnn1A=\n" |
| + "-----END CERTIFICATE-----\n"; |
| |
| /** |
| * This is a certificate whose basicConstraints extension marks it as a CA, with no pathlen |
| * constraint. |
| */ |
| private static final String BASIC_CONSTRAINTS_NO_PATHLEN = "-----BEGIN CERTIFICATE-----\n" |
| + "MIIBMzCB2qADAgECAgkA2UwE2kl9v+swCgYIKoZIzj0EAwIwFjEUMBIGA1UEAwwL\n" |
| + "VGVzdCBJc3N1ZXIwHhcNMTQwNDIzMjMyMTU3WhcNMTQwNTIzMjMyMTU3WjAXMRUw\n" |
| + "EwYDVQQDDAxUZXN0IFN1YmplY3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATm\n" |
| + "K2niv2Wfl74vHg2UikzVl2u3qR4NRvvdqakendy6WgHn1peoChj5w8SjHlbifINI\n" |
| + "2xYaHPUdfvGULUvPciLBoxAwDjAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0gA\n" |
| + "MEUCIQDyoDVeUTo2w4J5m+4nUIWOcAZ0lVfSKXQA9L4Vh13EBwIgfB55FGohg/B6\n" |
| + "dGh5XxSZmmi08cueFV7mHzJSYV51yRQ=\n" |
| + "-----END CERTIFICATE-----\n"; |
| |
| /** |
| * This is a certificate whose basicConstraints extension marks it as a CA with a pathlen |
| * constraint of zero. |
| */ |
| private static final String BASIC_CONSTRAINTS_PATHLEN_0 = "-----BEGIN CERTIFICATE-----\n" |
| + "MIIBNjCB3aADAgECAgkA2UwE2kl9v+swCgYIKoZIzj0EAwIwFjEUMBIGA1UEAwwL\n" |
| + "VGVzdCBJc3N1ZXIwHhcNMTQwNDIzMjMyMTU3WhcNMTQwNTIzMjMyMTU3WjAXMRUw\n" |
| + "EwYDVQQDDAxUZXN0IFN1YmplY3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATm\n" |
| + "K2niv2Wfl74vHg2UikzVl2u3qR4NRvvdqakendy6WgHn1peoChj5w8SjHlbifINI\n" |
| + "2xYaHPUdfvGULUvPciLBoxMwETAPBgNVHRMECDAGAQH/AgEAMAoGCCqGSM49BAMC\n" |
| + "A0gAMEUCIQDyoDVeUTo2w4J5m+4nUIWOcAZ0lVfSKXQA9L4Vh13EBwIgfB55FGoh\n" |
| + "g/B6dGh5XxSZmmi08cueFV7mHzJSYV51yRQ=\n" |
| + "-----END CERTIFICATE-----\n"; |
| |
| /** |
| * This is a certificate whose basicConstraints extension marks it as a leaf certificate. |
| */ |
| private static final String BASIC_CONSTRAINTS_LEAF = "-----BEGIN CERTIFICATE-----\n" |
| + "MIIBMDCB16ADAgECAgkA2UwE2kl9v+swCgYIKoZIzj0EAwIwFjEUMBIGA1UEAwwL\n" |
| + "VGVzdCBJc3N1ZXIwHhcNMTQwNDIzMjMyMTU3WhcNMTQwNTIzMjMyMTU3WjAXMRUw\n" |
| + "EwYDVQQDDAxUZXN0IFN1YmplY3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATm\n" |
| + "K2niv2Wfl74vHg2UikzVl2u3qR4NRvvdqakendy6WgHn1peoChj5w8SjHlbifINI\n" |
| + "2xYaHPUdfvGULUvPciLBow0wCzAJBgNVHRMEAjAAMAoGCCqGSM49BAMCA0gAMEUC\n" |
| + "IQDyoDVeUTo2w4J5m+4nUIWOcAZ0lVfSKXQA9L4Vh13EBwIgfB55FGohg/B6dGh5\n" |
| + "XxSZmmi08cueFV7mHzJSYV51yRQ=\n" |
| + "-----END CERTIFICATE-----\n"; |
| |
| /** |
| * This is a certificate with a pathlen constraint of 10, but there is an unrelated invalid |
| * subjectAltNames extension. |
| */ |
| private static final String BASIC_CONSTRAINTS_PATHLEN_10_BAD_SAN = |
| "-----BEGIN CERTIFICATE-----\n" |
| + "MIIBRjCB7aADAgECAgkA2UwE2kl9v+swCgYIKoZIzj0EAwIwFjEUMBIGA1UEAwwL\n" |
| + "VGVzdCBJc3N1ZXIwHhcNMTQwNDIzMjMyMTU3WhcNMTQwNTIzMjMyMTU3WjAXMRUw\n" |
| + "EwYDVQQDDAxUZXN0IFN1YmplY3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATm\n" |
| + "K2niv2Wfl74vHg2UikzVl2u3qR4NRvvdqakendy6WgHn1peoChj5w8SjHlbifINI\n" |
| + "2xYaHPUdfvGULUvPciLBoyMwITAPBgNVHRMECDAGAQH/AgEKMA4GA1UdEQQHSU5W\n" |
| + "QUxJRDAKBggqhkjOPQQDAgNIADBFAiEA8qA1XlE6NsOCeZvuJ1CFjnAGdJVX0il0\n" |
| + "APS+FYddxAcCIHweeRRqIYPwenRoeV8UmZpotPHLnhVe5h8yUmFedckU\n" |
| + "-----END CERTIFICATE-----\n"; |
| |
| /** |
| * This is a certificate whose keyUsage extension has more than nine bits. The getKeyUsage() |
| * method internally rounds up to nine bits, so this tests what happens when it does not need to |
| * round. |
| */ |
| private static final String LARGE_KEY_USAGE = "-----BEGIN CERTIFICATE-----\n" |
| + "MIIBNjCB3aADAgECAgkA2UwE2kl9v+swCgYIKoZIzj0EAwIwFjEUMBIGA1UEAwwL\n" |
| + "VGVzdCBJc3N1ZXIwHhcNMTQwNDIzMjMyMTU3WhcNMTQwNTIzMjMyMTU3WjAXMRUw\n" |
| + "EwYDVQQDDAxUZXN0IFN1YmplY3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATm\n" |
| + "K2niv2Wfl74vHg2UikzVl2u3qR4NRvvdqakendy6WgHn1peoChj5w8SjHlbifINI\n" |
| + "2xYaHPUdfvGULUvPciLBoxMwETAPBgNVHQ8BAf8EBQMDBaAAMAoGCCqGSM49BAMC\n" |
| + "A0gAMEUCIQDyoDVeUTo2w4J5m+4nUIWOcAZ0lVfSKXQA9L4Vh13EBwIgfB55FGoh\n" |
| + "g/B6dGh5XxSZmmi08cueFV7mHzJSYV51yRQ=\n" |
| + "-----END CERTIFICATE-----\n"; |
| |
| /* |
| * OpenSSLX509Certificate needs to compensate for OpenSSL's AlgorithmIdentifier representation |
| * by re-encoding the parameter field. Test this behaves correctly against a variety of |
| * different parameter types. |
| */ |
| private static final String SIGALG_NO_PARAMETER = "-----BEGIN CERTIFICATE-----\n" |
| + "MIIBKTCBzKADAgECAgkA2UwE2kl9v+swDgYMKoZIhvcSBAGEtwkCMBYxFDASBgNV\n" |
| + "BAMMC1Rlc3QgSXNzdWVyMB4XDTE0MDQyMzIzMjE1N1oXDTE0MDUyMzIzMjE1N1ow\n" |
| + "FzEVMBMGA1UEAwwMVGVzdCBTdWJqZWN0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD\n" |
| + "QgAE5itp4r9ln5e+Lx4NlIpM1Zdrt6keDUb73ampHp3culoB59aXqAoY+cPEox5W\n" |
| + "4nyDSNsWGhz1HX7xlC1Lz3IiwTAOBgwqhkiG9xIEAYS3CQIDSAAwRQIhAPKgNV5R\n" |
| + "OjbDgnmb7idQhY5wBnSVV9IpdAD0vhWHXcQHAiB8HnkUaiGD8Hp0aHlfFJmaaLTx\n" |
| + "y54VXuYfMlJhXnXJFA==\n" |
| + "-----END CERTIFICATE-----\n"; |
| private static final String SIGALG_NULL_PARAMETER = "-----BEGIN CERTIFICATE-----\n" |
| + "MIIBLTCBzqADAgECAgkA2UwE2kl9v+swEAYMKoZIhvcSBAGEtwkCBQAwFjEUMBIG\n" |
| + "A1UEAwwLVGVzdCBJc3N1ZXIwHhcNMTQwNDIzMjMyMTU3WhcNMTQwNTIzMjMyMTU3\n" |
| + "WjAXMRUwEwYDVQQDDAxUZXN0IFN1YmplY3QwWTATBgcqhkjOPQIBBggqhkjOPQMB\n" |
| + "BwNCAATmK2niv2Wfl74vHg2UikzVl2u3qR4NRvvdqakendy6WgHn1peoChj5w8Sj\n" |
| + "HlbifINI2xYaHPUdfvGULUvPciLBMBAGDCqGSIb3EgQBhLcJAgUAA0gAMEUCIQDy\n" |
| + "oDVeUTo2w4J5m+4nUIWOcAZ0lVfSKXQA9L4Vh13EBwIgfB55FGohg/B6dGh5XxSZ\n" |
| + "mmi08cueFV7mHzJSYV51yRQ=\n" |
| + "-----END CERTIFICATE-----\n"; |
| private static final String SIGALG_STRING_PARAMETER = "-----BEGIN CERTIFICATE-----\n" |
| + "MIIBNzCB06ADAgECAgkA2UwE2kl9v+swFQYMKoZIhvcSBAGEtwkCDAVwYXJhbTAW\n" |
| + "MRQwEgYDVQQDDAtUZXN0IElzc3VlcjAeFw0xNDA0MjMyMzIxNTdaFw0xNDA1MjMy\n" |
| + "MzIxNTdaMBcxFTATBgNVBAMMDFRlc3QgU3ViamVjdDBZMBMGByqGSM49AgEGCCqG\n" |
| + "SM49AwEHA0IABOYraeK/ZZ+Xvi8eDZSKTNWXa7epHg1G+92pqR6d3LpaAefWl6gK\n" |
| + "GPnDxKMeVuJ8g0jbFhoc9R1+8ZQtS89yIsEwFQYMKoZIhvcSBAGEtwkCDAVwYXJh\n" |
| + "bQNIADBFAiEA8qA1XlE6NsOCeZvuJ1CFjnAGdJVX0il0APS+FYddxAcCIHweeRRq\n" |
| + "IYPwenRoeV8UmZpotPHLnhVe5h8yUmFedckU\n" |
| + "-----END CERTIFICATE-----\n"; |
| private static final String SIGALG_BOOLEAN_PARAMETER = "-----BEGIN CERTIFICATE-----\n" |
| + "MIIBLzCBz6ADAgECAgkA2UwE2kl9v+swEQYMKoZIhvcSBAGEtwkCAQH/MBYxFDAS\n" |
| + "BgNVBAMMC1Rlc3QgSXNzdWVyMB4XDTE0MDQyMzIzMjE1N1oXDTE0MDUyMzIzMjE1\n" |
| + "N1owFzEVMBMGA1UEAwwMVGVzdCBTdWJqZWN0MFkwEwYHKoZIzj0CAQYIKoZIzj0D\n" |
| + "AQcDQgAE5itp4r9ln5e+Lx4NlIpM1Zdrt6keDUb73ampHp3culoB59aXqAoY+cPE\n" |
| + "ox5W4nyDSNsWGhz1HX7xlC1Lz3IiwTARBgwqhkiG9xIEAYS3CQIBAf8DSAAwRQIh\n" |
| + "APKgNV5ROjbDgnmb7idQhY5wBnSVV9IpdAD0vhWHXcQHAiB8HnkUaiGD8Hp0aHlf\n" |
| + "FJmaaLTxy54VXuYfMlJhXnXJFA==\n" |
| + "-----END CERTIFICATE-----\n"; |
| private static final String SIGALG_SEQUENCE_PARAMETER = "-----BEGIN CERTIFICATE-----\n" |
| + "MIIBLTCBzqADAgECAgkA2UwE2kl9v+swEAYMKoZIhvcSBAGEtwkCMAAwFjEUMBIG\n" |
| + "A1UEAwwLVGVzdCBJc3N1ZXIwHhcNMTQwNDIzMjMyMTU3WhcNMTQwNTIzMjMyMTU3\n" |
| + "WjAXMRUwEwYDVQQDDAxUZXN0IFN1YmplY3QwWTATBgcqhkjOPQIBBggqhkjOPQMB\n" |
| + "BwNCAATmK2niv2Wfl74vHg2UikzVl2u3qR4NRvvdqakendy6WgHn1peoChj5w8Sj\n" |
| + "HlbifINI2xYaHPUdfvGULUvPciLBMBAGDCqGSIb3EgQBhLcJAjAAA0gAMEUCIQDy\n" |
| + "oDVeUTo2w4J5m+4nUIWOcAZ0lVfSKXQA9L4Vh13EBwIgfB55FGohg/B6dGh5XxSZ\n" |
| + "mmi08cueFV7mHzJSYV51yRQ=\n" |
| + "-----END CERTIFICATE-----\n"; |
| |
| private static Date dateFromUTC(int year, int month, int day, int hour, int minute, int second) |
| throws Exception { |
| Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC")); |
| c.set(year, month, day, hour, minute, second); |
| c.set(Calendar.MILLISECOND, 0); |
| return c.getTime(); |
| } |
| |
| private static X509Certificate certificateFromPEM(Provider p, String pem) |
| throws CertificateException { |
| CertificateFactory cf = CertificateFactory.getInstance("X509", p); |
| return (X509Certificate) cf.generateCertificate( |
| new ByteArrayInputStream(pem.getBytes(Charset.forName("US-ASCII")))); |
| } |
| |
| private static List<Pair<Integer, String>> normalizeGeneralNames(Collection<List<?>> names) { |
| // Extract a more convenient type than Java's Collection<List<?>>. |
| List<Pair<Integer, String>> result = new ArrayList<Pair<Integer, String>>(); |
| for (List<?> tuple : names) { |
| assertEquals(2, tuple.size()); |
| int type = ((Integer) tuple.get(0)).intValue(); |
| // TODO(davidben): Most name types are expected to have a String value, but some use |
| // byte[]. Update this logic when testing those name types. See |
| // X509Certificate.getSubjectAlternativeNames(). |
| String value = (String) tuple.get(1); |
| result.add(Pair.of(type, value)); |
| } |
| // Although there is a natural order (the order in the certificate), Java's API returns a |
| // Collection, so there is no guarantee of the provider using a particular order. Normalize |
| // the order before comparing. |
| Collections.sort(result, new Comparator<Pair<Integer, String>>() { |
| @Override |
| public int compare(Pair<Integer, String> a, Pair<Integer, String> b) { |
| int cmp = a.getFirst().compareTo(b.getFirst()); |
| if (cmp != 0) { |
| return cmp; |
| } |
| return a.getSecond().compareTo(b.getSecond()); |
| } |
| }); |
| return result; |
| } |
| |
| private static void assertGeneralNamesEqual( |
| Collection<List<?>> expected, Collection<List<?>> actual) throws Exception { |
| assertEquals(normalizeGeneralNames(expected), normalizeGeneralNames(actual)); |
| } |
| |
| // Error Prone flags Date.equals(), but Instant and LocalDateTime are not available in Java 7. |
| // We could compare Date.getTime(), but this trips another warning in Error Prone. We do not use |
| // Date subclasses, so stick with Date.equals for now. |
| // |
| // https://errorprone.info/bugpattern/UndefinedEquals |
| @SuppressWarnings("UndefinedEquals") |
| private static void assertDatesEqual(Date expected, Date actual) throws Exception { |
| assertEquals(expected, actual); |
| } |
| |
| // See issue #539. |
| @Test |
| public void testMismatchedAlgorithm() throws Exception { |
| ServiceTester.test("CertificateFactory") |
| .withAlgorithm("X509") |
| .run(new ServiceTester.Test() { |
| @Override |
| public void test(Provider p, String algorithm) throws Exception { |
| try { |
| X509Certificate c = certificateFromPEM(p, MISMATCHED_ALGORITHM_CERT); |
| c.verify(c.getPublicKey()); |
| fail(); |
| } catch (CertificateException expected) { |
| } |
| } |
| }); |
| } |
| |
| /** |
| * Confirm that explicit EC params aren't accepted in certificates. |
| */ |
| @Test |
| public void testExplicitEcParams() throws Exception { |
| ServiceTester.test("CertificateFactory") |
| .withAlgorithm("X509") |
| // Bouncy Castle allows explicit EC params in certificates, even though they're |
| // barred by RFC 5480 |
| .skipProvider("BC") |
| .run(new ServiceTester.Test() { |
| @Override |
| public void test(Provider p, String algorithm) throws Exception { |
| try { |
| X509Certificate c = certificateFromPEM(p, EC_EXPLICIT_KEY_CERT); |
| c.verify(c.getPublicKey()); |
| fail(); |
| } catch (InvalidKeyException expected) { |
| // TODO: Should we throw CertificateParsingException at parse time |
| // instead of waiting for when the user accesses the key? |
| } catch (CertificateParsingException expected) { |
| } |
| } |
| }); |
| } |
| |
| @Test |
| public void testSigAlgName() throws Exception { |
| ServiceTester.test("CertificateFactory") |
| .withAlgorithm("X509") |
| .run(new ServiceTester.Test() { |
| @Override |
| public void test(Provider p, String algorithm) throws Exception { |
| X509Certificate c = certificateFromPEM(p, VALID_CERT); |
| assertEquals("SHA256WITHRSA", c.getSigAlgName().toUpperCase()); |
| c.verify(c.getPublicKey()); |
| } |
| }); |
| } |
| |
| @Test |
| public void testUnknownSigAlgOID() throws Exception { |
| ServiceTester.test("CertificateFactory") |
| .withAlgorithm("X509") |
| .run(new ServiceTester.Test() { |
| @Override |
| public void test(Provider p, String algorithm) throws Exception { |
| X509Certificate c = certificateFromPEM(p, UNKNOWN_SIGNATURE_OID); |
| assertEquals("1.2.840.113554.4.1.72585.2", c.getSigAlgOID()); |
| assertThrows(NoSuchAlgorithmException.class, () -> c.verify(c.getPublicKey())); |
| } |
| }); |
| } |
| |
| // MD5 signed certificates no longer supported by BoringSSL but still supported by OpenJDK 8 |
| // and by BC where present (up until Android 12) |
| @Test |
| public void unsupportedDigestType() { |
| ServiceTester.test("CertificateFactory") |
| .withAlgorithm("X509") |
| .skipProvider("SUN") |
| .skipProvider("BC") |
| .run(new ServiceTester.Test() { |
| @Override |
| public void test(Provider p, String algorithm) throws Exception { |
| X509Certificate c = certificateFromPEM(p, MD5_SIGNATURE); |
| assertThrows(NoSuchAlgorithmException.class, () -> c.verify(c.getPublicKey())); |
| } |
| }); |
| } |
| |
| @Test |
| public void invalidSignature() { |
| // Mutate the signature of VALID_CERT slightly |
| int index = VALID_CERT.lastIndexOf('9'); |
| assertTrue(index > 0); |
| String invalidCert = VALID_CERT.substring(0, index) + "8" + VALID_CERT.substring(index + 1); |
| ServiceTester.test("CertificateFactory") |
| .withAlgorithm("X509") |
| .run(new ServiceTester.Test() { |
| @Override |
| public void test(Provider p, String algorithm) throws Exception { |
| X509Certificate c = certificateFromPEM(p, invalidCert); |
| assertThrows(SignatureException.class, () -> c.verify(c.getPublicKey())); |
| } |
| }); |
| } |
| |
| @Test |
| public void testV1Cert() throws Exception { |
| ServiceTester tester = ServiceTester.test("CertificateFactory").withAlgorithm("X509"); |
| tester.run(new ServiceTester.Test() { |
| @Override |
| public void test(Provider p, String algorithm) throws Exception { |
| X509Certificate c = certificateFromPEM(p, X509V1_CERT); |
| |
| // Check basic certificate properties. |
| assertEquals(1, c.getVersion()); |
| assertEquals(new BigInteger("d94c04da497dbfeb", 16), c.getSerialNumber()); |
| assertDatesEqual( |
| dateFromUTC(2014, Calendar.APRIL, 23, 23, 21, 57), c.getNotBefore()); |
| assertDatesEqual(dateFromUTC(2014, Calendar.MAY, 23, 23, 21, 57), c.getNotAfter()); |
| assertEquals(new X500Principal("CN=Test Issuer"), c.getIssuerX500Principal()); |
| assertEquals(new X500Principal("CN=Test Subject"), c.getSubjectX500Principal()); |
| assertEquals("1.2.840.10045.4.1", c.getSigAlgOID()); |
| String signatureHex = "3045022100f2a0355e513a36c382799bee27" |
| + "50858e7006749557d2297400f4be15875dc4" |
| + "0702207c1e79146a2183f07a7468795f1499" |
| + "9a68b4f1cb9e155ee61f3252615e75c914"; |
| assertArrayEquals(TestUtils.decodeHex(signatureHex), c.getSignature()); |
| |
| // ECDSA signature AlgorithmIdentifiers omit parameters. |
| assertNull(c.getSigAlgParams()); |
| |
| // The certificate does not have UIDs. |
| assertNull(c.getIssuerUniqueID()); |
| assertNull(c.getSubjectUniqueID()); |
| |
| // The certificate does not have any extensions. |
| assertEquals(-1, c.getBasicConstraints()); |
| assertNull(c.getExtendedKeyUsage()); |
| assertNull(c.getIssuerAlternativeNames()); |
| assertNull(c.getKeyUsage()); |
| assertNull(c.getSubjectAlternativeNames()); |
| } |
| }); |
| } |
| |
| @Test |
| public void testManyExtensions() throws Exception { |
| ServiceTester tester = ServiceTester.test("CertificateFactory").withAlgorithm("X509"); |
| tester.run(new ServiceTester.Test() { |
| @Override |
| public void test(Provider p, String algorithm) throws Exception { |
| X509Certificate c = certificateFromPEM(p, MANY_EXTENSIONS); |
| |
| assertEquals(3, c.getVersion()); |
| assertEquals(new BigInteger("b5b622b95a04a521", 16), c.getSerialNumber()); |
| assertDatesEqual(dateFromUTC(2016, Calendar.JULY, 9, 4, 38, 9), c.getNotBefore()); |
| assertDatesEqual(dateFromUTC(2016, Calendar.AUGUST, 8, 4, 38, 9), c.getNotAfter()); |
| assertEquals(new X500Principal("CN=Test Issuer"), c.getIssuerX500Principal()); |
| assertEquals(new X500Principal("CN=Test Subject"), c.getSubjectX500Principal()); |
| assertEquals("1.2.840.113549.1.1.11", c.getSigAlgOID()); |
| String signatureHex = "3ec983af1202b61695ca077d9001f743e6ca" |
| + "bb791fa0fc2d18be5b6462d5f04dc511042e" |
| + "77b3589dac72397850c72c298a783e2f79d2" |
| + "054dfbad8882b22670236fb5be48d427f2fc" |
| + "c34dbabf5f7dab3a5f7df80f485854841378" |
| + "fc85937ba623eda6250aed659c8c3c829263" |
| + "fb181901e11865fac062be18efe88343d093" |
| + "f56ee83f865365d19c357461983596c02c1d" |
| + "ddb55ebc8ae9f0e636410cc1b216aedb38c5" |
| + "ceec711ac61d6cbe88c7faffba7f024fd222" |
| + "270ce174b09a543ca4fc4064fafe1362e855" |
| + "df69329594c295b651bb4ee70b064eb639b0" |
| + "ee39b4534dff2fa3b5485e0750b68a339b1b" |
| + "fb5710b6a2c8274cf92ff069ebafd0c5ed23" |
| + "8c679f50"; |
| assertArrayEquals(TestUtils.decodeHex(signatureHex), c.getSignature()); |
| |
| // Although documented to only return null when there are no parameters, the SUN |
| // provider also returns null when the algorithm uses an explicit parameter with a |
| // value of ASN.1 NULL. |
| if (c.getSigAlgParams() != null) { |
| assertArrayEquals(TestUtils.decodeHex("0500"), c.getSigAlgParams()); |
| } |
| |
| assertArrayEquals(new boolean[] {true, false, true, false}, c.getIssuerUniqueID()); |
| assertArrayEquals( |
| new boolean[] {false, true, false, true, false}, c.getSubjectUniqueID()); |
| assertEquals(10, c.getBasicConstraints()); |
| assertEquals(Arrays.asList("1.3.6.1.5.5.7.3.1", "1.2.840.113554.4.1.72585.2"), |
| c.getExtendedKeyUsage()); |
| |
| // TODO(davidben): Test the other name types. |
| assertGeneralNamesEqual( |
| Arrays.<List<?>>asList(Arrays.asList(1, "issuer@example.com"), |
| Arrays.asList(2, "issuer.example.com"), |
| Arrays.asList(4, "CN=Test Issuer"), |
| Arrays.asList(6, "https://example.com/issuer"), |
| // TODO(https://github.com/google/conscrypt/issues/938): Fix IPv6 |
| // handling and include it in this test. |
| Arrays.asList(7, "127.0.0.1"), |
| Arrays.asList(8, "1.2.840.113554.4.1.72585.2")), |
| c.getIssuerAlternativeNames()); |
| assertGeneralNamesEqual( |
| Arrays.<List<?>>asList(Arrays.asList(1, "subject@example.com"), |
| Arrays.asList(2, "subject.example.com"), |
| Arrays.asList(4, "CN=Test Subject"), |
| Arrays.asList(6, "https://example.com/subject"), |
| // TODO(https://github.com/google/conscrypt/issues/938): Fix IPv6 |
| // handling and include it in this test. |
| Arrays.asList(7, "127.0.0.1"), |
| Arrays.asList(8, "1.2.840.113554.4.1.72585.2")), |
| c.getSubjectAlternativeNames()); |
| |
| // Although the BIT STRING in the certificate only has three bits, getKeyUsage() |
| // rounds up to at least 9 bits. |
| assertArrayEquals( |
| new boolean[] {true, false, true, false, false, false, false, false, false}, |
| c.getKeyUsage()); |
| } |
| }); |
| } |
| |
| @Test |
| public void testBasicConstraints() throws Exception { |
| ServiceTester tester = ServiceTester.test("CertificateFactory").withAlgorithm("X509"); |
| tester.run(new ServiceTester.Test() { |
| @Override |
| public void test(Provider p, String algorithm) throws Exception { |
| // Test some additional edge cases in getBasicConstraints() beyond that |
| // testManyExtensions() and testV1Cert() covered. |
| |
| // If there is no pathLen constraint but the certificate is a CA, |
| // getBasicConstraints() returns Integer.MAX_VALUE. |
| X509Certificate c = certificateFromPEM(p, BASIC_CONSTRAINTS_NO_PATHLEN); |
| assertEquals(Integer.MAX_VALUE, c.getBasicConstraints()); |
| |
| // If there is a pathLen constraint of zero, getBasicConstraints() returns it. |
| c = certificateFromPEM(p, BASIC_CONSTRAINTS_PATHLEN_0); |
| assertEquals(0, c.getBasicConstraints()); |
| |
| // If there is basicConstraints extension indicating a leaf certficate, |
| // getBasicConstraints() returns -1. The accessor does not distinguish between no |
| // basicConstraints extension and a leaf one. |
| c = certificateFromPEM(p, BASIC_CONSTRAINTS_LEAF); |
| assertEquals(-1, c.getBasicConstraints()); |
| |
| // If some unrelated extension has a syntax error, and that syntax error does not |
| // fail when constructing the certificate, it should not interfere with |
| // getBasicConstraints(). |
| try { |
| c = certificateFromPEM(p, BASIC_CONSTRAINTS_PATHLEN_10_BAD_SAN); |
| } catch (CertificateParsingException e) { |
| // The certificate has a syntax error, so it would also be valid for the |
| // provider to reject the certificate at construction. X.509 is an extensible |
| // format, so different implementations may notice errors at different points. |
| c = null; |
| } |
| if (c != null) { |
| assertEquals(10, c.getBasicConstraints()); |
| } |
| } |
| }); |
| } |
| |
| @Test |
| public void testLargeKeyUsage() throws Exception { |
| ServiceTester tester = ServiceTester.test("CertificateFactory").withAlgorithm("X509"); |
| tester.run(new ServiceTester.Test() { |
| @Override |
| public void test(Provider p, String algorithm) throws Exception { |
| X509Certificate c = certificateFromPEM(p, LARGE_KEY_USAGE); |
| assertArrayEquals(new boolean[] {true, false, true, false, false, false, false, |
| false, false, false, false}, |
| c.getKeyUsage()); |
| } |
| }); |
| } |
| |
| @Test |
| public void testSigAlgParams() throws Exception { |
| ServiceTester tester = ServiceTester.test("CertificateFactory").withAlgorithm("X509"); |
| tester.run(new ServiceTester.Test() { |
| @Override |
| public void test(Provider p, String algorithm) throws Exception { |
| X509Certificate c = certificateFromPEM(p, SIGALG_NO_PARAMETER); |
| assertNull(c.getSigAlgParams()); |
| |
| c = certificateFromPEM(p, SIGALG_NULL_PARAMETER); |
| // Although documented to only return null when there are no parameters, the SUN |
| // provider also returns null when the algorithm uses an explicit parameter with a |
| // value of ASN.1 NULL. |
| if (c.getSigAlgParams() != null) { |
| assertArrayEquals(TestUtils.decodeHex("0500"), c.getSigAlgParams()); |
| } |
| |
| c = certificateFromPEM(p, SIGALG_STRING_PARAMETER); |
| assertArrayEquals(TestUtils.decodeHex("0c05706172616d"), c.getSigAlgParams()); |
| |
| c = certificateFromPEM(p, SIGALG_BOOLEAN_PARAMETER); |
| assertArrayEquals(TestUtils.decodeHex("0101ff"), c.getSigAlgParams()); |
| |
| c = certificateFromPEM(p, SIGALG_SEQUENCE_PARAMETER); |
| assertArrayEquals(TestUtils.decodeHex("3000"), c.getSigAlgParams()); |
| } |
| }); |
| } |
| } |