| /* |
| * Copyright (C) 2012 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 libcore.java.security.cert; |
| |
| import org.apache.harmony.security.utils.AlgNameMapper; |
| |
| import tests.support.resource.Support_Resources; |
| |
| import java.io.BufferedInputStream; |
| import java.io.BufferedReader; |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.DataInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.io.ObjectInputStream; |
| import java.io.ObjectOutputStream; |
| import java.io.PrintStream; |
| import java.math.BigInteger; |
| import java.security.KeyFactory; |
| import java.security.KeyPair; |
| import java.security.KeyPairGenerator; |
| import java.security.Principal; |
| import java.security.Provider; |
| import java.security.PublicKey; |
| import java.security.Security; |
| import java.security.SignatureException; |
| import java.security.cert.Certificate; |
| import java.security.cert.CertificateException; |
| import java.security.cert.CertificateExpiredException; |
| import java.security.cert.CertificateFactory; |
| import java.security.cert.CertificateNotYetValidException; |
| import java.security.cert.CertificateParsingException; |
| import java.security.cert.X509Certificate; |
| import java.security.spec.X509EncodedKeySpec; |
| import java.text.SimpleDateFormat; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Calendar; |
| import java.util.Collection; |
| import java.util.Date; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Set; |
| |
| import javax.security.auth.x500.X500Principal; |
| |
| import junit.framework.TestCase; |
| import libcore.java.security.StandardNames; |
| |
| public class X509CertificateTest extends TestCase { |
| private Provider[] mX509Providers; |
| |
| private static final String CERT_RSA = "x509/cert-rsa.der"; |
| |
| private static final String CERT_DSA = "x509/cert-dsa.der"; |
| |
| private static final String CERT_EC = "x509/cert-ec.der"; |
| |
| private static final String CERT_KEYUSAGE_EXTRALONG = "x509/cert-keyUsage-extraLong.der"; |
| |
| private static final String CERT_EXTENDEDKEYUSAGE = "x509/cert-extendedKeyUsage.der"; |
| |
| private final static String CERT_RSA_TBS = "x509/cert-rsa-tbs.der"; |
| |
| private final static String CERT_RSA_SIGNATURE = "x509/cert-rsa-sig.der"; |
| |
| private static final String CERT_USERWITHPATHLEN = "x509/cert-userWithPathLen.der"; |
| |
| private static final String CERT_CA = "x509/cert-ca.der"; |
| |
| private static final String CERT_CAWITHPATHLEN = "x509/cert-caWithPathLen.der"; |
| |
| private static final String CERT_INVALIDIP = "x509/cert-invalidip.der"; |
| |
| private static final String CERT_IPV6 = "x509/cert-ipv6.der"; |
| |
| private static final String CERT_ALT_OTHER = "x509/cert-alt-other.der"; |
| |
| private static final String CERT_ALT_EMAIL = "x509/cert-alt-email.der"; |
| |
| private static final String CERT_ALT_DNS = "x509/cert-alt-dns.der"; |
| |
| private static final String CERT_ALT_DIRNAME = "x509/cert-alt-dirname.der"; |
| |
| private static final String CERT_ALT_URI = "x509/cert-alt-uri.der"; |
| |
| private static final String CERT_ALT_RID = "x509/cert-alt-rid.der"; |
| |
| private static final String CERT_ALT_NONE = "x509/cert-alt-none.der"; |
| |
| private static final String CERT_UNSUPPORTED = "x509/cert-unsupported.der"; |
| |
| private static final String CERT_SIGOPT = "x509/cert-sigopt.der"; |
| |
| private static final String CERTS_X509_PEM = "x509/certs.pem"; |
| |
| private static final String CERTS_X509_DER = "x509/certs.der"; |
| |
| private static final String CERTS_PKCS7_PEM = "x509/certs-pk7.pem"; |
| |
| private static final String CERTS_PKCS7_DER = "x509/certs-pk7.der"; |
| |
| /** A list of certs that are all slightly different. */ |
| private static final String[] VARIOUS_CERTS = new String[] { |
| CERT_RSA, CERT_DSA, CERT_EC, |
| }; |
| |
| private final X509Certificate getCertificate(CertificateFactory f, String name) |
| throws Exception { |
| final InputStream is = Support_Resources.getStream(name); |
| assertNotNull("File does not exist: " + name, is); |
| try { |
| return (X509Certificate) f.generateCertificate(is); |
| } finally { |
| try { |
| is.close(); |
| } catch (IOException ignored) { |
| } |
| } |
| } |
| |
| private final Collection<? extends X509Certificate> getCertificates(CertificateFactory f, String name) |
| throws Exception { |
| final InputStream is = Support_Resources.getStream(name); |
| assertNotNull("File does not exist: " + name, is); |
| try { |
| return (Collection<? extends X509Certificate>) f.generateCertificates(is); |
| } finally { |
| try { |
| is.close(); |
| } catch (IOException ignored) { |
| } |
| } |
| } |
| |
| private PublicKey getRsaCertificatePublicKey() throws Exception { |
| final InputStream ris = Support_Resources.getStream("x509/cert-rsa-pubkey.der"); |
| try { |
| final int size = ris.available(); |
| final DataInputStream is = new DataInputStream(ris); |
| final byte[] keyBytes = new byte[size]; |
| is.readFully(keyBytes); |
| |
| final KeyFactory kf = KeyFactory.getInstance("RSA"); |
| return kf.generatePublic(new X509EncodedKeySpec(keyBytes)); |
| } finally { |
| try { |
| ris.close(); |
| } catch (IOException ignored) { |
| } |
| } |
| } |
| |
| private Date[] getRsaCertificateDates() throws Exception { |
| final InputStream ris = Support_Resources.getStream("x509/cert-rsa-dates.txt"); |
| try { |
| // notBefore=Dec 26 00:19:14 2012 GMT |
| final SimpleDateFormat sdf = |
| new SimpleDateFormat("MMM dd HH:mm:ss yyyy zzz", Locale.US); |
| |
| final BufferedReader buf = new BufferedReader(new InputStreamReader(ris)); |
| String line = buf.readLine(); |
| int index = line.indexOf('='); |
| assertEquals("notBefore", line.substring(0, index)); |
| final Date startDate = sdf.parse(line.substring(index + 1)); |
| |
| line = buf.readLine(); |
| index = line.indexOf('='); |
| assertEquals("notAfter", line.substring(0, index)); |
| final Date endDate = sdf.parse(line.substring(index + 1)); |
| |
| assertTrue(startDate.before(endDate)); |
| assertTrue(endDate.after(startDate)); |
| |
| return new Date[] { startDate, endDate }; |
| } finally { |
| try { |
| ris.close(); |
| } catch (IOException ignored) { |
| } |
| } |
| } |
| |
| private BigInteger getRsaCertificateSerial() throws Exception { |
| final InputStream ris = Support_Resources.getStream("x509/cert-rsa-serial.txt"); |
| try { |
| final BufferedReader buf = new BufferedReader(new InputStreamReader(ris)); |
| |
| String line = buf.readLine(); |
| int index = line.indexOf('='); |
| assertEquals("serial", line.substring(0, index)); |
| |
| return new BigInteger(line.substring(index + 1), 16); |
| } finally { |
| try { |
| ris.close(); |
| } catch (IOException ignored) { |
| } |
| } |
| } |
| |
| private byte[] getResourceAsBytes(String name) throws Exception { |
| final InputStream ris = Support_Resources.getStream(name); |
| try { |
| DataInputStream dis = new DataInputStream(ris); |
| byte[] buf = new byte[ris.available()]; |
| dis.readFully(buf); |
| return buf; |
| } finally { |
| try { |
| ris.close(); |
| } catch (IOException ignored) { |
| } |
| } |
| } |
| |
| private byte[] getRsaCertificateSignature() throws Exception { |
| return getResourceAsBytes(CERT_RSA_SIGNATURE); |
| } |
| |
| private byte[] getRsaCertificateTbs() throws Exception { |
| return getResourceAsBytes(CERT_RSA_TBS); |
| } |
| |
| public void test_Provider() throws Exception { |
| final ByteArrayOutputStream errBuffer = new ByteArrayOutputStream(); |
| PrintStream out = new PrintStream(errBuffer); |
| |
| for (Provider p : mX509Providers) { |
| try { |
| CertificateFactory f = CertificateFactory.getInstance("X.509", p); |
| getPublicKey(f); |
| getType(f); |
| check_equals(f); |
| check_toString(f); |
| check_hashCode(f); |
| checkValidity(f); |
| getVersion(f); |
| getSerialNumber(f); |
| getIssuerDN(f); |
| getIssuerX500Principal(f); |
| getSubjectDN(f); |
| getSubjectUniqueID(f); |
| getSubjectX500Principal(f); |
| getNotBeforeAndNotAfterDates(f); |
| getSigAlgName(f); |
| getSigAlgOID(f); |
| getSigAlgParams(f); |
| getIssuerUniqueID(f); |
| getSubjectUniqueID(f); |
| getKeyUsage(f); |
| getExtendedKeyUsage(f); |
| getBasicConstraints(f); |
| getSubjectAlternativeNames(f); |
| getSubjectAlternativeNames_IPV6(f); |
| getSubjectAlternativeNames_InvalidIP(f); |
| getSubjectAlternativeNames_Other(f); |
| getSubjectAlternativeNames_Email(f); |
| getSubjectAlternativeNames_DNS(f); |
| getSubjectAlternativeNames_DirName(f); |
| getSubjectAlternativeNames_URI(f); |
| getSubjectAlternativeNames_RID(f); |
| getSubjectAlternativeNames_None(f); |
| getIssuerAlternativeNames(f); |
| getTBSCertificate(f); |
| getSignature(f); |
| hasUnsupportedCriticalExtension(f); |
| getEncoded(f); |
| verify(f); |
| generateCertificate_PEM_TrailingData(f); |
| generateCertificate_DER_TrailingData(f); |
| generateCertificates_X509_PEM(f); |
| generateCertificates_X509_DER(f); |
| generateCertificates_PKCS7_PEM(f); |
| generateCertificates_PKCS7_DER(f); |
| generateCertificates_Empty(f); |
| generateCertificates_X509_PEM_TrailingData(f); |
| generateCertificates_X509_DER_TrailingData(f); |
| generateCertificates_PKCS7_PEM_TrailingData(f); |
| generateCertificates_PKCS7_DER_TrailingData(f); |
| test_Serialization(f); |
| test_UnknownUnmappedKeyOID(f); |
| test_UnknownMappedKeyOID(f); |
| } catch (Throwable e) { |
| out.append("Error encountered checking " + p.getName() + "\n"); |
| e.printStackTrace(out); |
| } |
| } |
| |
| out.flush(); |
| if (errBuffer.size() > 0) { |
| throw new Exception("Errors encountered:\n\n" + errBuffer.toString() + "\n\n"); |
| } |
| } |
| |
| private void getPublicKey(CertificateFactory f) throws Exception { |
| X509Certificate c = getCertificate(f, CERT_RSA); |
| PublicKey expected = getRsaCertificatePublicKey(); |
| |
| PublicKey actual = c.getPublicKey(); |
| assertEquals(expected, actual); |
| assertEquals(Arrays.toString(expected.getEncoded()), |
| Arrays.toString(actual.getEncoded())); |
| } |
| |
| private void getType(CertificateFactory f) throws Exception { |
| X509Certificate c = getCertificate(f, CERT_RSA); |
| assertEquals("X.509", c.getType()); |
| } |
| |
| private void verify(CertificateFactory f) throws Exception { |
| X509Certificate c = getCertificate(f, CERT_RSA); |
| PublicKey signer = getRsaCertificatePublicKey(); |
| |
| c.verify(signer); |
| |
| KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); |
| KeyPair pair = kpg.generateKeyPair(); |
| PublicKey invalidKey = pair.getPublic(); |
| |
| try { |
| c.verify(invalidKey); |
| fail("RSA signature should not verify"); |
| } catch (SignatureException expected) { |
| } |
| |
| Provider[] providers = Security.getProviders("Signature." + c.getSigAlgName()); |
| for (Provider p : providers) { |
| c.verify(signer, p.getName()); |
| |
| try { |
| c.verify(invalidKey, p.getName()); |
| fail("RSA signature should not verify"); |
| } catch (SignatureException expected) { |
| } |
| } |
| } |
| |
| private void check_equals(CertificateFactory f) throws Exception { |
| X509Certificate c1 = getCertificate(f, CERT_RSA); |
| X509Certificate c2 = getCertificate(f, CERT_RSA); |
| |
| assertEquals(c1, c2); |
| |
| X509Certificate c3 = getCertificate(f, CERT_DSA); |
| assertFalse(c1.equals(c3)); |
| assertFalse(c3.equals(c1)); |
| } |
| |
| private void check_toString(CertificateFactory f) throws Exception { |
| X509Certificate c1 = getCertificate(f, CERT_RSA); |
| |
| String output1 = c1.toString(); |
| assertNotNull(output1); |
| assertTrue(output1.length() > 0); |
| |
| X509Certificate c2 = getCertificate(f, CERT_RSA); |
| assertEquals(c1.toString(), c2.toString()); |
| |
| X509Certificate c3 = getCertificate(f, CERT_DSA); |
| assertFalse(c3.toString().equals(c1.toString())); |
| } |
| |
| private void check_hashCode(CertificateFactory f) throws Exception { |
| X509Certificate c1 = getCertificate(f, CERT_RSA); |
| X509Certificate c2 = getCertificate(f, CERT_RSA); |
| |
| assertEquals(c1.hashCode(), c2.hashCode()); |
| |
| X509Certificate c3 = getCertificate(f, CERT_DSA); |
| assertFalse(c3.hashCode() == c1.hashCode()); |
| } |
| |
| private void checkValidity(CertificateFactory f) throws Exception { |
| X509Certificate c = getCertificate(f, CERT_RSA); |
| Calendar cal = Calendar.getInstance(); |
| Date[] dates = getRsaCertificateDates(); |
| |
| /* |
| * The certificate validity periods in the test certificate MUST lie |
| * within the tested period. The API doesn't appear to allow any other |
| * way to test this code path as an unprivileged user. |
| */ |
| Date now = new Date(); |
| assertTrue(now.after(dates[0])); |
| assertTrue(now.before(dates[1])); |
| |
| /* This assumes the script makes a long-lived cert. */ |
| c.checkValidity(); |
| |
| /* A day after the start date. */ |
| cal.setTime(dates[0]); |
| cal.add(Calendar.DAY_OF_MONTH, 1); |
| c.checkValidity(cal.getTime()); |
| |
| /* A second before the start date. */ |
| cal.setTime(dates[1]); |
| cal.add(Calendar.SECOND, -1); |
| c.checkValidity(cal.getTime()); |
| |
| try { |
| cal.setTime(dates[0]); |
| cal.add(Calendar.SECOND, -1); |
| c.checkValidity(cal.getTime()); |
| fail(); |
| } catch (CertificateNotYetValidException expected) { |
| } |
| |
| try { |
| cal.setTime(dates[0]); |
| cal.add(Calendar.MONTH, -6); |
| c.checkValidity(cal.getTime()); |
| fail(); |
| } catch (CertificateNotYetValidException expected) { |
| } |
| |
| try { |
| cal.setTime(dates[1]); |
| cal.add(Calendar.SECOND, 1); |
| c.checkValidity(cal.getTime()); |
| fail(); |
| } catch (CertificateExpiredException expected) { |
| } |
| |
| try { |
| cal.setTime(dates[1]); |
| cal.add(Calendar.YEAR, 1); |
| c.checkValidity(cal.getTime()); |
| fail(); |
| } catch (CertificateExpiredException expected) { |
| } |
| } |
| |
| private void getVersion(CertificateFactory f) throws Exception { |
| X509Certificate c = getCertificate(f, CERT_RSA); |
| assertEquals(3, c.getVersion()); |
| } |
| |
| private void getSerialNumber(CertificateFactory f) throws Exception { |
| X509Certificate c = getCertificate(f, CERT_RSA); |
| BigInteger actual = getRsaCertificateSerial(); |
| |
| assertEquals(actual, c.getSerialNumber()); |
| } |
| |
| private void getIssuerDN(CertificateFactory f) throws Exception { |
| X509Certificate c = getCertificate(f, CERT_RSA); |
| |
| Principal princ = c.getIssuerDN(); |
| if (StandardNames.IS_RI) { |
| assertEquals("OU=NetOps, O=Genius.com Inc, L=San Mateo, ST=California, C=US", |
| princ.getName()); |
| } else { |
| if ("BC".equals(f.getProvider().getName())) { |
| // TODO: is it acceptable to have this in reverse order? |
| assertEquals(f.getProvider().getName(), |
| "C=US,ST=California,L=San Mateo,O=Genius.com Inc,OU=NetOps", |
| princ.getName()); |
| } else { |
| assertEquals("OU=NetOps,O=Genius.com Inc,L=San Mateo,ST=California,C=US", |
| princ.getName()); |
| } |
| } |
| |
| X509Certificate c2 = getCertificate(f, CERT_RSA); |
| assertEquals(princ, c2.getIssuerDN()); |
| } |
| |
| private void getIssuerX500Principal(CertificateFactory f) throws Exception { |
| X509Certificate c = getCertificate(f, CERT_RSA); |
| |
| final byte[] expected = new byte[] { |
| 0x30, 0x60, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, |
| 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, |
| 0x13, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, |
| 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x09, 0x53, |
| 0x61, 0x6e, 0x20, 0x4d, 0x61, 0x74, 0x65, 0x6f, 0x31, 0x17, 0x30, 0x15, |
| 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x47, 0x65, 0x6e, 0x69, 0x75, |
| 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x0f, 0x30, |
| 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x06, 0x4e, 0x65, 0x74, 0x4f, |
| 0x70, 0x73 |
| }; |
| X500Principal princ = c.getIssuerX500Principal(); |
| assertEquals(Arrays.toString(expected), |
| Arrays.toString(princ.getEncoded())); |
| assertEquals("OU=NetOps,O=Genius.com Inc,L=San Mateo,ST=California,C=US", |
| princ.getName()); |
| assertEquals("ou=netops,o=genius.com inc,l=san mateo,st=california,c=us", |
| princ.getName(X500Principal.CANONICAL)); |
| assertEquals("OU=NetOps, O=Genius.com Inc, L=San Mateo, ST=California, C=US", |
| princ.getName(X500Principal.RFC1779)); |
| assertEquals("OU=NetOps,O=Genius.com Inc,L=San Mateo,ST=California,C=US", |
| princ.getName(X500Principal.RFC2253)); |
| |
| X509Certificate c2 = getCertificate(f, CERT_RSA); |
| assertEquals(princ, c2.getIssuerX500Principal()); |
| } |
| |
| private void getSubjectDN(CertificateFactory f) throws Exception { |
| X509Certificate c = getCertificate(f, CERT_RSA); |
| |
| Principal princ = c.getSubjectDN(); |
| if (StandardNames.IS_RI) { |
| assertEquals("OU=NetOps, O=Genius.com Inc, L=San Mateo, ST=California, C=US", |
| princ.getName()); |
| } else { |
| if ("BC".equals(f.getProvider().getName())) { |
| // TODO: is it acceptable to have this in reverse order? |
| assertEquals(f.getProvider().getName(), |
| "C=US,ST=California,L=San Mateo,O=Genius.com Inc,OU=NetOps", |
| princ.getName()); |
| } else { |
| assertEquals("OU=NetOps,O=Genius.com Inc,L=San Mateo,ST=California,C=US", |
| princ.getName()); |
| } |
| } |
| |
| X509Certificate c2 = getCertificate(f, CERT_RSA); |
| assertEquals(princ, c2.getSubjectDN()); |
| } |
| |
| private void getSubjectUniqueID(CertificateFactory f) throws Exception { |
| /* This certificate has no unique ID. */ |
| X509Certificate c = getCertificate(f, CERT_RSA); |
| assertNull(c.getSubjectUniqueID()); |
| |
| // TODO: generate certificate that has a SubjectUniqueID field. |
| } |
| |
| private void getIssuerUniqueID(CertificateFactory f) throws Exception { |
| /* This certificate has no unique ID. */ |
| X509Certificate c = getCertificate(f, CERT_RSA); |
| assertNull(c.getIssuerUniqueID()); |
| |
| // TODO: generate certificate that has a IssuerUniqueID field. |
| } |
| |
| private void getSubjectX500Principal(CertificateFactory f) throws Exception { |
| X509Certificate c = getCertificate(f, CERT_RSA); |
| |
| final byte[] expected = new byte[] { |
| 0x30, 0x60, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, |
| 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, |
| 0x13, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, |
| 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x09, 0x53, |
| 0x61, 0x6e, 0x20, 0x4d, 0x61, 0x74, 0x65, 0x6f, 0x31, 0x17, 0x30, 0x15, |
| 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x47, 0x65, 0x6e, 0x69, 0x75, |
| 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x0f, 0x30, |
| 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x06, 0x4e, 0x65, 0x74, 0x4f, |
| 0x70, 0x73 |
| }; |
| X500Principal princ = c.getSubjectX500Principal(); |
| assertEquals(Arrays.toString(expected), |
| Arrays.toString(princ.getEncoded())); |
| assertEquals("OU=NetOps,O=Genius.com Inc,L=San Mateo,ST=California,C=US", |
| princ.getName()); |
| assertEquals("ou=netops,o=genius.com inc,l=san mateo,st=california,c=us", |
| princ.getName(X500Principal.CANONICAL)); |
| assertEquals("OU=NetOps, O=Genius.com Inc, L=San Mateo, ST=California, C=US", |
| princ.getName(X500Principal.RFC1779)); |
| assertEquals("OU=NetOps,O=Genius.com Inc,L=San Mateo,ST=California,C=US", |
| princ.getName(X500Principal.RFC2253)); |
| |
| X509Certificate c2 = getCertificate(f, CERT_RSA); |
| assertEquals(princ, c2.getSubjectX500Principal()); |
| } |
| |
| private static void assertDateEquals(Date date1, Date date2) throws Exception { |
| SimpleDateFormat formatter = new SimpleDateFormat("dd MMM yyyy HH:mm:ss"); |
| |
| String result1 = formatter.format(date1); |
| String result2 = formatter.format(date2); |
| |
| assertEquals(result1, result2); |
| } |
| |
| private void getNotBeforeAndNotAfterDates(CertificateFactory f) throws Exception { |
| X509Certificate c = getCertificate(f, CERT_RSA); |
| Date[] dates = getRsaCertificateDates(); |
| |
| assertDateEquals(dates[0], c.getNotBefore()); |
| assertDateEquals(dates[1], c.getNotAfter()); |
| } |
| |
| private void getSigAlgName(CertificateFactory f) throws Exception { |
| { |
| /* The test certificate is sha1WithRSAEncryption */ |
| X509Certificate c = getCertificate(f, CERT_RSA); |
| assertEquals("SHA1WITHRSA", c.getSigAlgName().toUpperCase(Locale.US)); |
| } |
| |
| { |
| /* The test certificate is sha1WithRSAEncryption */ |
| X509Certificate c = getCertificate(f, CERT_DSA); |
| assertEquals("SHA1WITHDSA", c.getSigAlgName().toUpperCase(Locale.US)); |
| } |
| |
| { |
| /* The test certificate is sha1WithRSAEncryption */ |
| X509Certificate c = getCertificate(f, CERT_EC); |
| if (StandardNames.IS_RI) { |
| assertEquals("SHA1WITHECDSA", c.getSigAlgName().toUpperCase(Locale.US)); |
| } else { |
| assertEquals("ECDSA", c.getSigAlgName().toUpperCase(Locale.US)); |
| } |
| } |
| } |
| |
| private void getSigAlgOID(CertificateFactory f) throws Exception { |
| { |
| /* The test certificate is sha1WithRSAEncryption */ |
| X509Certificate c = getCertificate(f, CERT_RSA); |
| assertEquals("1.2.840.113549.1.1.5", c.getSigAlgOID()); |
| } |
| |
| { |
| /* The test certificate is sha1WithRSAEncryption */ |
| X509Certificate c = getCertificate(f, CERT_DSA); |
| assertEquals("1.2.840.10040.4.3", c.getSigAlgOID()); |
| } |
| |
| { |
| /* The test certificate is sha1WithRSAEncryption */ |
| X509Certificate c = getCertificate(f, CERT_EC); |
| assertEquals("1.2.840.10045.4.1", c.getSigAlgOID()); |
| } |
| } |
| |
| private void getSigAlgParams(CertificateFactory f) throws Exception { |
| { |
| X509Certificate c = getCertificate(f, CERT_RSA); |
| // RI appears to disagree |
| if (StandardNames.IS_RI) { |
| assertNull(f.getProvider().getName(), c.getSigAlgParams()); |
| } else { |
| assertNotNull(f.getProvider().getName(), c.getSigAlgParams()); |
| } |
| } |
| |
| { |
| X509Certificate c = getCertificate(f, CERT_DSA); |
| assertNull(f.getProvider().getName(), c.getSigAlgParams()); |
| } |
| |
| { |
| X509Certificate c = getCertificate(f, CERT_EC); |
| assertNull(f.getProvider().getName(), c.getSigAlgParams()); |
| } |
| |
| { |
| X509Certificate c = getCertificate(f, CERT_SIGOPT); |
| |
| /* SEQUENCE, INTEGER 1 */ |
| final byte[] expected = new byte[] { |
| /* SEQUENCE, constructed, len=5 */ |
| (byte) 0x30, (byte) 0x05, |
| /* Type=2, constructed, context-specific, len=3 */ |
| (byte) 0xA2, (byte) 0x03, |
| /* INTEGER, len=1, value=1 */ |
| (byte) 0x02, (byte) 0x01, (byte) 0x01, |
| }; |
| |
| final byte[] params = c.getSigAlgParams(); |
| assertNotNull(f.getProvider().getName(), params); |
| assertEquals(Arrays.toString(expected), Arrays.toString(params)); |
| } |
| } |
| |
| private void getKeyUsage(CertificateFactory f) throws Exception { |
| { |
| /* The test certificate is sha1WithRSAEncryption */ |
| X509Certificate c = getCertificate(f, CERT_RSA); |
| boolean[] expected = new boolean[] { |
| true, /* digitalSignature (0) */ |
| true, /* nonRepudiation (1) */ |
| true, /* keyEncipherment (2) */ |
| false, /* dataEncipherment (3) */ |
| false, /* keyAgreement (4) */ |
| false, /* keyCertSign (5) */ |
| false, /* cRLSign (6) */ |
| false, /* encipherOnly (7) */ |
| false, /* decipherOnly (8) */ |
| }; |
| assertEquals(Arrays.toString(expected), Arrays.toString(c.getKeyUsage())); |
| } |
| |
| { |
| /* The test certificate is sha1WithRSAEncryption */ |
| X509Certificate c = getCertificate(f, CERT_DSA); |
| boolean[] expected = new boolean[] { |
| false, /* digitalSignature (0) */ |
| false, /* nonRepudiation (1) */ |
| true, /* keyEncipherment (2) */ |
| true, /* dataEncipherment (3) */ |
| false, /* keyAgreement (4) */ |
| true, /* keyCertSign (5) */ |
| true, /* cRLSign (6) */ |
| true, /* encipherOnly (7) */ |
| false, /* decipherOnly (8) */ |
| }; |
| boolean[] actual = c.getKeyUsage(); |
| assertEquals(9, actual.length); |
| assertEquals(Arrays.toString(expected), Arrays.toString(actual)); |
| } |
| |
| { |
| /* The test certificate is sha1WithRSAEncryption */ |
| X509Certificate c = getCertificate(f, CERT_EC); |
| boolean[] expected = new boolean[] { |
| false, /* digitalSignature (0) */ |
| false, /* nonRepudiation (1) */ |
| false, /* keyEncipherment (2) */ |
| false, /* dataEncipherment (3) */ |
| true, /* keyAgreement (4) */ |
| false, /* keyCertSign (5) */ |
| false, /* cRLSign (6) */ |
| false, /* encipherOnly (7) */ |
| true, /* decipherOnly (8) */ |
| }; |
| boolean[] actual = c.getKeyUsage(); |
| assertEquals(9, actual.length); |
| assertEquals(Arrays.toString(expected), Arrays.toString(actual)); |
| } |
| |
| { |
| /* All the bits are set in addition to some extra ones. */ |
| X509Certificate c = getCertificate(f, CERT_KEYUSAGE_EXTRALONG); |
| boolean[] expected = new boolean[] { |
| true, /* digitalSignature (0) */ |
| true, /* nonRepudiation (1) */ |
| true, /* keyEncipherment (2) */ |
| true, /* dataEncipherment (3) */ |
| true, /* keyAgreement (4) */ |
| true, /* keyCertSign (5) */ |
| true, /* cRLSign (6) */ |
| true, /* encipherOnly (7) */ |
| true, /* decipherOnly (8) */ |
| true, /* ????? (9) */ |
| true, /* ????? (10) */ |
| }; |
| boolean[] actual = c.getKeyUsage(); |
| assertEquals(11, actual.length); |
| assertEquals(Arrays.toString(expected), Arrays.toString(actual)); |
| } |
| } |
| |
| private void getExtendedKeyUsage(CertificateFactory f) throws Exception { |
| { |
| /* No ExtendedKeyUsage section */ |
| final X509Certificate c = getCertificate(f, CERT_RSA); |
| List<String> actual = c.getExtendedKeyUsage(); |
| assertNull(actual); |
| } |
| |
| { |
| /* ExtendedKeyUsage section with one entry of OID 1.2.3.4 */ |
| final X509Certificate c = getCertificate(f, CERT_EXTENDEDKEYUSAGE); |
| List<String> actual = c.getExtendedKeyUsage(); |
| assertNotNull(actual); |
| assertEquals(1, actual.size()); |
| assertEquals("1.2.3.4", actual.get(0)); |
| } |
| } |
| |
| private void getBasicConstraints(CertificateFactory f) throws Exception { |
| /* Non-CA cert with no pathLenConstraint */ |
| { |
| final X509Certificate c = getCertificate(f, CERT_RSA); |
| assertEquals(f.getProvider().getName(), -1, c.getBasicConstraints()); |
| } |
| |
| /* Non-CA cert with pathLenConstraint */ |
| { |
| final X509Certificate c = getCertificate(f, CERT_USERWITHPATHLEN); |
| assertEquals(f.getProvider().getName(), -1, c.getBasicConstraints()); |
| } |
| |
| /* CA cert with no pathLenConstraint */ |
| { |
| final X509Certificate c = getCertificate(f, CERT_CA); |
| assertEquals(f.getProvider().getName(), Integer.MAX_VALUE, c.getBasicConstraints()); |
| } |
| |
| /* CA cert with pathLenConstraint=10 */ |
| { |
| final X509Certificate c = getCertificate(f, CERT_CAWITHPATHLEN); |
| assertEquals(f.getProvider().getName(), 10, c.getBasicConstraints()); |
| } |
| } |
| |
| /** Encoding of: OID:1.2.3.4, UTF8:test1 */ |
| private static byte[] getOIDTestBytes() { |
| if (StandardNames.IS_RI) { |
| return new byte[] { 0x30, 0x10, 0x06, 0x03, 0x2a, 0x03, 0x04, (byte) 0xa0, |
| 0x09, (byte) 0xa0, 0x07, 0x0c, 0x05, 0x74, 0x65, 0x73, 0x74, 0x31 }; |
| } else { |
| return new byte[] { (byte) 0xa0, 0x0e, 0x06, 0x03, 0x2a, 0x03, 0x04, |
| (byte) 0xa0, 0x07, 0x0c, 0x05, 0x74, 0x65, 0x73, 0x74, 0x31 }; |
| } |
| } |
| |
| private void getSubjectAlternativeNames(CertificateFactory f) throws Exception { |
| X509Certificate c = getCertificate(f, CERT_RSA); |
| Collection<List<?>> col = c.getSubjectAlternativeNames(); |
| |
| checkAlternativeNames(f, col); |
| } |
| |
| private void checkAlternativeNames(CertificateFactory f, Collection<List<?>> col) throws Exception { |
| assertNotNull(col); |
| |
| /* Check to see that the Collection is unmodifiable. */ |
| { |
| try { |
| col.add(new ArrayList<Object>()); |
| fail("should be an unmodifiable list"); |
| } catch (UnsupportedOperationException expected) { |
| } |
| } |
| |
| /* |
| * There should be 9 types of alternative names in this test |
| * certificate. |
| */ |
| boolean[] typesFound = new boolean[9]; |
| |
| for (List<?> item : col) { |
| /* Check to see that the List is unmodifiable. */ |
| { |
| try { |
| item.remove(0); |
| fail("should be an unmodifiable list"); |
| } catch (UnsupportedOperationException expected) { |
| } |
| } |
| |
| assertTrue(item.get(0) instanceof Integer); |
| int type = (Integer) item.get(0); |
| typesFound[type] = true; |
| |
| switch (type) { |
| case 0: /* OtherName */ |
| final byte[] der = getOIDTestBytes(); |
| assertEquals(Arrays.toString(der), Arrays.toString((byte[]) item.get(1))); |
| break; |
| case 1: /* rfc822Name: IA5String */ |
| assertEquals("x509@example.com", (String) item.get(1)); |
| break; |
| case 2: /* dNSName: IA5String */ |
| assertEquals("x509.example.com", (String) item.get(1)); |
| break; |
| case 3: /* x400Address: ORAddress */ |
| assertEquals("UNSUPPORTED", (String) item.get(1)); |
| break; |
| case 4: /* directoryName: Name */ |
| if ("BC".equals(f.getProvider().getName())) { |
| // Bouncycastle doesn't parse T61String as UTF-8 like the RI, libcore, or OpenSSL. |
| byte[] bytes = "CN=∆ƒ,OU=Über Frîends,O=Awesome Dudes,C=US".getBytes("UTF-8"); |
| String string = new String(bytes, 0); |
| assertEquals(string, (String) item.get(1)); |
| } else { |
| assertEquals("CN=∆ƒ,OU=Über Frîends,O=Awesome Dudes,C=US", (String) item.get(1)); |
| } |
| break; |
| case 5: /* ediPartyName */ |
| assertEquals("UNSUPPORTED", Arrays.toString((byte[]) item.get(1))); |
| break; |
| case 6: /* uniformResourceIdentifier: IA5String */ |
| assertEquals("http://www.example.com/?q=awesomeness", (String) item.get(1)); |
| break; |
| case 7: /* iPAddress */ |
| assertEquals("192.168.0.1", (String) item.get(1)); |
| break; |
| case 8: |
| assertEquals("1.2.3.4", (String) item.get(1)); |
| break; |
| } |
| } |
| |
| Set<Integer> missing = new HashSet<Integer>(); |
| for (int i = 0; i < typesFound.length; i++) { |
| if (!typesFound[i]) { |
| missing.add(i); |
| } |
| } |
| |
| // TODO: fix X.400 names and ediPartyName |
| missing.remove(3); |
| missing.remove(5); |
| |
| if (!missing.isEmpty()) { |
| fail("Missing types: " + Arrays.toString(missing.toArray(new Integer[missing.size()]))); |
| } |
| } |
| |
| private void getSubjectAlternativeNames_IPV6(CertificateFactory f) throws Exception { |
| X509Certificate c = getCertificate(f, CERT_IPV6); |
| Collection<List<?>> col = c.getSubjectAlternativeNames(); |
| |
| assertNotNull(f.getProvider().getName(), col); |
| |
| assertEquals(1, col.size()); |
| List<?> item = col.iterator().next(); |
| |
| assertTrue(item.get(0) instanceof Integer); |
| assertTrue(7 == (Integer) item.get(0)); |
| |
| assertTrue(item.get(1) instanceof String); |
| // RI doesn't apply all the IPv6 shortening rules |
| if (StandardNames.IS_RI) { |
| assertEquals("2001:db8:0:0:0:ff00:42:8329", (String) item.get(1)); |
| } else { |
| assertEquals("2001:db8::ff00:42:8329", (String) item.get(1)); |
| } |
| } |
| |
| private void getSubjectAlternativeNames_InvalidIP(CertificateFactory f) throws Exception { |
| X509Certificate c = getCertificate(f, CERT_INVALIDIP); |
| Collection<List<?>> col = c.getSubjectAlternativeNames(); |
| assertNull(col); |
| } |
| |
| private void getSubjectAlternativeNames_Other(CertificateFactory f) throws Exception { |
| X509Certificate c = getCertificate(f, CERT_ALT_OTHER); |
| Collection<List<?>> col = c.getSubjectAlternativeNames(); |
| |
| assertNotNull(f.getProvider().getName(), col); |
| |
| assertEquals(1, col.size()); |
| List<?> item = col.iterator().next(); |
| |
| assertTrue(item.get(0) instanceof Integer); |
| assertTrue(0 == (Integer) item.get(0)); |
| |
| /* OID:1.2.3.4, UTF8:test1 */ |
| final byte[] der = getOIDTestBytes(); |
| final byte[] actual = (byte[]) item.get(1); |
| assertEquals(Arrays.toString(der), Arrays.toString(actual)); |
| |
| /* Make sure the byte[] array isn't modified by our test. */ |
| { |
| actual[0] ^= (byte) 0xFF; |
| byte[] actual2 = (byte[]) c.getSubjectAlternativeNames().iterator().next().get(1); |
| |
| if (!StandardNames.IS_RI) { |
| assertEquals(Arrays.toString(der), Arrays.toString(actual2)); |
| } else { |
| /* RI is broken here. */ |
| assertEquals(Arrays.toString(actual), Arrays.toString(actual2)); |
| } |
| } |
| } |
| |
| private void getSubjectAlternativeNames_Email(CertificateFactory f) throws Exception { |
| X509Certificate c = getCertificate(f, CERT_ALT_EMAIL); |
| Collection<List<?>> col = c.getSubjectAlternativeNames(); |
| |
| assertNotNull(f.getProvider().getName(), col); |
| |
| assertEquals(1, col.size()); |
| List<?> item = col.iterator().next(); |
| |
| assertTrue(item.get(0) instanceof Integer); |
| assertTrue(1 == (Integer) item.get(0)); |
| |
| assertTrue(item.get(1) instanceof String); |
| assertEquals("x509@example.com", (String) item.get(1)); |
| } |
| |
| private void getSubjectAlternativeNames_DNS(CertificateFactory f) throws Exception { |
| X509Certificate c = getCertificate(f, CERT_ALT_DNS); |
| Collection<List<?>> col = c.getSubjectAlternativeNames(); |
| |
| assertNotNull(f.getProvider().getName(), col); |
| |
| assertEquals(1, col.size()); |
| List<?> item = col.iterator().next(); |
| |
| assertTrue(item.get(0) instanceof Integer); |
| assertTrue(2 == (Integer) item.get(0)); |
| |
| assertTrue(item.get(1) instanceof String); |
| assertEquals("x509.example.com", (String) item.get(1)); |
| } |
| |
| private void getSubjectAlternativeNames_DirName(CertificateFactory f) throws Exception { |
| X509Certificate c = getCertificate(f, CERT_ALT_DIRNAME); |
| Collection<List<?>> col = c.getSubjectAlternativeNames(); |
| |
| assertNotNull(f.getProvider().getName(), col); |
| |
| assertEquals(1, col.size()); |
| List<?> item = col.iterator().next(); |
| |
| assertTrue(item.get(0) instanceof Integer); |
| assertTrue(String.valueOf((Integer) item.get(0)), 4 == (Integer) item.get(0)); |
| |
| assertTrue(item.get(1) instanceof String); |
| if ("BC".equals(f.getProvider().getName())) { |
| // Bouncycastle doesn't parse T61String as UTF-8 like the RI, libcore, or OpenSSL. |
| byte[] bytes = "CN=∆ƒ,OU=Über Frîends,O=Awesome Dudes,C=US".getBytes("UTF-8"); |
| String string = new String(bytes, 0); |
| assertEquals(string, (String) item.get(1)); |
| } else { |
| assertEquals("CN=∆ƒ,OU=Über Frîends,O=Awesome Dudes,C=US", (String) item.get(1)); |
| } |
| } |
| |
| private void getSubjectAlternativeNames_URI(CertificateFactory f) throws Exception { |
| X509Certificate c = getCertificate(f, CERT_ALT_URI); |
| Collection<List<?>> col = c.getSubjectAlternativeNames(); |
| |
| assertNotNull(f.getProvider().getName(), col); |
| |
| assertEquals(1, col.size()); |
| List<?> item = col.iterator().next(); |
| |
| assertTrue(item.get(0) instanceof Integer); |
| assertTrue(6 == (Integer) item.get(0)); |
| |
| assertTrue(item.get(1) instanceof String); |
| assertEquals("http://www.example.com/?q=awesomeness", (String) item.get(1)); |
| } |
| |
| private void getSubjectAlternativeNames_RID(CertificateFactory f) throws Exception { |
| X509Certificate c = getCertificate(f, CERT_ALT_RID); |
| Collection<List<?>> col = c.getSubjectAlternativeNames(); |
| |
| assertNotNull(f.getProvider().getName(), col); |
| |
| assertEquals(1, col.size()); |
| List<?> item = col.iterator().next(); |
| |
| assertTrue(item.get(0) instanceof Integer); |
| assertTrue(8 == (Integer) item.get(0)); |
| |
| assertTrue(item.get(1) instanceof String); |
| assertEquals("1.2.3.4", (String) item.get(1)); |
| } |
| |
| private void getSubjectAlternativeNames_None(CertificateFactory f) throws Exception { |
| X509Certificate c = getCertificate(f, CERT_ALT_NONE); |
| Collection<List<?>> col = c.getSubjectAlternativeNames(); |
| assertNull(col); |
| } |
| |
| private void getIssuerAlternativeNames(CertificateFactory f) throws Exception { |
| X509Certificate c = getCertificate(f, CERT_RSA); |
| Collection<List<?>> col = c.getIssuerAlternativeNames(); |
| |
| checkAlternativeNames(f, col); |
| } |
| |
| private void getSignature(CertificateFactory f) throws Exception { |
| X509Certificate c = getCertificate(f, CERT_RSA); |
| |
| assertEquals(Arrays.toString(getRsaCertificateSignature()), |
| Arrays.toString(c.getSignature())); |
| } |
| |
| private void getTBSCertificate(CertificateFactory f) throws Exception { |
| X509Certificate c = getCertificate(f, CERT_RSA); |
| |
| assertEquals(Arrays.toString(getRsaCertificateTbs()), |
| Arrays.toString(c.getTBSCertificate())); |
| } |
| |
| private void hasUnsupportedCriticalExtension(CertificateFactory f) throws Exception { |
| X509Certificate c = getCertificate(f, CERT_RSA); |
| assertFalse(c.hasUnsupportedCriticalExtension()); |
| |
| X509Certificate unsupported = getCertificate(f, CERT_UNSUPPORTED); |
| assertTrue(unsupported.hasUnsupportedCriticalExtension()); |
| } |
| |
| private void getEncoded(CertificateFactory f) throws Exception { |
| X509Certificate c = getCertificate(f, CERT_RSA); |
| |
| byte[] cBytes = getResourceAsBytes(CERT_RSA); |
| |
| assertEquals(Arrays.toString(cBytes), Arrays.toString(c.getEncoded())); |
| } |
| |
| private void generateCertificate_PEM_TrailingData(CertificateFactory f) throws Exception { |
| byte[] certsBytes = getResourceAsBytes(CERTS_X509_PEM); |
| byte[] certsTwice = new byte[certsBytes.length * 2]; |
| System.arraycopy(certsBytes, 0, certsTwice, 0, certsBytes.length); |
| System.arraycopy(certsBytes, 0, certsTwice, certsBytes.length, certsBytes.length); |
| ByteArrayInputStream bais = new ByteArrayInputStream(certsTwice); |
| |
| assertEquals(certsBytes.length * 2, bais.available()); |
| X509Certificate cert1 = (X509Certificate) f.generateCertificate(bais); |
| // TODO: If we had a single PEM certificate, we could know exact bytes. |
| assertTrue(certsBytes.length < bais.available()); |
| } |
| |
| private void generateCertificate_DER_TrailingData(CertificateFactory f) throws Exception { |
| byte[] cert1Bytes = getResourceAsBytes(CERT_RSA); |
| byte[] cert1WithTrailing = new byte[cert1Bytes.length * 2]; |
| System.arraycopy(cert1Bytes, 0, cert1WithTrailing, 0, cert1Bytes.length); |
| System.arraycopy(cert1Bytes, 0, cert1WithTrailing, cert1Bytes.length, cert1Bytes.length); |
| ByteArrayInputStream bais = new ByteArrayInputStream(cert1WithTrailing); |
| |
| assertEquals(cert1Bytes.length * 2, bais.available()); |
| X509Certificate cert1 = (X509Certificate) f.generateCertificate(bais); |
| assertEquals(cert1Bytes.length, bais.available()); |
| } |
| |
| private void generateCertificates_X509_DER(CertificateFactory f) throws Exception { |
| /* DER-encoded list of certificates */ |
| Collection<? extends X509Certificate> certs = getCertificates(f, CERTS_X509_DER); |
| assertNotNull(certs); |
| assertEquals(2, certs.size()); |
| } |
| |
| private void generateCertificates_X509_PEM(CertificateFactory f) throws Exception { |
| /* PEM-encoded list of certificates */ |
| Collection<? extends X509Certificate> certs = getCertificates(f, CERTS_X509_PEM); |
| assertNotNull(certs); |
| assertEquals(2, certs.size()); |
| } |
| |
| private void generateCertificates_PKCS7_PEM(CertificateFactory f) throws Exception { |
| /* PEM-encoded PKCS7 bag of certificates */ |
| Collection<? extends X509Certificate> certs = getCertificates(f, CERTS_PKCS7_PEM); |
| assertNotNull(certs); |
| if ("BC".equals(f.getProvider().getName())) { |
| // Bouncycastle is broken |
| assertEquals(0, certs.size()); |
| } else { |
| assertEquals(2, certs.size()); |
| } |
| } |
| |
| private void generateCertificates_PKCS7_DER(CertificateFactory f) throws Exception { |
| /* DER-encoded PKCS7 bag of certificates */ |
| Collection<? extends X509Certificate> certs = getCertificates(f, CERTS_PKCS7_DER); |
| assertNotNull(certs); |
| assertEquals(2, certs.size()); |
| } |
| |
| private void generateCertificates_Empty(CertificateFactory f) throws Exception { |
| final InputStream is = new ByteArrayInputStream(new byte[0]); |
| |
| final Collection<? extends Certificate> certs = f.generateCertificates(is); |
| |
| assertNotNull(certs); |
| assertEquals(0, certs.size()); |
| } |
| |
| private void generateCertificates_X509_PEM_TrailingData(CertificateFactory f) throws Exception { |
| byte[] certBytes = getResourceAsBytes(CERTS_X509_PEM); |
| byte[] certsPlusExtra = new byte[certBytes.length + 4096]; |
| System.arraycopy(certBytes, 0, certsPlusExtra, 0, certBytes.length); |
| ByteArrayInputStream bais = new ByteArrayInputStream(certsPlusExtra); |
| |
| assertEquals(certsPlusExtra.length, bais.available()); |
| |
| // RI is broken |
| try { |
| Collection<? extends X509Certificate> certs = (Collection<? extends X509Certificate>) |
| f.generateCertificates(bais); |
| if (StandardNames.IS_RI) { |
| return; |
| } |
| } catch (CertificateParsingException e) { |
| if (StandardNames.IS_RI) { |
| return; |
| } |
| throw e; |
| } |
| |
| // Bouncycastle is broken |
| if ("BC".equals(f.getProvider().getName())) { |
| assertEquals(0, bais.available()); |
| } else { |
| assertEquals(4096, bais.available()); |
| } |
| } |
| |
| private void generateCertificates_X509_DER_TrailingData(CertificateFactory f) throws Exception { |
| byte[] certBytes = getResourceAsBytes(CERTS_X509_DER); |
| byte[] certsPlusExtra = new byte[certBytes.length + 4096]; |
| System.arraycopy(certBytes, 0, certsPlusExtra, 0, certBytes.length); |
| ByteArrayInputStream bais = new ByteArrayInputStream(certsPlusExtra); |
| |
| assertEquals(certsPlusExtra.length, bais.available()); |
| |
| // RI is broken |
| try { |
| Collection<? extends X509Certificate> certs = (Collection<? extends X509Certificate>) |
| f.generateCertificates(bais); |
| if (StandardNames.IS_RI) { |
| return; |
| } |
| } catch (CertificateParsingException e) { |
| if (StandardNames.IS_RI) { |
| return; |
| } |
| throw e; |
| } |
| |
| // Bouncycastle is broken |
| if ("BC".equals(f.getProvider().getName())) { |
| assertEquals(0, bais.available()); |
| } else { |
| assertEquals(4096, bais.available()); |
| } |
| } |
| |
| private void generateCertificates_PKCS7_PEM_TrailingData(CertificateFactory f) throws Exception { |
| byte[] certBytes = getResourceAsBytes(CERTS_PKCS7_PEM); |
| byte[] certsPlusExtra = new byte[certBytes.length + 4096]; |
| System.arraycopy(certBytes, 0, certsPlusExtra, 0, certBytes.length); |
| ByteArrayInputStream bais = new ByteArrayInputStream(certsPlusExtra); |
| |
| assertEquals(certsPlusExtra.length, bais.available()); |
| Collection<? extends X509Certificate> certs = (Collection<? extends X509Certificate>) |
| f.generateCertificates(bais); |
| |
| // Bouncycastle is broken |
| if ("BC".equals(f.getProvider().getName())) { |
| assertEquals(0, bais.available()); |
| } else { |
| assertEquals(4096, bais.available()); |
| } |
| } |
| |
| private void generateCertificates_PKCS7_DER_TrailingData(CertificateFactory f) throws Exception { |
| byte[] certBytes = getResourceAsBytes(CERTS_PKCS7_DER); |
| byte[] certsPlusExtra = new byte[certBytes.length + 4096]; |
| System.arraycopy(certBytes, 0, certsPlusExtra, 0, certBytes.length); |
| ByteArrayInputStream bais = new ByteArrayInputStream(certsPlusExtra); |
| |
| assertEquals(certsPlusExtra.length, bais.available()); |
| Collection<? extends X509Certificate> certs = (Collection<? extends X509Certificate>) |
| f.generateCertificates(bais); |
| |
| assertEquals(4096, bais.available()); |
| } |
| |
| private void test_Serialization(CertificateFactory f) throws Exception { |
| for (String certName : VARIOUS_CERTS) { |
| X509Certificate expected = getCertificate(f, certName); |
| |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| ObjectOutputStream oos = new ObjectOutputStream(baos); |
| try { |
| oos.writeObject(expected); |
| } finally { |
| oos.close(); |
| } |
| |
| byte[] certBytes = baos.toByteArray(); |
| |
| ByteArrayInputStream bais = new ByteArrayInputStream(certBytes); |
| try { |
| ObjectInputStream ois = new ObjectInputStream(bais); |
| |
| X509Certificate actual = (X509Certificate) ois.readObject(); |
| |
| assertEquals(certName, expected, actual); |
| } finally { |
| bais.close(); |
| } |
| } |
| } |
| |
| private void test_UnknownUnmappedKeyOID(CertificateFactory f) throws Exception { |
| byte[] certBytes = generateFakeOidCertificate(); |
| |
| { |
| X509Certificate cert = (X509Certificate) f |
| .generateCertificate(new ByteArrayInputStream(certBytes)); |
| assertEquals(FakeOidProvider.SIGALG_OID, cert.getSigAlgOID()); |
| assertEquals(FakeOidProvider.SIGALG_OID, cert.getSigAlgName()); |
| } |
| } |
| |
| private void test_UnknownMappedKeyOID(CertificateFactory f) throws Exception { |
| AlgNameMapper.addMapping(FakeOidProvider.SIGALG_OID, FakeOidProvider.SIGALG_OID_NAME); |
| |
| Security.addProvider(new FakeOidProvider()); |
| try { |
| byte[] certBytes = generateFakeOidCertificate(); |
| |
| // Make sure the certificate is outputting something. |
| X509Certificate cert = (X509Certificate) f |
| .generateCertificate(new ByteArrayInputStream(certBytes)); |
| assertEquals(FakeOidProvider.SIGALG_OID, cert.getSigAlgOID()); |
| if ("AndroidOpenSSL".equals(f.getProvider().getName())) { |
| // AndroidOpenSSL provider has a connection to AlgNameMapper, so |
| // we expect it to get our special name. |
| assertEquals(FakeOidProvider.SIGALG_OID_NAME, cert.getSigAlgName()); |
| } else { |
| assertNotNull(cert.getSigAlgName()); |
| } |
| |
| cert.verify(cert.getPublicKey()); |
| } finally { |
| AlgNameMapper |
| .removeMapping(FakeOidProvider.SIGALG_OID, FakeOidProvider.SIGALG_OID_NAME); |
| Security.removeProvider(FakeOidProvider.PROVIDER_NAME); |
| } |
| } |
| |
| private byte[] generateFakeOidCertificate() throws IOException { |
| byte[] certBytes; |
| |
| // Read in the original cert. |
| { |
| InputStream is = null; |
| try { |
| is = Support_Resources.getStream(CERT_RSA); |
| |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| byte[] buffer = new byte[2048]; |
| int numRead; |
| while ((numRead = is.read(buffer, 0, buffer.length)) != -1) { |
| baos.write(buffer, 0, numRead); |
| } |
| certBytes = baos.toByteArray(); |
| } finally { |
| if (is != null) { |
| try { |
| is.close(); |
| } catch (IOException ignored) { |
| } |
| } |
| } |
| } |
| |
| // Fix the OID for the certificate. |
| { |
| int numFixed = 0; |
| for (int i = 0; i < certBytes.length - 5; i++) { |
| if (certBytes[i] == (byte) 0x2A && certBytes[i + 1] == (byte) 0x86 |
| && certBytes[i + 2] == (byte) 0x48 && certBytes[i + 3] == (byte) 0x86 |
| && certBytes[i + 4] == (byte) 0xF7) { |
| certBytes[i + 1] = (byte) 0xFF; |
| certBytes[i + 2] = (byte) 0xFF; |
| certBytes[i + 3] = (byte) 0xFF; |
| i += 4; |
| numFixed++; |
| } |
| } |
| assertEquals(3, numFixed); |
| } |
| return certBytes; |
| } |
| |
| @Override |
| protected void setUp() throws Exception { |
| super.setUp(); |
| |
| mX509Providers = Security.getProviders("CertificateFactory.X509"); |
| } |
| } |