diff options
author | Kenny Root <kroot@google.com> | 2014-05-08 18:02:06 +0000 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2014-05-08 18:02:06 +0000 |
commit | 2cbfef72ec2046d77d983bc106a3cfb3d69e9bf0 (patch) | |
tree | fb227576e5a953c00f610b3469fa128b7b9cf69a /luni/src | |
parent | 2df76ca9c08da5828c261ff15f276ad59838bc1b (diff) | |
parent | 13bb5c1b5d3ccd844f330734f46d1f7dd27f9094 (diff) | |
download | libcore-2cbfef72ec2046d77d983bc106a3cfb3d69e9bf0.zip libcore-2cbfef72ec2046d77d983bc106a3cfb3d69e9bf0.tar.gz libcore-2cbfef72ec2046d77d983bc106a3cfb3d69e9bf0.tar.bz2 |
am 13bb5c1b: Merge "Add CRLReason and friends"
* commit '13bb5c1b5d3ccd844f330734f46d1f7dd27f9094':
Add CRLReason and friends
Diffstat (limited to 'luni/src')
9 files changed, 477 insertions, 3 deletions
diff --git a/luni/src/main/java/java/security/cert/CRLReason.java b/luni/src/main/java/java/security/cert/CRLReason.java new file mode 100644 index 0000000..6f663db --- /dev/null +++ b/luni/src/main/java/java/security/cert/CRLReason.java @@ -0,0 +1,40 @@ +/* + * Copyright 2014 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 java.security.cert; + +import java.io.Serializable; + +/** + * The reason a CRL entry was revoked. See <a + * href="http://www.ietf.org/rfc/rfc3280.txt">RFC 3280</a> for more information. + * + * @since 1.7 + * @hide + */ +public enum CRLReason implements Comparable<CRLReason>, Serializable { + UNSPECIFIED, + KEY_COMPROMISE, + CA_COMPROMISE, + AFFILIATION_CHANGED, + SUPERSEDED, + CESSATION_OF_OPERATION, + CERTIFICATE_HOLD, + UNUSED, + REMOVE_FROM_CRL, + PRIVILEGE_WITHDRAWN, + AA_COMPROMISE; +} diff --git a/luni/src/main/java/java/security/cert/CertificateRevokedException.java b/luni/src/main/java/java/security/cert/CertificateRevokedException.java new file mode 100644 index 0000000..4d88a4d --- /dev/null +++ b/luni/src/main/java/java/security/cert/CertificateRevokedException.java @@ -0,0 +1,155 @@ +/* + * Copyright 2014 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 java.security.cert; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import javax.security.auth.x500.X500Principal; +import org.apache.harmony.security.x509.InvalidityDate; + +/** + * Exception that is thrown when a certificate is invalid because it has been + * revoked. + * + * @since 1.7 + * @hide + */ +public class CertificateRevokedException extends CertificateException { + + private static final long serialVersionUID = 7839996631571608627L; + + private final Date revocationDate; + + private final CRLReason reason; + + private final X500Principal authority; + + // Maps may not be serializable, so serialize it manually. + private transient Map<String, Extension> extensions; + + /** + * @param revocationDate date the certificate was revoked + * @param reason reason the certificate was revoked if available + * @param authority authority that revoked the certificate + * @param extensions X.509 extensions associated with this revocation + */ + public CertificateRevokedException(Date revocationDate, CRLReason reason, + X500Principal authority, Map<String, Extension> extensions) { + this.revocationDate = revocationDate; + this.reason = reason; + this.authority = authority; + this.extensions = extensions; + } + + /** + * Returns the principal of the authority that issued the revocation. + */ + public X500Principal getAuthorityName() { + return authority; + } + + /** + * X.509 extensions that are associated with this revocation. + */ + public Map<String, Extension> getExtensions() { + return Collections.unmodifiableMap(extensions); + } + + /** + * Returns the date when the certificate was known to become invalid if + * available. + */ + public Date getInvalidityDate() { + if (extensions == null) { + return null; + } + + Extension invalidityDateExtension = extensions.get("2.5.29.24"); + if (invalidityDateExtension == null) { + return null; + } + + try { + InvalidityDate invalidityDate = new InvalidityDate(invalidityDateExtension.getValue()); + return invalidityDate.getDate(); + } catch (IOException e) { + return null; + } + } + + /** + * Returns the detail message of the thrown exception. + */ + public String getMessage() { + StringBuffer sb = new StringBuffer("Certificate was revoked"); + if (revocationDate != null) { + sb.append(" on ").append(revocationDate.toString()); + } + if (reason != null) { + sb.append(" due to ").append(reason); + } + return sb.toString(); + } + + /** + * Returns the date the certificate was revoked. + */ + public Date getRevocationDate() { + return (Date) revocationDate.clone(); + } + + /** + * Returns the reason the certificate was revoked if available. + */ + public CRLReason getRevocationReason() { + return reason; + } + + private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { + stream.defaultReadObject(); + + int size = stream.readInt(); + extensions = new HashMap<String, Extension>(size); + for (int i = 0; i < size; i++) { + String oid = (String) stream.readObject(); + boolean critical = stream.readBoolean(); + int valueLen = stream.readInt(); + byte[] value = new byte[valueLen]; + stream.read(value); + extensions.put(oid, + new org.apache.harmony.security.x509.Extension(oid, critical, value)); + } + } + + private void writeObject(ObjectOutputStream stream) throws IOException { + stream.defaultWriteObject(); + + stream.writeInt(extensions.size()); + for (Extension e : extensions.values()) { + stream.writeObject(e.getId()); + stream.writeBoolean(e.isCritical()); + byte[] value = e.getValue(); + stream.writeInt(value.length); + stream.write(value); + } + } +} diff --git a/luni/src/main/java/java/security/cert/X509CRLEntry.java b/luni/src/main/java/java/security/cert/X509CRLEntry.java index 4b4c15d..451cfd5 100644 --- a/luni/src/main/java/java/security/cert/X509CRLEntry.java +++ b/luni/src/main/java/java/security/cert/X509CRLEntry.java @@ -17,10 +17,13 @@ package java.security.cert; +import java.io.IOException; import java.math.BigInteger; import java.util.Arrays; import java.util.Date; import javax.security.auth.x500.X500Principal; +import org.apache.harmony.security.asn1.ASN1OctetString; +import org.apache.harmony.security.x509.ReasonCode; /** * Abstract base class for entries in a certificate revocation list (CRL). @@ -121,5 +124,25 @@ public abstract class X509CRLEntry implements X509Extension { * @return a string representation of this instance. */ public abstract String toString(); -} + /** + * Returns the reason this CRL entry was revoked. If the implementation + * doesn't support reasons, this will return {@code null}. + * + * @since 1.7 + * @hide + */ + public CRLReason getRevocationReason() { + byte[] reasonBytes = getExtensionValue("2.5.29.21"); + if (reasonBytes == null) { + return null; + } + + try { + byte[] rawBytes = (byte[]) ASN1OctetString.getInstance().decode(reasonBytes); + return new ReasonCode(rawBytes).getReason(); + } catch (IOException e) { + return null; + } + } +}
\ No newline at end of file diff --git a/luni/src/main/java/org/apache/harmony/security/x509/InvalidityDate.java b/luni/src/main/java/org/apache/harmony/security/x509/InvalidityDate.java index b7c1847..533c79c 100644 --- a/luni/src/main/java/org/apache/harmony/security/x509/InvalidityDate.java +++ b/luni/src/main/java/org/apache/harmony/security/x509/InvalidityDate.java @@ -44,6 +44,13 @@ public final class InvalidityDate extends ExtensionValue { } /** + * Constructs the object from a date instance. + */ + public InvalidityDate(Date date) { + this.date = (Date) date.clone(); + } + + /** * Returns the invalidity date. */ public Date getDate() { diff --git a/luni/src/main/java/org/apache/harmony/security/x509/ReasonCode.java b/luni/src/main/java/org/apache/harmony/security/x509/ReasonCode.java index 183ecde..2c9d6aa 100644 --- a/luni/src/main/java/org/apache/harmony/security/x509/ReasonCode.java +++ b/luni/src/main/java/org/apache/harmony/security/x509/ReasonCode.java @@ -18,6 +18,7 @@ package org.apache.harmony.security.x509; import java.io.IOException; +import java.security.cert.CRLReason; import org.apache.harmony.security.asn1.ASN1Enumerated; import org.apache.harmony.security.asn1.ASN1Type; @@ -71,6 +72,14 @@ public final class ReasonCode extends ExtensionValue { return encoding; } + public CRLReason getReason() { + CRLReason[] values = CRLReason.values(); + if (code < 0 || code > values.length) { + return null; + } + return values[code]; + } + @Override public void dumpValue(StringBuilder sb, String prefix) { sb.append(prefix).append("Reason Code: [ "); switch (code) { diff --git a/luni/src/test/java/libcore/java/security/cert/CRLReasonTest.java b/luni/src/test/java/libcore/java/security/cert/CRLReasonTest.java new file mode 100644 index 0000000..8030de1 --- /dev/null +++ b/luni/src/test/java/libcore/java/security/cert/CRLReasonTest.java @@ -0,0 +1,67 @@ +/* + * Copyright 2014 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 java.security.cert.CRLReason; + +import junit.framework.TestCase; + +public class CRLReasonTest extends TestCase { + public void testCryptoPrimitive_ordinal_ExpectedValues() throws Exception { + assertEquals("UNSPECIFIED", 0, CRLReason.UNSPECIFIED.ordinal()); + assertEquals("KEY_COMPROMISE", 1, CRLReason.KEY_COMPROMISE.ordinal()); + assertEquals("CA_COMPROMISE", 2, CRLReason.CA_COMPROMISE.ordinal()); + assertEquals("AFFILIATION_CHANGED", 3, CRLReason.AFFILIATION_CHANGED.ordinal()); + assertEquals("SUPERSEDED", 4, CRLReason.SUPERSEDED.ordinal()); + assertEquals("CESSATION_OF_OPERATION", 5, CRLReason.CESSATION_OF_OPERATION.ordinal()); + assertEquals("CERTIFICATE_HOLD", 6, CRLReason.CERTIFICATE_HOLD.ordinal()); + assertEquals("UNUSED", 7, CRLReason.UNUSED.ordinal()); + assertEquals("REMOVE_FROM_CRL", 8, CRLReason.REMOVE_FROM_CRL.ordinal()); + assertEquals("PRIVILEGE_WITHDRAWN", 9, CRLReason.PRIVILEGE_WITHDRAWN.ordinal()); + assertEquals("AA_COMPROMISE", 10, CRLReason.AA_COMPROMISE.ordinal()); + } + + public void testCRLReason_values_ExpectedValues() throws Exception { + CRLReason[] reasons = CRLReason.values(); + assertEquals(11, reasons.length); + assertEquals(CRLReason.UNSPECIFIED, reasons[0]); + assertEquals(CRLReason.KEY_COMPROMISE, reasons[1]); + assertEquals(CRLReason.CA_COMPROMISE, reasons[2]); + assertEquals(CRLReason.AFFILIATION_CHANGED, reasons[3]); + assertEquals(CRLReason.SUPERSEDED, reasons[4]); + assertEquals(CRLReason.CESSATION_OF_OPERATION, reasons[5]); + assertEquals(CRLReason.CERTIFICATE_HOLD, reasons[6]); + assertEquals(CRLReason.UNUSED, reasons[7]); + assertEquals(CRLReason.REMOVE_FROM_CRL, reasons[8]); + assertEquals(CRLReason.PRIVILEGE_WITHDRAWN, reasons[9]); + assertEquals(CRLReason.AA_COMPROMISE, reasons[10]); + } + + public void testCRLReason_valueOf_ExpectedValues() throws Exception { + assertEquals(CRLReason.UNSPECIFIED, CRLReason.valueOf("UNSPECIFIED")); + assertEquals(CRLReason.KEY_COMPROMISE, CRLReason.valueOf("KEY_COMPROMISE")); + assertEquals(CRLReason.CA_COMPROMISE, CRLReason.valueOf("CA_COMPROMISE")); + assertEquals(CRLReason.AFFILIATION_CHANGED, CRLReason.valueOf("AFFILIATION_CHANGED")); + assertEquals(CRLReason.SUPERSEDED, CRLReason.valueOf("SUPERSEDED")); + assertEquals(CRLReason.CESSATION_OF_OPERATION, CRLReason.valueOf("CESSATION_OF_OPERATION")); + assertEquals(CRLReason.CERTIFICATE_HOLD, CRLReason.valueOf("CERTIFICATE_HOLD")); + assertEquals(CRLReason.UNUSED, CRLReason.valueOf("UNUSED")); + assertEquals(CRLReason.REMOVE_FROM_CRL, CRLReason.valueOf("REMOVE_FROM_CRL")); + assertEquals(CRLReason.PRIVILEGE_WITHDRAWN, CRLReason.valueOf("PRIVILEGE_WITHDRAWN")); + assertEquals(CRLReason.AA_COMPROMISE, CRLReason.valueOf("AA_COMPROMISE")); + } +} diff --git a/luni/src/test/java/libcore/java/security/cert/X509CRLTest.java b/luni/src/test/java/libcore/java/security/cert/X509CRLTest.java index dfd050d..1f0ee63 100644 --- a/luni/src/test/java/libcore/java/security/cert/X509CRLTest.java +++ b/luni/src/test/java/libcore/java/security/cert/X509CRLTest.java @@ -30,6 +30,7 @@ import java.security.Provider; import java.security.Security; import java.security.SignatureException; import java.security.cert.CRL; +import java.security.cert.CRLReason; import java.security.cert.CertificateFactory; import java.security.cert.X509CRL; import java.security.cert.X509CRLEntry; @@ -342,6 +343,7 @@ public class X509CRLTest extends TestCase { assertEquals(rsaCert.getSerialNumber(), rsaEntry.getSerialNumber()); assertDateSlightlyBefore(expectedDate, rsaEntry.getRevocationDate()); + assertNull(rsaEntry.getRevocationReason()); assertNull(rsaEntry.getCertificateIssuer()); assertFalse(rsaEntry.hasExtensions()); assertNull(rsaEntry.getCriticalExtensionOIDs()); @@ -359,12 +361,16 @@ public class X509CRLTest extends TestCase { assertEquals(dsaCert.getSerialNumber(), dsaEntry.getSerialNumber()); assertDateSlightlyBefore(expectedDate, dsaEntry.getRevocationDate()); + assertEquals(CRLReason.CESSATION_OF_OPERATION, dsaEntry.getRevocationReason()); assertNull(dsaEntry.getCertificateIssuer()); assertTrue(dsaEntry.hasExtensions()); - /* TODO: get the OID */ assertNotNull(dsaEntry.getCriticalExtensionOIDs()); - /* TODO: get the OID */ + assertEquals(0, dsaEntry.getCriticalExtensionOIDs().size()); assertNotNull(dsaEntry.getNonCriticalExtensionOIDs()); + assertEquals(1, dsaEntry.getNonCriticalExtensionOIDs().size()); + assertTrue(Arrays.toString(dsaEntry.getNonCriticalExtensionOIDs().toArray()), + dsaEntry.getNonCriticalExtensionOIDs().contains("2.5.29.21")); + System.out.println(Arrays.toString(dsaEntry.getExtensionValue("2.5.29.21"))); assertNotNull(dsaEntry.toString()); } diff --git a/luni/src/test/java/tests/security/cert/CertificateRevocationExceptionTest.java b/luni/src/test/java/tests/security/cert/CertificateRevocationExceptionTest.java new file mode 100644 index 0000000..ba7af7c --- /dev/null +++ b/luni/src/test/java/tests/security/cert/CertificateRevocationExceptionTest.java @@ -0,0 +1,167 @@ +/* + * Copyright 2014 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 tests.security.cert; + +import org.apache.harmony.testframework.serialization.SerializationTest; +import org.apache.harmony.testframework.serialization.SerializationTest.SerializableAssert; +import java.io.IOException; +import java.io.OutputStream; +import java.io.Serializable; +import java.security.cert.CRLReason; +import java.security.cert.CertificateRevokedException; +import java.security.cert.Extension; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import javax.security.auth.x500.X500Principal; + +import junit.framework.TestCase; + +/** + * + */ +public class CertificateRevocationExceptionTest extends TestCase implements SerializableAssert { + private CertificateRevokedException getTestException() { + HashMap<String, Extension> extensions = new HashMap<String, Extension>(); + // REASON_CODE + extensions.put("2.5.29.21", getReasonExtension()); + extensions.put("2.5.29.24", getInvalidityExtension()); + return new CertificateRevokedException( + new Date(108, 0, 1, 14, 34, 11), + CRLReason.CESSATION_OF_OPERATION, + new X500Principal("CN=test1"), + extensions); + } + + private Extension getReasonExtension() { + return new Extension() { + @Override + public String getId() { + return "2.5.29.21"; + } + + @Override + public boolean isCritical() { + return false; + } + + @Override + public byte[] getValue() { + return new byte[] {4, 3, 10, 1, 5}; + } + + @Override + public void encode(OutputStream out) throws IOException { + throw new UnsupportedOperationException(); + } + }; + } + + private Extension getInvalidityExtension() { + return new Extension() { + @Override + public String getId() { + return "2.5.29.24"; + } + + @Override + public boolean isCritical() { + return false; + } + + @Override + public byte[] getValue() { + return new byte[] { + 0x18, 0x0F, 0x32, 0x30, 0x31, 0x34, 0x30, 0x31, 0x31, 0x37, 0x30, 0x38, + 0x33, 0x30, 0x30, 0x39, 0x5a + }; + } + + @Override + public void encode(OutputStream out) throws IOException { + throw new UnsupportedOperationException(); + } + }; + } + + public void testGetExtensions() throws Exception { + CertificateRevokedException original = getTestException(); + Map<String, Extension> extensions = original.getExtensions(); + assertNotSame(extensions, original.getExtensions()); + + try { + extensions.put("2.2.2.2", getReasonExtension()); + fail(); + } catch (UnsupportedOperationException expected) { + } + } + + public void testGetRevocationDate() throws Exception { + CertificateRevokedException exception = getTestException(); + + Date firstDate = exception.getRevocationDate(); + assertNotSame(firstDate, exception.getRevocationDate()); + + firstDate.setYear(firstDate.getYear() + 1); + assertTrue(firstDate.compareTo(exception.getRevocationDate()) > 0); + } + + public void testGetInvalidityDate() throws Exception { + CertificateRevokedException exception = getTestException(); + + Date firstDate = exception.getInvalidityDate(); + assertNotSame(firstDate, exception.getInvalidityDate()); + + firstDate.setYear(firstDate.getYear() + 1); + assertTrue(firstDate.compareTo(exception.getInvalidityDate()) > 0); + } + + + /** + * serialization/deserialization compatibility. + */ + public void testSerializationCertificateRevokedExceptionSelf() throws Exception { + SerializationTest.verifySelf(getTestException(), this); + } + + /** + * serialization/deserialization compatibility with RI. + */ + public void testSerializationCertificateRevokedExceptionCompatability() throws Exception { + // create test file (once) + // SerializationTest.createGoldenFile("/tmp", this, getTestException()); + SerializationTest.verifyGolden(this, getTestException()); + } + + @Override + public void assertDeserialized(Serializable initial, Serializable deserialized) { + assertTrue(initial instanceof CertificateRevokedException); + assertTrue(deserialized instanceof CertificateRevokedException); + + CertificateRevokedException expected = (CertificateRevokedException) initial; + CertificateRevokedException actual = (CertificateRevokedException) deserialized; + + assertEquals(expected.getInvalidityDate(), actual.getInvalidityDate()); + assertNotSame(expected.getInvalidityDate(), actual.getInvalidityDate()); + assertEquals(expected.getRevocationDate(), actual.getRevocationDate()); + assertNotSame(expected.getRevocationDate(), actual.getRevocationDate()); + assertEquals(expected.getRevocationReason(), expected.getRevocationReason()); + + assertEquals(expected.getExtensions().size(), actual.getExtensions().size()); + assertEquals(expected.getExtensions().keySet(), actual.getExtensions().keySet()); + } +} diff --git a/luni/src/test/resources/serialization/tests/security/cert/CertificateRevocationExceptionTest.golden.ser b/luni/src/test/resources/serialization/tests/security/cert/CertificateRevocationExceptionTest.golden.ser Binary files differnew file mode 100644 index 0000000..f9f2746 --- /dev/null +++ b/luni/src/test/resources/serialization/tests/security/cert/CertificateRevocationExceptionTest.golden.ser |