summaryrefslogtreecommitdiffstats
path: root/luni/src/main/java/java/security
diff options
context:
space:
mode:
authorPeter Hallam <peterhal@google.com>2010-04-26 12:53:37 -0700
committerPeter Hallam <peterhal@google.com>2010-04-27 16:26:27 -0700
commitcec4dd4b1d33f78997603d0f89c0d0e56e64dbcd (patch)
treee71d43da21749bfeb4524b0adec05c91d1f89a5f /luni/src/main/java/java/security
parentf205f06be1ce65f132be1b7c850675086f26c0f7 (diff)
downloadlibcore-cec4dd4b1d33f78997603d0f89c0d0e56e64dbcd.zip
libcore-cec4dd4b1d33f78997603d0f89c0d0e56e64dbcd.tar.gz
libcore-cec4dd4b1d33f78997603d0f89c0d0e56e64dbcd.tar.bz2
merge more modules into luni
Diffstat (limited to 'luni/src/main/java/java/security')
-rw-r--r--luni/src/main/java/java/security/AccessControlException.java64
-rw-r--r--luni/src/main/java/java/security/AlgorithmParameterGenerator.java243
-rw-r--r--luni/src/main/java/java/security/AlgorithmParameterGeneratorSpi.java69
-rw-r--r--luni/src/main/java/java/security/AlgorithmParameters.java319
-rw-r--r--luni/src/main/java/java/security/AlgorithmParametersSpi.java124
-rw-r--r--luni/src/main/java/java/security/AllPermission.java128
-rw-r--r--luni/src/main/java/java/security/AllPermissionCollection.java140
-rw-r--r--luni/src/main/java/java/security/AuthProvider.java110
-rw-r--r--luni/src/main/java/java/security/BasicPermission.java215
-rw-r--r--luni/src/main/java/java/security/BasicPermissionCollection.java202
-rw-r--r--luni/src/main/java/java/security/Certificate.java112
-rw-r--r--luni/src/main/java/java/security/CodeSigner.java143
-rw-r--r--luni/src/main/java/java/security/CodeSource.java635
-rw-r--r--luni/src/main/java/java/security/DigestException.java67
-rw-r--r--luni/src/main/java/java/security/DigestInputStream.java151
-rw-r--r--luni/src/main/java/java/security/DigestOutputStream.java136
-rw-r--r--luni/src/main/java/java/security/DomainCombiner.java47
-rw-r--r--luni/src/main/java/java/security/GeneralSecurityException.java68
-rw-r--r--luni/src/main/java/java/security/Guard.java36
-rw-r--r--luni/src/main/java/java/security/GuardedObject.java76
-rw-r--r--luni/src/main/java/java/security/Identity.java433
-rw-r--r--luni/src/main/java/java/security/IdentityScope.java202
-rw-r--r--luni/src/main/java/java/security/InvalidAlgorithmParameterException.java68
-rw-r--r--luni/src/main/java/java/security/InvalidKeyException.java67
-rw-r--r--luni/src/main/java/java/security/InvalidParameterException.java44
-rw-r--r--luni/src/main/java/java/security/Key.java61
-rw-r--r--luni/src/main/java/java/security/KeyException.java65
-rw-r--r--luni/src/main/java/java/security/KeyFactory.java229
-rw-r--r--luni/src/main/java/java/security/KeyFactorySpi.java85
-rw-r--r--luni/src/main/java/java/security/KeyManagementException.java69
-rw-r--r--luni/src/main/java/java/security/KeyPair.java66
-rw-r--r--luni/src/main/java/java/security/KeyPairGenerator.java302
-rw-r--r--luni/src/main/java/java/security/KeyPairGeneratorSpi.java71
-rw-r--r--luni/src/main/java/java/security/KeyRep.java183
-rw-r--r--luni/src/main/java/java/security/KeyStore.java1501
-rw-r--r--luni/src/main/java/java/security/KeyStoreException.java69
-rw-r--r--luni/src/main/java/java/security/KeyStoreSpi.java536
-rw-r--r--luni/src/main/java/java/security/MessageDigest.java425
-rw-r--r--luni/src/main/java/java/security/MessageDigestSpi.java154
-rw-r--r--luni/src/main/java/java/security/NoSuchAlgorithmException.java68
-rw-r--r--luni/src/main/java/java/security/NoSuchProviderException.java44
-rw-r--r--luni/src/main/java/java/security/Permission.java161
-rw-r--r--luni/src/main/java/java/security/PermissionCollection.java120
-rw-r--r--luni/src/main/java/java/security/Permissions.java244
-rw-r--r--luni/src/main/java/java/security/PermissionsHash.java77
-rw-r--r--luni/src/main/java/java/security/Policy.java236
-rw-r--r--luni/src/main/java/java/security/Principal.java64
-rw-r--r--luni/src/main/java/java/security/PrivateKey.java31
-rw-r--r--luni/src/main/java/java/security/PrivilegedAction.java37
-rw-r--r--luni/src/main/java/java/security/PrivilegedActionException.java92
-rw-r--r--luni/src/main/java/java/security/PrivilegedExceptionAction.java40
-rw-r--r--luni/src/main/java/java/security/ProtectionDomain.java261
-rw-r--r--luni/src/main/java/java/security/Provider.java1164
-rw-r--r--luni/src/main/java/java/security/ProviderException.java69
-rw-r--r--luni/src/main/java/java/security/PublicKey.java30
-rw-r--r--luni/src/main/java/java/security/SecureClassLoader.java162
-rw-r--r--luni/src/main/java/java/security/SecureRandom.java342
-rw-r--r--luni/src/main/java/java/security/SecureRandomSpi.java60
-rw-r--r--luni/src/main/java/java/security/Security.java546
-rw-r--r--luni/src/main/java/java/security/SecurityPermission.java52
-rw-r--r--luni/src/main/java/java/security/Signature.java686
-rw-r--r--luni/src/main/java/java/security/SignatureException.java69
-rw-r--r--luni/src/main/java/java/security/SignatureSpi.java318
-rw-r--r--luni/src/main/java/java/security/SignedObject.java157
-rw-r--r--luni/src/main/java/java/security/Signer.java147
-rw-r--r--luni/src/main/java/java/security/Timestamp.java141
-rw-r--r--luni/src/main/java/java/security/UnrecoverableEntryException.java48
-rw-r--r--luni/src/main/java/java/security/UnrecoverableKeyException.java46
-rw-r--r--luni/src/main/java/java/security/UnresolvedPermission.java418
-rw-r--r--luni/src/main/java/java/security/UnresolvedPermissionCollection.java197
-rw-r--r--luni/src/main/java/java/security/acl/Acl.java167
-rw-r--r--luni/src/main/java/java/security/acl/AclEntry.java118
-rw-r--r--luni/src/main/java/java/security/acl/AclNotFoundException.java34
-rw-r--r--luni/src/main/java/java/security/acl/Group.java64
-rw-r--r--luni/src/main/java/java/security/acl/LastOwnerException.java35
-rw-r--r--luni/src/main/java/java/security/acl/NotOwnerException.java37
-rw-r--r--luni/src/main/java/java/security/acl/Owner.java69
-rw-r--r--luni/src/main/java/java/security/acl/Permission.java45
-rw-r--r--luni/src/main/java/java/security/acl/package.html14
-rw-r--r--luni/src/main/java/java/security/cert/CRL.java66
-rw-r--r--luni/src/main/java/java/security/cert/CRLException.java66
-rw-r--r--luni/src/main/java/java/security/cert/CRLSelector.java49
-rw-r--r--luni/src/main/java/java/security/cert/CertPath.java239
-rw-r--r--luni/src/main/java/java/security/cert/CertPathBuilder.java215
-rw-r--r--luni/src/main/java/java/security/cert/CertPathBuilderException.java68
-rw-r--r--luni/src/main/java/java/security/cert/CertPathBuilderResult.java39
-rw-r--r--luni/src/main/java/java/security/cert/CertPathBuilderSpi.java48
-rw-r--r--luni/src/main/java/java/security/cert/CertPathParameters.java34
-rw-r--r--luni/src/main/java/java/security/cert/CertPathValidator.java222
-rw-r--r--luni/src/main/java/java/security/cert/CertPathValidatorException.java142
-rw-r--r--luni/src/main/java/java/security/cert/CertPathValidatorResult.java33
-rw-r--r--luni/src/main/java/java/security/cert/CertPathValidatorSpi.java55
-rw-r--r--luni/src/main/java/java/security/cert/CertSelector.java49
-rw-r--r--luni/src/main/java/java/security/cert/CertStore.java291
-rw-r--r--luni/src/main/java/java/security/cert/CertStoreException.java67
-rw-r--r--luni/src/main/java/java/security/cert/CertStoreParameters.java32
-rw-r--r--luni/src/main/java/java/security/cert/CertStoreSpi.java71
-rw-r--r--luni/src/main/java/java/security/cert/Certificate.java257
-rw-r--r--luni/src/main/java/java/security/cert/CertificateEncodingException.java68
-rw-r--r--luni/src/main/java/java/security/cert/CertificateException.java67
-rw-r--r--luni/src/main/java/java/security/cert/CertificateExpiredException.java43
-rw-r--r--luni/src/main/java/java/security/cert/CertificateFactory.java320
-rw-r--r--luni/src/main/java/java/security/cert/CertificateFactorySpi.java161
-rw-r--r--luni/src/main/java/java/security/cert/CertificateNotYetValidException.java44
-rw-r--r--luni/src/main/java/java/security/cert/CertificateParsingException.java67
-rw-r--r--luni/src/main/java/java/security/cert/CollectionCertStoreParameters.java104
-rw-r--r--luni/src/main/java/java/security/cert/LDAPCertStoreParameters.java128
-rw-r--r--luni/src/main/java/java/security/cert/PKIXBuilderParameters.java133
-rw-r--r--luni/src/main/java/java/security/cert/PKIXCertPathBuilderResult.java83
-rw-r--r--luni/src/main/java/java/security/cert/PKIXCertPathChecker.java111
-rw-r--r--luni/src/main/java/java/security/cert/PKIXCertPathValidatorResult.java125
-rw-r--r--luni/src/main/java/java/security/cert/PKIXParameters.java621
-rw-r--r--luni/src/main/java/java/security/cert/PolicyNode.java84
-rw-r--r--luni/src/main/java/java/security/cert/PolicyQualifierInfo.java119
-rw-r--r--luni/src/main/java/java/security/cert/TrustAnchor.java282
-rw-r--r--luni/src/main/java/java/security/cert/X509CRL.java279
-rw-r--r--luni/src/main/java/java/security/cert/X509CRLEntry.java128
-rw-r--r--luni/src/main/java/java/security/cert/X509CRLSelector.java466
-rw-r--r--luni/src/main/java/java/security/cert/X509CertSelector.java1432
-rw-r--r--luni/src/main/java/java/security/cert/X509Certificate.java445
-rw-r--r--luni/src/main/java/java/security/cert/X509Extension.java66
-rw-r--r--luni/src/main/java/java/security/cert/package.html22
-rw-r--r--luni/src/main/java/java/security/interfaces/DSAKey.java34
-rw-r--r--luni/src/main/java/java/security/interfaces/DSAKeyPairGenerator.java67
-rw-r--r--luni/src/main/java/java/security/interfaces/DSAParams.java49
-rw-r--r--luni/src/main/java/java/security/interfaces/DSAPrivateKey.java40
-rw-r--r--luni/src/main/java/java/security/interfaces/DSAPublicKey.java40
-rw-r--r--luni/src/main/java/java/security/interfaces/ECKey.java33
-rw-r--r--luni/src/main/java/java/security/interfaces/ECPrivateKey.java39
-rw-r--r--luni/src/main/java/java/security/interfaces/ECPublicKey.java39
-rw-r--r--luni/src/main/java/java/security/interfaces/RSAKey.java33
-rw-r--r--luni/src/main/java/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java84
-rw-r--r--luni/src/main/java/java/security/interfaces/RSAPrivateCrtKey.java73
-rw-r--r--luni/src/main/java/java/security/interfaces/RSAPrivateKey.java39
-rw-r--r--luni/src/main/java/java/security/interfaces/RSAPublicKey.java40
-rw-r--r--luni/src/main/java/java/security/interfaces/package.html14
-rw-r--r--luni/src/main/java/java/security/package.html35
-rw-r--r--luni/src/main/java/java/security/security.properties120
-rw-r--r--luni/src/main/java/java/security/spec/AlgorithmParameterSpec.java25
-rw-r--r--luni/src/main/java/java/security/spec/DSAParameterSpec.java77
-rw-r--r--luni/src/main/java/java/security/spec/DSAPrivateKeySpec.java91
-rw-r--r--luni/src/main/java/java/security/spec/DSAPublicKeySpec.java91
-rw-r--r--luni/src/main/java/java/security/spec/ECField.java31
-rw-r--r--luni/src/main/java/java/security/spec/ECFieldF2m.java266
-rw-r--r--luni/src/main/java/java/security/spec/ECFieldFp.java97
-rw-r--r--luni/src/main/java/java/security/spec/ECGenParameterSpec.java53
-rw-r--r--luni/src/main/java/java/security/spec/ECParameterSpec.java115
-rw-r--r--luni/src/main/java/java/security/spec/ECPoint.java118
-rw-r--r--luni/src/main/java/java/security/spec/ECPrivateKeySpec.java71
-rw-r--r--luni/src/main/java/java/security/spec/ECPublicKeySpec.java76
-rw-r--r--luni/src/main/java/java/security/spec/EllipticCurve.java208
-rw-r--r--luni/src/main/java/java/security/spec/EncodedKeySpec.java63
-rw-r--r--luni/src/main/java/java/security/spec/InvalidKeySpecException.java71
-rw-r--r--luni/src/main/java/java/security/spec/InvalidParameterSpecException.java49
-rw-r--r--luni/src/main/java/java/security/spec/KeySpec.java25
-rw-r--r--luni/src/main/java/java/security/spec/MGF1ParameterSpec.java85
-rw-r--r--luni/src/main/java/java/security/spec/PKCS8EncodedKeySpec.java57
-rw-r--r--luni/src/main/java/java/security/spec/PSSParameterSpec.java159
-rw-r--r--luni/src/main/java/java/security/spec/RSAKeyGenParameterSpec.java73
-rw-r--r--luni/src/main/java/java/security/spec/RSAMultiPrimePrivateCrtKeySpec.java205
-rw-r--r--luni/src/main/java/java/security/spec/RSAOtherPrimeInfo.java93
-rw-r--r--luni/src/main/java/java/security/spec/RSAPrivateCrtKeySpec.java138
-rw-r--r--luni/src/main/java/java/security/spec/RSAPrivateKeySpec.java66
-rw-r--r--luni/src/main/java/java/security/spec/RSAPublicKeySpec.java66
-rw-r--r--luni/src/main/java/java/security/spec/X509EncodedKeySpec.java56
-rw-r--r--luni/src/main/java/java/security/spec/package.html18
166 files changed, 25188 insertions, 0 deletions
diff --git a/luni/src/main/java/java/security/AccessControlException.java b/luni/src/main/java/java/security/AccessControlException.java
new file mode 100644
index 0000000..ae23ab1
--- /dev/null
+++ b/luni/src/main/java/java/security/AccessControlException.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * {@code AccessControlException} is thrown if the access control infrastructure
+ * denies protected access due to missing permissions.
+ */
+public class AccessControlException extends SecurityException {
+
+ private static final long serialVersionUID = 5138225684096988535L;
+
+ private Permission perm; // Named as demanded by Serialized Form.
+
+ /**
+ * Constructs a new instance of {@code AccessControlException} with the
+ * given message.
+ *
+ * @param message
+ * the detail message for this exception.
+ */
+ public AccessControlException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs a new instance of {@code AccessControlException} with the
+ * given message and the requested {@code Permission} which was not granted.
+ *
+ * @param message
+ * the detail message for the exception.
+ * @param perm
+ * the requested {@code Permission} which was not granted.
+ */
+ public AccessControlException(String message, Permission perm) {
+ super(message);
+ this.perm = perm;
+ }
+
+ /**
+ * Returns the requested permission that caused this Exception or {@code
+ * null} if there is no corresponding {@code Permission}.
+ *
+ * @return the requested permission that caused this Exception, maybe {@code null}.
+ */
+ public Permission getPermission() {
+ return perm;
+ }
+}
diff --git a/luni/src/main/java/java/security/AlgorithmParameterGenerator.java b/luni/src/main/java/java/security/AlgorithmParameterGenerator.java
new file mode 100644
index 0000000..6814813
--- /dev/null
+++ b/luni/src/main/java/java/security/AlgorithmParameterGenerator.java
@@ -0,0 +1,243 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.apache.harmony.security.fortress.Engine;
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * {@code AlgorithmParameterGenerator} is an engine class which is capable of
+ * generating parameters for the algorithm it was initialized with.
+ */
+public class AlgorithmParameterGenerator {
+
+ // Store spi service name
+ private static final String SERVICE = "AlgorithmParameterGenerator"; //$NON-NLS-1$
+
+ // Used to access common engine functionality
+ private static Engine engine = new Engine(SERVICE);
+
+ // Store SecureRandom
+ private static SecureRandom randm = new SecureRandom();
+
+ // Store used provider
+ private final Provider provider;
+
+ // Store used AlgorithmParameterGeneratorSpi implementation
+ private final AlgorithmParameterGeneratorSpi spiImpl;
+
+ //Store used algorithm
+ private final String algorithm;
+
+ /**
+ * Constructs a new instance of {@code AlgorithmParameterGenerator} with the
+ * given arguments.
+ *
+ * @param paramGenSpi
+ * a concrete implementation, this engine instance delegates to.
+ * @param provider
+ * the provider.
+ * @param algorithm
+ * the name of the algorithm.
+ */
+ protected AlgorithmParameterGenerator(
+ AlgorithmParameterGeneratorSpi paramGenSpi, Provider provider,
+ String algorithm) {
+ this.provider = provider;
+ this.algorithm = algorithm;
+ this.spiImpl = paramGenSpi;
+ }
+
+ /**
+ * Returns the name of the algorithm.
+ *
+ * @return the name of the algorithm.
+ */
+ public final String getAlgorithm() {
+ return algorithm;
+ }
+
+ /**
+ * Returns a new instance of {@code AlgorithmParameterGenerator} for the
+ * specified algorithm.
+ *
+ * @param algorithm
+ * the name of the algorithm to use.
+ * @return a new instance of {@code AlgorithmParameterGenerator} for the
+ * specified algorithm.
+ * @throws NoSuchAlgorithmException
+ * if the specified algorithm is not available.
+ * @throws NullPointerException
+ * if {@code algorithm} is {@code null}.
+ */
+ public static AlgorithmParameterGenerator getInstance(String algorithm)
+ throws NoSuchAlgorithmException {
+ if (algorithm == null) {
+ throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+ }
+ synchronized (engine) {
+ engine.getInstance(algorithm, null);
+ return new AlgorithmParameterGenerator(
+ (AlgorithmParameterGeneratorSpi) engine.spi, engine.provider,
+ algorithm);
+ }
+ }
+
+ /**
+ * Returns a new instance of {@code AlgorithmParameterGenerator} from the
+ * specified provider for the specified algorithm.
+ *
+ * @param algorithm
+ * the name of the algorithm to use.
+ * @param provider
+ * name of the provider of the {@code
+ * AlgorithmParameterGenerator}.
+ * @return a new instance of {@code AlgorithmParameterGenerator} for the
+ * specified algorithm.
+ * @throws NoSuchAlgorithmException
+ * if the specified algorithm is not available.
+ * @throws NoSuchProviderException
+ * if the specified provider is not available.
+ * @throws NullPointerException
+ * if {@code algorithm} is {@code null}.
+ */
+ public static AlgorithmParameterGenerator getInstance(String algorithm,
+ String provider) throws NoSuchAlgorithmException,
+ NoSuchProviderException {
+ if ((provider == null) || (provider.length() == 0)) {
+ throw new IllegalArgumentException(
+ Messages.getString("security.02")); //$NON-NLS-1$
+ }
+ Provider impProvider = Security.getProvider(provider);
+ if (impProvider == null) {
+ throw new NoSuchProviderException(provider);
+ }
+ return getInstance(algorithm, impProvider);
+ }
+
+ /**
+ * Returns a new instance of {@code AlgorithmParameterGenerator} from the
+ * specified provider for the specified algorithm.
+ *
+ * @param algorithm
+ * the name of the algorithm to use.
+ * @param provider
+ * the provider of the {@code AlgorithmParameterGenerator}.
+ * @return a new instance of {@code AlgorithmParameterGenerator} for the
+ * specified algorithm.
+ * @throws NoSuchAlgorithmException
+ * if the specified algorithm is not available.
+ * @throws NullPointerException
+ * if {@code algorithm} is {@code null}.
+ */
+ public static AlgorithmParameterGenerator getInstance(String algorithm,
+ Provider provider) throws NoSuchAlgorithmException {
+ if (provider == null) {
+ throw new IllegalArgumentException(Messages.getString("security.04")); //$NON-NLS-1$
+ }
+ if (algorithm == null) {
+ throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+ }
+ synchronized (engine) {
+ engine.getInstance(algorithm, provider, null);
+ return new AlgorithmParameterGenerator(
+ (AlgorithmParameterGeneratorSpi) engine.spi, provider,
+ algorithm);
+ }
+ }
+
+ /**
+ * Returns the provider associated with this {@code
+ * AlgorithmParameterGenerator}.
+ *
+ * @return the provider associated with this {@code
+ * AlgorithmParameterGenerator}.
+ */
+ public final Provider getProvider() {
+ return provider;
+ }
+
+ /**
+ * Initializes this {@code AlgorithmParameterGenerator} with the given size.
+ * The default parameter set and a default {@code SecureRandom} instance
+ * will be used.
+ *
+ * @param size
+ * the size (in number of bits).
+ */
+ public final void init(int size) {
+ spiImpl.engineInit(size, randm);
+ }
+
+ /**
+ * Initializes this {@code AlgorithmParameterGenerator} with the given size
+ * and the given {@code SecureRandom}. The default parameter set will be
+ * used.
+ *
+ * @param size
+ * the size (in number of bits).
+ * @param random
+ * the source of randomness.
+ */
+ public final void init(int size, SecureRandom random) {
+ spiImpl.engineInit(size, random);
+ }
+
+ /**
+ * Initializes this {@code AlgorithmParameterGenerator} with the given {@code
+ * AlgorithmParameterSpec}. A default {@code SecureRandom} instance will be
+ * used.
+ *
+ * @param genParamSpec
+ * the parameters to use.
+ * @throws InvalidAlgorithmParameterException
+ * if the specified parameters are not supported.
+ */
+ public final void init(AlgorithmParameterSpec genParamSpec)
+ throws InvalidAlgorithmParameterException {
+ spiImpl.engineInit(genParamSpec, randm);
+ }
+
+ /**
+ * Initializes this {@code AlgorithmParameterGenerator} with the given
+ * {@code AlgorithmParameterSpec} and the given {@code SecureRandom}.
+ *
+ * @param genParamSpec
+ * the parameters to use.
+ * @param random
+ * the source of randomness.
+ * @throws InvalidAlgorithmParameterException
+ * if the specified parameters are not supported.
+ */
+ public final void init(AlgorithmParameterSpec genParamSpec,
+ SecureRandom random) throws InvalidAlgorithmParameterException {
+ spiImpl.engineInit(genParamSpec, random);
+ }
+
+ /**
+ * Computes and returns {@code AlgorithmParameters} for this generator's
+ * algorithm.
+ *
+ * @return {@code AlgorithmParameters} for this generator's algorithm.
+ */
+ public final AlgorithmParameters generateParameters() {
+ return spiImpl.engineGenerateParameters();
+ }
+}
diff --git a/luni/src/main/java/java/security/AlgorithmParameterGeneratorSpi.java b/luni/src/main/java/java/security/AlgorithmParameterGeneratorSpi.java
new file mode 100644
index 0000000..44b3def
--- /dev/null
+++ b/luni/src/main/java/java/security/AlgorithmParameterGeneratorSpi.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * {@code AlgorithmParameterGeneratorSpi} is the Service Provider Interface
+ * (SPI) definition for {@code AlgorithmParameterGenerator}.
+ *
+ * @see AlgorithmParameterGenerator
+ */
+public abstract class AlgorithmParameterGeneratorSpi {
+
+ /**
+ * Constructs a new instance of {@code AlgorithmParameterGeneratorSpi} .
+ */
+ public AlgorithmParameterGeneratorSpi() {
+ }
+
+ /**
+ * Initializes this {@code AlgorithmParameterGeneratorSpi} with the given
+ * size and the given {@code SecureRandom}. The default parameter set
+ * will be used.
+ *
+ * @param size
+ * the size (in number of bits).
+ * @param random
+ * the source of randomness.
+ */
+ protected abstract void engineInit(int size, SecureRandom random);
+
+ /**
+ * Initializes this {@code AlgorithmParameterGeneratorSpi} with the given
+ * {@code AlgorithmParameterSpec} and the given {@code SecureRandom}.
+ *
+ * @param genParamSpec
+ * the parameters to use.
+ * @param random
+ * the source of randomness.
+ * @throws InvalidAlgorithmParameterException
+ * if the specified parameters are not supported.
+ */
+ protected abstract void engineInit(AlgorithmParameterSpec genParamSpec,
+ SecureRandom random) throws InvalidAlgorithmParameterException;
+
+ /**
+ * Computes and returns {@code AlgorithmParameters} for this generator's
+ * algorithm.
+ *
+ * @return {@code AlgorithmParameters} for this generator's algorithm.
+ */
+ protected abstract AlgorithmParameters engineGenerateParameters();
+}
diff --git a/luni/src/main/java/java/security/AlgorithmParameters.java b/luni/src/main/java/java/security/AlgorithmParameters.java
new file mode 100644
index 0000000..d659200
--- /dev/null
+++ b/luni/src/main/java/java/security/AlgorithmParameters.java
@@ -0,0 +1,319 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import org.apache.harmony.security.fortress.Engine;
+import org.apache.harmony.security.internal.nls.Messages;
+
+
+/**
+ * {@code AlgorithmParameters} is an engine class which provides algorithm
+ * parameters.
+ */
+public class AlgorithmParameters {
+ /**
+ * The service name.
+ */
+ private static final String SEVICE = "AlgorithmParameters"; //$NON-NLS-1$
+
+ /**
+ * Used to access common engine functionality.
+ */
+ private static Engine engine = new Engine(SEVICE);
+
+ /**
+ * The security provider.
+ */
+ private Provider provider;
+
+ /**
+ * The SPI implementation.
+ */
+ private AlgorithmParametersSpi spiImpl;
+
+ /**
+ * The security algorithm.
+ */
+ private String algorithm;
+
+ /**
+ * The initialization state.
+ */
+ private boolean initialized; // = false;
+
+ /**
+ * Constructs a new instance of {@code AlgorithmParameters} with the given
+ * arguments.
+ *
+ * @param algPramSpi
+ * the concrete implementation.
+ * @param provider
+ * the security provider.
+ * @param algorithm
+ * the name of the algorithm.
+ */
+ protected AlgorithmParameters(AlgorithmParametersSpi algPramSpi,
+ Provider provider, String algorithm) {
+ this.provider = provider;
+ this.algorithm = algorithm;
+ this.spiImpl = algPramSpi;
+ }
+
+ /**
+ * Returns a new instance of {@code AlgorithmParameters} for the specified
+ * algorithm.
+ *
+ * @param algorithm
+ * the name of the algorithm to use.
+ * @return a new instance of {@code AlgorithmParameters} for the specified
+ * algorithm.
+ * @throws NoSuchAlgorithmException
+ * if the specified algorithm is not available.
+ * @throws NullPointerException
+ * if {@code algorithm} is {@code null}.
+ */
+ public static AlgorithmParameters getInstance(String algorithm)
+ throws NoSuchAlgorithmException {
+ if (algorithm == null) {
+ throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+ }
+ synchronized (engine) {
+ engine.getInstance(algorithm, null);
+ return new AlgorithmParameters((AlgorithmParametersSpi) engine.spi,
+ engine.provider, algorithm);
+ }
+ }
+
+ /**
+ * Returns a new instance of {@code AlgorithmParameters} from the specified
+ * provider for the specified algorithm.
+ *
+ * @param algorithm
+ * the name of the algorithm to use.
+ * @param provider
+ * name of the provider of the {@code AlgorithmParameters}.
+ * @return a new instance of {@code AlgorithmParameters} for the specified
+ * algorithm.
+ * @throws NoSuchAlgorithmException
+ * if the specified algorithm is not available.
+ * @throws NoSuchProviderException
+ * if the specified provider is not available.
+ * @throws IllegalArgumentException
+ * if {@code provider} is {@code null} or of length zero.
+ * @throws NullPointerException
+ * if {@code algorithm} is {@code null}.
+ */
+ public static AlgorithmParameters getInstance(String algorithm,
+ String provider) throws NoSuchAlgorithmException,
+ NoSuchProviderException {
+ if ((provider == null) || (provider.length() == 0)) {
+ throw new IllegalArgumentException(Messages.getString("security.02")); //$NON-NLS-1$
+ }
+ Provider p = Security.getProvider(provider);
+ if (p == null) {
+ throw new NoSuchProviderException(Messages.getString("security.03", //$NON-NLS-1$
+ provider));
+ }
+ return getInstance(algorithm, p);
+ }
+
+ /**
+ * Returns a new instance of {@code AlgorithmParameters} from the specified
+ * provider for the specified algorithm.
+ *
+ * @param algorithm
+ * the name of the algorithm to use.
+ * @param provider
+ * the provider of the {@code AlgorithmParameters}.
+ * @return a new instance of {@code AlgorithmParameters} for the specified
+ * algorithm.
+ * @throws NoSuchAlgorithmException
+ * if the specified algorithm is not available.
+ * @throws NullPointerException
+ * if {@code algorithm} is {@code null}.
+ * @throws IllegalArgumentException
+ * if {@code provider} is {@code null}.
+ */
+ public static AlgorithmParameters getInstance(String algorithm,
+ Provider provider) throws NoSuchAlgorithmException {
+ if (provider == null) {
+ throw new IllegalArgumentException(Messages.getString("security.04")); //$NON-NLS-1$
+ }
+ if (algorithm == null) {
+ throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+ }
+ synchronized (engine) {
+ engine.getInstance(algorithm, provider, null);
+ return new AlgorithmParameters((AlgorithmParametersSpi) engine.spi,
+ provider, algorithm);
+ }
+ }
+
+ /**
+ * Returns the provider associated with this {@code AlgorithmParameters}.
+ *
+ * @return the provider associated with this {@code AlgorithmParameters}.
+ */
+ public final Provider getProvider() {
+ return provider;
+ }
+
+ /**
+ * Returns the name of the algorithm.
+ *
+ * @return the name of the algorithm.
+ */
+ public final String getAlgorithm() {
+ return algorithm;
+ }
+
+ /**
+ * Initializes this {@code AlgorithmParameters} with the specified {@code
+ * AlgorithmParameterSpec}.
+ *
+ * @param paramSpec
+ * the parameter specification.
+ * @throws InvalidParameterSpecException
+ * if this {@code AlgorithmParameters} has already been
+ * initialized or the given {@code paramSpec} is not appropriate
+ * for initializing this {@code AlgorithmParameters}.
+ */
+ public final void init(AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException {
+ if (initialized) {
+ throw new InvalidParameterSpecException(
+ Messages.getString("security.1E")); //$NON-NLS-1$
+ }
+ spiImpl.engineInit(paramSpec);
+ initialized = true;
+ }
+
+ /**
+ * Initializes this {@code AlgorithmParameters} with the specified {@code
+ * byte[]} using the default decoding format for parameters. The default
+ * encoding format is ASN.1.
+ *
+ * @param params
+ * the encoded parameters.
+ * @throws IOException
+ * if this {@code AlgorithmParameters} has already been
+ * initialized, or the parameter could not be encoded.
+ */
+ public final void init(byte[] params) throws IOException {
+ if (initialized) {
+ throw new IOException(Messages.getString("security.1E")); //$NON-NLS-1$
+ }
+ spiImpl.engineInit(params);
+ initialized = true;
+ }
+
+ /**
+ * Initializes this {@code AlgorithmParameters} with the specified {@code
+ * byte[]} using the specified decoding format.
+ *
+ * @param params
+ * the encoded parameters.
+ * @param format
+ * the name of the decoding format.
+ * @throws IOException
+ * if this {@code AlgorithmParameters} has already been
+ * initialized, or the parameter could not be encoded.
+ */
+ public final void init(byte[] params, String format) throws IOException {
+ if (initialized) {
+ throw new IOException(Messages.getString("security.1E")); //$NON-NLS-1$
+ }
+ spiImpl.engineInit(params, format);
+ initialized = true;
+ }
+
+ /**
+ * Returns the {@code AlgorithmParameterSpec} for this {@code
+ * AlgorithmParameters}.
+ *
+ * @param paramSpec
+ * the type of the parameter specification in which this
+ * parameters should be converted.
+ * @return the {@code AlgorithmParameterSpec} for this {@code
+ * AlgorithmParameters}.
+ * @throws InvalidParameterSpecException
+ * if this {@code AlgorithmParameters} has already been
+ * initialized, or if this parameters could not be converted to
+ * the specified class.
+ */
+ public final <T extends AlgorithmParameterSpec> T getParameterSpec(Class<T> paramSpec)
+ throws InvalidParameterSpecException {
+ if (!initialized) {
+ throw new InvalidParameterSpecException(
+ Messages.getString("security.1F")); //$NON-NLS-1$
+ }
+ return spiImpl.engineGetParameterSpec(paramSpec);
+ }
+
+ /**
+ * Returns this {@code AlgorithmParameters} in their default encoding
+ * format. The default encoding format is ASN.1.
+ *
+ * @return the encoded parameters.
+ * @throws IOException
+ * if this {@code AlgorithmParameters} has already been
+ * initialized, or if this parameters could not be encoded.
+ */
+ public final byte[] getEncoded() throws IOException {
+ if (!initialized) {
+ throw new IOException(Messages.getString("security.1F")); //$NON-NLS-1$
+ }
+ return spiImpl.engineGetEncoded();
+ }
+
+ /**
+ * Returns this {@code AlgorithmParameters} in the specified encoding
+ * format.
+ *
+ * @param format
+ * the name of the encoding format.
+ * @return the encoded parameters.
+ * @throws IOException
+ * if this {@code AlgorithmParameters} has already been
+ * initialized, or if this parameters could not be encoded.
+ */
+ public final byte[] getEncoded(String format) throws IOException {
+ if (!initialized) {
+ throw new IOException(Messages.getString("security.1F")); //$NON-NLS-1$
+ }
+ return spiImpl.engineGetEncoded(format);
+ }
+
+ /**
+ * Returns a string containing a concise, human-readable description of this
+ * {@code AlgorithmParameters}.
+ *
+ * @return a printable representation for this {@code AlgorithmParameters}.
+ */
+ @Override
+ public final String toString() {
+ if (!initialized) {
+ return null;
+ }
+ return spiImpl.engineToString();
+ }
+}
diff --git a/luni/src/main/java/java/security/AlgorithmParametersSpi.java b/luni/src/main/java/java/security/AlgorithmParametersSpi.java
new file mode 100644
index 0000000..41b30bc
--- /dev/null
+++ b/luni/src/main/java/java/security/AlgorithmParametersSpi.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+/**
+ * {@code AlgorithmParametersSpi} is the Service Provider Interface (SPI)
+ * definition for {@code AlgorithmParameters}.
+ *
+ * @see AlgorithmParameters
+ */
+public abstract class AlgorithmParametersSpi {
+
+ /**
+ * Initializes this {@code AlgorithmParametersSpi} with the specified
+ * {@code AlgorithmParameterSpec}.
+ *
+ * @param paramSpec
+ * the parameter specification.
+ * @throws InvalidParameterSpecException
+ * if this {@code AlgorithmParametersSpi} has already been
+ * initialized or the given {@code paramSpec} is not appropriate
+ * for initializing this {@code AlgorithmParametersSpi}.
+ */
+ protected abstract void engineInit(AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException;
+
+ /**
+ * Initializes this {@code AlgorithmParametersSpi} with the specified
+ * {@code byte[]} using the default decoding format for parameters. The
+ * default encoding format is ASN.1.
+ *
+ * @param params
+ * the encoded parameters.
+ * @throws IOException
+ * if this {@code AlgorithmParametersSpi} has already been
+ * initialized, or the parameter could not be encoded.
+ */
+ protected abstract void engineInit(byte[] params) throws IOException;
+
+ /**
+ * Initializes this {@code AlgorithmParametersSpi} with the specified
+ * {@code byte[]} using the specified decoding format.
+ *
+ * @param params
+ * the encoded parameters.
+ * @param format
+ * the name of the decoding format.
+ * @throws IOException
+ * if this {@code AlgorithmParametersSpi} has already been
+ * initialized, or the parameter could not be encoded.
+ */
+ protected abstract void engineInit(byte[] params, String format)
+ throws IOException;
+
+ /**
+ * Returns the {@code AlgorithmParameterSpec} for this {@code
+ * AlgorithmParametersSpi}.
+ *
+ * @param paramSpec
+ * the type of the parameter specification in which this
+ * parameters should be converted.
+ * @return the {@code AlgorithmParameterSpec} for this {@code
+ * AlgorithmParametersSpi}.
+ * @throws InvalidParameterSpecException
+ * if this {@code AlgorithmParametersSpi} has already been
+ * initialized, or if this parameters could not be converted to
+ * the specified class.
+ */
+ protected abstract <T extends AlgorithmParameterSpec> T engineGetParameterSpec(
+ Class<T> paramSpec) throws InvalidParameterSpecException;
+
+ /**
+ * Returns the parameters in their default encoding format. The default
+ * encoding format is ASN.1.
+ *
+ * @return the encoded parameters.
+ * @throws IOException
+ * if this {@code AlgorithmParametersSpi} has already been
+ * initialized, or if this parameters could not be encoded.
+ */
+ protected abstract byte[] engineGetEncoded() throws IOException;
+
+ /**
+ * Returns the parameters in the specified encoding format.
+ *
+ * @param format
+ * the name of the encoding format.
+ * @return the encoded parameters.
+ * @throws IOException
+ * if this {@code AlgorithmParametersSpi} has already been
+ * initialized, or if this parameters could not be encoded.
+ */
+ protected abstract byte[] engineGetEncoded(String format)
+ throws IOException;
+
+ /**
+ * Returns a string containing a concise, human-readable description of this
+ * {@code AlgorithmParametersSpi}.
+ *
+ * @return a printable representation for this {@code
+ * AlgorithmParametersSpi}.
+ */
+ protected abstract String engineToString();
+
+}
diff --git a/luni/src/main/java/java/security/AllPermission.java b/luni/src/main/java/java/security/AllPermission.java
new file mode 100644
index 0000000..c12bb27
--- /dev/null
+++ b/luni/src/main/java/java/security/AllPermission.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+
+/**
+ * {@code AllPermission} represents the permission to perform any operation.
+ * Since its {@link #implies(Permission)} method always returns {@code true},
+ * granting this permission is equivalent to disabling security.
+ */
+public final class AllPermission extends Permission {
+
+ /**
+ * @serial
+ */
+ private static final long serialVersionUID = -2916474571451318075L;
+
+ // Permission name
+ private static final String ALL_PERMISSIONS = "<all permissions>"; //$NON-NLS-1$
+
+ // Actions name
+ private static final String ALL_ACTIONS = "<all actions>"; //$NON-NLS-1$
+
+ /**
+ * Constructs a new instance of {@code AllPermission}. The two argument
+ * version is provided for class {@code Policy} so that it has a consistent
+ * call pattern across all permissions. The name and action list are both
+ * ignored.
+ *
+ * @param name
+ * ignored.
+ * @param actions
+ * ignored.
+ */
+ public AllPermission(String name, String actions) {
+ super(ALL_PERMISSIONS);
+ }
+
+ /**
+ * Constructs a new instance of {@code AllPermission}.
+ */
+ public AllPermission() {
+ super(ALL_PERMISSIONS);
+ }
+
+ /**
+ * Compares the specified object with this {@code AllPermission} for
+ * equality and returns {@code true} if the specified object is equal,
+ * {@code false} otherwise. To be equal, the given object needs to be an
+ * instance of {@code AllPermission}.
+ *
+ * @param obj
+ * object to be compared for equality with this {@code
+ * AllPermission}.
+ * @return {@code true} if the specified object is equal to this {@code
+ * AllPermission}, otherwise {@code false}.
+ * @see #hashCode
+ */
+ @Override
+ public boolean equals(Object obj) {
+ return (obj instanceof AllPermission);
+ }
+
+ /**
+ * Returns the hash code value for this {@code AllPermission}. Returns the
+ * same hash code for {@code AllPermission}s that are equal to each other as
+ * required by the general contract of {@link Object#hashCode}.
+ *
+ * @return the hash code value for this {@code AllPermission}.
+ * @see Object#equals(Object)
+ * @see AllPermission#equals(Object)
+ */
+ @Override
+ public int hashCode() {
+ return 1;
+ }
+
+ /**
+ * Returns the actions associated with this {@code AllPermission}. Since
+ * {@code AllPermission} objects allow all actions, this method returns
+ * always the string "&lt;all actions&gt;".
+ *
+ * @return the actions associated with this {@code AllPermission}.
+ */
+ @Override
+ public String getActions() {
+ return ALL_ACTIONS;
+ }
+
+ /**
+ * Indicates whether the given permission is implied by this permission.
+ * {@code AllPermission} objects imply all other permissions.
+ *
+ * @return always {@code true}.
+ * @param permission
+ * the permission to check.
+ */
+ @Override
+ public boolean implies(Permission permission) {
+ return true;
+ }
+
+ /**
+ * Returns a new {@code PermissionCollection} for holding permissions of
+ * this class.
+ *
+ * @return a new {@code PermissionCollection}.
+ */
+ @Override
+ public PermissionCollection newPermissionCollection() {
+ return new AllPermissionCollection();
+ }
+}
diff --git a/luni/src/main/java/java/security/AllPermissionCollection.java b/luni/src/main/java/java/security/AllPermissionCollection.java
new file mode 100644
index 0000000..5b28420
--- /dev/null
+++ b/luni/src/main/java/java/security/AllPermissionCollection.java
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * Specific {@code PermissionCollection} for storing {@code AllPermission}s. All
+ * instances of {@code AllPermission} are equivalent, so it is enough to store a
+ * single added instance.
+ *
+ * @see AllPermission
+ */
+final class AllPermissionCollection extends PermissionCollection {
+
+ private static final long serialVersionUID = -4023755556366636806L;
+
+ private static final ObjectStreamField[] serialPersistentFields = { new ObjectStreamField(
+ "all_allowed", Boolean.TYPE), }; //$NON-NLS-1$
+
+ // Single element of collection.
+ private transient Permission all;
+
+ /**
+ * Adds an {@code AllPermission} to the collection.
+ */
+ @Override
+ public void add(Permission permission) {
+ if (isReadOnly()) {
+ throw new SecurityException(Messages.getString("security.15")); //$NON-NLS-1$
+ }
+ if (!(permission instanceof AllPermission)) {
+ throw new IllegalArgumentException(Messages.getString("security.16", //$NON-NLS-1$
+ permission));
+ }
+ all = permission;
+ }
+
+ /**
+ * Returns the enumeration of the collection.
+ */
+ @Override
+ public Enumeration<Permission> elements() {
+ return new SingletonEnumeration<Permission>(all);
+ }
+
+ /**
+ * An auxiliary implementation for enumerating a single object.
+ *
+ */
+ final static class SingletonEnumeration<E> implements Enumeration<E> {
+
+ private E element;
+
+ /**
+ * Constructor taking the single element.
+ * @param single the element
+ */
+ public SingletonEnumeration(E single) {
+ element = single;
+ }
+
+ /**
+ * Returns true if the element is not enumerated yet.
+ */
+ public boolean hasMoreElements() {
+ return element != null;
+ }
+
+ /**
+ * Returns the element and clears internal reference to it.
+ */
+ public E nextElement() {
+ if (element == null) {
+ throw new NoSuchElementException(Messages.getString("security.17")); //$NON-NLS-1$
+ }
+ E last = element;
+ element = null;
+ return last;
+ }
+ }
+
+ /**
+ * Indicates whether the argument permission is implied by the receiver.
+ * {@code AllPermission} objects imply all other permissions.
+ *
+ * @return boolean {@code true} if the argument permission is implied by the
+ * receiver, and {@code false} if it is not.
+ * @param permission
+ * the permission to check.
+ */
+ @Override
+ public boolean implies(Permission permission) {
+ return all != null;
+ }
+
+ /**
+ * Writes the fields according to expected format, adding the boolean field
+ * {@code all_allowed} which is {@code true} if this collection is not
+ * empty.
+ */
+ private void writeObject(java.io.ObjectOutputStream out) throws IOException {
+ ObjectOutputStream.PutField fields = out.putFields();
+ fields.put("all_allowed", all != null); //$NON-NLS-1$
+ out.writeFields();
+ }
+
+ /**
+ * Restores internal state.
+ */
+ private void readObject(java.io.ObjectInputStream in) throws IOException,
+ ClassNotFoundException {
+ ObjectInputStream.GetField fields = in.readFields();
+ if (fields.get("all_allowed", false)) { //$NON-NLS-1$
+ all = new AllPermission();
+ }
+ }
+}
diff --git a/luni/src/main/java/java/security/AuthProvider.java b/luni/src/main/java/java/security/AuthProvider.java
new file mode 100644
index 0000000..15324b3
--- /dev/null
+++ b/luni/src/main/java/java/security/AuthProvider.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.LoginException;
+
+/**
+ * {@code AuthProvider} is an abstract superclass for Java Security {@code
+ * Provider} which provide login and logout.
+ */
+public abstract class AuthProvider extends Provider {
+
+ /**
+ * @serial
+ */
+ private static final long serialVersionUID = 4197859053084546461L;
+
+ /**
+ * Constructs a new instance of {@code AuthProvider} with its name, version
+ * and description.
+ *
+ * @param name
+ * the name of the provider.
+ * @param version
+ * the version of the provider.
+ * @param info
+ * a description of the provider.
+ */
+ protected AuthProvider(String name, double version, String info) {
+ super(name, version, info);
+ }
+
+ /**
+ * Performs a login into this {@code AuthProvider}. The specified {@code
+ * CallbackHandler} is used to obtain information from the caller.
+ * <p>
+ * If a {@code SecurityManager} is installed, code calling this method needs
+ * the {@code SecurityPermission} {@code authProvider.NAME} (where NAME is
+ * the provider name) to be granted, otherwise a {@code SecurityException}
+ * will be thrown.
+ *
+ * @param subject
+ * the subject that is used to login.
+ * @param handler
+ * the handler to obtain authentication information from the
+ * caller.
+ * @throws LoginException
+ * if the login fails.
+ * @throws SecurityException
+ * if a {@code SecurityManager} is installed and the caller does
+ * not have permission to invoke this method.
+ */
+ public abstract void login(Subject subject, CallbackHandler handler) throws LoginException;
+
+ /**
+ * Performs a logout from this {@code AuthProvider}.
+ * <p>
+ * If a {@code SecurityManager} is installed, code calling this method needs
+ * the {@code SecurityPermission} {@code authProvider.NAME} (where NAME is
+ * the provider name) to be granted, otherwise a {@code SecurityException}
+ * will be thrown.
+ *
+ * @throws LoginException
+ * if the logout fails.
+ * @throws SecurityException
+ * if a {@code SecurityManager} is installed and the caller does
+ * not have permission to invoke this method.
+ */
+ public abstract void logout() throws LoginException;
+
+ /**
+ * Sets the {@code CallbackHandler} to this {@code AuthProvider}. If no
+ * handler is passed to the {@link #login(Subject, CallbackHandler)} method,
+ * this {@code AuthProvider} is using the specified {@code CallbackHandler}.
+ * <p>
+ * If no handler is set, this {@code AuthProvider} uses the {@code
+ * CallbackHandler} specified by the {@code
+ * auth.login.defaultCallbackHandler} security property.
+ * <p>
+ * If a {@code SecurityManager} is installed, code calling this method needs
+ * the {@code SecurityPermission} {@code authProvider.NAME} (where NAME is
+ * the provider name) to be granted, otherwise a {@code SecurityException}
+ * will be thrown.
+ *
+ * @param handler
+ * the handler to obtain authentication information from the
+ * caller.
+ * @throws SecurityException
+ * if a {@code SecurityManager} is installed and the caller does
+ * not have permission to invoke this method.
+ */
+ public abstract void setCallbackHandler(CallbackHandler handler);
+}
diff --git a/luni/src/main/java/java/security/BasicPermission.java b/luni/src/main/java/java/security/BasicPermission.java
new file mode 100644
index 0000000..aa49cba
--- /dev/null
+++ b/luni/src/main/java/java/security/BasicPermission.java
@@ -0,0 +1,215 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.io.IOException;
+import java.io.Serializable;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * {@code BasicPermission} is the common base class of all permissions which
+ * have a name but no action lists. A {@code BasicPermission} is granted or it
+ * is not.
+ * <p>
+ * Names of a BasicPermission follow the dot separated, hierarchical property
+ * naming convention. Asterisk '*' can be used as wildcards. Either by itself,
+ * matching anything, or at the end of the name, immediately preceded by a '.'.
+ * For example:
+ *
+ * <pre>
+ * java.io.* grants all permissions under the java.io permission hierarchy
+ * * grants all permissions
+ * </pre>
+ * <p>
+ * While this class ignores the action list in the
+ * {@link #BasicPermission(String, String)} constructor, subclasses may
+ * implement actions on top of this class.
+ */
+public abstract class BasicPermission extends Permission implements
+ Serializable {
+
+ private static final long serialVersionUID = 6279438298436773498L;
+
+ /**
+ * Constructs a new instance of {@code BasicPermission} with the specified
+ * name.
+ *
+ * @param name
+ * the name of the permission.
+ * @throws NullPointerException if {@code name} is {@code null}.
+ * @throws IllegalArgumentException if {@code name.length() == 0}.
+ */
+ public BasicPermission(String name) {
+ super(name);
+ checkName(name);
+ }
+
+ /**
+ * Constructs a new instance of {@code BasicPermission} with the specified
+ * name. The {@code action} parameter is ignored.
+ *
+ * @param name
+ * the name of the permission.
+ * @param action
+ * is ignored.
+ * @throws NullPointerException
+ * if {@code name} is {@code null}.
+ * @throws IllegalArgumentException
+ * if {@code name.length() == 0}.
+ */
+ public BasicPermission(String name, String action) {
+ super(name);
+ checkName(name);
+ }
+
+ /**
+ * Checks name parameter
+ */
+ private final void checkName(String name) {
+ if (name == null) {
+ throw new NullPointerException(Messages.getString("security.28")); //$NON-NLS-1$
+ }
+ if (name.length() == 0) {
+ throw new IllegalArgumentException(Messages.getString("security.29")); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Compares the specified object with this {@code BasicPermission} for
+ * equality. Returns {@code true} if the specified object has the same class
+ * and the two {@code Permissions}s have the same name.
+ * <p>
+ * The {@link #implies(Permission)} method should be used for making access
+ * control checks.
+ *
+ * @param obj
+ * object to be compared for equality with this {@code
+ * BasicPermission}.
+ * @return {@code true} if the specified object is equal to this {@code
+ * BasicPermission}, otherwise {@code false}.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+
+ if (obj != null && obj.getClass() == this.getClass()) {
+ return this.getName().equals(((Permission)obj).getName());
+ }
+ return false;
+ }
+
+ /**
+ * Returns the hash code value for this {@code BasicPermission}. Returns the
+ * same hash code for {@code BasicPermission}s that are equal to each other
+ * as required by the general contract of {@link Object#hashCode}.
+ *
+ * @return the hash code value for this {@code BasicPermission}.
+ * @see Object#equals(Object)
+ * @see BasicPermission#equals(Object)
+ */
+ @Override
+ public int hashCode() {
+ return getName().hashCode();
+ }
+
+ /**
+ * Returns the actions associated with this permission. Since {@code
+ * BasicPermission} instances have no actions, an empty string is returned.
+ *
+ * @return an empty string.
+ */
+ @Override
+ public String getActions() {
+ return ""; //$NON-NLS-1$
+ }
+
+ /**
+ * Indicates whether the specified permission is implied by this permission.
+ *
+ * @param permission
+ * the permission to check against this permission.
+ * @return {@code true} if the specified permission is implied by this
+ * permission, {@code false} otherwise.
+ */
+ @Override
+ public boolean implies(Permission permission) {
+ if (permission != null && permission.getClass() == this.getClass()) {
+ return nameImplies(getName(), permission.getName());
+ }
+ return false;
+ }
+
+ /**
+ * Checks if {@code thisName} implies {@code thatName},
+ * accordingly to hierarchical property naming convention.
+ * It is assumed that names cannot be {@code null} or empty.
+ */
+ static boolean nameImplies(String thisName, String thatName) {
+ if (thisName == thatName) {
+ return true;
+ }
+ int end = thisName.length();
+ if (end > thatName.length()) {
+ return false;
+ }
+ if (thisName.charAt(--end) == '*'
+ && (end == 0 || thisName.charAt(end - 1) == '.')) {
+ //wildcard found
+ end--;
+ } else if (end != (thatName.length()-1)) {
+ //names are not equal
+ return false;
+ }
+ for (int i = end; i >= 0; i--) {
+ if (thisName.charAt(i) != thatName.charAt(i)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns an empty {@link PermissionCollection} for holding permissions.
+ * <p>
+ * For {@code PermissionCollection} (and subclasses which do not override
+ * this method), the collection which is returned does <em>not</em> invoke
+ * the {@link #implies(Permission)} method of the permissions which are
+ * stored in it when checking if the collection implies a permission.
+ * Instead, it assumes that if the type of the permission is correct, and
+ * the name of the permission is correct, there is a match.
+ *
+ * @return an empty {@link PermissionCollection} for holding permissions.
+ * @see BasicPermissionCollection
+ */
+ @Override
+ public PermissionCollection newPermissionCollection() {
+ return new BasicPermissionCollection();
+ }
+
+ /**
+ * Checks name after default deserialization.
+ */
+ private void readObject(java.io.ObjectInputStream in) throws IOException,
+ ClassNotFoundException {
+ in.defaultReadObject();
+ checkName(this.getName());
+ }
+}
diff --git a/luni/src/main/java/java/security/BasicPermissionCollection.java b/luni/src/main/java/java/security/BasicPermissionCollection.java
new file mode 100644
index 0000000..820ae7f
--- /dev/null
+++ b/luni/src/main/java/java/security/BasicPermissionCollection.java
@@ -0,0 +1,202 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * Specific {@code PermissionCollection} for storing {@code BasicPermissions} of
+ * arbitrary type.
+ *
+ * @see BasicPermission
+ * @see PermissionCollection
+ */
+final class BasicPermissionCollection extends PermissionCollection {
+
+ private static final long serialVersionUID = 739301742472979399L;
+
+ private static final ObjectStreamField[] serialPersistentFields = {
+ new ObjectStreamField("all_allowed", Boolean.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("permissions", Hashtable.class), //$NON-NLS-1$
+ new ObjectStreamField("permClass", Class.class), }; //$NON-NLS-1$
+
+ //should be final, but because of writeObject() cannot be
+ private transient Map<String, Permission> items = new HashMap<String, Permission>();
+
+ // true if this Collection contains a BasicPermission with '*' as its permission name
+ private transient boolean allEnabled; // = false;
+
+ private Class<? extends Permission> permClass;
+
+ /**
+ * Adds a permission to the collection. The first added permission must be a
+ * subclass of BasicPermission, next permissions must be of the same class
+ * as the first one.
+ *
+ * @see java.security.PermissionCollection#add(java.security.Permission)
+ */
+ @Override
+ public void add(Permission permission) {
+ if (isReadOnly()) {
+ throw new SecurityException(Messages.getString("security.15")); //$NON-NLS-1$
+ }
+ if (permission == null) {
+ throw new IllegalArgumentException(Messages.getString("security.20")); //$NON-NLS-1$
+ }
+
+ Class<? extends Permission> inClass = permission.getClass();
+ if (permClass != null) {
+ if (permClass != inClass) {
+ throw new IllegalArgumentException(Messages.getString("security.16", //$NON-NLS-1$
+ permission));
+ }
+ } else if( !(permission instanceof BasicPermission)) {
+ throw new IllegalArgumentException(Messages.getString("security.16", //$NON-NLS-1$
+ permission));
+ } else {
+ // this is the first element provided that another thread did not add
+ synchronized (this) {
+ if (permClass != null && inClass != permClass) {
+ throw new IllegalArgumentException(Messages.getString("security.16", //$NON-NLS-1$
+ permission));
+ }
+ permClass = inClass;
+ }
+ }
+
+ String name = permission.getName();
+ items.put(name, permission);
+ allEnabled = allEnabled || (name.length() == 1 && '*' == name.charAt(0));
+ }
+
+ /**
+ * Returns enumeration of contained elements.
+ */
+ @Override
+ public Enumeration<Permission> elements() {
+ return Collections.enumeration(items.values());
+ }
+
+ /**
+ * Indicates whether the argument permission is implied by the receiver.
+ *
+ * @return boolean {@code true} if the argument permission is implied by the
+ * receiver, and {@code false} if it is not.
+ * @param permission
+ * the permission to check.
+ * @see Permission
+ */
+ @Override
+ public boolean implies(Permission permission) {
+ if (permission == null || permission.getClass() != permClass) {
+ return false;
+ }
+ if (allEnabled) {
+ return true;
+ }
+ String checkName = permission.getName();
+ //first check direct coincidence
+ if (items.containsKey(checkName)) {
+ return true;
+ }
+ //now check if there are suitable wildcards
+ //suppose we have "a.b.c", let's check "a.b.*" and "a.*"
+ char[] name = checkName.toCharArray();
+ //I presume that "a.b.*" does not imply "a.b."
+ //so the dot at end is ignored
+ int pos = name.length - 2;
+ for (; pos >= 0; pos--) {
+ if (name[pos] == '.') {
+ break;
+ }
+ }
+ while (pos >= 0) {
+ name[pos + 1] = '*';
+ if (items.containsKey(new String(name, 0, pos + 2))) {
+ return true;
+ }
+ for (--pos; pos >= 0; pos--) {
+ if (name[pos] == '.') {
+ break;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Expected format is the following:
+ * <dl>
+ * <dt>boolean all_allowed
+ * <dd>This is set to true if this BasicPermissionCollection contains a
+ * {@code BasicPermission} with '*' as its permission name.
+ * <dt>Class&lt;T&gt; permClass
+ * <dd>The class to which all {@code BasicPermission}s in this
+ * BasicPermissionCollection belongs.
+ * <dt>Hashtable&lt;K,V&gt; permissions
+ * <dd>The {@code BasicPermission}s in this collection. All {@code
+ * BasicPermission}s in the collection must belong to the same class. The
+ * Hashtable is indexed by the {@code BasicPermission} name; the value of
+ * the Hashtable entry is the permission.
+ * </dl>
+ */
+ private void writeObject(java.io.ObjectOutputStream out) throws IOException {
+ ObjectOutputStream.PutField fields = out.putFields();
+ fields.put("all_allowed", allEnabled); //$NON-NLS-1$
+ fields.put("permissions", new Hashtable<String, Permission>(items)); //$NON-NLS-1$
+ fields.put("permClass", permClass); //$NON-NLS-1$
+ out.writeFields();
+ }
+
+ /**
+ * Reads the object from stream and checks its consistency: all contained
+ * permissions must be of the same subclass of BasicPermission.
+ */
+ private void readObject(java.io.ObjectInputStream in) throws IOException,
+ ClassNotFoundException {
+ ObjectInputStream.GetField fields = in.readFields();
+
+ items = new HashMap<String, Permission>();
+ synchronized (this) {
+ permClass = (Class<? extends Permission>)fields.get("permClass", null); //$NON-NLS-1$
+ items.putAll((Hashtable<String, Permission>) fields.get(
+ "permissions", new Hashtable<String, Permission>())); //$NON-NLS-1$
+ for (Iterator<Permission> iter = items.values().iterator(); iter.hasNext();) {
+ if (iter.next().getClass() != permClass) {
+ throw new InvalidObjectException(Messages.getString("security.24")); //$NON-NLS-1$
+ }
+ }
+ allEnabled = fields.get("all_allowed", false); //$NON-NLS-1$
+ if (allEnabled && !items.containsKey("*")) { //$NON-NLS-1$
+ throw new InvalidObjectException(Messages.getString("security.25")); //$NON-NLS-1$
+ }
+ }
+ }
+}
diff --git a/luni/src/main/java/java/security/Certificate.java b/luni/src/main/java/java/security/Certificate.java
new file mode 100644
index 0000000..b30352d
--- /dev/null
+++ b/luni/src/main/java/java/security/Certificate.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * {@code Certificate} represents an identity certificate, such as X.509 or PGP.
+ * Note: A {@code Certificate} instances does not make any statement about the
+ * validity of itself. It's in the responsibility of the application to verify
+ * the validity of its certificates.
+ *
+ * @deprecated Replaced by behavior in {@link java.security.cert}
+ * @see java.security.cert.Certificate
+ */
+@Deprecated
+public interface Certificate {
+
+ /**
+ * Decodes a certificate from the given {@code InputStream}. The format of
+ * the data to encode must be that identified by {@link #getFormat()} and
+ * encoded by {@link #encode(OutputStream)}.
+ *
+ * @param stream
+ * the {@code InputStream} to read from.
+ * @throws KeyException
+ * if certificate information is incomplete or incorrect.
+ * @throws IOException
+ * if an exception is thrown by accessing the provided stream.
+ * @see #encode(OutputStream)
+ * @see #getFormat()
+ */
+ public void decode(InputStream stream) throws KeyException, IOException;
+
+ /**
+ * Encodes this certificate to an output stream. The
+ * {@link #decode(InputStream)} method must be able to decode the format
+ * written by this method.
+ *
+ * @param stream
+ * the {@code OutputStream} to encode this certificate to.
+ * @throws KeyException
+ * if certificate information is incomplete or incorrect.
+ * @throws IOException
+ * if an exception is thrown by accessing the provided stream.
+ * @see #decode(InputStream)
+ */
+ public void encode(OutputStream stream) throws KeyException, IOException;
+
+ /**
+ * Returns a string identifying the format of this certificate.
+ *
+ * @return a string identifying the format of this certificate.
+ */
+ public String getFormat();
+
+ /**
+ * Returns the guarantor of this certificate. That guarantor guarantees,
+ * that the public key of this certificate is from the principal returned by
+ * {@link #getPrincipal()}.
+ *
+ * @return the guarantor of this certificate.
+ * @see #getPrincipal()
+ */
+ public Principal getGuarantor();
+
+ /**
+ * Returns the principal of this certificate. The principal is guaranteed by
+ * the guarantor returned by {@link #getGuarantor()}.
+ *
+ * @return the principal of this certificate.
+ * @see #getGuarantor()
+ */
+ public Principal getPrincipal();
+
+ /**
+ * Returns the public key of this certificate. The public key is guaranteed
+ * by the guarantor to belong to the principal.
+ *
+ * @return the public key of this certificate.
+ * @see #getGuarantor()
+ * @see Certificate#getPrincipal()
+ */
+ public PublicKey getPublicKey();
+
+ /**
+ * Returns a string containing a concise, human-readable description of the
+ * this {@code Certificate}.
+ *
+ * @param detailed
+ * whether or not this method should return detailed information.
+ * @return a string representation of this certificate.
+ */
+ public String toString(boolean detailed);
+}
diff --git a/luni/src/main/java/java/security/CodeSigner.java b/luni/src/main/java/java/security/CodeSigner.java
new file mode 100644
index 0000000..24d2b55
--- /dev/null
+++ b/luni/src/main/java/java/security/CodeSigner.java
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.io.Serializable;
+import java.security.cert.CertPath;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * {@code CodeSigner} represents a signer of code. Instances are immutable.
+ */
+public final class CodeSigner implements Serializable {
+
+ private static final long serialVersionUID = 6819288105193937581L;
+
+ private CertPath signerCertPath;
+
+ private Timestamp timestamp;
+
+ // Cached hash code value
+ private transient int hash;
+
+ /**
+ * Constructs a new instance of {@code CodeSigner}.
+ *
+ * @param signerCertPath
+ * the certificate path associated with this code signer.
+ * @param timestamp
+ * the time stamp associated with this code signer, maybe {@code
+ * null}.
+ * @throws NullPointerException
+ * if {@code signerCertPath} is {@code null}.
+ */
+ public CodeSigner(CertPath signerCertPath, Timestamp timestamp) {
+ if (signerCertPath == null) {
+ throw new NullPointerException(Messages.getString("security.10")); //$NON-NLS-1$
+ }
+ this.signerCertPath = signerCertPath;
+ this.timestamp = timestamp;
+ }
+
+ /**
+ * Compares the specified object with this {@code CodeSigner} for equality.
+ * Returns {@code true} if the specified object is also an instance of
+ * {@code CodeSigner}, the two {@code CodeSigner} encapsulate the same
+ * certificate path and the same time stamp, if present in both.
+ *
+ * @param obj
+ * object to be compared for equality with this {@code
+ * CodeSigner}.
+ * @return {@code true} if the specified object is equal to this {@code
+ * CodeSigner}, otherwise {@code false}.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof CodeSigner) {
+ CodeSigner that = (CodeSigner) obj;
+ if (!signerCertPath.equals(that.signerCertPath)) {
+ return false;
+ }
+ return timestamp == null ? that.timestamp == null : timestamp
+ .equals(that.timestamp);
+ }
+ return false;
+ }
+
+ /**
+ * Returns the certificate path associated with this {@code CodeSigner}.
+ *
+ * @return the certificate path associated with this {@code CodeSigner}.
+ */
+ public CertPath getSignerCertPath() {
+ return signerCertPath;
+ }
+
+ /**
+ * Returns the time stamp associated with this {@code CodeSigner}.
+ *
+ * @return the time stamp associated with this {@code CodeSigner}, maybe
+ * {@code null}.
+ */
+ public Timestamp getTimestamp() {
+ return timestamp;
+ }
+
+ /**
+ * Returns the hash code value for this {@code CodeSigner}. Returns the same
+ * hash code for {@code CodeSigner}s that are equal to each other as
+ * required by the general contract of {@link Object#hashCode}.
+ *
+ * @return the hash code value for this {@code CodeSigner}.
+ * @see Object#equals(Object)
+ * @see CodeSigner#equals(Object)
+ */
+ @Override
+ public int hashCode() {
+ if (hash == 0) {
+ hash = signerCertPath.hashCode()
+ ^ (timestamp == null ? 0 : timestamp.hashCode());
+ }
+ return hash;
+ }
+
+ /**
+ * Returns a string containing a concise, human-readable description of the
+ * this {@code CodeSigner} including its first certificate and its time
+ * stamp, if present.
+ *
+ * @return a printable representation for this {@code CodeSigner}.
+ */
+ @Override
+ public String toString() {
+ // There is no any special reason for '256' here, it's taken abruptly
+ StringBuilder buf = new StringBuilder(256);
+ // The javadoc says nothing, and the others implementations behavior seems as
+ // dumping only the first certificate. Well, let's do the same.
+ buf.append("CodeSigner [").append(signerCertPath.getCertificates().get(0)); //$NON-NLS-1$
+ if( timestamp != null ) {
+ buf.append("; ").append(timestamp); //$NON-NLS-1$
+ }
+ buf.append("]"); //$NON-NLS-1$
+ return buf.toString();
+ }
+}
diff --git a/luni/src/main/java/java/security/CodeSource.java b/luni/src/main/java/java/security/CodeSource.java
new file mode 100644
index 0000000..96a4b8c5
--- /dev/null
+++ b/luni/src/main/java/java/security/CodeSource.java
@@ -0,0 +1,635 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.OptionalDataException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.net.SocketPermission;
+import java.net.URL;
+import java.security.cert.CertPath;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.harmony.security.fortress.PolicyUtils;
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * {@code CodeSource} encapsulates the location from where code is loaded and
+ * the certificates that were used to verify that code. This information is used
+ * by {@code SecureClassLoader} to define protection domains for loaded classes.
+ *
+ * @see SecureClassLoader
+ * @see ProtectionDomain
+ */
+public class CodeSource implements Serializable {
+
+ private static final long serialVersionUID = 4977541819976013951L;
+
+ // Location of this CodeSource object
+ private URL location;
+
+ // Array of certificates assigned to this CodeSource object
+ private transient java.security.cert.Certificate[] certs;
+
+ // Array of CodeSigners
+ private transient CodeSigner[] signers;
+
+ // SocketPermission() in implies() method takes to many time.
+ // Need to cache it for better performance.
+ private transient SocketPermission sp;
+
+ // Cached factory used to build CertPath-s in <code>getCodeSigners()</code>.
+ private transient CertificateFactory factory;
+
+ /**
+ * Constructs a new instance of {@code CodeSource} with the specified
+ * {@code URL} and the {@code Certificate}s.
+ *
+ * @param location
+ * the {@code URL} representing the location from where code is
+ * loaded, maybe {@code null}.
+ * @param certs
+ * the {@code Certificate} used to verify the code, loaded from
+ * the specified {@code location}, maybe {@code null}.
+ */
+ public CodeSource(URL location, Certificate[] certs) {
+ this.location = location;
+ if (certs != null) {
+ this.certs = new Certificate[certs.length];
+ System.arraycopy(certs, 0, this.certs, 0, certs.length);
+ }
+ }
+
+ /**
+ * Constructs a new instance of {@code CodeSource} with the specified
+ * {@code URL} and the {@code CodeSigner}s.
+ *
+ * @param location
+ * the {@code URL} representing the location from where code is
+ * loaded, maybe {@code null}.
+ * @param signers
+ * the {@code CodeSigner}s of the code, loaded from the specified
+ * {@code location}. Maybe {@code null}.
+ */
+ public CodeSource(URL location, CodeSigner[] signers) {
+ this.location = location;
+ if (signers != null) {
+ this.signers = new CodeSigner[signers.length];
+ System.arraycopy(signers, 0, this.signers, 0, signers.length);
+ }
+ }
+
+ /**
+ * Compares the specified object with this {@code CodeSource} for equality.
+ * Returns {@code true} if the specified object is also an instance of
+ * {@code CodeSource}, points to the same {@code URL} location and the two
+ * code sources encapsulate the same {@code Certificate}s. The order of the
+ * {@code Certificate}s is ignored by this method.
+ *
+ * @param obj
+ * object to be compared for equality with this {@code
+ * CodeSource}.
+ * @return {@code true} if the specified object is equal to this {@code
+ * CodeSource}, otherwise {@code false}.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+
+ if (!(obj instanceof CodeSource)) {
+ return false;
+ }
+
+ CodeSource that = (CodeSource) obj;
+
+ if (this.location != null) {
+ if (that.location == null) {
+ return false;
+ }
+ if (!this.location.equals(that.location)) {
+ return false;
+ }
+ } else if (that.location != null) {
+ return false;
+ }
+
+ // do not use this.certs, as we also need to take care about
+ // CodeSigners' certificates
+ Certificate[] thizCerts = getCertificatesNoClone();
+ Certificate[] thatCerts = that.getCertificatesNoClone();
+ if (!PolicyUtils.matchSubset(thizCerts, thatCerts)) {
+ return false;
+ }
+ if (!PolicyUtils.matchSubset(thatCerts, thizCerts)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns the certificates of this {@code CodeSource}. If the
+ * {@link #CodeSource(URL, CodeSigner[])} constructor was used to create
+ * this instance, the certificates are obtained from the supplied signers.
+ * <p>
+ * External modifications of the returned {@code Certificate[]} has no
+ * impact on this {@code CodeSource}.
+ *
+ * @return the certificates of this {@code CodeSource} or {@code null} if
+ * there is none.
+ */
+ public final Certificate[] getCertificates() {
+ getCertificatesNoClone();
+ if (certs == null) {
+ return null;
+ }
+ Certificate[] tmp = new Certificate[certs.length];
+ System.arraycopy(certs, 0, tmp, 0, certs.length);
+ return tmp;
+ }
+
+ // Acts exactly as {@link #getCertificates()} does, but does not clone the
+ // array before returning (and returns reference to <code>this.certs</code>
+ // if this array is not null).<br>
+ // @return a reference to the certificates array, or null if there are no
+ // certificates associated.
+ private Certificate[] getCertificatesNoClone() {
+ if (certs != null) {
+ return certs;
+ }
+
+ if (signers == null) {
+ return null;
+ }
+ // Extract Certificates from the CodeSigner-s
+ ArrayList<Certificate> v = new ArrayList<Certificate>();
+ for (int i = 0; i < signers.length; i++) {
+ v.addAll(signers[i].getSignerCertPath().getCertificates());
+ }
+
+ certs = v.toArray(new Certificate[v.size()]);
+ return certs;
+ }
+
+ /**
+ * Returns the {@code CodeSigner}s of this {@code CodeSource}. If the
+ * {@link #CodeSource(URL, Certificate[])} constructor was used to create
+ * this instance, the signers are obtained from the supplied certificates.
+ * Only X.509 certificates are analyzed.
+ *
+ * @return the signers of this {@code CodeSource}, or {@code null} if there
+ * is none.
+ */
+ public final CodeSigner[] getCodeSigners() {
+ if (signers != null) {
+ CodeSigner[] tmp = new CodeSigner[signers.length];
+ System.arraycopy(signers, 0, tmp, 0, tmp.length);
+ return tmp;
+ }
+ if(certs == null || factory != null){
+ // factory != null means we've done this exercise already.
+ return null;
+ }
+
+ X500Principal prevIssuer = null;
+ ArrayList<Certificate> list = new ArrayList<Certificate>(certs.length);
+ ArrayList<CodeSigner> asigners = new ArrayList<CodeSigner>();
+
+ // The presumption is that the chains of certificates are placed
+ // according to the CertPath agreement:
+ //
+ // the lowest certs first; the CAs are at the last
+ //
+ // So the following loop scans trough the certs and checks
+ // that every next certificate is an Issuer of the previous one.
+ // Any certificate that is not an Issuer of the previous one starts a
+ // new chain (== a new CertPath)
+
+ for (int i = 0; i < certs.length; i++) {
+ if (!(certs[i] instanceof X509Certificate)) {
+ // Only X509Certificate-s are taken into account - see API spec.
+ continue;
+ }
+ X509Certificate x509 = (X509Certificate) certs[i];
+ if (prevIssuer == null) {
+ // start a very first chain
+ prevIssuer = x509.getIssuerX500Principal();
+ list.add(x509);
+ } else {
+ X500Principal subj = x509.getSubjectX500Principal();
+ if (!prevIssuer.equals(subj)) {
+ // Ok, this ends the previous chain,
+ // so transform this one into CertPath ...
+ CertPath cpath = makeCertPath(list);
+ if (cpath != null) {
+ asigners.add(new CodeSigner(cpath, null));
+ }
+ // ... and start a new one
+ list.clear();
+ }// else { it's still the same chain }
+ prevIssuer = x509.getSubjectX500Principal();
+ list.add(x509);
+ }
+ }
+ if (!list.isEmpty()) {
+ CertPath cpath = makeCertPath(list);
+ if (cpath != null) {
+ asigners.add(new CodeSigner(cpath, null));
+ }
+ }
+ if (asigners.isEmpty()) {
+ // 'signers' is 'null' already
+ return null;
+ }
+ signers = new CodeSigner[asigners.size()];
+ asigners.toArray(signers);
+ CodeSigner[] tmp = new CodeSigner[asigners.size()];
+ System.arraycopy(signers, 0, tmp, 0, tmp.length);
+ return tmp;
+ }
+
+ // Makes an CertPath from a given List of X509Certificate-s.
+ // @param list
+ // @return CertPath, or null if CertPath cannot be made
+ private CertPath makeCertPath(List<? extends Certificate> list) {
+ if (factory == null) {
+ try {
+ factory = CertificateFactory.getInstance("X.509"); //$NON-NLS-1$
+ } catch (CertificateException ex) {
+ //? throw new Error("X.509 is a 'must be'", ex);
+ return null;
+ }
+ }
+ try {
+ return factory.generateCertPath(list);
+ } catch (CertificateException ex) {
+ // ignore(ex)
+ }
+ return null;
+ }
+
+ /**
+ * Returns the location of this {@code CodeSource}.
+ *
+ * @return the location of this {@code CodeSource}, maybe {@code null}.
+ */
+ public final URL getLocation() {
+ return location;
+ }
+
+ /**
+ * Returns the hash code value for this {@code CodeSource}.
+ * Returns the same hash code for {@code CodeSource}s that are
+ * equal to each other as required by the general contract of
+ * {@link Object#hashCode}.
+ *
+ * @return the hash code value for this {@code CodeSource}.
+ * @see Object#equals(Object)
+ * @see CodeSource#equals(Object)
+ */
+ @Override
+ public int hashCode() {
+ //
+ // hashCode() is undocumented there. Should we also use certs[i] to
+ // compute the hash ?
+ // for now, I don't take certs[] into account
+ return location == null ? 0 : location.hashCode();
+ }
+
+ /**
+ * Indicates whether the specified code source is implied by this {@code
+ * CodeSource}. Returns {@code true} if all of the following conditions are
+ * {@code true}, otherwise {@code false}:
+ * <p>
+ * <ul>
+ * <li>{@code cs} is not {@code null}
+ * <li>if this {@code CodeSource} has associated certificates, all
+ * certificates are present in {@code cs}. The certificates are extracted
+ * from the signers if signers are present.
+ * <li>if this {@code CodeSource}'s location is not {@code null}, the
+ * following conditions are checked
+ * <ul>
+ * <li>this {@code CodeSource}'s location is not {@code null}
+ * <li>this {@code CodeSource}'s location protocol is equal to {@code cs}'s
+ * location protocol
+ * <li>if this {@code CodeSource}'s location host is not {@code null}, the
+ * following conditions are checked
+ * <ul>
+ * <li>{@code cs}'s host is not {@code null}
+ * <li>the {@link SocketPermission} of this {@code CodeSource}'s location
+ * host implies the {@code SocketPermission} of {@code cs}'s location host
+ * </ul>
+ * <li>if this {@code CodeSource}'s location port != -1 the port of {@code
+ * cs}'s location is equal to this {@code CodeSource}'s location port
+ * <li>this {@code CodeSource}'s location file matches {@code cs}'s file
+ * whereas special wildcard matching applies as described below
+ * <li>this {@code CodeSource}'s location reference is equal to to {@code
+ * cs}'s location reference
+ * </ul>
+ * </ul>
+ * <p>
+ * Note: If this {@code CodeSource} has a {@code null} location and not any
+ * certificates, this method returns {@code true}.
+ * <p>
+ * Matching rules for the {@code CodeSource}'s location file:
+ * <ul>
+ * <li>if this {@code CodeSource}'s location file ends with {@code "/-"},
+ * then {@code cs}'s file must start with {@code CodeSource}'s location file
+ * (exclusive the trailing '-')
+ * <li>if this {@code CodeSource}'s location file ends with {@code "/*"},
+ * then {@code cs}'s file must start with {@code CodeSource}'s location file
+ * (exclusive the trailing '*') and must not have any further '/'
+ * <li>if this {@code CodeSource}'s location file ends with {@code "/"},
+ * then {@code cs}'s file must start with {@code CodeSource}'s location file
+ * <li>if this {@code CodeSource}'s location file does not end with {@code
+ * "/"}, then {@code cs}'s file must start with {@code CodeSource}'s
+ * location file with the '/' appended to it.
+ * </ul>
+ * Examples for locations that imply the location
+ * "http://harmony.apache.org/milestones/M9/apache-harmony.jar":
+ *
+ * <pre>
+ * http:
+ * http://&#42;/milestones/M9/*
+ * http://*.apache.org/milestones/M9/*
+ * http://harmony.apache.org/milestones/-
+ * http://harmony.apache.org/milestones/M9/apache-harmony.jar
+ * </pre>
+ *
+ * @param cs
+ * the code source to check.
+ * @return {@code true} if the argument code source is implied by this
+ * {@code CodeSource}, otherwise {@code false}.
+ */
+ public boolean implies(CodeSource cs) {
+ //
+ // Here, javadoc:N refers to the appropriate item in the API spec for
+ // the CodeSource.implies()
+ // The info was taken from the 1.5 final API spec
+
+ // javadoc:1
+ if (cs == null) {
+ return false;
+ }
+
+ // javadoc:2
+ // with a comment: the javadoc says only about certificates and does
+ // not explicitly mention CodeSigners' certs.
+ // It seems more convenient to use getCerts() to get the real
+ // certificates - with a certificates got form the signers
+ Certificate[] thizCerts = getCertificatesNoClone();
+ if (thizCerts != null) {
+ Certificate[] thatCerts = cs.getCertificatesNoClone();
+ if (thatCerts == null
+ || !PolicyUtils.matchSubset(thizCerts, thatCerts)) {
+ return false;
+ }
+ }
+
+ // javadoc:3
+ if (this.location != null) {
+ //javadoc:3.1
+ if (cs.location == null) {
+ return false;
+ }
+ //javadoc:3.2
+ if (this.location.equals(cs.location)) {
+ return true;
+ }
+ //javadoc:3.3
+ if (!this.location.getProtocol().equals(cs.location.getProtocol())) {
+ return false;
+ }
+ //javadoc:3.4
+ String thisHost = this.location.getHost();
+ if (thisHost != null) {
+ String thatHost = cs.location.getHost();
+ if (thatHost == null) {
+ return false;
+ }
+
+ // 1. According to the spec, an empty string will be considered
+ // as "localhost" in the SocketPermission
+ // 2. 'file://' URLs will have an empty getHost()
+ // so, let's make a special processing of localhost-s, I do
+ // believe this'll improve performance of file:// code sources
+
+ //
+ // Don't have to evaluate both the boolean-s each time.
+ // It's better to evaluate them directly under if() statement.
+ //
+ // boolean thisIsLocalHost = thisHost.length() == 0 || "localhost".equals(thisHost);
+ // boolean thatIsLocalHost = thatHost.length() == 0 || "localhost".equals(thatHost);
+ //
+ // if( !(thisIsLocalHost && thatIsLocalHost) &&
+ // !thisHost.equals(thatHost)) {
+
+ if (!((thisHost.length() == 0 || "localhost".equals(thisHost)) && (thatHost //$NON-NLS-1$
+ .length() == 0 || "localhost".equals(thatHost))) //$NON-NLS-1$
+ && !thisHost.equals(thatHost)) {
+
+ // Obvious, but very slow way....
+ //
+ // SocketPermission thisPerm = new SocketPermission(
+ // this.location.getHost(), "resolve");
+ // SocketPermission thatPerm = new SocketPermission(
+ // cs.location.getHost(), "resolve");
+ // if (!thisPerm.implies(thatPerm)) {
+ // return false;
+ // }
+ //
+ // let's cache it:
+
+ if (this.sp == null) {
+ this.sp = new SocketPermission(thisHost, "resolve"); //$NON-NLS-1$
+ }
+
+ if (cs.sp == null) {
+ cs.sp = new SocketPermission(thatHost, "resolve"); //$NON-NLS-1$
+ }
+
+ if (!this.sp.implies(cs.sp)) {
+ return false;
+ }
+ } // if( ! this.location.getHost().equals(cs.location.getHost())
+ } // if (this.location.getHost() != null)
+
+ //javadoc:3.5
+ if (this.location.getPort() != -1) {
+ if (this.location.getPort() != cs.location.getPort()) {
+ return false;
+ }
+ }
+
+ //javadoc:3.6
+ String thisFile = this.location.getFile();
+ String thatFile = cs.location.getFile();
+
+ if (thisFile.endsWith("/-")) { //javadoc:3.6."/-" //$NON-NLS-1$
+ if (!thatFile.startsWith(thisFile.substring(0, thisFile
+ .length() - 2))) {
+ return false;
+ }
+ } else if (thisFile.endsWith("/*")) { //javadoc:3.6."/*" //$NON-NLS-1$
+ if (!thatFile.startsWith(thisFile.substring(0, thisFile
+ .length() - 2))) {
+ return false;
+ }
+ // no further separators(s) allowed
+ if (thatFile.indexOf("/", thisFile.length() - 1) != -1) { //$NON-NLS-1$
+ return false;
+ }
+ } else {
+ // javadoc:3.6."/"
+ if (!thisFile.equals(thatFile)) {
+ if (!thisFile.endsWith("/")) { //$NON-NLS-1$
+ if (!thatFile.equals(thisFile + "/")) { //$NON-NLS-1$
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ }
+
+ //javadoc:3.7
+ if (this.location.getRef() != null) {
+ if (!this.location.getRef().equals(cs.location.getRef())) {
+ return false;
+ }
+ }
+ // ok, every check was made, and they all were successful.
+ // it's ok to return true.
+ } // if this.location != null
+
+ // javadoc: a note about CodeSource with null location and null Certs
+ // is applicable here
+ return true;
+ }
+
+ /**
+ * Returns a string containing a concise, human-readable description of the
+ * this {@code CodeSource} including its location, its certificates and its
+ * signers.
+ *
+ * @return a printable representation for this {@code CodeSource}.
+ */
+ @Override
+ public String toString() {
+ StringBuilder buf = new StringBuilder();
+ buf.append("CodeSource, url="); //$NON-NLS-1$
+ buf.append(location == null ? "<null>" : location.toString()); //$NON-NLS-1$
+
+ if (certs == null) {
+ buf.append(", <no certificates>"); //$NON-NLS-1$
+ } else {
+ buf.append("\nCertificates [\n"); //$NON-NLS-1$
+ for (int i = 0; i < certs.length; i++) {
+ buf.append(i + 1).append(") ").append(certs[i]).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ buf.append("]\n"); //$NON-NLS-1$
+ }
+ if (signers != null) {
+ buf.append("\nCodeSigners [\n"); //$NON-NLS-1$
+ for (int i = 0; i < signers.length; i++) {
+ buf.append(i + 1).append(") ").append(signers[i]).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ buf.append("]\n"); //$NON-NLS-1$
+ }
+ return buf.toString();
+ }
+
+ private void writeObject(ObjectOutputStream oos) throws IOException {
+
+ oos.defaultWriteObject();
+
+ if (certs == null || certs.length == 0) {
+ oos.writeInt(0);
+ } else {
+ oos.writeInt(certs.length);
+ for (int i = 0; i < certs.length; i++) {
+ try {
+ oos.writeUTF(certs[i].getType());
+ byte[] data = certs[i].getEncoded();
+ // hope there are no certificates with 'data==null'
+ oos.writeInt(data.length);
+ oos.write(data);
+ } catch (CertificateEncodingException ex) {
+ throw (IOException) new IOException(
+ Messages.getString("security.18")).initCause(ex); //$NON-NLS-1$
+ }
+ }
+ }
+ if (signers != null && signers.length != 0) {
+ oos.writeObject(signers);
+ }
+ }
+
+ private void readObject(ObjectInputStream ois) throws IOException,
+ ClassNotFoundException {
+
+ ois.defaultReadObject();
+
+ int certsCount = ois.readInt();
+ certs = null;
+ if (certsCount != 0) {
+ certs = new Certificate[certsCount];
+ for (int i = 0; i < certsCount; i++) {
+ String type = ois.readUTF();
+ CertificateFactory factory;
+ try {
+ factory = CertificateFactory.getInstance(type);
+ } catch (CertificateException ex) {
+ throw new ClassNotFoundException(
+ Messages.getString("security.19", type), //$NON-NLS-1$
+ ex);
+ }
+ int dataLen = ois.readInt();
+ byte[] data = new byte[dataLen];
+ ois.readFully(data);
+ ByteArrayInputStream bais = new ByteArrayInputStream(data);
+ try {
+ certs[i] = factory.generateCertificate(bais);
+ } catch (CertificateException ex) {
+ throw (IOException) new IOException(
+ Messages.getString("security.1A")).initCause(ex); //$NON-NLS-1$
+ }
+ }
+ }
+ try {
+ signers = (CodeSigner[]) ois.readObject();
+ } catch (OptionalDataException ex) {
+ if (!ex.eof) {
+ throw ex;
+ }
+ // no signers (ex.eof==true <= no data left) is allowed
+ }
+ }
+}
diff --git a/luni/src/main/java/java/security/DigestException.java b/luni/src/main/java/java/security/DigestException.java
new file mode 100644
index 0000000..0d0a1ee
--- /dev/null
+++ b/luni/src/main/java/java/security/DigestException.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ *{@code DigestException} is a general message digest exception.
+ */
+public class DigestException extends GeneralSecurityException {
+
+ private static final long serialVersionUID = 5821450303093652515L;
+
+ /**
+ * Constructs a new instance of {@code DigestException} with the
+ * given message.
+ *
+ * @param msg
+ * the detail message for this exception.
+ */
+ public DigestException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs a new instance of {@code DigestException}.
+ */
+ public DigestException() {
+ }
+
+ /**
+ * Constructs a new instance of {@code DigestException} with the
+ * given message and the cause.
+ *
+ * @param message
+ * the detail message for this exception.
+ * @param cause
+ * the exception which is the cause for this exception.
+ */
+ public DigestException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructs a new instance of {@code DigestException} with the
+ * cause.
+ *
+ * @param cause
+ * the exception which is the cause for this exception.
+ */
+ public DigestException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/luni/src/main/java/java/security/DigestInputStream.java b/luni/src/main/java/java/security/DigestInputStream.java
new file mode 100644
index 0000000..26433fa
--- /dev/null
+++ b/luni/src/main/java/java/security/DigestInputStream.java
@@ -0,0 +1,151 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * {@code DigestInputStream} is a {@code FilterInputStream} which maintains an
+ * associated message digest.
+ */
+public class DigestInputStream extends FilterInputStream {
+
+ /**
+ * The message digest for this stream.
+ */
+ protected MessageDigest digest;
+
+ // Indicates whether digest functionality is on or off
+ private boolean isOn = true;
+
+ /**
+ * Constructs a new instance of this {@code DigestInputStream}, using the
+ * given {@code stream} and the {@code digest}.
+ *
+ * @param stream
+ * the input stream.
+ * @param digest
+ * the message digest.
+ */
+ public DigestInputStream(InputStream stream, MessageDigest digest) {
+ super(stream);
+ this.digest = digest;
+ }
+
+ /**
+ * Returns the message digest for this stream.
+ *
+ * @return the message digest for this stream.
+ */
+ public MessageDigest getMessageDigest() {
+ return digest;
+ }
+
+ /**
+ * Sets the message digest which this stream will use.
+ *
+ * @param digest
+ * the message digest which this stream will use.
+ */
+ public void setMessageDigest(MessageDigest digest) {
+ this.digest = digest;
+ }
+
+ /**
+ * Reads the next byte and returns it as an {@code int}. Updates the digest
+ * for the byte if this function is {@link #on(boolean)}.
+ * <p>
+ * This operation is blocking.
+ *
+ * @return the byte which was read or -1 at end of stream.
+ * @throws IOException
+ * if reading the source stream causes an {@code IOException}.
+ */
+ @Override
+ public int read() throws IOException {
+ // read the next byte
+ int byteRead = in.read();
+ // update digest only if
+ // - digest functionality is on
+ // - eos has not been reached
+ if (isOn && (byteRead != -1)) {
+ digest.update((byte)byteRead);
+ }
+ // return byte read
+ return byteRead;
+ }
+
+ /**
+ * Reads {@code len} bytes into the specified {@code byte[]}, starting from
+ * the specified offset. Updates the digest if this function is
+ * {@link #on(boolean)}.
+ * <p>
+ * This operation is blocking.
+ *
+ * @param b
+ * the byte array in which to store the bytes
+ * @param off
+ * the initial position in {@code b} to store the bytes read from
+ * this stream
+ * @param len
+ * the maximum number of bytes to store in {@code b}
+ * @return the number of bytes actually read or -1 if the end of the
+ * filtered stream has been reached while reading
+ * @throws IOException
+ * if reading the source stream causes an {@code IOException}
+ */
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ // read next up to len bytes
+ int bytesRead = in.read(b, off, len);
+ // update digest only if
+ // - digest functionality is on
+ // - eos has not been reached
+ if (isOn && (bytesRead != -1)) {
+ digest.update(b, off, bytesRead);
+ }
+ // return number of bytes read
+ return bytesRead;
+ }
+
+ /**
+ * Enables or disables the digest function (default is on).
+ *
+ * @param on
+ * {@code true} if the digest should be computed, {@code false}
+ * otherwise.
+ * @see MessageDigest
+ */
+ public void on(boolean on) {
+ isOn = on;
+ }
+
+ /**
+ * Returns a string containing a concise, human-readable description of this
+ * {@code DigestInputStream} including the digest.
+ *
+ * @return a printable representation for this {@code DigestInputStream}.
+ */
+ @Override
+ public String toString() {
+ return super.toString() + ", " + digest.toString() + //$NON-NLS-1$
+ (isOn ? ", is on" : ", is off"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+}
diff --git a/luni/src/main/java/java/security/DigestOutputStream.java b/luni/src/main/java/java/security/DigestOutputStream.java
new file mode 100644
index 0000000..f4cd659
--- /dev/null
+++ b/luni/src/main/java/java/security/DigestOutputStream.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * {@code DigestOutputStream} is a {@code FilterOutputStream} which maintains an
+ * associated message digest.
+ */
+public class DigestOutputStream extends FilterOutputStream {
+
+ /**
+ * The message digest for this stream.
+ */
+ protected MessageDigest digest;
+
+ // Indicates whether digest functionality is on or off
+ private boolean isOn = true;
+
+ /**
+ * Constructs a new instance of this {@code DigestOutputStream}, using the
+ * given {@code stream} and the {@code digest}.
+ *
+ * @param stream
+ * the output stream.
+ * @param digest
+ * the message digest.
+ */
+ public DigestOutputStream(OutputStream stream, MessageDigest digest) {
+ super(stream);
+ this.digest = digest;
+ }
+
+ /**
+ * Returns the message digest for this stream.
+ *
+ * @return the message digest for this stream.
+ */
+ public MessageDigest getMessageDigest() {
+ return digest;
+ }
+
+ /**
+ * Sets the message digest which this stream will use.
+ *
+ * @param digest
+ * the message digest which this stream will use.
+ */
+ public void setMessageDigest(MessageDigest digest) {
+ this.digest = digest;
+ }
+
+ /**
+ * Writes the specified {@code int} to the stream. Updates the digest if
+ * this function is {@link #on(boolean)}.
+ *
+ * @param b
+ * the byte to be written.
+ * @throws IOException
+ * if writing to the stream causes a {@code IOException}
+ */
+ @Override
+ public void write(int b) throws IOException {
+ // update digest only if digest functionality is on
+ if (isOn) {
+ digest.update((byte)b);
+ }
+ // write the byte
+ out.write(b);
+ }
+
+ /**
+ * Writes {@code len} bytes into the stream, starting from the specified
+ * offset. Updates the digest if this function is {@link #on(boolean)}.
+ *
+ * @param b
+ * the buffer to write to.
+ * @param off
+ * the index of the first byte in {@code b} to write.
+ * @param len
+ * the number of bytes in {@code b} to write.
+ * @throws IOException
+ * if writing to the stream causes an {@code IOException}.
+ */
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ // update digest only if digest functionality is on
+ if (isOn) {
+ digest.update(b, off, len);
+ }
+ // write len bytes
+ out.write(b, off, len);
+ }
+
+ /**
+ * Enables or disables the digest function (default is on).
+ *
+ * @param on
+ * {@code true} if the digest should be computed, {@code false}
+ * otherwise.
+ * @see MessageDigest
+ */
+ public void on(boolean on) {
+ isOn = on;
+ }
+
+ /**
+ * Returns a string containing a concise, human-readable description of this
+ * {@code DigestOutputStream} including the digest.
+ *
+ * @return a printable representation for this {@code DigestOutputStream}.
+ */
+ @Override
+ public String toString() {
+ return super.toString() + ", " + digest.toString() + //$NON-NLS-1$
+ (isOn ? ", is on" : ", is off"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+}
diff --git a/luni/src/main/java/java/security/DomainCombiner.java b/luni/src/main/java/java/security/DomainCombiner.java
new file mode 100644
index 0000000..36433b3
--- /dev/null
+++ b/luni/src/main/java/java/security/DomainCombiner.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * {@code DomainCombiner} is used to update and optimize {@code
+ * ProtectionDomain}s from an {@code AccessControlContext}.
+ *
+ * @see AccessControlContext
+ * @see AccessControlContext#AccessControlContext(AccessControlContext,
+ * DomainCombiner)
+ */
+public interface DomainCombiner {
+
+ /**
+ * Returns a combination of the two provided {@code ProtectionDomain}
+ * arrays. Implementers can simply merge the two arrays into one, remove
+ * duplicates and perform other optimizations.
+ *
+ * @param current
+ * the protection domains of the current execution thread (since
+ * the most recent call to {@link AccessController#doPrivileged}
+ * ).
+ * @param assigned
+ * the protection domains of the parent thread, maybe {@code
+ * null}.
+ * @return a single {@code ProtectionDomain} array computed from the two
+ * provided arrays.
+ */
+ ProtectionDomain[] combine(ProtectionDomain[] current,
+ ProtectionDomain[] assigned);
+}
diff --git a/luni/src/main/java/java/security/GeneralSecurityException.java b/luni/src/main/java/java/security/GeneralSecurityException.java
new file mode 100644
index 0000000..78fca29
--- /dev/null
+++ b/luni/src/main/java/java/security/GeneralSecurityException.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * {@code GeneralSecurityException} is a general security exception and the
+ * superclass for all security specific exceptions.
+ */
+public class GeneralSecurityException extends Exception {
+
+ private static final long serialVersionUID = 894798122053539237L;
+
+ /**
+ * Constructs a new instance of {@code GeneralSecurityException} with the
+ * given message.
+ *
+ * @param msg
+ * the detail message for this exception.
+ */
+ public GeneralSecurityException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs a new instance of {@code GeneralSecurityException}.
+ */
+ public GeneralSecurityException() {
+ }
+
+ /**
+ * Constructs a new instance of {@code GeneralSecurityException} with the
+ * given message and the cause.
+ *
+ * @param message
+ * the detail message for this exception.
+ * @param cause
+ * the exception which is the cause for this exception.
+ */
+ public GeneralSecurityException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructs a new instance of {@code GeneralSecurityException} with the
+ * cause.
+ *
+ * @param cause
+ * the exception which is the cause for this exception.
+ */
+ public GeneralSecurityException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/luni/src/main/java/java/security/Guard.java b/luni/src/main/java/java/security/Guard.java
new file mode 100644
index 0000000..b652054
--- /dev/null
+++ b/luni/src/main/java/java/security/Guard.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * {@code Guard} implementors protect access to other objects.
+ */
+public interface Guard {
+
+ /**
+ * Checks whether access to the specified {@code Object} should be granted.
+ * This method returns silently if access is granted, otherwise a {@code
+ * SecurityException} is thrown.
+ *
+ * @param object
+ * the object to be protected by this {@code Guard}.
+ * @throws SecurityException
+ * if access is not granted.
+ */
+ public void checkGuard(Object object) throws SecurityException;
+}
diff --git a/luni/src/main/java/java/security/GuardedObject.java b/luni/src/main/java/java/security/GuardedObject.java
new file mode 100644
index 0000000..34a5113
--- /dev/null
+++ b/luni/src/main/java/java/security/GuardedObject.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.io.IOException;
+import java.io.Serializable;
+
+/**
+ * {@code GuardedObject} controls access to an object, by checking all requests
+ * for the object with a {@code Guard}.
+ */
+public class GuardedObject implements Serializable {
+
+ private static final long serialVersionUID = -5240450096227834308L;
+
+ private final Object object;
+
+ private final Guard guard;
+
+ /**
+ * Constructs a new instance of {@code GuardedObject} which protects access
+ * to the specified {@code Object} using the specified {@code Guard}.
+ *
+ * @param object
+ * the {@code Object} to protect.
+ * @param guard
+ * the {@code Guard} which protects the specified {@code Object},
+ * maybe {@code null}.
+ */
+ public GuardedObject(Object object, Guard guard) {
+ this.object = object;
+ this.guard = guard;
+ }
+
+ /**
+ * Returns the guarded {@code Object} if the associated {@code Guard}
+ * permits access. If access is not granted, then a {@code
+ * SecurityException} is thrown.
+ *
+ * @return the guarded object.
+ * @exception SecurityException
+ * if access is not granted to the guarded object.
+ */
+ public Object getObject() throws SecurityException {
+ if (guard != null) {
+ guard.checkGuard(object);
+ }
+ return object;
+ }
+
+ /**
+ * Checks the guard (if there is one) before performing a default
+ * serialization.
+ */
+ private void writeObject(java.io.ObjectOutputStream out) throws IOException {
+ if (guard != null) {
+ guard.checkGuard(object);
+ }
+ out.defaultWriteObject();
+ }
+}
diff --git a/luni/src/main/java/java/security/Identity.java b/luni/src/main/java/java/security/Identity.java
new file mode 100644
index 0000000..d55cd3a
--- /dev/null
+++ b/luni/src/main/java/java/security/Identity.java
@@ -0,0 +1,433 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.io.Serializable;
+import java.util.Vector;
+import java.util.Arrays;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * {@code Identity} represents an identity like a person or a company.
+ *
+ * @deprecated The functionality of this class has been replace by
+ * {@link Principal}, {@link KeyStore} and the {@code
+ * java.security.cert} package.
+ */
+@Deprecated
+public abstract class Identity implements Principal, Serializable {
+ private static final long serialVersionUID = 3609922007826600659L;
+
+ private String name;
+
+ private PublicKey publicKey;
+
+ private String info = "no additional info"; //$NON-NLS-1$
+
+ private IdentityScope scope;
+
+ private Vector<Certificate> certificates;
+
+ /**
+ * Constructs a new instance of {@code Identity}.
+ */
+ protected Identity() {
+ }
+
+ /**
+ * Creates a new instance of {@code Identity} with the specified name.
+ *
+ * @param name
+ * the name of this {@code Identity}.
+ */
+ public Identity(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Creates a new instance of {@code Identity} with the specified name and
+ * the scope of this {@code Identity}.
+ *
+ * @param name
+ * the name of this {@code Identity}.
+ * @param scope
+ * the {@code IdentityScope} of this {@code Identity}.
+ * @throws KeyManagementException
+ * if an {@code Identity} with the same name is already present
+ * in the specified scope.
+ */
+ public Identity(String name, IdentityScope scope)
+ throws KeyManagementException {
+ this(name);
+ if (scope != null) {
+ scope.addIdentity(this);
+ this.scope = scope;
+ }
+ }
+
+ /**
+ * Adds a {@code Certificate} to this {@code Identity}.
+ * <p>
+ * If a {@code SecurityManager} is installed, code calling this method needs
+ * the {@code SecurityPermission} {@code addIdentityCertificate} to be
+ * granted, otherwise a {@code SecurityException} will be thrown.
+ *
+ * @param certificate
+ * the {@code Certificate} to be added to this {@code Identity}.
+ * @throws KeyManagementException
+ * if the certificate is not valid.
+ * @throws SecurityException
+ * if a {@code SecurityManager} is installed and the caller does
+ * not have permission to invoke this method.
+ */
+ public void addCertificate(Certificate certificate)
+ throws KeyManagementException {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkSecurityAccess("addIdentityCertificate"); //$NON-NLS-1$
+ }
+ PublicKey certPK = certificate.getPublicKey();
+ if (publicKey != null) {
+ if (!checkKeysEqual(publicKey, certPK)) {
+ throw new KeyManagementException(Messages.getString("security.13")); //$NON-NLS-1$
+ }
+ } else {
+ publicKey = certPK;
+ }
+ if (certificates == null) {
+ certificates = new Vector<Certificate>();
+ }
+ certificates.add(certificate);
+ }
+
+
+
+
+ private static boolean checkKeysEqual(PublicKey pk1, PublicKey pk2) {
+ // first, they should have the same format
+ // second, their encoded form must be the same
+
+ // assert(pk1 != null);
+ // assert(pk2 != null);
+
+ String format1 = pk1.getFormat();
+ String format2;
+ if ((pk2 == null)
+ || (((format2 = pk2.getFormat()) != null) ^ (format1 != null))
+ || ((format1 != null) && !format1.equals(format2))) {
+ return false;
+ }
+
+ return Arrays.equals(pk1.getEncoded(), pk2.getEncoded());
+ }
+
+
+
+
+ /**
+ * Removes the specified {@code Certificate} from this {@code Identity}.
+ * <p>
+ * If a {@code SecurityManager} is installed, code calling this method needs
+ * the {@code SecurityPermission} {@code "removeIdentityCertificate"} to be
+ * granted, otherwise a {@code SecurityException} will be thrown.
+ * <p>
+ *
+ * @param certificate
+ * the {@code Certificate} to be removed.
+ * @throws KeyManagementException
+ * if the certificate is not found.
+ * @throws SecurityException
+ * if a {@code SecurityManager} is installed and the caller does
+ * not have permission to invoke this method.
+ */
+ public void removeCertificate(Certificate certificate)
+ throws KeyManagementException {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkSecurityAccess("removeIdentityCertificate"); //$NON-NLS-1$
+ }
+ if (certificates != null) {
+ // BEGIN android-added
+ if (!certificates.contains(certificate)) {
+ throw new KeyManagementException("Certificate not found");
+ }
+ // END android-added
+ certificates.removeElement(certificate);
+ }
+ }
+
+
+
+
+ /**
+ * Returns the certificates for this {@code Identity}. External
+ * modifications of the returned array has no impact on this {@code
+ * Identity}.
+ *
+ * @return the {@code Certificates} for this {@code Identity}
+ */
+ public Certificate[] certificates() {
+ if (certificates == null) {
+ return new Certificate[0];
+ }
+ Certificate[] ret = new Certificate[certificates.size()];
+ certificates.copyInto(ret);
+ return ret;
+ }
+
+
+
+
+ /**
+ * Compares the specified {@code Identity} with this {@code Identity} for
+ * equality and returns {@code true} if the specified object is equal,
+ * {@code false} otherwise.
+ * <p>
+ * To be equal, two {@code Identity} objects need to have the same name and
+ * the same public keys.
+ *
+ * @param identity
+ * the identity to check for equality.
+ * @return {@code true} if the {@code Identity} objects are equal, {@code
+ * false} otherwise.
+ */
+ protected boolean identityEquals(Identity identity) {
+ if (!name.equals(identity.name)) {
+ return false;
+ }
+
+ if (publicKey == null) {
+ return (identity.publicKey == null);
+ }
+
+ return checkKeysEqual(publicKey, identity.publicKey);
+ }
+
+
+
+
+ /**
+ * Returns a string containing a concise, human-readable description of the
+ * this {@code Identity}.
+ *
+ * @param detailed
+ * whether or not this method should return detailed information.
+ * @return a printable representation for this {@code Permission}.
+ */
+ public String toString(boolean detailed) {
+ String s = toString();
+ if (detailed) {
+ s += " " + info; //$NON-NLS-1$
+ }
+ return s;
+ }
+
+
+
+
+ /**
+ * Returns the {@code IdentityScope} of this {@code Identity}.
+ *
+ * @return the {@code IdentityScope} of this {@code Identity}.
+ */
+ public final IdentityScope getScope() {
+ return scope;
+ }
+
+
+
+
+ /**
+ * Sets the specified {@code PublicKey} to this {@code Identity}.
+ * <p>
+ * If a {@code SecurityManager} is installed, code calling this method needs
+ * the {@code SecurityPermission} {@code setIdentityPublicKey} to be
+ * granted, otherwise a {@code SecurityException} will be thrown.
+ *
+ * @param key
+ * the {@code PublicKey} to be set.
+ * @throws KeyManagementException
+ * if another {@code Identity} in the same scope as this {@code
+ * Identity} already has the same {@code PublicKey}.
+ * @throws SecurityException
+ * if a {@code SecurityManager} is installed and the caller does
+ * not have permission to invoke this method.
+ */
+ public void setPublicKey(PublicKey key) throws KeyManagementException {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkSecurityAccess("setIdentityPublicKey"); //$NON-NLS-1$
+ }
+ // this check does not always work
+ if ((scope != null) && (key != null)) {
+ Identity i = scope.getIdentity(key);
+ //System.out.println("###DEBUG## Identity: "+i);
+ if ((i != null) && (i != this)) {
+ throw new KeyManagementException(Messages.getString("security.14")); //$NON-NLS-1$
+ }
+ }
+ this.publicKey = key;
+ certificates = null;
+ }
+
+
+
+
+ /**
+ * Returns the {@code PublicKey} associated with this {@code Identity}.
+ *
+ * @return the {@code PublicKey} associated with this {@code Identity}.
+ */
+ public PublicKey getPublicKey() {
+ return publicKey;
+ }
+
+
+
+
+ /**
+ * Sets an information string for this {@code Identity}.
+ * <p>
+ * If a {@code SecurityManager} is installed, code calling this method needs
+ * the {@code SecurityPermission} {@code setIdentityInfo} to be granted,
+ * otherwise a {@code SecurityException} will be thrown.
+ *
+ * @param info
+ * the information to be set.
+ * @throws SecurityException
+ * if a {@code SecurityManager} is installed and the caller does
+ * not have permission to invoke this method.
+ */
+ public void setInfo(String info) {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkSecurityAccess("setIdentityInfo"); //$NON-NLS-1$
+ }
+ this.info = info;
+ }
+
+
+
+
+ /**
+ * Returns the information string of this {@code Identity}.
+ *
+ * @return the information string of this {@code Identity}.
+ */
+ public String getInfo() {
+ return info;
+ }
+
+
+
+
+ /**
+ * Compares the specified object with this {@code Identity} for equality and
+ * returns {@code true} if the specified object is equal, {@code false}
+ * otherwise. {@code Identity} objects are considered equal, if they have
+ * the same name and are in the same scope.
+ *
+ * @param obj
+ * object to be compared for equality with this {@code
+ * Identity}.
+ * @return {@code true} if the specified object is equal to this {@code
+ * Identity}, otherwise {@code false}.
+ */
+ @Override
+ public final boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof Identity)) {
+ return false;
+ }
+ Identity i = (Identity) obj;
+ if ((name == i.name || (name != null && name.equals(i.name)))
+ && (scope == i.scope || (scope != null && scope.equals(i.scope)))) {
+ return true;
+ }
+ return identityEquals(i);
+ }
+
+
+
+
+ /**
+ * Returns the name of this {@code Identity}.
+ *
+ * @return the name of this {@code Identity}.
+ */
+ public final String getName() {
+ return name;
+ }
+
+
+
+
+ /**
+ * Returns the hash code value for this {@code Identity}. Returns the same
+ * hash code for {@code Identity}s that are equal to each other as required
+ * by the general contract of {@link Object#hashCode}.
+ *
+ * @return the hash code value for this {@code Identity}.
+ * @see Object#equals(Object)
+ * @see Identity#equals(Object)
+ */
+ @Override
+ public int hashCode() {
+ int hash = 0;
+ if (name != null) {
+ hash += name.hashCode();
+ }
+ if (scope != null) {
+ hash += scope.hashCode();
+ }
+ return hash;
+ }
+
+
+
+
+ /**
+ * Returns a string containing a concise, human-readable description of the
+ * this {@code Identity} including its name and its scope.
+ * <p>
+ * If a {@code SecurityManager} is installed, code calling this method
+ * needs the {@code SecurityPermission} {@code printIdentity} to be granted,
+ * otherwise a {@code SecurityException} will be thrown.
+ *
+ * @return a printable representation for this {@code Identity}.
+ * @throws SecurityException
+ * if a {@code SecurityManager} is installed and the caller does
+ * not have permission to invoke this method.
+ */
+ @Override
+ @SuppressWarnings("nls")
+ public String toString() {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkSecurityAccess("printIdentity");
+ }
+ String s = (this.name == null ? "" : this.name);
+ if (scope != null) {
+ s += " [" + scope.getName() + "]";
+ }
+ return s;
+ }
+}
diff --git a/luni/src/main/java/java/security/IdentityScope.java b/luni/src/main/java/java/security/IdentityScope.java
new file mode 100644
index 0000000..60ab3e8
--- /dev/null
+++ b/luni/src/main/java/java/security/IdentityScope.java
@@ -0,0 +1,202 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.util.Enumeration;
+
+
+/**
+ * {@code IdentityScope} represents a scope for {@link Identity} objects.
+ *
+ * @deprecated The functionality of this class has been replace by
+ * {@link Principal}, {@link KeyStore} and the {@code
+ * java.security.cert} package.
+ */
+@Deprecated
+public abstract class IdentityScope extends Identity {
+
+ private static final long serialVersionUID = -2337346281189773310L;
+
+ // systemScope holds reference to the current system scope
+ private static IdentityScope systemScope;
+
+ /**
+ * Constructs a new instance of {@code IdentityScope}.
+ */
+ protected IdentityScope() {
+ super();
+ }
+
+ /**
+ * Constructs a new instance of {@code IdentityScope} with the specified
+ * name.
+ *
+ * @param name
+ * the name of this {@code IdentityScope}.
+ */
+ public IdentityScope(String name) {
+ super(name);
+ }
+
+ /**
+ * Constructs a new instance of {@code IdentityScope} with the specified
+ * name and the specified scope.
+ *
+ * @param name
+ * the name of this {@code IdentityScope}.
+ * @param scope
+ * the scope of this {@code IdentityScope}.
+ * @throws KeyManagementException
+ * if an identity with the same key already exists.
+ */
+ public IdentityScope(String name, IdentityScope scope)
+ throws KeyManagementException {
+ super(name, scope);
+ }
+
+ /**
+ * Returns the system's scope.
+ *
+ * @return the system's scope.
+ */
+ public static IdentityScope getSystemScope() {
+ /*
+ * Test shows that the implementation class name is read from security property
+ * "system.scope", and the class is only loaded from boot classpath. No default
+ * implementation as fallback, i.e., return null if fails to init an instance.
+ */
+ if (systemScope == null) {
+ String className = AccessController.doPrivileged(new PrivilegedAction<String>(){
+ public String run() {
+ return Security.getProperty("system.scope"); //$NON-NLS-1$
+ }
+ });
+ if(className != null){
+ try {
+ systemScope = (IdentityScope) Class.forName(className).newInstance();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ return systemScope;
+ }
+
+ /**
+ * Sets the system's scope.
+ *
+ * @param scope
+ * the scope to set.
+ */
+ protected static void setSystemScope(IdentityScope scope) {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkSecurityAccess("setSystemScope"); //$NON-NLS-1$
+ }
+ systemScope = scope;
+ }
+
+ /**
+ * Returns the number of {@code Identity} objects in this scope.
+ *
+ * @return the number of {@code Identity} objects in this scope.
+ */
+ public abstract int size();
+
+ /**
+ * Returns the {@code Identity} with the specified name or {@code null} if
+ * no {@code Identity} with the specified name is present in this scope.
+ *
+ * @param name
+ * the name of the {@code Identity} to be returned.
+ * @return the {@code Identity} with the specified name or {@code null} if
+ * not present.
+ */
+ public abstract Identity getIdentity(String name);
+
+ /**
+ * Returns the {@code Identity} with the name of the specified principal or
+ * {@code null} if no {@code Identity} with the name of the specified
+ * principal is present in this scope.
+ *
+ * @param principal
+ * the {@code Principal} whose name is used to lookup the {@code
+ * Identity} to be returned.
+ * @return the {@code Identity} with the specified name or {@code null} if
+ * not present.
+ */
+ public Identity getIdentity(Principal principal) {
+ return getIdentity(principal.getName());
+ }
+
+ /**
+ * Returns the {@code Identity} which is associated with the specified key
+ * or {@code null} if no {@code Identity} associated with the specified key
+ * is present in this scope.
+ *
+ * @param key
+ * the {@code PublicKey} of the {@code Identity} to be returned.
+ * @return the {@code Identity} associated with the specified key or {@code
+ * null} if not present.
+ */
+ public abstract Identity getIdentity(PublicKey key);
+
+ /**
+ * Adds an {@code Identity} to this {@code IdentityScope}.
+ *
+ * @param identity
+ * the {@code Identity} to be added.
+ * @throws KeyManagementException
+ * if the specified {@code Identity} is invalid or an identity
+ * with the same key already exists.
+ */
+ public abstract void addIdentity(Identity identity)
+ throws KeyManagementException;
+
+ /**
+ * Removes an {@code Identity} from this {@code IdentityScope}.
+ *
+ * @param identity
+ * the {@code Identity} to be removed.
+ * @throws KeyManagementException
+ * if the {@code Identity} is not present in this scope.
+ */
+ public abstract void removeIdentity(Identity identity)
+ throws KeyManagementException;
+
+ /**
+ * Returns an {@code Enumeration} over the {@code Identity} objects in this
+ * {@code IdentityScope}.
+ *
+ * @return an {@code Enumeration} over the {@code Identity} objects in this
+ * {@code IdentityScope}.
+ */
+ public abstract Enumeration<Identity> identities();
+
+ /**
+ * Returns a string containing a concise, human-readable description of this
+ * {@code IdentityScope}.
+ *
+ * @return a printable representation for this {@code IdentityScope}.
+ */
+ @Override
+ public String toString() {
+ return new StringBuilder(super.toString())
+ .append("[").append(size()).append("]").toString(); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+}
diff --git a/luni/src/main/java/java/security/InvalidAlgorithmParameterException.java b/luni/src/main/java/java/security/InvalidAlgorithmParameterException.java
new file mode 100644
index 0000000..26d9f97
--- /dev/null
+++ b/luni/src/main/java/java/security/InvalidAlgorithmParameterException.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * {@code InvalidAlgorithmParameterException} indicates the occurrence of
+ * invalid algorithm parameters.
+ */
+public class InvalidAlgorithmParameterException extends
+ GeneralSecurityException {
+ private static final long serialVersionUID = 2864672297499471472L;
+
+ /**
+ * Constructs a new instance of {@code InvalidAlgorithmParameterException}
+ * with the given message.
+ *
+ * @param msg
+ * the detail message for this exception.
+ */
+ public InvalidAlgorithmParameterException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs a new instance of {@code InvalidAlgorithmParameterException}.
+ */
+ public InvalidAlgorithmParameterException() {
+ }
+
+ /**
+ * Constructs a new instance of {@code InvalidAlgorithmParameterException} with the
+ * given message and the cause.
+ *
+ * @param message
+ * the detail message for this exception.
+ * @param cause
+ * the exception which is the cause for this exception.
+ */
+ public InvalidAlgorithmParameterException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructs a new instance of {@code InvalidAlgorithmParameterException}
+ * with the cause.
+ *
+ * @param cause
+ * the exception which is the cause for this exception.
+ */
+ public InvalidAlgorithmParameterException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/luni/src/main/java/java/security/InvalidKeyException.java b/luni/src/main/java/java/security/InvalidKeyException.java
new file mode 100644
index 0000000..f08fc51
--- /dev/null
+++ b/luni/src/main/java/java/security/InvalidKeyException.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * {@code InvalidKeyException} indicates exceptional conditions, caused by an
+ * invalid key.
+ */
+public class InvalidKeyException extends KeyException {
+
+ private static final long serialVersionUID = 5698479920593359816L;
+
+ /**
+ * Constructs a new instance of {@code InvalidKeyException} with the given
+ * message.
+ *
+ * @param msg
+ * the detail message for this exception.
+ */
+ public InvalidKeyException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs a new instance of {@code InvalidKeyException}.
+ */
+ public InvalidKeyException() {
+ }
+
+ /**
+ * Constructs a new instance of {@code InvalidKeyException} with the given
+ * message and the cause.
+ *
+ * @param message
+ * the detail message for this exception.
+ * @param cause
+ * the exception which is the cause for this exception.
+ */
+ public InvalidKeyException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructs a new instance of {@code InvalidKeyException} with the cause.
+ *
+ * @param cause
+ * the exception which is the cause for this exception.
+ */
+ public InvalidKeyException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/luni/src/main/java/java/security/InvalidParameterException.java b/luni/src/main/java/java/security/InvalidParameterException.java
new file mode 100644
index 0000000..6ad4645
--- /dev/null
+++ b/luni/src/main/java/java/security/InvalidParameterException.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * {@code InvalidParameterException} indicates exceptional conditions, caused by
+ * invalid parameters.
+ */
+public class InvalidParameterException extends IllegalArgumentException {
+
+ private static final long serialVersionUID = -857968536935667808L;
+
+ /**
+ * Constructs a new instance of {@code InvalidParameterException} with the
+ * given message.
+ *
+ * @param msg
+ * the detail message for this exception.
+ */
+ public InvalidParameterException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs a new instance of {@code InvalidParameterException}.
+ */
+ public InvalidParameterException() {
+ }
+}
diff --git a/luni/src/main/java/java/security/Key.java b/luni/src/main/java/java/security/Key.java
new file mode 100644
index 0000000..28d24ff
--- /dev/null
+++ b/luni/src/main/java/java/security/Key.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.io.Serializable;
+
+/**
+ * {@code Key} is the common interface for all keys.
+ *
+ * @see PublicKey
+ * @see PrivateKey
+ */
+public interface Key extends Serializable {
+
+ /**
+ * The {@code serialVersionUID} to be compatible with JDK1.1.
+ */
+ public static final long serialVersionUID = 6603384152749567654L;
+
+ /**
+ * Returns the name of the algorithm of this key. If the algorithm is
+ * unknown, {@code null} is returned.
+ *
+ * @return the name of the algorithm of this key or {@code null} if the
+ * algorithm is unknown.
+ */
+ public String getAlgorithm();
+
+ /**
+ * Returns the name of the format used to encode this key, or {@code null}
+ * if it can not be encoded.
+ *
+ * @return the name of the format used to encode this key, or {@code null}
+ * if it can not be encoded.
+ */
+ public String getFormat();
+
+ /**
+ * Returns the encoded form of this key, or {@code null} if encoding is not
+ * supported by this key.
+ *
+ * @return the encoded form of this key, or {@code null} if encoding is not
+ * supported by this key.
+ */
+ public byte[] getEncoded();
+}
diff --git a/luni/src/main/java/java/security/KeyException.java b/luni/src/main/java/java/security/KeyException.java
new file mode 100644
index 0000000..721c896
--- /dev/null
+++ b/luni/src/main/java/java/security/KeyException.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * {@code KeyException} is the common superclass of all key related exceptions.
+ */
+public class KeyException extends GeneralSecurityException {
+
+ private static final long serialVersionUID = -7483676942812432108L;
+
+ /**
+ * Constructs a new instance of {@code KeyException} with the given message.
+ *
+ * @param msg
+ * the detail message for this exception.
+ */
+ public KeyException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs a new instance of {@code KeyException}.
+ */
+ public KeyException() {
+ }
+
+ /**
+ * Constructs a new instance of {@code KeyException} with the given message
+ * and the cause.
+ *
+ * @param message
+ * the detail message for this exception.
+ * @param cause
+ * the exception which is the cause for this exception.
+ */
+ public KeyException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructs a new instance of {@code KeyException} with the cause.
+ *
+ * @param cause
+ * the exception which is the cause for this exception.
+ */
+ public KeyException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/luni/src/main/java/java/security/KeyFactory.java b/luni/src/main/java/java/security/KeyFactory.java
new file mode 100644
index 0000000..7484a31
--- /dev/null
+++ b/luni/src/main/java/java/security/KeyFactory.java
@@ -0,0 +1,229 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import org.apache.harmony.security.fortress.Engine;
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * {@code KeyFactory} is an engine class that can be used to translate between
+ * public and private key objects and convert keys between their external
+ * representation, that can be easily transported and their internal
+ * representation.
+ */
+public class KeyFactory {
+ // The service name.
+ private static final String SERVICE = "KeyFactory"; //$NON-NLS-1$
+
+ // The provider
+ private Provider provider;
+
+
+ // Used to access common engine functionality
+ static private Engine engine = new Engine(SERVICE);
+
+ // The SPI implementation.
+ private KeyFactorySpi spiImpl;
+
+ // The algorithm.
+ private String algorithm;
+
+ /**
+ * Constructs a new instance of {@code KeyFactory} with the specified
+ * arguments.
+ *
+ * @param keyFacSpi
+ * the concrete key factory service.
+ * @param provider
+ * the provider.
+ * @param algorithm
+ * the algorithm to use.
+ */
+ protected KeyFactory(KeyFactorySpi keyFacSpi,
+ Provider provider,
+ String algorithm) {
+ this.provider = provider;
+ this. algorithm = algorithm;
+ this.spiImpl = keyFacSpi;
+ }
+
+ /**
+ * Returns a new instance of {@code KeyFactory} that utilizes the specified
+ * algorithm.
+ *
+ * @param algorithm
+ * the name of the algorithm.
+ * @return a new instance of {@code KeyFactory} that utilizes the specified
+ * algorithm.
+ * @throws NoSuchAlgorithmException
+ * if no provider provides the requested algorithm.
+ */
+ public static KeyFactory getInstance(String algorithm)
+ throws NoSuchAlgorithmException {
+ if (algorithm == null) {
+ throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+ }
+ synchronized (engine) {
+ engine.getInstance(algorithm, null);
+ return new KeyFactory((KeyFactorySpi)engine.spi, engine.provider, algorithm);
+ }
+ }
+
+ /**
+ * Returns a new instance of {@code KeyFactory} that utilizes the specified
+ * algorithm from the specified provider.
+ *
+ * @param algorithm
+ * the name of the algorithm.
+ * @param provider
+ * the name of the provider.
+ * @return a new instance of {@code KeyFactory} that utilizes the specified
+ * algorithm from the specified provider.
+ * @throws NoSuchAlgorithmException
+ * if the provider does not provide the requested algorithm.
+ * @throws NoSuchProviderException
+ * if the requested provider is not available.
+ * @throws IllegalArgumentException
+ * if {@code provider} is {@code null} or empty.
+ */
+ @SuppressWarnings("nls")
+ public static KeyFactory getInstance(String algorithm, String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException {
+ if ((provider == null) || (provider.length() == 0)) {
+ throw new IllegalArgumentException(Messages.getString("security.02"));
+ }
+ Provider p = Security.getProvider(provider);
+ if (p == null) {
+ throw new NoSuchProviderException(Messages.getString("security.03", provider));
+ }
+ return getInstance(algorithm, p);
+ }
+
+ /**
+ * Returns a new instance of {@code KeyFactory} that utilizes the specified
+ * algorithm from the specified provider.
+ *
+ * @param algorithm
+ * the name of the algorithm.
+ * @param provider
+ * the security provider.
+ * @return a new instance of {@code KeyFactory} that utilizes the specified
+ * algorithm from the specified provider.
+ * @throws NoSuchAlgorithmException
+ * if the provider does not provide the requested algorithm.
+ */
+ public static KeyFactory getInstance(String algorithm, Provider provider)
+ throws NoSuchAlgorithmException {
+ if (provider == null) {
+ throw new IllegalArgumentException(Messages.getString("security.04")); //$NON-NLS-1$
+ }
+ if (algorithm == null) {
+ throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+ }
+ synchronized (engine) {
+ engine.getInstance(algorithm, provider, null);
+ return new KeyFactory((KeyFactorySpi)engine.spi, provider, algorithm);
+ }
+ }
+
+ /**
+ * Returns the provider associated with this {@code KeyFactory}.
+ *
+ * @return the provider associated with this {@code KeyFactory}.
+ */
+ public final Provider getProvider() {
+ return provider;
+ }
+
+ /**
+ * Returns the name of the algorithm associated with this {@code
+ * KeyFactory}.
+ *
+ * @return the name of the algorithm associated with this {@code
+ * KeyFactory}.
+ */
+ public final String getAlgorithm() {
+ return algorithm;
+ }
+
+ /**
+ * Generates a instance of {@code PublicKey} from the given key
+ * specification.
+ *
+ * @param keySpec
+ * the specification of the public key
+ * @return the public key
+ * @throws InvalidKeySpecException
+ * if the specified {@code keySpec} is invalid
+ */
+ public final PublicKey generatePublic(KeySpec keySpec)
+ throws InvalidKeySpecException {
+ return spiImpl.engineGeneratePublic(keySpec);
+ }
+
+ /**
+ * Generates a instance of {@code PrivateKey} from the given key
+ * specification.
+ *
+ * @param keySpec
+ * the specification of the private key.
+ * @return the private key.
+ * @throws InvalidKeySpecException
+ * if the specified {@code keySpec} is invalid.
+ */
+ public final PrivateKey generatePrivate(KeySpec keySpec)
+ throws InvalidKeySpecException {
+ return spiImpl.engineGeneratePrivate(keySpec);
+ }
+
+ /**
+ * Returns the key specification for the specified key.
+ *
+ * @param key
+ * the key from which the specification is requested.
+ * @param keySpec
+ * the type of the requested {@code KeySpec}.
+ * @return the key specification for the specified key.
+ * @throws InvalidKeySpecException
+ * if the key can not be processed, or the requested requested
+ * {@code KeySpec} is inappropriate for the given key.
+ */
+ public final <T extends KeySpec> T getKeySpec(Key key,
+ Class<T> keySpec)
+ throws InvalidKeySpecException {
+ return spiImpl.engineGetKeySpec(key, keySpec);
+ }
+
+ /**
+ * Translates the given key into a key from this key factory.
+ *
+ * @param key
+ * the key to translate.
+ * @return the translated key.
+ * @throws InvalidKeyException
+ * if the specified key can not be translated by this key
+ * factory.
+ */
+ public final Key translateKey(Key key)
+ throws InvalidKeyException {
+ return spiImpl.engineTranslateKey(key);
+ }
+}
diff --git a/luni/src/main/java/java/security/KeyFactorySpi.java b/luni/src/main/java/java/security/KeyFactorySpi.java
new file mode 100644
index 0000000..0de00b2
--- /dev/null
+++ b/luni/src/main/java/java/security/KeyFactorySpi.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+/**
+ * {@code KeyFactorySpi} is the Service Provider Interface (SPI) definition for
+ * {@link KeyFactory}.
+ *
+ * @see KeyFactory
+ */
+public abstract class KeyFactorySpi {
+
+ /**
+ * Generates a instance of {@code PublicKey} from the given key
+ * specification.
+ *
+ * @param keySpec
+ * the specification of the public key.
+ * @return the public key.
+ * @throws InvalidKeySpecException
+ * if the specified {@code keySpec} is invalid.
+ */
+ protected abstract PublicKey engineGeneratePublic(KeySpec keySpec)
+ throws InvalidKeySpecException;
+
+ /**
+ * Generates a instance of {@code PrivateKey} from the given key
+ * specification.
+ *
+ * @param keySpec
+ * the specification of the private key.
+ * @return the private key.
+ * @throws InvalidKeySpecException
+ * if the specified {@code keySpec} is invalid.
+ */
+ protected abstract PrivateKey engineGeneratePrivate(KeySpec keySpec)
+ throws InvalidKeySpecException;
+
+ /**
+ * Returns the key specification for the specified key.
+ *
+ * @param key
+ * the key from which the specification is requested.
+ * @param keySpec
+ * the type of the requested {@code KeySpec}.
+ * @return the key specification for the specified key.
+ * @throws InvalidKeySpecException
+ * if the key can not be processed, or the requested requested
+ * {@code KeySpec} is inappropriate for the given key.
+ */
+ protected abstract <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)
+ throws InvalidKeySpecException;
+ //FIXME 1.5 signature: protected abstract <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec) throws InvalidKeySpecException
+
+ /**
+ * Translates the given key into a key from this key factory.
+ *
+ * @param key
+ * the key to translate.
+ * @return the translated key.
+ * @throws InvalidKeyException
+ * if the specified key can not be translated by this key
+ * factory.
+ */
+ protected abstract Key engineTranslateKey(Key key) throws InvalidKeyException;
+
+}
diff --git a/luni/src/main/java/java/security/KeyManagementException.java b/luni/src/main/java/java/security/KeyManagementException.java
new file mode 100644
index 0000000..00a5b3c
--- /dev/null
+++ b/luni/src/main/java/java/security/KeyManagementException.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * {@code KeyManagementException} is a general exception, thrown to indicate an
+ * exception during processing an operation concerning key management.
+ */
+public class KeyManagementException extends KeyException {
+
+ private static final long serialVersionUID = 947674216157062695L;
+
+ /**
+ * Constructs a new instance of {@code KeyManagementException} with the
+ * given message.
+ *
+ * @param msg
+ * the detail message for this exception.
+ */
+ public KeyManagementException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs a new instance of {@code KeyManagementException}.
+ */
+ public KeyManagementException() {
+ }
+
+ /**
+ * Constructs a new instance of {@code KeyManagementException} with the
+ * given message and the cause.
+ *
+ * @param message
+ * the detail message for this exception.
+ * @param cause
+ * the exception which is the cause for this exception.
+ */
+ public KeyManagementException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructs a new instance of {@code KeyManagementException} with the
+ * cause.
+ *
+ * @param cause
+ * the exception which is the cause for this exception.
+ */
+ public KeyManagementException(Throwable cause) {
+ super(cause);
+ }
+
+}
diff --git a/luni/src/main/java/java/security/KeyPair.java b/luni/src/main/java/java/security/KeyPair.java
new file mode 100644
index 0000000..b86593b
--- /dev/null
+++ b/luni/src/main/java/java/security/KeyPair.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.io.Serializable;
+
+/**
+ * {@code KeyPair} is a container for a public key and a private key. Since the
+ * private key can be accessed, instances must be treated like a private key.
+ *
+ * @see PrivateKey
+ * @see PublicKey
+ */
+public final class KeyPair implements Serializable {
+
+ private static final long serialVersionUID = -7565189502268009837L;
+ private final PrivateKey privateKey;
+ private final PublicKey publicKey;
+
+ /**
+ * Constructs a new instance of {@code KeyPair} with a public key and the
+ * corresponding private key.
+ *
+ * @param publicKey
+ * the public key.
+ * @param privateKey
+ * the private key.
+ */
+ public KeyPair(PublicKey publicKey, PrivateKey privateKey) {
+ this.privateKey = privateKey;
+ this.publicKey = publicKey;
+ }
+
+ /**
+ * Returns the private key.
+ *
+ * @return the private key.
+ */
+ public PrivateKey getPrivate() {
+ return privateKey;
+ }
+
+ /**
+ * Returns the public key.
+ *
+ * @return the public key.
+ */
+ public PublicKey getPublic() {
+ return publicKey;
+ }
+}
diff --git a/luni/src/main/java/java/security/KeyPairGenerator.java b/luni/src/main/java/java/security/KeyPairGenerator.java
new file mode 100644
index 0000000..2a17e98
--- /dev/null
+++ b/luni/src/main/java/java/security/KeyPairGenerator.java
@@ -0,0 +1,302 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.apache.harmony.security.fortress.Engine;
+import org.apache.harmony.security.internal.nls.Messages;
+
+
+/**
+ * {@code KeyPairGenerator} is an engine class which is capable of generating a
+ * private key and its related public key utilizing the algorithm it was
+ * initialized with.
+ *
+ * @see KeyPairGeneratorSpi
+ */
+public abstract class KeyPairGenerator extends KeyPairGeneratorSpi {
+
+ // Store KeyPairGenerator SERVICE name
+ private static final String SERVICE = "KeyPairGenerator"; //$NON-NLS-1$
+
+ // Used to access common engine functionality
+ private static Engine engine = new Engine(SERVICE);
+
+ // Store SecureRandom
+ private static SecureRandom random = new SecureRandom();
+
+ // Store used provider
+ private Provider provider;
+
+ // Store used algorithm
+ private String algorithm;
+
+ /**
+ * Constructs a new instance of {@code KeyPairGenerator} with the name of
+ * the algorithm to use.
+ *
+ * @param algorithm
+ * the name of algorithm to use
+ */
+ protected KeyPairGenerator(String algorithm) {
+ this.algorithm = algorithm;
+ }
+
+ /**
+ * Returns the name of the algorithm of this {@code KeyPairGenerator}.
+ *
+ * @return the name of the algorithm of this {@code KeyPairGenerator}
+ */
+ public String getAlgorithm() {
+ return algorithm;
+ }
+
+ /**
+ * Returns a new instance of {@code KeyPairGenerator} that utilizes the
+ * specified algorithm.
+ *
+ * @param algorithm
+ * the name of the algorithm to use
+ * @return a new instance of {@code KeyPairGenerator} that utilizes the
+ * specified algorithm
+ * @throws NoSuchAlgorithmException if the specified algorithm is not available
+ * @throws NullPointerException
+ * if {@code algorithm} is {@code null}
+ */
+ public static KeyPairGenerator getInstance(String algorithm)
+ throws NoSuchAlgorithmException {
+ if (algorithm == null) {
+ throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+ }
+ KeyPairGenerator result;
+ synchronized (engine) {
+ engine.getInstance(algorithm, null);
+ if (engine.spi instanceof KeyPairGenerator) {
+ result = (KeyPairGenerator) engine.spi;
+ result.algorithm = algorithm;
+ result.provider = engine.provider;
+ return result;
+ }
+ result = new KeyPairGeneratorImpl((KeyPairGeneratorSpi) engine.spi,
+ engine.provider, algorithm);
+ return result;
+ }
+ }
+
+ /**
+ * Returns a new instance of {@code KeyPairGenerator} that utilizes the
+ * specified algorithm from the specified provider.
+ *
+ * @param algorithm
+ * the name of the algorithm to use
+ * @param provider
+ * the name of the provider
+ * @return a new instance of {@code KeyPairGenerator} that utilizes the
+ * specified algorithm from the specified provider
+ * @throws NoSuchAlgorithmException if the specified algorithm is not available
+ * @throws NoSuchProviderException if the specified provider is not available
+ * @throws NullPointerException
+ * if {@code algorithm} is {@code null}
+ */
+ public static KeyPairGenerator getInstance(String algorithm, String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException {
+ if ((provider == null) || (provider.length() == 0)) {
+ throw new IllegalArgumentException(
+ Messages.getString("security.02")); //$NON-NLS-1$
+ }
+ Provider impProvider = Security.getProvider(provider);
+ if (impProvider == null) {
+ throw new NoSuchProviderException(provider);
+ }
+ return getInstance(algorithm, impProvider);
+ }
+
+ /**
+ * Returns a new instance of {@code KeyPairGenerator} that utilizes the
+ * specified algorithm from the specified provider.
+ *
+ * @param algorithm
+ * the name of the algorithm to use
+ * @param provider
+ * the provider
+ * @return a new instance of {@code KeyPairGenerator} that utilizes the
+ * specified algorithm from the specified provider
+ * @throws NoSuchAlgorithmException if the specified algorithm is not available
+ * @throws NullPointerException
+ * if {@code algorithm} is {@code null}
+ */
+ public static KeyPairGenerator getInstance(String algorithm,
+ Provider provider) throws NoSuchAlgorithmException {
+ if (provider == null) {
+ throw new IllegalArgumentException(Messages.getString("security.04")); //$NON-NLS-1$
+ }
+ if (algorithm == null) {
+ throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+ }
+ KeyPairGenerator result;
+ synchronized (engine) {
+ engine.getInstance(algorithm, provider, null);
+ if (engine.spi instanceof KeyPairGenerator) {
+ result = (KeyPairGenerator) engine.spi;
+ result.algorithm = algorithm;
+ result.provider = provider;
+ return result;
+ }
+ result = new KeyPairGeneratorImpl((KeyPairGeneratorSpi) engine.spi,
+ provider, algorithm);
+ return result;
+ }
+ }
+
+ /**
+ * Returns the provider associated with this {@code KeyPairGenerator}.
+ *
+ * @return the provider associated with this {@code KeyPairGenerator}
+ */
+ public final Provider getProvider() {
+ return provider;
+ }
+
+ /**
+ * Initializes this {@code KeyPairGenerator} with the given key size. The
+ * default parameter set and a default {@code SecureRandom} instance will be
+ * used.
+ *
+ * @param keysize
+ * the size of the key (number of bits)
+ */
+ public void initialize(int keysize) {
+ initialize(keysize, random);
+ }
+
+ /**
+ * Initializes this {@code KeyPairGenerator} with the given {@code
+ * AlgorithmParameterSpec}. A default {@code SecureRandom} instance will be
+ * used.
+ *
+ * @param param
+ * the parameters to use
+ * @throws InvalidAlgorithmParameterException
+ * if the specified parameters are not supported
+ */
+ public void initialize(AlgorithmParameterSpec param)
+ throws InvalidAlgorithmParameterException {
+ initialize(param, random);
+ }
+
+ /**
+ * Computes and returns a new unique {@code KeyPair} each time this method
+ * is called.
+ * <p>
+ * This does exactly the same as {@link #generateKeyPair()}.
+ *
+ * @return a new unique {@code KeyPair} each time this method is called
+ */
+ public final KeyPair genKeyPair() {
+ return generateKeyPair();
+ }
+
+ /**
+ * Computes and returns a new unique {@code KeyPair} each time this method
+ * is called.
+ * <p>
+ * This does exactly the same as {@link #genKeyPair()}.
+ *
+ * @return a new unique {@code KeyPair} each time this method is called
+ */
+ @Override
+ public KeyPair generateKeyPair() {
+ return null;
+ }
+
+ /**
+ * Initializes this {@code KeyPairGenerator} with the given key size and the
+ * given {@code SecureRandom}. The default parameter set will be used.
+ *
+ * @param keysize
+ * the key size
+ * @param random
+ * the source of randomness
+ */
+ @Override
+ public void initialize(int keysize, SecureRandom random) {
+ }
+
+ /**
+ * Initializes this {@code KeyPairGenerator} with the given {@code
+ * AlgorithmParameterSpec} and the given {@code SecureRandom}.
+ *
+ * @param param
+ * the parameters to use
+ * @param random
+ * the source of randomness
+ * @throws InvalidAlgorithmParameterException
+ * if the specified parameters are not supported
+ */
+ @Override
+ public void initialize(AlgorithmParameterSpec param, SecureRandom random)
+ throws InvalidAlgorithmParameterException {
+ }
+
+ /**
+ *
+ * Internal class: KeyPairGenerator implementation
+ *
+ */
+ private static class KeyPairGeneratorImpl extends KeyPairGenerator {
+ // Save KeyPairGeneratorSpi
+ private KeyPairGeneratorSpi spiImpl;
+
+ // Implementation of KeyPaiGenerator constructor
+ //
+ // @param KeyPairGeneratorSpi
+ // @param provider
+ // @param algorithm
+ private KeyPairGeneratorImpl(KeyPairGeneratorSpi keyPairGeneratorSpi,
+ Provider provider, String algorithm) {
+ super(algorithm);
+ super.provider = provider;
+ spiImpl = keyPairGeneratorSpi;
+ }
+
+ // implementation of initialize(int keysize, SecureRandom random)
+ // using corresponding spi initialize() method
+ @Override
+ public void initialize(int keysize, SecureRandom random) {
+ spiImpl.initialize(keysize, random);
+ }
+
+ // implementation of generateKeyPair()
+ // using corresponding spi generateKeyPair() method
+ @Override
+ public KeyPair generateKeyPair() {
+ return spiImpl.generateKeyPair();
+ }
+
+ // implementation of initialize(int keysize, SecureRandom random)
+ // using corresponding spi initialize() method
+ @Override
+ public void initialize(AlgorithmParameterSpec param, SecureRandom random)
+ throws InvalidAlgorithmParameterException {
+ spiImpl.initialize(param, random);
+ }
+
+ }
+
+}
diff --git a/luni/src/main/java/java/security/KeyPairGeneratorSpi.java b/luni/src/main/java/java/security/KeyPairGeneratorSpi.java
new file mode 100644
index 0000000..e2e22c1
--- /dev/null
+++ b/luni/src/main/java/java/security/KeyPairGeneratorSpi.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * {@code KeyPairGeneratorSpi} is the Service Provider Interface (SPI)
+ * definition for {@link KeyPairGenerator}.
+ *
+ * @see KeyPairGenerator
+ */
+public abstract class KeyPairGeneratorSpi {
+ /**
+ * Constructs a new instance of {@code KeyPairGeneratorSpi}.
+ */
+ public KeyPairGeneratorSpi() {
+ }
+
+ /**
+ * Computes and returns a new unique {@code KeyPair} each time this method
+ * is called.
+ *
+ * @return a new unique {@code KeyPair} each time this method is called.
+ */
+ public abstract KeyPair generateKeyPair();
+
+ /**
+ * Initializes this {@code KeyPairGeneratorSpi} with the given key size and
+ * the given {@code SecureRandom}. The default parameter set will be used.
+ *
+ * @param keysize
+ * the key size (number of bits).
+ * @param random
+ * the source of randomness.
+ */
+ public abstract void initialize(int keysize, SecureRandom random);
+
+ /**
+ * Initializes this {@code KeyPairGeneratorSpi} with the given {@code
+ * AlgorithmParameterSpec} and the given {@code SecureRandom}.
+ *
+ * @param params
+ * the parameters to use.
+ * @param random
+ * the source of randomness.
+ * @throws InvalidAlgorithmParameterException
+ * if the specified parameters are not supported.
+ */
+ public void initialize(AlgorithmParameterSpec params, SecureRandom random)
+ throws InvalidAlgorithmParameterException {
+ throw new UnsupportedOperationException(Messages.getString("security.2E")); //$NON-NLS-1$
+ }
+}
diff --git a/luni/src/main/java/java/security/KeyRep.java b/luni/src/main/java/java/security/KeyRep.java
new file mode 100644
index 0000000..29ccd22
--- /dev/null
+++ b/luni/src/main/java/java/security/KeyRep.java
@@ -0,0 +1,183 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.io.IOException;
+import java.io.NotSerializableException;
+import java.io.ObjectInputStream;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.security.spec.X509EncodedKeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.InvalidKeySpecException;
+
+import javax.crypto.spec.SecretKeySpec;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * {@code KeyRep} is a standardized representation for serialized {@link Key}
+ * objects.
+ */
+public class KeyRep implements Serializable {
+
+ private static final long serialVersionUID = -4757683898830641853L;
+ // Key type
+ private final Type type;
+ // Key algorithm name
+ private final String algorithm;
+ // Key encoding format
+ private final String format;
+ // Key encoding
+ private byte[] encoded;
+
+ /**
+ * Constructs a new instance of {@code KeyRep} with the specified arguments.
+ * The arguments should be obtained from the {@code Key} object that has to
+ * be serialized.
+ *
+ * @param type
+ * the type of the key.
+ * @param algorithm
+ * the algorithm (obtained by {@link Key#getAlgorithm()}).
+ * @param format
+ * the format of the key (obtained by {@link Key#getFormat()}).
+ * @param encoded
+ * the encoded {@code byte[]} (obtained by
+ * {@link Key#getEncoded()}).
+ * @throws NullPointerException
+ * if {@code type, algorithm, format or encoded} is {@code null}
+ * .
+ */
+ public KeyRep(Type type,
+ String algorithm, String format, byte[] encoded) {
+ this.type = type;
+ this.algorithm = algorithm;
+ this.format = format;
+ this.encoded = encoded;
+ if(this.type == null) {
+ throw new NullPointerException(Messages.getString("security.07")); //$NON-NLS-1$
+ }
+ if(this.algorithm == null) {
+ throw new NullPointerException(Messages.getString("security.08")); //$NON-NLS-1$
+ }
+ if(this.format == null) {
+ throw new NullPointerException(Messages.getString("security.09")); //$NON-NLS-1$
+ }
+ if(this.encoded == null) {
+ throw new NullPointerException(Messages.getString("security.0A")); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Resolves and returns the {@code Key} object. Three {@link Type}|format
+ * combinations are supported:
+ * <ul>
+ * <li> {@code Type.PRIVATE} | "PKCS#8" : returns a {@link PrivateKey}
+ * instance, generated from a key factory (suitable for the algorithm) that
+ * is initialized with a {@link PKCS8EncodedKeySpec} using the encoded key
+ * bytes.
+ * <li> {@code Type.SECRET} | "RAW" : returns a {@link SecretKeySpec}
+ * instance, created with the encoded key bytes and the algorithm.
+ * <li> {@code Type.PUBLIC} | "X.509": returns a {@link PublicKey} instance,
+ * generated from a key factory (suitable for the algorithm) that is
+ * initialized with a {@link X509EncodedKeySpec} using the encoded key
+ * bytes.
+ * </ul>
+ *
+ * @return the resolved {@code Key} object.
+ * @throws ObjectStreamException
+ * if the {@code Type}|format combination is not recognized, or
+ * the resolution of any key parameter fails.
+ */
+ protected Object readResolve() throws ObjectStreamException {
+ switch (type) {
+ case SECRET:
+ if ("RAW".equals(format)) { //$NON-NLS-1$
+ try {
+ return new SecretKeySpec(encoded, algorithm);
+ } catch (IllegalArgumentException e) {
+ throw new NotSerializableException(
+ Messages.getString("security.0B", e)); //$NON-NLS-1$
+ }
+ }
+ throw new NotSerializableException(
+ Messages.getString("security.0C", type, format)); //$NON-NLS-1$
+ case PUBLIC:
+ if ("X.509".equals(format)) { //$NON-NLS-1$
+ try {
+ KeyFactory kf = KeyFactory.getInstance(algorithm);
+ return kf.generatePublic(new X509EncodedKeySpec(encoded));
+ } catch (NoSuchAlgorithmException e) {
+ throw new NotSerializableException(
+ Messages.getString("security.0D", e)); //$NON-NLS-1$
+ }
+ catch (InvalidKeySpecException e) {
+ throw new NotSerializableException(
+ Messages.getString("security.0D", e)); //$NON-NLS-1$
+ }
+ }
+ throw new NotSerializableException(
+ Messages.getString("security.0C", type, format)); //$NON-NLS-1$
+ case PRIVATE:
+ if ("PKCS#8".equals(format)) { //$NON-NLS-1$
+ try {
+ KeyFactory kf = KeyFactory.getInstance(algorithm);
+ return kf.generatePrivate(new PKCS8EncodedKeySpec(encoded));
+ } catch (NoSuchAlgorithmException e) {
+ throw new NotSerializableException(
+ Messages.getString("security.0D", e)); //$NON-NLS-1$
+ }
+ catch (InvalidKeySpecException e) {
+ throw new NotSerializableException(
+ Messages.getString("security.0D", e)); //$NON-NLS-1$
+ }
+ }
+ throw new NotSerializableException(
+ Messages.getString("security.0C", type, format)); //$NON-NLS-1$
+ }
+ throw new NotSerializableException(Messages.getString("security.0E", type)); //$NON-NLS-1$
+ }
+
+ // Makes defensive copy of key encoding
+ private void readObject(ObjectInputStream is)
+ throws IOException, ClassNotFoundException {
+ is.defaultReadObject();
+ byte[] new_encoded = new byte[encoded.length];
+ System.arraycopy(encoded, 0, new_encoded, 0, new_encoded.length);
+ encoded = new_encoded;
+ }
+
+ /**
+ * {@code Type} enumerates the supported key types.
+ */
+ public static enum Type {
+ /**
+ * Type for secret keys.
+ */
+ SECRET,
+ /**
+ * Type for public keys.
+ */
+ PUBLIC,
+ /**
+ * Type for private keys.
+ */
+ PRIVATE
+ }
+}
diff --git a/luni/src/main/java/java/security/KeyStore.java b/luni/src/main/java/java/security/KeyStore.java
new file mode 100644
index 0000000..02ac01d
--- /dev/null
+++ b/luni/src/main/java/java/security/KeyStore.java
@@ -0,0 +1,1501 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Enumeration;
+
+import javax.crypto.SecretKey;
+import javax.security.auth.DestroyFailedException;
+import javax.security.auth.Destroyable;
+import javax.security.auth.callback.CallbackHandler;
+
+import org.apache.harmony.security.fortress.Engine;
+import org.apache.harmony.security.internal.nls.Messages;
+
+
+/**
+ * {@code KeyStore} is responsible for maintaining cryptographic keys and their
+ * owners.
+ * <p>
+ * The type of the system key store can be changed by setting the {@code
+ * 'keystore.type'} property in the file named {@code
+ * JAVA_HOME/lib/security/java.security}.
+ *
+ * @see Certificate
+ * @see PrivateKey
+ */
+public class KeyStore {
+
+ // Store KeyStore SERVICE name
+ private static final String SERVICE = "KeyStore"; //$NON-NLS-1$
+
+ // Used to access common engine functionality
+ private static Engine engine = new Engine(SERVICE);
+
+ // Store KeyStore property name
+ private static final String PROPERTYNAME = "keystore.type"; //$NON-NLS-1$
+
+ // Store default KeyStore type
+ private static final String DEFAULT_KEYSTORE_TYPE = "jks"; //$NON-NLS-1$
+
+ // Message to report about non-initialized key store object
+ // BEGIN android-changed
+ private static String NOTINITKEYSTORE;
+ // END android-changed
+
+ // Store KeyStore state (initialized or not)
+ private boolean isInit;
+
+ // Store used KeyStoreSpi
+ private final KeyStoreSpi implSpi;
+
+ // Store used provider
+ private final Provider provider;
+
+ // Store used type
+ private final String type;
+
+ /**
+ * Constructs a new instance of {@code KeyStore} with the given arguments.
+ *
+ * @param keyStoreSpi
+ * the concrete key store.
+ * @param provider
+ * the provider.
+ * @param type
+ * the type of the {@code KeyStore} to be constructed.
+ */
+ protected KeyStore(KeyStoreSpi keyStoreSpi, Provider provider, String type) {
+ this.type = type;
+ this.provider = provider;
+ this.implSpi = keyStoreSpi;
+ isInit = false;
+ }
+
+ // BEGIN android-added
+ /**
+ * Throws the standard "keystore not initialized" exception.
+ */
+ private static void throwNotInitialized() throws KeyStoreException {
+ if (NOTINITKEYSTORE == null) {
+ NOTINITKEYSTORE = Messages.getString("security.4F"); //$NON-NLS-1$
+ }
+ throw new KeyStoreException(NOTINITKEYSTORE);
+ }
+ // END android-added
+
+ /**
+ * Returns a new instance of {@code KeyStore} with the specified type.
+ *
+ * @param type
+ * the type of the returned {@code KeyStore}.
+ * @return a new instance of {@code KeyStore} with the specified type.
+ * @throws KeyStoreException
+ * if an error occurred during the creation of the new {@code
+ * KeyStore}.
+ * @throws NullPointerException
+ * if {@code type} is {@code null}.
+ * @see #getDefaultType
+ */
+ public static KeyStore getInstance(String type) throws KeyStoreException {
+ if (type == null) {
+ throw new NullPointerException(Messages.getString("security.07")); //$NON-NLS-1$
+ }
+ synchronized (engine) {
+ try {
+ engine.getInstance(type, null);
+ return new KeyStore((KeyStoreSpi) engine.spi, engine.provider, type);
+ } catch (NoSuchAlgorithmException e) {
+ throw new KeyStoreException(e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * Returns a new instance of {@code KeyStore} from the specified provider
+ * with the given type.
+ *
+ * @param type
+ * the type of the returned {@code KeyStore}.
+ * @param provider
+ * name of the provider of the {@code KeyStore}.
+ * @return a new instance of {@code KeyStore} from the specified provider
+ * with the given type.
+ * @throws KeyStoreException
+ * if an error occurred during the creation of the new {@code
+ * KeyStore}.
+ * @throws NoSuchProviderException
+ * if the specified provider is not available.
+ * @throws IllegalArgumentException
+ * if {@code provider} is {@code null} or the empty string.
+ * @throws NullPointerException
+ * if {@code type} is {@code null} (instead of
+ * NoSuchAlgorithmException) as in 1.4 release
+ * @see #getDefaultType
+ */
+ public static KeyStore getInstance(String type, String provider)
+ throws KeyStoreException, NoSuchProviderException {
+ if ((provider == null) || (provider.length() == 0)) {
+ throw new IllegalArgumentException(Messages.getString("security.02")); //$NON-NLS-1$
+ }
+ Provider impProvider = Security.getProvider(provider);
+ if (impProvider == null) {
+ throw new NoSuchProviderException(provider);
+ }
+ try {
+ return getInstance(type, impProvider);
+ } catch (Exception e) {
+ throw new KeyStoreException(e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Returns a new instance of {@code KeyStore} from the specified provider
+ * with the given type.
+ *
+ * @param type
+ * the type of the returned {@code KeyStore}.
+ * @param provider
+ * the provider of the {@code KeyStore}.
+ * @return a new instance of {@code KeyStore} from the specified provider
+ * with the given type.
+ * @throws KeyStoreException
+ * if an error occurred during the creation of the new {@code
+ * KeyStore}.
+ * @throws IllegalArgumentException
+ * if {@code provider} is {@code null} or the empty string.
+ * @throws NullPointerException
+ * if {@code type} is {@code null} (instead of
+ * NoSuchAlgorithmException) as in 1.4 release
+ * @see #getDefaultType
+ */
+ public static KeyStore getInstance(String type, Provider provider)
+ throws KeyStoreException {
+ // check parameters
+ if (provider == null) {
+ throw new IllegalArgumentException(Messages.getString("security.04")); //$NON-NLS-1$
+ }
+ if (type == null) {
+ throw new NullPointerException(Messages.getString("security.07")); //$NON-NLS-1$
+ }
+ // return KeyStore instance
+ synchronized (engine) {
+ try {
+ engine.getInstance(type, provider, null);
+ return new KeyStore((KeyStoreSpi) engine.spi, provider, type);
+ } catch (Exception e) {
+ // override exception
+ throw new KeyStoreException(e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * Returns the default type for {@code KeyStore} instances.
+ * <p>
+ * The default is specified in the {@code 'keystore.type'} property in the
+ * file named {@code JAVA_HOME/lib/security/java.security}. If this property
+ * is not set, {@code "jks"} will be used.
+ *
+ * @return the default type for {@code KeyStore} instances
+ */
+ public static final String getDefaultType() {
+ String dt = AccessController.doPrivileged(
+ new PrivilegedAction<String>() {
+ public String run() {
+ return Security.getProperty(PROPERTYNAME);
+ }
+ }
+ );
+ return (dt == null ? DEFAULT_KEYSTORE_TYPE : dt);
+ }
+
+ /**
+ * Returns the provider associated with this {@code KeyStore}.
+ *
+ * @return the provider associated with this {@code KeyStore}.
+ */
+ public final Provider getProvider() {
+ return provider;
+ }
+
+ /**
+ * Returns the type of this {@code KeyStore}.
+ *
+ * @return the type of this {@code KeyStore}.
+ */
+ public final String getType() {
+ return type;
+ }
+
+ /**
+ * Returns the key with the given alias, using the password to recover the
+ * key from the store.
+ *
+ * @param alias
+ * the alias for the entry.
+ * @param password
+ * the password used to recover the key.
+ * @return the key with the specified alias, or {@code null} if the
+ * specified alias is not bound to an entry.
+ * @throws KeyStoreException
+ * if this {@code KeyStore} is not initialized.
+ * @throws NoSuchAlgorithmException
+ * if the algorithm for recovering the key is not available.
+ * @throws UnrecoverableKeyException
+ * if the key can not be recovered.
+ */
+ public final Key getKey(String alias, char[] password)
+ throws KeyStoreException, NoSuchAlgorithmException,
+ UnrecoverableKeyException {
+ if (!isInit) {
+ // BEGIN android-changed
+ throwNotInitialized();
+ // END android-changed
+ }
+ return implSpi.engineGetKey(alias, password);
+ }
+
+ /**
+ * Returns the certificate chain for the entry with the given alias.
+ *
+ * @param alias
+ * the alias for the entry.
+ * @return the certificate chain for the entry with the given alias, or
+ * {@code null} if the specified alias is not bound to an entry.
+ * @throws KeyStoreException
+ * if this {@code KeyStore} is not initialized.
+ */
+ public final Certificate[] getCertificateChain(String alias)
+ throws KeyStoreException {
+ if (!isInit) {
+ // BEGIN android-changed
+ throwNotInitialized();
+ // END android-changed
+ }
+ return implSpi.engineGetCertificateChain(alias);
+ }
+
+ /**
+ * Returns the trusted certificate for the entry with the given alias.
+ *
+ * @param alias
+ * the alias for the entry.
+ * @return the trusted certificate for the entry with the given alias, or
+ * {@code null} if the specified alias is not bound to an entry.
+ * @throws KeyStoreException
+ * if this {@code KeyStore} is not initialized.
+ */
+ public final Certificate getCertificate(String alias)
+ throws KeyStoreException {
+ if (!isInit) {
+ // BEGIN android-changed
+ throwNotInitialized();
+ // END android-changed
+ }
+ return implSpi.engineGetCertificate(alias);
+ }
+
+ /**
+ * Returns the creation date of the entry with the given alias.
+ *
+ * @param alias
+ * the alias for the entry.
+ * @return the creation date, or {@code null} if the specified alias is not
+ * bound to an entry.
+ * @throws KeyStoreException
+ * if this {@code KeyStore} is not initialized.
+ */
+ public final Date getCreationDate(String alias) throws KeyStoreException {
+ if (!isInit) {
+ // BEGIN android-changed
+ throwNotInitialized();
+ // END android-changed
+ }
+ return implSpi.engineGetCreationDate(alias);
+ }
+
+ /**
+ * Associates the given alias with the key, password and certificate chain.
+ * <p>
+ * If the specified alias already exists, it will be reassigned.
+ *
+ * @param alias
+ * the alias for the key.
+ * @param key
+ * the key.
+ * @param password
+ * the password.
+ * @param chain
+ * the certificate chain.
+ * @throws KeyStoreException
+ * if this {@code KeyStore} is not initialized.
+ * @throws IllegalArgumentException
+ * if {@code key} is a {@code PrivateKey} and {@code chain} does
+ * not contain any certificates.
+ * @throws NullPointerException
+ * if {@code alias} is {@code null}.
+ */
+ public final void setKeyEntry(String alias, Key key, char[] password,
+ Certificate[] chain) throws KeyStoreException {
+ if (!isInit) {
+ // BEGIN android-changed
+ throwNotInitialized();
+ // END android-changed
+ }
+
+ // Certificate chain is required for PrivateKey
+ if (null != key && key instanceof PrivateKey
+ && (chain == null || chain.length == 0)) {
+ throw new IllegalArgumentException(Messages
+ .getString("security.52")); //$NON-NLS-1$
+ }
+ implSpi.engineSetKeyEntry(alias, key, password, chain);
+ }
+
+ /**
+ * Associates the given alias with a key and a certificate chain.
+ * <p>
+ * If the specified alias already exists, it will be reassigned.
+ * <p>
+ * If this {@code KeyStore} is of type {@code "jks"}, {@code key} must be
+ * encoded conform to the PKS#8 standard as an
+ * {@link javax.crypto.EncryptedPrivateKeyInfo}.
+ *
+ * @param alias
+ * the alias for the key.
+ * @param key
+ * the key in an encoded format.
+ * @param chain
+ * the certificate chain.
+ * @throws KeyStoreException
+ * if this {@code KeyStore} is not initialized or if {@code key}
+ * is null.
+ * @throws IllegalArgumentException
+ * if {@code key} is a {@code PrivateKey} and {@code chain}
+ * does.
+ * @throws NullPointerException
+ * if {@code alias} is {@code null}.
+ */
+ public final void setKeyEntry(String alias, byte[] key, Certificate[] chain)
+ throws KeyStoreException {
+ if (!isInit) {
+ // BEGIN android-changed
+ throwNotInitialized();
+ // END android-changed
+ }
+ implSpi.engineSetKeyEntry(alias, key, chain);
+ }
+
+ /**
+ * Associates the given alias with a certificate.
+ * <p>
+ * If the specified alias already exists, it will be reassigned.
+ *
+ * @param alias
+ * the alias for the certificate.
+ * @param cert
+ * the certificate.
+ * @throws KeyStoreException
+ * if this {@code KeyStore} is not initialized, or an existing
+ * alias is not associated to an entry containing a trusted
+ * certificate, or this method fails for any other reason.
+ * @throws NullPointerException
+ * if {@code alias} is {@code null}.
+ */
+ public final void setCertificateEntry(String alias, Certificate cert)
+ throws KeyStoreException {
+ if (!isInit) {
+ // BEGIN android-changed
+ throwNotInitialized();
+ // END android-changed
+ }
+ implSpi.engineSetCertificateEntry(alias, cert);
+ }
+
+ /**
+ * Deletes the entry identified with the given alias from this {@code
+ * KeyStore}.
+ *
+ * @param alias
+ * the alias for the entry.
+ * @throws KeyStoreException
+ * if this {@code KeyStore} is not initialized, or if the entry
+ * can not be deleted.
+ * @throws NullPointerException
+ * if {@code alias} is {@code null}.
+ */
+ public final void deleteEntry(String alias) throws KeyStoreException {
+ if (!isInit) {
+ // BEGIN android-changed
+ throwNotInitialized();
+ // END android-changed
+ }
+ if (alias == null) {
+ throw new NullPointerException(Messages.getString("security.3F")); //$NON-NLS-1$
+ }
+ implSpi.engineDeleteEntry(alias);
+ }
+
+ /**
+ * Returns an {@code Enumeration} over all alias names stored in this
+ * {@code KeyStore}.
+ *
+ * @return an {@code Enumeration} over all alias names stored in this
+ * {@code KeyStore}.
+ * @throws KeyStoreException
+ * if this {@code KeyStore} is not initialized.
+ */
+ public final Enumeration<String> aliases() throws KeyStoreException {
+ if (!isInit) {
+ // BEGIN android-changed
+ throwNotInitialized();
+ // END android-changed
+ }
+ return implSpi.engineAliases();
+ }
+
+ /**
+ * Indicates whether the given alias is present in this {@code KeyStore}.
+ *
+ * @param alias
+ * the alias of an entry.
+ * @return {@code true} if the alias exists, {@code false} otherwise.
+ * @throws KeyStoreException
+ * if this {@code KeyStore} is not initialized.
+ * @throws NullPointerException
+ * if {@code alias} is {@code null}.
+ */
+ public final boolean containsAlias(String alias) throws KeyStoreException {
+ if (!isInit) {
+ // BEGIN android-changed
+ throwNotInitialized();
+ // END android-changed
+ }
+ if (alias == null) {
+ throw new NullPointerException(Messages.getString("security.3F")); //$NON-NLS-1$
+ }
+ return implSpi.engineContainsAlias(alias);
+ }
+
+ /**
+ * Returns the number of entries stored in this {@code KeyStore}.
+ *
+ * @return the number of entries stored in this {@code KeyStore}.
+ * @throws KeyStoreException
+ * if this {@code KeyStore} is not initialized.
+ */
+ public final int size() throws KeyStoreException {
+ if (!isInit) {
+ // BEGIN android-changed
+ throwNotInitialized();
+ // END android-changed
+ }
+ return implSpi.engineSize();
+ }
+
+ /**
+ * Indicates whether the specified alias is associated with either a
+ * {@link PrivateKeyEntry} or a {@link SecretKeyEntry}.
+ *
+ * @param alias
+ * the alias of an entry.
+ * @return {@code true} if the given alias is associated with a key entry.
+ * @throws KeyStoreException
+ * if this {@code KeyStore} is not initialized.
+ * @throws NullPointerException
+ * if {@code alias} is {@code null}.
+ */
+ public final boolean isKeyEntry(String alias) throws KeyStoreException {
+ if (!isInit) {
+ // BEGIN android-changed
+ throwNotInitialized();
+ // END android-changed
+ }
+ if (alias == null) {
+ throw new NullPointerException(Messages.getString("security.3F")); //$NON-NLS-1$
+ }
+ return implSpi.engineIsKeyEntry(alias);
+ }
+
+ /**
+ * Indicates whether the specified alias is associated with a
+ * {@link TrustedCertificateEntry}.
+ *
+ * @param alias
+ * the alias of an entry.
+ * @return {@code true} if the given alias is associated with a certificate
+ * entry.
+ * @throws KeyStoreException
+ * if this {@code KeyStore} is not initialized.
+ * @throws NullPointerException
+ * if {@code alias} is {@code null}.
+ */
+ public final boolean isCertificateEntry(String alias)
+ throws KeyStoreException {
+ if (!isInit) {
+ // BEGIN android-changed
+ throwNotInitialized();
+ // END android-changed
+ }
+ if (alias == null) {
+ throw new NullPointerException(Messages.getString("security.3F")); //$NON-NLS-1$
+ }
+ return implSpi.engineIsCertificateEntry(alias);
+ }
+
+ /**
+ * Returns the alias associated with the first entry whose certificate
+ * matches the specified certificate.
+ *
+ * @param cert
+ * the certificate to find the associated entry's alias for.
+ * @return the alias or {@code null} if no entry with the specified
+ * certificate can be found.
+ * @throws KeyStoreException
+ * if this {@code KeyStore} is not initialized.
+ */
+ public final String getCertificateAlias(Certificate cert)
+ throws KeyStoreException {
+ if (!isInit) {
+ // BEGIN android-changed
+ throwNotInitialized();
+ // END android-changed
+ }
+ return implSpi.engineGetCertificateAlias(cert);
+ }
+
+ /**
+ * Writes this {@code KeyStore} to the specified {@code OutputStream}. The
+ * data written to the {@code OutputStream} is protected by the specified
+ * password.
+ *
+ * @param stream
+ * the {@code OutputStream} to write the store's data to.
+ * @param password
+ * the password to protect the data.
+ * @throws KeyStoreException
+ * if this {@code KeyStore} is not initialized.
+ * @throws IOException
+ * if a problem occurred while writing to the stream.
+ * @throws NoSuchAlgorithmException
+ * if the required algorithm is not available.
+ * @throws CertificateException
+ * if an exception occurred while storing the certificates of
+ * this {@code KeyStore}.
+ */
+ public final void store(OutputStream stream, char[] password)
+ throws KeyStoreException, IOException, NoSuchAlgorithmException,
+ CertificateException {
+ if (!isInit) {
+ // BEGIN android-changed
+ throwNotInitialized();
+ // END android-changed
+ }
+
+ //Just delegate stream and password to implSpi
+ implSpi.engineStore(stream, password);
+ }
+
+ /**
+ * Stores this {@code KeyStore} using the specified {@code
+ * LoadStoreParameter}.
+ *
+ * @param param
+ * the {@code LoadStoreParameter} that specifies how to store
+ * this {@code KeyStore}, maybe {@code null}.
+ * @throws KeyStoreException
+ * if this {@code KeyStore} is not initialized.
+ * @throws IOException
+ * if a problem occurred while writing to the stream.
+ * @throws NoSuchAlgorithmException
+ * if the required algorithm is not available.
+ * @throws CertificateException
+ * if an exception occurred while storing the certificates of
+ * this {@code KeyStore}.
+ * @throws IllegalArgumentException
+ * if the given {@link LoadStoreParameter} is not recognized.
+ */
+ public final void store(LoadStoreParameter param) throws KeyStoreException,
+ IOException, NoSuchAlgorithmException, CertificateException {
+ if (!isInit) {
+ // BEGIN android-changed
+ throwNotInitialized();
+ // END android-changed
+ }
+ implSpi.engineStore(param);
+ }
+
+ /**
+ * Initializes this {@code KeyStore} from the provided {@code InputStream}.
+ * Pass {@code null} as the {@code stream} argument to initialize an empty
+ * {@code KeyStore} or to initialize a {@code KeyStore} which does not rely
+ * on an {@code InputStream}. This {@code KeyStore} utilizes the given
+ * password to verify the stored data.
+ *
+ * @param stream
+ * the {@code InputStream} to load this {@code KeyStore}'s data
+ * from or {@code null}.
+ * @param password
+ * the password to verify the stored data, maybe {@code null}.
+ * @throws IOException
+ * if a problem occurred while reading from the stream.
+ * @throws NoSuchAlgorithmException
+ * if the required algorithm is not available.
+ * @throws CertificateException
+ * if an exception occurred while loading the certificates of
+ * this {@code KeyStore}.
+ */
+ public final void load(InputStream stream, char[] password)
+ throws IOException, NoSuchAlgorithmException, CertificateException {
+ implSpi.engineLoad(stream, password);
+ isInit = true;
+ }
+
+ /**
+ * Loads this {@code KeyStore} using the specified {@code
+ * LoadStoreParameter}.
+ *
+ * @param param
+ * the {@code LoadStoreParameter} that specifies how to load this
+ * {@code KeyStore}, maybe {@code null}.
+ * @throws IOException
+ * if a problem occurred while reading from the stream.
+ * @throws NoSuchAlgorithmException
+ * if the required algorithm is not available.
+ * @throws CertificateException
+ * if an exception occurred while loading the certificates of
+ * this {@code KeyStore}.
+ * @throws IllegalArgumentException
+ * if the given {@link LoadStoreParameter} is not recognized.
+ */
+ public final void load(LoadStoreParameter param) throws IOException,
+ NoSuchAlgorithmException, CertificateException {
+ implSpi.engineLoad(param);
+ isInit = true;
+ }
+
+ /**
+ * Returns the {@code Entry} with the given alias, using the specified
+ * {@code ProtectionParameter}.
+ *
+ * @param alias
+ * the alias of the requested entry.
+ * @param param
+ * the {@code ProtectionParameter} used to protect the requested
+ * entry, maybe {@code null}.
+ * @return he {@code Entry} with the given alias, using the specified
+ * {@code ProtectionParameter}.
+ * @throws NoSuchAlgorithmException
+ * if the required algorithm is not available.
+ * @throws UnrecoverableEntryException
+ * if the entry can not be recovered.
+ * @throws KeyStoreException
+ * if this {@code KeyStore} is not initialized.
+ * @throws NullPointerException
+ * if {@code alias} is {@code null}.
+ */
+ public final Entry getEntry(String alias, ProtectionParameter param)
+ throws NoSuchAlgorithmException, UnrecoverableEntryException,
+ KeyStoreException {
+ if (alias == null) {
+ throw new NullPointerException(Messages.getString("security.3F")); //$NON-NLS-1$
+ }
+ if (!isInit) {
+ // BEGIN android-changed
+ throwNotInitialized();
+ // END android-changed
+ }
+ return implSpi.engineGetEntry(alias, param);
+ }
+
+ /**
+ * Stores the given {@code Entry} in this {@code KeyStore} and associates
+ * the entry with the given {@code alias}. The entry is protected by the
+ * specified {@code ProtectionParameter}.
+ * <p>
+ * If the specified alias already exists, it will be reassigned.
+ *
+ * @param alias
+ * the alias for the entry.
+ * @param entry
+ * the entry to store.
+ * @param param
+ * the {@code ProtectionParameter} to protect the entry.
+ * @throws KeyStoreException
+ * if this {@code KeyStore} is not initialized.
+ * @throws NullPointerException
+ * if {@code alias} is {@code null} or {@code entry} is {@code
+ * null}.
+ */
+ public final void setEntry(String alias, Entry entry,
+ ProtectionParameter param) throws KeyStoreException {
+ if (!isInit) {
+ // BEGIN android-changed
+ throwNotInitialized();
+ // END android-changed
+ }
+ if (alias == null) {
+ throw new NullPointerException(Messages.getString("security.3F")); //$NON-NLS-1$
+ }
+ if (entry == null) {
+ throw new NullPointerException(Messages.getString("security.39")); //$NON-NLS-1$
+ }
+ implSpi.engineSetEntry(alias, entry, param);
+ }
+
+ /**
+ * Indicates whether the entry for the given alias is assignable to the
+ * provided {@code Class}.
+ *
+ * @param alias
+ * the alias for the entry.
+ * @param entryClass
+ * the type of the entry.
+ * @return {@code true} if the {@code Entry} for the alias is assignable to
+ * the specified {@code entryClass}.
+ * @throws KeyStoreException
+ * if this {@code KeyStore} is not initialized.
+ */
+ public final boolean entryInstanceOf(String alias,
+ Class<? extends KeyStore.Entry> entryClass)
+ throws KeyStoreException {
+ if (alias == null) {
+ throw new NullPointerException(Messages.getString("security.3F")); //$NON-NLS-1$
+ }
+ if (entryClass == null) {
+ throw new NullPointerException(Messages.getString("security.40")); //$NON-NLS-1$
+ }
+
+ if (!isInit) {
+ // BEGIN android-changed
+ throwNotInitialized();
+ // END android-changed
+ }
+ return implSpi.engineEntryInstanceOf(alias, entryClass);
+ }
+
+ /**
+ * {@code Builder} is used to construct new instances of {@code KeyStore}.
+ */
+ public abstract static class Builder {
+ /**
+ * Constructs a new instance of {@code Builder}.
+ */
+ protected Builder() {
+ }
+
+ /**
+ * Returns the {@code KeyStore} created by this {@code Builder}.
+ *
+ * @return the {@code KeyStore} created by this {@code Builder}.
+ * @throws KeyStoreException
+ * if an error occurred during construction.
+ */
+ public abstract KeyStore getKeyStore() throws KeyStoreException;
+
+ /**
+ * Returns the {@code ProtectionParameter} to be used when a {@code
+ * Entry} with the specified alias is requested. Before this method is
+ * invoked, {@link #getKeyStore()} must be called.
+ *
+ * @param alias
+ * the alias for the entry.
+ * @return the {@code ProtectionParameter} to be used when a {@code
+ * Entry} with the specified alias is requested.
+ * @throws KeyStoreException
+ * if an error occurred during the lookup for the protection
+ * parameter.
+ * @throws IllegalStateException
+ * if {@link #getKeyStore()} is not called prior the
+ * invocation of this method.
+ * @throws NullPointerException
+ * if {@code alias} is {@code null}.
+ */
+ public abstract ProtectionParameter getProtectionParameter(String alias)
+ throws KeyStoreException;
+
+ /**
+ * Returns a new {@code Builder} that holds the given {@code KeyStore}
+ * and the given {@code ProtectionParameter}.
+ *
+ * @param keyStore
+ * the {@code KeyStore} to be held.
+ * @param protectionParameter
+ * the {@code ProtectionParameter} to be held.
+ * @return a new instance of {@code Builder} that holds the specified
+ * {@code KeyStore} and the specified {@code
+ * ProtectionParameter}.
+ * @throws NullPointerException
+ * if {@code keyStore} or {@code protectionParameter} is
+ * {@code null}.
+ * @throws IllegalArgumentException
+ * if the given {@code KeyStore} is not initialized.
+ */
+ public static Builder newInstance(KeyStore keyStore,
+ ProtectionParameter protectionParameter) {
+ if (keyStore == null) {
+ throw new NullPointerException(Messages.getString("security.41")); //$NON-NLS-1$
+ }
+ if (protectionParameter == null) {
+ throw new NullPointerException(Messages.getString("security.42")); //$NON-NLS-1$
+ }
+
+ if (!keyStore.isInit) {
+ throw new IllegalArgumentException(NOTINITKEYSTORE);
+ }
+ return new BuilderImpl(keyStore, protectionParameter,
+ null, null, null, null);
+ }
+
+ /**
+ * Returns a new {@code Builder} that creates a new {@code KeyStore}
+ * based on the provided arguments.
+ * <p>
+ * If {@code provider} is {@code null}, all installed providers are
+ * searched, otherwise the key store from the specified provider is
+ * used.
+ *
+ * @param type
+ * the type of the {@code KeyStore} to be constructed.
+ * @param provider
+ * the provider of the {@code KeyStore} to be constructed,
+ * maybe {@code null}.
+ * @param file
+ * the {@code File} that contains the data for the {@code
+ * KeyStore}.
+ * @param protectionParameter
+ * the {@code ProtectionParameter} used to protect the stored
+ * keys.
+ * @return a new {@code Builder} that creates a new {@code KeyStore}
+ * based on the provided arguments.
+ * @throws NullPointerException
+ * if {@code type, protectionParameter} or {@code file} is
+ * {@code null}.
+ * @throws IllegalArgumentException
+ * {@code protectionParameter} not an instance of either
+ * {@code PasswordProtection} or {@code
+ * CallbackHandlerProtection}, {@code file} is not a file or
+ * does not exist at all.
+ */
+ public static Builder newInstance(String type, Provider provider,
+ File file, ProtectionParameter protectionParameter) {
+ // check null parameters
+ if (type == null) {
+ throw new NullPointerException(Messages.getString("security.07")); //$NON-NLS-1$
+ }
+ if (protectionParameter == null) {
+ throw new NullPointerException(Messages.getString("security.42")); //$NON-NLS-1$
+ }
+ if (file == null) {
+ throw new NullPointerException(Messages.getString("security.43")); //$NON-NLS-1$
+ }
+ // protection parameter should be PasswordProtection or
+ // CallbackHandlerProtection
+ if (!(protectionParameter instanceof PasswordProtection)
+ && !(protectionParameter instanceof CallbackHandlerProtection)) {
+ throw new IllegalArgumentException(Messages.getString("security.35")); //$NON-NLS-1$
+ }
+ // check file parameter
+ if (!file.exists()) {
+ throw new IllegalArgumentException(Messages.getString("security.44", file.getName())); //$NON-NLS-1$
+ }
+ if (!file.isFile()) {
+ throw new IllegalArgumentException(Messages.getString("security.45", file.getName())); //$NON-NLS-1$
+ }
+ // create new instance
+ return new BuilderImpl(null, protectionParameter, file,
+ type, provider, AccessController.getContext());
+ }
+
+ /**
+ * Returns a new {@code Builder} that creates a new {@code KeyStore}
+ * based on the provided arguments.
+ * <p>
+ * If {@code provider} is {@code null}, all installed providers are
+ * searched, otherwise the key store from the specified provider is
+ * used.
+ *
+ * @param type
+ * the type of the {@code KeyStore} to be constructed.
+ * @param provider
+ * the provider of the {@code KeyStore} to be constructed,
+ * maybe {@code null}.
+ * @param protectionParameter
+ * the {@code ProtectionParameter} used to protect the stored
+ * keys.
+ * @return a new {@code Builder} that creates a new {@code KeyStore}
+ * based on the provided arguments.
+ * @throws NullPointerException
+ * if {@code type} or {@code protectionParameter} is {@code
+ * null}.
+ * @throws IllegalArgumentException
+ * {@code protectionParameter} not an instance of either
+ * {@code PasswordProtection} or {@code
+ * CallbackHandlerProtection}, {@code file} is not a file or
+ * does not exist at all.
+ */
+ public static Builder newInstance(String type, Provider provider,
+ ProtectionParameter protectionParameter) {
+ if (type == null) {
+ throw new NullPointerException(Messages.getString("security.07")); //$NON-NLS-1$
+ }
+ if (protectionParameter == null) {
+ throw new NullPointerException(Messages.getString("security.42")); //$NON-NLS-1$
+ }
+ return new BuilderImpl(null, protectionParameter, null,
+ type, provider, AccessController.getContext());
+ }
+
+ /*
+ * This class is implementation of abstract class KeyStore.Builder
+ *
+ * @author Vera Petrashkova
+ *
+ */
+ private static class BuilderImpl extends Builder {
+ // Store used KeyStore
+ private KeyStore keyStore;
+
+ // Store used ProtectionParameter
+ private ProtectionParameter protParameter;
+
+ // Store used KeyStore type
+ private final String typeForKeyStore;
+
+ // Store used KeyStore provider
+ private final Provider providerForKeyStore;
+
+ // Store used file for KeyStore loading
+ private final File fileForLoad;
+
+ // Store getKeyStore method was invoked or not for KeyStoreBuilder
+ private boolean isGetKeyStore = false;
+
+ // Store last Exception in getKeyStore()
+ private KeyStoreException lastException;
+
+ // Store AccessControlContext which is used in getKeyStore() method
+ private final AccessControlContext accControlContext;
+
+ //
+ // Constructor BuilderImpl initializes private fields: keyStore,
+ // protParameter, typeForKeyStore providerForKeyStore fileForLoad,
+ // isGetKeyStore
+ //
+ BuilderImpl(KeyStore ks, ProtectionParameter pp, File file,
+ String type, Provider provider, AccessControlContext context) {
+ super();
+ keyStore = ks;
+ protParameter = pp;
+ fileForLoad = file;
+ typeForKeyStore = type;
+ providerForKeyStore = provider;
+ isGetKeyStore = false;
+ lastException = null;
+ accControlContext = context;
+ }
+
+ //
+ // Implementation of abstract getKeyStore() method If
+ // KeyStoreBuilder encapsulates KeyStore object then this object is
+ // returned
+ //
+ // If KeyStoreBuilder encapsulates KeyStore type and provider then
+ // KeyStore is created using these parameters. If KeyStoreBuilder
+ // encapsulates file and ProtectionParameter then KeyStore data are
+ // loaded from FileInputStream that is created on file. If file is
+ // not defined then KeyStore object is initialized with null
+ // InputStream and null password.
+ //
+ // Result KeyStore object is returned.
+ //
+ @Override
+ public synchronized KeyStore getKeyStore() throws KeyStoreException {
+ // If KeyStore was created but in final block some exception was
+ // thrown
+ // then it was stored in lastException variable and will be
+ // thrown
+ // all subsequent calls of this method.
+ if (lastException != null) {
+ throw lastException;
+ }
+ if (keyStore != null) {
+ isGetKeyStore = true;
+ return keyStore;
+ }
+
+ try {
+ final KeyStore ks;
+ final char[] passwd;
+
+ // get KeyStore instance using type or type and provider
+ ks = (providerForKeyStore == null ? KeyStore
+ .getInstance(typeForKeyStore) : KeyStore
+ .getInstance(typeForKeyStore, providerForKeyStore));
+ // protection parameter should be PasswordProtection
+ // or CallbackHandlerProtection
+ if (protParameter instanceof PasswordProtection) {
+ passwd = ((PasswordProtection) protParameter)
+ .getPassword();
+ } else if (protParameter instanceof CallbackHandlerProtection) {
+ passwd = KeyStoreSpi
+ .getPasswordFromCallBack(protParameter);
+ } else {
+ throw new KeyStoreException(Messages.getString("security.35")); //$NON-NLS-1$
+ }
+
+ // load KeyStore from file
+ AccessController.doPrivileged(
+ new PrivilegedExceptionAction<Object>() {
+ public Object run() throws Exception {
+ if (fileForLoad != null) {
+ FileInputStream fis = null;
+ try {
+ fis = new FileInputStream(fileForLoad);
+ ks.load(fis, passwd);
+ } finally {
+ // close file input stream
+ if( fis != null ) {
+ fis.close();
+ }
+ }
+ } else {
+ ks.load(new TmpLSParameter(
+ protParameter));
+ }
+ return null;
+ }
+ }, accControlContext);
+
+
+ isGetKeyStore = true;
+ return ks;
+ } catch (KeyStoreException e) {
+ // Store exception
+ throw lastException = e;
+ } catch (Exception e) {
+ // Override exception
+ throw lastException = new KeyStoreException(e);
+ }
+ }
+
+ //
+ // This is implementation of abstract method
+ // getProtectionParameter(String alias)
+ //
+ // Return: ProtectionParameter to get Entry which was saved in
+ // KeyStore with defined alias
+ //
+ @Override
+ public synchronized ProtectionParameter getProtectionParameter(
+ String alias) throws KeyStoreException {
+ if (alias == null) {
+ throw new NullPointerException(Messages.getString("security.3F")); //$NON-NLS-1$
+ }
+ if (!isGetKeyStore) {
+ throw new IllegalStateException(Messages.getString("security.46")); //$NON-NLS-1$
+ }
+ return protParameter;
+ }
+ }
+
+ /*
+ * Implementation of LoadStoreParameter interface
+ */
+ private static class TmpLSParameter implements LoadStoreParameter {
+
+ // Store used protection parameter
+ private final ProtectionParameter protPar;
+
+ /**
+ * Creates TmpLoadStoreParameter object
+ * @param protPar protection parameter
+ */
+ public TmpLSParameter(ProtectionParameter protPar) {
+ this.protPar = protPar;
+ }
+
+ /**
+ * This method returns protection parameter
+ */
+ public ProtectionParameter getProtectionParameter() {
+ return protPar;
+ }
+ }
+ }
+
+ /**
+ * {@code CallbackHandlerProtection} is a {@code ProtectionParameter} that
+ * encapsulates a {@link CallbackHandler}.
+ */
+ public static class CallbackHandlerProtection implements
+ ProtectionParameter {
+ // Store CallbackHandler
+ private final CallbackHandler callbackHandler;
+
+ /**
+ * Constructs a new instance of {@code CallbackHandlerProtection} with
+ * the {@code CallbackHandler}.
+ *
+ * @param handler
+ * the {@code CallbackHandler}.
+ * @throws NullPointerException
+ * if {@code handler} is {@code null}.
+ */
+ public CallbackHandlerProtection(CallbackHandler handler) {
+ if (handler == null) {
+ throw new NullPointerException(Messages.getString("security.47")); //$NON-NLS-1$
+ }
+ this.callbackHandler = handler;
+ }
+
+ /**
+ * Returns the {@code CallbackHandler}.
+ *
+ * @return the {@code CallbackHandler}.
+ */
+ public CallbackHandler getCallbackHandler() {
+ return callbackHandler;
+ }
+ }
+
+ /**
+ * {@code Entry} is the common marker interface for a {@code KeyStore}
+ * entry.
+ */
+ public static interface Entry {
+ }
+
+ /**
+ * {@code LoadStoreParameter} represents a parameter that specifies how a
+ * {@code KeyStore} can be loaded and stored.
+ *
+ * @see KeyStore#load(LoadStoreParameter)
+ * @see KeyStore#store(LoadStoreParameter)
+ */
+ public static interface LoadStoreParameter {
+ /**
+ * Returns the {@code ProtectionParameter} which is used to protect data
+ * in the {@code KeyStore}.
+ *
+ * @return the {@code ProtectionParameter} which is used to protect data
+ * in the {@code KeyStore}, maybe {@code null}.
+ */
+ public ProtectionParameter getProtectionParameter();
+ }
+
+ /**
+ * {@code PasswordProtection} is a {@code ProtectionParameter} that protects
+ * a {@code KeyStore} using a password.
+ */
+ public static class PasswordProtection implements ProtectionParameter,
+ Destroyable {
+
+ // Store password
+ private char[] password;
+
+ private boolean isDestroyed = false;
+
+ /**
+ * Constructs a new instance of {@code PasswordProtection} with a
+ * password. A copy of the password is stored in the new {@code
+ * PasswordProtection} object.
+ *
+ * @param password
+ * the password, maybe {@code null}.
+ */
+ public PasswordProtection(char[] password) {
+ if (password != null) {
+ this.password = password.clone();
+ }
+ }
+
+ /**
+ * Returns the password.
+ *
+ * @return the password.
+ * @throws IllegalStateException
+ * if the password has been destroyed.
+ */
+ public synchronized char[] getPassword() {
+ if (isDestroyed) {
+ throw new IllegalStateException(Messages.getString("security.36")); //$NON-NLS-1$
+ }
+ return password;
+ }
+
+ /**
+ * Destroys / invalidates the password.
+ *
+ * @throws DestroyFailedException
+ * if the password could not be invalidated.
+ */
+ public synchronized void destroy() throws DestroyFailedException {
+ isDestroyed = true;
+ if (password != null) {
+ Arrays.fill(password, '\u0000');
+ password = null;
+ }
+ }
+
+ /**
+ * Indicates whether the password is invalidated.
+ *
+ * @return {@code true} if the password is invalidated, {@code false}
+ * otherwise.
+ */
+ public synchronized boolean isDestroyed() {
+ return isDestroyed;
+ }
+ }
+
+ /**
+ * {@code ProtectionParameter} is a marker interface for protection
+ * parameters. A protection parameter is used to protect the content of a
+ * {@code KeyStore}.
+ */
+ public static interface ProtectionParameter {
+ }
+
+ /**
+ * {@code PrivateKeyEntry} represents a {@code KeyStore} entry that
+ * holds a private key.
+ */
+ public static final class PrivateKeyEntry implements Entry {
+ // Store Certificate chain
+ private Certificate[] chain;
+
+ // Store PrivateKey
+ private PrivateKey privateKey;
+
+ /**
+ * Constructs a new instance of {@code PrivateKeyEntry} with the given
+ * {@code PrivateKey} and the provided certificate chain.
+ *
+ * @param privateKey
+ * the private key.
+ * @param chain
+ * the ordered certificate chain with the certificate
+ * corresponding to the private key at index 0.
+ * @throws NullPointerException
+ * if {@code privateKey} or {@code chain} is {@code null}.
+ * @throws IllegalArgumentException
+ * if {@code chain.length == 0}, the algorithm of the
+ * private key does not match the algorithm of the public
+ * key of the first certificate or the certificates are not
+ * all of the same type.
+ */
+ public PrivateKeyEntry(PrivateKey privateKey, Certificate[] chain) {
+ if (privateKey == null) {
+ throw new NullPointerException(Messages.getString("security.48")); //$NON-NLS-1$
+ }
+ if (chain == null) {
+ throw new NullPointerException(Messages.getString("security.49")); //$NON-NLS-1$
+ }
+
+ if (chain.length == 0) {
+ throw new IllegalArgumentException(Messages.getString("security.4A")); //$NON-NLS-1$
+ }
+ // Match algorithm of private key and algorithm of public key from
+ // the end certificate
+ String s = chain[0].getType();
+ if (!(chain[0].getPublicKey().getAlgorithm()).equals(privateKey
+ .getAlgorithm())) {
+ throw new IllegalArgumentException(Messages.getString("security.4B")); //$NON-NLS-1$
+ }
+ // Match certificate types
+ for (int i = 1; i < chain.length; i++) {
+ if (!s.equals(chain[i].getType())) {
+ throw new IllegalArgumentException(
+ Messages.getString("security.4C")); //$NON-NLS-1$
+ }
+ }
+ // clone chain - this.chain = (Certificate[])chain.clone();
+ boolean isAllX509Certificates = true;
+ // assert chain length > 0
+ for(Certificate cert: chain){
+ if(!(cert instanceof X509Certificate)){
+ isAllX509Certificates = false;
+ break;
+ }
+ }
+
+ if(isAllX509Certificates){
+ this.chain = new X509Certificate[chain.length];
+ }
+ else{
+ this.chain = new Certificate[chain.length];
+ }
+ System.arraycopy(chain, 0, this.chain, 0, chain.length);
+ this.privateKey = privateKey;
+ }
+
+ /**
+ * Returns the private key.
+ *
+ * @return the private key.
+ */
+ public PrivateKey getPrivateKey() {
+ return privateKey;
+ }
+
+ /**
+ * Returns the certificate chain.
+ *
+ * @return the certificate chain.
+ */
+ public Certificate[] getCertificateChain() {
+ return chain.clone();
+ }
+
+ /**
+ * Returns the certificate corresponding to the private key.
+ *
+ * @return the certificate corresponding to the private key.
+ */
+ public Certificate getCertificate() {
+ return chain[0];
+ }
+
+ /**
+ * Returns a string containing a concise, human-readable description of
+ * this {@code PrivateKeyEntry}.
+ *
+ * @return a printable representation for this {@code PrivateKeyEntry}.
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(
+ "PrivateKeyEntry: number of elements in certificate chain is "); //$NON-NLS-1$
+ sb.append(Integer.toString(chain.length));
+ sb.append("\n"); //$NON-NLS-1$
+ for (int i = 0; i < chain.length; i++) {
+ sb.append(chain[i].toString());
+ sb.append("\n"); //$NON-NLS-1$
+ }
+ return sb.toString();
+ }
+ }
+
+ /**
+ * {@code SecretKeyEntry} represents a {@code KeyStore} entry that
+ * holds a secret key.
+ */
+ public static final class SecretKeyEntry implements Entry {
+
+ // Store SecretKey
+ private final SecretKey secretKey;
+
+ /**
+ * Constructs a new instance of {@code SecretKeyEntry} with the given
+ * {@code SecretKey}.
+ *
+ * @param secretKey
+ * the secret key.
+ * @throws NullPointerException
+ * if {@code secretKey} is {@code null}.
+ */
+ public SecretKeyEntry(SecretKey secretKey) {
+ if (secretKey == null) {
+ throw new NullPointerException(Messages.getString("security.4D")); //$NON-NLS-1$
+ }
+ this.secretKey = secretKey;
+ }
+
+ /**
+ * Returns the secret key.
+ *
+ * @return the secret key.
+ */
+ public SecretKey getSecretKey() {
+ return secretKey;
+ }
+
+ /**
+ * Returns a string containing a concise, human-readable description of
+ * this {@code SecretKeyEntry}.
+ *
+ * @return a printable representation for this {@code
+ * SecretKeyEntry}.
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("SecretKeyEntry: algorithm - "); //$NON-NLS-1$
+ sb.append(secretKey.getAlgorithm());
+ return sb.toString();
+ }
+ }
+
+ /**
+ * {@code TrustedCertificateEntry} represents a {@code KeyStore} entry that
+ * holds a trusted certificate.
+ */
+ public static final class TrustedCertificateEntry implements Entry {
+
+ // Store trusted Certificate
+ private final Certificate trustCertificate;
+
+ /**
+ * Constructs a new instance of {@code TrustedCertificateEntry} with the
+ * given {@code Certificate}.
+ *
+ * @param trustCertificate
+ * the trusted certificate.
+ * @throws NullPointerException
+ * if {@code trustCertificate} is {@code null}.
+ */
+ public TrustedCertificateEntry(Certificate trustCertificate) {
+ if (trustCertificate == null) {
+ throw new NullPointerException(Messages.getString("security.4E")); //$NON-NLS-1$
+ }
+ this.trustCertificate = trustCertificate;
+ }
+
+ /**
+ * Returns the trusted certificate.
+ *
+ * @return the trusted certificate.
+ */
+ public Certificate getTrustedCertificate() {
+ return trustCertificate;
+ }
+
+ /**
+ * Returns a string containing a concise, human-readable description of
+ * this {@code TrustedCertificateEntry}.
+ *
+ * @return a printable representation for this {@code
+ * TrustedCertificateEntry}.
+ */
+ @Override
+ public String toString() {
+ return "Trusted certificate entry:\n" + trustCertificate; //$NON-NLS-1$
+ }
+ }
+}
diff --git a/luni/src/main/java/java/security/KeyStoreException.java b/luni/src/main/java/java/security/KeyStoreException.java
new file mode 100644
index 0000000..4327f7f
--- /dev/null
+++ b/luni/src/main/java/java/security/KeyStoreException.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * {@code KeyStoreException} is a general {@code KeyStore} exception.
+ *
+ * @see KeyStore
+ */
+public class KeyStoreException extends GeneralSecurityException {
+
+ private static final long serialVersionUID = -1119353179322377262L;
+
+ /**
+ * Constructs a new instance of {@code KeyStoreException} with the
+ * given message.
+ *
+ * @param msg
+ * the detail message for this exception.
+ */
+ public KeyStoreException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs a new instance of {@code KeyStoreException}.
+ */
+ public KeyStoreException() {
+ }
+
+ /**
+ * Constructs a new instance of {@code KeyStoreException} with the
+ * given message and the cause.
+ *
+ * @param message
+ * the detail message for this exception.
+ * @param cause
+ * the exception which is the cause for this exception.
+ */
+ public KeyStoreException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructs a new instance of {@code KeyStoreException} with the
+ * cause.
+ *
+ * @param cause
+ * the exception which is the cause for this exception.
+ */
+ public KeyStoreException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/luni/src/main/java/java/security/KeyStoreSpi.java b/luni/src/main/java/java/security/KeyStoreSpi.java
new file mode 100644
index 0000000..e884123
--- /dev/null
+++ b/luni/src/main/java/java/security/KeyStoreSpi.java
@@ -0,0 +1,536 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.util.Date;
+import java.util.Enumeration;
+import javax.crypto.SecretKey;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.PasswordCallback;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * {@code KeyStoreSpi} is the Service Provider Interface (SPI) definition for
+ * {@link KeyStore}.
+ *
+ * @see KeyStore
+ */
+public abstract class KeyStoreSpi {
+
+ /**
+ * Returns the key with the given alias, using the password to recover the
+ * key from the store.
+ *
+ * @param alias
+ * the alias for the entry.
+ * @param password
+ * the password used to recover the key.
+ * @return the key with the specified alias, or {@code null} if the
+ * specified alias is not bound to an entry.
+ * @throws NoSuchAlgorithmException
+ * if the algorithm for recovering the key is not available.
+ * @throws UnrecoverableKeyException
+ * if the key can not be recovered.
+ */
+ public abstract Key engineGetKey(String alias, char[] password)
+ throws NoSuchAlgorithmException, UnrecoverableKeyException;
+
+ /**
+ * Returns the certificate chain for the entry with the given alias.
+ *
+ * @param alias
+ * the alias for the entry
+ * @return the certificate chain for the entry with the given alias, or
+ * {@code null} if the specified alias is not bound to an entry.
+ */
+ public abstract Certificate[] engineGetCertificateChain(String alias);
+
+ /**
+ * Returns the trusted certificate for the entry with the given alias.
+ *
+ * @param alias
+ * the alias for the entry.
+ * @return the trusted certificate for the entry with the given alias, or
+ * {@code null} if the specified alias is not bound to an entry.
+ */
+ public abstract Certificate engineGetCertificate(String alias);
+
+ /**
+ * Returns the creation date of the entry with the given alias.
+ *
+ * @param alias
+ * the alias for the entry.
+ * @return the creation date, or {@code null} if the specified alias is not
+ * bound to an entry.
+ */
+ public abstract Date engineGetCreationDate(String alias);
+
+ /**
+ * Associates the given alias with the key, password and certificate chain.
+ * <p>
+ * If the specified alias already exists, it will be reassigned.
+ *
+ * @param alias
+ * the alias for the key.
+ * @param key
+ * the key.
+ * @param password
+ * the password.
+ * @param chain
+ * the certificate chain.
+ * @throws KeyStoreException
+ * if the specified key can not be protected, or if this
+ * operation fails for another reason.
+ * @throws IllegalArgumentException
+ * if {@code key} is a {@code PrivateKey} and {@code chain} does
+ * not contain any certificates.
+ */
+ public abstract void engineSetKeyEntry(String alias, Key key,
+ char[] password, Certificate[] chain) throws KeyStoreException;
+
+ /**
+ * Associates the given alias with a key and a certificate chain.
+ * <p>
+ * If the specified alias already exists, it will be reassigned.
+ *
+ * @param alias
+ * the alias for the key.
+ * @param key
+ * the key in an encoded format.
+ * @param chain
+ * the certificate chain.
+ * @throws KeyStoreException
+ * if this operation fails.
+ * @throws IllegalArgumentException
+ * if {@code key} is a {@code PrivateKey} and {@code chain}
+ * does.
+ */
+ public abstract void engineSetKeyEntry(String alias, byte[] key,
+ Certificate[] chain) throws KeyStoreException;
+
+ /**
+ * Associates the given alias with a certificate.
+ * <p>
+ * If the specified alias already exists, it will be reassigned.
+ *
+ * @param alias
+ * the alias for the certificate.
+ * @param cert
+ * the certificate.
+ * @throws KeyStoreException
+ * if an existing alias is not associated to an entry containing
+ * a trusted certificate, or this method fails for any other
+ * reason.
+ */
+ public abstract void engineSetCertificateEntry(String alias,
+ Certificate cert) throws KeyStoreException;
+
+ /**
+ * Deletes the entry identified with the given alias from this {@code
+ * KeyStoreSpi}.
+ *
+ * @param alias
+ * the alias for the entry.
+ * @throws KeyStoreException
+ * if the entry can not be deleted.
+ */
+ public abstract void engineDeleteEntry(String alias)
+ throws KeyStoreException;
+
+ /**
+ * Returns an {@code Enumeration} over all alias names stored in this
+ * {@code KeyStoreSpi}.
+ *
+ * @return an {@code Enumeration} over all alias names stored in this
+ * {@code KeyStoreSpi}.
+ */
+ public abstract Enumeration<String> engineAliases();
+
+ /**
+ * Indicates whether the given alias is present in this {@code KeyStoreSpi}.
+ *
+ * @param alias
+ * the alias of an entry.
+ * @return {@code true} if the alias exists, {@code false} otherwise.
+ */
+ public abstract boolean engineContainsAlias(String alias);
+
+ /**
+ * Returns the number of entries stored in this {@code KeyStoreSpi}.
+ *
+ * @return the number of entries stored in this {@code KeyStoreSpi}.
+ */
+ public abstract int engineSize();
+
+ /**
+ * Indicates whether the specified alias is associated with either a
+ * {@link KeyStore.PrivateKeyEntry} or a {@link KeyStore.SecretKeyEntry}.
+ *
+ * @param alias
+ * the alias of an entry.
+ * @return {@code true} if the given alias is associated with a key entry.
+ */
+ public abstract boolean engineIsKeyEntry(String alias);
+
+ /**
+ * Indicates whether the specified alias is associated with a
+ * {@link KeyStore.TrustedCertificateEntry}.
+ *
+ * @param alias
+ * the alias of an entry.
+ * @return {@code true} if the given alias is associated with a certificate
+ * entry.
+ */
+ public abstract boolean engineIsCertificateEntry(String alias);
+
+ /**
+ * Returns the alias associated with the first entry whose certificate
+ * matches the specified certificate.
+ *
+ * @param cert
+ * the certificate to find the associated entry's alias for.
+ * @return the alias or {@code null} if no entry with the specified
+ * certificate can be found.
+ */
+ public abstract String engineGetCertificateAlias(Certificate cert);
+
+ /**
+ * Writes this {@code KeyStoreSpi} to the specified {@code OutputStream}.
+ * The data written to the {@code OutputStream} is protected by the
+ * specified password.
+ *
+ * @param stream
+ * the {@code OutputStream} to write the store's data to.
+ * @param password
+ * the password to protect the data.
+ * @throws IOException
+ * if a problem occurred while writing to the stream.
+ * @throws NoSuchAlgorithmException
+ * if the required algorithm is not available.
+ * @throws CertificateException
+ * if the an exception occurred while storing the certificates
+ * of this code {@code KeyStoreSpi}.
+ */
+ public abstract void engineStore(OutputStream stream, char[] password)
+ throws IOException, NoSuchAlgorithmException, CertificateException;
+
+ /**
+ * Stores this {@code KeyStoreSpi} using the specified {@code
+ * LoadStoreParameter}.
+ *
+ * @param param
+ * the {@code LoadStoreParameter} that specifies how to store
+ * this {@code KeyStoreSpi}, maybe {@code null}.
+ * @throws IOException
+ * if a problem occurred while writing to the stream.
+ * @throws NoSuchAlgorithmException
+ * if the required algorithm is not available.
+ * @throws CertificateException
+ * if the an exception occurred while storing the certificates
+ * of this code {@code KeyStoreSpi}.
+ * @throws IllegalArgumentException
+ * if the given {@link KeyStore.LoadStoreParameter} is not
+ * recognized.
+ */
+ public void engineStore(KeyStore.LoadStoreParameter param)
+ throws IOException, NoSuchAlgorithmException, CertificateException {
+ throw new UnsupportedOperationException(Messages.getString("security.33")); //$NON-NLS-1$
+ }
+
+ /**
+ * Loads this {@code KeyStoreSpi} from the given {@code InputStream}.
+ * Utilizes the given password to verify the stored data.
+ *
+ * @param stream
+ * the {@code InputStream} to load this {@code KeyStoreSpi}'s
+ * data from.
+ * @param password
+ * the password to verify the stored data, maybe {@code null}.
+ * @throws IOException
+ * if a problem occurred while reading from the stream.
+ * @throws NoSuchAlgorithmException
+ * if the required algorithm is not available.
+ * @throws CertificateException
+ * if the an exception occurred while loading the certificates
+ * of this code {@code KeyStoreSpi}.
+ */
+ public abstract void engineLoad(InputStream stream, char[] password)
+ throws IOException, NoSuchAlgorithmException, CertificateException;
+
+ /**
+ * Loads this {@code KeyStoreSpi} using the specified {@code
+ * LoadStoreParameter}.
+ *
+ * @param param
+ * the {@code LoadStoreParameter} that specifies how to load this
+ * {@code KeyStoreSpi}, maybe {@code null}.
+ * @throws IOException
+ * if a problem occurred while reading from the stream.
+ * @throws NoSuchAlgorithmException
+ * if the required algorithm is not available.
+ * @throws CertificateException
+ * if the an exception occurred while loading the certificates
+ * of this code {@code KeyStoreSpi}.
+ * @throws IllegalArgumentException
+ * if the given {@link KeyStore.LoadStoreParameter} is not
+ * recognized.
+ */
+ public void engineLoad(KeyStore.LoadStoreParameter param)
+ throws IOException, NoSuchAlgorithmException, CertificateException {
+ if (param == null) {
+ engineLoad(null, null);
+ return;
+ }
+ char[] pwd;
+ KeyStore.ProtectionParameter pp = param.getProtectionParameter();
+ if (pp instanceof KeyStore.PasswordProtection) {
+ try {
+ pwd = ((KeyStore.PasswordProtection) pp).getPassword();
+ engineLoad(null, pwd);
+ return;
+ } catch (IllegalStateException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+ if (pp instanceof KeyStore.CallbackHandlerProtection) {
+ try {
+ pwd = getPasswordFromCallBack(pp);
+ engineLoad(null, pwd);
+ return;
+ } catch (UnrecoverableEntryException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+ throw new UnsupportedOperationException(
+ Messages.getString("security.35")); //$NON-NLS-1$
+ }
+
+ /**
+ * Returns the {@code Entry} with the given alias, using the specified
+ * {@code ProtectionParameter}.
+ *
+ * @param alias
+ * the alias of the requested entry.
+ * @param protParam
+ * the {@code ProtectionParameter}, used to protect the requested
+ * entry, maybe {@code null}.
+ * @return he {@code Entry} with the given alias, using the specified
+ * {@code ProtectionParameter}.
+ * @throws NoSuchAlgorithmException
+ * if the required algorithm is not available.
+ * @throws UnrecoverableEntryException
+ * if the entry can not be recovered.
+ * @throws KeyStoreException
+ * if this operation fails
+ */
+ public KeyStore.Entry engineGetEntry(String alias,
+ KeyStore.ProtectionParameter protParam) throws KeyStoreException,
+ NoSuchAlgorithmException, UnrecoverableEntryException {
+ if (!engineContainsAlias(alias)) {
+ return null;
+ }
+ if (engineIsCertificateEntry(alias)) {
+ return new KeyStore.TrustedCertificateEntry(
+ engineGetCertificate(alias));
+ }
+ char[] passW = null;
+ if (protParam != null) {
+ if (protParam instanceof KeyStore.PasswordProtection) {
+ try {
+ passW = ((KeyStore.PasswordProtection) protParam)
+ .getPassword();
+ } catch (IllegalStateException ee) {
+ throw new KeyStoreException(Messages.getString("security.36"), ee); //$NON-NLS-1$
+ }
+ } else if (protParam instanceof KeyStore.CallbackHandlerProtection) {
+ passW = getPasswordFromCallBack(protParam);
+ } else {
+ throw new UnrecoverableEntryException(
+ Messages.getString("security.37", //$NON-NLS-1$
+ protParam.toString()));
+ }
+ }
+ if (engineIsKeyEntry(alias)) {
+ try {
+ Key key = engineGetKey(alias, passW);
+ if (key instanceof PrivateKey) {
+ return new KeyStore.PrivateKeyEntry((PrivateKey) key,
+ engineGetCertificateChain(alias));
+ }
+ if (key instanceof SecretKey) {
+ return new KeyStore.SecretKeyEntry((SecretKey) key);
+ }
+ } catch (UnrecoverableKeyException e) {
+ throw new KeyStoreException(e);
+ }
+ }
+ throw new NoSuchAlgorithmException(Messages.getString("security.38")); //$NON-NLS-1$
+ }
+
+ /**
+ * Stores the given {@code Entry} in this {@code KeyStoreSpi} and associates
+ * the entry with the given {@code alias}. The entry is protected by the
+ * specified {@code ProtectionParameter}.
+ * <p>
+ * If the specified alias already exists, it will be reassigned.
+ *
+ * @param alias
+ * the alias for the entry.
+ * @param entry
+ * the entry to store.
+ * @param protParam
+ * the {@code ProtectionParameter} to protect the entry.
+ * @throws KeyStoreException
+ * if this operation fails.
+ */
+ public void engineSetEntry(String alias, KeyStore.Entry entry,
+ KeyStore.ProtectionParameter protParam) throws KeyStoreException {
+ if (entry == null) {
+ throw new KeyStoreException(Messages.getString("security.39")); //$NON-NLS-1$
+ }
+
+ if (engineContainsAlias(alias)) {
+ engineDeleteEntry(alias);
+ }
+
+ if (entry instanceof KeyStore.TrustedCertificateEntry) {
+ KeyStore.TrustedCertificateEntry trE = (KeyStore.TrustedCertificateEntry) entry;
+ engineSetCertificateEntry(alias, trE.getTrustedCertificate());
+ return;
+ }
+
+ char[] passW = null;
+ if (protParam instanceof KeyStore.PasswordProtection) {
+ try {
+ passW = ((KeyStore.PasswordProtection) protParam).getPassword();
+ } catch (IllegalStateException ee) {
+ throw new KeyStoreException(Messages.getString("security.36"), ee); //$NON-NLS-1$
+ }
+ } else {
+ if (protParam instanceof KeyStore.CallbackHandlerProtection) {
+ try {
+ passW = getPasswordFromCallBack(protParam);
+ } catch (Exception e) {
+ throw new KeyStoreException(e);
+ }
+ } else {
+ throw new KeyStoreException(
+ Messages.getString("security.3A")); //$NON-NLS-1$
+ }
+ }
+
+ if (entry instanceof KeyStore.PrivateKeyEntry) {
+ KeyStore.PrivateKeyEntry prE = (KeyStore.PrivateKeyEntry) entry;
+ engineSetKeyEntry(alias, prE.getPrivateKey(), passW, prE
+ .getCertificateChain());
+ return;
+ }
+
+ if (entry instanceof KeyStore.SecretKeyEntry) {
+ KeyStore.SecretKeyEntry skE = (KeyStore.SecretKeyEntry) entry;
+ engineSetKeyEntry(alias, skE.getSecretKey(), passW, null);
+ // engineSetKeyEntry(alias, skE.getSecretKey().getEncoded(), null);
+ return;
+ }
+
+ throw new KeyStoreException(
+ Messages.getString("security.3B", entry.toString())); //$NON-NLS-1$
+ }
+
+ /**
+ * Indicates whether the entry for the given alias is assignable to the
+ * provided {@code Class}.
+ *
+ * @param alias
+ * the alias for the entry.
+ * @param entryClass
+ * the type of the entry.
+ * @return {@code true} if the {@code Entry} for the alias is assignable to
+ * the specified {@code entryClass}.
+ */
+ public boolean engineEntryInstanceOf(String alias,
+ Class<? extends KeyStore.Entry> entryClass) {
+ if (!engineContainsAlias(alias)) {
+ return false;
+ }
+
+ try {
+ if (engineIsCertificateEntry(alias)) {
+ return entryClass
+ .isAssignableFrom(Class
+ .forName("java.security.KeyStore$TrustedCertificateEntry")); //$NON-NLS-1$
+ }
+
+ if (engineIsKeyEntry(alias)) {
+ if (entryClass.isAssignableFrom(Class
+ .forName("java.security.KeyStore$PrivateKeyEntry"))) { //$NON-NLS-1$
+ return engineGetCertificate(alias) != null;
+ }
+
+ if (entryClass.isAssignableFrom(Class
+ .forName("java.security.KeyStore$SecretKeyEntry"))) { //$NON-NLS-1$
+ return engineGetCertificate(alias) == null;
+ }
+ }
+ } catch (ClassNotFoundException ignore) {}
+
+ return false;
+ }
+
+ /*
+ * This method returns password which is encapsulated in
+ * CallbackHandlerProtection object If there is no implementation of
+ * CallbackHandler then this method returns null
+ */
+ static char[] getPasswordFromCallBack(KeyStore.ProtectionParameter protParam)
+ throws UnrecoverableEntryException {
+
+ if (protParam == null) {
+ return null;
+ }
+
+ if (!(protParam instanceof KeyStore.CallbackHandlerProtection)) {
+ throw new UnrecoverableEntryException(
+ Messages.getString("security.3C")); //$NON-NLS-1$
+ }
+
+ String clName = Security
+ .getProperty("auth.login.defaultCallbackHandler"); //$NON-NLS-1$
+ if (clName == null) {
+ throw new UnrecoverableEntryException(
+ Messages.getString("security.3D")); //$NON-NLS-1$
+
+ }
+
+ try {
+ Class<?> cl = Class.forName(clName);
+ CallbackHandler cbHand = (CallbackHandler) cl.newInstance();
+ PasswordCallback[] pwCb = { new PasswordCallback("password: ", true) }; //$NON-NLS-1$
+ cbHand.handle(pwCb);
+ return pwCb[0].getPassword();
+ } catch (Exception e) {
+ throw new UnrecoverableEntryException(e.toString());
+ }
+ }
+}
diff --git a/luni/src/main/java/java/security/MessageDigest.java b/luni/src/main/java/java/security/MessageDigest.java
new file mode 100644
index 0000000..6996054
--- /dev/null
+++ b/luni/src/main/java/java/security/MessageDigest.java
@@ -0,0 +1,425 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.nio.ByteBuffer;
+
+import org.apache.harmony.security.fortress.Engine;
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * {@code MessageDigest} is an engine class which is capable of generating one
+ * way hash values for arbitrary input, utilizing the algorithm it was
+ * initialized with.
+ *
+ * @see MessageDigestSpi
+ */
+public abstract class MessageDigest extends MessageDigestSpi {
+
+ // The service name
+ private static final String SERVICE = "MessageDigest"; //$NON-NLS-1$
+
+ // Used to access common engine functionality
+ private static Engine engine = new Engine(SERVICE);
+
+ // The provider
+ private Provider provider;
+
+ // The algorithm.
+ private String algorithm;
+
+ /**
+ * Constructs a new instance of {@code MessageDigest} with the name of
+ * the algorithm to use.
+ *
+ * @param algorithm
+ * the name of algorithm to use
+ */
+ protected MessageDigest(String algorithm) {
+ this.algorithm = algorithm;
+ }
+
+ /**
+ * Returns a new instance of {@code MessageDigest} that utilizes the
+ * specified algorithm.
+ *
+ * @param algorithm
+ * the name of the algorithm to use
+ * @return a new instance of {@code MessageDigest} that utilizes the
+ * specified algorithm
+ * @throws NoSuchAlgorithmException
+ * if the specified algorithm is not available
+ * @throws NullPointerException
+ * if {@code algorithm} is {@code null}
+ */
+ public static MessageDigest getInstance(String algorithm)
+ throws NoSuchAlgorithmException {
+ if (algorithm == null) {
+ throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+ }
+ MessageDigest result;
+ synchronized (engine) {
+ engine.getInstance(algorithm, null);
+ if (engine.spi instanceof MessageDigest) {
+ result = (MessageDigest) engine.spi;
+ result.algorithm = algorithm;
+ result.provider = engine.provider;
+ return result;
+ }
+ return new MessageDigestImpl((MessageDigestSpi) engine.spi,
+ engine.provider, algorithm);
+ }
+ }
+
+ /**
+ * Returns a new instance of {@code MessageDigest} that utilizes the
+ * specified algorithm from the specified provider.
+ *
+ * @param algorithm
+ * the name of the algorithm to use
+ * @param provider
+ * the name of the provider
+ * @return a new instance of {@code MessageDigest} that utilizes the
+ * specified algorithm from the specified provider
+ * @throws NoSuchAlgorithmException
+ * if the specified algorithm is not available
+ * @throws NoSuchProviderException
+ * if the specified provider is not available
+ * @throws NullPointerException
+ * if {@code algorithm} is {@code null}
+ */
+ public static MessageDigest getInstance(String algorithm, String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException {
+ if ((provider == null) || (provider.length() == 0)) {
+ throw new IllegalArgumentException(Messages
+ .getString("security.02")); //$NON-NLS-1$
+ }
+ Provider p = Security.getProvider(provider);
+ if (p == null) {
+ throw new NoSuchProviderException(Messages.getString(
+ "security.03", provider)); //$NON-NLS-1$
+ }
+ return getInstance(algorithm, p);
+ }
+
+ /**
+ * Returns a new instance of {@code MessageDigest} that utilizes the
+ * specified algorithm from the specified provider.
+ *
+ * @param algorithm
+ * the name of the algorithm to use
+ * @param provider
+ * the provider
+ * @return a new instance of {@code MessageDigest} that utilizes the
+ * specified algorithm from the specified provider
+ * @throws NoSuchAlgorithmException
+ * if the specified algorithm is not available
+ * @throws NullPointerException
+ * if {@code algorithm} is {@code null}
+ */
+ public static MessageDigest getInstance(String algorithm, Provider provider)
+ throws NoSuchAlgorithmException {
+ if (provider == null) {
+ throw new IllegalArgumentException(Messages
+ .getString("security.04")); //$NON-NLS-1$
+ }
+ if (algorithm == null) {
+ throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+ }
+ MessageDigest result;
+ synchronized (engine) {
+ engine.getInstance(algorithm, provider, null);
+ if (engine.spi instanceof MessageDigest) {
+ result = (MessageDigest) engine.spi;
+ result.algorithm = algorithm;
+ result.provider = provider;
+ return result;
+ }
+ result = new MessageDigestImpl((MessageDigestSpi) engine.spi,
+ provider, algorithm);
+ return result;
+ }
+ }
+
+ /**
+ * Puts this {@code MessageDigest} back in an initial state, such that it is
+ * ready to compute a one way hash value.
+ */
+ public void reset() {
+ engineReset();
+ }
+
+ /**
+ * Updates this {@code MessageDigest} using the given {@code byte}.
+ *
+ * @param arg0
+ * the {@code byte} to update this {@code MessageDigest} with
+ * @see #reset()
+ */
+ public void update(byte arg0) {
+ engineUpdate(arg0);
+ }
+
+ /**
+ * Updates this {@code MessageDigest} using the given {@code byte[]}.
+ *
+ * @param input
+ * the {@code byte} array
+ * @param offset
+ * the index of the first byte in {@code input} to update from
+ * @param len
+ * the number of bytes in {@code input} to update from
+ * @throws IllegalArgumentException
+ * if {@code offset} or {@code len} are not valid in respect to
+ * {@code input}
+ */
+ public void update(byte[] input, int offset, int len) {
+ if (input == null ||
+ // offset < 0 || len < 0 ||
+ // checks for negative values are commented out intentionally
+ // see HARMONY-1120 for details
+ (long) offset + (long) len > input.length) {
+ throw new IllegalArgumentException(Messages
+ .getString("security.05")); //$NON-NLS-1$
+ }
+ engineUpdate(input, offset, len);
+ }
+
+ /**
+ * Updates this {@code MessageDigest} using the given {@code byte[]}.
+ *
+ * @param input
+ * the {@code byte} array
+ * @throws NullPointerException
+ * if {@code input} is {@code null}
+ */
+ public void update(byte[] input) {
+ if (input == null) {
+ throw new NullPointerException(Messages.getString("security.06")); //$NON-NLS-1$
+ }
+ engineUpdate(input, 0, input.length);
+ }
+
+ /**
+ * Computes and returns the final hash value for this {@link MessageDigest}.
+ * After the digest is computed the receiver is reset.
+ *
+ * @return the computed one way hash value
+ * @see #reset
+ */
+ public byte[] digest() {
+ return engineDigest();
+ }
+
+ /**
+ * Computes and stores the final hash value for this {@link MessageDigest}.
+ * After the digest is computed the receiver is reset.
+ *
+ * @param buf
+ * the buffer to store the result
+ * @param offset
+ * the index of the first byte in {@code buf} to store
+ * @param len
+ * the number of bytes allocated for the digest
+ * @return the number of bytes written to {@code buf}
+ * @throws DigestException
+ * if an error occures
+ * @throws IllegalArgumentException
+ * if {@code offset} or {@code len} are not valid in respect to
+ * {@code buf}
+ * @see #reset()
+ */
+ public int digest(byte[] buf, int offset, int len) throws DigestException {
+ if (buf == null ||
+ // offset < 0 || len < 0 ||
+ // checks for negative values are commented out intentionally
+ // see HARMONY-1148 for details
+ (long) offset + (long) len > buf.length) {
+ throw new IllegalArgumentException(Messages
+ .getString("security.05")); //$NON-NLS-1$
+ }
+ return engineDigest(buf, offset, len);
+ }
+
+ /**
+ * Performs the final update and then computes and returns the final hash
+ * value for this {@link MessageDigest}. After the digest is computed the
+ * receiver is reset.
+ *
+ * @param input
+ * the {@code byte} array
+ * @return the computed one way hash value
+ * @see #reset()
+ */
+ public byte[] digest(byte[] input) {
+ update(input);
+ return digest();
+ }
+
+ /**
+ * Returns a string containing a concise, human-readable description of this
+ * {@code MessageDigest} including the name of its algorithm.
+ *
+ * @return a printable representation for this {@code MessageDigest}
+ */
+ @Override
+ public String toString() {
+ return "MESSAGE DIGEST " + algorithm; //$NON-NLS-1$
+ }
+
+ /**
+ * Indicates whether to digest are equal by performing a simply
+ * byte-per-byte compare of the two digests.
+ *
+ * @param digesta
+ * the first digest to be compared
+ * @param digestb
+ * the second digest to be compared
+ * @return {@code true} if the two hashes are equal, {@code false} otherwise
+ */
+ public static boolean isEqual(byte[] digesta, byte[] digestb) {
+ if (digesta.length != digestb.length) {
+ return false;
+ }
+ for (int i = 0; i < digesta.length; i++) {
+ if (digesta[i] != digestb[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns the name of the algorithm of this {@code MessageDigest}.
+ *
+ * @return the name of the algorithm of this {@code MessageDigest}
+ */
+ public final String getAlgorithm() {
+ return algorithm;
+ }
+
+ /**
+ * Returns the provider associated with this {@code MessageDigest}.
+ *
+ * @return the provider associated with this {@code MessageDigest}
+ */
+ public final Provider getProvider() {
+ return provider;
+ }
+
+ /**
+ * Returns the engine digest length in bytes. If the implementation does not
+ * implement this function or is not an instance of {@code Cloneable},
+ * {@code 0} is returned.
+ *
+ * @return the digest length in bytes, or {@code 0}
+ */
+ public final int getDigestLength() {
+ int l = engineGetDigestLength();
+ if (l != 0) {
+ return l;
+ }
+ if (!(this instanceof Cloneable)) {
+ return 0;
+ }
+ try {
+ MessageDigest md = (MessageDigest) clone();
+ return md.digest().length;
+ } catch (CloneNotSupportedException e) {
+ return 0;
+ }
+ }
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ if (this instanceof Cloneable) {
+ return super.clone();
+ }
+ throw new CloneNotSupportedException();
+ }
+
+ /**
+ * Updates this {@code MessageDigest} using the given {@code input}.
+ *
+ * @param input
+ * the {@code ByteBuffer}
+ */
+ public final void update(ByteBuffer input) {
+ engineUpdate(input);
+ }
+
+ /**
+ *
+ * The internal MessageDigest implementation
+ *
+ */
+ private static class MessageDigestImpl extends MessageDigest {
+
+ // MessageDigestSpi implementation
+ private MessageDigestSpi spiImpl;
+
+ // MessageDigestImpl ctor
+ private MessageDigestImpl(MessageDigestSpi messageDigestSpi,
+ Provider provider, String algorithm) {
+ super(algorithm);
+ super.provider = provider;
+ spiImpl = messageDigestSpi;
+ }
+
+ // engineReset() implementation
+ @Override
+ protected void engineReset() {
+ spiImpl.engineReset();
+ }
+
+ // engineDigest() implementation
+ @Override
+ protected byte[] engineDigest() {
+ return spiImpl.engineDigest();
+ }
+
+ // engineGetDigestLength() implementation
+ @Override
+ protected int engineGetDigestLength() {
+ return spiImpl.engineGetDigestLength();
+ }
+
+ // engineUpdate() implementation
+ @Override
+ protected void engineUpdate(byte arg0) {
+ spiImpl.engineUpdate(arg0);
+ }
+
+ // engineUpdate() implementation
+ @Override
+ protected void engineUpdate(byte[] arg0, int arg1, int arg2) {
+ spiImpl.engineUpdate(arg0, arg1, arg2);
+ }
+
+ // Returns a clone if the spiImpl is cloneable
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ if (spiImpl instanceof Cloneable) {
+ MessageDigestSpi spi = (MessageDigestSpi) spiImpl.clone();
+ return new MessageDigestImpl(spi, getProvider(), getAlgorithm());
+ }
+
+ throw new CloneNotSupportedException();
+ }
+ }
+}
diff --git a/luni/src/main/java/java/security/MessageDigestSpi.java b/luni/src/main/java/java/security/MessageDigestSpi.java
new file mode 100644
index 0000000..52ad3cd
--- /dev/null
+++ b/luni/src/main/java/java/security/MessageDigestSpi.java
@@ -0,0 +1,154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.nio.ByteBuffer;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * {@code MessageDigestSpi} is the Service Provider Interface (SPI) definition
+ * for {@link MessageDigest}. Examples of digest algorithms are MD5 and SHA. A
+ * digest is a secure one way hash function for a stream of bytes. It acts like
+ * a fingerprint for a stream of bytes.
+ *
+ * @see MessageDigest
+ */
+public abstract class MessageDigestSpi {
+
+ /**
+ * Returns the engine digest length in bytes. If the implementation does not
+ * implement this function {@code 0} is returned.
+ *
+ * @return the digest length in bytes, or {@code 0}.
+ */
+ protected int engineGetDigestLength() {
+ return 0;
+ }
+
+ /**
+ * Updates this {@code MessageDigestSpi} using the given {@code byte}.
+ *
+ * @param input
+ * the {@code byte} to update this {@code MessageDigestSpi} with.
+ * @see #engineReset()
+ */
+ protected abstract void engineUpdate(byte input);
+
+ /**
+ * Updates this {@code MessageDigestSpi} using the given {@code byte[]}.
+ *
+ * @param input
+ * the {@code byte} array.
+ * @param offset
+ * the index of the first byte in {@code input} to update from.
+ * @param len
+ * the number of bytes in {@code input} to update from.
+ * @throws IllegalArgumentException
+ * if {@code offset} or {@code len} are not valid in respect to
+ * {@code input}.
+ */
+ protected abstract void engineUpdate(byte[] input, int offset, int len);
+
+ /**
+ * Updates this {@code MessageDigestSpi} using the given {@code input}.
+ *
+ * @param input
+ * the {@code ByteBuffer}.
+ */
+ protected void engineUpdate(ByteBuffer input) {
+ if (!input.hasRemaining()) {
+ return;
+ }
+ byte[] tmp;
+ if (input.hasArray()) {
+ tmp = input.array();
+ int offset = input.arrayOffset();
+ int position = input.position();
+ int limit = input.limit();
+ engineUpdate(tmp, offset+position, limit - position);
+ input.position(limit);
+ } else {
+ tmp = new byte[input.limit() - input.position()];
+ input.get(tmp);
+ engineUpdate(tmp, 0, tmp.length);
+ }
+ }
+
+ /**
+ * Computes and returns the final hash value for this
+ * {@link MessageDigestSpi}. After the digest is computed the receiver is
+ * reset.
+ *
+ * @return the computed one way hash value.
+ * @see #engineReset()
+ */
+ protected abstract byte[] engineDigest();
+
+ /**
+ * Computes and stores the final hash value for this
+ * {@link MessageDigestSpi}. After the digest is computed the receiver is
+ * reset.
+ *
+ * @param buf
+ * the buffer to store the result in.
+ * @param offset
+ * the index of the first byte in {@code buf} to store in.
+ * @param len
+ * the number of bytes allocated for the digest.
+ * @return the number of bytes written to {@code buf}.
+ * @throws DigestException
+ * if an error occures.
+ * @throws IllegalArgumentException
+ * if {@code offset} or {@code len} are not valid in respect to
+ * {@code buf}.
+ * @see #engineReset()
+ */
+ protected int engineDigest(byte[] buf, int offset, int len)
+ throws DigestException {
+ if (len < engineGetDigestLength()) {
+ engineReset();
+ throw new DigestException(Messages.getString("security.1B")); //$NON-NLS-1$
+ }
+ if (offset < 0) {
+ engineReset();
+ throw new DigestException(Messages.getString("security.1C")); //$NON-NLS-1$
+ }
+ if (offset + len > buf.length) {
+ engineReset();
+ throw new DigestException(Messages.getString("security.1D")); //$NON-NLS-1$
+ }
+ byte tmp[] = engineDigest();
+ if (len < tmp.length) {
+ throw new DigestException(Messages.getString("security.1B")); //$NON-NLS-1$
+ }
+ System.arraycopy(tmp, 0, buf, offset, tmp.length);
+ return tmp.length;
+ }
+
+ /**
+ * Puts this {@code MessageDigestSpi} back in an initial state, such that it
+ * is ready to compute a one way hash value.
+ */
+ protected abstract void engineReset();
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+}
diff --git a/luni/src/main/java/java/security/NoSuchAlgorithmException.java b/luni/src/main/java/java/security/NoSuchAlgorithmException.java
new file mode 100644
index 0000000..8ef2e3f
--- /dev/null
+++ b/luni/src/main/java/java/security/NoSuchAlgorithmException.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * {@code NoSuchAlgorithmException} indicates that a requested algorithm could
+ * not be found.
+ */
+public class NoSuchAlgorithmException extends GeneralSecurityException {
+
+ private static final long serialVersionUID = -7443947487218346562L;
+
+ /**
+ * Constructs a new instance of {@code NoSuchAlgorithmException} with the
+ * given message.
+ *
+ * @param msg
+ * the detail message for this exception.
+ */
+ public NoSuchAlgorithmException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs a new instance of {@code NoSuchAlgorithmException}.
+ */
+ public NoSuchAlgorithmException() {
+ }
+
+ /**
+ * Constructs a new instance of {@code NoSuchAlgorithmException} with the
+ * given message and the cause.
+ *
+ * @param message
+ * the detail message for this exception.
+ * @param cause
+ * the exception which is the cause for this exception.
+ */
+ public NoSuchAlgorithmException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructs a new instance of {@code NoSuchAlgorithmException} with the
+ * cause.
+ *
+ * @param cause
+ * the exception which is the cause for this exception.
+ */
+ public NoSuchAlgorithmException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/luni/src/main/java/java/security/NoSuchProviderException.java b/luni/src/main/java/java/security/NoSuchProviderException.java
new file mode 100644
index 0000000..57cda40
--- /dev/null
+++ b/luni/src/main/java/java/security/NoSuchProviderException.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * {@code NoSuchProviderException} indicates that a requested security provider
+ * could not be found.
+ */
+public class NoSuchProviderException extends GeneralSecurityException {
+
+ private static final long serialVersionUID = 8488111756688534474L;
+
+ /**
+ * Constructs a new instance of {@code NoSuchProviderException} with the
+ * given message.
+ *
+ * @param msg
+ * the detail message for this exception.
+ */
+ public NoSuchProviderException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs a new instance of {@code NoSuchProviderException}.
+ */
+ public NoSuchProviderException() {
+ }
+}
diff --git a/luni/src/main/java/java/security/Permission.java b/luni/src/main/java/java/security/Permission.java
new file mode 100644
index 0000000..26bdfcd
--- /dev/null
+++ b/luni/src/main/java/java/security/Permission.java
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.io.Serializable;
+
+/**
+ * {@code Permission} is the common base class of all permissions that
+ * participate in the access control security framework around
+ * {@link AccessController} and {@link AccessControlContext}. A permission
+ * constitutes of a name and associated actions.
+ */
+public abstract class Permission implements Guard, Serializable {
+
+ private static final long serialVersionUID = -5636570222231596674L;
+
+ private final String name;
+
+ /**
+ * Compares the specified object with this {@code Permission} for equality
+ * and returns {@code true} if the specified object is equal, {@code false}
+ * otherwise.
+ * <p>
+ * The {@link #implies(Permission)} method should be used for making access
+ * control checks.
+ *
+ * @param obj
+ * object to be compared for equality with this {@code
+ * Permission}.
+ * @return {@code true} if the specified object is equal to this {@code
+ * Permission}, otherwise {@code false}.
+ */
+ @Override
+ public abstract boolean equals(Object obj);
+
+ /**
+ * Returns the hash code value for this {@code Permission}. Returns the same
+ * hash code for {@code Permission}s that are equal to each other as
+ * required by the general contract of {@link Object#hashCode}.
+ *
+ * @return the hash code value for this {@code Permission}.
+ * @see Object#equals(Object)
+ * @see Permission#equals(Object)
+ */
+ @Override
+ public abstract int hashCode();
+
+ /**
+ * Returns a comma separated string identifying the actions associated with
+ * this permission. The returned actions are in canonical form. For example:
+ *
+ * <pre>
+ * sp0 = new SocketPermission(&quot;www.example.com&quot;, &quot;connect,resolve&quot;)
+ * sp1 = new SocketPermission(&quot;www.example.com&quot;, &quot;resolve,connect&quot;)
+ * sp0.getActions().equals(sp1.getActions()) //yields true
+ * </pre>
+ *
+ * Both permissions return "connect,resolve" (in that order) if {@code
+ * #getActions()} is invoked. Returns an empty String, if no actions are
+ * associated with this permission.
+ *
+ * @return the actions associated with this permission or an empty string if
+ * no actions are associated with this permission.
+ */
+ public abstract String getActions();
+
+ /**
+ * Indicates whether the specified permission is implied by this permission.
+ * The {@link AccessController} uses this method to check whether permission
+ * protected access is allowed with the present policy.
+ *
+ * @param permission
+ * the permission to check against this permission.
+ * @return {@code true} if the specified permission is implied by this
+ * permission, {@code false} otherwise.
+ */
+ public abstract boolean implies(Permission permission);
+
+ /**
+ * Constructs a new instance of {@code Permission} with its name.
+ *
+ * @param name
+ * the name of the permission.
+ */
+ public Permission(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Returns the name of this permission.
+ *
+ * @return the name of this permission.
+ */
+ public final String getName() {
+ return name;
+ }
+
+ /**
+ * Invokes {@link SecurityManager#checkPermission(Permission)} with this
+ * permission as its argument. This method implements the {@link Guard}
+ * interface.
+ *
+ * @param obj
+ * as specified in {@link Guard#checkGuard(Object)} but ignored
+ * in this implementation.
+ * @throws SecurityException
+ * if this permission is not granted.
+ * @see Guard
+ * @see SecurityManager#checkPermission(Permission)
+ */
+ public void checkGuard(Object obj) throws SecurityException {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(this);
+ }
+ }
+
+ /**
+ * Returns a specific {@link PermissionCollection} container for permissions
+ * of this type. Returns {@code null} if any permission collection can be
+ * used.
+ * <p>
+ * Subclasses may override this method to return an appropriate collection
+ * for the specific permissions they implement.
+ *
+ * @return an empty {@link PermissionCollection} or {@code null} if any
+ * permission collection can be used.
+ */
+ public PermissionCollection newPermissionCollection() {
+ return null;
+ }
+
+ /**
+ * Returns a string containing a concise, human-readable description of the
+ * this {@code Permission} including its name and its actions.
+ *
+ * @return a printable representation for this {@code Permission}.
+ */
+ @Override
+ public String toString() {
+ String actions = getActions();
+ actions = (actions == null || actions.length() == 0) ? "" : " " //$NON-NLS-1$ //$NON-NLS-2$
+ + getActions();
+ return "(" + getClass().getName() + " " + getName() + actions + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+}
diff --git a/luni/src/main/java/java/security/PermissionCollection.java b/luni/src/main/java/java/security/PermissionCollection.java
new file mode 100644
index 0000000..56b6cd0
--- /dev/null
+++ b/luni/src/main/java/java/security/PermissionCollection.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+
+/**
+ * {@code PermissionCollection} is the common base class for all collections
+ * that provide a convenient method for determining whether or not a given
+ * permission is implied by any of the permissions present in this collection.
+ * <p>
+ * A {@code PermissionCollection} is typically created by using the
+ * {@link Permission#newPermissionCollection()} factory method. If the mentioned
+ * method returns {@code null}, then a {@code PermissionCollection} of any type
+ * can be used. If a collection is returned, it must be used for holding several
+ * permissions of the particular type.
+ * <p>
+ * Subclasses must be implemented thread save.
+ */
+public abstract class PermissionCollection implements Serializable {
+
+ private static final long serialVersionUID = -6727011328946861783L;
+
+ private boolean readOnly; // = false;
+
+ /**
+ * Adds the specified {@code Permission} to this collection.
+ *
+ * @param permission
+ * the {@code Permission} to add.
+ * @throws IllegalStateException
+ * if the collection is read only.
+ */
+ public abstract void add(Permission permission);
+
+ /**
+ * Returns an enumeration over all {@link Permission}s encapsulated by this
+ * {@code PermissionCollection}.
+ *
+ * @return an enumeration over all {@link Permission}s.
+ */
+ public abstract Enumeration<Permission> elements();
+
+ /**
+ * Indicates whether the specified permission is implied by this {@code
+ * PermissionCollection}.
+ *
+ * @param permission
+ * the permission to check.
+ * @return {@code true} if the given permission is implied by the
+ * permissions in this collection, {@code false} otherwise.
+ */
+ public abstract boolean implies(Permission permission);
+
+ /**
+ * Indicates whether new permissions can be added to this {@code
+ * PermissionCollection}.
+ *
+ * @return {@code true} if the receiver is read only, {@code false} if new
+ * elements can still be added to this {@code PermissionCollection}.
+ */
+ public boolean isReadOnly() {
+ return readOnly;
+ }
+
+ /**
+ * Marks this {@code PermissionCollection} as read only, so that no new
+ * permissions can be added to it.
+ */
+ public void setReadOnly() {
+ readOnly = true;
+ }
+
+ /**
+ * Returns a string containing a concise, human-readable description of this
+ * {@code PermissionCollection}.
+ *
+ * @return a printable representation for this {@code PermissionCollection}.
+ */
+ @Override
+ public String toString() {
+ List<String> elist = new ArrayList<String>(100);
+ Enumeration<Permission> elenum = elements();
+ String superStr = super.toString();
+ int totalLength = superStr.length() + 5;
+ if (elenum != null) {
+ while (elenum.hasMoreElements()) {
+ String el = elenum.nextElement().toString();
+ totalLength += el.length();
+ elist.add(el);
+ }
+ }
+ int esize = elist.size();
+ totalLength += esize * 4;
+ StringBuilder result = new StringBuilder(totalLength).append(superStr)
+ .append(" ("); //$NON-NLS-1$
+ for (int i = 0; i < esize; i++) {
+ result.append("\n ").append(elist.get(i).toString()); //$NON-NLS-1$
+ }
+ return result.append("\n)\n").toString(); //$NON-NLS-1$
+ }
+}
diff --git a/luni/src/main/java/java/security/Permissions.java b/luni/src/main/java/java/security/Permissions.java
new file mode 100644
index 0000000..e8d3375
--- /dev/null
+++ b/luni/src/main/java/java/security/Permissions.java
@@ -0,0 +1,244 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.io.Serializable;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * {@code Permissions} represents a {@code PermissionCollection} where the
+ * contained permissions can be of different types. The permissions are
+ * organized in their appropriate {@code PermissionCollection} obtained by
+ * {@link Permission#newPermissionCollection()}. For permissions which do not
+ * provide a dedicated {@code PermissionCollection}, a default permission
+ * collection, based on a hash table, will be used.
+ */
+public final class Permissions extends PermissionCollection implements
+ Serializable {
+
+ private static final long serialVersionUID = 4858622370623524688L;
+
+ private static final ObjectStreamField[] serialPersistentFields = {
+ new ObjectStreamField("perms", Hashtable.class), //$NON-NLS-1$
+ new ObjectStreamField("allPermission", PermissionCollection.class), }; //$NON-NLS-1$
+
+ // Hash to store PermissionCollection's
+ private transient Map klasses = new HashMap();
+
+ private boolean allEnabled; // = false;
+
+ /**
+ * Adds the given {@code Permission} to this heterogeneous {@code
+ * PermissionCollection}. The {@code permission} is stored in its
+ * appropriate {@code PermissionCollection}.
+ *
+ * @param permission
+ * the {@code Permission} to be added.
+ * @throws SecurityException
+ * if this collection's {@link #isReadOnly()} method returns
+ * {@code true}.
+ * @throws NullPointerException
+ * if {@code permission} is {@code null}.
+ */
+ public void add(Permission permission) {
+ if (isReadOnly()) {
+ throw new SecurityException(Messages.getString("security.15")); //$NON-NLS-1$
+ }
+
+ if (permission == null) {
+ throw new NullPointerException(Messages.getString("security.20")); //$NON-NLS-1$
+ }
+
+ Class klass = permission.getClass();
+ PermissionCollection klassMates = (PermissionCollection)klasses
+ .get(klass);
+
+ if (klassMates == null) {
+ synchronized (klasses) {
+ klassMates = (PermissionCollection)klasses.get(klass);
+ if (klassMates == null) {
+
+ klassMates = permission.newPermissionCollection();
+ if (klassMates == null) {
+ klassMates = new PermissionsHash();
+ }
+ klasses.put(klass, klassMates);
+ }
+ }
+ }
+ klassMates.add(permission);
+
+ if (klass == AllPermission.class) {
+ allEnabled = true;
+ }
+ }
+
+ public Enumeration<Permission> elements() {
+ return new MetaEnumeration(klasses.values().iterator());
+ }
+
+ /**
+ * An auxiliary implementation for enumerating individual permissions from a
+ * collection of PermissionCollections.
+ *
+ */
+ final static class MetaEnumeration implements Enumeration {
+
+ private Iterator pcIter;
+
+ private Enumeration current;
+
+ /**
+ * Initiates this enumeration.
+ *
+ * @param outer an iterator over external collection of
+ * PermissionCollections
+ */
+ public MetaEnumeration(Iterator outer) {
+ pcIter = outer;
+ current = getNextEnumeration();
+ }
+
+ private Enumeration getNextEnumeration() {
+ while (pcIter.hasNext()) {
+ Enumeration en = ((PermissionCollection)pcIter.next())
+ .elements();
+ if (en.hasMoreElements()) {
+ return en;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Indicates if there are more elements to enumerate.
+ */
+ public boolean hasMoreElements() {
+ return current != null /* && current.hasMoreElements() */;
+ }
+
+ /**
+ * Returns next element.
+ */
+ public Object nextElement() {
+ if (current != null) {
+ //assert current.hasMoreElements();
+ Object next = current.nextElement();
+ if (!current.hasMoreElements()) {
+ current = getNextEnumeration();
+ }
+
+ return next;
+ }
+ throw new NoSuchElementException(Messages.getString("security.17")); //$NON-NLS-1$
+ }
+ }
+
+ public boolean implies(Permission permission) {
+ if (permission == null) {
+ // RI compatible
+ throw new NullPointerException(Messages.getString("security.21")); //$NON-NLS-1$
+ }
+ if (allEnabled) {
+ return true;
+ }
+ Class klass = permission.getClass();
+ PermissionCollection klassMates = null;
+
+ UnresolvedPermissionCollection billets = (UnresolvedPermissionCollection)klasses
+ .get(UnresolvedPermission.class);
+ if (billets != null && billets.hasUnresolved(permission)) {
+ // try to fill up klassMates with freshly resolved permissions
+ synchronized (klasses) {
+ klassMates = (PermissionCollection)klasses.get(klass);
+ try {
+ klassMates = billets.resolveCollection(permission,
+ klassMates);
+ } catch (Exception ignore) {
+ //TODO log warning
+ ignore.printStackTrace();
+ }
+
+ if (klassMates != null) {
+ //maybe klassMates were just created
+ // so put them into common map
+ klasses.put(klass, klassMates);
+ // very uncommon case, but not improbable one
+ if (klass == AllPermission.class) {
+ allEnabled = true;
+ }
+ }
+ }
+ } else {
+ klassMates = (PermissionCollection)klasses.get(klass);
+ }
+
+ if (klassMates != null) {
+ return klassMates.implies(permission);
+ }
+ return false;
+ }
+
+ /**
+ * Reads the object from stream and checks for consistency.
+ */
+ private void readObject(java.io.ObjectInputStream in) throws IOException,
+ ClassNotFoundException {
+ ObjectInputStream.GetField fields = in.readFields();
+ Map perms = (Map)fields.get("perms", null); //$NON-NLS-1$
+ klasses = new HashMap();
+ synchronized (klasses) {
+ for (Iterator iter = perms.entrySet().iterator(); iter.hasNext();) {
+ Map.Entry entry = (Map.Entry) iter.next();
+ Class key = (Class) entry.getKey();
+ PermissionCollection pc = (PermissionCollection) entry.getValue();
+ if (key != pc.elements().nextElement().getClass()) {
+ throw new InvalidObjectException(Messages.getString("security.22")); //$NON-NLS-1$
+ }
+ klasses.put(key, pc);
+ }
+ }
+ allEnabled = fields.get("allPermission", null) != null; //$NON-NLS-1$
+ if (allEnabled && !klasses.containsKey(AllPermission.class)) {
+ throw new InvalidObjectException(Messages.getString("security.23")); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Outputs fields via default mechanism.
+ */
+ private void writeObject(java.io.ObjectOutputStream out) throws IOException {
+ ObjectOutputStream.PutField fields = out.putFields();
+ fields.put("perms", new Hashtable(klasses)); //$NON-NLS-1$
+ fields.put("allPermission", allEnabled ? klasses //$NON-NLS-1$
+ .get(AllPermission.class) : null);
+ out.writeFields();
+ }
+}
diff --git a/luni/src/main/java/java/security/PermissionsHash.java b/luni/src/main/java/java/security/PermissionsHash.java
new file mode 100644
index 0000000..4c9e0c9
--- /dev/null
+++ b/luni/src/main/java/java/security/PermissionsHash.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * A default {@code PermissionCollection} implementation that uses a hashtable.
+ * Each hashtable entry stores a Permission object as both the key and the
+ * value.
+ * <p>
+ * This {@code PermissionCollection} is intended for storing &quot;neutral&quot;
+ * permissions which do not require special collection.
+ */
+
+final class PermissionsHash extends PermissionCollection {
+
+ private static final long serialVersionUID = -8491988220802933440L;
+
+ private final Hashtable perms = new Hashtable();
+
+ /**
+ * Adds the argument to the collection.
+ *
+ * @param permission
+ * the permission to add to the collection.
+ */
+ public void add(Permission permission) {
+ perms.put(permission, permission);
+ }
+
+ /**
+ * Returns an enumeration of the permissions in the receiver.
+ *
+ * @return Enumeration the permissions in the receiver.
+ */
+ public Enumeration elements() {
+ return perms.elements();
+ }
+
+ /**
+ * Indicates whether the argument permission is implied by the permissions
+ * contained in the receiver.
+ *
+ * @return boolean <code>true</code> if the argument permission is implied
+ * by the permissions in the receiver, and <code>false</code> if
+ * it is not.
+ * @param permission
+ * java.security.Permission the permission to check
+ */
+ public boolean implies(Permission permission) {
+ for (Enumeration elements = elements(); elements.hasMoreElements();) {
+ if (((Permission)elements.nextElement()).implies(permission)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/luni/src/main/java/java/security/Policy.java b/luni/src/main/java/java/security/Policy.java
new file mode 100644
index 0000000..d5719a3
--- /dev/null
+++ b/luni/src/main/java/java/security/Policy.java
@@ -0,0 +1,236 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.util.Enumeration;
+
+import org.apache.harmony.security.fortress.DefaultPolicy;
+import org.apache.harmony.security.fortress.PolicyUtils;
+
+
+/**
+ * {@code Policy} is the common super type of classes which represent a system
+ * security policy. The {@code Policy} specifies which permissions apply to
+ * which code sources.
+ * <p>
+ * The system policy can be changed by setting the {@code 'policy.provider'}
+ * property in the file named {@code JAVA_HOME/lib/security/java.security} to
+ * the fully qualified class name of the desired {@code Policy}.
+ * <p>
+ * Only one instance of a {@code Policy} is active at any time.
+ */
+public abstract class Policy {
+
+ // Key to security properties, defining default policy provider.
+ private static final String POLICY_PROVIDER = "policy.provider"; //$NON-NLS-1$
+
+ // The SecurityPermission required to set custom Policy.
+ private static final SecurityPermission SET_POLICY = new SecurityPermission(
+ "setPolicy"); //$NON-NLS-1$
+
+ // The SecurityPermission required to get current Policy.
+ private static final SecurityPermission GET_POLICY = new SecurityPermission(
+ "getPolicy"); //$NON-NLS-1$
+
+ // The policy currently in effect.
+ private static Policy activePolicy;
+
+ /**
+ * Returns a {@code PermissionCollection} describing what permissions are
+ * allowed for the specified {@code CodeSource} based on the current
+ * security policy.
+ * <p>
+ * Note that this method is not called for classes which are in the system
+ * domain (i.e. system classes). System classes are always given
+ * full permissions (i.e. AllPermission). This can not be changed by
+ * installing a new policy.
+ *
+ * @param cs
+ * the {@code CodeSource} to compute the permissions for.
+ * @return the permissions that are granted to the specified {@code
+ * CodeSource}.
+ */
+ public abstract PermissionCollection getPermissions(CodeSource cs);
+
+ /**
+ * Reloads the policy configuration for this {@code Policy} instance.
+ */
+ public abstract void refresh();
+
+ /**
+ * Returns a {@code PermissionCollection} describing what permissions are
+ * allowed for the specified {@code ProtectionDomain} (more specifically,
+ * its {@code CodeSource}) based on the current security policy.
+ * <p>
+ * Note that this method is not< called for classes which are in the
+ * system domain (i.e. system classes). System classes are always
+ * given full permissions (i.e. AllPermission). This can not be changed by
+ * installing a new policy.
+ *
+ * @param domain
+ * the {@code ProtectionDomain} to compute the permissions for.
+ * @return the permissions that are granted to the specified {@code
+ * CodeSource}.
+ */
+ public PermissionCollection getPermissions(ProtectionDomain domain) {
+ if (domain != null) {
+ return getPermissions(domain.getCodeSource());
+ }
+ return new Permissions();
+ }
+
+ /**
+ * Indicates whether the specified {@code Permission} is implied by the
+ * {@code PermissionCollection} of the specified {@code ProtectionDomain}.
+ *
+ * @param domain
+ * the {@code ProtectionDomain} for which the permission should
+ * be granted.
+ * @param permission
+ * the {@code Permission} for which authorization is to be
+ * verified.
+ * @return {@code true} if the {@code Permission} is implied by the {@code
+ * ProtectionDomain}, {@code false} otherwise.
+ */
+ public boolean implies(ProtectionDomain domain, Permission permission) {
+ if (domain != null) {
+ PermissionCollection total = getPermissions(domain);
+ PermissionCollection inherent = domain.getPermissions();
+ if (total == null) {
+ total = inherent;
+ } else if (inherent != null) {
+ for (Enumeration<Permission> en = inherent.elements(); en.hasMoreElements();) {
+ total.add(en.nextElement());
+ }
+ }
+ if (total != null && total.implies(permission)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns the current system security policy. If no policy has been
+ * instantiated then this is done using the security property {@code
+ * "policy.provider"}.
+ * <p>
+ * If a {@code SecurityManager} is installed, code calling this method needs
+ * the {@code SecurityPermission} {@code getPolicy} to be granted, otherwise
+ * a {@code SecurityException} will be thrown.
+ *
+ * @return the current system security policy.
+ * @throws SecurityException
+ * if a {@code SecurityManager} is installed and the caller does
+ * not have permission to invoke this method.
+ */
+ public static Policy getPolicy() {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(GET_POLICY);
+ }
+ return getAccessiblePolicy();
+ }
+
+ // Reads name of default policy provider from security.properties,
+ // loads the class and instantiates the provider.<br>
+ // In case of any error, including undefined provider name,
+ // returns new instance of org.apache.harmony.security.FilePolicy provider.
+ private static Policy getDefaultProvider() {
+ final String defaultClass = AccessController
+ .doPrivileged(new PolicyUtils.SecurityPropertyAccessor(
+ POLICY_PROVIDER));
+ if (defaultClass == null) {
+ //TODO log warning
+ //System.err.println("No policy provider specified. Loading the "
+ // + DefaultPolicy.class.getName());
+ return new DefaultPolicy();
+ }
+
+ // TODO accurate classloading
+ return AccessController.doPrivileged(new PrivilegedAction<Policy>() {
+
+ public Policy run() {
+ try {
+ return (Policy) Class.forName(defaultClass, true,
+ ClassLoader.getSystemClassLoader()).newInstance();
+ }
+ catch (Exception e) {
+ //TODO log error
+ //System.err.println("Error loading policy provider <"
+ // + defaultClass + "> : " + e
+ // + "\nSwitching to the default "
+ // + DefaultPolicy.class.getName());
+ return new DefaultPolicy();
+ }
+ }
+ });
+
+ }
+
+ /**
+ * Returns {@code true} if system policy provider is instantiated.
+ */
+ static boolean isSet() {
+ return activePolicy != null;
+ }
+
+ /**
+ * Shortcut accessor for friendly classes, to skip security checks.
+ * If active policy was set to <code>null</code>, loads default provider,
+ * so this method never returns <code>null</code>. <br>
+ * This method is synchronized with setPolicy()
+ */
+ static Policy getAccessiblePolicy() {
+ Policy current = activePolicy;
+ if (current == null) {
+ synchronized (Policy.class) {
+ // double check in case value has been reassigned
+ // while we've been awaiting monitor
+ if (activePolicy == null) {
+ activePolicy = getDefaultProvider();
+ }
+ return activePolicy;
+ }
+ }
+ return current;
+ }
+
+ /**
+ * Sets the system wide policy.
+ * <p>
+ * If a {@code SecurityManager} is installed, code calling this method needs
+ * the {@code SecurityPermission} {@code setPolicy} to be granted, otherwise
+ * a {@code SecurityException} will be thrown.
+ *
+ * @param policy
+ * the {@code Policy} to set.
+ * @throws SecurityException
+ * if a {@code SecurityManager} is installed and the caller does
+ * not have permission to invoke this method.
+ */
+ public static void setPolicy(Policy policy) {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(SET_POLICY);
+ }
+ synchronized (Policy.class) {
+ activePolicy = policy;
+ }
+ }
+}
diff --git a/luni/src/main/java/java/security/Principal.java b/luni/src/main/java/java/security/Principal.java
new file mode 100644
index 0000000..f86bc87
--- /dev/null
+++ b/luni/src/main/java/java/security/Principal.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+
+/**
+ * {@code Principal}s are objects which have identities. These can be
+ * individuals, groups, corporations, unique program executions, etc.
+ */
+public interface Principal {
+ /**
+ * Compares the specified object with this {@code Principal} for equality
+ * and returns {@code true} if the specified object is equal, {@code false}
+ * otherwise.
+ *
+ * @param obj
+ * object to be compared for equality with this {@code
+ * Principal}.
+ * @return {@code true} if the specified object is equal to this {@code
+ * Principal}, otherwise {@code false}.
+ */
+ public boolean equals( Object obj );
+
+ /**
+ * Returns the name of this {@code Principal}.
+ *
+ * @return the name of this {@code Principal}.
+ */
+ public String getName();
+
+ /**
+ * Returns the hash code value for this {@code Principal}. Returns the same
+ * hash code for {@code Principal}s that are equal to each other as
+ * required by the general contract of {@link Object#hashCode}.
+ *
+ * @return the hash code value for this {@code Principal}.
+ * @see Object#equals(Object)
+ * @see Principal#equals(Object)
+ */
+ public int hashCode();
+
+ /**
+ * Returns a string containing a concise, human-readable description of
+ * this {@code Principal}.
+ *
+ * @return a printable representation for this {@code Principal}.
+ */
+ public String toString();
+}
diff --git a/luni/src/main/java/java/security/PrivateKey.java b/luni/src/main/java/java/security/PrivateKey.java
new file mode 100644
index 0000000..246f286
--- /dev/null
+++ b/luni/src/main/java/java/security/PrivateKey.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * {@code PrivateKey} is the common interface for private keys.
+ *
+ * @see PublicKey
+ */
+public interface PrivateKey extends Key {
+
+ /**
+ * The {@code serialVersionUID} to be compatible with JDK1.1.
+ */
+ public static final long serialVersionUID = 6034044314589513430L;
+}
diff --git a/luni/src/main/java/java/security/PrivilegedAction.java b/luni/src/main/java/java/security/PrivilegedAction.java
new file mode 100644
index 0000000..1dbbe65
--- /dev/null
+++ b/luni/src/main/java/java/security/PrivilegedAction.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * {@code PrivilegedAction} represents an action that can be executed privileged
+ * regarding access control. Instances of {@code PrivilegedAction} can be
+ * executed on {@code AccessController.doPrivileged()}.
+ *
+ * @see AccessController
+ * @see AccessController#doPrivileged(PrivilegedAction)
+ * @see AccessController#doPrivileged(PrivilegedAction, AccessControlContext)
+ * @see PrivilegedExceptionAction
+ */
+public interface PrivilegedAction<T> {
+ /**
+ * Returns the result of running the action.
+ *
+ * @return the result of running the action.
+ */
+ public T run();
+}
diff --git a/luni/src/main/java/java/security/PrivilegedActionException.java b/luni/src/main/java/java/security/PrivilegedActionException.java
new file mode 100644
index 0000000..a1f5b15
--- /dev/null
+++ b/luni/src/main/java/java/security/PrivilegedActionException.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * {@code PrivilegedActionException} wraps exceptions which are thrown from
+ * within privileged operations.
+ * <p>
+ * Privileged actions which can throw exceptions are of type {@code
+ * PrivilegedExceptionAction} and are thrown by
+ * <ul>
+ * {@code AccessController#doPrivileged(PrivilegedExceptionAction)}<br>
+ * {@code AccessController#doPrivileged(PrivilegedExceptionAction,
+ * AccessControlContext)} </br>
+ * </ul>
+ *
+ * @see PrivilegedExceptionAction
+ * @see AccessController#doPrivileged(PrivilegedExceptionAction)
+ * @see AccessController#doPrivileged(PrivilegedExceptionAction,
+ * AccessControlContext)
+ */
+public class PrivilegedActionException extends Exception {
+
+ private static final long serialVersionUID = 4724086851538908602l;
+
+ private Exception exception;
+
+ /**
+ * Constructs a new instance of {@code PrivilegedActionException} with the
+ * cause.
+ *
+ * @param ex
+ * the exception which is the cause for this exception.
+ */
+ public PrivilegedActionException(Exception ex) {
+ super(ex);
+ this.exception = ex;
+ }
+
+ /**
+ * Returns the exception that was thrown by a
+ * {@code PrivilegedExceptionAction}.
+ *
+ * @return the exception that was thrown by a
+ * {@code PrivilegedExceptionAction}.
+ */
+ public Exception getException() {
+ return exception; // return ( getCause() instanceof Exception ) ?
+ // getCause() : null;
+ }
+
+ /**
+ * Returns the exception that was thrown by a
+ * {@code PrivilegedExceptionAction}.
+ *
+ * @return the exception that was thrown by a
+ * {@code PrivilegedExceptionAction}.
+ */
+ @Override
+ public Throwable getCause() {
+ return exception;
+ }
+
+ /**
+ * Returns a string containing a concise, human-readable description of this
+ * {@code PrivilegedActionException}.
+ *
+ * @return a printable representation for this {@code
+ * PrivilegedActionException}.
+ */
+ @Override
+ public String toString() {
+ String s = getClass().getName();
+ return exception == null ? s : s + ": " + exception; //$NON-NLS-1$
+ }
+
+}
diff --git a/luni/src/main/java/java/security/PrivilegedExceptionAction.java b/luni/src/main/java/java/security/PrivilegedExceptionAction.java
new file mode 100644
index 0000000..bc072d5
--- /dev/null
+++ b/luni/src/main/java/java/security/PrivilegedExceptionAction.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * {@code PrivilegedAction} represents an action, that can be executed
+ * privileged regarding access control. Instances of {@code PrivilegedAction}
+ * can be executed invoking {@code AccessController.doPrivileged()}.
+ *
+ * @see AccessController
+ * @see AccessController#doPrivileged(PrivilegedExceptionAction)
+ * @see AccessController#doPrivileged(PrivilegedExceptionAction,
+ * AccessControlContext)
+ * @see PrivilegedAction
+ */
+public interface PrivilegedExceptionAction<T> {
+ /**
+ * Returns the result of running the action.
+ *
+ * @return the result of running the action
+ * @throws Exception
+ * if an exception occurred.
+ */
+ T run() throws Exception;
+}
diff --git a/luni/src/main/java/java/security/ProtectionDomain.java b/luni/src/main/java/java/security/ProtectionDomain.java
new file mode 100644
index 0000000..1e85c4a
--- /dev/null
+++ b/luni/src/main/java/java/security/ProtectionDomain.java
@@ -0,0 +1,261 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * {@code ProtectionDomain} represents all permissions that are granted to a
+ * specific code source. The {@link ClassLoader} associates each class with the
+ * corresponding {@code ProtectionDomain}, depending on the location and the
+ * certificates (encapsulates in {@link CodeSource}) it loads the code from.
+ * <p>
+ * A class belongs to exactly one protection domain and the protection domain
+ * can not be changed during the lifetime of the class.
+ */
+public class ProtectionDomain {
+
+ // CodeSource for this ProtectionDomain
+ private CodeSource codeSource;
+
+ // Static permissions for this ProtectionDomain
+ private PermissionCollection permissions;
+
+ // ClassLoader
+ private ClassLoader classLoader;
+
+ // Set of principals associated with this ProtectionDomain
+ private Principal[] principals;
+
+ // false if this ProtectionDomain was constructed with static
+ // permissions, true otherwise.
+ private boolean dynamicPerms;
+
+ /**
+ * Constructs a new instance of {@code ProtectionDomain} with the specified
+ * code source and the specified static permissions.
+ * <p>
+ * If {@code permissions} is not {@code null}, the {@code permissions}
+ * collection is made immutable by calling
+ * {@link PermissionCollection#setReadOnly()} and it is considered as
+ * granted statically to this {@code ProtectionDomain}.
+ * <p>
+ * The policy will not be consulted by access checks against this {@code
+ * ProtectionDomain}.
+ * <p>
+ * If {@code permissions} is {@code null}, the method {@link
+ * ProtectionDomain#implies(Permission)} always returns {@code false}.
+ *
+ * @param cs
+ * the code source associated with this domain, maybe {@code
+ * null}.
+ * @param permissions
+ * the {@code PermissionCollection} containing all permissions to
+ * be statically granted to this {@code ProtectionDomain}, maybe
+ * {@code null}.
+ */
+ public ProtectionDomain(CodeSource cs, PermissionCollection permissions) {
+ this.codeSource = cs;
+ if (permissions != null) {
+ permissions.setReadOnly();
+ }
+ this.permissions = permissions;
+ //this.classLoader = null;
+ //this.principals = null;
+ //dynamicPerms = false;
+ }
+
+ /**
+ * Constructs a new instance of {@code ProtectionDomain} with the specified
+ * code source, the permissions, the class loader and the principals.
+ * <p>
+ * If {@code permissions} is {@code null}, and access checks are performed
+ * against this protection domain, the permissions defined by the policy are
+ * consulted. If {@code permissions} is not {@code null}, the {@code
+ * permissions} collection is made immutable by calling
+ * {@link PermissionCollection#setReadOnly()}. If access checks are
+ * performed, the policy and the provided permission collection are checked.
+ * <p>
+ * External modifications of the provided {@code principals} array has no
+ * impact on this {@code ProtectionDomain}.
+ *
+ * @param cs
+ * the code source associated with this domain, maybe {@code
+ * null}.
+ * @param permissions
+ * the permissions associated with this domain, maybe {@code
+ * null}.
+ * @param cl
+ * the class loader associated with this domain, maybe {@code
+ * null}.
+ * @param principals
+ * the principals associated with this domain, maybe {@code
+ * null}.
+ */
+ public ProtectionDomain(CodeSource cs, PermissionCollection permissions,
+ ClassLoader cl, Principal[] principals) {
+ this.codeSource = cs;
+ if (permissions != null) {
+ permissions.setReadOnly();
+ }
+ this.permissions = permissions;
+ this.classLoader = cl;
+ if (principals != null) {
+ this.principals = new Principal[principals.length];
+ System.arraycopy(principals, 0, this.principals, 0,
+ this.principals.length);
+ }
+ dynamicPerms = true;
+ }
+
+ /**
+ * Returns the {@code ClassLoader} associated with this {@code
+ * ProtectionDomain}.
+ *
+ * @return the {@code ClassLoader} associated with this {@code
+ * ProtectionDomain}, maybe {@code null}.
+ */
+ public final ClassLoader getClassLoader() {
+ return classLoader;
+ }
+
+ /**
+ * Returns the {@code CodeSource} of this {@code ProtectionDomain}.
+ *
+ * @return the {@code CodeSource} of this {@code ProtectionDomain}, maybe
+ * {@code null}.
+ */
+ public final CodeSource getCodeSource() {
+ return codeSource;
+ }
+
+ /**
+ * Returns the static permissions that are granted to this {@code
+ * ProtectionDomain}.
+ *
+ * @return the static permissions that are granted to this {@code
+ * ProtectionDomain}, maybe {@code null}.
+ */
+ public final PermissionCollection getPermissions() {
+ return permissions;
+ }
+
+ /**
+ * Returns the principals associated with this {@code ProtectionDomain}.
+ * Modifications of the returned {@code Principal} array has no impact on
+ * this {@code ProtectionDomain}.
+ *
+ * @return the principals associated with this {@code ProtectionDomain}.
+ */
+ public final Principal[] getPrincipals() {
+ if( principals == null ) {
+ return new Principal[0];
+ }
+ Principal[] tmp = new Principal[principals.length];
+ System.arraycopy(principals, 0, tmp, 0, tmp.length);
+ return tmp;
+ }
+
+ /**
+ * Indicates whether the specified permission is implied by this {@code
+ * ProtectionDomain}.
+ * <p>
+ * If this {@code ProtectionDomain} was constructed with
+ * {@link #ProtectionDomain(CodeSource, PermissionCollection)}, the
+ * specified permission is only checked against the permission collection
+ * provided in the constructor. If {@code null} was provided, {@code false}
+ * is returned.
+ * <p>
+ * If this {@code ProtectionDomain} was constructed with
+ * {@link #ProtectionDomain(CodeSource, PermissionCollection, ClassLoader, Principal[])}
+ * , the specified permission is checked against the policy and the
+ * permission collection provided in the constructor.
+ *
+ * @param permission
+ * the permission to check against the domain.
+ * @return {@code true} if the specified {@code permission} is implied by
+ * this {@code ProtectionDomain}, {@code false} otherwise.
+ */
+ public boolean implies(Permission permission) {
+ // First, test with the Policy, as the default Policy.implies()
+ // checks for both dynamic and static collections of the
+ // ProtectionDomain passed...
+ if (dynamicPerms
+ && Policy.getAccessiblePolicy().implies(this, permission)) {
+ return true;
+ }
+
+ // ... and we get here if
+ // either the permissions are static
+ // or Policy.implies() did not check for static permissions
+ // or the permission is not implied
+ return permissions == null ? false : permissions.implies(permission);
+ }
+
+ /**
+ * Returns a string containing a concise, human-readable description of the
+ * this {@code ProtectionDomain}.
+ *
+ * @return a printable representation for this {@code ProtectionDomain}.
+ */
+ @Override
+ public String toString() {
+ StringBuilder buf = new StringBuilder(200);
+ buf.append("ProtectionDomain\n"); //$NON-NLS-1$
+ buf.append("CodeSource=").append( //$NON-NLS-1$
+ codeSource == null ? "<null>" : codeSource.toString()).append( //$NON-NLS-1$
+ "\n"); //$NON-NLS-1$
+ buf.append("ClassLoader=").append( //$NON-NLS-1$
+ classLoader == null ? "<null>" : classLoader.toString()) //$NON-NLS-1$
+ .append("\n"); //$NON-NLS-1$
+ if (principals == null || principals.length == 0) {
+ buf.append("<no principals>\n"); //$NON-NLS-1$
+ } else {
+ buf.append("Principals: <\n"); //$NON-NLS-1$
+ for (int i = 0; i < principals.length; i++) {
+ buf.append("\t").append( //$NON-NLS-1$
+ principals[i] == null ? "<null>" : principals[i] //$NON-NLS-1$
+ .toString()).append("\n"); //$NON-NLS-1$
+ }
+ buf.append(">"); //$NON-NLS-1$
+ }
+
+ //permissions here
+ buf.append("Permissions:\n"); //$NON-NLS-1$
+ if (permissions == null) {
+ buf.append("\t\t<no static permissions>\n"); //$NON-NLS-1$
+ } else {
+ buf.append("\t\tstatic: ").append(permissions.toString()).append( //$NON-NLS-1$
+ "\n"); //$NON-NLS-1$
+ }
+
+ if (dynamicPerms) {
+ if (Policy.isSet()) {
+ PermissionCollection perms;
+ perms = Policy.getAccessiblePolicy().getPermissions(this);
+ if (perms == null) {
+ buf.append("\t\t<no dynamic permissions>\n"); //$NON-NLS-1$
+ } else {
+ buf.append("\t\tdynamic: ").append(perms.toString()) //$NON-NLS-1$
+ .append("\n"); //$NON-NLS-1$
+ }
+ } else {
+ buf.append("\t\t<no dynamic permissions>\n"); //$NON-NLS-1$
+ }
+ }
+ return buf.toString();
+ }
+}
diff --git a/luni/src/main/java/java/security/Provider.java b/luni/src/main/java/java/security/Provider.java
new file mode 100644
index 0000000..cf9c94d
--- /dev/null
+++ b/luni/src/main/java/java/security/Provider.java
@@ -0,0 +1,1164 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.NotActiveException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.harmony.luni.util.TwoKeyHashMap;
+import org.apache.harmony.security.Util;
+import org.apache.harmony.security.fortress.Services;
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * {@code Provider} is the abstract superclass for all security providers in the
+ * Java security infrastructure.
+ */
+public abstract class Provider extends Properties {
+ private static final long serialVersionUID = -4298000515446427739L;
+
+ private String name;
+
+ private double version;
+
+ // String representation of the provider version number.
+ private transient String versionString;
+
+ private String info;
+
+ //The provider preference order number.
+ // Equals -1 for non registered provider.
+ private transient int providerNumber = -1;
+
+ // Contains "Service.Algorithm" and Provider.Service classes added using
+ // putService()
+ private transient TwoKeyHashMap<String, String, Service> serviceTable;
+
+ // Contains "Service.Alias" and Provider.Service classes added using
+ // putService()
+ private transient TwoKeyHashMap<String, String, Service> aliasTable;
+
+ // Contains "Service.Algorithm" and Provider.Service classes added using
+ // put()
+ private transient TwoKeyHashMap<String, String, Service> propertyServiceTable;
+
+ // Contains "Service.Alias" and Provider.Service classes added using put()
+ private transient TwoKeyHashMap<String, String, Service> propertyAliasTable;
+
+ // The properties changed via put()
+ private transient Properties changedProperties;
+
+ // For getService(String type, String algorithm) optimization:
+ // previous result
+ private transient Provider.Service returnedService;
+ // previous parameters
+ private transient String lastAlgorithm;
+ // last name
+ private transient String lastServiceName;
+
+ // For getServices() optimization:
+ private transient Set<Service> lastServicesSet;
+
+ // For getService(String type) optimization:
+ private transient String lastType;
+ // last Service found by type
+ private transient Provider.Service lastServicesByType;
+
+ /**
+ * Constructs a new instance of {@code Provider} with its name, version and
+ * description.
+ *
+ * @param name
+ * the name of the provider.
+ * @param version
+ * the version of the provider.
+ * @param info
+ * a description of the provider.
+ */
+ protected Provider(String name, double version, String info) {
+ this.name = name;
+ this.version = version;
+ this.info = info;
+ versionString = String.valueOf(version);
+ putProviderInfo();
+ }
+
+ /**
+ * Returns the name of this provider.
+ *
+ * @return the name of this provider.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns the version number for the services being provided.
+ *
+ * @return the version number for the services being provided.
+ */
+ public double getVersion() {
+ return version;
+ }
+
+ /**
+ * Returns a description of the services being provided.
+ *
+ * @return a description of the services being provided.
+ */
+ public String getInfo() {
+ return info;
+ }
+
+ /**
+ * Returns a string containing a concise, human-readable description of
+ * this {@code Provider} including its name and its version.
+ *
+ * @return a printable representation for this {@code Provider}.
+ */
+ @Override
+ public String toString() {
+ return name + " version " + version; //$NON-NLS-1$
+ }
+
+ /**
+ * Clears all properties used to look up services implemented by this
+ * {@code Provider}.
+ * <p>
+ * If a {@code SecurityManager} is installed, code calling this method needs
+ * the {@code SecurityPermission} {@code clearProviderProperties.NAME}
+ * (where NAME is the provider name) to be granted, otherwise a {@code
+ * SecurityException} will be thrown.
+ *
+ * @throws SecurityException
+ * if a {@code SecurityManager} is installed and the caller does
+ * not have permission to invoke this method.
+ */
+ @Override
+ public synchronized void clear() {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkSecurityAccess("clearProviderProperties." + name); //$NON-NLS-1$
+ }
+ super.clear();
+ if (serviceTable != null) {
+ serviceTable.clear();
+ }
+ if (propertyServiceTable != null) {
+ propertyServiceTable.clear();
+ }
+ if (aliasTable != null) {
+ aliasTable.clear();
+ }
+ if (propertyAliasTable != null) {
+ propertyAliasTable.clear();
+ }
+ // BEGIN android-changed
+ changedProperties = null;
+ // END android-changed
+ putProviderInfo();
+ if (providerNumber != -1) {
+ // if registered then refresh Services
+ Services.setNeedRefresh();
+ }
+ servicesChanged();
+ }
+
+ @Override
+ public synchronized void load(InputStream inStream) throws IOException {
+ Properties tmp = new Properties();
+ tmp.load(inStream);
+ myPutAll(tmp);
+ }
+
+ /**
+ * Copies all from the provided map to this {@code Provider}.
+ * <p>
+ * If a {@code SecurityManager} is installed, code calling this method needs
+ * the {@code SecurityPermission} {@code putProviderProperty.NAME} (where
+ * NAME is the provider name) to be granted, otherwise a {@code
+ * SecurityException} will be thrown.
+ *
+ * @param t
+ * the mappings to copy to this provider.
+ * @throws SecurityException
+ * if a {@code SecurityManager} is installed and the caller does
+ * not have permission to invoke this method.
+ */
+ @Override
+ public synchronized void putAll(Map<?,?> t) {
+
+ // Implementation note:
+ // checkSecurityAccess method call is NOT specified
+ // Do it as in put(Object key, Object value).
+
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkSecurityAccess("putProviderProperty." + name); //$NON-NLS-1$
+ }
+ myPutAll(t);
+ }
+
+ private void myPutAll(Map<?,?> t) {
+ if (changedProperties == null) {
+ changedProperties = new Properties();
+ }
+ Iterator<? extends Map.Entry<?, ?>> it = t.entrySet().iterator();
+ Object key;
+ Object value;
+ while (it.hasNext()) {
+ Map.Entry<?, ?> entry = it.next();
+ key = entry.getKey();
+ if (key instanceof String && ((String) key).startsWith("Provider.")) { //$NON-NLS-1$
+ // Provider service type is reserved
+ continue;
+ }
+ value = entry.getValue();
+ super.put(key, value);
+ if (changedProperties.remove(key) == null) {
+ removeFromPropertyServiceTable(key);
+ }
+ changedProperties.put(key, value);
+ }
+ if (providerNumber != -1) {
+ // if registered then refresh Services
+ Services.setNeedRefresh();
+ }
+ }
+
+ @Override
+ public synchronized Set<Map.Entry<Object,Object>> entrySet() {
+ return Collections.unmodifiableSet(super.entrySet());
+ }
+
+ @Override
+ public Set<Object> keySet() {
+ return Collections.unmodifiableSet(super.keySet());
+ }
+
+ @Override
+ public Collection<Object> values() {
+ return Collections.unmodifiableCollection(super.values());
+ }
+
+ /**
+ * Maps the specified {@code key} property name to the specified {@code
+ * value}.
+ * <p>
+ * If a {@code SecurityManager} is installed, code calling this method needs
+ * the {@code SecurityPermission} {@code putProviderProperty.NAME} (where
+ * NAME is the provider name) to be granted, otherwise a {@code
+ * SecurityException} will be thrown.
+ *
+ * @param key
+ * the name of the property.
+ * @param value
+ * the value of the property.
+ * @return the value that was previously mapped to the specified {@code key}
+ * ,or {@code null} if it did not have one.
+ * @throws SecurityException
+ * if a {@code SecurityManager} is installed and the caller does
+ * not have permission to invoke this method.
+ */
+ @Override
+ public synchronized Object put(Object key, Object value) {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkSecurityAccess("putProviderProperty." + name); //$NON-NLS-1$
+ }
+ if (key instanceof String && ((String) key).startsWith("Provider.")) { //$NON-NLS-1$
+ // Provider service type is reserved
+ return null;
+ }
+ if (providerNumber != -1) {
+ // if registered then refresh Services
+ Services.setNeedRefresh();
+ }
+ if (changedProperties != null && changedProperties.remove(key) == null) {
+ removeFromPropertyServiceTable(key);
+ }
+ if (changedProperties == null) {
+ changedProperties = new Properties();
+ }
+ changedProperties.put(key, value);
+ return super.put(key, value);
+ }
+
+ /**
+ * Removes the specified {@code key} and its associated value from this
+ * {@code Provider}.
+ * <p>
+ * If a {@code SecurityManager} is installed, code calling this method needs
+ * the {@code SecurityPermission} {@code removeProviderProperty.NAME} (where
+ * NAME is the provider name) to be granted, otherwise a {@code
+ * SecurityException} will be thrown.
+ *
+ * @param key
+ * the name of the property
+ * @return the value that was mapped to the specified {@code key} ,or
+ * {@code null} if no mapping was present
+ * @throws SecurityException
+ * if a {@code SecurityManager} is installed and the caller does
+ * not have the permission to invoke this method.
+ */
+ @Override
+ public synchronized Object remove(Object key) {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkSecurityAccess("removeProviderProperty." + name); //$NON-NLS-1$
+ }
+ if (key instanceof String && ((String) key).startsWith("Provider.")) { //$NON-NLS-1$
+ // Provider service type is reserved
+ return null;
+ }
+ if (providerNumber != -1) {
+ // if registered then refresh Services
+ Services.setNeedRefresh();
+ }
+ if (changedProperties != null && changedProperties.remove(key) == null) {
+ removeFromPropertyServiceTable(key);
+ // BEGIN android-added
+ if (changedProperties.size() == 0) {
+ changedProperties = null;
+ }
+ // END android-added
+ }
+ return super.remove(key);
+ }
+
+ /**
+ * Returns true if this provider implements the given algorithm. Caller
+ * must specify the cryptographic service and specify constraints via the
+ * attribute name and value.
+ *
+ * @param serv
+ * Crypto service.
+ * @param alg
+ * Algorithm or type.
+ * @param attribute
+ * The attribute name or {@code null}.
+ * @param val
+ * The attribute value.
+ * @return
+ */
+ boolean implementsAlg(String serv, String alg, String attribute, String val) {
+ String servAlg = serv + "." + alg; //$NON-NLS-1$
+ String prop = getPropertyIgnoreCase(servAlg);
+ if (prop == null) {
+ alg = getPropertyIgnoreCase("Alg.Alias." + servAlg); //$NON-NLS-1$
+ if (alg != null) {
+ servAlg = serv + "." + alg; //$NON-NLS-1$
+ prop = getPropertyIgnoreCase(servAlg);
+ }
+ }
+ if (prop != null) {
+ if (attribute == null) {
+ return true;
+ }
+ return checkAttribute(servAlg, attribute, val);
+ }
+ return false;
+ }
+
+ // Returns true if this provider has the same value as is given for the
+ // given attribute
+ private boolean checkAttribute(String servAlg, String attribute, String val) {
+
+ String attributeValue = getPropertyIgnoreCase(servAlg + ' ' + attribute);
+ if (attributeValue != null) {
+ if (Util.equalsIgnoreCase(attribute,"KeySize")) { //$NON-NLS-1$
+ // BEGIN android-changed
+ if (Integer.parseInt(attributeValue) >= Integer.parseInt(val)) {
+ return true;
+ }
+ // END android-changed
+ } else { // other attributes
+ if (Util.equalsIgnoreCase(attributeValue, val)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ *
+ * Set the provider preference order number.
+ *
+ * @param n
+ */
+ void setProviderNumber(int n) {
+ providerNumber = n;
+ }
+
+ /**
+ *
+ * Get the provider preference order number.
+ *
+ * @return
+ */
+ int getProviderNumber() {
+ return providerNumber;
+ }
+
+ /**
+ * Get the service of the specified type
+ *
+ */
+ synchronized Provider.Service getService(String type) {
+ updatePropertyServiceTable();
+ if (lastServicesByType != null && type.equals(lastType)) {
+ return lastServicesByType;
+ }
+ Provider.Service service;
+ for (Iterator<Service> it = getServices().iterator(); it.hasNext();) {
+ service = it.next();
+ if (type.equals(service.type)) {
+ lastType = type;
+ lastServicesByType = service;
+ return service;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the service with the specified {@code type} implementing the
+ * specified {@code algorithm}, or {@code null} if no such implementation
+ * exists.
+ * <p>
+ * If two services match the requested type and algorithm, the one added
+ * with the {@link #putService(Service)} is returned (as opposed to the one
+ * added via {@link #put(Object, Object)}.
+ *
+ * @param type
+ * the type of the service (for example {@code KeyPairGenerator})
+ * @param algorithm
+ * the algorithm name (case insensitive)
+ * @return the requested service, or {@code null} if no such implementation
+ * exists
+ */
+ public synchronized Provider.Service getService(String type,
+ String algorithm) {
+ if (type == null || algorithm == null) {
+ throw new NullPointerException();
+ }
+
+ if (type.equals(lastServiceName)
+ && Util.equalsIgnoreCase(algorithm, lastAlgorithm)) {
+ return returnedService;
+ }
+
+ String alg = Util.toUpperCase(algorithm);
+ Object o = null;
+ if (serviceTable != null) {
+ o = serviceTable.get(type, alg);
+ }
+ if (o == null && aliasTable != null) {
+ o = aliasTable.get(type, alg);
+ }
+ if (o == null) {
+ updatePropertyServiceTable();
+ }
+ if (o == null && propertyServiceTable != null) {
+ o = propertyServiceTable.get(type, alg);
+ }
+ if (o == null && propertyAliasTable != null) {
+ o = propertyAliasTable.get(type, alg);
+ }
+
+ if (o != null) {
+ lastServiceName = type;
+ lastAlgorithm = algorithm;
+ returnedService = (Provider.Service) o;
+ return returnedService;
+ }
+ return null;
+ }
+
+ /**
+ * Returns an unmodifiable {@code Set} of all services registered by this
+ * provider.
+ *
+ * @return an unmodifiable {@code Set} of all services registered by this
+ * provider
+ */
+ public synchronized Set<Provider.Service> getServices() {
+ updatePropertyServiceTable();
+ if (lastServicesSet != null) {
+ return lastServicesSet;
+ }
+ if (serviceTable != null) {
+ lastServicesSet = new HashSet<Service>(serviceTable.values());
+ } else {
+ lastServicesSet = new HashSet<Service>();
+ }
+ if (propertyServiceTable != null) {
+ lastServicesSet.addAll(propertyServiceTable.values());
+ }
+ lastServicesSet = Collections.unmodifiableSet(lastServicesSet);
+ return lastServicesSet;
+ }
+
+ /**
+ * Adds a {@code Service} to this {@code Provider}. If a service with the
+ * same name was registered via this method, it is replace.
+ * <p>
+ * If a {@code SecurityManager} is installed, code calling this method needs
+ * the {@code SecurityPermission} {@code putProviderProperty.NAME} (where
+ * NAME is the provider name) to be granted, otherwise a {@code
+ * SecurityException} will be thrown.
+ *
+ * @param s
+ * the {@code Service} to register
+ * @throws SecurityException
+ * if a {@code SecurityManager} is installed and the caller does
+ * not have permission to invoke this method
+ */
+ protected synchronized void putService(Provider.Service s) {
+ if (s == null) {
+ throw new NullPointerException();
+ }
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkSecurityAccess("putProviderProperty." + name); //$NON-NLS-1$
+ }
+ if ("Provider".equals(s.getType())) { // Provider service type cannot be //$NON-NLS-1$
+ // added
+ return;
+ }
+ servicesChanged();
+ if (serviceTable == null) {
+ serviceTable = new TwoKeyHashMap<String, String, Service>(128);
+ }
+ serviceTable.put(s.type, Util.toUpperCase(s.algorithm), s);
+ if (s.aliases != null) {
+ if (aliasTable == null) {
+ aliasTable = new TwoKeyHashMap<String, String, Service>(256);
+ }
+ for (Iterator<String> it = s.getAliases(); it.hasNext();) {
+ aliasTable.put(s.type, Util.toUpperCase(it.next()), s);
+ }
+ }
+ serviceInfoToProperties(s);
+ }
+
+ /**
+ * Removes a previously registered {@code Service} from this {@code
+ * Provider}.
+ * <p>
+ * If a {@code SecurityManager} is installed, code calling this method needs
+ * the {@code SecurityPermission} {@code removeProviderProperty.NAME} (where
+ * NAME is the provider name) to be granted, otherwise a {@code
+ * SecurityException} will be thrown.
+ *
+ * @param s
+ * the {@code Service} to remove
+ * @throws SecurityException
+ * if a {@code SecurityManager} is installed and the caller does
+ * not have permission to invoke this method
+ * @throws NullPointerException
+ * if {@code s} is {@code null}
+ */
+ protected synchronized void removeService(Provider.Service s) {
+ if (s == null) {
+ throw new NullPointerException();
+ }
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkSecurityAccess("removeProviderProperty." + name); //$NON-NLS-1$
+ }
+ servicesChanged();
+ if (serviceTable != null) {
+ serviceTable.remove(s.type, Util.toUpperCase(s.algorithm));
+ }
+ if (aliasTable != null && s.aliases != null) {
+ for (Iterator<String> it = s.getAliases(); it.hasNext();) {
+ aliasTable.remove(s.type, Util.toUpperCase(it.next()));
+ }
+ }
+ serviceInfoFromProperties(s);
+ }
+
+ // Add Service information to the provider's properties.
+ private void serviceInfoToProperties(Provider.Service s) {
+ super.put(s.type + "." + s.algorithm, s.className); //$NON-NLS-1$
+ if (s.aliases != null) {
+ for (Iterator<String> i = s.aliases.iterator(); i.hasNext();) {
+ super.put("Alg.Alias." + s.type + "." + i.next(), s.algorithm); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+ if (s.attributes != null) {
+ for (Iterator<Map.Entry<String, String>> i = s.attributes.entrySet().iterator(); i.hasNext();) {
+ Map.Entry<String, String> entry = i.next();
+ super.put(s.type + "." + s.algorithm + " " + entry.getKey(), //$NON-NLS-1$ //$NON-NLS-2$
+ entry.getValue());
+ }
+ }
+ if (providerNumber != -1) {
+ // if registered then refresh Services
+ Services.setNeedRefresh();
+ }
+ }
+
+ // Remove Service information from the provider's properties.
+ private void serviceInfoFromProperties(Provider.Service s) {
+ super.remove(s.type + "." + s.algorithm); //$NON-NLS-1$
+ if (s.aliases != null) {
+ for (Iterator<String> i = s.aliases.iterator(); i.hasNext();) {
+ super.remove("Alg.Alias." + s.type + "." + i.next()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+ if (s.attributes != null) {
+ for (Iterator<Map.Entry<String, String>> i = s.attributes.entrySet().iterator(); i.hasNext();) {
+ Map.Entry<String, String> entry = i.next();
+ super.remove(s.type + "." + s.algorithm + " " + entry.getKey()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+ if (providerNumber != -1) {
+ // if registered then refresh Services
+ Services.setNeedRefresh();
+ }
+ }
+
+ // Remove property information from provider Services
+ private void removeFromPropertyServiceTable(Object key) {
+ if (key == null || !(key instanceof String)) {
+ return;
+ }
+ String k = (String) key;
+ if (k.startsWith("Provider.")) { // Provider service type is reserved //$NON-NLS-1$
+ return;
+ }
+ Provider.Service s;
+ String serviceName;
+ String algorithm = null;
+ String attribute = null;
+ int i;
+ if (k.startsWith("Alg.Alias.")) { // Alg.Alias.<crypto_service>.<aliasName>=<standardName> //$NON-NLS-1$
+ String aliasName;
+ String service_alias = k.substring(10);
+ i = service_alias.indexOf('.');
+ serviceName = service_alias.substring(0, i);
+ aliasName = service_alias.substring(i + 1);
+ if (propertyAliasTable != null) {
+ propertyAliasTable.remove(serviceName, Util.toUpperCase(aliasName));
+ }
+ if (propertyServiceTable != null) {
+ for (Iterator<Service> it = propertyServiceTable.values().iterator(); it
+ .hasNext();) {
+ s = it.next();
+ if (s.aliases.contains(aliasName)) {
+ s.aliases.remove(aliasName);
+ return;
+ }
+ }
+ }
+ return;
+ }
+ int j = k.indexOf('.');
+ if (j == -1) { // unknown format
+ return;
+ }
+
+ i = k.indexOf(' ');
+ if (i == -1) { // <crypto_service>.<algorithm_or_type>=<className>
+ serviceName = k.substring(0, j);
+ algorithm = k.substring(j + 1);
+ if (propertyServiceTable != null) {
+ Provider.Service ser = propertyServiceTable.remove(serviceName, Util.toUpperCase(algorithm));
+ if (ser != null && propertyAliasTable != null
+ && ser.aliases != null) {
+ for (Iterator<String> it = ser.aliases.iterator(); it.hasNext();) {
+ propertyAliasTable.remove(serviceName, Util.toUpperCase(it
+ .next()));
+ }
+ }
+ }
+ } else { // <crypto_service>.<algorithm_or_type>
+ // <attribute_name>=<attrValue>
+ attribute = k.substring(i + 1);
+ serviceName = k.substring(0, j);
+ algorithm = k.substring(j + 1, i);
+ if (propertyServiceTable != null) {
+ Object o = propertyServiceTable.get(serviceName, Util.toUpperCase(algorithm));
+ if (o != null) {
+ s = (Provider.Service) o;
+ s.attributes.remove(attribute);
+ }
+ }
+ }
+ }
+
+ // Update provider Services if the properties was changed
+ private void updatePropertyServiceTable() {
+ Object _key;
+ Object _value;
+ Provider.Service s;
+ String serviceName;
+ String algorithm;
+ if (changedProperties == null || changedProperties.isEmpty()) {
+ return;
+ }
+ for (Iterator<Map.Entry<Object, Object>> it = changedProperties.entrySet().iterator(); it
+ .hasNext();) {
+ Map.Entry<Object, Object> entry = it.next();
+ _key = entry.getKey();
+ _value = entry.getValue();
+ if (_key == null || _value == null || !(_key instanceof String)
+ || !(_value instanceof String)) {
+ continue;
+ }
+ String key = (String) _key;
+ String value = (String) _value;
+ if (key.startsWith("Provider")) { // Provider service type is reserved //$NON-NLS-1$
+ continue;
+ }
+ int i;
+ if (key.startsWith("Alg.Alias.")) { // Alg.Alias.<crypto_service>.<aliasName>=<standardName> //$NON-NLS-1$
+ String aliasName;
+ String service_alias = key.substring(10);
+ i = service_alias.indexOf('.');
+ serviceName = service_alias.substring(0, i);
+ aliasName = service_alias.substring(i + 1);
+ algorithm = value;
+ String algUp = Util.toUpperCase(algorithm);
+ Object o = null;
+ if (propertyServiceTable == null) {
+ propertyServiceTable = new TwoKeyHashMap<String, String, Service>(128);
+ } else {
+ o = propertyServiceTable.get(serviceName, algUp);
+ }
+ if (o != null) {
+ s = (Provider.Service) o;
+ // BEGIN android-changed
+ s.addAlias(aliasName);
+ // END android-changed
+ if (propertyAliasTable == null) {
+ propertyAliasTable = new TwoKeyHashMap<String, String, Service>(256);
+ }
+ propertyAliasTable.put(serviceName,
+ Util.toUpperCase(aliasName), s);
+ } else {
+ String className = (String) changedProperties
+ .get(serviceName + "." + algorithm); //$NON-NLS-1$
+ if (className != null) {
+ List<String> l = new ArrayList<String>();
+ l.add(aliasName);
+ s = new Provider.Service(this, serviceName, algorithm,
+ className, l, new HashMap<String, String>());
+ propertyServiceTable.put(serviceName, algUp, s);
+ if (propertyAliasTable == null) {
+ propertyAliasTable = new TwoKeyHashMap<String, String, Service>(256);
+ }
+ propertyAliasTable.put(serviceName, Util.toUpperCase(aliasName
+ ), s);
+ }
+ }
+ continue;
+ }
+ int j = key.indexOf('.');
+ if (j == -1) { // unknown format
+ continue;
+ }
+ i = key.indexOf(' ');
+ if (i == -1) { // <crypto_service>.<algorithm_or_type>=<className>
+ serviceName = key.substring(0, j);
+ algorithm = key.substring(j + 1);
+ String alg = Util.toUpperCase(algorithm);
+ Object o = null;
+ if (propertyServiceTable != null) {
+ o = propertyServiceTable.get(serviceName, alg);
+ }
+ if (o != null) {
+ s = (Provider.Service) o;
+ s.className = value;
+ } else {
+ // BEGIN android-changed
+ s = new Provider.Service(this, serviceName, algorithm,
+ value, Collections.<String>emptyList(),
+ Collections.<String,String>emptyMap());
+ // END android-changed
+ if (propertyServiceTable == null) {
+ propertyServiceTable = new TwoKeyHashMap<String, String, Service>(128);
+ }
+ propertyServiceTable.put(serviceName, alg, s);
+
+ }
+ } else { // <crypto_service>.<algorithm_or_type>
+ // <attribute_name>=<attrValue>
+ serviceName = key.substring(0, j);
+ algorithm = key.substring(j + 1, i);
+ String attribute = key.substring(i + 1);
+ String alg = Util.toUpperCase(algorithm);
+ Object o = null;
+ if (propertyServiceTable != null) {
+ o = propertyServiceTable.get(serviceName, alg);
+ }
+ if (o != null) {
+ s = (Provider.Service) o;
+ // BEGIN android-changed
+ s.putAttribute(attribute, value);
+ // END android-changed
+ } else {
+ String className = (String) changedProperties
+ .get(serviceName + "." + algorithm); //$NON-NLS-1$
+ if (className != null) {
+ Map<String, String> m = new HashMap<String, String>();
+ m.put(attribute, value);
+ s = new Provider.Service(this, serviceName, algorithm,
+ className, new ArrayList<String>(), m);
+ if (propertyServiceTable == null) {
+ propertyServiceTable = new TwoKeyHashMap<String, String, Service>(128);
+ }
+ propertyServiceTable.put(serviceName, alg, s);
+ }
+ }
+ }
+ }
+ servicesChanged();
+ // BEGIN android-changed
+ changedProperties = null;
+ // END android-changed
+ }
+
+ private void servicesChanged() {
+ lastServicesByType = null;
+ lastServiceName = null;
+ lastServicesSet = null;
+ }
+
+ // These attributes should be placed in each Provider object:
+ // Provider.id name, Provider.id version, Provider.id info,
+ // Provider.id className
+ @SuppressWarnings("nls")
+ private void putProviderInfo() {
+ super.put("Provider.id name", null != name ? name : "null");
+ super.put("Provider.id version", versionString);
+ super.put("Provider.id info", null != info ? info : "null");
+ super.put("Provider.id className", this.getClass().getName());
+ }
+
+ // Searches for the property with the specified key in the provider
+ // properties. Key is not case-sensitive.
+ //
+ // @param prop
+ // @return the property value with the specified key value.
+ private String getPropertyIgnoreCase(String key) {
+ String res = getProperty(key);
+ if (res != null) {
+ return res;
+ }
+ for (Enumeration<?> e = propertyNames(); e.hasMoreElements();) {
+ String pname = (String) e.nextElement();
+ if (Util.equalsIgnoreCase(key, pname)) {
+ return getProperty(pname);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * {@code Service} represents a service in the Java Security infrastructure.
+ * Each service describes its type, the algorithm it implements, to which
+ * provider it belongs and other properties.
+ */
+ public static class Service {
+ // The provider
+ private Provider provider;
+
+ // The type of this service
+ private String type;
+
+ // The algorithm name
+ private String algorithm;
+
+ // The class implementing this service
+ private String className;
+
+ // The aliases
+ private List<String> aliases;
+
+ // The attributes
+ private Map<String,String> attributes;
+
+ // Service implementation
+ private Class<?> implementation;
+
+ // For newInstance() optimization
+ private String lastClassName;
+
+ /**
+ * Constructs a new instance of {@code Service} with the given
+ * attributes.
+ *
+ * @param provider
+ * the provider to which this service belongs.
+ * @param type
+ * the type of this service (for example {@code
+ * KeyPairGenerator}).
+ * @param algorithm
+ * the algorithm this service implements.
+ * @param className
+ * the name of the class implementing this service.
+ * @param aliases
+ * {@code List} of aliases for the algorithm name, or {@code
+ * null} if the implemented algorithm has no aliases.
+ * @param attributes
+ * {@code Map} of additional attributes, or {@code null} if
+ * this {@code Service} has no attributed.
+ * @throws NullPointerException
+ * if {@code provider, type, algorithm} or {@code className}
+ * is {@code null}.
+ */
+ public Service(Provider provider, String type, String algorithm,
+ String className, List<String> aliases, Map<String, String> attributes) {
+ if (provider == null || type == null || algorithm == null
+ || className == null) {
+ throw new NullPointerException();
+ }
+ this.provider = provider;
+ this.type = type;
+ this.algorithm = algorithm;
+ this.className = className;
+ // BEGIN android-changed
+ this.aliases = ((aliases != null) && (aliases.size() == 0))
+ ? Collections.<String>emptyList() : aliases;
+ this.attributes =
+ ((attributes != null) && (attributes.size() == 0))
+ ? Collections.<String,String>emptyMap() : attributes;
+ // END android-changed
+ }
+
+ // BEGIN android-added
+ /**
+ * Adds an alias.
+ *
+ * @param alias the alias to add
+ */
+ /*package*/ void addAlias(String alias) {
+ if ((aliases == null) || (aliases.size() == 0)) {
+ aliases = new ArrayList<String>();
+ }
+ aliases.add(alias);
+ }
+
+ /**
+ * Puts a new attribute mapping.
+ *
+ * @param name the attribute name.
+ * @param value the attribute value.
+ */
+ /*package*/ void putAttribute(String name, String value) {
+ if ((attributes == null) || (attributes.size() == 0)) {
+ attributes = new HashMap<String,String>();
+ }
+ attributes.put(name, value);
+ }
+ // END android-added
+
+ /**
+ * Returns the type of this {@code Service}. For example {@code
+ * KeyPairGenerator}.
+ *
+ * @return the type of this {@code Service}.
+ */
+ public final String getType() {
+ return type;
+ }
+
+ /**
+ * Returns the name of the algorithm implemented by this {@code
+ * Service}.
+ *
+ * @return the name of the algorithm implemented by this {@code
+ * Service}.
+ */
+ public final String getAlgorithm() {
+ return algorithm;
+ }
+
+ /**
+ * Returns the {@code Provider} this {@code Service} belongs to.
+ *
+ * @return the {@code Provider} this {@code Service} belongs to.
+ */
+ public final Provider getProvider() {
+ return provider;
+ }
+
+ /**
+ * Returns the name of the class implementing this {@code Service}.
+ *
+ * @return the name of the class implementing this {@code Service}.
+ */
+ public final String getClassName() {
+ return className;
+ }
+
+ /**
+ * Returns the value of the attribute with the specified {@code name}.
+ *
+ * @param name
+ * the name of the attribute.
+ * @return the value of the attribute, or {@code null} if no attribute
+ * with the given name is set.
+ * @throws NullPointerException
+ * if {@code name} is {@code null}.
+ */
+ public final String getAttribute(String name) {
+ if (name == null) {
+ throw new NullPointerException();
+ }
+ if (attributes == null) {
+ return null;
+ }
+ return attributes.get(name);
+ }
+
+ Iterator<String> getAliases() {
+ if(aliases == null){
+ aliases = new ArrayList<String>(0);
+ }
+ return aliases.iterator();
+ }
+
+ /**
+ * Creates and returns a new instance of the implementation described by
+ * this {@code Service}.
+ *
+ * @param constructorParameter
+ * the parameter that is used by the constructor, or {@code
+ * null} if the implementation does not declare a constructor
+ * parameter.
+ * @return a new instance of the implementation described by this
+ * {@code Service}.
+ * @throws NoSuchAlgorithmException
+ * if the instance could not be constructed.
+ * @throws InvalidParameterException
+ * if the implementation does not support the specified
+ * {@code constructorParameter}.
+ */
+ public Object newInstance(Object constructorParameter)
+ throws NoSuchAlgorithmException {
+ if (implementation == null || !className.equals(lastClassName)) {
+ NoSuchAlgorithmException result = AccessController
+ .doPrivileged(new PrivilegedAction<NoSuchAlgorithmException>() {
+ public NoSuchAlgorithmException run() {
+ ClassLoader cl = provider.getClass()
+ .getClassLoader();
+ if (cl == null) {
+ cl = ClassLoader.getSystemClassLoader();
+ }
+ try {
+ implementation = Class.forName(className,
+ true, cl);
+ } catch (Exception e) {
+ return new NoSuchAlgorithmException(
+ Messages.getString("security.11", //$NON-NLS-1$
+ new Object[]{type, algorithm, e}));
+ }
+ lastClassName = className;
+ return null;
+ }
+ });
+ if (result != null) {
+ throw result;
+ }
+ }
+ if (constructorParameter == null) {
+ try {
+ return implementation.newInstance();
+ } catch (Exception e) {
+ throw new NoSuchAlgorithmException(Messages.getString("security.199", //$NON-NLS-1$
+ type, algorithm), e);
+ }
+ }
+ if (!supportsParameter(constructorParameter)) {
+ throw new InvalidParameterException(
+ Messages.getString("security.12", type)); //$NON-NLS-1$
+ }
+
+ Class[] parameterTypes = new Class[1];
+ Object[] initargs = { constructorParameter };
+ try {
+ if (Util.equalsIgnoreCase(type,"CertStore")) { //$NON-NLS-1$
+ parameterTypes[0] = Class
+ .forName("java.security.cert.CertStoreParameters"); //$NON-NLS-1$
+ } else {
+ parameterTypes[0] = constructorParameter.getClass();
+ }
+ return implementation.getConstructor(parameterTypes)
+ .newInstance(initargs);
+ } catch (Exception e) {
+ throw new NoSuchAlgorithmException(Messages.getString("security.199", //$NON-NLS-1$
+ type, algorithm), e);
+ }
+ }
+
+ /**
+ * Indicates whether this {@code Service} supports the specified
+ * constructor parameter.
+ *
+ * @param parameter
+ * the parameter to test.
+ * @return {@code true} if this {@code Service} supports the specified
+ * constructor parameter, {@code false} otherwise.
+ */
+ public boolean supportsParameter(Object parameter) {
+ return true;
+ }
+
+ /**
+ * Returns a string containing a concise, human-readable description of
+ * this {@code Service}.
+ *
+ * @return a printable representation for this {@code Service}.
+ */
+ @Override
+ public String toString() {
+ String result = "Provider " + provider.getName() + " Service " //$NON-NLS-1$ //$NON-NLS-2$
+ + type + "." + algorithm + " " + className; //$NON-NLS-1$ //$NON-NLS-2$
+ if (aliases != null) {
+ result = result + "\nAliases " + aliases.toString(); //$NON-NLS-1$
+ }
+ if (attributes != null) {
+ result = result + "\nAttributes " + attributes.toString(); //$NON-NLS-1$
+ }
+ return result;
+ }
+ }
+
+ private void readObject(java.io.ObjectInputStream in) throws NotActiveException, IOException, ClassNotFoundException {
+ in.defaultReadObject();
+ versionString = String.valueOf(version);
+ providerNumber = -1;
+ }
+}
diff --git a/luni/src/main/java/java/security/ProviderException.java b/luni/src/main/java/java/security/ProviderException.java
new file mode 100644
index 0000000..22950f5
--- /dev/null
+++ b/luni/src/main/java/java/security/ProviderException.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * {@code ProviderException} is a general exception, thrown by security {@code
+ * Providers}.
+ *
+ * @see Provider
+ */
+public class ProviderException extends RuntimeException {
+
+ private static final long serialVersionUID = 5256023526693665674L;
+
+ /**
+ * Constructs a new instance of {@code ProviderException} with the given
+ * message.
+ *
+ * @param msg
+ * the detail message for this exception.
+ */
+ public ProviderException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs a new instance of {@code ProviderException}.
+ */
+ public ProviderException() {
+ }
+
+ /**
+ * Constructs a new instance of {@code ProviderException} with the given
+ * message and the cause.
+ *
+ * @param message
+ * the detail message for this exception.
+ * @param cause
+ * the exception which is the cause for this exception.
+ */
+ public ProviderException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructs a new instance of {@code ProviderException} with the cause.
+ *
+ * @param cause
+ * the exception which is the cause for this exception.
+ */
+ public ProviderException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/luni/src/main/java/java/security/PublicKey.java b/luni/src/main/java/java/security/PublicKey.java
new file mode 100644
index 0000000..c197840
--- /dev/null
+++ b/luni/src/main/java/java/security/PublicKey.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * {@code PublicKey} is the common interface for public keys.
+ *
+ * @see PrivateKey
+ */
+public interface PublicKey extends Key {
+ /**
+ * The {@code serialVersionUID} to be compatible with JDK1.1.
+ */
+ public static final long serialVersionUID = 7187392471159151072L;
+}
diff --git a/luni/src/main/java/java/security/SecureClassLoader.java b/luni/src/main/java/java/security/SecureClassLoader.java
new file mode 100644
index 0000000..07bebc9
--- /dev/null
+++ b/luni/src/main/java/java/security/SecureClassLoader.java
@@ -0,0 +1,162 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+
+/**
+ * {@code SecureClassLoader} represents a {@code ClassLoader} which associates
+ * the classes it loads with a code source and provide mechanisms to allow the
+ * relevant permissions to be retrieved.
+ */
+public class SecureClassLoader extends ClassLoader {
+
+ // A cache of ProtectionDomains for a given CodeSource
+ private HashMap<CodeSource, ProtectionDomain> pds = new HashMap<CodeSource, ProtectionDomain>();
+
+ /**
+ * Constructs a new instance of {@code SecureClassLoader}. The default
+ * parent {@code ClassLoader} is used.
+ * <p>
+ * If a {@code SecurityManager} is installed, code calling this constructor
+ * needs the {@code SecurityPermission} {@code checkCreateClassLoader} to be
+ * granted, otherwise a {@code SecurityException} will be thrown.
+ *
+ * @throws SecurityException
+ * if a {@code SecurityManager} is installed and the caller does
+ * not have permission to invoke this constructor.
+ */
+ protected SecureClassLoader() {
+ super();
+ }
+
+ /**
+ * Constructs a new instance of {@code SecureClassLoader} with the specified
+ * parent {@code ClassLoader}.
+ * <p>
+ * If a {@code SecurityManager} is installed, code calling this constructor
+ * needs the {@code SecurityPermission} {@code checkCreateClassLoader} to be
+ * granted, otherwise a {@code SecurityException} will be thrown.
+ *
+ * @param parent
+ * the parent {@code ClassLoader}.
+ * @throws SecurityException
+ * if a {@code SecurityManager} is installed and the caller does
+ * not have permission to invoke this constructor.
+ */
+ protected SecureClassLoader(ClassLoader parent) {
+ super(parent);
+ }
+
+ /**
+ * Returns the {@code PermissionCollection} for the specified {@code
+ * CodeSource}.
+ *
+ * @param codesource
+ * the code source.
+ * @return the {@code PermissionCollection} for the specified {@code
+ * CodeSource}.
+ */
+ protected PermissionCollection getPermissions(CodeSource codesource) {
+ // Do nothing by default, ProtectionDomain will take care about
+ // permissions in dynamic
+ return new Permissions();
+ }
+
+ /**
+ * Constructs a new class from an array of bytes containing a class
+ * definition in class file format with an optional {@code CodeSource}.
+ *
+ * @param name
+ * the name of the new class.
+ * @param b
+ * a memory image of a class file.
+ * @param off
+ * the start offset in b of the class data.
+ * @param len
+ * the length of the class data.
+ * @param cs
+ * the {@code CodeSource}, or {@code null}.
+ * @return a new class.
+ * @throws IndexOutOfBoundsException
+ * if {@code off} or {@code len} are not valid in respect to
+ * {@code b}.
+ * @throws ClassFormatError
+ * if the specified data is not valid class data.
+ * @throws SecurityException
+ * if the package to which this class is to be added, already
+ * contains classes which were signed by different certificates,
+ * or if the class name begins with "java."
+ */
+ protected final Class<?> defineClass(String name, byte[] b, int off, int len,
+ CodeSource cs) {
+ return cs == null ? defineClass(name, b, off, len) : defineClass(name,
+ b, off, len, getPD(cs));
+ }
+
+ /**
+ * Constructs a new class from an array of bytes containing a class
+ * definition in class file format with an optional {@code CodeSource}.
+ *
+ * @param name
+ * the name of the new class.
+ * @param b
+ * a memory image of a class file.
+ * @param cs
+ * the {@code CodeSource}, or {@code null}.
+ * @return a new class.
+ * @throws ClassFormatError
+ * if the specified data is not valid class data.
+ * @throws SecurityException
+ * if the package to which this class is to be added, already
+ * contains classes which were signed by different certificates,
+ * or if the class name begins with "java."
+ */
+ protected final Class<?> defineClass(String name, ByteBuffer b, CodeSource cs) {
+ //FIXME 1.5 - remove b.array(), call super.defineClass(,ByteBuffer,)
+ // directly
+ byte[] data = b.array();
+ return cs == null ? defineClass(name, data, 0, data.length)
+ : defineClass(name, data, 0, data.length, getPD(cs));
+ }
+
+ // Constructs and caches ProtectionDomain for the given CodeSource
+ // object.<br>
+ // It calls {@link getPermissions()} to get a set of permissions.
+ //
+ // @param cs CodeSource object
+ // @return ProtectionDomain for the passed CodeSource object
+ private ProtectionDomain getPD(CodeSource cs) {
+ if (cs == null) {
+ return null;
+ }
+ // need to cache PDs, otherwise every class from a given CodeSource
+ // will have it's own ProtectionDomain, which does not look right.
+ ProtectionDomain pd;
+ synchronized (pds) {
+ if ((pd = pds.get(cs)) != null) {
+ return pd;
+ }
+ PermissionCollection perms = getPermissions(cs);
+ pd = new ProtectionDomain(cs, perms, this, null);
+ pds.put(cs, pd);
+ }
+ return pd;
+ }
+}
diff --git a/luni/src/main/java/java/security/SecureRandom.java b/luni/src/main/java/java/security/SecureRandom.java
new file mode 100644
index 0000000..c697504
--- /dev/null
+++ b/luni/src/main/java/java/security/SecureRandom.java
@@ -0,0 +1,342 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.util.Iterator;
+import java.util.Random;
+import java.util.Set;
+
+import org.apache.harmony.security.fortress.Engine;
+import org.apache.harmony.security.fortress.Services;
+import org.apache.harmony.security.internal.nls.Messages;
+
+import org.apache.harmony.security.provider.crypto.SHA1PRNG_SecureRandomImpl;
+
+/**
+ * {@code SecureRandom} is an engine class which is capable of generating
+ * cryptographically secure pseudo-random numbers.
+ */
+public class SecureRandom extends Random {
+
+ private static final long serialVersionUID = 4940670005562187L;
+
+ // The service name.
+ private static final transient String SERVICE = "SecureRandom"; //$NON-NLS-1$
+
+ // Used to access common engine functionality
+ private static transient Engine engine = new Engine(SERVICE);
+
+ private Provider provider;
+
+ private SecureRandomSpi secureRandomSpi;
+
+ private String algorithm;
+
+ private byte[] state;
+
+ private byte[] randomBytes;
+
+ private int randomBytesUsed;
+
+ private long counter;
+
+ // Internal SecureRandom used for getSeed(int)
+ private static transient SecureRandom internalSecureRandom;
+
+ /**
+ * Constructs a new instance of {@code SecureRandom}. An implementation for
+ * the highest-priority provider is returned. The constructed instance will
+ * not have been seeded.
+ */
+ public SecureRandom() {
+ super(0);
+ Provider.Service service = findService();
+ if (service == null) {
+ this.provider = null;
+ this.secureRandomSpi = new SHA1PRNG_SecureRandomImpl();
+ this.algorithm = "SHA1PRNG"; //$NON-NLS-1$
+ } else {
+ try {
+ this.provider = service.getProvider();
+ this.secureRandomSpi = (SecureRandomSpi)service.newInstance(null);
+ this.algorithm = service.getAlgorithm();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ /**
+ * Constructs a new instance of {@code SecureRandom}. An implementation for
+ * the highest-priority provider is returned. The constructed instance will
+ * be seeded with the parameter.
+ *
+ * @param seed
+ * the seed for this generator.
+ */
+ public SecureRandom(byte[] seed) {
+ this();
+ setSeed(seed);
+ }
+
+ //Find SecureRandom service.
+ private Provider.Service findService() {
+ Set s;
+ Provider.Service service;
+ for (Iterator it1 = Services.getProvidersList().iterator(); it1.hasNext();) {
+ service = ((Provider)it1.next()).getService("SecureRandom"); //$NON-NLS-1$
+ if (service != null) {
+ return service;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Constructs a new instance of {@code SecureRandom} using the given
+ * implementation from the specified provider.
+ *
+ * @param secureRandomSpi
+ * the implementation.
+ * @param provider
+ * the security provider.
+ */
+ protected SecureRandom(SecureRandomSpi secureRandomSpi,
+ Provider provider) {
+ this(secureRandomSpi, provider, "unknown"); //$NON-NLS-1$
+ }
+
+ // Constructor
+ private SecureRandom(SecureRandomSpi secureRandomSpi,
+ Provider provider,
+ String algorithm) {
+ super(0);
+ this.provider = provider;
+ this.algorithm = algorithm;
+ this.secureRandomSpi = secureRandomSpi;
+ }
+
+ /**
+ * Returns a new instance of {@code SecureRandom} that utilizes the
+ * specified algorithm.
+ *
+ * @param algorithm
+ * the name of the algorithm to use.
+ * @return a new instance of {@code SecureRandom} that utilizes the
+ * specified algorithm.
+ * @throws NoSuchAlgorithmException
+ * if the specified algorithm is not available.
+ * @throws NullPointerException
+ * if {@code algorithm} is {@code null}.
+ */
+ public static SecureRandom getInstance(String algorithm)
+ throws NoSuchAlgorithmException {
+ if (algorithm == null) {
+ throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+ }
+ synchronized (engine) {
+ engine.getInstance(algorithm, null);
+ return new SecureRandom((SecureRandomSpi)engine.spi, engine.provider, algorithm);
+ }
+ }
+
+ /**
+ * Returns a new instance of {@code SecureRandom} that utilizes the
+ * specified algorithm from the specified provider.
+ *
+ * @param algorithm
+ * the name of the algorithm to use.
+ * @param provider
+ * the name of the provider.
+ * @return a new instance of {@code SecureRandom} that utilizes the
+ * specified algorithm from the specified provider.
+ * @throws NoSuchAlgorithmException
+ * if the specified algorithm is not available.
+ * @throws NoSuchProviderException
+ * if the specified provider is not available.
+ * @throws NullPointerException
+ * if {@code algorithm} is {@code null}.
+ */
+ public static SecureRandom getInstance(String algorithm, String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException {
+ if ((provider == null) || (provider.length() == 0)) {
+ throw new IllegalArgumentException(
+ Messages.getString("security.02")); //$NON-NLS-1$
+ }
+ Provider p = Security.getProvider(provider);
+ if (p == null) {
+ throw new NoSuchProviderException(Messages.getString("security.03", provider)); //$NON-NLS-1$
+ }
+ return getInstance(algorithm, p);
+ }
+
+ /**
+ * Returns a new instance of {@code SecureRandom} that utilizes the
+ * specified algorithm from the specified provider.
+ *
+ * @param algorithm
+ * the name of the algorithm to use.
+ * @param provider
+ * the security provider.
+ * @return a new instance of {@code SecureRandom} that utilizes the
+ * specified algorithm from the specified provider.
+ * @throws NoSuchAlgorithmException
+ * if the specified algorithm is not available.
+ * @throws NullPointerException
+ * if {@code algorithm} is {@code null}.
+ */
+ public static SecureRandom getInstance(String algorithm, Provider provider)
+ throws NoSuchAlgorithmException {
+ if (provider == null) {
+ throw new IllegalArgumentException(Messages.getString("security.04")); //$NON-NLS-1$
+ }
+ if (algorithm == null) {
+ throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+ }
+ synchronized (engine) {
+ engine.getInstance(algorithm, provider, null);
+ return new SecureRandom((SecureRandomSpi)engine.spi, provider, algorithm);
+ }
+ }
+
+ /**
+ * Returns the provider associated with this {@code SecureRandom}.
+ *
+ * @return the provider associated with this {@code SecureRandom}.
+ */
+ public final Provider getProvider() {
+ return provider;
+ }
+
+ /**
+ * Returns the name of the algorithm of this {@code SecureRandom}.
+ *
+ * @return the name of the algorithm of this {@code SecureRandom}.
+ */
+ public String getAlgorithm() {
+ return algorithm;
+ }
+
+ /**
+ * Reseeds this {@code SecureRandom} instance with the specified {@code
+ * seed}. The seed of this {@code SecureRandom} instance is supplemented,
+ * not replaced.
+ *
+ * @param seed
+ * the new seed.
+ */
+ public synchronized void setSeed(byte[] seed) {
+ secureRandomSpi.engineSetSeed(seed);
+ }
+
+ /**
+ * Reseeds this this {@code SecureRandom} instance with the eight bytes
+ * described by the representation of the given {@code long seed}. The seed
+ * of this {@code SecureRandom} instance is supplemented, not replaced.
+ *
+ * @param seed
+ * the new seed.
+ */
+ @Override
+ public void setSeed(long seed) {
+ if (seed == 0) { // skip call from Random
+ return;
+ }
+ byte[] byteSeed = {
+ (byte)((seed >> 56) & 0xFF),
+ (byte)((seed >> 48) & 0xFF),
+ (byte)((seed >> 40) & 0xFF),
+ (byte)((seed >> 32) & 0xFF),
+ (byte)((seed >> 24) & 0xFF),
+ (byte)((seed >> 16) & 0xFF),
+ (byte)((seed >> 8) & 0xFF),
+ (byte)((seed) & 0xFF)
+ };
+ setSeed(byteSeed);
+ }
+
+ /**
+ * Generates and stores random bytes in the given {@code byte[]} for each
+ * array element.
+ *
+ * @param bytes
+ * the {@code byte[]} to be filled with random bytes.
+ */
+ @Override
+ public synchronized void nextBytes(byte[] bytes) {
+ secureRandomSpi.engineNextBytes(bytes);
+ }
+
+ /**
+ * Generates and returns an {@code int} containing the specified number of
+ * random bits (right justified, with leading zeros).
+ *
+ * @param numBits
+ * number of bits to be generated. An input value should be in
+ * the range [0, 32].
+ * @return an {@code int} containing the specified number of random bits.
+ */
+ @Override
+ protected final int next(int numBits) {
+ if (numBits < 0) {
+ numBits = 0;
+ } else {
+ if (numBits > 32) {
+ numBits = 32;
+ }
+ }
+ int bytes = (numBits+7)/8;
+ byte[] next = new byte[bytes];
+ int ret = 0;
+
+ nextBytes(next);
+ for (int i = 0; i < bytes; i++) {
+ ret = (next[i] & 0xFF) | (ret << 8);
+ }
+ ret = ret >>> (bytes*8 - numBits);
+ return ret;
+ }
+
+ /**
+ * Generates and returns the specified number of seed bytes, computed using
+ * the seed generation algorithm used by this {@code SecureRandom}.
+ *
+ * @param numBytes
+ * the number of seed bytes.
+ * @return the seed bytes
+ */
+ public static byte[] getSeed(int numBytes) {
+ if (internalSecureRandom == null) {
+ internalSecureRandom = new SecureRandom();
+ }
+ return internalSecureRandom.generateSeed(numBytes);
+ }
+
+ /**
+ * Generates and returns the specified number of seed bytes, computed using
+ * the seed generation algorithm used by this {@code SecureRandom}.
+ *
+ * @param numBytes
+ * the number of seed bytes.
+ * @return the seed bytes.
+ */
+ public byte[] generateSeed(int numBytes) {
+ return secureRandomSpi.engineGenerateSeed(numBytes);
+ }
+
+}
diff --git a/luni/src/main/java/java/security/SecureRandomSpi.java b/luni/src/main/java/java/security/SecureRandomSpi.java
new file mode 100644
index 0000000..829464f
--- /dev/null
+++ b/luni/src/main/java/java/security/SecureRandomSpi.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.io.Serializable;
+
+/**
+ * {@code SecureRandomSpi} is the <i>Service Provider Interface</i> (<b>SPI</b>) definition
+ * for {@link SecureRandom}.
+ *
+ * @see SecureRandom
+ */
+public abstract class SecureRandomSpi implements Serializable {
+
+ private static final long serialVersionUID = -2991854161009191830L;
+
+ /**
+ * Reseeds this {@code SecureRandomSpi} instance with the specified {@code
+ * seed}. The seed of this {@code SecureRandomSpi} instance is supplemented,
+ * not replaced.
+ *
+ * @param seed
+ * the new seed.
+ */
+ protected abstract void engineSetSeed(byte[] seed);
+
+ /**
+ * Generates and stores random bytes in the given {@code byte[]} for each
+ * array element.
+ *
+ * @param bytes
+ * the {@code byte[]} to be filled with random bytes.
+ */
+ protected abstract void engineNextBytes(byte[] bytes);
+
+ /**
+ * Generates and returns the specified number of seed bytes, computed using
+ * the seed generation algorithm used by this {@code SecureRandomSpi}.
+ *
+ * @param numBytes
+ * the number of seed bytes.
+ * @return the seed bytes
+ */
+ protected abstract byte[] engineGenerateSeed(int numBytes);
+}
diff --git a/luni/src/main/java/java/security/Security.java b/luni/src/main/java/java/security/Security.java
new file mode 100644
index 0000000..1fea1bd
--- /dev/null
+++ b/luni/src/main/java/java/security/Security.java
@@ -0,0 +1,546 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+// BEGIN android-added
+import java.util.logging.Level;
+import java.util.logging.Logger;
+// END android-added
+import java.util.Enumeration;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.Map.Entry;
+
+import org.apache.harmony.security.Util;
+import org.apache.harmony.security.fortress.Engine;
+import org.apache.harmony.security.fortress.PolicyUtils;
+import org.apache.harmony.security.fortress.SecurityAccess;
+import org.apache.harmony.security.fortress.Services;
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * {@code Security} is the central class in the Java Security API. It manages
+ * the list of security {@code Provider} that have been installed into this
+ * runtime environment.
+ */
+public final class Security {
+
+ // Security properties
+ private static Properties secprops = new Properties();
+
+ // static initialization
+ // - load security properties files
+ // - load statically registered providers
+ // - if no provider description file found then load default providers
+ static {
+ AccessController.doPrivileged(new java.security.PrivilegedAction<Void>() {
+ public Void run() {
+ boolean loaded = false;
+
+ // BEGIN android-added
+ /*
+ * Android only uses a local "security.properties" resource
+ * for configuration. TODO: Reevaluate this decision.
+ */
+ try {
+ InputStream configStream =
+ getClass().getResourceAsStream("security.properties"); //$NON-NLS-1$
+ InputStream input = new BufferedInputStream(configStream);
+ secprops.load(input);
+ loaded = true;
+ configStream.close();
+ } catch (Exception ex) {
+ Logger.global.log(Level.SEVERE,
+ "Could not load Security properties.", ex);
+ }
+ // END android-added
+
+ // BEGIN android-removed
+// if (Util.equalsIgnoreCase("true", secprops.getProperty("security.allowCustomPropertiesFile", "true"))) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+// String securityFile = System.getProperty("java.security.properties"); //$NON-NLS-1$
+// if (securityFile != null) {
+// if (securityFile.startsWith("=")) { // overwrite //$NON-NLS-1$
+// secprops = new Properties();
+// loaded = false;
+// securityFile = securityFile.substring(1);
+// }
+// try {
+// securityFile = PolicyUtils.expand(securityFile, System.getProperties());
+// } catch (PolicyUtils.ExpansionFailedException e) {
+//// System.err.println("Could not load custom Security properties file "
+//// + securityFile +": " + e);
+// }
+// f = new File(securityFile);
+// InputStream is;
+// try {
+// if (f.exists()) {
+// FileInputStream fis = new FileInputStream(f);
+// is = new BufferedInputStream(fis);
+// } else {
+// URL url = new URL(securityFile);
+// is = new BufferedInputStream(url.openStream());
+// }
+// secprops.load(is);
+// loaded = true;
+// is.close();
+// } catch (IOException e) {
+// // System.err.println("Could not load custom Security properties file "
+// // + securityFile +": " + e);
+// }
+// }
+// }
+ // END android-removed
+ if (!loaded) {
+ registerDefaultProviders();
+ }
+ Engine.door = new SecurityDoor();
+ return null;
+ }
+ });
+ }
+
+ /**
+ * This class can't be instantiated.
+ */
+ private Security() {
+ }
+
+ // Register default providers
+ private static void registerDefaultProviders() {
+ secprops.put("security.provider.1", "org.apache.harmony.security.provider.cert.DRLCertFactory"); //$NON-NLS-1$ //$NON-NLS-2$
+ secprops.put("security.provider.2", "org.apache.harmony.security.provider.crypto.CryptoProvider"); //$NON-NLS-1$ //$NON-NLS-2$
+ secprops.put("security.provider.3", "org.apache.harmony.xnet.provider.jsse.JSSEProvider"); //$NON-NLS-1$ //$NON-NLS-2$
+ secprops.put("security.provider.4", "org.bouncycastle.jce.provider.BouncyCastleProvider"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Returns value for the specified algorithm with the specified name.
+ *
+ * @param algName
+ * the name of the algorithm.
+ * @param propName
+ * the name of the property.
+ * @return value of the property.
+ * @deprecated Use {@link AlgorithmParameters} and {@link KeyFactory}
+ * instead.
+ */
+ @Deprecated
+ public static String getAlgorithmProperty(String algName, String propName) {
+ if (algName == null || propName == null) {
+ return null;
+ }
+ // BEGIN android-changed
+ String prop = "Alg." + propName + "." + algName; //$NON-NLS-1$
+ // END android-changed
+ Provider[] providers = getProviders();
+ for (int i = 0; i < providers.length; i++) {
+ for (Enumeration e = providers[i].propertyNames(); e
+ .hasMoreElements();) {
+ String pname = (String) e.nextElement();
+ if (Util.equalsIgnoreCase(prop, pname)) {
+ return providers[i].getProperty(pname);
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Insert the given {@code Provider} at the specified {@code position}. The
+ * positions define the preference order in which providers are searched for
+ * requested algorithms.
+ * <p>
+ * If a {@code SecurityManager} is installed, code calling this method needs
+ * the {@code SecurityPermission} {@code insertProvider.NAME} (where NAME is
+ * the provider name) to be granted, otherwise a {@code SecurityException}
+ * will be thrown.
+ *
+ * @param provider
+ * the provider to insert.
+ * @param position
+ * the position (starting from 1).
+ * @return the actual position or {@code -1} if the given {@code provider}
+ * was already in the list. The actual position may be different
+ * from the desired position.
+ * @throws SecurityException
+ * if a {@code SecurityManager} is installed and the caller does
+ * not have permission to invoke this method.
+ */
+ public static synchronized int insertProviderAt(Provider provider,
+ int position) {
+ // check security access; check that provider is not already
+ // installed, else return -1; if (position <1) or (position > max
+ // position) position = max position + 1; insert provider, shift up
+ // one position for next providers; Note: The position is 1-based
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkSecurityAccess("insertProvider." + provider.getName()); //$NON-NLS-1$
+ }
+ if (getProvider(provider.getName()) != null) {
+ return -1;
+ }
+ int result = Services.insertProviderAt(provider, position);
+ renumProviders();
+ return result;
+ }
+
+ /**
+ * Adds the given {@code provider} to the collection of providers at the
+ * next available position.
+ * <p>
+ * If a {@code SecurityManager} is installed, code calling this method needs
+ * the {@code SecurityPermission} {@code insertProvider.NAME} (where NAME is
+ * the provider name) to be granted, otherwise a {@code SecurityException}
+ * will be thrown.
+ *
+ * @param provider
+ * the provider to be added.
+ * @return the actual position or {@code -1} if the given {@code provider}
+ * was already in the list.
+ * @throws SecurityException
+ * if a {@code SecurityManager} is installed and the caller does
+ * not have permission to invoke this method.
+ */
+ public static int addProvider(Provider provider) {
+ return insertProviderAt(provider, 0);
+ }
+
+ /**
+ * Removes the {@code Provider} with the specified name form the collection
+ * of providers. If the the {@code Provider} with the specified name is
+ * removed, all provider at a greater position are shifted down one
+ * position.
+ * <p>
+ * Returns silently if {@code name} is {@code null} or no provider with the
+ * specified name is installed.
+ * <p>
+ * If a {@code SecurityManager} is installed, code calling this method needs
+ * the {@code SecurityPermission} {@code removeProvider.NAME} (where NAME is
+ * the provider name) to be granted, otherwise a {@code SecurityException}
+ * will be thrown.
+ *
+ * @param name
+ * the name of the provider to remove.
+ * @throws SecurityException
+ * if a {@code SecurityManager} is installed and the caller does
+ * not have permission to invoke this method.
+ */
+ public static synchronized void removeProvider(String name) {
+ // It is not clear from spec.:
+ // 1. if name is null, should we checkSecurityAccess or not?
+ // throw SecurityException or not?
+ // 2. as 1 but provider is not installed
+ // 3. behavior if name is empty string?
+
+ Provider p;
+ if ((name == null) || (name.length() == 0)) {
+ return;
+ }
+ p = getProvider(name);
+ if (p == null) {
+ return;
+ }
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkSecurityAccess("removeProvider." + name); //$NON-NLS-1$
+ }
+ Services.removeProvider(p.getProviderNumber());
+ renumProviders();
+ p.setProviderNumber(-1);
+ }
+
+ /**
+ * Returns an array containing all installed providers. The providers are
+ * ordered according their preference order.
+ *
+ * @return an array containing all installed providers.
+ */
+ public static synchronized Provider[] getProviders() {
+ return Services.getProviders();
+ }
+
+ /**
+ * Returns the {@code Provider} with the specified name. Returns {@code
+ * null} if name is {@code null} or no provider with the specified name is
+ * installed.
+ *
+ * @param name
+ * the name of the requested provider.
+ * @return the provider with the specified name, maybe {@code null}.
+ */
+ public static synchronized Provider getProvider(String name) {
+ return Services.getProvider(name);
+ }
+
+ /**
+ * Returns the array of providers which meet the user supplied string
+ * filter. The specified filter must be supplied in one of two formats:
+ * <nl>
+ * <li> CRYPTO_SERVICE_NAME.ALGORITHM_OR_TYPE
+ * <p>
+ * (for example: "MessageDigest.SHA")
+ * <li> CRYPTO_SERVICE_NAME.ALGORITHM_OR_TYPE
+ * ATTR_NAME:ATTR_VALUE
+ * <p>
+ * (for example: "Signature.MD2withRSA KeySize:512")
+ * </nl>
+ *
+ * @param filter
+ * case-insensitive filter.
+ * @return the providers which meet the user supplied string filter {@code
+ * filter}. A {@code null} value signifies that none of the
+ * installed providers meets the filter specification.
+ * @throws InvalidParameterException
+ * if an unusable filter is supplied.
+ * @throws NullPointerException
+ * if {@code filter} is {@code null}.
+ */
+ public static Provider[] getProviders(String filter) {
+ if (filter == null) {
+ throw new NullPointerException(Messages.getString("security.2A")); //$NON-NLS-1$
+ }
+ if (filter.length() == 0) {
+ throw new InvalidParameterException(
+ Messages.getString("security.2B")); //$NON-NLS-1$
+ }
+ HashMap<String, String> hm = new HashMap<String, String>();
+ int i = filter.indexOf(':');
+ if ((i == filter.length() - 1) || (i == 0)) {
+ throw new InvalidParameterException(
+ Messages.getString("security.2B")); //$NON-NLS-1$
+ }
+ if (i < 1) {
+ hm.put(filter, ""); //$NON-NLS-1$
+ } else {
+ hm.put(filter.substring(0, i), filter.substring(i + 1));
+ }
+ return getProviders(hm);
+ }
+
+ /**
+ * Returns the array of providers which meet the user supplied set of
+ * filters. The filter must be supplied in one of two formats:
+ * <nl>
+ * <li> CRYPTO_SERVICE_NAME.ALGORITHM_OR_TYPE
+ * <p>
+ * for example: "MessageDigest.SHA" The value associated with the key must
+ * be an empty string. <li> CRYPTO_SERVICE_NAME.ALGORITHM_OR_TYPE
+ * ATTR_NAME:ATTR_VALUE
+ * <p>
+ * for example: "Signature.MD2withRSA KeySize:512" where "KeySize:512" is
+ * the value of the filter map entry.
+ * </nl>
+ *
+ * @param filter
+ * case-insensitive filter.
+ * @return the providers which meet the user supplied string filter {@code
+ * filter}. A {@code null} value signifies that none of the
+ * installed providers meets the filter specification.
+ * @throws InvalidParameterException
+ * if an unusable filter is supplied.
+ * @throws NullPointerException
+ * if {@code filter} is {@code null}.
+ */
+ public static synchronized Provider[] getProviders(Map<String,String> filter) {
+ if (filter == null) {
+ throw new NullPointerException(Messages.getString("security.2A")); //$NON-NLS-1$
+ }
+ if (filter.isEmpty()) {
+ return null;
+ }
+ java.util.List<Provider> result = Services.getProvidersList();
+ Set<Entry<String, String>> keys = filter.entrySet();
+ Map.Entry<String, String> entry;
+ for (Iterator<Entry<String, String>> it = keys.iterator(); it.hasNext();) {
+ entry = it.next();
+ String key = entry.getKey();
+ String val = entry.getValue();
+ String attribute = null;
+ int i = key.indexOf(' ');
+ int j = key.indexOf('.');
+ if (j == -1) {
+ throw new InvalidParameterException(
+ Messages.getString("security.2B")); //$NON-NLS-1$
+ }
+ if (i == -1) { // <crypto_service>.<algorithm_or_type>
+ if (val.length() != 0) {
+ throw new InvalidParameterException(
+ Messages.getString("security.2B")); //$NON-NLS-1$
+ }
+ } else { // <crypto_service>.<algorithm_or_type> <attribute_name>
+ if (val.length() == 0) {
+ throw new InvalidParameterException(
+ Messages.getString("security.2B")); //$NON-NLS-1$
+ }
+ attribute = key.substring(i + 1);
+ if (attribute.trim().length() == 0) {
+ throw new InvalidParameterException(
+ Messages.getString("security.2B")); //$NON-NLS-1$
+ }
+ key = key.substring(0, i);
+ }
+ String serv = key.substring(0, j);
+ String alg = key.substring(j + 1);
+ if (serv.length() == 0 || alg.length() == 0) {
+ throw new InvalidParameterException(
+ Messages.getString("security.2B")); //$NON-NLS-1$
+ }
+ Provider p;
+ for (int k = 0; k < result.size(); k++) {
+ try {
+ p = result.get(k);
+ } catch (IndexOutOfBoundsException e) {
+ break;
+ }
+ if (!p.implementsAlg(serv, alg, attribute, val)) {
+ result.remove(p);
+ k--;
+ }
+ }
+ }
+ if (result.size() > 0) {
+ return result.toArray(new Provider[result.size()]);
+ }
+ return null;
+ }
+
+ /**
+ * Returns the value of the security property named by the argument.
+ * <p>
+ * If a {@code SecurityManager} is installed, code calling this method needs
+ * the {@code SecurityPermission} {@code getProperty.KEY} (where KEY is the
+ * specified {@code key}) to be granted, otherwise a {@code
+ * SecurityException} will be thrown.
+ *
+ * @param key
+ * the name of the requested security property.
+ * @return the value of the security property.
+ * @throws SecurityException
+ * if a {@code SecurityManager} is installed and the caller does
+ * not have permission to invoke this method.
+ */
+ public static String getProperty(String key) {
+ if (key == null) {
+ throw new NullPointerException(Messages.getString("security.2C")); //$NON-NLS-1$
+ }
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkSecurityAccess("getProperty." + key); //$NON-NLS-1$
+ }
+ String property = secprops.getProperty(key);
+ if (property != null) {
+ property = property.trim();
+ }
+ return property;
+ }
+
+ /**
+ * Sets the value of the specified security property.
+ * <p>
+ * If a {@code SecurityManager} is installed, code calling this method needs
+ * the {@code SecurityPermission} {@code setProperty.KEY} (where KEY is the
+ * specified {@code key}) to be granted, otherwise a {@code
+ * SecurityException} will be thrown.
+ *
+ * @param key
+ * the name of the security property.
+ * @param datnum
+ * the value of the security property.
+ * @throws SecurityException
+ * if a {@code SecurityManager} is installed and the caller does
+ * not have permission to invoke this method.
+ */
+ public static void setProperty(String key, String datnum) {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkSecurityAccess("setProperty." + key); //$NON-NLS-1$
+ }
+ secprops.put(key, datnum);
+ }
+
+ /**
+ * Returns a {@code Set} of all registered algorithms for the specified
+ * cryptographic service. {@code "Signature"}, {@code "Cipher"} and {@code
+ * "KeyStore"} are examples for such kind of services.
+ *
+ * @param serviceName
+ * the case-insensitive name of the service.
+ * @return a {@code Set} of all registered algorithms for the specified
+ * cryptographic service, or an empty {@code Set} if {@code
+ * serviceName} is {@code null} or if no registered provider
+ * provides the requested service.
+ */
+ public static Set<String> getAlgorithms(String serviceName) {
+ Set<String> result = new HashSet<String>();
+ // BEGIN android-added
+ // compatibility with RI
+ if (serviceName == null) {
+ return result;
+ }
+ // END android-added
+ Provider[] p = getProviders();
+ for (int i = 0; i < p.length; i++) {
+ for (Iterator it = p[i].getServices().iterator(); it.hasNext();) {
+ Provider.Service s = (Provider.Service) it.next();
+ if (Util.equalsIgnoreCase(s.getType(),serviceName)) {
+ result.add(s.getAlgorithm());
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ *
+ * Update sequence numbers of all providers.
+ *
+ */
+ private static void renumProviders() {
+ Provider[] p = Services.getProviders();
+ for (int i = 0; i < p.length; i++) {
+ p[i].setProviderNumber(i + 1);
+ }
+ }
+
+ private static class SecurityDoor implements SecurityAccess {
+ // Access to Security.renumProviders()
+ public void renumProviders() {
+ Security.renumProviders();
+ }
+
+ // Access to Security.getAliases()
+ public Iterator<String> getAliases(Provider.Service s) {
+ return s.getAliases();
+ }
+
+ // Access to Provider.getService()
+ public Provider.Service getService(Provider p, String type) {
+ return p.getService(type);
+ }
+ }
+}
diff --git a/luni/src/main/java/java/security/SecurityPermission.java b/luni/src/main/java/java/security/SecurityPermission.java
new file mode 100644
index 0000000..599ec6f
--- /dev/null
+++ b/luni/src/main/java/java/security/SecurityPermission.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * {@code SecurityPermission} objects guard access to the mechanisms which
+ * implement security. Security permissions have names, but not actions.
+ */
+public final class SecurityPermission extends BasicPermission {
+
+ private static final long serialVersionUID = 5236109936224050470L;
+
+ /**
+ * Constructs a new instance of {@code SecurityPermission} with the given
+ * name.
+ *
+ * @param name
+ * the name of the permission.
+ */
+ public SecurityPermission(String name) {
+ super(name);
+ }
+
+ /**
+ * Constructs a new instance of {@code SecurityPermission} with the given
+ * {@code name} and {@code action} list. The action list is ignored - it is
+ * existing for compatibility reasons only.
+ *
+ * @param name
+ * the name of the permission.
+ * @param action
+ * ignored.
+ */
+ public SecurityPermission(String name, String action) {
+ super(name, action);
+ }
+}
diff --git a/luni/src/main/java/java/security/Signature.java b/luni/src/main/java/java/security/Signature.java
new file mode 100644
index 0000000..4e3fe14
--- /dev/null
+++ b/luni/src/main/java/java/security/Signature.java
@@ -0,0 +1,686 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.nio.ByteBuffer;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.harmony.security.fortress.Engine;
+import org.apache.harmony.security.internal.nls.Messages;
+
+
+/**
+ * {@code Signature} is an engine class which is capable of creating and
+ * verifying digital signatures, using different algorithms that have been
+ * registered with the {@link Security} class.
+ *
+ * @see SignatureSpi
+ */
+public abstract class Signature extends SignatureSpi {
+
+ // The service name.
+ private static final String SERVICE = "Signature"; //$NON-NLS-1$
+
+ // Used to access common engine functionality
+ private static Engine engine = new Engine(SERVICE);
+
+ // The provider
+ private Provider provider;
+
+ // The algorithm.
+ private String algorithm;
+
+ /**
+ * Constant that indicates that this {@code Signature} instance has not yet
+ * been initialized.
+ */
+ protected static final int UNINITIALIZED = 0;
+
+ /**
+ * Constant that indicates that this {@code Signature} instance has been
+ * initialized for signing.
+ */
+ protected static final int SIGN = 2;
+
+ /**
+ * Constant that indicates that this {@code Signature} instance has been
+ * initialized for verification.
+ */
+ protected static final int VERIFY = 3;
+
+ /**
+ * Represents the current state of this {@code Signature}. The three
+ * possible states are {@link #UNINITIALIZED}, {@link #SIGN} or
+ * {@link #VERIFY}.
+ */
+ protected int state = UNINITIALIZED;
+
+ /**
+ * Constructs a new instance of {@code Signature} with the name of
+ * the algorithm to use.
+ *
+ * @param algorithm
+ * the name of algorithm to use.
+ */
+ protected Signature(String algorithm) {
+ this.algorithm = algorithm;
+ }
+
+ /**
+ * Returns a new instance of {@code Signature} that utilizes the specified
+ * algorithm.
+ *
+ * @param algorithm
+ * the name of the algorithm to use.
+ * @return a new instance of {@code Signature} that utilizes the specified
+ * algorithm.
+ * @throws NoSuchAlgorithmException
+ * if the specified algorithm is not available.
+ * @throws NullPointerException
+ * if {@code algorithm} is {@code null}.
+ */
+ public static Signature getInstance(String algorithm)
+ throws NoSuchAlgorithmException {
+ if (algorithm == null) {
+ throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+ }
+ Signature result;
+ synchronized (engine) {
+ engine.getInstance(algorithm, null);
+ if (engine.spi instanceof Signature) {
+ result = (Signature) engine.spi;
+ result.algorithm = algorithm;
+ result.provider = engine.provider;
+ } else {
+ result = new SignatureImpl((SignatureSpi) engine.spi,
+ engine.provider, algorithm);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns a new instance of {@code Signature} that utilizes the specified
+ * algorithm from the specified provider.
+ *
+ * @param algorithm
+ * the name of the algorithm to use.
+ * @param provider
+ * the name of the provider.
+ * @return a new instance of {@code Signature} that utilizes the specified
+ * algorithm from the specified provider.
+ * @throws NoSuchAlgorithmException
+ * if the specified algorithm is not available.
+ * @throws NoSuchProviderException
+ * if the specified provider is not available.
+ * @throws NullPointerException
+ * if {@code algorithm} is {@code null}.
+ */
+ public static Signature getInstance(String algorithm, String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException {
+ if (algorithm == null) {
+ throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+ }
+ if ((provider == null) || (provider.length() == 0)) {
+ throw new IllegalArgumentException(
+ Messages.getString("security.02")); //$NON-NLS-1$
+ }
+ Provider p = Security.getProvider(provider);
+ if (p == null) {
+ throw new NoSuchProviderException(Messages.getString("security.03", provider)); //$NON-NLS-1$
+ }
+ return getSignatureInstance(algorithm, p);
+ }
+
+ /**
+ * Returns a new instance of {@code Signature} that utilizes the specified
+ * algorithm from the specified provider.
+ *
+ * @param algorithm
+ * the name of the algorithm to use.
+ * @param provider
+ * the security provider.
+ * @return a new instance of {@code Signature} that utilizes the specified
+ * algorithm from the specified provider.
+ * @throws NoSuchAlgorithmException
+ * if the specified algorithm is not available.
+ * @throws NullPointerException
+ * if {@code algorithm} is {@code null}.
+ */
+ public static Signature getInstance(String algorithm, Provider provider)
+ throws NoSuchAlgorithmException {
+ if (algorithm == null) {
+ throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+ }
+ if (provider == null) {
+ throw new IllegalArgumentException(Messages.getString("security.04")); //$NON-NLS-1$
+ }
+ return getSignatureInstance(algorithm, provider);
+ }
+
+ private static Signature getSignatureInstance(String algorithm,
+ Provider provider) throws NoSuchAlgorithmException {
+ Signature result;
+ synchronized (engine) {
+ engine.getInstance(algorithm, provider, null);
+ if (engine.spi instanceof Signature) {
+ result = (Signature) engine.spi;
+ result.algorithm = algorithm;
+ result.provider = provider;
+ } else {
+ result = new SignatureImpl((SignatureSpi) engine.spi, provider,
+ algorithm);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns the provider associated with this {@code Signature}.
+ *
+ * @return the provider associated with this {@code Signature}.
+ */
+ public final Provider getProvider() {
+ return provider;
+ }
+
+ /**
+ * Returns the name of the algorithm of this {@code Signature}.
+ *
+ * @return the name of the algorithm of this {@code Signature}.
+ */
+ public final String getAlgorithm() {
+ return algorithm;
+ }
+
+ /**
+ * Initializes this {@code Signature} instance for signature verification,
+ * using the public key of the identity whose signature is going to be
+ * verified.
+ *
+ * @param publicKey
+ * the public key.
+ * @throws InvalidKeyException
+ * if {@code publicKey} is not valid.
+ */
+ public final void initVerify(PublicKey publicKey)
+ throws InvalidKeyException {
+ engineInitVerify(publicKey);
+ state = VERIFY;
+ }
+
+ /**
+ * Initializes this {@code Signature} instance for signature verification,
+ * using the certificate of the identity whose signature is going to be
+ * verified.
+ * <p>
+ * If the given certificate is an instance of {@link X509Certificate} and
+ * has a key usage parameter that indicates, that this certificate is not to
+ * be used for signing, an {@code InvalidKeyException} is thrown.
+ *
+ * @param certificate
+ * the certificate used to verify a signature.
+ * @throws InvalidKeyException
+ * if the publicKey in the certificate is not valid or not to be
+ * used for signing.
+ */
+ public final void initVerify(Certificate certificate)
+ throws InvalidKeyException {
+ if (certificate instanceof X509Certificate) {
+ Set ce = ((X509Certificate) certificate).getCriticalExtensionOIDs();
+ boolean critical = false;
+ if (ce != null && !ce.isEmpty()) {
+ for (Iterator i = ce.iterator(); i.hasNext();) {
+ if ("2.5.29.15".equals(i.next())) { //$NON-NLS-1$
+ //KeyUsage OID = 2.5.29.15
+ critical = true;
+ break;
+ }
+ }
+ if (critical) {
+ boolean[] keyUsage = ((X509Certificate) certificate)
+ .getKeyUsage();
+ // As specified in RFC 3280 -
+ // Internet X.509 Public Key Infrastructure
+ // Certificate and Certificate Revocation List (CRL) Profile.
+ // (http://www.ietf.org/rfc/rfc3280.txt)
+ //
+ // KeyUsage ::= BIT STRING { digitalSignature (0), <skipped> }
+ if ((keyUsage != null) && (!keyUsage[0])) { // digitalSignature
+ throw new InvalidKeyException(
+ Messages.getString("security.26")); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+ engineInitVerify(certificate.getPublicKey());
+ state = VERIFY;
+ }
+
+ /**
+ * Initializes this {@code Signature} instance for signing, using the
+ * private key of the identity whose signature is going to be generated.
+ *
+ * @param privateKey
+ * the private key.
+ * @throws InvalidKeyException
+ * if {@code privateKey} is not valid.
+ */
+ public final void initSign(PrivateKey privateKey)
+ throws InvalidKeyException {
+ engineInitSign(privateKey);
+ state = SIGN;
+ }
+
+ /**
+ * Initializes this {@code Signature} instance for signing, using the
+ * private key of the identity whose signature is going to be generated and
+ * the specified source of randomness.
+ *
+ * @param privateKey
+ * the private key.
+ * @param random
+ * the {@code SecureRandom} to use.
+ * @throws InvalidKeyException
+ * if {@code privateKey} is not valid.
+ */
+ public final void initSign(PrivateKey privateKey, SecureRandom random)
+ throws InvalidKeyException {
+ engineInitSign(privateKey, random);
+ state = SIGN;
+ }
+
+ /**
+ * Generates and returns the signature of all updated data.
+ * <p>
+ * This {@code Signature} instance is reset to the state of its last
+ * initialization for signing and thus can be used for another signature
+ * from the same identity.
+ *
+ * @return the signature of all updated data.
+ * @throws SignatureException
+ * if this {@code Signature} instance is not initialized
+ * properly.
+ */
+ public final byte[] sign() throws SignatureException {
+ if (state != SIGN) {
+ throw new SignatureException(
+ Messages.getString("security.27")); //$NON-NLS-1$
+ }
+ return engineSign();
+ }
+
+ /**
+ * Generates and stores the signature of all updated data in the provided
+ * {@code byte[]} at the specified position with the specified length.
+ * <p>
+ * This {@code Signature} instance is reset to the state of its last
+ * initialization for signing and thus can be used for another signature
+ * from the same identity.
+ *
+ * @param outbuf
+ * the buffer to store the signature.
+ * @param offset
+ * the index of the first byte in {@code outbuf} to store.
+ * @param len
+ * the number of bytes allocated for the signature.
+ * @return the number of bytes stored in {@code outbuf}.
+ * @throws SignatureException
+ * if this {@code Signature} instance is not initialized
+ * properly.
+ * @throws IllegalArgumentException
+ * if {@code offset} or {@code len} are not valid in respect to
+ * {@code outbuf}.
+ */
+ public final int sign(byte[] outbuf, int offset, int len)
+ throws SignatureException {
+ if (outbuf == null || offset < 0 || len < 0 ||
+ offset + len > outbuf.length) {
+ throw new IllegalArgumentException(
+ Messages.getString("security.05")); //$NON-NLS-1$
+ }
+ if (state != SIGN) {
+ throw new SignatureException(
+ Messages.getString("security.27")); //$NON-NLS-1$
+ }
+ return engineSign(outbuf, offset, len);
+ }
+
+ /**
+ * Indicates whether the given {@code signature} can be verified using the
+ * public key or a certificate of the signer.
+ * <p>
+ * This {@code Signature} instance is reset to the state of its last
+ * initialization for verifying and thus can be used to verify another
+ * signature of the same signer.
+ *
+ * @param signature
+ * the signature to verify.
+ * @return {@code true} if the signature was verified, {@code false}
+ * otherwise.
+ * @throws SignatureException
+ * if this {@code Signature} instance is not initialized
+ * properly.
+ */
+ public final boolean verify(byte[] signature) throws SignatureException {
+ if (state != VERIFY) {
+ throw new SignatureException(
+ Messages.getString("security.27")); //$NON-NLS-1$
+ }
+ return engineVerify(signature);
+ }
+
+ /**
+ * Indicates whether the given {@code signature} starting at index {@code
+ * offset} with {@code length} bytes can be verified using the public key or
+ * a certificate of the signer.
+ * <p>
+ * This {@code Signature} instance is reset to the state of its last
+ * initialization for verifying and thus can be used to verify another
+ * signature of the same signer.
+ *
+ * @param signature
+ * the {@code byte[]} containing the signature to verify.
+ * @param offset
+ * the start index in {@code signature} of the signature.
+ * @param length
+ * the number of bytes allocated for the signature.
+ * @return {@code true} if the signature was verified, {@code false}
+ * otherwise.
+ * @throws SignatureException
+ * if this {@code Signature} instance is not initialized
+ * properly.
+ * @throws IllegalArgumentException
+ * if {@code offset} or {@code length} are not valid in respect
+ * to {@code signature}.
+ */
+ public final boolean verify(byte[] signature, int offset, int length)
+ throws SignatureException {
+ if (state != VERIFY) {
+ throw new SignatureException(
+ Messages.getString("security.27")); //$NON-NLS-1$
+ }
+ if (signature == null || offset < 0 || length < 0 ||
+ offset + length > signature.length) {
+ throw new IllegalArgumentException(
+ Messages.getString("security.05")); //$NON-NLS-1$
+ }
+ return engineVerify(signature, offset, length);
+ }
+
+ /**
+ * Updates the data to be verified or to be signed, using the specified
+ * {@code byte}.
+ *
+ * @param b
+ * the byte to update with.
+ * @throws SignatureException
+ * if this {@code Signature} instance is not initialized
+ * properly.
+ */
+ public final void update(byte b) throws SignatureException {
+ if (state == UNINITIALIZED) {
+ throw new SignatureException(
+ Messages.getString("security.27")); //$NON-NLS-1$
+ }
+ engineUpdate(b);
+ }
+
+ /**
+ * Updates the data to be verified or to be signed, using the specified
+ * {@code byte[]}.
+ *
+ * @param data
+ * the byte array to update with.
+ * @throws SignatureException
+ * if this {@code Signature} instance is not initialized
+ * properly.
+ */
+ public final void update(byte[] data) throws SignatureException {
+ if (state == UNINITIALIZED) {
+ throw new SignatureException(
+ Messages.getString("security.27")); //$NON-NLS-1$
+ }
+ engineUpdate(data, 0, data.length);
+ }
+
+ /**
+ * Updates the data to be verified or to be signed, using the given {@code
+ * byte[]}, starting form the specified index for the specified length.
+ *
+ * @param data
+ * the byte array to update with.
+ * @param off
+ * the start index in {@code data} of the data.
+ * @param len
+ * the number of bytes to use.
+ * @throws SignatureException
+ * if this {@code Signature} instance is not initialized
+ * properly.
+ */
+ public final void update(byte[] data, int off, int len)
+ throws SignatureException {
+ if (state == UNINITIALIZED) {
+ throw new SignatureException(
+ Messages.getString("security.27")); //$NON-NLS-1$
+ }
+ if (data == null || off < 0 || len < 0 ||
+ off + len > data.length) {
+ throw new IllegalArgumentException(
+ Messages.getString("security.05")); //$NON-NLS-1$
+ }
+ engineUpdate(data, off, len);
+ }
+
+ /**
+ * Updates the data to be verified or to be signed, using the specified
+ * {@code ByteBuffer}.
+ *
+ * @param data
+ * the {@code ByteBuffer} to update with.
+ * @throws SignatureException
+ * if this {@code Signature} instance is not initialized
+ * properly.
+ */
+ public final void update(ByteBuffer data) throws SignatureException {
+ if (state == UNINITIALIZED) {
+ throw new SignatureException(
+ Messages.getString("security.27")); //$NON-NLS-1$
+ }
+ engineUpdate(data);
+ }
+
+ /**
+ * Returns a string containing a concise, human-readable description of this
+ * {@code Signature} including its algorithm and its state.
+ *
+ * @return a printable representation for this {@code Signature}.
+ */
+ @Override
+ public String toString() {
+ return "SIGNATURE " + algorithm + " state: " + stateToString(state); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ // Convert state to string
+ private String stateToString(int state) {
+ switch (state) {
+ case UNINITIALIZED:
+ return "UNINITIALIZED"; //$NON-NLS-1$
+ case SIGN:
+ return "SIGN"; //$NON-NLS-1$
+ case VERIFY:
+ return "VERIFY"; //$NON-NLS-1$
+ default:
+ return ""; //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Sets the specified parameter to the given value.
+ *
+ * @param param
+ * the name of the parameter.
+ * @param value
+ * the parameter value.
+ * @throws InvalidParameterException
+ * if the parameter is invalid, already set or is not allowed to
+ * be changed.
+ * @deprecated Use {@link #setParameter(AlgorithmParameterSpec)}
+ */
+ @Deprecated
+ public final void setParameter(String param, Object value)
+ throws InvalidParameterException {
+ engineSetParameter(param, value);
+ }
+
+ /**
+ * Sets the specified {@code AlgorithmParameterSpec}.
+ *
+ * @param params
+ * the parameter to set.
+ * @throws InvalidAlgorithmParameterException
+ * if the parameter is invalid, already set or is not allowed to
+ * be changed.
+ */
+ public final void setParameter(AlgorithmParameterSpec params)
+ throws InvalidAlgorithmParameterException {
+ engineSetParameter(params);
+ }
+
+ /**
+ * Returns the {@code AlgorithmParameters} of this {@link Signature}
+ * instance.
+ *
+ * @return the {@code AlgorithmParameters} of this {@link Signature}
+ * instance, maybe {@code null}.
+ */
+ public final AlgorithmParameters getParameters() {
+ return engineGetParameters();
+ }
+
+ /**
+ * Returns the value of the parameter with the specified name.
+ *
+ * @param param
+ * the name of the requested parameter value
+ * @return the value of the parameter with the specified name, maybe {@code
+ * null}.
+ * @throws InvalidParameterException
+ * if {@code param} is not a valid parameter for this {@code
+ * Signature} or an other error occures.
+ * @deprecated There is no generally accepted parameter naming convention.
+ */
+ @Deprecated
+ public final Object getParameter(String param)
+ throws InvalidParameterException {
+ return engineGetParameter(param);
+ }
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ if (this instanceof Cloneable) {
+ return super.clone();
+ }
+ throw new CloneNotSupportedException();
+ }
+
+ /**
+ *
+ * Internal Signature implementation
+ *
+ */
+ private static class SignatureImpl extends Signature {
+
+ private SignatureSpi spiImpl;
+
+ // Constructor
+ public SignatureImpl(SignatureSpi signatureSpi, Provider provider,
+ String algorithm) {
+ super(algorithm);
+ super.provider = provider;
+ spiImpl = signatureSpi;
+ }
+
+ // engineSign() implementation
+ @Override
+ protected byte[] engineSign() throws SignatureException {
+ return spiImpl.engineSign();
+ }
+
+ // engineUpdate() implementation
+ @Override
+ protected void engineUpdate(byte arg0) throws SignatureException {
+ spiImpl.engineUpdate(arg0);
+ }
+
+ // engineVerify() implementation
+ @Override
+ protected boolean engineVerify(byte[] arg0) throws SignatureException {
+ return spiImpl.engineVerify(arg0);
+ }
+
+ // engineUpdate() implementation
+ @Override
+ protected void engineUpdate(byte[] arg0, int arg1, int arg2)
+ throws SignatureException {
+ spiImpl.engineUpdate(arg0, arg1, arg2);
+ }
+
+ // engineInitSign() implementation
+ @Override
+ protected void engineInitSign(PrivateKey arg0)
+ throws InvalidKeyException {
+ spiImpl.engineInitSign(arg0);
+ }
+
+ // engineInitVerify() implementation
+ @Override
+ protected void engineInitVerify(PublicKey arg0)
+ throws InvalidKeyException {
+ spiImpl.engineInitVerify(arg0);
+ }
+
+ // engineGetParameter() implementation
+ @Override
+ protected Object engineGetParameter(String arg0)
+ throws InvalidParameterException {
+ return spiImpl.engineGetParameter(arg0);
+ }
+
+ // engineSetParameter() implementation
+ @Override
+ protected void engineSetParameter(String arg0, Object arg1)
+ throws InvalidParameterException {
+ spiImpl.engineSetParameter(arg0, arg1);
+ }
+
+ // Returns a clone if the spiImpl is cloneable
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ if (spiImpl instanceof Cloneable) {
+ SignatureSpi spi = (SignatureSpi) spiImpl.clone();
+ return new SignatureImpl(spi, getProvider(), getAlgorithm());
+ }
+ throw new CloneNotSupportedException();
+ }
+ }
+}
diff --git a/luni/src/main/java/java/security/SignatureException.java b/luni/src/main/java/java/security/SignatureException.java
new file mode 100644
index 0000000..f8909d1
--- /dev/null
+++ b/luni/src/main/java/java/security/SignatureException.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ *{@code SignatureException} is a general {@code Signature} exception.
+ *
+ * @see Signature
+ */
+public class SignatureException extends GeneralSecurityException {
+
+ private static final long serialVersionUID = 7509989324975124438L;
+
+ /**
+ * Constructs a new instance of {@code SignatureException} with the
+ * given message.
+ *
+ * @param msg
+ * the detail message for this exception.
+ */
+ public SignatureException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs a new instance of {@code SignatureException}.
+ */
+ public SignatureException() {
+ }
+
+ /**
+ * Constructs a new instance of {@code SignatureException} with the
+ * given message and the cause.
+ *
+ * @param message
+ * the detail message for this exception
+ * @param cause
+ * the exception which is the cause for this exception
+ */
+ public SignatureException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructs a new instance of {@code SignatureException} with the
+ * cause.
+ *
+ * @param cause
+ * the exception which is the cause for this exception
+ */
+ public SignatureException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/luni/src/main/java/java/security/SignatureSpi.java b/luni/src/main/java/java/security/SignatureSpi.java
new file mode 100644
index 0000000..93c9e8c
--- /dev/null
+++ b/luni/src/main/java/java/security/SignatureSpi.java
@@ -0,0 +1,318 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.nio.ByteBuffer;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * {@code SignatureSpi} is the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * definition for {@link Signature}.
+ *
+ * @see Signature
+ */
+public abstract class SignatureSpi {
+
+ /**
+ * Implementation specific source of randomness.
+ */
+ protected SecureRandom appRandom;
+
+ /**
+ * Initializes this {@code SignatureSpi} instance for signature
+ * verification, using the public key of the identity whose signature is
+ * going to be verified.
+ *
+ * @param publicKey
+ * the public key.
+ * @throws InvalidKeyException
+ * if {@code publicKey} is not valid.
+ */
+ protected abstract void engineInitVerify(PublicKey publicKey)
+ throws InvalidKeyException;
+
+ /**
+ * Initializes this {@code SignatureSpi} instance for signing, using the
+ * private key of the identity whose signature is going to be generated.
+ *
+ * @param privateKey
+ * the private key.
+ * @throws InvalidKeyException
+ * if {@code privateKey} is not valid.
+ */
+ protected abstract void engineInitSign(PrivateKey privateKey)
+ throws InvalidKeyException;
+
+ /**
+ * Initializes this {@code SignatureSpi} instance for signing, using the
+ * private key of the identity whose signature is going to be generated and
+ * the specified source of randomness.
+ *
+ * @param privateKey
+ * the private key.
+ * @param random
+ * the {@code SecureRandom} to use.
+ * @throws InvalidKeyException
+ * if {@code privateKey} is not valid.
+ */
+ protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
+ throws InvalidKeyException {
+ appRandom = random;
+ engineInitSign(privateKey);
+ }
+
+ /**
+ * Updates the data to be verified or to be signed, using the specified
+ * {@code byte}.
+ *
+ * @param b
+ * the byte to update with.
+ * @throws SignatureException
+ * if this {@code SignatureSpi} instance is not initialized
+ * properly.
+ */
+ protected abstract void engineUpdate(byte b) throws SignatureException;
+
+ /**
+ * Updates the data to be verified or to be signed, using the given {@code
+ * byte[]}, starting form the specified index for the specified length.
+ *
+ * @param b
+ * the byte array to update with.
+ * @param off
+ * the start index in {@code b} of the data.
+ * @param len
+ * the number of bytes to use.
+ * @throws SignatureException
+ * if this {@code SignatureSpi} instance is not initialized
+ * properly.
+ */
+ protected abstract void engineUpdate(byte[] b, int off, int len)
+ throws SignatureException;
+
+ /**
+ * Updates the data to be verified or to be signed, using the specified
+ * {@code ByteBuffer}.
+ *
+ * @param input
+ * the {@code ByteBuffer} to update with.
+ * @throws RuntimeException
+ * since {@code SignatureException} is not specified for this
+ * method it throws a {@code RuntimeException} if underlying
+ * {@link #engineUpdate(byte[], int, int)} throws {@code
+ * SignatureException}.
+ */
+ protected void engineUpdate(ByteBuffer input) {
+ if (!input.hasRemaining()) {
+ return;
+ }
+ byte[] tmp;
+ if (input.hasArray()) {
+ tmp = input.array();
+ int offset = input.arrayOffset();
+ int position = input.position();
+ int limit = input.limit();
+ try {
+ engineUpdate(tmp, offset + position, limit - position);
+ } catch (SignatureException e) {
+ throw new RuntimeException(e); //Wrap SignatureException
+ }
+ input.position(limit);
+ } else {
+ tmp = new byte[input.limit() - input.position()];
+ input.get(tmp);
+ try {
+ engineUpdate(tmp, 0, tmp.length);
+ } catch (SignatureException e) {
+ throw new RuntimeException(e); //Wrap SignatureException
+ }
+ }
+ }
+
+ /**
+ * Generates and returns the signature of all updated data.
+ * <p>
+ * This {@code SignatureSpi} instance is reset to the state of its last
+ * initialization for signing and thus can be used for another signature
+ * from the same identity.
+ *
+ * @return the signature of all updated data.
+ * @throws SignatureException
+ * if this {@code SignatureSpi} instance is not initialized
+ * properly.
+ */
+ protected abstract byte[] engineSign() throws SignatureException;
+
+ /**
+ * Generates and stores the signature of all updated data in the provided
+ * {@code byte[]} at the specified position with the specified length.
+ * <p>
+ * This {@code SignatureSpi} instance is reset to the state of its last
+ * initialization for signing and thus can be used for another signature
+ * from the same identity.
+ *
+ * @param outbuf
+ * the buffer to store the signature.
+ * @param offset
+ * the index of the first byte in {@code outbuf} to store.
+ * @param len
+ * the number of bytes allocated for the signature.
+ * @return the number of bytes stored in {@code outbuf}.
+ * @throws SignatureException
+ * if this {@code SignatureSpi} instance is not initialized
+ * properly.
+ * @throws IllegalArgumentException
+ * if {@code offset} or {@code len} are not valid in respect to
+ * {@code outbuf}.
+ */
+ protected int engineSign(byte[] outbuf, int offset, int len)
+ throws SignatureException {
+ byte tmp[] = engineSign();
+ if (tmp == null) {
+ return 0;
+ }
+ if (len < tmp.length) {
+ throw new SignatureException(Messages.getString("security.2D")); //$NON-NLS-1$
+ }
+ if (offset < 0) {
+ throw new SignatureException(Messages.getString("security.1C")); //$NON-NLS-1$
+ }
+ if (offset + len > outbuf.length) {
+ throw new SignatureException(Messages.getString("security.05")); //$NON-NLS-1$
+ }
+ System.arraycopy(tmp, 0, outbuf, offset, tmp.length);
+ return tmp.length;
+ }
+
+ /**
+ * Indicates whether the given {@code sigBytes} can be verified using the
+ * public key or a certificate of the signer.
+ * <p>
+ * This {@code SignatureSpi} instance is reset to the state of its last
+ * initialization for verifying and thus can be used to verify another
+ * signature of the same signer.
+ *
+ * @param sigBytes
+ * the signature to verify.
+ * @return {@code true} if the signature was verified, {@code false}
+ * otherwise.
+ * @throws SignatureException
+ * if this {@code SignatureSpi} instance is not initialized
+ * properly.
+ */
+ protected abstract boolean engineVerify(byte[] sigBytes)
+ throws SignatureException;
+
+ /**
+ * Indicates whether the given {@code sigBytes} starting at index {@code
+ * offset} with {@code length} bytes can be verified using the public key or
+ * a certificate of the signer.
+ * <p>
+ * This {@code SignatureSpi} instance is reset to the state of its last
+ * initialization for verifying and thus can be used to verify another
+ * signature of the same signer.
+ *
+ * @param sigBytes
+ * the {@code byte[]} containing the signature to verify.
+ * @param offset
+ * the start index in {@code sigBytes} of the signature
+ * @param length
+ * the number of bytes allocated for the signature.
+ * @return {@code true} if the signature was verified, {@code false}
+ * otherwise.
+ * @throws SignatureException
+ * if this {@code SignatureSpi} instance is not initialized
+ * properly.
+ * @throws IllegalArgumentException
+ * if {@code offset} or {@code length} are not valid in respect
+ * to {@code sigBytes}.
+ */
+ protected boolean engineVerify(byte[] sigBytes, int offset, int length)
+ throws SignatureException {
+ byte tmp[] = new byte[length];
+ System.arraycopy(sigBytes, offset, tmp, 0, length);
+ return engineVerify(tmp);
+ }
+
+ /**
+ * Sets the specified parameter to the given value.
+ *
+ * @param param
+ * the name of the parameter.
+ * @param value
+ * the parameter value.
+ * @throws InvalidParameterException
+ * if the parameter is invalid, already set or is not allowed to
+ * be changed.
+ * @deprecated Use {@link #engineSetParameter(AlgorithmParameterSpec)}
+ */
+ @Deprecated
+ protected abstract void engineSetParameter(String param, Object value)
+ throws InvalidParameterException;
+
+ /**
+ * Sets the specified {@code AlgorithmParameterSpec}.
+ *
+ * @param params
+ * the parameter to set.
+ * @throws InvalidAlgorithmParameterException
+ * if the parameter is invalid, already set or is not allowed to
+ * be changed.
+ */
+ protected void engineSetParameter(AlgorithmParameterSpec params)
+ throws InvalidAlgorithmParameterException {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns the {@code AlgorithmParameters} of this {@link SignatureSpi}
+ * instance.
+ *
+ * @return the {@code AlgorithmParameters} of this {@link SignatureSpi}
+ * instance, maybe {@code null}.
+ */
+ protected AlgorithmParameters engineGetParameters() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns the value of the parameter with the specified name.
+ *
+ * @param param
+ * the name of the requested parameter value.
+ * @return the value of the parameter with the specified name, maybe {@code
+ * null}.
+ * @throws InvalidParameterException
+ * if {@code param} is not a valid parameter for this {@code
+ * SignatureSpi} or an other error occurs.
+ * @deprecated There is no generally accepted parameter naming convention.
+ */
+ @Deprecated
+ protected abstract Object engineGetParameter(String param)
+ throws InvalidParameterException;
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ if (this instanceof Cloneable) {
+ return super.clone();
+ }
+ throw new CloneNotSupportedException();
+ }
+}
diff --git a/luni/src/main/java/java/security/SignedObject.java b/luni/src/main/java/java/security/SignedObject.java
new file mode 100644
index 0000000..3347cf3
--- /dev/null
+++ b/luni/src/main/java/java/security/SignedObject.java
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+
+/**
+ * A {@code SignedObject} instance acts as a container for another object. The
+ * {@code SignedObject} contains the target in serialized form along with a
+ * digital signature of the serialized data.
+ */
+public final class SignedObject implements Serializable {
+
+ private static final long serialVersionUID = 720502720485447167L;
+
+ private byte[] content;
+
+ private byte[] signature;
+
+ private String thealgorithm;
+
+ private void readObject(ObjectInputStream s) throws IOException,
+ ClassNotFoundException {
+
+ s.defaultReadObject();
+ byte[] tmp = new byte[content.length];
+ System.arraycopy(content, 0, tmp, 0, content.length);
+ content = tmp;
+ tmp = new byte[signature.length];
+ System.arraycopy(signature, 0, tmp, 0, signature.length);
+ signature = tmp;
+ }
+
+ /**
+ * Constructs a new instance of {@code SignedObject} with the target object,
+ * the private key and the engine to compute the signature. The given
+ * {@code object} is signed with the specified key and engine.
+ *
+ * @param object
+ * the object to bes signed.
+ * @param signingKey
+ * the private key, used to sign the {@code object}.
+ * @param signingEngine
+ * the engine that performs the signature generation.
+ * @throws IOException
+ * if a serialization error occurs.
+ * @throws InvalidKeyException
+ * if the private key is not valid.
+ * @throws SignatureException
+ * if signature generation failed.
+ */
+ public SignedObject(Serializable object, PrivateKey signingKey,
+ Signature signingEngine) throws IOException, InvalidKeyException,
+ SignatureException {
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+ try {
+ // Serialize
+ oos.writeObject(object);
+ oos.flush();
+ } finally {
+ oos.close();
+ }
+ content = baos.toByteArray();
+ signingEngine.initSign(signingKey);
+ thealgorithm = signingEngine.getAlgorithm();
+ signingEngine.update(content);
+ signature = signingEngine.sign();
+ }
+
+ /**
+ * Returns the encapsulated object. Each time this method is invoked, the
+ * encapsulated object is deserialized before it is returned.
+ *
+ * @return the encapsulated object.
+ * @throws IOException
+ * if deserialization failed.
+ * @throws ClassNotFoundException
+ * if the class of the encapsulated object can not be found.
+ */
+ public Object getObject() throws IOException, ClassNotFoundException {
+ // deserialize our object
+ ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(
+ content));
+ try {
+ return ois.readObject();
+ } finally {
+ ois.close();
+ }
+ }
+
+ /**
+ * Returns the signature data of the encapsulated serialized object.
+ *
+ * @return the signature data of the encapsulated serialized object.
+ */
+ public byte[] getSignature() {
+ byte[] sig = new byte[signature.length];
+ System.arraycopy(signature, 0, sig, 0, signature.length);
+ return sig;
+ }
+
+ /**
+ * Returns the name of the algorithm of this {@code SignedObject}.
+ *
+ * @return the name of the algorithm of this {@code SignedObject}.
+ */
+ public String getAlgorithm() {
+ return thealgorithm;
+ }
+
+ /**
+ * Indicates whether the contained signature for the encapsulated object is
+ * valid.
+ *
+ * @param verificationKey
+ * the public key to verify the signature.
+ * @param verificationEngine
+ * the signature engine.
+ * @return {@code true} if the contained signature for the encapsulated
+ * object is valid, {@code false} otherwise.
+ * @throws InvalidKeyException
+ * if the public key is invalid.
+ * @throws SignatureException
+ * if signature verification failed.
+ */
+ public boolean verify(PublicKey verificationKey,
+ Signature verificationEngine) throws InvalidKeyException,
+ SignatureException {
+
+ verificationEngine.initVerify(verificationKey);
+ verificationEngine.update(content);
+ return verificationEngine.verify(signature);
+ }
+
+}
diff --git a/luni/src/main/java/java/security/Signer.java b/luni/src/main/java/java/security/Signer.java
new file mode 100644
index 0000000..64996bf
--- /dev/null
+++ b/luni/src/main/java/java/security/Signer.java
@@ -0,0 +1,147 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * {@link Signer} represents an identity (individual or corporation) that owns a
+ * private key and the corresponding public key.
+ *
+ * @deprecated Replaced by behavior in {@link java.security.cert
+ * java.security.cert} package and {@link java.security.Principal
+ * Principal}
+ */
+@Deprecated
+public abstract class Signer extends Identity {
+
+ private static final long serialVersionUID = -1763464102261361480L;
+
+ private PrivateKey privateKey;
+
+ /**
+ * Constructs a new instance of {@code Signer}.
+ */
+ protected Signer() {
+ super();
+ }
+
+ /**
+ * Constructs a new instance of {@code Signer} with the given name.
+ *
+ * @param name
+ * the name of the signer.
+ */
+ public Signer(String name) {
+ super(name);
+ }
+
+ /**
+ * Constructs a new instance of {@code Signer} with the given name in the
+ * given scope.
+ *
+ * @param name
+ * the name of the signer.
+ * @param scope
+ * the scope of the signer.
+ * @throws KeyManagementException
+ * if a signer with the specified name already exists in the
+ * provided scope.
+ */
+ public Signer(String name, IdentityScope scope)
+ throws KeyManagementException {
+ super(name, scope);
+ }
+
+ /**
+ * Returns the private key of this {@code Signer}. If a {@code
+ * SecurityManager} is installed, code calling this method needs the {@code
+ * SecurityPermission} {@code "getSignerPrivateKey"} to be granted, otherwise
+ * a {@code SecurityException} will be thrown.
+ *
+ * @return the private key of this {@code Signer}.
+ * @throws SecurityException
+ * if a {@code SecurityManager} is installed and the caller does
+ * not have permission to invoke this method.
+ */
+ public PrivateKey getPrivateKey() {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkSecurityAccess("getSignerPrivateKey"); //$NON-NLS-1$
+ }
+
+ return privateKey;
+ }
+
+ /**
+ * Associates the specified key pair with this {@code Signer}. If a {@code
+ * SecurityManager} is installed, code calling this method needs the {@code
+ * SecurityPermission} {@code getSignerPrivateKey} to be granted, otherwise
+ * a {@code SecurityException} will be thrown.
+ *
+ * @param pair
+ * the key pair to associate with this {@code Signer}.
+ * @throws InvalidParameterException
+ * if the key pair is invalid.
+ * @throws KeyException
+ * if any other key related problem occurs.
+ * @throws SecurityException
+ * if a {@code SecurityManager} is installed and the caller does
+ * not have permission to invoke this method.
+ */
+ public final void setKeyPair(KeyPair pair)
+ throws InvalidParameterException, KeyException {
+
+ if (pair == null) {
+ throw new NullPointerException();
+ }
+
+ if ((pair.getPrivate() == null) || (pair.getPublic() == null)) {
+ throw new InvalidParameterException();
+ }
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkSecurityAccess("setSignerKeyPair"); //$NON-NLS-1$
+ }
+ final PublicKey pk = pair.getPublic();
+ try {
+ AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
+ public Void run() throws KeyManagementException {
+ setPublicKey(pk);
+ return null;
+ }
+ });
+ } catch (PrivilegedActionException e) {
+ throw new KeyException(e.getException());
+ }
+ this.privateKey = pair.getPrivate();
+ }
+
+ /**
+ * Returns a string containing a concise, human-readable description of this
+ * {@code Signer} including its name and its scope if present.
+ *
+ * @return a printable representation for this {@code Signer}.
+ */
+ @Override
+ public String toString() {
+ String s = "[Signer]" + getName(); //$NON-NLS-1$
+ if (getScope() != null) {
+ s = s + '[' + getScope().toString() + ']';
+ }
+ return s;
+ }
+}
diff --git a/luni/src/main/java/java/security/Timestamp.java b/luni/src/main/java/java/security/Timestamp.java
new file mode 100644
index 0000000..5a2930a
--- /dev/null
+++ b/luni/src/main/java/java/security/Timestamp.java
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.security.cert.CertPath;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * {@code Timestamp} represents a signed time stamp. {@code Timestamp} is
+ * immutable.
+ */
+public final class Timestamp implements Serializable {
+
+ private static final long serialVersionUID = -5502683707821851294L;
+
+ private Date timestamp;
+
+ private CertPath signerCertPath;
+
+ // Cached hash
+ private transient int hash;
+
+ /**
+ * Constructs a new instance of {@code Timestamp} with the specified {@code
+ * timestamp} and the given certificate path.
+ *
+ * @param timestamp
+ * date and time.
+ * @param signerCertPath
+ * the certificate path.
+ * @throws NullPointerException
+ * if {@code timestamp} is {@code null} or if {@code
+ * signerCertPath} is {@code null}.
+ */
+ public Timestamp(Date timestamp, CertPath signerCertPath) {
+ if (timestamp == null) {
+ throw new NullPointerException(Messages.getString("security.0F")); //$NON-NLS-1$
+ }
+ if (signerCertPath == null) {
+ throw new NullPointerException(Messages.getString("security.10")); //$NON-NLS-1$
+ }
+ // Clone timestamp to prevent modifications
+ this.timestamp = new Date(timestamp.getTime());
+ this.signerCertPath = signerCertPath;
+ }
+
+ /**
+ * Compares the specified object with this {@code Timestamp} for equality
+ * and returns {@code true} if the specified object is equal, {@code false}
+ * otherwise. The given object is equal to this {@code Timestamp}, if it is
+ * an instance of {@code Timestamp}, the two timestamps have an equal date
+ * and time and their certificate paths are equal.
+ *
+ * @param obj
+ * object to be compared for equality with this {@code
+ * Timestamp}.
+ * @return {@code true} if the specified object is equal to this {@code
+ * Timestamp}, otherwise {@code false}.
+ * @see #hashCode
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof Timestamp) {
+ Timestamp that = (Timestamp) obj;
+ return timestamp.equals(that.timestamp)
+ && signerCertPath.equals(that.signerCertPath);
+ }
+ return false;
+ }
+
+ /**
+ * Returns the certificate path of this {@code Timestamp}.
+ *
+ * @return the certificate path of this {@code Timestamp}.
+ */
+ public CertPath getSignerCertPath() {
+ return signerCertPath;
+ }
+
+ /**
+ * Returns the date and time of this {@code Timestamp}.
+ *
+ * @return the date and time of this {@code Timestamp}.
+ */
+ public Date getTimestamp() {
+ return (Date) timestamp.clone();
+ }
+
+ /**
+ * Returns the hash code value for this {@code Timestamp}. Returns the same
+ * hash code for {@code Timestamp}s that are equal to each other as
+ * required by the general contract of {@link Object#hashCode}.
+ *
+ * @return the hash code value for this {@code Timestamp}.
+ * @see Object#equals(Object)
+ * @see Timestamp#equals(Object)
+ */
+ @Override
+ public int hashCode() {
+ if (hash == 0) {
+ hash = timestamp.hashCode() ^ signerCertPath.hashCode();
+ }
+ return hash;
+ }
+
+ /**
+ * Returns a string containing a concise, human-readable description of this
+ * {@code Timestamp}.
+ *
+ * @return a printable representation for this {@code Timestamp}.
+ */
+ @Override
+ public String toString() {
+ StringBuilder buf = new StringBuilder(256);
+ // Dump only the first certificate
+ buf.append("Timestamp [").append(timestamp).append(" certPath="); //$NON-NLS-1$ //$NON-NLS-2$
+ buf.append(signerCertPath.getCertificates().get(0)).append("]"); //$NON-NLS-1$
+ return buf.toString();
+ }
+}
diff --git a/luni/src/main/java/java/security/UnrecoverableEntryException.java b/luni/src/main/java/java/security/UnrecoverableEntryException.java
new file mode 100644
index 0000000..24ff54b
--- /dev/null
+++ b/luni/src/main/java/java/security/UnrecoverableEntryException.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+
+/**
+ * {@code UnrecoverableEntryException} indicates, that a {@code KeyStore.Entry}
+ * cannot be recovered from a {@code KeyStore}.
+ *
+ * @see KeyStore
+ * @see KeyStore.Entry
+ */
+public class UnrecoverableEntryException extends GeneralSecurityException {
+
+ private static final long serialVersionUID = -4527142945246286535L;
+
+ /**
+ * Constructs a new instance of {@code UnrecoverableEntryException}.
+ */
+ public UnrecoverableEntryException() {
+ }
+
+ /**
+ * Constructs a new instance of {@code UnrecoverableEntryException} with the
+ * given message.
+ *
+ * @param msg
+ * the detail message for this exception.
+ */
+ public UnrecoverableEntryException(String msg) {
+ super(msg);
+ }
+}
diff --git a/luni/src/main/java/java/security/UnrecoverableKeyException.java b/luni/src/main/java/java/security/UnrecoverableKeyException.java
new file mode 100644
index 0000000..3840e6b
--- /dev/null
+++ b/luni/src/main/java/java/security/UnrecoverableKeyException.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * {@code UnrecoverableKeyException} indicates, that a key cannot be recovered
+ * from a {@code KeyStore}.
+ *
+ * @see KeyStore
+ */
+public class UnrecoverableKeyException extends GeneralSecurityException {
+
+ private static final long serialVersionUID = 7275063078190151277L;
+
+ /**
+ * Constructs a new instance of {@code UnrecoverableKeyException} with the
+ * given message.
+ *
+ * @param msg
+ * the detail message for this exception
+ */
+ public UnrecoverableKeyException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs a new instance of {@code UnrecoverableKeyException}.
+ */
+ public UnrecoverableKeyException() {
+ }
+}
diff --git a/luni/src/main/java/java/security/UnresolvedPermission.java b/luni/src/main/java/java/security/UnresolvedPermission.java
new file mode 100644
index 0000000..bf99a40
--- /dev/null
+++ b/luni/src/main/java/java/security/UnresolvedPermission.java
@@ -0,0 +1,418 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.NotSerializableException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+
+import org.apache.harmony.security.fortress.PolicyUtils;
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * An {@code UnresolvedPermission} represents a {@code Permission} whose type
+ * should be resolved lazy and not during initialization time of the {@code
+ * Policy}. {@code UnresolvedPermission}s contain all information to be replaced
+ * by a concrete typed {@code Permission} right before the access checks are
+ * performed.
+ */
+public final class UnresolvedPermission extends Permission
+ implements Serializable {
+
+ private static final long serialVersionUID = -4821973115467008846L;
+
+ private String type;
+
+ private String name;
+
+ private String actions;
+
+ // The signer certificates
+ private transient Certificate[] targetCerts;
+
+ // Cached hash value
+ private transient int hash;
+
+ /**
+ * Constructs a new instance of {@code UnresolvedPermission}. The supplied
+ * parameters are used when this instance is resolved to the concrete
+ * {@code Permission}.
+ *
+ * @param type
+ * the fully qualified class name of the permission this class is
+ * resolved to.
+ * @param name
+ * the name of the permission this class is resolved to, maybe
+ * {@code null}.
+ * @param actions
+ * the actions of the permission this class is resolved to, maybe
+ * {@code null}.
+ * @param certs
+ * the certificates of the permission this class is resolved to,
+ * maybe {@code null}.
+ * @throws NullPointerException
+ * if type is {@code null}.
+ */
+ public UnresolvedPermission(String type, String name, String actions,
+ Certificate[] certs) {
+ super(type);
+ checkType(type);
+ this.type = type;
+ this.name = name;
+ this.actions = actions;
+ if (certs != null) {
+ this.targetCerts = new Certificate[certs.length];
+ System.arraycopy(certs, 0, targetCerts, 0, certs.length);
+ }
+ hash = 0;
+ }
+
+ // Check type parameter
+ private final void checkType(String type) {
+ if (type == null) {
+ throw new NullPointerException(Messages.getString("security.2F")); //$NON-NLS-1$
+ }
+
+ // type is the class name of the Permission class.
+ // Empty string is inappropriate for class name.
+ // But this check is commented out for compatibility with RI.
+ // see JIRA issue HARMONY-733
+ // if (type.length() == 0) {
+ // throw new IllegalArgumentException("type cannot be empty");
+ // }
+ }
+
+ /**
+ * Compares the specified object with this {@code UnresolvedPermission} for
+ * equality and returns {@code true} if the specified object is equal,
+ * {@code false} otherwise. To be equal, the specified object needs to be an
+ * instance of {@code UnresolvedPermission}, the two {@code
+ * UnresolvedPermission}s must refer to the same type and must have the same
+ * name, the same actions and certificates.
+ *
+ * @param obj
+ * object to be compared for equality with this {@code
+ * UnresolvedPermission}.
+ * @return {@code true} if the specified object is equal to this {@code
+ * UnresolvedPermission}, otherwise {@code false}.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof UnresolvedPermission) {
+ UnresolvedPermission that = (UnresolvedPermission) obj;
+ if (getName().equals(that.getName())
+ && (name == null ? that.name == null : name
+ .equals(that.name))
+ && (actions == null ? that.actions == null : actions
+ .equals(that.actions))
+ && equalsCertificates(this.targetCerts, that.targetCerts)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /*
+ * check whether given array of certificates are equivalent
+ */
+ private boolean equalsCertificates(Certificate[] certs1,
+ Certificate[] certs2) {
+ if (certs1 == null || certs2 == null) {
+ return certs1 == certs2;
+ }
+
+ int length = certs1.length;
+ if (length != certs2.length) {
+ return false;
+ }
+
+ if (length > 0) {
+ boolean found;
+ for (int i = 0; i < length; i++) {
+ // Skip the checking for null
+ if(certs1[i] == null){
+ continue;
+ }
+ found = false;
+ for (int j = 0; j < length; j++) {
+ if (certs1[i].equals(certs2[j])) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ return false;
+ }
+ }
+
+ for (int i = 0; i < length; i++) {
+ if(certs2[i] == null){
+ continue;
+ }
+ found = false;
+ for (int j = 0; j < length; j++) {
+ if (certs2[i].equals(certs1[j])) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns the hash code value for this {@code UnresolvedPermission}.
+ * Returns the same hash code for {@code UnresolvedPermission}s that are
+ * equal to each other as required by the general contract of
+ * {@link Object#hashCode}.
+ *
+ * @return the hash code value for this {@code UnresolvedPermission}.
+ * @see Object#equals(Object)
+ * @see UnresolvedPermission#equals(Object)
+ */
+ @Override
+ public int hashCode() {
+ if (hash == 0) {
+ hash = getName().hashCode();
+ if (name != null) {
+ hash ^= name.hashCode();
+ }
+ if (actions != null) {
+ hash ^= actions.hashCode();
+ }
+ }
+ return hash;
+ }
+
+ /**
+ * Returns an empty string since there are no actions allowed for {@code
+ * UnresolvedPermission}. The actions, specified in the constructor, are
+ * used when the concrete permission is resolved and created.
+ *
+ * @return an empty string, indicating that there are no actions.
+ */
+ @Override
+ public String getActions() {
+ return ""; //$NON-NLS-1$
+ }
+
+ /**
+ * Returns the name of the permission this {@code UnresolvedPermission} is
+ * resolved to.
+ *
+ * @return the name of the permission this {@code UnresolvedPermission} is
+ * resolved to.
+ */
+ public String getUnresolvedName() {
+ return name;
+ }
+
+ /**
+ * Returns the actions of the permission this {@code UnresolvedPermission}
+ * is resolved to.
+ *
+ * @return the actions of the permission this {@code UnresolvedPermission}
+ * is resolved to.
+ */
+ public String getUnresolvedActions() {
+ return actions;
+ }
+
+ /**
+ * Returns the fully qualified class name of the permission this {@code
+ * UnresolvedPermission} is resolved to.
+ *
+ * @return the fully qualified class name of the permission this {@code
+ * UnresolvedPermission} is resolved to.
+ */
+ public String getUnresolvedType() {
+ return super.getName();
+ }
+
+ /**
+ * Returns the certificates of the permission this {@code
+ * UnresolvedPermission} is resolved to.
+ *
+ * @return the certificates of the permission this {@code
+ * UnresolvedPermission} is resolved to.
+ */
+ public Certificate[] getUnresolvedCerts() {
+ if (targetCerts != null) {
+ Certificate[] certs = new Certificate[targetCerts.length];
+ System.arraycopy(targetCerts, 0, certs, 0, certs.length);
+ return certs;
+ }
+ return null;
+ }
+
+ /**
+ * Indicates whether the specified permission is implied by this {@code
+ * UnresolvedPermission}. {@code UnresolvedPermission} objects imply nothing
+ * since nothing is known about them yet.
+ * <p>
+ * Before actual implication checking, this method tries to resolve
+ * UnresolvedPermissions (if any) against the passed instance. Successfully
+ * resolved permissions (if any) are taken into account during further
+ * processing.
+ *
+ * @param permission
+ * the permission to check.
+ * @return always {@code false}
+ */
+ @Override
+ public boolean implies(Permission permission) {
+ return false;
+ }
+
+ /**
+ * Returns a string containing a concise, human-readable description of this
+ * {@code UnresolvedPermission} including its target name and its target
+ * actions.
+ *
+ * @return a printable representation for this {@code UnresolvedPermission}.
+ */
+ @Override
+ public String toString() {
+ return "(unresolved " + type + " " + name + " " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ + actions + ")"; //$NON-NLS-1$
+ }
+
+ /**
+ * Returns a new {@code PermissionCollection} for holding {@code
+ * UnresolvedPermission} objects.
+ *
+ * @return a new PermissionCollection for holding {@code
+ * UnresolvedPermission} objects.
+ */
+ @Override
+ public PermissionCollection newPermissionCollection() {
+ return new UnresolvedPermissionCollection();
+ }
+
+ /**
+ * Tries to resolve this permission into the specified class.
+ * <p>
+ * It is assumed that the class has a proper name (as returned by {@code
+ * getName()} of this unresolved permission), so no check is performed to
+ * verify this. However, the class must have all required certificates (as
+ * per {@code getUnresolvedCerts()}) among the passed collection of signers.
+ * If it does, a zero, one, and/or two-argument constructor is tried to
+ * instantiate a new permission, which is then returned.
+ * <p>
+ * If an appropriate constructor is not available or the class is improperly
+ * signed, {@code null} is returned.
+ *
+ * @param targetType
+ * - a target class instance, must not be {@code null}
+ * @return resolved permission or null
+ */
+ Permission resolve(Class targetType) {
+ // check signers at first
+ if (PolicyUtils.matchSubset(targetCerts, targetType.getSigners())) {
+ try {
+ return PolicyUtils.instantiatePermission(targetType,
+ name,
+ actions);
+ } catch (Exception ignore) {
+ //TODO log warning?
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Outputs {@code type},{@code name},{@code actions}
+ * fields via default mechanism; next manually writes certificates in the
+ * following format: <br>
+ *
+ * <ol>
+ * <li> int : number of certs or zero </li>
+ * <li> each cert in the following format
+ * <ol>
+ * <li> String : certificate type </li>
+ * <li> int : length in bytes of certificate </li>
+ * <li> byte[] : certificate encoding </li>
+ * </ol>
+ * </li>
+ * </ol>
+ *
+ * @see <a href="http://java.sun.com/j2se/1.5.0/docs/api/serialized-form.html#java.security.UnresolvedPermission">Java Spec</a>
+ */
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ out.defaultWriteObject();
+ if (targetCerts == null) {
+ out.writeInt(0);
+ } else {
+ out.writeInt(targetCerts.length);
+ for (int i = 0; i < targetCerts.length; i++) {
+ try {
+ byte[] enc = targetCerts[i].getEncoded();
+ out.writeUTF(targetCerts[i].getType());
+ out.writeInt(enc.length);
+ out.write(enc);
+ } catch (CertificateEncodingException cee) {
+ throw ((IOException)new NotSerializableException(
+ Messages.getString("security.30", //$NON-NLS-1$
+ targetCerts[i])).initCause(cee));
+ }
+ }
+ }
+ }
+
+ /**
+ * Reads the object from stream and checks target type for validity.
+ */
+ private void readObject(ObjectInputStream in) throws IOException,
+ ClassNotFoundException {
+ in.defaultReadObject();
+ checkType(getUnresolvedType());
+ int certNumber = in.readInt();
+ if (certNumber != 0) {
+ targetCerts = new Certificate[certNumber];
+ for (int i = 0; i < certNumber; i++) {
+ try {
+ String type = in.readUTF();
+ int length = in.readInt();
+ byte[] enc = new byte[length];
+ in.readFully(enc, 0, length);
+ targetCerts[i] = CertificateFactory.getInstance(type)
+ .generateCertificate(new ByteArrayInputStream(enc));
+ } catch (CertificateException cee) {
+ throw ((IOException)new IOException(
+ Messages.getString("security.32")).initCause(cee)); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+}
diff --git a/luni/src/main/java/java/security/UnresolvedPermissionCollection.java b/luni/src/main/java/java/security/UnresolvedPermissionCollection.java
new file mode 100644
index 0000000..3a6ba92
--- /dev/null
+++ b/luni/src/main/java/java/security/UnresolvedPermissionCollection.java
@@ -0,0 +1,197 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Vector;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * {@code UnresolvedPermissionCollection} represents a specific {@code
+ * PermissionCollection} for storing {@link UnresolvedPermission} instances.
+ * Contained elements are grouped by their target type.
+ */
+final class UnresolvedPermissionCollection extends PermissionCollection {
+
+ private static final long serialVersionUID = -7176153071733132400L;
+
+ private static final ObjectStreamField[] serialPersistentFields = {
+ new ObjectStreamField("permissions", Hashtable.class), }; //$NON-NLS-1$
+
+ // elements of the collection.
+ private transient Map klasses = new HashMap();
+
+ /**
+ * Adds an unresolved permission to this {@code
+ * UnresolvedPermissionCollection}.
+ *
+ * @param permission
+ * the permission to be added.
+ * @throws SecurityException
+ * if this collection is read only.
+ * @throws IllegalArgumentException
+ * if {@code permission} is {@code null} or not an {@code
+ * UnresolvedPermission}.
+ */
+ public void add(Permission permission) {
+ if (isReadOnly()) {
+ throw new SecurityException(Messages.getString("security.15")); //$NON-NLS-1$
+ }
+ if (permission == null
+ || permission.getClass() != UnresolvedPermission.class) {
+ throw new IllegalArgumentException(Messages.getString("security.16", //$NON-NLS-1$
+ permission));
+ }
+ synchronized (klasses) {
+ String klass = permission.getName();
+ Collection klassMates = (Collection)klasses.get(klass);
+ if (klassMates == null) {
+ klassMates = new HashSet();
+ klasses.put(klass, klassMates);
+ }
+ klassMates.add(permission);
+ }
+ }
+
+ public Enumeration elements() {
+ Collection all = new ArrayList();
+ for (Iterator iter = klasses.values().iterator(); iter.hasNext();) {
+ all.addAll((Collection)iter.next());
+ }
+ return Collections.enumeration(all);
+ }
+
+ /**
+ * Always returns {@code false}.
+ *
+ * @return always {@code false}
+ * @see UnresolvedPermission#implies(Permission).
+ */
+ public boolean implies(Permission permission) {
+ return false;
+ }
+
+ /**
+ * Returns true if this collection contains unresolved permissions
+ * with the same classname as argument permission.
+ */
+ boolean hasUnresolved(Permission permission) {
+ return klasses.containsKey(permission.getClass().getName());
+ }
+
+ /**
+ * Resolves all permissions of the same class as the specified target
+ * permission and adds them to the specified collection. If passed
+ * collection is {@code null} and some unresolved permissions were resolved,
+ * an appropriate new collection is instantiated and used. All resolved
+ * permissions are removed from this unresolved collection, and collection
+ * with resolved ones is returned.
+ *
+ * @param target
+ * a kind of permissions to be resolved.
+ * @param holder
+ * an existing collection for storing resolved permissions.
+ * @return a collection containing resolved permissions (if any found)
+ */
+ PermissionCollection resolveCollection(Permission target,
+ PermissionCollection holder) {
+ String klass = target.getClass().getName();
+ if (klasses.containsKey(klass)) {
+ synchronized (klasses) {
+ Collection klassMates = (Collection)klasses.get(klass);
+ for (Iterator iter = klassMates.iterator(); iter.hasNext();) {
+ UnresolvedPermission element = (UnresolvedPermission)iter
+ .next();
+ Permission resolved = element.resolve(target.getClass());
+ if (resolved != null) {
+ if (holder == null) {
+ holder = target.newPermissionCollection();
+ if (holder == null) {
+ holder = new PermissionsHash();
+ }
+ }
+ holder.add(resolved);
+ iter.remove();
+ }
+ }
+ if (klassMates.size() == 0) {
+ klasses.remove(klass);
+ }
+ }
+ }
+ return holder;
+ }
+
+ /**
+ * Output fields via default mechanism.
+ */
+ private void writeObject(java.io.ObjectOutputStream out) throws IOException {
+ Hashtable permissions = new Hashtable();
+ for (Iterator iter = klasses.entrySet().iterator(); iter.hasNext();) {
+ Map.Entry entry = (Map.Entry) iter.next();
+ String key = (String) entry.getKey();
+ permissions.put(key, new Vector(((Collection) entry.getValue())));
+ }
+ ObjectOutputStream.PutField fields = out.putFields();
+ fields.put("permissions", permissions); //$NON-NLS-1$
+ out.writeFields();
+ }
+
+ /**
+ * Reads the object from stream and checks elements grouping for validity.
+ */
+ private void readObject(java.io.ObjectInputStream in) throws IOException,
+ ClassNotFoundException {
+ ObjectInputStream.GetField fields = in.readFields();
+ Map permissions = (Map)fields.get("permissions", null); //$NON-NLS-1$
+ klasses = new HashMap();
+ synchronized (klasses) {
+ for (Iterator iter = permissions.entrySet().iterator(); iter
+ .hasNext();) {
+ Map.Entry entry = (Map.Entry) iter.next();
+ String key = (String) entry.getKey();
+ Collection values = (Collection) entry.getValue();
+
+ for (Iterator iterator = values.iterator(); iterator.hasNext();) {
+ UnresolvedPermission element =
+ (UnresolvedPermission) iterator.next();
+
+ if (!element.getName().equals(key)) {
+ throw new InvalidObjectException(
+ Messages.getString("security.22")); //$NON-NLS-1$
+ }
+ }
+ klasses.put(key, new HashSet(values));
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/luni/src/main/java/java/security/acl/Acl.java b/luni/src/main/java/java/security/acl/Acl.java
new file mode 100644
index 0000000..88dd9f0
--- /dev/null
+++ b/luni/src/main/java/java/security/acl/Acl.java
@@ -0,0 +1,167 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.acl;
+
+import java.security.Principal;
+import java.util.Enumeration;
+
+/**
+ * The <i>Access Control List</i> (<b>ACL</b>) interface definition.
+ * <p>
+ * An ACL is a set of {@link AclEntry} objects.
+ * <p>
+ * An {@code AclEntry} is a list of {@link Permission}s that are granted
+ * (<i>positive</i>) or denied
+ * (<i>negative</i>) to a {@link Principal}.
+ * <p>
+ * An {@code Acl} has a list of owners ({@link Owner}) which are principals as
+ * well {@code Principal}. Only those principals which are the {@code Acl}'s
+ * owners are allowed to modify the {@code
+ * Acl}.
+ * <p>
+ * The <i>ACL</i> has to conform to the following rules:
+ * <ul>
+ * <li>For each {@code Principal} there can be only one <i>positive</i> and one
+ * <i>negative</i> {@code AclEntry}.</li>
+ * <li>If the two {@code AclEntry}'s (<i>positive</i> and <i>negative</i>) for a
+ * specific {@code Principal} grant and deny the same {@code Permission} to that
+ * {@code Principal}, then that {@code Permission} is treated as
+ * neither granted nor denied to that {@code Principal}.</li>
+ * <li>Permissions associated with an individual {@code Principal} always
+ * override permissions of the group(s) to which the individual belongs.</li>
+ * <li>If there is no {@code AclEntry} associated with a specific {@code
+ * Principal}, then it is interpreted as an empty list of permissions.</li>
+ * </ul>
+ */
+public interface Acl extends Owner {
+
+ /**
+ * Sets the name of this <i>ACL</i> instance.
+ *
+ * @param caller
+ * the invoking {@code Principal}.
+ * @param name
+ * the name to be set.
+ * @throws NotOwnerException
+ * if the invoking {@code Principal} is not an owner of this
+ * <i>ACL</i>.
+ */
+ void setName(Principal caller, String name) throws NotOwnerException;
+
+ /**
+ * Returns the name of this <i>ACL</i> instance.
+ *
+ * @return the name of this <i>ACL</i> instance.
+ */
+ String getName();
+
+ /**
+ * Adds an {@code AclEntry} to this <i>ACL</i> instance.
+ * <p>
+ * If the <i>ACL</i> already has an {@code AclEntry} of the same type (<i>
+ * positive</i> or <i>negative</i>) and principal, then the new entry is not added.
+ *
+ * @param caller
+ * the invoking {@code Principal}.
+ * @param entry
+ * the ACL entry to add.
+ * @return {@code true} if the entry is added, {@code false} if there is
+ * already an entry of the same type for the same principal
+ * @throws NotOwnerException
+ * if the invoking {@code Principal} is not an owner of this
+ * <i>ACL</i>.
+ */
+ boolean addEntry(Principal caller, AclEntry entry) throws NotOwnerException;
+
+ /**
+ * Removes an {@code AclEntry} from this <i>ACL</i> instance.
+ *
+ * @param caller
+ * the invoking {@code Principal}.
+ * @param entry
+ * the ACL entry to remove.
+ * @return {@code true} if the entry is removed, {@code false} if the entry
+ * is not in this <i>ACL</i>.
+ * @throws NotOwnerException
+ * if the invoking {@code Principal} is not an owner of this
+ * <i>ACL</i>.
+ */
+ boolean removeEntry(Principal caller, AclEntry entry)
+ throws NotOwnerException;
+
+ /**
+ * Returns the set of allowed permissions for the specified {@code
+ * Principal}.
+ * <p>
+ * If the specified principal has no entry in this ACL, an empty set is
+ * returned.
+ * <p>
+ * The allowed permissions are collected according to the following rules:
+ * <ul>
+ * <li>The two permission lists (<i>positive</i> and <i>negative</i>) of the
+ * principal's groups ({@link Group}) are collected. The positive (granted)
+ * permissions are the union of all group's positive permissions that the
+ * principal belongs to, the negative (denied) permissions are the union of
+ * all group's negative permissions that the principal belongs to. If a
+ * specific permission is in both the positive and the negative list, it is
+ * removed from both lists.</li>
+ * <li>The individual permissions (<i>positive</i> and <i>negative</i>) of
+ * the principal override the group permissions. The positive individual
+ * permissions override the group's negative permissions and the negative
+ * individual permissions override the grpup's positive permissions.</li>
+ * </ul>
+ *
+ * @param user
+ * the principal to get the allowed permissions for.
+ * @return the set of allowed permissions for the specified principal.
+ */
+ Enumeration<Permission> getPermissions(Principal user);
+
+ /**
+ * Returns an {@code Enumeration} of the {@code AclEntry} of this
+ * <i>ACL</i>.
+ *
+ * @return an {@code Enumeration} of the {@code AclEntry} of this
+ * <i>ACL</i>.
+ */
+ Enumeration<AclEntry> entries();
+
+ /**
+ * Checks whether the specified principal is granted the specified
+ * permission.
+ * <p>
+ * The list of granted permissions is determined according to the rules
+ * specified by {@code getPermissions}.
+ *
+ * @param principal
+ * the principal the check the permissions for.
+ * @param permission
+ * the permission to check for the principal.
+ * @return {@code true} if the principal is granted the permission,
+ * otherwise {@code false}.
+ * @see #getPermissions(Principal)
+ */
+ boolean checkPermission(Principal principal, Permission permission);
+
+ /**
+ * Returns the string representation of this ACL.
+ *
+ * @return the string representation of this ACL.
+ */
+ String toString();
+}
diff --git a/luni/src/main/java/java/security/acl/AclEntry.java b/luni/src/main/java/java/security/acl/AclEntry.java
new file mode 100644
index 0000000..fe2fb3a
--- /dev/null
+++ b/luni/src/main/java/java/security/acl/AclEntry.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.acl;
+
+import java.security.Principal;
+import java.util.Enumeration;
+
+/**
+ * The <i>Access Control List Entry</i> interface definition.
+ * <p>
+ * An {@code AclEntry} is a list of the {@link Permission}s that are
+ * granted (<i>positive</i>) or denied (<i>negative</i>) to a {@link Principal}.
+ */
+public interface AclEntry extends Cloneable {
+
+ /**
+ * Set the principal for this ACL entry.
+ * <p>
+ * The principal for an ACL entry can only be set once.
+ *
+ * @param user
+ * the principal for this ACL entry.
+ * @return {@code true} on success, {@code false} if there is a principal already set for
+ * this entry.
+ */
+ boolean setPrincipal(Principal user);
+
+ /**
+ * Returns the principal of this ACL entry.
+ *
+ * @return the principal of this ACL entry, or null if none is set.
+ */
+ Principal getPrincipal();
+
+ /**
+ * Sets this ACL entry to be <i>negative</i>.
+ * <p>
+ * The permissions in this ACL entry will be denied to the principal
+ * associated with this entry.
+ * <p>
+ * Note: An ACL entry is <i>positive</i> by default and can only become
+ * <i>negative</i> by calling this method.
+ */
+ void setNegativePermissions();
+
+ /**
+ * Returns whether this ACL entry is <i>negative</i>.
+ *
+ * @return {@code true} if this ACL entry is negative, {@code false} if it's positive.
+ */
+ boolean isNegative();
+
+ /**
+ * Adds the specified permission to this ACL entry.
+ *
+ * @param permission
+ * the permission to be added.
+ * @return {@code true} if the specified permission is added, {@code false} if the
+ * permission was already in this entry.
+ */
+ boolean addPermission(Permission permission);
+
+ /**
+ * Removes the specified permission from this ACL entry.
+ *
+ * @param permission
+ * the permission to be removed.
+ * @return {@code true} if the permission is removed, {@code false} if the permission was
+ * not in this entry.
+ */
+ boolean removePermission(Permission permission);
+
+ /**
+ * Checks whether the specified permission is in this ACL entry.
+ *
+ * @param permission
+ * the permission to check.
+ * @return {@code true} if the permission is in this entry, otherwise {@code false}.
+ */
+ boolean checkPermission(Permission permission);
+
+ /**
+ * Returns the list of permissions of this ACL entry.
+ *
+ * @return the list of permissions of this ACL entry,
+ */
+ Enumeration<Permission> permissions();
+
+ /**
+ * Returns the string representation of this ACL entry.
+ *
+ * @return the string representation of this ACL entry.
+ */
+ String toString();
+
+ /**
+ * Clones this ACL entry instance.
+ *
+ * @return a copy of this entry.
+ */
+ Object clone();
+
+}
diff --git a/luni/src/main/java/java/security/acl/AclNotFoundException.java b/luni/src/main/java/java/security/acl/AclNotFoundException.java
new file mode 100644
index 0000000..59b9045
--- /dev/null
+++ b/luni/src/main/java/java/security/acl/AclNotFoundException.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.acl;
+
+/**
+ * The exception, that is thrown when a reference to a non-existent <i>Access
+ * Control List</i> (ACL) is made.
+ */
+public class AclNotFoundException extends Exception {
+
+ private static final long serialVersionUID = 5684295034092681791L;
+
+ /**
+ * Creates a new {@code AclNotFoundException}.
+ */
+ public AclNotFoundException() {
+
+ }
+}
diff --git a/luni/src/main/java/java/security/acl/Group.java b/luni/src/main/java/java/security/acl/Group.java
new file mode 100644
index 0000000..7452181
--- /dev/null
+++ b/luni/src/main/java/java/security/acl/Group.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.acl;
+
+import java.security.Principal;
+import java.util.Enumeration;
+
+/**
+ * A {@code Principal} that represents a group of principals.
+ *
+ * @see Principal
+ */
+public interface Group extends Principal {
+
+ /**
+ * Adds a member to this group.
+ *
+ * @param user
+ * the member to add.
+ * @return {@code true} if the member was added, {@code false} if it was already a member.
+ */
+ boolean addMember(Principal user);
+
+ /**
+ * Removes a member from this group.
+ *
+ * @param user
+ * the member to remove.
+ * @return {@code true} if the member was removed, {@code false} if it was not a member.
+ */
+ boolean removeMember(Principal user);
+
+ /**
+ * Returns whether the specified principal is a member of this group.
+ *
+ * @param member
+ * the principal to check.
+ * @return {@code true} if the principal is a member, otherwise {@code false}.
+ */
+ boolean isMember(Principal member);
+
+ /**
+ * Returns the members of this group.
+ *
+ * @return the members of this group.
+ */
+ Enumeration<? extends Principal> members();
+
+}
diff --git a/luni/src/main/java/java/security/acl/LastOwnerException.java b/luni/src/main/java/java/security/acl/LastOwnerException.java
new file mode 100644
index 0000000..f947f22
--- /dev/null
+++ b/luni/src/main/java/java/security/acl/LastOwnerException.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.acl;
+
+/**
+ * The exception that is thrown when an attempt is made to remove the
+ * the last {@code Owner} from an {@code Owner}.
+ *
+ * @see Owner
+ */
+public class LastOwnerException extends Exception {
+
+ private static final long serialVersionUID = -5141997548211140359L;
+
+ /**
+ * Creates a new {@code LastOwnerException}.
+ */
+ public LastOwnerException() {
+ }
+}
diff --git a/luni/src/main/java/java/security/acl/NotOwnerException.java b/luni/src/main/java/java/security/acl/NotOwnerException.java
new file mode 100644
index 0000000..c7de8c9
--- /dev/null
+++ b/luni/src/main/java/java/security/acl/NotOwnerException.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.acl;
+
+/**
+ * The exception that is thrown when an action that requires ownership is
+ * attempted by a principal that is not an owner of the object for which
+ * ownership is required.
+ *
+ * @see Acl
+ * @see Owner
+ */
+public class NotOwnerException extends Exception {
+
+ private static final long serialVersionUID = -5555597911163362399L;
+
+ /**
+ * Creates a new {@code NotOwnerException}.
+ */
+ public NotOwnerException() {
+ }
+}
diff --git a/luni/src/main/java/java/security/acl/Owner.java b/luni/src/main/java/java/security/acl/Owner.java
new file mode 100644
index 0000000..c392e2f
--- /dev/null
+++ b/luni/src/main/java/java/security/acl/Owner.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.acl;
+
+import java.security.Principal;
+
+/**
+ * The interface to manage owners of objects that require ownership.
+ *
+ * @see Acl
+ * @see Principal
+ */
+public interface Owner {
+
+ /**
+ * Adds a principal to the list of owners.
+ *
+ * @param caller
+ * the invoking principal.
+ * @param owner
+ * the owner to added.
+ * @return {@code true} if the owner was added, {@code false} if it was already an owner.
+ * @throws NotOwnerException
+ * if the invoking principal is not an owner.
+ */
+ boolean addOwner(Principal caller, Principal owner)
+ throws NotOwnerException;
+
+ /**
+ * Removes a principal from the list of owners.
+ *
+ * @param caller
+ * the invoking principal.
+ * @param owner
+ * the owner to be removed.
+ * @return {@code true} if the owner was removed, {@code false} if it was not an owner.
+ * @throws NotOwnerException
+ * if the invoking principal is not an owner.
+ * @throws LastOwnerException
+ * if the owner to be removed is the last owner and hence removing it
+ * would make this object owner-less.
+ */
+ boolean deleteOwner(Principal caller, Principal owner)
+ throws NotOwnerException, LastOwnerException;
+
+ /**
+ * Checks whether the specified principal is an owner of this object.
+ *
+ * @param owner
+ * the principal to check.
+ * @return {@code true} if the specified principal is an owner, otherwise {@code false}.
+ */
+ boolean isOwner(Principal owner);
+}
diff --git a/luni/src/main/java/java/security/acl/Permission.java b/luni/src/main/java/java/security/acl/Permission.java
new file mode 100644
index 0000000..f2ee251
--- /dev/null
+++ b/luni/src/main/java/java/security/acl/Permission.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.acl;
+
+/**
+ * The interface that represents a permission.
+ * <p>
+ * It can be granted or denied to a {@link java.security.Principal Principal}
+ * using an {@link Acl}.
+ */
+public interface Permission {
+
+
+ /**
+ * Checks whether the specified object equals this permission.
+ *
+ * @param another
+ * the permission object to compare to this permission.
+ * @return true if the specified permission object is equal to this, false
+ * if not.
+ */
+ boolean equals(Object another);
+
+ /**
+ * Returns the string representation of this permission.
+ *
+ * @return the string representation of this permission.
+ */
+ String toString();
+}
diff --git a/luni/src/main/java/java/security/acl/package.html b/luni/src/main/java/java/security/acl/package.html
new file mode 100644
index 0000000..b8ec061
--- /dev/null
+++ b/luni/src/main/java/java/security/acl/package.html
@@ -0,0 +1,14 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
+</head>
+<html>
+<body>
+<p>
+This package provides the classes and the interfaces needed to build Access Control Lists.
+Functionality for generating new entries in an ACL {@link java.security.acl.AclEntry},
+for the creation of new owners {@link java.security.acl.Owner}, and for the registration of
+new permissions {@link java.security.acl.Permission} are provided.
+</p>
+</body>
+</html>
diff --git a/luni/src/main/java/java/security/cert/CRL.java b/luni/src/main/java/java/security/cert/CRL.java
new file mode 100644
index 0000000..8153853
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/CRL.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * This class represents Certificate Revocation Lists (CRLs) maintained by a
+ * certificate authority. They are used to indicate that a given Certificate has
+ * expired and consequently has become invalid.
+ *
+ * @see CertificateFactory
+ */
+public abstract class CRL {
+ // The CRL type
+ private final String type;
+
+ /**
+ * Creates a new certificate revocation list of the specified type.
+ *
+ * @param type
+ * the type for the CRL.
+ */
+ protected CRL(String type) {
+ this.type = type;
+ }
+
+ /**
+ * Returns the type of this CRL.
+ *
+ * @return the type of this CRL.
+ */
+ public final String getType() {
+ return type;
+ }
+
+ /**
+ * Returns whether the specified certificate is revoked by this CRL.
+ *
+ * @param cert
+ * the certificate to check.
+ * @return {@code true} if the certificate is revoked by this CRL, otherwise
+ * {@code false}.
+ */
+ public abstract boolean isRevoked(Certificate cert);
+
+ /**
+ * Returns the string representation of this instance.
+ *
+ * @return the string representation of this instance.
+ */
+ public abstract String toString();
+}
diff --git a/luni/src/main/java/java/security/cert/CRLException.java b/luni/src/main/java/java/security/cert/CRLException.java
new file mode 100644
index 0000000..01e2071
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/CRLException.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.security.GeneralSecurityException;
+
+/**
+ * The exception that is thrown if errors occur during handling of {@code CRL}s.
+ */
+public class CRLException extends GeneralSecurityException {
+
+ private static final long serialVersionUID = -6694728944094197147L;
+
+ /**
+ * Creates a new {@code CRLException} with the specified message.
+ *
+ * @param msg
+ * the detail message for this exception.
+ */
+ public CRLException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Creates a new {@code CRLException}.
+ */
+ public CRLException() {
+ }
+
+ /**
+ * Creates a new {@code CRLException} with the specified message and cause.
+ *
+ * @param message
+ * the detail message for this exception.
+ * @param cause
+ * the cause for this exception.
+ */
+ public CRLException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Creates a new {@code CRLException} with the specified cause.
+ *
+ * @param cause
+ * the cause for this exception.
+ */
+ public CRLException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/luni/src/main/java/java/security/cert/CRLSelector.java b/luni/src/main/java/java/security/cert/CRLSelector.java
new file mode 100644
index 0000000..5b14446
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/CRLSelector.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * The interface specification for determining whether a CRL meets some criteria
+ * to select CRL objects among a set of {@code CRL}s.
+ * <p>
+ * The implementations of this interface are typically used to define the
+ * criteria for selecting {@code CRL}s from a {@code CertStore}.
+ *
+ * @see CertStore
+ * @see CRL
+ */
+public interface CRLSelector extends Cloneable {
+
+ /**
+ * Clones this {@code CRLSelector} instance.
+ *
+ * @return the cloned instance.
+ */
+ public Object clone();
+
+ /**
+ * Checks whether the defined criteria of this instance match the specified
+ * CRL.
+ *
+ * @param crl
+ * the CRL to be evaluated.
+ * @return {@code true} if the CRL matches the criteria, {@code false}
+ * otherwise.
+ */
+ public boolean match(CRL crl);
+}
diff --git a/luni/src/main/java/java/security/cert/CertPath.java b/luni/src/main/java/java/security/cert/CertPath.java
new file mode 100644
index 0000000..e9d049b
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/CertPath.java
@@ -0,0 +1,239 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.ByteArrayInputStream;
+import java.io.NotSerializableException;
+import java.io.ObjectStreamException;
+import java.io.ObjectStreamField;
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * An immutable certificate path that can be validated. All certificates in the
+ * path are of the same type (i.e., X509).
+ * <p>
+ * A {@code CertPath} can be represented as a byte array in at least one
+ * supported encoding scheme (i.e. PkiPath or PKCS7) when serialized.
+ * <p>
+ * When a {@code List} of the certificates is obtained it must be immutable.
+ * <p>
+ * A {@code CertPath} must be thread-safe without requiring coordinated access.
+ *
+ * @see Certificate
+ */
+public abstract class CertPath implements Serializable {
+
+ private static final long serialVersionUID = 6068470306649138683L;
+ // Standard name of the type of certificates in this path
+ private final String type;
+
+ /**
+ * Creates a new {@code CertPath} instance for the specified certificate
+ * type.
+ *
+ * @param type
+ * the certificate type.
+ */
+ protected CertPath(String type) {
+ this.type = type;
+ }
+
+ /**
+ * Returns the type of {@code Certificate} in this instance.
+ *
+ * @return the certificate type.
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * Returns {@code true} if {@code Certificate}s in the list are the same
+ * type and the lists are equal (and by implication the certificates
+ * contained within are the same).
+ *
+ * @param other
+ * {@code CertPath} to be compared for equality.
+ * @return {@code true} if the object are equal, {@code false} otherwise.
+ */
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (other instanceof CertPath) {
+ CertPath o = (CertPath)other;
+ if (getType().equals(o.getType())) {
+ if (getCertificates().equals(o.getCertificates())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Overrides {@code Object.hashCode()}. The function is defined as follows:
+ * <pre>
+ * {@code hashCode = 31 * path.getType().hashCode() +
+ * path.getCertificates().hashCode();}
+ * </pre>
+ *
+ * @return the hash code for this instance.
+ */
+ public int hashCode() {
+ int hash = getType().hashCode();
+ hash = hash*31 + getCertificates().hashCode();
+ return hash;
+ }
+
+ /**
+ * Returns a {@code String} representation of this {@code CertPath}
+ * instance. It is the result of calling {@code toString} on all {@code
+ * Certificate}s in the {@code List}.
+ *
+ * @return a string representation of this instance.
+ */
+ public String toString() {
+ StringBuilder sb = new StringBuilder(getType());
+ sb.append(" Cert Path, len="); //$NON-NLS-1$
+ sb.append(getCertificates().size());
+ sb.append(": [\n"); //$NON-NLS-1$
+ int n=1;
+ // BEGIN android-changed
+ for (Iterator<? extends Certificate> i=getCertificates().iterator();
+ i.hasNext(); n++) {
+ sb.append("---------------certificate "); //$NON-NLS-1$
+ sb.append(n);
+ sb.append("---------------\n"); //$NON-NLS-1$
+ sb.append(((Certificate)i.next()).toString());
+ }
+ // END android-changed
+ sb.append("\n]"); //$NON-NLS-1$
+ return sb.toString();
+ }
+
+ /**
+ * Returns an immutable List of the {@code Certificate}s contained
+ * in the {@code CertPath}.
+ *
+ * @return a list of {@code Certificate}s in the {@code CertPath}.
+ */
+ public abstract List<? extends Certificate> getCertificates();
+
+ /**
+ * Returns an encoding of the {@code CertPath} using the default encoding.
+ *
+ * @return default encoding of the {@code CertPath}.
+ * @throws CertificateEncodingException
+ * if the encoding fails.
+ */
+ public abstract byte[] getEncoded()
+ throws CertificateEncodingException;
+
+ /**
+ * Returns an encoding of the {@code CertPath} using the specified encoding.
+ *
+ * @param encoding
+ * encoding that should be generated.
+ * @return default encoding of the {@code CertPath}.
+ * @throws CertificateEncodingException
+ * if the encoding fails.
+ */
+ public abstract byte[] getEncoded(String encoding)
+ throws CertificateEncodingException;
+
+ /**
+ * Returns an {@code Iterator} over the supported encodings for a
+ * representation of the certificate path.
+ *
+ * @return {@code Iterator} over supported encodings (as {@code String}s).
+ */
+ public abstract Iterator<String> getEncodings();
+
+ /**
+ * Returns an alternate object to be serialized.
+ *
+ * @return an alternate object to be serialized.
+ * @throws ObjectStreamException
+ * if the creation of the alternate object fails.
+ */
+ protected Object writeReplace() throws ObjectStreamException {
+ try {
+ return new CertPathRep(getType(), getEncoded());
+ } catch (CertificateEncodingException e) {
+ throw new NotSerializableException (
+ Messages.getString("security.66", e)); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * The alternate {@code Serializable} class to be used for serialization and
+ * deserialization on {@code CertPath} objects.
+ */
+ protected static class CertPathRep implements Serializable {
+
+ private static final long serialVersionUID = 3015633072427920915L;
+ // Standard name of the type of certificates in this path
+ private final String type;
+ // cert path data
+ private final byte[] data;
+
+ // Force default serialization to use writeUnshared/readUnshared
+ // for cert path data
+ private static final ObjectStreamField[] serialPersistentFields = {
+ new ObjectStreamField("type", String.class), //$NON-NLS-1$
+ new ObjectStreamField("data", byte[].class, true) //$NON-NLS-1$
+ };
+
+ /**
+ * Creates a new {@code CertPathRep} instance with the specified type
+ * and encoded data.
+ *
+ * @param type
+ * the certificate type.
+ * @param data
+ * the encoded data.
+ */
+ protected CertPathRep(String type, byte[] data) {
+ this.type = type;
+ this.data = data;
+ }
+
+ /**
+ * Deserializes a {@code CertPath} from a serialized {@code CertPathRep}
+ * object.
+ *
+ * @return the deserialized {@code CertPath}.
+ * @throws ObjectStreamException
+ * if deserialization fails.
+ */
+ protected Object readResolve() throws ObjectStreamException {
+ try {
+ CertificateFactory cf = CertificateFactory.getInstance(type);
+ return cf.generateCertPath(new ByteArrayInputStream(data));
+ } catch (Throwable t) {
+ throw new NotSerializableException(
+ Messages.getString("security.67", t)); //$NON-NLS-1$
+ }
+ }
+ }
+}
diff --git a/luni/src/main/java/java/security/cert/CertPathBuilder.java b/luni/src/main/java/java/security/cert/CertPathBuilder.java
new file mode 100644
index 0000000..8daa741
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/CertPathBuilder.java
@@ -0,0 +1,215 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.security.AccessController;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.Security;
+
+import org.apache.harmony.security.fortress.Engine;
+import org.apache.harmony.security.internal.nls.Messages;
+
+
+/**
+ * This class implements the functionality of a builder for an unverified
+ * <i>Certification Path</i>s from a specified certificate to a trust anchor.
+ */
+public class CertPathBuilder {
+
+ // Store CertPathBuilder service name
+ private static final String SERVICE = "CertPathBuilder"; //$NON-NLS-1$
+
+ // Used to access common engine functionality
+ private static Engine engine = new Engine(SERVICE);
+
+ // Store default property name
+ private static final String PROPERTYNAME = "certpathbuilder.type"; //$NON-NLS-1$
+
+ // Default value of CertPathBuilder type. It returns if certpathbuild.type
+ // property is not defined in java.security file
+ private static final String DEFAULTPROPERTY = "PKIX"; //$NON-NLS-1$
+
+ // Store used provider
+ private final Provider provider;
+
+ // Store spi implementation
+ private CertPathBuilderSpi spiImpl;
+
+ // Store algorithm name
+ private final String algorithm;
+
+ /**
+ * Creates a new {@code CertPathBuilder}.
+ *
+ * @param builderSpi
+ * the implementation delegate.
+ * @param provider
+ * the provider.
+ * @param algorithm
+ * the desired algorithm available at the provider.
+ */
+ protected CertPathBuilder(CertPathBuilderSpi builderSpi, Provider provider,
+ String algorithm) {
+ this.provider = provider;
+ this.algorithm = algorithm;
+ this.spiImpl = builderSpi;
+ }
+
+ /**
+ * Returns the algorithm name of this instance.
+ *
+ * @return the algorithm name of this instance.
+ */
+ public final String getAlgorithm() {
+ return algorithm;
+ }
+
+ /**
+ * Returns the provider of this instance.
+ *
+ * @return the provider of this instance.
+ */
+ public final Provider getProvider() {
+ return provider;
+ }
+
+ /**
+ * Creates a new {@code CertPathBuilder} instance with the specified
+ * algorithm.
+ *
+ * @param algorithm
+ * the name of the algorithm.
+ * @return a builder for the requested algorithm.
+ * @throws NullPointerException
+ * if the algorithm is {@code null}.
+ * @throws NoSuchAlgorithmException
+ * if no installed provider can provide the algorithm.
+ */
+ public static CertPathBuilder getInstance(String algorithm)
+ throws NoSuchAlgorithmException {
+ if (algorithm == null) {
+ throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+ }
+ synchronized (engine) {
+ engine.getInstance(algorithm, null);
+ return new CertPathBuilder((CertPathBuilderSpi) engine.spi,
+ engine.provider, algorithm);
+ }
+ }
+
+ /**
+ * Creates a new {@code CertPathBuilder} instance from the specified
+ * provider providing the specified algorithm.
+ *
+ * @param algorithm
+ * the name of the algorithm.
+ * @param provider
+ * the name of the provider.
+ * @return a builder for the requested algorithm.
+ * @throws NoSuchAlgorithmException
+ * if the specified provider cannot provide the algorithm.
+ * @throws NoSuchProviderException
+ * if no provider with the specified name can be found.
+ * @throws NullPointerException
+ * if algorithm is {@code null}.
+ * @throws IllegalArgumentException
+ * if provider is {@code null} or empty.
+ */
+ public static CertPathBuilder getInstance(String algorithm, String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException {
+ if ((provider == null) || (provider.length() == 0)) {
+ throw new IllegalArgumentException(Messages.getString("security.02")); //$NON-NLS-1$
+ }
+ Provider impProvider = Security.getProvider(provider);
+ if (impProvider == null) {
+ throw new NoSuchProviderException(provider);
+ }
+ return getInstance(algorithm, impProvider);
+
+ }
+
+ /**
+ * Creates a new {@code CertPathBuilder} instance from the specified
+ * provider providing the specified algorithm.
+ *
+ * @param algorithm
+ * the name of the algorithm.
+ * @param provider
+ * the provider.
+ * @return a builder for the requested algorithm
+ * @throws NoSuchAlgorithmException
+ * if the specified provider cannot provide the algorithm.
+ * @throws IllegalArgumentException
+ * if provider is {@code null}.
+ * @throws NullPointerException
+ * if algorithm is {@code null}.
+ */
+ public static CertPathBuilder getInstance(String algorithm,
+ Provider provider) throws NoSuchAlgorithmException {
+ if (provider == null) {
+ throw new IllegalArgumentException(Messages.getString("security.04")); //$NON-NLS-1$
+ }
+ if (algorithm == null) {
+ throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+ }
+ synchronized (engine) {
+ engine.getInstance(algorithm, provider, null);
+ return new CertPathBuilder((CertPathBuilderSpi) engine.spi, provider,
+ algorithm);
+ }
+ }
+
+ /**
+ * Builds a certification path with the specified algorithm parameters.
+ *
+ * @param params
+ * the algorithm parameters.
+ * @return the built certification path.
+ * @throws CertPathBuilderException
+ * if the build fails.
+ * @throws InvalidAlgorithmParameterException
+ * if the specified parameters cannot be used to build with this
+ * builder.
+ * @see CertPathBuilderResult
+ */
+ public final CertPathBuilderResult build(CertPathParameters params)
+ throws CertPathBuilderException, InvalidAlgorithmParameterException {
+ return spiImpl.engineBuild(params);
+ }
+
+ /**
+ * Returns the default {@code CertPathBuilder} type from the <i>Security
+ * Properties</i>.
+ *
+ * @return the default {@code CertPathBuilder} type from the <i>Security
+ * Properties</i>, or the string "{@code PKIX}" if it cannot be
+ * determined.
+ */
+ public static final String getDefaultType() {
+ String defaultType = AccessController
+ .doPrivileged(new java.security.PrivilegedAction<String>() {
+ public String run() {
+ return Security.getProperty(PROPERTYNAME);
+ }
+ });
+ return (defaultType != null ? defaultType : DEFAULTPROPERTY);
+ }
+}
diff --git a/luni/src/main/java/java/security/cert/CertPathBuilderException.java b/luni/src/main/java/java/security/cert/CertPathBuilderException.java
new file mode 100644
index 0000000..58a4a60
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/CertPathBuilderException.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.security.GeneralSecurityException;
+
+/**
+ * The exception that is thrown when a {@code CertPathBuilder} method fails.
+ */
+public class CertPathBuilderException extends GeneralSecurityException {
+
+ private static final long serialVersionUID = 5316471420178794402L;
+
+ /**
+ * Creates a new {@code CertPathBuilderException} with the specified message
+ * and cause.
+ *
+ * @param msg
+ * the detail message for the exception
+ * @param cause
+ * why the building of the certification path failed.
+ */
+ public CertPathBuilderException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+ /**
+ * Creates a new {@code CertPathBuilderException} with the specified cause.
+ *
+ * @param cause
+ * why the building of the certification path failed.
+ */
+ public CertPathBuilderException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * Creates a new {@code CertPathBuilderException} with the specified
+ * message.
+ *
+ * @param msg
+ * the detail message for the exception.
+ */
+ public CertPathBuilderException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Creates a new {@code CertPathBuilderException}.
+ */
+ public CertPathBuilderException() {
+ }
+}
diff --git a/luni/src/main/java/java/security/cert/CertPathBuilderResult.java b/luni/src/main/java/java/security/cert/CertPathBuilderResult.java
new file mode 100644
index 0000000..36d99a1
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/CertPathBuilderResult.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * The interface for results generated by
+ * {@link CertPathBuilder#build(CertPathParameters)}.
+ */
+public interface CertPathBuilderResult extends Cloneable {
+
+ /**
+ * Clones this {@code CertPathBuilderResult} instance.
+ *
+ * @return the copy of this instance.
+ */
+ public Object clone();
+
+ /**
+ * Returns the built {@code CertPath} instance. Never returns {@code null}.
+ *
+ * @return the built certificate path instance.
+ */
+ public CertPath getCertPath();
+}
diff --git a/luni/src/main/java/java/security/cert/CertPathBuilderSpi.java b/luni/src/main/java/java/security/cert/CertPathBuilderSpi.java
new file mode 100644
index 0000000..80ee0ef
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/CertPathBuilderSpi.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.security.InvalidAlgorithmParameterException;
+
+/**
+ * The <i>Service Provider Interface</i> (<b>SPI</b>) for the {@code
+ * CertPathBuilder} class to be implemented by security providers.
+ */
+public abstract class CertPathBuilderSpi {
+
+ /**
+ * Creates a new {@code CertPathBuilderSpi} instance.
+ */
+ public CertPathBuilderSpi() {
+ }
+
+ /**
+ * Builds a certification path with the specified algorithm parameters.
+ *
+ * @param params
+ * the algorithm parameters.
+ * @return a result of the build.
+ * @throws CertPathBuilderException
+ * if the build fails.
+ * @throws InvalidAlgorithmParameterException
+ * if the specified parameters cannot be used to build the path
+ * with this builder.
+ */
+ public abstract CertPathBuilderResult engineBuild(CertPathParameters params)
+ throws CertPathBuilderException, InvalidAlgorithmParameterException;
+}
diff --git a/luni/src/main/java/java/security/cert/CertPathParameters.java b/luni/src/main/java/java/security/cert/CertPathParameters.java
new file mode 100644
index 0000000..e2cee18
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/CertPathParameters.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * The interface specification for certification path algorithm parameters.
+ * <p>
+ * This interface is for grouping purposes of {@code CertPath} parameter
+ * implementations.
+ */
+public interface CertPathParameters extends Cloneable {
+
+ /**
+ * Clones this {@code CertPathParameters} instance.
+ *
+ * @return the cloned instance.
+ */
+ public Object clone();
+}
diff --git a/luni/src/main/java/java/security/cert/CertPathValidator.java b/luni/src/main/java/java/security/cert/CertPathValidator.java
new file mode 100644
index 0000000..0d73280
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/CertPathValidator.java
@@ -0,0 +1,222 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.security.AccessController;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.Security;
+
+import org.apache.harmony.security.fortress.Engine;
+import org.apache.harmony.security.internal.nls.Messages;
+
+
+/**
+ * This class provides the functionality for validating certification paths
+ * (certificate chains) establishing a trust chain from a certificate to a trust
+ * anchor.
+ */
+public class CertPathValidator {
+ // Store CertPathValidator implementation service name
+ private static final String SERVICE = "CertPathValidator"; //$NON-NLS-1$
+
+ // Used to access common engine functionality
+ private static Engine engine = new Engine(SERVICE);
+
+ // Store default property name
+ private static final String PROPERTYNAME = "certpathvalidator.type"; //$NON-NLS-1$
+
+ // Default value of CertPathBuilder type. It returns if certpathbuild.type
+ // property is not defined in java.security file
+ private static final String DEFAULTPROPERTY = "PKIX"; //$NON-NLS-1$
+
+ // Store used provider
+ private final Provider provider;
+
+ // Store used spi implementation
+ private final CertPathValidatorSpi spiImpl;
+
+ // Store used algorithm value
+ private final String algorithm;
+
+ /**
+ * Creates a new {@code CertPathValidator} instance.
+ *
+ * @param validatorSpi
+ * the implementation delegate.
+ * @param provider
+ * the security provider.
+ * @param algorithm
+ * the name of the algorithm.
+ */
+ protected CertPathValidator(CertPathValidatorSpi validatorSpi,
+ Provider provider, String algorithm) {
+ this.provider = provider;
+ this.algorithm = algorithm;
+ this.spiImpl = validatorSpi;
+ }
+
+ /**
+ * Returns the certification path algorithm name.
+ *
+ * @return the certification path algorithm name.
+ */
+ public final String getAlgorithm() {
+ return algorithm;
+ }
+
+ /**
+ * Returns the security provider.
+ *
+ * @return the provider.
+ */
+ public final Provider getProvider() {
+ return provider;
+ }
+
+ /**
+ * Returns a new certification path validator for the specified algorithm.
+ *
+ * @param algorithm
+ * the algorithm name.
+ * @return a certification path validator for the requested algorithm.
+ * @throws NoSuchAlgorithmException
+ * if no installed provider provides the specified algorithm.
+ * @throws NullPointerException
+ * if algorithm is {@code null}.
+ */
+ public static CertPathValidator getInstance(String algorithm)
+ throws NoSuchAlgorithmException {
+ if (algorithm == null) {
+ throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+ }
+ synchronized (engine) {
+ engine.getInstance(algorithm, null);
+ return new CertPathValidator((CertPathValidatorSpi) engine.spi,
+ engine.provider, algorithm);
+ }
+ }
+
+ /**
+ * Returns a new certification path validator for the specified algorithm
+ * from the specified provider.
+ *
+ * @param algorithm
+ * the algorithm name.
+ * @param provider
+ * the security provider name.
+ * @return a certification path validator for the requested algorithm.
+ * @throws NoSuchAlgorithmException
+ * if the specified security provider cannot provide the
+ * requested algorithm.
+ * @throws NoSuchProviderException
+ * if no provider with the specified name can be found.
+ * @throws NullPointerException
+ * if algorithm is {@code null}.
+ * @throws IllegalArgumentException
+ * if provider is {@code null} or empty.
+ */
+ public static CertPathValidator getInstance(String algorithm,
+ String provider) throws NoSuchAlgorithmException,
+ NoSuchProviderException {
+ if ((provider == null) || (provider.length() == 0)) {
+ throw new IllegalArgumentException(Messages.getString("security.02")); //$NON-NLS-1$
+ }
+ Provider impProvider = Security.getProvider(provider);
+ if (impProvider == null) {
+ throw new NoSuchProviderException(provider);
+ }
+ return getInstance(algorithm, impProvider);
+ }
+
+ /**
+ * Returns a new certification path validator for the specified algorithm
+ * from the specified provider.
+ *
+ * @param algorithm
+ * the algorithm name.
+ * @param provider
+ * the security provider name.
+ * @return a certification path validator for the requested algorithm.
+ * @throws NoSuchAlgorithmException
+ * if the specified provider cannot provide the requested
+ * algorithm.
+ * @throws IllegalArgumentException
+ * if provider is {@code null}.
+ * @throws NullPointerException
+ * if algorithm is {@code null}.
+ */
+ public static CertPathValidator getInstance(String algorithm,
+ Provider provider) throws NoSuchAlgorithmException {
+ if (provider == null) {
+ throw new IllegalArgumentException(Messages.getString("security.04")); //$NON-NLS-1$
+ }
+ if (algorithm == null) {
+ throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+ }
+ synchronized (engine) {
+ engine.getInstance(algorithm, provider, null);
+ return new CertPathValidator((CertPathValidatorSpi) engine.spi,
+ provider, algorithm);
+ }
+ }
+
+ /**
+ * Validates the {@code CertPath} with the algorithm of this {@code
+ * CertPathValidator} using the specified algorithm parameters.
+ *
+ * @param certPath
+ * the certification path to be validated.
+ * @param params
+ * the certification path validator algorithm parameters.
+ * @return the validation result.
+ * @throws CertPathValidatorException
+ * if the validation fails, or the algorithm of the specified
+ * certification path cannot be validated using the algorithm of
+ * this instance.
+ * @throws InvalidAlgorithmParameterException
+ * if the specified algorithm parameters cannot be used with
+ * this algorithm.
+ * @see CertPathValidatorResult
+ */
+ public final CertPathValidatorResult validate(CertPath certPath,
+ CertPathParameters params) throws CertPathValidatorException,
+ InvalidAlgorithmParameterException {
+ return spiImpl.engineValidate(certPath, params);
+ }
+
+ /**
+ * Returns the default {@code CertPathValidator} type from the <i>Security
+ * Properties</i>.
+ *
+ * @return the default {@code CertPathValidator} type from the <i>Security
+ * Properties</i>, or the string {@code "PKIX"} if it cannot be
+ * determined.
+ */
+ public static final String getDefaultType() {
+ String defaultType = AccessController
+ .doPrivileged(new java.security.PrivilegedAction<String>() {
+ public String run() {
+ return Security.getProperty(PROPERTYNAME);
+ }
+ });
+ return (defaultType != null ? defaultType : DEFAULTPROPERTY);
+ }
+}
diff --git a/luni/src/main/java/java/security/cert/CertPathValidatorException.java b/luni/src/main/java/java/security/cert/CertPathValidatorException.java
new file mode 100644
index 0000000..4d2b69f
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/CertPathValidatorException.java
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.security.GeneralSecurityException;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * The exception that is thrown when a certification path (or certificate chain)
+ * cannot be validated.
+ * <p>
+ * A {@code CertPathValidatorException} may optionally include the certification
+ * path instance that failed the validation and the index of the failed
+ * certificate.
+ */
+public class CertPathValidatorException extends GeneralSecurityException {
+
+ private static final long serialVersionUID = -3083180014971893139L;
+
+ /**
+ * the certification path.
+ */
+ private CertPath certPath;
+
+ /**
+ * the index of the certificate.
+ */
+ private int index = -1;
+
+ /**
+ * Creates a new {@code CertPathValidatorException} with the specified
+ * message , cause, certification path and certificate index in the
+ * certification path.
+ *
+ * @param msg
+ * the detail message for this exception.
+ * @param cause
+ * the cause.
+ * @param certPath
+ * the certification path that failed the validation.
+ * @param index
+ * the index of the failed certificate.
+ * @throws IllegalArgumentException
+ * if {@code certPath} is {@code null} and index is not {@code
+ * -1}.
+ * @throws IndexOutOfBoundsException
+ * if {@code certPath} is not {@code null} and index is not
+ * referencing an certificate in the certification path.
+ */
+ public CertPathValidatorException(String msg, Throwable cause,
+ CertPath certPath, int index) {
+ super(msg, cause);
+ // check certPath and index parameters
+ if ((certPath == null) && (index != -1)) {
+ throw new IllegalArgumentException(
+ Messages.getString("security.53")); //$NON-NLS-1$
+ }
+ if ((certPath != null)
+ && ((index < -1) || (index >= certPath.getCertificates().size()))) {
+ throw new IndexOutOfBoundsException(Messages.getString("security.54")); //$NON-NLS-1$
+ }
+ this.certPath = certPath;
+ this.index = index;
+ }
+
+ /**
+ * Creates a new {@code CertPathValidatorException} with the specified
+ * message and cause.
+ *
+ * @param msg
+ * the detail message for this exception.
+ * @param cause
+ * the cause why the path could not be validated.
+ */
+ public CertPathValidatorException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+ /**
+ * Creates a new {@code CertPathValidatorException} with the specified
+ * cause.
+ *
+ * @param cause
+ * the cause why the path could not be validated.
+ */
+ public CertPathValidatorException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * Creates a new {@code CertPathValidatorException} with the specified
+ * message.
+ *
+ * @param msg
+ * the detail message for this exception.
+ */
+ public CertPathValidatorException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Creates a new {@code CertPathValidatorException}.
+ */
+ public CertPathValidatorException() {
+ }
+
+ /**
+ * Returns the certification path that failed validation.
+ *
+ * @return the certification path that failed validation, or {@code null} if
+ * none was specified.
+ */
+ public CertPath getCertPath() {
+ return certPath;
+ }
+
+ /**
+ * Returns the index of the failed certificate in the certification path.
+ *
+ * @return the index of the failed certificate in the certification path, or
+ * {@code -1} if none was specified.
+ */
+ public int getIndex() {
+ return index;
+ }
+}
diff --git a/luni/src/main/java/java/security/cert/CertPathValidatorResult.java b/luni/src/main/java/java/security/cert/CertPathValidatorResult.java
new file mode 100644
index 0000000..7fab21a
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/CertPathValidatorResult.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * The interface specification for certification path validation results.
+ * <p>
+ * This interface is for grouping purposes of validation result implementations.
+ */
+public interface CertPathValidatorResult extends Cloneable {
+
+ /**
+ * Clones this {@code CertPathValidatorResult} instance.
+ *
+ * @return the cloned instance.
+ */
+ public Object clone();
+}
diff --git a/luni/src/main/java/java/security/cert/CertPathValidatorSpi.java b/luni/src/main/java/java/security/cert/CertPathValidatorSpi.java
new file mode 100644
index 0000000..e14e8dd
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/CertPathValidatorSpi.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.security.InvalidAlgorithmParameterException;
+
+/**
+ * The <i>Service Provider Interface</i> (<b>SPI</b>) for the {@code
+ * CertPathValidator} class to be implemented by security providers.
+ */
+public abstract class CertPathValidatorSpi {
+
+ /**
+ * Creates a new {@code CertPathValidatorSpi} instance.
+ */
+ public CertPathValidatorSpi() {
+ }
+
+ /**
+ * Validates the {@code CertPath} with the algorithm of this {@code
+ * CertPathValidator} using the specified algorithm parameters.
+ *
+ * @param certPath
+ * the certification path to be validated.
+ * @param params
+ * the certification path validator algorithm parameters.
+ * @return the validation result.
+ * @throws CertPathValidatorException
+ * if the validation fails, or the algorithm of the specified
+ * certification path cannot be validated using the algorithm of
+ * this instance.
+ * @throws InvalidAlgorithmParameterException
+ * if the specified algorithm parameters cannot be used with
+ * this algorithm.
+ */
+ public abstract CertPathValidatorResult engineValidate(CertPath certPath,
+ CertPathParameters params) throws CertPathValidatorException,
+ InvalidAlgorithmParameterException;
+
+}
diff --git a/luni/src/main/java/java/security/cert/CertSelector.java b/luni/src/main/java/java/security/cert/CertSelector.java
new file mode 100644
index 0000000..c490b22
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/CertSelector.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * The interface specification to determine whether a {@code
+ * Certificate} meets some criteria.
+ * <p>
+ * The implementations of this interface are typically used to define the
+ * criteria for selecting {@code Certificate}s from a {@code CertStore}.
+ *
+ * @see CertStore
+ * @see Certificate
+ */
+public interface CertSelector extends Cloneable {
+
+ /**
+ * Clones this {@code CertSelector} instance.
+ *
+ * @return the cloned instance.
+ */
+ public Object clone();
+
+ /**
+ * Checks whether the defined criteria of this instance match the specified
+ * certificate.
+ *
+ * @param cert
+ * the certificate to be evaluated.
+ * @return {@code true} if the certificate matches the criteria, {@code
+ * false} otherwise.
+ */
+ public boolean match(Certificate cert);
+}
diff --git a/luni/src/main/java/java/security/cert/CertStore.java b/luni/src/main/java/java/security/cert/CertStore.java
new file mode 100644
index 0000000..d0b7600
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/CertStore.java
@@ -0,0 +1,291 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.security.AccessController;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.Security;
+import java.util.Collection;
+
+import org.apache.harmony.security.fortress.Engine;
+import org.apache.harmony.security.internal.nls.Messages;
+
+
+/**
+ * This class provides the functionality to retrieve {@code Certificate}s and
+ * {@code CRL}s from a read-only repository. This repository may be very large
+ * and may store trusted as well as untrusted certificates.
+ */
+public class CertStore {
+
+ // Store spi implementation service name
+ private static final String SERVICE = "CertStore"; //$NON-NLS-1$
+
+ // Used to access common engine functionality
+ private static Engine engine = new Engine(SERVICE);
+
+ // Store default property name
+ private static final String PROPERTYNAME = "certstore.type"; //$NON-NLS-1$
+
+ // Default value of CertStore type. It returns if certpathbuild.type
+ // property is not defined in java.security file
+ private static final String DEFAULTPROPERTY = "LDAP"; //$NON-NLS-1$
+
+ // Store used provider
+ private final Provider provider;
+
+ // Store CertStoreSpi implementation
+ private final CertStoreSpi spiImpl;
+
+ // Store used type
+ private final String type;
+
+ // Store used parameters
+ private final CertStoreParameters certStoreParams;
+
+ /**
+ * Creates a new {@code CertStore} instance.
+ *
+ * @param storeSpi
+ * the implementation delegate.
+ * @param provider
+ * the security provider.
+ * @param type
+ * the certificate store type.
+ * @param params
+ * the certificate store parameters (may be {@code null}.
+ */
+ protected CertStore(CertStoreSpi storeSpi, Provider provider, String type,
+ CertStoreParameters params) {
+ this.provider = provider;
+ this.type = type;
+ this.spiImpl = storeSpi;
+ this.certStoreParams = params;
+ }
+
+ /**
+ * Creates a new {@code CertStore} instance with the specified type and
+ * initialized with the specified parameters.
+ *
+ * @param type
+ * the certificate store type.
+ * @param params
+ * the certificate store parameters (may be {@code null}).
+ * @return the new certificate store instance.
+ * @throws NoSuchAlgorithmException
+ * if no provider can provide the specified certificate store
+ * type.
+ * @throws InvalidAlgorithmParameterException
+ * if the specified parameters cannot be used to initialize this
+ * certificate store instance.
+ * @throws NullPointerException
+ * if the {@code type} is {@code null}.
+ */
+ public static CertStore getInstance(String type, CertStoreParameters params)
+ throws InvalidAlgorithmParameterException, NoSuchAlgorithmException {
+ if (type == null) {
+ throw new NullPointerException(Messages.getString("security.07")); //$NON-NLS-1$
+ }
+ try {
+ synchronized (engine) {
+ engine.getInstance(type, params);
+ return new CertStore((CertStoreSpi) engine.spi, engine.provider,
+ type, params);
+ }
+ } catch (NoSuchAlgorithmException e) {
+ Throwable th = e.getCause();
+ if (th == null) {
+ throw e;
+ } else {
+ throw new InvalidAlgorithmParameterException(e.getMessage(), th);
+ }
+ }
+ }
+
+ /**
+ * Creates a new {@code CertStore} instance from the specified provider with
+ * the specified type and initialized with the specified parameters.
+ *
+ * @param type
+ * the certificate store type.
+ * @param params
+ * the certificate store parameters (may be {@code null}).
+ * @param provider
+ * the name of the provider.
+ * @return the new certificate store instance.
+ * @throws NoSuchAlgorithmException
+ * if the specified provider cannot provide the requested
+ * certificate store type.
+ * @throws NoSuchProviderException
+ * if no provider with the specified name can be found.
+ * @throws InvalidAlgorithmParameterException
+ * if the specified parameters cannot be used to initialize this
+ * certificate store instance.
+ * @throws IllegalArgumentException
+ * if provider is null of empty.
+ * @throws NullPointerException
+ * if {@code type} is {@code null}.
+ */
+ public static CertStore getInstance(String type,
+ CertStoreParameters params, String provider)
+ throws InvalidAlgorithmParameterException,
+ NoSuchAlgorithmException, NoSuchProviderException {
+ if ((provider == null) || (provider.length() == 0)) {
+ throw new IllegalArgumentException(Messages.getString("security.02")); //$NON-NLS-1$
+ }
+ Provider impProvider = Security.getProvider(provider);
+ if (impProvider == null) {
+ throw new NoSuchProviderException(provider);
+ }
+ return getInstance(type, params, impProvider);
+ }
+
+ /**
+ * Creates a new {@code CertStore} instance from the specified provider with
+ * the specified type and initialized with the specified parameters.
+ * @param type
+ * the certificate store type.
+ * @param params
+ * the certificate store parameters (may be {@code null}).
+ * @param provider
+ * the name of the provider.
+ * @return the new certificate store instance.
+ * @throws NoSuchAlgorithmException
+ * if the specified provider cannot provide the requested
+ * certificate store type.
+ * @throws InvalidAlgorithmParameterException
+ * if the specified parameters cannot be used to initialize this
+ * certificate store instance.
+ * @throws IllegalArgumentException
+ * if provider is {@code null}.
+ * @throws NullPointerException
+ * if {@code type} is {@code null}.
+ */
+ public static CertStore getInstance(String type,
+ CertStoreParameters params, Provider provider)
+ throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
+ if (provider == null) {
+ throw new IllegalArgumentException(Messages.getString("security.04")); //$NON-NLS-1$
+ }
+ if (type == null) {
+ throw new NullPointerException(Messages.getString("security.07")); //$NON-NLS-1$
+ }
+ try {
+ synchronized (engine) {
+ engine.getInstance(type, provider, params);
+ return new CertStore((CertStoreSpi) engine.spi, provider, type,
+ params);
+ }
+ } catch (NoSuchAlgorithmException e) {
+ Throwable th = e.getCause();
+ if (th == null) {
+ throw e;
+ } else {
+ throw new InvalidAlgorithmParameterException(e.getMessage(), th);
+ }
+ }
+ }
+
+ /**
+ * Returns the certificate store type.
+ *
+ * @return the certificate store type.
+ */
+ public final String getType() {
+ return type;
+ }
+
+ /**
+ * Returns the security provider.
+ *
+ * @return the security provider.
+ */
+ public final Provider getProvider() {
+ return provider;
+ }
+
+ /**
+ * Returns a copy of the certificate store parameters that were used to
+ * initialize this instance.
+ *
+ * @return a copy of the certificate store parameters or {@code null} if
+ * none were specified.
+ */
+ public final CertStoreParameters getCertStoreParameters() {
+ if (certStoreParams == null) {
+ return null;
+ } else {
+ return (CertStoreParameters) certStoreParams.clone();
+ }
+ }
+
+ /**
+ * Returns the list of {@code Certificate}s for the specified {@code
+ * CertSelector} from this certificate store.
+ *
+ * @param selector
+ * the selector containing the criteria to search for
+ * certificates in this certificate store.
+ * @return the list of {@code Certificate}s that match the criteria of the
+ * specified selector.
+ * @throws CertStoreException
+ * if error(s) occur.
+ */
+ public final Collection<? extends Certificate> getCertificates(CertSelector selector)
+ throws CertStoreException {
+ return spiImpl.engineGetCertificates(selector);
+ }
+
+ /**
+ * Returns the list of {@code CRL}s for the specified {@code CRLSelector}
+ * from this certificate store.
+ *
+ * @param selector
+ * the selector containing the criteria to search for certificate
+ * revocation lists in this store.
+ * @return the list of {@code CRL}s that match the criteria of the specified
+ * selector
+ * @throws CertStoreException
+ * if error(s) occur.
+ */
+ public final Collection<? extends CRL> getCRLs(CRLSelector selector)
+ throws CertStoreException {
+ return spiImpl.engineGetCRLs(selector);
+ }
+
+ /**
+ * Returns the default {@code CertStore} type from the <i>Security
+ * Properties</i>.
+ *
+ * @return the default {@code CertStore} type from the <i>Security
+ * Properties</i>, or the string {@code "LDAP"} if it cannot be
+ * determined.
+ */
+ public static final String getDefaultType() {
+ String defaultType = AccessController
+ .doPrivileged(new java.security.PrivilegedAction<String>() {
+ public String run() {
+ return Security.getProperty(PROPERTYNAME);
+ }
+ });
+ return (defaultType == null ? DEFAULTPROPERTY : defaultType);
+ }
+}
diff --git a/luni/src/main/java/java/security/cert/CertStoreException.java b/luni/src/main/java/java/security/cert/CertStoreException.java
new file mode 100644
index 0000000..7f356b2
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/CertStoreException.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.security.GeneralSecurityException;
+
+/**
+ * The exception that is thrown when an access to a {@code CertStore} fails.
+ */
+public class CertStoreException extends GeneralSecurityException {
+
+ private static final long serialVersionUID = 2395296107471573245L;
+
+ /**
+ * Creates a new {@code CertStoreException} with the specified message and
+ * cause.
+ *
+ * @param msg
+ * the detail message for this exception.
+ * @param cause
+ * the cause why the access to the certificate store failed.
+ */
+ public CertStoreException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+ /**
+ * Creates a new {@code CertStoreException} with the specified cause.
+ *
+ * @param cause
+ * the cause why the access to the certificate store failed.
+ */
+ public CertStoreException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * Creates a new {@code CertStoreException} with the specified message.
+ *
+ * @param msg
+ * the detail message for this exception.
+ */
+ public CertStoreException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Creates a new {@code CertStoreException}.
+ */
+ public CertStoreException() {
+ }
+}
diff --git a/luni/src/main/java/java/security/cert/CertStoreParameters.java b/luni/src/main/java/java/security/cert/CertStoreParameters.java
new file mode 100644
index 0000000..06a1976
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/CertStoreParameters.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * The marker interface specifying the parameters used to initialize a {@code
+ * CertStore} instance.
+ */
+public interface CertStoreParameters extends Cloneable {
+
+ /**
+ * Clones this {@code CertStoreParameters} instance.
+ *
+ * @return the cloned instance.
+ */
+ public Object clone();
+}
diff --git a/luni/src/main/java/java/security/cert/CertStoreSpi.java b/luni/src/main/java/java/security/cert/CertStoreSpi.java
new file mode 100644
index 0000000..cb38a31
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/CertStoreSpi.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.security.InvalidAlgorithmParameterException;
+import java.util.Collection;
+
+/**
+ * The <i>Service Provider Interface</i> (<b>SPI</b>) definition for the {@code
+ * CertStore} class to be implemented by security providers.
+ */
+public abstract class CertStoreSpi {
+
+ /**
+ * Creates a new {@code CertStoreSpi}.
+ *
+ * @param params
+ * the initialization parameters.
+ * @throws InvalidAlgorithmParameterException
+ * if the specified initialization parameters cannot be used to
+ * initialize this instance.
+ */
+ public CertStoreSpi(CertStoreParameters params)
+ throws InvalidAlgorithmParameterException {
+ }
+
+ /**
+ * Returns the list of {@code Certificate}s for the specified {@code
+ * CertSelector} from this instance.
+ *
+ * @param selector
+ * the selector containing the criteria to search for
+ * certificates in this instance.
+ * @return the list of {@code Certificate}s that match the criteria of the
+ * specified selector.
+ * @throws CertStoreException
+ * if error(s) occur.
+ */
+ public abstract Collection<? extends Certificate> engineGetCertificates(CertSelector selector)
+ throws CertStoreException;
+
+ /**
+ * Returns the list of {@code CRL}s for the specified {@code CRLSelector}
+ * from this instance.
+ *
+ * @param selector
+ * the selector containing the criteria to search for certificate
+ * revocation lists in instance.
+ * @return the list of {@code CRL}s that match the criteria of the specified
+ * selector
+ * @throws CertStoreException
+ * if error(s) occur.
+ */
+ public abstract Collection<? extends CRL> engineGetCRLs(CRLSelector selector)
+ throws CertStoreException;
+}
diff --git a/luni/src/main/java/java/security/cert/Certificate.java b/luni/src/main/java/java/security/cert/Certificate.java
new file mode 100644
index 0000000..22cbe9c
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/Certificate.java
@@ -0,0 +1,257 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.ByteArrayInputStream;
+import java.io.NotSerializableException;
+import java.io.ObjectStreamException;
+import java.io.ObjectStreamField;
+import java.io.Serializable;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.util.Arrays;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * Abstract class to represent identity certificates. It represents a way to
+ * verify the binding of a Principal and its public key. Examples are X.509,
+ * PGP, and SDSI.
+ */
+public abstract class Certificate implements Serializable {
+
+ private static final long serialVersionUID = -3585440601605666277L;
+
+ // The standard name of the certificate type
+ private final String type;
+
+ /**
+ * Creates a new {@code Certificate} with the specified type.
+ *
+ * @param type
+ * the certificate type.
+ */
+ protected Certificate(String type) {
+ this.type = type;
+ }
+
+ /**
+ * Returns the certificate type.
+ *
+ * @return the certificate type.
+ */
+ public final String getType() {
+ return type;
+ }
+
+ /**
+ * Compares the argument to the certificate, and returns {@code true} if they
+ * represent the <em>same</em> object using a class specific comparison. The
+ * implementation in Object returns {@code true} only if the argument is the
+ * exact same object as the callee (==).
+ *
+ * @param other
+ * the object to compare with this object.
+ * @return {@code true} if the object is the same as this object, {@code
+ * false} if it is different from this object.
+ * @see #hashCode
+ */
+ public boolean equals(Object other) {
+ // obj equal to itself
+ if (this == other) {
+ return true;
+ }
+ if (other instanceof Certificate) {
+ try {
+ // check that encoded forms match
+ return Arrays.equals(this.getEncoded(),
+ ((Certificate)other).getEncoded());
+ } catch (CertificateEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns an integer hash code for the certificate. Any two objects which
+ * return {@code true} when passed to {@code equals} must return the same
+ * value for this method.
+ *
+ * @return the certificate's hash
+ * @see #equals
+ */
+ public int hashCode() {
+ try {
+ byte[] encoded = getEncoded();
+ int hash = 0;
+ for (int i=0; i<encoded.length; i++) {
+ hash += i*encoded[i];
+ }
+ return hash;
+ } catch (CertificateEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Returns the encoded representation for this certificate.
+ *
+ * @return the encoded representation for this certificate.
+ * @throws CertificateEncodingException
+ * if the encoding fails.
+ */
+ public abstract byte[] getEncoded() throws CertificateEncodingException;
+
+ /**
+ * Verifies that this certificate was signed with the given public key.
+ *
+ * @param key
+ * PublicKey public key for which verification should be
+ * performed.
+ * @throws CertificateException
+ * if encoding errors are detected.
+ * @throws NoSuchAlgorithmException
+ * if an unsupported algorithm is detected.
+ * @throws InvalidKeyException
+ * if an invalid key is detected.
+ * @throws NoSuchProviderException
+ * if there is no default provider.
+ * @throws SignatureException
+ * if signature errors are detected.
+ */
+ public abstract void verify(PublicKey key)
+ throws CertificateException,
+ NoSuchAlgorithmException,
+ InvalidKeyException,
+ NoSuchProviderException,
+ SignatureException;
+
+ /**
+ * Verifies that this certificate was signed with the given public key. It
+ * Uses the signature algorithm given by the provider.
+ *
+ * @param key
+ * PublicKey public key for which verification should be
+ * performed.
+ * @param sigProvider
+ * String the name of the signature provider.
+ * @exception CertificateException
+ * if encoding errors are detected.
+ * @exception NoSuchAlgorithmException
+ * if an unsupported algorithm is detected.
+ * @exception InvalidKeyException
+ * if an invalid key is detected.
+ * @exception NoSuchProviderException
+ * if the specified provider does not exists.
+ * @exception SignatureException
+ * if signature errors are detected.
+ */
+ public abstract void verify(PublicKey key, String sigProvider)
+ throws CertificateException,
+ NoSuchAlgorithmException,
+ InvalidKeyException,
+ NoSuchProviderException,
+ SignatureException;
+
+ /**
+ * Returns a string containing a concise, human-readable description of the
+ * certificate.
+ *
+ * @return a printable representation for the certificate.
+ */
+ public abstract String toString();
+
+ /**
+ * Returns the public key corresponding to this certificate.
+ *
+ * @return the public key corresponding to this certificate.
+ */
+ public abstract PublicKey getPublicKey();
+
+ /**
+ * Returns an alternate object to be serialized.
+ *
+ * @return the object to serialize.
+ * @throws ObjectStreamException
+ * if the creation of the alternate object fails.
+ */
+ protected Object writeReplace() throws ObjectStreamException {
+ try {
+ return new CertificateRep(getType(), getEncoded());
+ } catch (CertificateEncodingException e) {
+ throw new NotSerializableException (
+ Messages.getString("security.66", e)); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * The alternate {@code Serializable} class to be used for serialization and
+ * deserialization of {@code Certificate} objects.
+ */
+ protected static class CertificateRep implements Serializable {
+
+ private static final long serialVersionUID = -8563758940495660020L;
+ // The standard name of the certificate type
+ private final String type;
+ // The certificate data
+ private final byte[] data;
+
+ // Force default serialization to use writeUnshared/readUnshared
+ // for the certificate data
+ private static final ObjectStreamField[] serialPersistentFields = {
+ new ObjectStreamField("type", String.class), //$NON-NLS-1$
+ new ObjectStreamField("data", byte[].class, true) //$NON-NLS-1$
+ };
+
+ /**
+ * Creates a new {@code CertificateRep} instance with the specified
+ * certificate type and encoded data.
+ *
+ * @param type
+ * the certificate type.
+ * @param data
+ * the encoded data.
+ */
+ protected CertificateRep(String type, byte[] data) {
+ this.type = type;
+ this.data = data;
+ }
+
+ /**
+ * Deserializes a {@code Certificate} from a serialized {@code
+ * CertificateRep} object.
+ *
+ * @return the deserialized {@code Certificate}.
+ * @throws ObjectStreamException
+ * if deserialization fails.
+ */
+ protected Object readResolve() throws ObjectStreamException {
+ try {
+ CertificateFactory cf = CertificateFactory.getInstance(type);
+ return cf.generateCertificate(new ByteArrayInputStream(data));
+ } catch (Throwable t) {
+ throw new NotSerializableException(
+ Messages.getString("security.68", t)); //$NON-NLS-1$
+ }
+ }
+ }
+}
diff --git a/luni/src/main/java/java/security/cert/CertificateEncodingException.java b/luni/src/main/java/java/security/cert/CertificateEncodingException.java
new file mode 100644
index 0000000..c5532b9
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/CertificateEncodingException.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * The exception that is thrown when an error occurs while a {@code Certificate}
+ * is being encoded.
+ */
+public class CertificateEncodingException extends CertificateException {
+
+ private static final long serialVersionUID = 6219492851589449162L;
+
+ /**
+ * Creates a new {@code CertificateEncodingException} with the specified
+ * message.
+ *
+ * @param msg
+ * The detail message for the exception.
+ */
+ public CertificateEncodingException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Creates a new {@code CertificateEncodingException}.
+ */
+ public CertificateEncodingException() {
+ }
+
+ /**
+ * Creates a new {@code CertificateEncodingException} with the specified
+ * message and cause.
+ *
+ * @param message
+ * the detail message for the exception.
+ * @param cause
+ * the cause.
+ */
+ public CertificateEncodingException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Creates a new {@code CertificateEncodingException} with the specified
+ * cause.
+ *
+ * @param cause
+ * the cause.
+ */
+ public CertificateEncodingException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/luni/src/main/java/java/security/cert/CertificateException.java b/luni/src/main/java/java/security/cert/CertificateException.java
new file mode 100644
index 0000000..8b1c4d3
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/CertificateException.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.security.GeneralSecurityException;
+
+/**
+ * The base class for all {@code Certificate} related exceptions.
+ */
+public class CertificateException extends GeneralSecurityException {
+
+ private static final long serialVersionUID = 3192535253797119798L;
+
+ /**
+ * Creates a new {@code CertificateException} with the specified message.
+ *
+ * @param msg
+ * the detail message for the exception.
+ */
+ public CertificateException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Creates a new {@code CertificateException}.
+ */
+ public CertificateException() {
+ }
+
+ /**
+ * Creates a new {@code CertificateException} with the specified message and
+ * cause.
+ *
+ * @param message
+ * the detail message for the exception.
+ * @param cause
+ * the cause.
+ */
+ public CertificateException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Creates a new {@code CertificateException} with the specified cause.
+ *
+ * @param cause
+ * the cause
+ */
+ public CertificateException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/luni/src/main/java/java/security/cert/CertificateExpiredException.java b/luni/src/main/java/java/security/cert/CertificateExpiredException.java
new file mode 100644
index 0000000..e15bf98
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/CertificateExpiredException.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * The exception that is thrown when a {@code Certificate} has expired.
+ */
+public class CertificateExpiredException extends CertificateException {
+
+ private static final long serialVersionUID = 9071001339691533771L;
+
+ /**
+ * Creates a new {@code CertificateExpiredException} with the specified
+ * message.
+ *
+ * @param msg
+ * the detail message for this exception
+ */
+ public CertificateExpiredException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Creates a new {@code CertificateExpiredException}.
+ */
+ public CertificateExpiredException() {
+ }
+}
diff --git a/luni/src/main/java/java/security/cert/CertificateFactory.java b/luni/src/main/java/java/security/cert/CertificateFactory.java
new file mode 100644
index 0000000..cb2636a
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/CertificateFactory.java
@@ -0,0 +1,320 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.InputStream;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.Security;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.harmony.security.fortress.Engine;
+import org.apache.harmony.security.internal.nls.Messages;
+
+
+/**
+ * This class implements the functionality of a certificate factory algorithm,
+ * relying on parsing a stream of bytes.
+ * <p>
+ * It defines methods for parsing certificate chains (certificate paths) and
+ * <i>Certificate Revocation Lists</i> (CRLs).
+ */
+public class CertificateFactory {
+
+ // Store CertificateFactory service name
+ private static final String SERVICE = "CertificateFactory"; //$NON-NLS-1$
+
+ // Used to access common engine functionality
+ private static Engine engine = new Engine(SERVICE);
+
+ // Store used provider
+ private final Provider provider;
+
+ // Store used CertificateFactorySpi implementation
+ private final CertificateFactorySpi spiImpl;
+
+ // Store used type
+ private final String type;
+
+ /**
+ * Creates a new {@code CertificateFactory} instance.
+ *
+ * @param certFacSpi
+ * the implementation delegate.
+ * @param provider
+ * the associated provider.
+ * @param type
+ * the certificate type.
+ */
+ protected CertificateFactory(CertificateFactorySpi certFacSpi,
+ Provider provider, String type) {
+ this.provider = provider;
+ this.type = type;
+ this.spiImpl = certFacSpi;
+ }
+
+ /**
+ * Creates a new {@code CertificateFactory} instance that provides the
+ * requested certificate type.
+ *
+ * @param type
+ * the certificate type.
+ * @return the new {@code CertificateFactory} instance.
+ * @throws CertificateException
+ * if the specified certificate type is not available at any
+ * installed provider.
+ * @throws NullPointerException
+ * if {@code type} is {@code null}.
+ */
+ public static final CertificateFactory getInstance(String type)
+ throws CertificateException {
+ if (type == null) {
+ throw new NullPointerException(Messages.getString("security.07")); //$NON-NLS-1$
+ }
+ try {
+ synchronized (engine) {
+ engine.getInstance(type, null);
+ return new CertificateFactory((CertificateFactorySpi) engine.spi,
+ engine.provider, type);
+ }
+ } catch (NoSuchAlgorithmException e) {
+ throw new CertificateException(e);
+ }
+ }
+
+ /**
+ * Creates a new {@code CertificateFactory} instance from the specified
+ * provider that provides the requested certificate type.
+ *
+ * @param type
+ * the certificate type.
+ * @param provider
+ * the name of the provider providing certificates of the
+ * specified type.
+ * @return the new {@code CertificateFactory} instance.
+ * @throws CertificateException
+ * if the specified certificate type is not available by the
+ * specified provider.
+ * @throws NoSuchProviderException
+ * if no provider with the specified name can be found.
+ * @throws IllegalArgumentException
+ * if the specified provider name is {@code null} or empty.
+ * @throws NullPointerException
+ * it {@code type} is {@code null}.
+ */
+ public static final CertificateFactory getInstance(String type,
+ String provider) throws CertificateException,
+ NoSuchProviderException {
+ if ((provider == null) || (provider.length() == 0)) {
+ throw new IllegalArgumentException(Messages.getString("security.02")); //$NON-NLS-1$
+ }
+ Provider impProvider = Security.getProvider(provider);
+ if (impProvider == null) {
+ throw new NoSuchProviderException(provider);
+ }
+ return getInstance(type, impProvider);
+ }
+
+ /**
+ * Creates a new {@code CertificateFactory} instance from the specified
+ * provider that provides the requested certificate type.
+ *
+ * @param type
+ * the certificate type.
+ * @param provider
+ * the name of the provider providing certificates of the
+ * specified type.
+ * @return the new {@code CertificateFactory} instance.
+ * @throws CertificateException
+ * if the specified certificate type is not available at the
+ * specified provider.
+ * @throws IllegalArgumentException
+ * if the specified provider is {@code null}.
+ * @throws NullPointerException
+ * is {@code type} is {@code null}.
+ */
+ public static final CertificateFactory getInstance(String type,
+ Provider provider) throws CertificateException {
+ if (provider == null) {
+ throw new IllegalArgumentException(Messages.getString("security.04")); //$NON-NLS-1$
+ }
+ if (type == null) {
+ throw new NullPointerException(Messages.getString("security.07")); //$NON-NLS-1$
+ }
+ try {
+ synchronized (engine) {
+ engine.getInstance(type, provider, null);
+ return new CertificateFactory((CertificateFactorySpi) engine.spi,
+ provider, type);
+ }
+ } catch (NoSuchAlgorithmException e) {
+ throw new CertificateException(e.getMessage());
+ }
+ }
+
+ /**
+ * Returns the {@code Provider} of the certificate factory represented by
+ * the certificate.
+ *
+ * @return the provider of this certificate factory.
+ */
+ public final Provider getProvider() {
+ return provider;
+ }
+
+ /**
+ * Returns the Certificate type.
+ *
+ * @return type of certificate being used.
+ */
+ public final String getType() {
+ return type;
+ }
+
+ /**
+ * Generates and initializes a {@code Certificate} from the provided input
+ * stream.
+ *
+ * @param inStream
+ * the stream from where data is read to create the {@code
+ * Certificate}.
+ * @return an initialized Certificate.
+ * @throws CertificateException
+ * if parsing problems are detected.
+ */
+ public final Certificate generateCertificate(InputStream inStream)
+ throws CertificateException {
+ return spiImpl.engineGenerateCertificate(inStream);
+ }
+
+ /**
+ * Returns an {@code Iterator} over the supported {@code CertPath} encodings
+ * (as Strings). The first element is the default encoding scheme to apply.
+ *
+ * @return an iterator over supported {@link CertPath} encodings (as
+ * Strings).
+ */
+ public final Iterator<String> getCertPathEncodings() {
+ return spiImpl.engineGetCertPathEncodings();
+ }
+
+ /**
+ * Generates a {@code CertPath} (a certificate chain) from the provided
+ * {@code InputStream}. The default encoding scheme is applied.
+ *
+ * @param inStream
+ * {@code InputStream} with encoded data.
+ * @return a {@code CertPath} initialized from the provided data.
+ * @throws CertificateException
+ * if parsing problems are detected.
+ */
+ public final CertPath generateCertPath(InputStream inStream)
+ throws CertificateException {
+ Iterator<String> it = getCertPathEncodings();
+ if (!it.hasNext()) {
+ throw new CertificateException(Messages.getString("security.74")); //$NON-NLS-1$
+ }
+ return spiImpl.engineGenerateCertPath(inStream, it.next());
+ }
+
+ /**
+ * Generates a {@code CertPath} (a certificate chain) from the provided
+ * {@code InputStream} and the specified encoding scheme.
+ *
+ * @param inStream
+ * {@code InputStream} containing certificate path data in
+ * specified encoding.
+ * @param encoding
+ * encoding of the data in the input stream.
+ * @return a {@code CertPath} initialized from the provided data.
+ * @throws CertificateException
+ * if parsing problems are detected.
+ * @throws UnsupportedOperationException
+ * if the provider does not implement this method.
+ */
+ public final CertPath generateCertPath(InputStream inStream, String encoding)
+ throws CertificateException {
+ return spiImpl.engineGenerateCertPath(inStream, encoding);
+ }
+
+ /**
+ * Generates a {@code CertPath} from the provided list of certificates. The
+ * encoding is the default encoding.
+ *
+ * @param certificates
+ * the list containing certificates in a format supported by the
+ * {@code CertificateFactory}.
+ * @return a {@code CertPath} initialized from the provided data.
+ * @throws CertificateException
+ * if parsing problems are detected.
+ * @throws UnsupportedOperationException
+ * if the provider does not implement this method.
+ */
+ public final CertPath generateCertPath(List<? extends Certificate> certificates)
+ throws CertificateException {
+ return spiImpl.engineGenerateCertPath(certificates);
+ }
+
+ /**
+ * Generates and initializes a collection of (unrelated) certificates from
+ * the provided input stream.
+ *
+ * @param inStream
+ * the stream from which the data is read to create the
+ * collection.
+ * @return an initialized collection of certificates.
+ * @throws CertificateException
+ * if parsing problems are detected.
+ */
+ public final Collection<? extends Certificate> generateCertificates(InputStream inStream)
+ throws CertificateException {
+ return spiImpl.engineGenerateCertificates(inStream);
+ }
+
+ /**
+ * Generates and initializes a <i>Certificate Revocation List</i> (CRL) from
+ * the provided input stream.
+ *
+ * @param inStream
+ * the stream from where data is read to create the CRL.
+ * @return an initialized CRL.
+ * @exception CRLException
+ * if parsing problems are detected.
+ */
+ public final CRL generateCRL(InputStream inStream) throws CRLException {
+ return spiImpl.engineGenerateCRL(inStream);
+ }
+
+ /**
+ * Generates and initializes a collection of <i>Certificate Revocation
+ * List</i> (CRL) from the provided input stream.
+ *
+ * @param inStream
+ * the stream from which the data is read to create the CRLs.
+ * @return an initialized collection of CRLs.
+ * @exception CRLException
+ * if parsing problems are detected.
+ */
+ public final Collection<? extends CRL> generateCRLs(InputStream inStream)
+ throws CRLException {
+ return spiImpl.engineGenerateCRLs(inStream);
+ }
+}
diff --git a/luni/src/main/java/java/security/cert/CertificateFactorySpi.java b/luni/src/main/java/java/security/cert/CertificateFactorySpi.java
new file mode 100644
index 0000000..d9f2044
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/CertificateFactorySpi.java
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.InputStream;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>) for the
+ * {@code CertificateFactory} class. This SPI must be implemented for each
+ * certificate type a security provider wishes to support.
+ */
+
+public abstract class CertificateFactorySpi {
+
+ /**
+ * Constructs a new instance of this class.
+ */
+ public CertificateFactorySpi() {
+ }
+
+ /**
+ * Generates and initializes a {@code Certificate} from the provided input
+ * stream.
+ *
+ * @param inStream
+ * the stream from which the data is read to create the
+ * certificate.
+ * @return an initialized certificate.
+ * @exception CertificateException
+ * if parsing problems are detected.
+ */
+ public abstract Certificate engineGenerateCertificate(InputStream inStream)
+ throws CertificateException;
+
+ /**
+ * Generates and initializes a collection of certificates from the provided
+ * input stream.
+ *
+ * @param inStream
+ * the stream from where data is read to create the certificates.
+ * @return a collection of certificates.
+ * @exception CertificateException
+ * if parsing problems are detected.
+ */
+ public abstract Collection<? extends Certificate>
+ engineGenerateCertificates(InputStream inStream) throws CertificateException;
+
+ /**
+ * Generates and initializes a <i>Certificate Revocation List</i> (CRL) from
+ * the provided input stream.
+ *
+ * @param inStream
+ * the stream from where data is read to create the CRL.
+ * @return an CRL instance.
+ * @exception CRLException
+ * if parsing problems are detected.
+ */
+ public abstract CRL engineGenerateCRL(InputStream inStream)
+ throws CRLException;
+
+ /**
+ * Generates and initializes a collection of <i>Certificate Revocation
+ * List</i> (CRL) from the provided input stream.
+ *
+ * @param inStream
+ * the stream from which the data is read to create the CRLs.
+ * @return a collection of CRLs.
+ * @exception CRLException
+ * if parsing problems are detected.
+ */
+ public abstract Collection<? extends CRL>
+ engineGenerateCRLs(InputStream inStream) throws CRLException;
+
+ /**
+ * Generates a {@code CertPath} from the provided {@code InputStream}. The
+ * default encoding scheme is applied.
+ *
+ * @param inStream
+ * an input stream with encoded data.
+ * @return a {@code CertPath} initialized from the provided data.
+ * @throws CertificateException
+ * if parsing problems are detected.
+ */
+ public CertPath engineGenerateCertPath(InputStream inStream)
+ throws CertificateException {
+ throw new UnsupportedOperationException(
+ Messages.getString("security.70")); //$NON-NLS-1$
+ }
+
+ /**
+ * Generates a {@code CertPath} from the provided {@code
+ * InputStream} in the specified encoding.
+ *
+ * @param inStream
+ * an input stream containing certificate path data in specified
+ * encoding.
+ * @param encoding
+ * the encoding of the data in the input stream.
+ * @return a {@code CertPath} initialized from the provided data
+ * @throws CertificateException
+ * if parsing problems are detected.
+ * @throws UnsupportedOperationException
+ * if the provider does not implement this method.
+ */
+ public CertPath engineGenerateCertPath(InputStream inStream, String encoding)
+ throws CertificateException {
+ throw new UnsupportedOperationException(
+ Messages.getString("security.71")); //$NON-NLS-1$
+ }
+
+ /**
+ * Generates a {@code CertPath} from the provided list of certificates. The
+ * encoding is the default encoding.
+ *
+ * @param certificates
+ * the list containing certificates in a format supported by the
+ * {@code CertificateFactory}.
+ * @return a {@code CertPath} initialized from the provided data.
+ * @throws CertificateException
+ * if parsing problems are detected.
+ * @throws UnsupportedOperationException
+ * if the provider does not implement this method.
+ */
+ public CertPath engineGenerateCertPath(List<? extends Certificate> certificates)
+ throws CertificateException {
+ throw new UnsupportedOperationException(
+ Messages.getString("security.72")); //$NON-NLS-1$
+ }
+
+ /**
+ * Returns an {@code Iterator} over the supported {@code CertPath} encodings
+ * (as Strings). The first element is the default encoding.
+ *
+ * @return an iterator over supported {@code CertPath} encodings (as
+ * Strings).
+ */
+ public Iterator<String> engineGetCertPathEncodings() {
+ throw new UnsupportedOperationException(
+ Messages.getString("security.73")); //$NON-NLS-1$
+ }
+}
diff --git a/luni/src/main/java/java/security/cert/CertificateNotYetValidException.java b/luni/src/main/java/java/security/cert/CertificateNotYetValidException.java
new file mode 100644
index 0000000..dd26bf8
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/CertificateNotYetValidException.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * The exception that is thrown when a {@code Certificate} is not yet valid or
+ * will not yet be valid on a specified date.
+ */
+public class CertificateNotYetValidException extends CertificateException {
+
+ private static final long serialVersionUID = 4355919900041064702L;
+
+ /**
+ * Creates a new {@code CertificateNotYetValidException} with the specified
+ * message.
+ *
+ * @param msg
+ * the detail message for the exception.
+ */
+ public CertificateNotYetValidException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Creates a new {@code CertificateNotYetValidException}.
+ */
+ public CertificateNotYetValidException() {
+ }
+}
diff --git a/luni/src/main/java/java/security/cert/CertificateParsingException.java b/luni/src/main/java/java/security/cert/CertificateParsingException.java
new file mode 100644
index 0000000..4efd159
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/CertificateParsingException.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * The exception that is thrown when a {@code Certificate} can not be parsed.
+ */
+public class CertificateParsingException extends CertificateException {
+
+ private static final long serialVersionUID = -7989222416793322029L;
+
+ /**
+ * Creates a new {@code CertificateParsingException} with the specified
+ * message.
+ *
+ * @param msg
+ * the detail message for the exception.
+ */
+ public CertificateParsingException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Creates a new {@code CertificateParsingException}.
+ */
+ public CertificateParsingException() {
+ }
+
+ /**
+ * Creates a new {@code CertificateParsingException} with the specified
+ * message and cause.
+ *
+ * @param message
+ * the detail message for the exception.
+ * @param cause
+ * the exception's source.
+ */
+ public CertificateParsingException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Creates a new {@code CertificateParsingException} with the specified
+ * cause.
+ *
+ * @param cause
+ * the exception's source.
+ */
+ public CertificateParsingException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/luni/src/main/java/java/security/cert/CollectionCertStoreParameters.java b/luni/src/main/java/java/security/cert/CollectionCertStoreParameters.java
new file mode 100644
index 0000000..3c2fe1c
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/CollectionCertStoreParameters.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.util.Collection;
+import java.util.Collections;
+
+/**
+ * The parameters to initialize a <i>Collection</i> type {@code CertStore} instance.
+ * <p>
+ * It is used to specify the {@code Collection} where the {@code CertStore} will
+ * retrieve the certificates and CRLs from.
+ */
+public class CollectionCertStoreParameters implements CertStoreParameters {
+ // Default empty and immutable collection.
+ // Used if <code>CollectionCertStoreParameters</code>instance
+ // created by the no arg constructor
+ private static final Collection<?> defaultCollection = Collections.EMPTY_SET;
+ // A <code>Collection</code> of <code>Certificate</code>s
+ // and <code>CRL</code>s
+ private final Collection<?> collection;
+
+ /**
+ * Creates a new {@code CollectionCertStoreParameters} without a collection.
+ * <p>
+ * The default collection is an empty and unmodifiable {@code Collection}.
+ */
+ public CollectionCertStoreParameters() {
+ this.collection = defaultCollection;
+ }
+
+ /**
+ * Creates a new {@code CollectionCertStoreParameters} with the specified
+ * collection.
+ * <p>
+ * The specified collection is not copied and therefore may be modified at
+ * any time.
+ *
+ * @param collection
+ * the collection where the {@code Certificate}s and {@code CRL}s
+ * will be retrieved from.
+ * @throws NullPointerException
+ * if {@code collection is null}.
+ */
+ public CollectionCertStoreParameters(Collection<?> collection) {
+ this.collection = collection;
+ if (this.collection == null) {
+ throw new NullPointerException();
+ }
+ }
+
+ /**
+ * Clones this {@code CollectionCertStoreParameters} instance, but not the
+ * underlying collection.
+ *
+ * @return the cloned instance.
+ */
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the collection where the {@code Certificate}s and {@code CRL}s
+ * are retrieved from.
+ *
+ * @return the collection where the {@code Certificate}s and {@code CRL}s
+ * will be retrieved from.
+ */
+ public Collection<?> getCollection() {
+ return collection;
+ }
+
+ /**
+ * Returns the string representation of this instance.
+ *
+ * @return the string representation of this instance.
+ */
+ public String toString() {
+ StringBuilder sb =
+ new StringBuilder("CollectionCertStoreParameters: [\ncollection: "); //$NON-NLS-1$
+ sb.append(getCollection().toString());
+ sb.append("\n]"); //$NON-NLS-1$
+ return sb.toString();
+ }
+}
diff --git a/luni/src/main/java/java/security/cert/LDAPCertStoreParameters.java b/luni/src/main/java/java/security/cert/LDAPCertStoreParameters.java
new file mode 100644
index 0000000..1d6542f
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/LDAPCertStoreParameters.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * The parameters to initialize a LDAP {@code CertStore} instance.
+ */
+public class LDAPCertStoreParameters implements CertStoreParameters {
+ // Default LDAP server name
+ private static final String DEFAULT_LDAP_SERVER_NAME = "localhost"; //$NON-NLS-1$
+ // Default LDAP server port number
+ private static final int DEFAULT_LDAP_PORT = 389;
+
+ // LDAP server name for this cert store
+ private final String serverName;
+ // LDAP server port number for this cert store
+ private final int port;
+
+ /**
+ * Creates a new {@code LDAPCertStoreParameters} instance with the specified
+ * server name and port.
+ *
+ * @param serverName
+ * the LDAP server name.
+ * @param port
+ * the port.
+ * @throws NullPointerException
+ * is {@code serverName} is {@code null}.
+ */
+ public LDAPCertStoreParameters(String serverName, int port) {
+ this.port = port;
+ this.serverName = serverName;
+ if (this.serverName == null) {
+ throw new NullPointerException();
+ }
+ }
+
+ /**
+ * Creates a new {@code LDAPCertStoreParameters} instance with default
+ * parameters.
+ * <p>
+ * The default parameters are server name "localhost" and port 389.
+ */
+ public LDAPCertStoreParameters() {
+ this.serverName = DEFAULT_LDAP_SERVER_NAME;
+ this.port = DEFAULT_LDAP_PORT;
+ }
+
+ /**
+ * Creates a new {@code LDAPCertStoreParameters} instance with the specified
+ * server name and default port 389.
+ *
+ * @param serverName
+ * the LDAP server name.
+ * @throws NullPointerException
+ * if {@code serverName} is {@code null}.
+ */
+ public LDAPCertStoreParameters(String serverName) {
+ this.port = DEFAULT_LDAP_PORT;
+ this.serverName = serverName;
+ if (this.serverName == null) {
+ throw new NullPointerException();
+ }
+ }
+
+ /**
+ * Clones this {@code LDAPCertStoreParameters} instance.
+ *
+ * @return the cloned instance.
+ */
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the LDAP server port.
+ *
+ * @return the LDAP server port.
+ */
+ public int getPort() {
+ return port;
+ }
+
+ /**
+ * Returns the LDAP server name.
+ *
+ * @return the LDAP server name.
+ */
+ public String getServerName() {
+ return serverName;
+ }
+
+ /**
+ * Returns the string representation of this {@code LDAPCertStoreParameters}
+ * instance.
+ *
+ * @return the string representation of this {@code LDAPCertStoreParameters}
+ * instance.
+ */
+ public String toString() {
+ StringBuilder sb =
+ new StringBuilder("LDAPCertStoreParameters: [\n serverName: "); //$NON-NLS-1$
+ sb.append(getServerName());
+ sb.append("\n port: "); //$NON-NLS-1$
+ sb.append(getPort());
+ sb.append("\n]"); //$NON-NLS-1$
+ return sb.toString();
+ }
+}
diff --git a/luni/src/main/java/java/security/cert/PKIXBuilderParameters.java b/luni/src/main/java/java/security/cert/PKIXBuilderParameters.java
new file mode 100644
index 0000000..1a75063
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/PKIXBuilderParameters.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.util.Set;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * The parameter specification for a PKIX {@code CertPathBuilder}
+ * algorithm used to {@link CertPathBuilder#build(CertPathParameters) build}
+ * certificate chains validated with the PKIX certification path validation.
+ * <p>
+ * The parameters must be created with <i>trusted</i> certificate authorities
+ * and constraints for the target certificates.
+ *
+ * @see CertPathBuilder
+ * @see CertPathParameters
+ */
+public class PKIXBuilderParameters extends PKIXParameters {
+ // Maximum certificate path length (5 by default)
+ private int maxPathLength = 5;
+
+ /**
+ * Creates a new {@code PKIXBuilderParameters} instance with the specified
+ * set of {@code TrustAnchor} and certificate constraints.
+ *
+ * @param trustAnchors
+ * the set of {@code TrustAnchors}.
+ * @param targetConstraints
+ * the certificate constraints.
+ * @throws InvalidAlgorithmParameterException
+ * if {@code trustAnchors} is empty.
+ * @throws ClassCastException
+ * if one of the items in {@code trustAnchors} is not an
+ * instance of {@code java.security.cert.TrustAnchor}.
+ */
+ public PKIXBuilderParameters(Set<TrustAnchor> trustAnchors,
+ CertSelector targetConstraints)
+ throws InvalidAlgorithmParameterException {
+ super(trustAnchors);
+ super.setTargetCertConstraints(targetConstraints);
+ }
+
+ /**
+ * Creates a new {@code PKIXBuilderParameters} instance with the trusted
+ * {@code X509Certificate} entries from the specified {@code KeyStore}.
+ *
+ * @param keyStore
+ * the key store containing trusted certificates.
+ * @param targetConstraints
+ * the certificate constraints.
+ * @throws KeyStoreException
+ * if the {@code keyStore} is not initialized.
+ * @throws InvalidAlgorithmParameterException
+ * if {@code keyStore} does not contained any trusted
+ * certificate entry.
+ */
+ public PKIXBuilderParameters(KeyStore keyStore,
+ CertSelector targetConstraints)
+ throws KeyStoreException,
+ InvalidAlgorithmParameterException {
+ super(keyStore);
+ super.setTargetCertConstraints(targetConstraints);
+ }
+
+ /**
+ * Returns the maximum length of a certification path.
+ * <p>
+ * This is the maximum number of non-self-signed certificates in a
+ * certification path.
+ *
+ * @return the maximum length of a certification path, or {@code -1} if it
+ * is unlimited.
+ */
+ public int getMaxPathLength() {
+ return maxPathLength;
+ }
+
+ /**
+ * Set the maximum length of a certification path.
+ * <p>
+ * This is the maximum number of non-self-signed certificates in a
+ * certification path.
+ *
+ * @param maxPathLength
+ * the maximum length of a certification path.
+ * @throws InvalidParameterException
+ * if {@code maxPathLength} is less than {@code -1}.
+ */
+ public void setMaxPathLength(int maxPathLength) {
+ if (maxPathLength < -1) {
+ throw new InvalidParameterException(
+ Messages.getString("security.5B")); //$NON-NLS-1$
+ }
+ this.maxPathLength = maxPathLength;
+ }
+
+ /**
+ * Returns a string representation of this {@code PKIXBuilderParameters}
+ * instance.
+ *
+ * @return a string representation of this {@code PKIXBuilderParameters}
+ * instance.
+ */
+ public String toString() {
+ StringBuilder sb = new StringBuilder("[\n"); //$NON-NLS-1$
+ sb.append(super.toString());
+ sb.append(" Max Path Length: "); //$NON-NLS-1$
+ sb.append(maxPathLength);
+ sb.append("\n]"); //$NON-NLS-1$
+ return sb.toString();
+ }
+}
diff --git a/luni/src/main/java/java/security/cert/PKIXCertPathBuilderResult.java b/luni/src/main/java/java/security/cert/PKIXCertPathBuilderResult.java
new file mode 100644
index 0000000..5a9fb2d
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/PKIXCertPathBuilderResult.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.security.PublicKey;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * The result of the PKIX certification path builder, returned by
+ * {@link CertPathBuilder#build(CertPathParameters)}.
+ */
+public class PKIXCertPathBuilderResult extends PKIXCertPathValidatorResult
+ implements CertPathBuilderResult {
+ // Built and validated certification path
+ private final CertPath certPath;
+
+ /**
+ * Creates a new {@code PKIXCertPathBuilderResult} instance with the
+ * specified validated certification path, the trust anchor of the
+ * certification path, the policy tree and the public key of the subject.
+ *
+ * @param certPath
+ * the validated certification path.
+ * @param trustAnchor
+ * the trust anchor.
+ * @param policyTree
+ * the policy tree (or {@code null} if not used).
+ * @param subjectPublicKey
+ * the public key.
+ * @throws NullPointerException
+ * if the {@code cerPath}, {@code trustAnchor} or {@code
+ * subjectPolicyKey} is {@code null}.
+ */
+ public PKIXCertPathBuilderResult(CertPath certPath, TrustAnchor trustAnchor,
+ PolicyNode policyTree, PublicKey subjectPublicKey) {
+ super(trustAnchor, policyTree, subjectPublicKey);
+ this.certPath = certPath;
+ if (this.certPath == null) {
+ throw new NullPointerException(Messages.getString("security.55")); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Returns the validated certification path.
+ *
+ * @return the validated certification path.
+ */
+ public CertPath getCertPath() {
+ return certPath;
+ }
+
+ /**
+ * Returns a string representation of this {@code PKIXCertPathBuilderResult}
+ * instance.
+ *
+ * @return a string representation of this {@code PKIXCertPathBuilderResult}
+ * instance.
+ */
+ public String toString() {
+ StringBuilder sb = new StringBuilder(super.toString());
+ sb.append("\n Certification Path: "); //$NON-NLS-1$
+ sb.append(certPath.toString());
+ sb.append("\n]"); //$NON-NLS-1$
+ return sb.toString();
+ }
+}
diff --git a/luni/src/main/java/java/security/cert/PKIXCertPathChecker.java b/luni/src/main/java/java/security/cert/PKIXCertPathChecker.java
new file mode 100644
index 0000000..5eaac74
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/PKIXCertPathChecker.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.util.Collection;
+import java.util.Set;
+
+/**
+ * The class specifying the interface to extend the certification path
+ * validation algorithm by checks to perform on an {@code X509Certificate}.
+ * <p>
+ * The checks are added to a certification path validation using the
+ * {@link PKIXParameters#setCertPathCheckers(java.util.List)
+ * setCertPathCheckers} or
+ * {@link PKIXBuilderParameters#addCertPathChecker(PKIXCertPathChecker)
+ * addCertPathChecker} of the {@code PKIXParameters} and {@code
+ * PKIXBuilderParameters} class respectively. The
+ * {@link #check(Certificate, Collection) check} method will be called for each
+ * certificate processed by a {@code CertPathBuilder} of {@code
+ * CertPathValidator}.
+ * <p>
+ * A {@code PKIXCertPathChecker} implementation <u>must</u> support reverse
+ * checking (from trusted CA to target) and <u>may</u> support forward checking
+ * (from target to trusted CA). The return value of {@code
+ * isForwardCheckingSupported} indicates whether forward checking is supported.
+ */
+public abstract class PKIXCertPathChecker implements Cloneable {
+
+ /**
+ * Creates a new {@code PKIXCertPathChecker} instance.
+ */
+ protected PKIXCertPathChecker() {}
+
+ /**
+ * Clones this {@code PKIXCertPathChecker} instance.
+ *
+ * @return the cloned instance.
+ */
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new AssertionError(e); // android-changed
+ }
+ }
+
+ /**
+ * Initializes this {@code PKIXCertPathChecker} instance for specified
+ * <i>checking direction</i>.
+ *
+ * @param forward
+ * the direction of the certification path processing, {@code
+ * true} if the certificates are processed in forward direction
+ * (from target to trusted CA), {@code false} if processed in
+ * reverse direction (from trusted CA to target).
+ * @throws CertPathValidatorException
+ * if initialization of this {@code PKIXCertPathChecker}
+ * instance fails, or if it cannot process certificates in the
+ * specified order.
+ */
+ public abstract void init(boolean forward)
+ throws CertPathValidatorException;
+
+ /**
+ * Returns whether this {@code PKIXCertPathChecker} instance supports
+ * <i>forward checking</i>.
+ *
+ * @return {@code true} if this {@code PKIXCertPathChecker} instance
+ * supports forward checking, otherwise {@code false}.
+ */
+ public abstract boolean isForwardCheckingSupported();
+
+ /**
+ * Returns the list of extensions of X.509 certificates that this {@code
+ * PKIXCertPathChecker} is able to process.
+ *
+ * @return the list of extensions of X.509 certificates that this {@code
+ * PKIXCertPathChecker} is able to process, or {@code null} if there
+ * are none.
+ */
+ public abstract Set<String> getSupportedExtensions();
+
+ /**
+ * Checks the specified certificate and removes the processed critical
+ * extensions from the specified list of X.509 extension <i>OID</i>s.
+ *
+ * @param cert
+ * the certificate.
+ * @param unresolvedCritExts
+ * the list of critical X.509 extension OID strings.
+ * @throws CertPathValidatorException
+ * if check(s) fail on the specified certificate.
+ */
+ public abstract void check(Certificate cert, Collection<String> unresolvedCritExts)
+ throws CertPathValidatorException;
+}
diff --git a/luni/src/main/java/java/security/cert/PKIXCertPathValidatorResult.java b/luni/src/main/java/java/security/cert/PKIXCertPathValidatorResult.java
new file mode 100644
index 0000000..d82c699
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/PKIXCertPathValidatorResult.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.security.PublicKey;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * The implementation of the result of the PKIX certification path validation.
+ *
+ * @see CertPathValidator
+ * @see CertPathValidator#validate(CertPath, CertPathParameters)
+ */
+public class PKIXCertPathValidatorResult implements CertPathValidatorResult {
+ // A trust anchor used during validation of certification path
+ private final TrustAnchor trustAnchor;
+ // Valid policy tree resulting from PKIX
+ // certification path validation algorithm
+ private final PolicyNode policyTree;
+ // Public key of the subject (target) certificate
+ private final PublicKey subjectPublicKey;
+
+ /**
+ * Creates a new {@code PKIXCertPathValidatorResult} with the specified
+ * trust anchor, the valid policy tree and the subject public key.
+ *
+ * @param trustAnchor
+ * the trust anchor describing the certification authority (CA)
+ * that served as trust anchor for the certification path.
+ * @param policyTree
+ * the valid policy tree from the validation.
+ * @param subjectPublicKey
+ * the subject public key from the validation.
+ */
+ public PKIXCertPathValidatorResult(TrustAnchor trustAnchor,
+ PolicyNode policyTree, PublicKey subjectPublicKey) {
+ this.trustAnchor = trustAnchor;
+ this.policyTree = policyTree;
+ this.subjectPublicKey = subjectPublicKey;
+ if (this.trustAnchor == null) {
+ throw new NullPointerException(Messages.getString("security.64")); //$NON-NLS-1$
+ }
+ if (this.subjectPublicKey == null) {
+ throw new NullPointerException(
+ Messages.getString("security.65")); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Returns the valid policy tree from the validation.
+ *
+ * @return the valid policy tree from the validation.
+ */
+ public PolicyNode getPolicyTree() {
+ return policyTree;
+ }
+
+ /**
+ * Returns the subject public key from the validation.
+ *
+ * @return the subject public key from the validation.
+ */
+ public PublicKey getPublicKey() {
+ return subjectPublicKey;
+ }
+
+ /**
+ * Returns the trust anchor describing the certification authority (CA) that
+ * served as trust anchor for this certification path.
+ *
+ * @return the trust anchor.
+ */
+ public TrustAnchor getTrustAnchor() {
+ return trustAnchor;
+ }
+
+ /**
+ * Clones this {@code PKIXCertPathValidatorResult} instance.
+ *
+ * @return the cloned instance.
+ */
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new AssertionError(e); // android-changed
+ }
+ }
+
+ /**
+ * Returns a string representation for this {@code
+ * PKIXCertPathValidatorResult} instance.
+ *
+ * @return a string representation for this {@code
+ * PKIXCertPathValidatorResult} instance.
+ */
+ public String toString() {
+ StringBuilder sb = new StringBuilder(super.toString());
+ sb.append(": [\n Trust Anchor: "); //$NON-NLS-1$
+ sb.append(trustAnchor.toString());
+ sb.append("\n Policy Tree: "); //$NON-NLS-1$
+ sb.append(policyTree == null ? "no valid policy tree\n" //$NON-NLS-1$
+ : policyTree.toString());
+ sb.append("\n Subject Public Key: "); //$NON-NLS-1$
+ sb.append(subjectPublicKey.toString());
+ sb.append("\n]"); //$NON-NLS-1$
+ return sb.toString();
+ }
+}
diff --git a/luni/src/main/java/java/security/cert/PKIXParameters.java b/luni/src/main/java/java/security/cert/PKIXParameters.java
new file mode 100644
index 0000000..79d3d5e
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/PKIXParameters.java
@@ -0,0 +1,621 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.security.InvalidAlgorithmParameterException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * This class implements the parameters for the {@code PKIX CertPathValidator}.
+ * <p>
+ * The parameters must be created with <i>trusted</i> certificate authorities
+ * (trust anchors).
+ *
+ * @see CertPathValidator
+ * @see CertPathParameters
+ */
+public class PKIXParameters implements CertPathParameters {
+ // Set of trust anchors - most trusted CAs
+ private Set<TrustAnchor> trustAnchors;
+ // Set of acceptable initial policy identifiers (OID strings)
+ private Set<String> initialPolicies;
+ // List of cert stores that used to find certificates and CRLs
+ private List<CertStore> certStores;
+ // Time for which the validity of the certification
+ // patch should be determined
+ private Date date;
+ // List of certification patch checkers (PKIXCertPathChecker)
+ private List<PKIXCertPathChecker> certPathCheckers;
+ // Preferred signature provider name
+ private String sigProvider;
+ // Required constraints on the target certificate
+ private CertSelector targetCertConstraints;
+ // Indicates whether cert revocation is enabled or not
+ private boolean revocationEnabled = true;
+ // Indicates whether explicit policy required or not
+ private boolean explicitPolicyRequired = false;
+ // Indicates whether policy mapping inhibited or not
+ private boolean policyMappingInhibited = false;
+ // Indicates whether any policy inhibited or not
+ private boolean anyPolicyInhibited = false;
+ // Indicates whether certificates that include policy
+ // qualifiers in a certificate policies extension that
+ // is marked critical must be rejected or not
+ private boolean policyQualifiersRejected = true;
+
+ /**
+ * Creates a new {@code PKIXParameters} instance with the specified set of
+ * <i>trusted</i> certificate authorities.
+ *
+ * @param trustAnchors
+ * the trusted CAs.
+ * @throws InvalidAlgorithmParameterException
+ * if {@code trustAnchors} is empty.
+ */
+ public PKIXParameters(Set<TrustAnchor> trustAnchors)
+ throws InvalidAlgorithmParameterException {
+ if (trustAnchors == null) {
+ throw new NullPointerException(Messages.getString("security.6F")); //$NON-NLS-1$
+ }
+ checkTrustAnchors(trustAnchors);
+ this.trustAnchors = new HashSet<TrustAnchor>(trustAnchors);
+ }
+
+ /**
+ * Creates a new {@code PKIXParameters} instance with the trusted {@code
+ * X509Certificate} entries from the specified {@code KeyStore}.
+ *
+ * @param keyStore
+ * the key store containing trusted certificates.
+ * @throws KeyStoreException
+ * if the {@code keyStore} is not initialized.
+ * @throws InvalidAlgorithmParameterException
+ * if {@code keyStore} does not contained any trusted
+ * certificate entry.
+ */
+ public PKIXParameters(KeyStore keyStore)
+ throws KeyStoreException,
+ InvalidAlgorithmParameterException {
+ if (keyStore == null) {
+ throw new NullPointerException(Messages.getString("security.41")); //$NON-NLS-1$
+ }
+ // Will throw KeyStoreException if
+ // keyStore has not been initialized (loaded)
+ if (keyStore.size() == 0) {
+ throw new InvalidAlgorithmParameterException(
+ Messages.getString("security.6A")); //$NON-NLS-1$
+ }
+ // keyStore is not null and loaded
+ trustAnchors = new HashSet<TrustAnchor>();
+ for (Enumeration i = keyStore.aliases(); i.hasMoreElements();) {
+ String alias = (String) i.nextElement();
+ if (keyStore.isCertificateEntry(alias)) {
+ // this is trusted certificate entry
+ // check if it is X509Cerificate
+ Certificate c = keyStore.getCertificate(alias);
+ // add only X509Cerificate
+ // ignore all other types
+ if (c instanceof X509Certificate) {
+ trustAnchors.add(new TrustAnchor((X509Certificate)c, null));
+ }
+ }
+ }
+ checkTrustAnchors(trustAnchors);
+ }
+
+ /**
+ * Returns a unmodifiable set of the <i>trusted</i> certificate authorities.
+ *
+ * @return a unmodifiable set of the <i>trusted</i> certificate authorities.
+ */
+ public Set<TrustAnchor> getTrustAnchors() {
+ return Collections.unmodifiableSet(trustAnchors);
+ }
+
+ /**
+ * Sets the set of <i>trusted</i> certificate authorities.
+ *
+ * @param trustAnchors
+ * the set of <i>trusted</i> certificate authorities.
+ * @throws InvalidAlgorithmParameterException
+ * if {@code trustAnchors} is empty.
+ */
+ public void setTrustAnchors(Set<TrustAnchor> trustAnchors)
+ throws InvalidAlgorithmParameterException {
+ if (trustAnchors == null) {
+ throw new NullPointerException(
+ Messages.getString("security.6F")); //$NON-NLS-1$
+ }
+ checkTrustAnchors(trustAnchors);
+ // make shallow copy
+ this.trustAnchors = new HashSet<TrustAnchor>(trustAnchors);
+ }
+
+ /**
+ * Returns whether the <i>any policy OID</i> will be inhibited if it's
+ * included in a certificate.
+ *
+ * @return {@code true} if the <i>any policy OID</i> will be inhibited,
+ * otherwise {@code false}.
+ */
+ public boolean isAnyPolicyInhibited() {
+ return anyPolicyInhibited;
+ }
+
+ /**
+ * Sets whether the <i>any policy OID</i> should be inhibited if it's
+ * included in a certificate.
+ *
+ * @param anyPolicyInhibited
+ * {@code true} if the <i>any policy OID</i> should be inhibited,
+ * otherwise {@code false}.
+ */
+ public void setAnyPolicyInhibited(boolean anyPolicyInhibited) {
+ this.anyPolicyInhibited = anyPolicyInhibited;
+ }
+
+ /**
+ * Returns the list of checkers for the certification path.
+ * <p>
+ * The list is unmodifiable and the entries in the list are cloned.
+ *
+ * @return the list of checkers for the certification path.
+ */
+ public List<PKIXCertPathChecker> getCertPathCheckers() {
+ if (certPathCheckers == null) {
+ // set to empty List if has not been set yet
+ certPathCheckers = new ArrayList<PKIXCertPathChecker>();
+ }
+ if (certPathCheckers.isEmpty()) {
+ // no content - no need to copy,
+ // just return immutable view of the same
+ // empty List each time
+ return Collections.unmodifiableList(certPathCheckers);
+ }
+ // List is not empty - do deep copy
+ ArrayList<PKIXCertPathChecker> modifiableList =
+ new ArrayList<PKIXCertPathChecker>();
+ for (Iterator<PKIXCertPathChecker> i
+ = certPathCheckers.iterator(); i.hasNext();) {
+ modifiableList.add((PKIXCertPathChecker)i.next().clone());
+ }
+ return Collections.unmodifiableList(modifiableList);
+ }
+
+ /**
+ * Sets the list of checkers for the certification path.
+ * <p>
+ * The list is copied and the entries are cloned.
+ *
+ * @param certPathCheckers
+ * the list of checkers for the certification path, or {@code
+ * null} to clear the checkers.
+ */
+ public void setCertPathCheckers(List<PKIXCertPathChecker> certPathCheckers) {
+ if (certPathCheckers == null || certPathCheckers.isEmpty()) {
+ // empty list or null provided
+ if (this.certPathCheckers != null &&
+ !this.certPathCheckers.isEmpty()) {
+ // discard non-empty list
+ this.certPathCheckers = null;
+ }
+ return;
+ }
+ // non-empty list provided - do deep copy
+ this.certPathCheckers = new ArrayList<PKIXCertPathChecker>();
+ for (Iterator<PKIXCertPathChecker> i
+ = certPathCheckers.iterator(); i.hasNext();) {
+ this.certPathCheckers.add((PKIXCertPathChecker)i.next().clone());
+ }
+ }
+
+ /**
+ * Adds the specified {@code PKIXCertPathChecker} to the list of
+ * certification path checkers.
+ *
+ * @param checker
+ * the {@code PKIXCertPathChecker} to add, if {@code null}, it
+ * will be ignored.
+ */
+ public void addCertPathChecker(PKIXCertPathChecker checker) {
+ if (checker == null) {
+ // do nothing if null provided
+ return;
+ }
+ if (certPathCheckers == null) {
+ // set to empty List if has not been set yet
+ certPathCheckers = new ArrayList<PKIXCertPathChecker>();
+ }
+ // add a copy to avoid possible modifications
+ certPathCheckers.add((PKIXCertPathChecker) checker.clone());
+ }
+
+ /**
+ * Returns the list of certificate stores that are used to find certificates
+ * and CRLs.
+ *
+ * @return an immutable list of certificate stores.
+ */
+ public List<CertStore> getCertStores() {
+ if (certStores == null) {
+ // set to empty List if has not been set yet
+ certStores = new ArrayList<CertStore>();
+ }
+ if (certStores.isEmpty()) {
+ // no content - no need to copy,
+ // just return immutable view of the same
+ // empty List each time
+ return Collections.unmodifiableList(certStores);
+ }
+ // List is not empty - do shallow copy
+ ArrayList<CertStore> modifiableList
+ = new ArrayList<CertStore>(certStores);
+ return Collections.unmodifiableList(modifiableList);
+ }
+
+ /**
+ * Set the list of certificate stores that are used to find certificates and
+ * CRLs.
+ *
+ * @param certStores the list of certificate stores.
+ */
+ public void setCertStores(List<CertStore> certStores) {
+ if (certStores == null || certStores.isEmpty()) {
+ // empty list or null provided
+ if (this.certStores != null && !this.certStores.isEmpty()) {
+ // discard non-empty list
+ this.certStores = null;
+ }
+ return;
+ }
+ // non-empty list provided - do shallow copy
+ this.certStores = new ArrayList(certStores);
+ // check that all elements are CertStore
+ for (Iterator i = this.certStores.iterator(); i.hasNext();) {
+ if (!(i.next() instanceof CertStore)) {
+ throw new ClassCastException(Messages.getString("security.6B")); //$NON-NLS-1$
+ }
+ }
+ }
+
+ /**
+ * Adds a certificate store to the list of certificate stores that are used
+ * to find certificates and CRLs.
+ *
+ * @param store
+ * the store to add, if {@code null}, it will be ignored.
+ */
+ public void addCertStore(CertStore store) {
+ if (store == null) {
+ // do nothing if null provided
+ return;
+ }
+ if (certStores == null) {
+ // set to empty List if has not been set yet
+ certStores = new ArrayList();
+ }
+ // add store
+ certStores.add(store);
+ }
+
+ /**
+ * Returns the time for which the validation of the certification path
+ * should be evaluated.
+ *
+ * @return the time for the validation, or {@code null} for the current
+ * time.
+ */
+ public Date getDate() {
+ return date == null ? null : (Date)date.clone();
+ }
+
+ /**
+ * Sets the time for which the validation of the certification path sould be
+ * evaluated.
+ *
+ * @param date
+ * the time for the validation, or {@code null} for the current
+ * time.
+ */
+ public void setDate(Date date) {
+ this.date = (date == null ? null : new Date(date.getTime()));
+ }
+
+ /**
+ * Returns whether an acceptable policy needs to be explicit identified in
+ * every certificate.
+ *
+ * @return {@code true} if an explicit policy is required, otherwise {@code
+ * false}.
+ */
+ public boolean isExplicitPolicyRequired() {
+ return explicitPolicyRequired;
+ }
+
+ /**
+ * Sets whether an an acceptable policy needs to be explicit identified in
+ * every certificate.
+ *
+ * @param explicitPolicyRequired
+ * {@code true} if an explicit policy is required, otherwise
+ * {@code false}.
+ */
+ public void setExplicitPolicyRequired(boolean explicitPolicyRequired) {
+ this.explicitPolicyRequired = explicitPolicyRequired;
+ }
+
+ /**
+ * Returns the list of policies (as OID strings) that would be acceptable
+ * for the purpose of certification path processing.
+ *
+ * @return the unmodifiable list of policies, or an empty set if any policy
+ * is acceptable.
+ */
+ public Set<String> getInitialPolicies() {
+ if (initialPolicies == null) {
+ // set to empty Set if has not been set yet
+ initialPolicies = new HashSet();
+ }
+ if (initialPolicies.isEmpty()) {
+ // no content - no need to copy,
+ // just return immutable view of the same
+ // empty Set each time
+ return Collections.unmodifiableSet(initialPolicies);
+ }
+ // List is not empty - do shallow copy
+ HashSet modifiableSet = new HashSet(initialPolicies);
+ return Collections.unmodifiableSet(modifiableSet);
+ }
+
+ /**
+ * Sets the list of policies (as OID strings) that would be acceptable for
+ * the purpose of certification path processing.
+ *
+ * @param initialPolicies
+ * the list of policies, or an empty set or {@code null} if any
+ * policy is acceptable.
+ */
+ public void setInitialPolicies(Set<String> initialPolicies) {
+ if (initialPolicies == null || initialPolicies.isEmpty()) {
+ // empty list or null provided
+ if (this.initialPolicies != null &&
+ !this.initialPolicies.isEmpty()) {
+ // discard non-empty list
+ this.initialPolicies = null;
+ }
+ return;
+ }
+ // non-empty list provided - do shallow copy
+ this.initialPolicies = new HashSet(initialPolicies);
+ // check that all elements are String
+ for (Iterator i = this.initialPolicies.iterator(); i.hasNext();) {
+ if (!(i.next() instanceof String)) {
+ throw new ClassCastException(Messages.getString("security.6C")); //$NON-NLS-1$
+ }
+ }
+ }
+
+ /**
+ * Returns whether policy mapping is inhibited.
+ *
+ * @return {@code true} if policy mapping is inhibited, otherwise {@code
+ * false}.
+ */
+ public boolean isPolicyMappingInhibited() {
+ return policyMappingInhibited;
+ }
+
+ /**
+ * Sets whether policy mapping is to be inhibited.
+ *
+ * @param policyMappingInhibited
+ * {@code true} if policy mapping is to be inhibited, otherwise
+ * {@code false}.
+ */
+ public void setPolicyMappingInhibited(boolean policyMappingInhibited) {
+ this.policyMappingInhibited = policyMappingInhibited;
+ }
+
+ /**
+ * Returns whether certificates are rejected that include policy
+ * qualifiers in a certificate policy extension that is marked as critical.
+ *
+ * @return {@code true} if the certificates should be rejected, otherwise
+ * {@code false}.
+ */
+ public boolean getPolicyQualifiersRejected() {
+ return policyQualifiersRejected;
+ }
+
+ /**
+ * Sets whether certificates should be rejected that include policy
+ * qualifiers in a certificate policy extension that is marked as critical.
+ *
+ * @param policyQualifiersRejected
+ * {@code true} if the certificates should be rejected, otherwise
+ * {@code false}.
+ */
+ public void setPolicyQualifiersRejected(boolean policyQualifiersRejected) {
+ this.policyQualifiersRejected = policyQualifiersRejected;
+ }
+
+ /**
+ * Returns whether the default revocation checking mechanism of the
+ * underlying service provider is used.
+ *
+ * @return {@code true} if the default revocation checking mechanism is
+ * used, otherwise {@code false}.
+ */
+ public boolean isRevocationEnabled() {
+ return revocationEnabled;
+ }
+
+ /**
+ * Sets whether the default revocation checking mechanism of the underlying
+ * service provider should be used.
+ *
+ * @param revocationEnabled
+ * {@code true} id the default revocation checking mechanism
+ * should be used, otherwise {@code false}.
+ */
+ public void setRevocationEnabled(boolean revocationEnabled) {
+ this.revocationEnabled = revocationEnabled;
+ }
+
+ /**
+ * Returns the name of the signature provider.
+ *
+ * @return the name of the signature provider, or {@code null} if none is
+ * set.
+ */
+ public String getSigProvider() {
+ return sigProvider;
+ }
+
+ /**
+ * Sets the name of the preferred signature provider.
+ * <p>
+ * If set, the specified provider will be preferred for creating signatures.
+ * If not set, the first provider found supporting creation of signatures
+ * will be used.
+ *
+ * @param sigProvider
+ * the name of the preferred signature provider, or {@code null}
+ * if none is preferred.
+ */
+ public void setSigProvider(String sigProvider) {
+ this.sigProvider = sigProvider;
+ }
+
+ /**
+ * Returns the constraints that are required for the target certificate.
+ *
+ * @return the constraints for the target certificate, or {@code null} if
+ * none are set.
+ */
+ public CertSelector getTargetCertConstraints() {
+ return (targetCertConstraints == null ? null
+ :(CertSelector)targetCertConstraints.clone());
+ }
+
+ /**
+ * Sets the constraints that are required for the target certificate.
+ *
+ * @param targetCertConstraints
+ * the constraints for the target certificate, or {@code null} if
+ * none should be used.
+ */
+ public void setTargetCertConstraints(CertSelector targetCertConstraints) {
+ this.targetCertConstraints = (targetCertConstraints == null ? null
+ : (CertSelector)targetCertConstraints.clone());
+ }
+
+ /**
+ * Clones this {@code PKIXParameters} instance.
+ *
+ * @return the cloned instance.
+ */
+ public Object clone() {
+ try {
+ // do shallow copy first
+ PKIXParameters ret = (PKIXParameters)super.clone();
+ // copy fields containing references to mutable objects
+ if (this.certStores != null) {
+ ret.certStores = new ArrayList(this.certStores);
+ }
+ if (this.certPathCheckers != null) {
+ ret.certPathCheckers = new ArrayList(this.certPathCheckers);
+ }
+ return ret;
+ } catch (CloneNotSupportedException e) {
+ throw new AssertionError(e); // android-changed
+ }
+ }
+
+ /**
+ * Returns a string representation of this {@code PKIXParameters} instance.
+ *
+ * @return a string representation of this {@code PKIXParameters} instance.
+ */
+ public String toString() {
+ StringBuilder sb =
+ new StringBuilder("[\n Trust Anchors: "); //$NON-NLS-1$
+ sb.append(trustAnchors);
+ sb.append("\n Revocation Enabled: "); //$NON-NLS-1$
+ sb.append(revocationEnabled);
+ sb.append("\n Explicit Policy Required: "); //$NON-NLS-1$
+ sb.append(explicitPolicyRequired);
+ sb.append("\n Policy Mapping Inhibited: "); //$NON-NLS-1$
+ sb.append(policyMappingInhibited);
+ sb.append("\n Any Policy Inhibited: "); //$NON-NLS-1$
+ sb.append(anyPolicyInhibited);
+ sb.append("\n Policy Qualifiers Rejected: "); //$NON-NLS-1$
+ sb.append(policyQualifiersRejected);
+ sb.append("\n Initial Policy OIDs: "); //$NON-NLS-1$
+ sb.append((initialPolicies == null || initialPolicies.isEmpty())
+ ? "any" : initialPolicies.toString()); //$NON-NLS-1$
+ sb.append("\n Cert Stores: "); //$NON-NLS-1$
+ sb.append((certStores==null||certStores.isEmpty())?
+ "no":certStores.toString()); //$NON-NLS-1$
+ sb.append("\n Validity Date: "); //$NON-NLS-1$
+ sb.append(date);
+ sb.append("\n Cert Path Checkers: "); //$NON-NLS-1$
+ sb.append((certPathCheckers==null||certPathCheckers.isEmpty())?
+ "no":certPathCheckers.toString()); //$NON-NLS-1$
+ sb.append("\n Signature Provider: "); //$NON-NLS-1$
+ sb.append(sigProvider);
+ sb.append("\n Target Certificate Constraints: "); //$NON-NLS-1$
+ sb.append(targetCertConstraints);
+ sb.append("\n]"); //$NON-NLS-1$
+ return sb.toString();
+ }
+
+ //
+ // Private stuff
+ //
+
+ //
+ // Checks that 'trustAnchors' contains
+ // only TrustAnchor instances.
+ // Throws InvalidAlgorithmParameterException if trustAnchors set is empty.
+ //
+ private void checkTrustAnchors(Set trustAnchors)
+ throws InvalidAlgorithmParameterException {
+ if (trustAnchors.isEmpty()) {
+ throw new InvalidAlgorithmParameterException(
+ Messages.getString("security.6D")); //$NON-NLS-1$
+ }
+ for (Iterator i = trustAnchors.iterator(); i.hasNext();) {
+ if (!(i.next() instanceof TrustAnchor)) {
+ throw new ClassCastException(
+ Messages.getString("security.6E")); //$NON-NLS-1$
+ }
+ }
+ }
+}
diff --git a/luni/src/main/java/java/security/cert/PolicyNode.java b/luni/src/main/java/java/security/cert/PolicyNode.java
new file mode 100644
index 0000000..c485b69
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/PolicyNode.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.util.Iterator;
+import java.util.Set;
+
+/**
+ * The interface to a valid policy tree node for the PKIX certification path
+ * validation algorithm.
+ * <p>
+ * Instances of this class are one of the outputs of the PKIX certification path
+ * validation algorithm.
+ */
+public interface PolicyNode {
+
+ /**
+ * Returns the list of children of this node as an {@code Iterator}.
+ *
+ * @return the list of children of this node as an {@code Iterator}.
+ */
+ public Iterator<? extends PolicyNode> getChildren();
+
+ /**
+ * Returns the depth of this node in the policy tree.
+ * <p>
+ * the depth is zero based.
+ *
+ * @return the depth of this node in the policy tree.
+ */
+ public int getDepth();
+
+ /**
+ * Returns the expected policies for the next certificate to be valid.
+ *
+ * @return the expected policies.
+ */
+ public Set<String> getExpectedPolicies();
+
+ /**
+ * Returns the parent policy node.
+ *
+ * @return the parent policy node.
+ */
+ public PolicyNode getParent();
+
+ /**
+ * Returns the policy qualifiers associated with the policy of this node.
+ *
+ * @return the policy qualifiers associated with the policy of this node.
+ */
+ public Set<? extends PolicyQualifierInfo> getPolicyQualifiers();
+
+ /**
+ * Returns the valid policy of this node.
+ *
+ * @return the valid policy of this node.
+ */
+ public String getValidPolicy();
+
+ /**
+ * Returns whether the certificate policy extension of the most recently
+ * processed certificate is marked as critical.
+ *
+ * @return {@code true} if the extension is marked as critical, otherwise
+ * {@code false}.
+ */
+ public boolean isCritical();
+}
diff --git a/luni/src/main/java/java/security/cert/PolicyQualifierInfo.java b/luni/src/main/java/java/security/cert/PolicyQualifierInfo.java
new file mode 100644
index 0000000..903a6e9
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/PolicyQualifierInfo.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.harmony.security.asn1.ObjectIdentifier;
+import org.apache.harmony.security.internal.nls.Messages;
+import org.apache.harmony.security.utils.Array;
+
+
+/**
+ * This class implements a policy qualifier as defined by the ASN.1
+ * {@code PolicyQualifierInfo} structure.
+ */
+public class PolicyQualifierInfo {
+ // This PolicyQualifierInfo DER encoding
+ private final byte[] encoded;
+ // This PolicyQualifierInfo policy qualifier id -
+ // OID represented as String containing non-negative integers
+ // separated by periods
+ private final String policyQualifierId;
+ // DER encoding of the policy qualifier - part of encoded
+ private final byte[] policyQualifier;
+
+ /**
+ * Creates a new {@code PolicyQualifierInfo} from the specified encoded
+ * form.
+ *
+ * @param encoded
+ * the DER encoded policy qualifier.
+ * @throws IOException
+ * the policy qualifier cannot be decoded.
+ */
+ public PolicyQualifierInfo(byte[] encoded) throws IOException {
+ if (encoded == null) {
+ throw new NullPointerException(Messages.getString("security.0A")); //$NON-NLS-1$
+ }
+ if (encoded.length == 0) {
+ throw new IOException(Messages.getString("security.69")); //$NON-NLS-1$
+ }
+ this.encoded = new byte[encoded.length];
+ System.arraycopy(encoded, 0, this.encoded, 0, this.encoded.length);
+
+ // DER Decoding:
+ Object[] decoded = (Object[]) org.apache.harmony.security.x509.PolicyQualifierInfo.ASN1
+ .decode(this.encoded);
+ policyQualifierId = ObjectIdentifier.toString((int[]) decoded[0]);
+ policyQualifier = (byte[]) decoded[1];
+ }
+
+ /**
+ * Returns a ASN.1 DER encoded copy of policy qualifier info.
+ *
+ * @return a ASN.1 DER encoded copy of policy qualifier info.
+ */
+ public final byte[] getEncoded() {
+ byte[] ret = new byte[encoded.length];
+ System.arraycopy(encoded, 0, ret, 0, encoded.length);
+ return ret;
+ }
+
+ /**
+ * Returns the identifier (an OID) of this policy qualifier info.
+ *
+ * @return the identifier of this policy qualifier info.
+ */
+ public final String getPolicyQualifierId() {
+ return policyQualifierId;
+ }
+
+ /**
+ * Returns a ASN.1 DER encoded copy of the qualifier of this policy
+ * qualifier info.
+ *
+ * @return a ASN.1 DER encoded copy of the qualifier of this policy
+ * qualifier info.
+ */
+ public final byte[] getPolicyQualifier() {
+ if (policyQualifier == null) {
+ return null;
+ }
+ byte[] ret = new byte[policyQualifier.length];
+ System.arraycopy(policyQualifier, 0, ret, 0, policyQualifier.length);
+ return ret;
+ }
+
+ /**
+ * Returns a string representation of this {@code PolicyQualifierInfo}
+ * instance.
+ *
+ * @return a string representation of this {@code PolicyQualifierInfo}
+ * instance.
+ */
+ public String toString() {
+ StringBuilder sb =
+ new StringBuilder("PolicyQualifierInfo: [\npolicyQualifierId: "); //$NON-NLS-1$
+ sb.append(policyQualifierId);
+ sb.append("\npolicyQualifier: \n"); //$NON-NLS-1$
+ sb.append(Array.toString(policyQualifier, " ")); //$NON-NLS-1$
+ sb.append("]"); //$NON-NLS-1$
+ return sb.toString();
+ }
+}
diff --git a/luni/src/main/java/java/security/cert/TrustAnchor.java b/luni/src/main/java/java/security/cert/TrustAnchor.java
new file mode 100644
index 0000000..eae38d6
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/TrustAnchor.java
@@ -0,0 +1,282 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.security.PublicKey;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.harmony.security.internal.nls.Messages;
+import org.apache.harmony.security.utils.Array;
+import org.apache.harmony.security.x509.NameConstraints;
+
+
+
+/**
+ * This class represents a trust anchor for validation of X.509 certification
+ * path.
+ * <p>
+ * It is a <i>trusted</i> certificate authority (CA) and includes the public key
+ * of the CA, the CA's name and the constraints for the validation of
+ * certification paths. The constructor also allows to specify a binary
+ * representation of a so called "Name Constraints" extension as a byte array.
+ */
+public class TrustAnchor {
+ // Most trusted CA as a X500Principal
+ private final X500Principal caPrincipal;
+ // Most trusted CA name
+ private final String caName;
+ // Most trusted CA public key
+ private final PublicKey caPublicKey;
+ // Most trusted CA certificate
+ private final X509Certificate trustedCert;
+ // Name constraints extension
+ private final byte[] nameConstraints;
+
+ /**
+ * Creates a new {@code TrustAnchor} with the specified certificate and name
+ * constraints.
+ * <p>
+ * The name constraints will be used as additional constraints during the
+ * validation of certification paths.
+ *
+ * @param trustedCert
+ * the trusted certificate
+ * @param nameConstraints
+ * the ASN.1 DER encoded form of the name constraints or {@code
+ * null} if none.
+ * @throws IllegalArgumentException
+ * if the decoding of the name constraints fail.
+ */
+ public TrustAnchor(X509Certificate trustedCert, byte[] nameConstraints) {
+ if (trustedCert == null) {
+ throw new NullPointerException(Messages.getString("security.5C")); //$NON-NLS-1$
+ }
+ this.trustedCert = trustedCert;
+ // copy nameConstraints if not null
+ if (nameConstraints != null) {
+ this.nameConstraints = new byte[nameConstraints.length];
+ System.arraycopy(nameConstraints, 0,
+ this.nameConstraints, 0, this.nameConstraints.length);
+ processNameConstraints();
+ } else {
+ this.nameConstraints = null;
+ }
+ this.caName = null;
+ this.caPrincipal = null;
+ this.caPublicKey = null;
+ }
+
+ /**
+ * Creates a new {@code TrustAnchor} with the specified certificate
+ * authority name, its public key and the specified name constraints.
+ * <p>
+ * The name constraints will be used as additional constraints during the
+ * validation of certification paths.
+ *
+ * @param caName
+ * the X.500 name of the certificate authority in RFC 2253
+ * {@code String} format.
+ * @param caPublicKey
+ * the public key of the certificate authority
+ * @param nameConstraints
+ * the ASN.1 DER encoded form of the name constraints or {@code
+ * null} if none.
+ * @throws IllegalArgumentException
+ * if the {@code caName} is empty or if decoding of the name
+ * constraints fail.
+ */
+ public TrustAnchor(String caName, PublicKey caPublicKey,
+ byte[] nameConstraints) {
+ if (caName == null) {
+ throw new NullPointerException(Messages.getString("security.5D")); //$NON-NLS-1$
+ }
+ this.caName = caName;
+ if (caPublicKey == null) {
+ throw new NullPointerException(Messages.getString("security.5E")); //$NON-NLS-1$
+ }
+ this.caPublicKey = caPublicKey;
+ // copy nameConstraints if not null
+ if (nameConstraints != null) {
+ this.nameConstraints = new byte[nameConstraints.length];
+ System.arraycopy(nameConstraints, 0,
+ this.nameConstraints, 0, this.nameConstraints.length);
+ processNameConstraints();
+ } else {
+ this.nameConstraints = null;
+ }
+
+ this.trustedCert = null;
+
+ // X500Principal checks caName validity
+ if (caName.length() == 0) {
+ throw new IllegalArgumentException(
+ Messages.getString("security.5F")); //$NON-NLS-1$
+ }
+ this.caPrincipal = new X500Principal(this.caName);
+ }
+
+ /**
+ * Creates a new {@code TrustAnchor} with the specified certificate
+ * authority name as principal, its public key and the specified name
+ * constraints.
+ * <p>
+ * The name constraints will be used as additional constraints during the
+ * validation of certification paths.
+ *
+ * @param caPrincipal
+ * the name of the certificate authority as X500 principal.
+ * @param caPublicKey
+ * the public key of the certificate authority.
+ * @param nameConstraints
+ * the ASN.1 DER encoded form of the name constraints or {@code
+ * null} if none.
+ * @throws IllegalArgumentException
+ * if decoding of the name constraints fail.
+ */
+ public TrustAnchor(X500Principal caPrincipal,
+ PublicKey caPublicKey, byte[] nameConstraints) {
+ if (caPrincipal == null) {
+ throw new NullPointerException(Messages.getString("security.60")); //$NON-NLS-1$
+ }
+ this.caPrincipal = caPrincipal;
+ if (caPublicKey == null) {
+ throw new NullPointerException(Messages.getString("security.5E")); //$NON-NLS-1$
+ }
+ this.caPublicKey = caPublicKey;
+ // copy nameConstraints if not null
+ if (nameConstraints != null) {
+ this.nameConstraints = new byte[nameConstraints.length];
+ System.arraycopy(nameConstraints, 0,
+ this.nameConstraints, 0, this.nameConstraints.length);
+ processNameConstraints();
+ } else {
+ this.nameConstraints = null;
+ }
+
+ this.trustedCert = null;
+ this.caName = caPrincipal.getName();
+ }
+
+ /**
+ * Returns a copy of the name constraints in ASN.1 DER encoded form.
+ *
+ * @return a copy of the name constraints in ASN.1 DER encoded form.
+ */
+ public final byte[] getNameConstraints() {
+ if (nameConstraints == null) {
+ return null;
+ }
+ byte[] ret = new byte[nameConstraints.length];
+ System.arraycopy(nameConstraints, 0,
+ ret, 0, nameConstraints.length);
+ return ret;
+ }
+
+ /**
+ * Returns the certificate of this <i>trusted</i> certificate authority.
+ *
+ * @return the certificate of this CA or {@code null}, if the trust anchor
+ * of this instance was not created with a certificate.
+ */
+ public final X509Certificate getTrustedCert() {
+ return trustedCert;
+ }
+
+ /**
+ * Returns the name of the certificate authority as {@code X500Principal}.
+ *
+ * @return the name of the certificate authority or {@code null} if the
+ * trust anchor of this instance was not created with a {@code
+ * X500Principal}.
+ */
+ public final X500Principal getCA() {
+ return caPrincipal;
+ }
+
+ /**
+ * Returns the name of the certificate authority as {@code String} in RFC
+ * 2253 format.
+ *
+ * @return the name of the certificate authority as {@code String} in RFC
+ * 2253 format or {@code null} if the trust anchor of this instance
+ * was not created with a CA name.
+ */
+ public final String getCAName() {
+ return caName;
+ }
+
+ /**
+ * Returns the public key of the certificate authority.
+ *
+ * @return the public key of the certificate authority or {@code null} if
+ * the trust anchor if this instance was not created with a public
+ * key.
+ */
+ public final PublicKey getCAPublicKey() {
+ return caPublicKey;
+ }
+
+ /**
+ * Returns a string representation of this {@code TrustAnchor} instance.
+ *
+ * @return a string representation of this {@code TrustAnchor} instance.
+ */
+ public String toString() {
+ StringBuilder sb = new StringBuilder("TrustAnchor: [\n"); //$NON-NLS-1$
+ if (trustedCert != null) {
+ sb.append("Trusted CA certificate: "); //$NON-NLS-1$
+ sb.append(trustedCert);
+ sb.append("\n"); //$NON-NLS-1$
+ }
+ if (caPrincipal != null) {
+ sb.append("Trusted CA Name: "); //$NON-NLS-1$
+ sb.append(caPrincipal);
+ sb.append("\n"); //$NON-NLS-1$
+ }
+ if (caPublicKey != null) {
+ sb.append("Trusted CA Public Key: "); //$NON-NLS-1$
+ sb.append(caPublicKey);
+ sb.append("\n"); //$NON-NLS-1$
+ }
+ // FIXME if needed:
+ if (nameConstraints != null) {
+ sb.append("Name Constraints:\n"); //$NON-NLS-1$
+ sb.append(Array.toString(nameConstraints, " ")); //$NON-NLS-1$
+ }
+ sb.append("\n]"); //$NON-NLS-1$
+ return sb.toString();
+ }
+
+ //
+ // Private stuff
+ //
+
+ // Decodes and checks NameConstraints structure.
+ // Throws IllegalArgumentException if NameConstraints
+ // encoding is invalid.
+ private void processNameConstraints() {
+ try {
+ // decode and check nameConstraints
+ NameConstraints.ASN1.decode(nameConstraints);
+ } catch (IOException e) {
+ throw new IllegalArgumentException(e.getMessage());
+ }
+ }
+}
diff --git a/luni/src/main/java/java/security/cert/X509CRL.java b/luni/src/main/java/java/security/cert/X509CRL.java
new file mode 100644
index 0000000..cb99843
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/X509CRL.java
@@ -0,0 +1,279 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.ByteArrayInputStream;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.cert.CRL;
+import java.security.cert.CRLException;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509Extension;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Set;
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * Abstract base class for X.509 certificate revocation lists (CRL).
+ * <p>
+ * More information regarding CRL can be found in RFC 2459,
+ * "Internet X.509 Public Key Infrastructure Certificate and CRL Profile" at <a
+ * href
+ * ="http://www.ietf.org/rfc/rfc2459.txt">http://www.ietf.org/rfc/rfc2459.txt
+ * </a>.
+ */
+public abstract class X509CRL extends CRL implements X509Extension {
+
+ /**
+ * Creates a new {@code X509CRL} instance.
+ */
+ protected X509CRL() {
+ super("X.509"); //$NON-NLS-1$
+ }
+
+ /**
+ * Returns whether the specified object equals to this instance.
+ *
+ * @param other
+ * the object to compare.
+ * @return {@code true} if the specified object is equal to this, otherwise
+ * {@code false}.
+ */
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+ if (!(other instanceof X509CRL)) {
+ return false;
+ }
+ X509CRL obj = (X509CRL) other;
+ try {
+ return Arrays.equals(getEncoded(), obj.getEncoded());
+ } catch (CRLException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Returns the hashcode of this CRL instance.
+ *
+ * @return the hashcode.
+ */
+ public int hashCode() {
+ try {
+ int res = 0;
+ byte[] array = getEncoded();
+ for (int i=0; i<array.length; i++) {
+ res += array[i] & 0xFF;
+ }
+ return res;
+ } catch (CRLException e) {
+ return 0;
+ }
+ }
+
+ /**
+ * Returns this CRL in ASN.1 DER encoded form.
+ *
+ * @return this CRL in ASN.1 DER encoded form.
+ * @throws CRLException
+ * if encoding fails.
+ */
+ public abstract byte[] getEncoded() throws CRLException;
+
+
+ /**
+ * Verifies this CRL by verifying that this CRL was signed with the
+ * corresponding private key to the specified public key.
+ *
+ * @param key
+ * the public key to verify this CRL with.
+ * @throws CRLException
+ * if encoding or decoding fails.
+ * @throws NoSuchAlgorithmException
+ * if a needed algorithm is not present.
+ * @throws InvalidKeyException
+ * if the specified key is invalid.
+ * @throws NoSuchProviderException
+ * if no provider can be found.
+ * @throws SignatureException
+ * if errors occur on signatures.
+ */
+ public abstract void verify(PublicKey key)
+ throws CRLException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException,
+ SignatureException;
+
+ /**
+ * Verifies this CRL by verifying that this CRL was signed with the
+ * corresponding private key to the specified public key. The signature
+ * verification engine of the specified provider will be used.
+ *
+ * @param key
+ * the public key to verify this CRL with.
+ * @param sigProvider
+ * the name of the provider for the signature algorithm.
+ * @throws CRLException
+ * if encoding decoding fails.
+ * @throws NoSuchAlgorithmException
+ * if a needed algorithm is not present.
+ * @throws InvalidKeyException
+ * if the specified key is invalid.
+ * @throws NoSuchProviderException
+ * if the specified provider cannot be found.
+ * @throws SignatureException
+ * if errors occur on signatures.
+ */
+ public abstract void verify(PublicKey key, String sigProvider)
+ throws CRLException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException,
+ SignatureException;
+
+ /**
+ * Returns the version number of this CRL.
+ *
+ * @return the version number of this CRL.
+ */
+ public abstract int getVersion();
+
+ /**
+ * <b>Do not use</b>, use {@link #getIssuerX500Principal()} instead. Returns
+ * the issuer as an implementation specific Principal object.
+ *
+ * @return the issuer distinguished name.
+ */
+ public abstract Principal getIssuerDN();
+
+ /**
+ * Returns the issuer distinguished name of this CRL.
+ *
+ * @return the issuer distinguished name of this CRL.
+ */
+ public X500Principal getIssuerX500Principal() {
+ try {
+ // TODO if there is no X.509 certificate provider installed
+ // should we try to access Harmony X509CRLImpl via classForName?
+ CertificateFactory factory = CertificateFactory
+ .getInstance("X.509"); //$NON-NLS-1$
+
+ X509CRL crl = (X509CRL) factory
+ .generateCRL(new ByteArrayInputStream(getEncoded()));
+
+ return crl.getIssuerX500Principal();
+
+ } catch (Exception e) {
+ throw new RuntimeException(Messages.getString("security.59"), e); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Returns the {@code thisUpdate} value of this CRL.
+ *
+ * @return the {@code thisUpdate} value of this CRL.
+ */
+ public abstract Date getThisUpdate();
+
+ /**
+ * Returns the {@code nextUpdate} value of this CRL.
+ *
+ * @return the {@code nextUpdate} value of this CRL, or {@code null} if none
+ * is present.
+ */
+ public abstract Date getNextUpdate();
+
+ /**
+ * Returns the CRL entry with the specified certificate serial number.
+ *
+ * @param serialNumber
+ * the certificate serial number to search for a CRL entry.
+ * @return the entry for the specified certificate serial number, or {@code
+ * null} if not found.
+ */
+ public abstract X509CRLEntry getRevokedCertificate(BigInteger serialNumber);
+
+ /**
+ * Returns the CRL entry for the specified certificate.
+ *
+ * @param certificate
+ * the certificate to search a CRL entry for.
+ * @return the entry for the specified certificate, or {@code null} if not
+ * found.
+ */
+ public X509CRLEntry getRevokedCertificate(X509Certificate certificate) {
+ if (certificate == null) {
+ throw new NullPointerException();
+ }
+ return getRevokedCertificate(certificate.getSerialNumber());
+ }
+
+ /**
+ * Returns the set of revoked certificates.
+ *
+ * @return the set of revoked certificates, or {@code null} if no revoked
+ * certificates are in this CRL.
+ */
+ public abstract Set<? extends X509CRLEntry> getRevokedCertificates();
+
+ /**
+ * Returns the {@code tbsCertList} information of this CRL in DER encoded
+ * form.
+ *
+ * @return the CRL information in DER encoded form.
+ * @throws CRLException
+ * if encoding fails.
+ */
+ public abstract byte[] getTBSCertList() throws CRLException;
+
+ /**
+ * Returns the signature bytes of this CRL.
+ *
+ * @return the signature bytes of this CRL.
+ */
+ public abstract byte[] getSignature();
+
+ /**
+ * Returns the name of the signature algorithm.
+ *
+ * @return the name of the signature algorithm.
+ */
+ public abstract String getSigAlgName();
+
+ /**
+ * Returns the OID of the signature algorithm.
+ *
+ * @return the OID of the signature algorithm.
+ */
+ public abstract String getSigAlgOID();
+
+ /**
+ * Returns the parameters of the signature algorithm in DER encoded form.
+ *
+ * @return the parameters of the signature algorithm in DER encoded form, or
+ * {@code null} if not present.
+ */
+ public abstract byte[] getSigAlgParams();
+}
+
diff --git a/luni/src/main/java/java/security/cert/X509CRLEntry.java b/luni/src/main/java/java/security/cert/X509CRLEntry.java
new file mode 100644
index 0000000..ccdaf2f
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/X509CRLEntry.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.math.BigInteger;
+import java.security.cert.CRLException;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509Extension;
+import java.util.Arrays;
+import java.util.Date;
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * Abstract base class for entries in a certificate revocation list (CRL).
+ *
+ * @see X509CRL
+ */
+public abstract class X509CRLEntry implements X509Extension {
+
+ /**
+ * Creates a new {@code X509CRLEntry} instance.
+ */
+ public X509CRLEntry() {}
+
+ /**
+ * Returns whether the specified object equals to this instance.
+ *
+ * @param other
+ * the object to compare.
+ * @return {@code true} if the specified object equals to this instance,
+ * otherwise {@code false}.
+ */
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+ if (!(other instanceof X509CRLEntry)) {
+ return false;
+ }
+ X509CRLEntry obj = (X509CRLEntry) other;
+ try {
+ return Arrays.equals(getEncoded(), obj.getEncoded());
+ } catch (CRLException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Returns the hashcode of this instance.
+ *
+ * @return the hashcode of this instance.
+ */
+ public int hashCode() {
+ int res = 0;
+ try {
+ byte[] array = getEncoded();
+ for (int i=0; i<array.length; i++) {
+ res += array[i] & 0xFF;
+ }
+ } catch (CRLException e) {
+ }
+ return res;
+ }
+
+ /**
+ * Returns this entry in ASN.1 DER encoded form.
+ *
+ * @return the encoded form of this entry.
+ * @throws CRLException
+ * if encoding fails.
+ */
+ public abstract byte[] getEncoded() throws CRLException;
+
+ /**
+ * Returns the serial number of the revoked certificate.
+ *
+ * @return the serial number of the revoked certificate.
+ */
+ public abstract BigInteger getSerialNumber();
+
+ /**
+ * Returns the issuer of the revoked certificate.
+ *
+ * @return the issuer of the revoked certificate, or {@code null} if the
+ * issuer is equal to the CRL issuer.
+ */
+ public X500Principal getCertificateIssuer() {
+ return null;
+ }
+
+ /**
+ * Returns the date when the certificate is revoked.
+ *
+ * @return the date when the certificate is revoked.
+ */
+ public abstract Date getRevocationDate();
+
+ /**
+ * Returns whether this CRL entry has extensions.
+ *
+ * @return {@code true} is this CRL entry has extensions, otherwise {@code
+ * false}.
+ */
+ public abstract boolean hasExtensions();
+
+ /**
+ * Returns a string representation of this instance.
+ *
+ * @return a string representation of this instance.
+ */
+ public abstract String toString();
+}
+
diff --git a/luni/src/main/java/java/security/cert/X509CRLSelector.java b/luni/src/main/java/java/security/cert/X509CRLSelector.java
new file mode 100644
index 0000000..0edddf4
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/X509CRLSelector.java
@@ -0,0 +1,466 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.harmony.security.asn1.ASN1Integer;
+import org.apache.harmony.security.asn1.ASN1OctetString;
+import org.apache.harmony.security.internal.nls.Messages;
+import org.apache.harmony.security.x501.Name;
+
+/**
+ * A CRL selector ({@code CRLSelector} for selecting {@code
+ * X509CRL}s that match the specified criteria.
+ * <p>
+ * When constructed, all criteria are set to default values that will match any
+ * {@code X509CRL}.
+ */
+public class X509CRLSelector implements CRLSelector {
+
+ // issuerNames criterion:
+ // contains X.500 distinguished names in CANONICAL format
+ private ArrayList<String> issuerNames;
+ // contains X500Principal objects corresponding to the names
+ // from issuerNames collection (above)
+ private ArrayList<X500Principal> issuerPrincipals;
+ // minCRLNumber criterion
+ private BigInteger minCRL;
+ // maxCRLNumber criterion
+ private BigInteger maxCRL;
+ // dateAndTime criterion
+ private long dateAndTime = -1;
+ // the certificate being checked
+ private X509Certificate certificateChecking;
+
+ /**
+ * Creates a new {@code X509CertSelector}.
+ */
+ public X509CRLSelector() { }
+
+ /**
+ * Sets the criterion for the issuer distinguished names.
+ * <p>
+ * The CRL issuer must match at least one of the specified distinguished
+ * names.
+ *
+ * @param issuers
+ * the list of issuer distinguished names to match, or {@code
+ * null} if any issuer distinguished name will do.
+ */
+ public void setIssuers(Collection<X500Principal> issuers) {
+ if (issuers == null) {
+ issuerNames = null;
+ issuerPrincipals = null;
+ return;
+ }
+ issuerNames = new ArrayList<String>(issuers.size());
+ issuerPrincipals = new ArrayList<X500Principal>(issuers);
+ for (X500Principal issuer: issuers) {
+ issuerNames.add(issuer.getName(X500Principal.CANONICAL));
+ }
+ }
+
+ /**
+ * <b>Do not use:</b> use {@link #setIssuers(Collection)} or one of
+ * {@link #addIssuerName} instead. Sets the criterion for the issuer
+ * distinguished names.
+ * <p>
+ * The CRL issuer must match at least one of the specified distinguished
+ * names.
+ * <p>
+ * The specified parameter {@code names} is a collection with an entry for
+ * each name to be included in the criterion. The name is specified as a
+ * {@code String} or a byte array specifying the name (in RFC 2253 or ASN.1
+ * DER encoded form)
+ *
+ * @param names
+ * the list of issuer distinguished names to match, or {@code
+ * null} if any issuer distinguished name will do.
+ * @throws IOException
+ * if parsing fails.
+ */
+ public void setIssuerNames(Collection<?> names) throws IOException {
+ if (names == null) {
+ issuerNames = null;
+ issuerPrincipals = null;
+ return;
+ }
+ if (names.size() == 0) {
+ return;
+ }
+ issuerNames = new ArrayList<String>(names.size());
+ for (Object name: names) {
+ if (name instanceof String) {
+ issuerNames.add(
+ new Name((String) name).getName(
+ X500Principal.CANONICAL));
+ } else if (name instanceof byte[]) {
+ issuerNames.add(
+ new Name((byte[]) name).getName(
+ X500Principal.CANONICAL));
+ } else {
+ throw new IOException(
+ Messages.getString("security.62")); //$NON-NLS-1$
+ }
+ }
+ }
+
+ /**
+ * Adds an issuer to the criterion for the issuer distinguished names.
+ * <p>
+ * The CRL issuer must match at least one of the specified distinguished
+ * names.
+ *
+ * @param issuer
+ * the issuer to add to the criterion
+ */
+ public void addIssuer(X500Principal issuer) {
+ if (issuer == null) {
+ throw new NullPointerException(Messages.getString("security.61")); //$NON-NLS-1$
+ }
+ if (issuerNames == null) {
+ issuerNames = new ArrayList<String>();
+ }
+ String name = issuer.getName(X500Principal.CANONICAL);
+ if (!issuerNames.contains(name)) {
+ issuerNames.add(name);
+ }
+ if (issuerPrincipals == null) {
+ issuerPrincipals = new ArrayList<X500Principal>(issuerNames.size());
+ }
+ // extend the list of issuer Principals
+ int size = issuerNames.size() - 1;
+ for (int i=issuerPrincipals.size(); i<size; i++) {
+ issuerPrincipals.add(new X500Principal(issuerNames.get(i)));
+ }
+ issuerPrincipals.add(issuer);
+ }
+
+ /**
+ * <b>Do not use:</b>, use {@link #addIssuer(X500Principal)} or
+ * {@link #addIssuerName(byte[])} instead. It can fail to match some CRLs
+ * because of a loss of encoding information in a RFC 2253 string.
+ * <p>
+ * Adds an issuer to the criterion for the issuer distinguished names. The
+ * CRK issuer must match at least one of the specified distinguished names.
+ *
+ * @param iss_name
+ * the RFC 2253 encoded name.
+ * @throws IOException
+ * if parsing fails.
+ */
+ public void addIssuerName(String iss_name) throws IOException {
+ if (issuerNames == null) {
+ issuerNames = new ArrayList<String>();
+ }
+
+ if (iss_name == null) {
+ iss_name = ""; //$NON-NLS-1$
+ }
+
+ String name = new Name(iss_name).getName(X500Principal.CANONICAL);
+ if (!issuerNames.contains(name)) {
+ issuerNames.add(name);
+ }
+ }
+
+ /**
+ * Adds an issuer to the criterion for the issuer distinguished names.
+ * <p>
+ * The CRL issuer must match at least one of the specified distinguished
+ * names.
+ *
+ * @param iss_name
+ * the issuer to add to the criterion in ASN.1 DER encoded form.
+ * @throws IOException
+ * if parsing fails.
+ */
+ public void addIssuerName(byte[] iss_name) throws IOException {
+ if (iss_name == null) {
+ throw new NullPointerException(Messages.getString("security.63")); //$NON-NLS-1$
+ }
+ if (issuerNames == null) {
+ issuerNames = new ArrayList<String>();
+ }
+ String name = new Name(iss_name).getName(X500Principal.CANONICAL);
+ if (!issuerNames.contains(name)) {
+ issuerNames.add(name);
+ }
+ }
+
+ /**
+ * Sets the criterion for the minimum CRL number.
+ * <p>
+ * The CRL must have a number extension with a value greater than or equal
+ * to the specified parameter.
+ *
+ * @param minCRL
+ * the minimum CRL number or null to not check the minimum CRL
+ * number
+ */
+ public void setMinCRLNumber(BigInteger minCRL) {
+ this.minCRL = minCRL;
+ }
+
+ /**
+ * Sets the criterion for the maximum CRL number.
+ * <p>
+ * The CRL must have a number extension with a value less than or equal to
+ * the specified parameter.
+ *
+ * @param maxCRL
+ * the maximum CRL number or null to not check the maximum CRL
+ * number.
+ */
+ public void setMaxCRLNumber(BigInteger maxCRL) {
+ this.maxCRL = maxCRL;
+ }
+
+ /**
+ * Sets the criterion for the CRL update period.
+ * <p>
+ * The CRL's {@code thisUpdate} value must be equal or before the specified
+ * date and the {@code nextUpdate} value must be after the specified date.
+ *
+ * @param dateAndTime
+ * the date to search for valid CRL's or {@code null} to not
+ * check the date.
+ */
+ public void setDateAndTime(Date dateAndTime) {
+ if (dateAndTime == null) {
+ this.dateAndTime = -1;
+ return;
+ }
+ this.dateAndTime = dateAndTime.getTime();
+ }
+
+ /**
+ * Sets a certificate hint to find CRLs. It's not a criterion but may help
+ * finding relevant CRLs.
+ *
+ * @param cert
+ * the certificate hint or {@code null}.
+ */
+ public void setCertificateChecking(X509Certificate cert) {
+ this.certificateChecking = cert;
+ }
+
+ /**
+ * Returns the criterion for the issuer distinguished names.
+ * <p>
+ * The CRL issuer must match at least one of the distinguished names.
+ *
+ * @return the unmodifiable list of issuer distinguished names to match, or
+ * {@code null} if any issuer distinguished name will do.
+ */
+ public Collection<X500Principal> getIssuers() {
+ if (issuerNames == null) {
+ return null;
+ }
+ if (issuerPrincipals == null) {
+ issuerPrincipals = new ArrayList<X500Principal>(issuerNames.size());
+ }
+ int size = issuerNames.size();
+ // extend the list of issuer Principals
+ for (int i=issuerPrincipals.size(); i<size; i++) {
+ issuerPrincipals.add(new X500Principal(issuerNames.get(i)));
+ }
+ return Collections.unmodifiableCollection(issuerPrincipals);
+ }
+
+ /**
+ * Returns the criterion for the issuer distinguished names.
+ * <p>
+ * The CRL issuer must match at least one of the distinguished names.
+ *
+ * @return a copy of the list of issuer distinguished names to match, or
+ * {@code null} if any issuer distinguished name will do.
+ */
+ public Collection<Object> getIssuerNames() {
+ if (issuerNames == null) {
+ return null;
+ }
+ return Collections.unmodifiableCollection((ArrayList<?>) issuerNames);
+ }
+
+ /**
+ * Returns the criterion for the minimum CRL number.
+ * <p>
+ * The CRL must have a number extension with a value greater than or equal
+ * to the returned value.
+ *
+ * @return the minimum CRL number or {@code null} if the minimum CRL number
+ * is not to be checked.
+ */
+ public BigInteger getMinCRL() {
+ return minCRL;
+ }
+
+ /**
+ * Returns the criterion for the maximum CRL number.
+ * <p>
+ * The CRL must have a number extension with a value less than or equal to
+ * the returned value.
+ *
+ * @return the maximum CRL number or null if the maximum CRL number is not
+ * checked.
+ */
+ public BigInteger getMaxCRL() {
+ return maxCRL;
+ }
+
+ /**
+ * Returns the criterion for the CRL update period.
+ * <p>
+ * The CRL's {@code thisUpdate} value must be equal or before the returned
+ * date and the {@code nextUpdate} value must be after the returned date.
+ *
+ * @return the date to search for valid CRL's or {@code null} if the date is
+ * not checked.
+ */
+ public Date getDateAndTime() {
+ if (dateAndTime == -1) {
+ return null;
+ }
+ return new Date(dateAndTime);
+ }
+
+ /**
+ * Returns the certificate hint to find CRLs. It's not a criterion but may
+ * help finding relevant CRLs.
+ *
+ * @return the certificate hint or {@code null} if none set.
+ */
+ public X509Certificate getCertificateChecking() {
+ return certificateChecking;
+ }
+
+ /**
+ * Returns a string representation of this {@code X509CRLSelector} instance.
+ *
+ * @return a string representation of this {@code X509CRLSelector} instance.
+ */
+ public String toString() {
+ StringBuilder result = new StringBuilder();
+ result.append("X509CRLSelector:\n["); //$NON-NLS-1$
+ if (issuerNames != null) {
+ result.append("\n IssuerNames:\n ["); //$NON-NLS-1$
+ int size = issuerNames.size();
+ for (int i=0; i<size; i++) {
+ result.append("\n " //$NON-NLS-1$
+ + issuerNames.get(i));
+ }
+ result.append("\n ]"); //$NON-NLS-1$
+ }
+ if (minCRL != null) {
+ result.append("\n minCRL: " + minCRL); //$NON-NLS-1$
+ }
+ if (maxCRL != null) {
+ result.append("\n maxCRL: " + maxCRL); //$NON-NLS-1$
+ }
+ if (dateAndTime != -1) {
+ result.append("\n dateAndTime: " + (new Date(dateAndTime))); //$NON-NLS-1$
+ }
+ if (certificateChecking != null) {
+ result.append("\n certificateChecking: " + certificateChecking); //$NON-NLS-1$
+ }
+ result.append("\n]"); //$NON-NLS-1$
+ return result.toString();
+ }
+
+ /**
+ * Returns whether the specified CRL matches all the criteria collected in
+ * this instance.
+ *
+ * @param crl
+ * the CRL to check.
+ * @return {@code true} if the CRL matches all the criteria, otherwise
+ * {@code false}.
+ */
+ public boolean match(CRL crl) {
+ if (!(crl instanceof X509CRL)) {
+ return false;
+ }
+ X509CRL crlist = (X509CRL) crl;
+ if ((issuerNames != null) &&
+ // the search speed depends on the class of issuerNames
+ !(issuerNames.contains(
+ crlist.getIssuerX500Principal().getName(
+ X500Principal.CANONICAL)))) {
+ return false;
+ }
+ if ((minCRL != null) || (maxCRL != null)) {
+ try {
+ // As specified in rfc 3280 (http://www.ietf.org/rfc/rfc3280.txt)
+ // CRL Number Extension's OID is 2.5.29.20 .
+ byte[] bytes = crlist.getExtensionValue("2.5.29.20"); //$NON-NLS-1$
+ bytes = (byte[]) ASN1OctetString.getInstance().decode(bytes);
+ BigInteger crlNumber = new BigInteger((byte[])
+ ASN1Integer.getInstance().decode(bytes));
+ if ((minCRL != null) && (crlNumber.compareTo(minCRL) < 0)) {
+ return false;
+ }
+ if ((maxCRL != null) && (crlNumber.compareTo(maxCRL) > 0)) {
+ return false;
+ }
+ } catch (IOException e) {
+ return false;
+ }
+ }
+ if (dateAndTime != -1) {
+ Date thisUp = crlist.getThisUpdate();
+ Date nextUp = crlist.getNextUpdate();
+ if ((thisUp == null) || (nextUp == null)) {
+ return false;
+ }
+ if ((dateAndTime < thisUp.getTime())
+ || (dateAndTime > nextUp.getTime())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Clones this {@code X509CRL} instance.
+ *
+ * @return the cloned instance.
+ */
+ public Object clone() {
+ X509CRLSelector result;
+
+ try {
+ result = (X509CRLSelector) super.clone();
+ if (issuerNames != null) {
+ result.issuerNames = new ArrayList<String>(issuerNames);
+ }
+ } catch (CloneNotSupportedException e) {
+ result = null;
+ }
+ return result;
+ }
+}
+
diff --git a/luni/src/main/java/java/security/cert/X509CertSelector.java b/luni/src/main/java/java/security/cert/X509CertSelector.java
new file mode 100644
index 0000000..0460fd6
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/X509CertSelector.java
@@ -0,0 +1,1432 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.math.BigInteger;
+import java.security.PublicKey;
+import java.security.cert.CertSelector;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.harmony.security.asn1.ASN1OctetString;
+import org.apache.harmony.security.internal.nls.Messages;
+import org.apache.harmony.security.x509.AlgorithmIdentifier;
+import org.apache.harmony.security.x509.CertificatePolicies;
+import org.apache.harmony.security.x509.GeneralName;
+import org.apache.harmony.security.x509.GeneralNames;
+import org.apache.harmony.security.x509.NameConstraints;
+import org.apache.harmony.security.x509.PolicyInformation;
+import org.apache.harmony.security.x509.PrivateKeyUsagePeriod;
+import org.apache.harmony.security.x509.SubjectPublicKeyInfo;
+
+
+
+/**
+ * A certificate selector ({@code CertSelector} for selecting {@code
+ * X509Certificate}s that match the specified criteria.
+ */
+public class X509CertSelector implements CertSelector {
+
+ // match criteria
+ private X509Certificate certificateEquals;
+ private BigInteger serialNumber;
+ private X500Principal issuer;
+ private X500Principal subject;
+ private byte[] subjectKeyIdentifier;
+ private byte[] authorityKeyIdentifier;
+ private Date certificateValid;
+ private String subjectPublicKeyAlgID;
+ private Date privateKeyValid;
+ private byte[] subjectPublicKey;
+ private boolean[] keyUsage;
+ private Set extendedKeyUsage;
+ private boolean matchAllNames = true;
+ private int pathLen = -1;
+ private List[] subjectAltNames;
+ private NameConstraints nameConstraints;
+ private Set policies;
+ private ArrayList pathToNames;
+
+ // needed to avoid needless encoding/decoding work
+ private PublicKey subjectPublicKeyImpl;
+ private String issuerName;
+ private byte[] issuerBytes;
+
+ /**
+ * Creates a new {@code X509CertSelector}.
+ */
+ public X509CertSelector() {}
+
+ /**
+ * Sets the certificate that a matching certificate must be equal to.
+ *
+ * @param certificate
+ * the certificate to match, or null to not check this criteria.
+ */
+ public void setCertificate(X509Certificate certificate) {
+ certificateEquals = certificate;
+ }
+
+ /**
+ * Returns the certificate that a matching certificate must be equal to.
+ *
+ * @return the certificate to match, or null if this criteria is not
+ * checked.
+ */
+ public X509Certificate getCertificate() {
+ return certificateEquals;
+ }
+
+ /**
+ * Sets the serial number that a certificate must match.
+ *
+ * @param serialNumber
+ * the serial number to match, or {@code null} to not check the
+ * serial number.
+ */
+ public void setSerialNumber(BigInteger serialNumber) {
+ this.serialNumber = serialNumber;
+ }
+
+ /**
+ * Returns the serial number that a certificate must match.
+ *
+ * @return the serial number to match, or {@code null} if the serial number
+ * is not to be checked.
+ */
+ public BigInteger getSerialNumber() {
+ return serialNumber;
+ }
+
+ /**
+ * Sets the issuer that a certificate must match.
+ *
+ * @param issuer
+ * the issuer to match, or {@code null} if the issuer is not to
+ * be checked.
+ */
+ public void setIssuer(X500Principal issuer) {
+ this.issuer = issuer;
+ this.issuerName = null;
+ this.issuerBytes = null;
+ }
+
+ /**
+ * Returns the issuer that a certificate must match.
+ *
+ * @return the issuer that a certificate must match, or {@code null} if the
+ * issuer is not to be checked.
+ */
+ public X500Principal getIssuer() {
+ return issuer;
+ }
+
+ /**
+ * <b>Do not use</b>, use {@link #getIssuer()} or
+ * {@link #getIssuerAsBytes()} instead. Sets the issuer that a certificate
+ * must match.
+ *
+ * @param issuerName
+ * the issuer in a RFC 2253 format string, or {@code null} to not
+ * check the issuer.
+ * @throws IOException
+ * if parsing the issuer fails.
+ */
+ public void setIssuer(String issuerName) throws IOException {
+ if (issuerName == null) {
+ this.issuer = null;
+ this.issuerName = null;
+ this.issuerBytes = null;
+ return;
+ }
+ try {
+ this.issuer = new X500Principal(issuerName);
+ this.issuerName = issuerName;
+ this.issuerBytes = null;
+ } catch (IllegalArgumentException e) {
+ throw new IOException(e.getMessage());
+ }
+ }
+
+ /**
+ * <b>Do not use</b>, use {@link #getIssuer()} or
+ * {@link #getIssuerAsBytes()} instead. Returns the issuer that a
+ * certificate must match in a RFC 2253 format string.
+ *
+ * @return the issuer in a RFC 2253 format string, or {@code null} if the
+ * issuer is not to be checked.
+ */
+ public String getIssuerAsString() {
+ if (issuer == null) {
+ return null;
+ }
+ if (issuerName == null) {
+ issuerName = issuer.getName();
+ }
+ return issuerName;
+ }
+
+ /**
+ * Sets the issuer that a certificate must match.
+ *
+ * @param issuerDN
+ * the distinguished issuer name in ASN.1 DER encoded format, or
+ * {@code null} to not check the issuer.
+ * @throws IOException
+ * if decoding the issuer fail.
+ */
+ public void setIssuer(byte[] issuerDN) throws IOException {
+ if (issuerDN == null) {
+ issuer = null;
+ return;
+ }
+ try {
+ issuer = new X500Principal(issuerDN);
+ this.issuerName = null;
+ this.issuerBytes = new byte[issuerDN.length];
+ System.arraycopy(issuerDN, 0, this.issuerBytes, 0, issuerDN.length);
+ } catch (IllegalArgumentException e) {
+ throw new IOException(e.getMessage());
+ }
+ }
+
+ /**
+ * Returns the issuer that a certificate must match.
+ *
+ * @return the distinguished issuer name in ASN.1 DER encoded format, or
+ * {@code null} if the issuer is not to be checked.
+ * @throws IOException
+ * if encoding the issuer fails.
+ */
+ public byte[] getIssuerAsBytes() throws IOException {
+ if (issuer == null) {
+ return null;
+ }
+ if (issuerBytes == null) {
+ issuerBytes = issuer.getEncoded();
+ }
+ byte[] result = new byte[issuerBytes.length];
+ System.arraycopy(issuerBytes, 0, result, 0, issuerBytes.length);
+ return result;
+ }
+
+ /**
+ * Set the subject that a certificate must match.
+ *
+ * @param subject
+ * the subject distinguished name or {@code null} to not check
+ * the subject.
+ */
+ public void setSubject(X500Principal subject) {
+ this.subject = subject;
+ }
+
+ /**
+ * Returns the subject that a certificate must match.
+ *
+ * @return the subject distinguished name, or null if the subject is not to
+ * be checked.
+ */
+ public X500Principal getSubject() {
+ return subject;
+ }
+
+ /**
+ * <b>Do not use</b>, use {@link #setSubject(byte[])} or
+ * {@link #setSubject(X500Principal)} instead. Returns the subject that a
+ * certificate must match.
+ *
+ * @param subjectDN
+ * the subject distinguished name in RFC 2253 format or {@code
+ * null} to not check the subject.
+ * @throws IOException
+ * if decoding the subject fails.
+ */
+ public void setSubject(String subjectDN) throws IOException {
+ if (subjectDN == null) {
+ subject = null;
+ return;
+ }
+ try {
+ subject = new X500Principal(subjectDN);
+ } catch (IllegalArgumentException e) {
+ throw new IOException(e.getMessage());
+ }
+ }
+
+ /**
+ * <b>Do not use</b>, use {@link #getSubject()} or
+ * {@link #getSubjectAsBytes()} instead. Returns the subject that a
+ * certificate must match.
+ *
+ * @return the subject distinguished name in RFC 2253 format, or {@code
+ * null} if the subject is not to be checked.
+ */
+ public String getSubjectAsString() {
+ if (subject == null) {
+ return null;
+ }
+ return subject.getName();
+ }
+
+ /**
+ * Sets the subject that a certificate must match.
+ *
+ * @param subjectDN
+ * the subject distinguished name in ASN.1 DER format, or {@code
+ * null} to not check the subject.
+ * @throws IOException
+ * if decoding the subject fails.
+ */
+ public void setSubject(byte[] subjectDN) throws IOException {
+ if (subjectDN == null) {
+ subject = null;
+ return;
+ }
+ try {
+ subject = new X500Principal(subjectDN);
+ } catch (IllegalArgumentException e) {
+ throw new IOException(e.getMessage());
+ }
+ }
+
+ /**
+ * Returns the subject that a certificate must match.
+ *
+ * @return the subject distinguished name in ASN.1 DER format, or {@code
+ * null} if the subject is not to be checked.
+ * @throws IOException
+ * if encoding the subject fails.
+ */
+ public byte[] getSubjectAsBytes() throws IOException {
+ if (subject == null) {
+ return null;
+ }
+ return subject.getEncoded();
+ }
+
+ /**
+ * Sets the criterion for the {@literal SubjectKeyIdentifier} extension.
+ * <p>
+ * The {@code subjectKeyIdentifier} should be a single DER encoded value.
+ *
+ * @param subjectKeyIdentifier
+ * the subject key identifier or {@code null} to disable this
+ * check.
+ */
+ public void setSubjectKeyIdentifier(byte[] subjectKeyIdentifier) {
+ if (subjectKeyIdentifier == null) {
+ this.subjectKeyIdentifier = null;
+ return;
+ }
+ this.subjectKeyIdentifier = new byte[subjectKeyIdentifier.length];
+ System.arraycopy(subjectKeyIdentifier, 0, this.subjectKeyIdentifier, 0,
+ subjectKeyIdentifier.length);
+ }
+
+ /**
+ * Returns the criterion for the {@literal SubjectKeyIdentifier} extension.
+ *
+ * @return the subject key identifier or {@code null} if it is not to be
+ * checked.
+ */
+ public byte[] getSubjectKeyIdentifier() {
+ if (subjectKeyIdentifier == null) {
+ return null;
+ }
+ byte[] res = new byte[subjectKeyIdentifier.length];
+ System.arraycopy(subjectKeyIdentifier, 0, res, 0, res.length);
+ return res;
+ }
+
+ /**
+ * Sets the criterion for the {@literal AuthorityKeyIdentifier} extension.
+ *
+ * @param authorityKeyIdentifier
+ * the authority key identifier, or {@code null} to disable this
+ * check.
+ */
+ public void setAuthorityKeyIdentifier(byte[] authorityKeyIdentifier) {
+ if (authorityKeyIdentifier == null) {
+ this.authorityKeyIdentifier = null;
+ return;
+ }
+ this.authorityKeyIdentifier = new byte[authorityKeyIdentifier.length];
+ System.arraycopy(authorityKeyIdentifier, 0,
+ this.authorityKeyIdentifier, 0,
+ authorityKeyIdentifier.length);
+ }
+
+ /**
+ * Returns the criterion for the {@literal AuthorityKeyIdentifier}
+ * extension.
+ *
+ * @return the authority key identifier, or {@code null} if it is not to be
+ * checked.
+ */
+ public byte[] getAuthorityKeyIdentifier() {
+ if (authorityKeyIdentifier == null) {
+ return null;
+ }
+ byte[] res = new byte[authorityKeyIdentifier.length];
+ System.arraycopy(authorityKeyIdentifier, 0, res, 0, res.length);
+ return res;
+ }
+
+ /**
+ * Sets the criterion for the validity date of the certificate.
+ * <p>
+ * The certificate must be valid at the specified date.
+ * @param certificateValid
+ * the validity date or {@code null} to not check the date.
+ */
+ public void setCertificateValid(Date certificateValid) {
+ this.certificateValid = (certificateValid == null)
+ ? null
+ : (Date) certificateValid.clone();
+ }
+
+ /**
+ * Returns the criterion for the validity date of the certificate.
+ *
+ * @return the validity date or {@code null} if the date is not to be
+ * checked.
+ */
+ public Date getCertificateValid() {
+ return (certificateValid == null)
+ ? null
+ : (Date) certificateValid.clone();
+ }
+
+ /**
+ * Sets the criterion for the validity date of the private key.
+ * <p>
+ * The private key must be valid at the specified date.
+ *
+ * @param privateKeyValid
+ * the validity date or {@code null} to not check the date.
+ */
+ public void setPrivateKeyValid(Date privateKeyValid) {
+ if (privateKeyValid == null) {
+ this.privateKeyValid = null;
+ return;
+ }
+ this.privateKeyValid = (Date) privateKeyValid.clone();
+ }
+
+ /**
+ * Returns the criterion for the validity date of the private key.
+ * <p>
+ * The private key must be valid at the specified date.
+ *
+ * @return the validity date or {@code null} if the date is not to be
+ * checked.
+ */
+ public Date getPrivateKeyValid() {
+ if (privateKeyValid != null) {
+ return (Date) privateKeyValid.clone();
+ }
+ return null;
+ }
+
+ private void checkOID(String oid) throws IOException {
+ int beg = 0;
+ int end = oid.indexOf('.', beg);
+ try {
+ int comp = Integer.parseInt(oid.substring(beg, end));
+ beg = end + 1;
+ if ((comp < 0) || (comp > 2)) {
+ throw new IOException(Messages.getString("security.56", oid)); //$NON-NLS-1$
+ }
+ end = oid.indexOf('.', beg);
+ comp = Integer.parseInt(oid.substring(beg, end));
+ if ((comp < 0) || (comp > 39)) {
+ throw new IOException(Messages.getString("security.56", oid)); //$NON-NLS-1$
+ }
+ } catch (IndexOutOfBoundsException e) {
+ throw new IOException(Messages.getString("security.56", oid)); //$NON-NLS-1$
+ } catch (NumberFormatException e) {
+ throw new IOException(Messages.getString("security.56", oid)); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Sets the criterion for the subject public key signature algorithm.
+ * <p>
+ * The certificate must contain a subject public key with the algorithm
+ * specified.
+ *
+ * @param oid
+ * the OID (object identifier) of the signature algorithm or
+ * {@code null} to not check the OID.
+ * @throws IOException
+ * if the specified object identifier is invalid.
+ */
+ public void setSubjectPublicKeyAlgID(String oid) throws IOException {
+ if (oid == null) {
+ subjectPublicKeyAlgID = null;
+ return;
+ }
+ checkOID(oid);
+ subjectPublicKeyAlgID = oid;
+ }
+
+ /**
+ * Returns the criterion for the subject public key signature algorithm.
+ *
+ * @return the OID (object identifier) or the signature algorithm or {@code
+ * null} if it's not to be checked.
+ */
+ public String getSubjectPublicKeyAlgID() {
+ return subjectPublicKeyAlgID;
+ }
+
+ /**
+ * Sets the criterion for the subject public key.
+ *
+ * @param key
+ * the subject public key or {@code null} to not check the key.
+ */
+ public void setSubjectPublicKey(PublicKey key) {
+ subjectPublicKey = (key == null) ? null : key.getEncoded();
+ subjectPublicKeyImpl = key;
+ }
+
+ /**
+ * Sets the criterion for the subject public key.
+ *
+ * @param key
+ * the subject public key in ASN.1 DER encoded format or {@code null} to
+ * not check the key.
+ * @throws IOException
+ * if decoding the the public key fails.
+ */
+ public void setSubjectPublicKey(byte[] key) throws IOException {
+ if (key == null) {
+ subjectPublicKey = null;
+ subjectPublicKeyImpl = null;
+ return;
+ }
+ subjectPublicKey = new byte[key.length];
+ System.arraycopy(key, 0, subjectPublicKey, 0, key.length);
+ subjectPublicKeyImpl =
+ ((SubjectPublicKeyInfo) SubjectPublicKeyInfo.ASN1.decode(key))
+ .getPublicKey();
+ }
+
+ /**
+ * Returns the criterion for the subject public key.
+ *
+ * @return the subject public key or {@code null} if the key is not to be
+ * checked.
+ */
+ public PublicKey getSubjectPublicKey() {
+ return subjectPublicKeyImpl;
+ }
+
+ /**
+ * Sets the criterion for the {@literal KeyUsage} extension.
+ *
+ * @param keyUsage
+ * the boolean array in the format as returned by
+ * {@link X509Certificate#getKeyUsage()}, or {@code null} to not
+ * check the key usage.
+ */
+ public void setKeyUsage(boolean[] keyUsage) {
+ if (keyUsage == null) {
+ this.keyUsage = null;
+ return;
+ }
+ this.keyUsage = new boolean[keyUsage.length];
+ System.arraycopy(keyUsage, 0, this.keyUsage, 0, keyUsage.length);
+ }
+
+ /**
+ * Returns the criterion for the {@literal KeyUsage} extension.
+ *
+ * @return the boolean array in the format as returned by
+ * {@link X509Certificate#getKeyUsage()}, or {@code null} if the key
+ * usage is not to be checked.
+ */
+ public boolean[] getKeyUsage() {
+ if (keyUsage == null) {
+ return null;
+ }
+ boolean[] result = new boolean[keyUsage.length];
+ System.arraycopy(keyUsage, 0, result, 0, keyUsage.length);
+ return result;
+ }
+
+ /**
+ * Sets the criterion for the {@literal ExtendedKeyUsage} extension.
+ *
+ * @param keyUsage
+ * the set of key usage OIDs, or {@code null} to not check it.
+ * @throws IOException
+ * if one of the OIDs is invalid.
+ */
+ public void setExtendedKeyUsage(Set<String> keyUsage)
+ throws IOException {
+ extendedKeyUsage = null;
+ if ((keyUsage == null) || (keyUsage.size() == 0)) {
+ return;
+ }
+ HashSet key_u = new HashSet();
+ Iterator it = keyUsage.iterator();
+ while (it.hasNext()) {
+ String usage = (String) it.next();
+ checkOID(usage);
+ key_u.add(usage);
+ }
+ extendedKeyUsage = Collections.unmodifiableSet(key_u);
+ }
+
+ /**
+ * Returns the criterion for the {@literal ExtendedKeyUsage} extension.
+ *
+ * @return the set of key usage OIDs, or {@code null} if it's not to be
+ * checked.
+ */
+ public Set<String> getExtendedKeyUsage() {
+ return extendedKeyUsage;
+ }
+
+ /**
+ * Sets the flag for the matching behavior for subject alternative names.
+ * <p>
+ * The flag indicates whether a certificate must contain all or at least one
+ * of the subject alternative names specified by {@link
+ * #setSubjectAlternativeNames} or {@link #addSubjectAlternativeName}.
+ *
+ * @param matchAllNames
+ * {@code true} if a certificate must contain all of the
+ * specified subject alternative names, otherwise {@code false}.
+ */
+ public void setMatchAllSubjectAltNames(boolean matchAllNames) {
+ this.matchAllNames = matchAllNames;
+ }
+
+ /**
+ * Returns the flag for the matching behavior for subject alternative names.
+ * <p>
+ * The flag indicates whether a certificate must contain all or at least one
+ * of the subject alternative names specified by {@link
+ * #setSubjectAlternativeNames} or {@link #addSubjectAlternativeName}.
+ *
+ * @return {@code true} if a certificate must contain all of the specified
+ * subject alternative names, otherwise {@code false}.
+ */
+ public boolean getMatchAllSubjectAltNames() {
+ return matchAllNames;
+ }
+
+ /**
+ * Sets the criterion for subject alternative names.
+ * <p>
+ * the certificate must contain all or at least one of the specified subject
+ * alternative names. The behavior is specified by
+ * {@link #getMatchAllSubjectAltNames}.
+ * <p>
+ * The specified parameter {@code names} is a collection with an entry for
+ * each name to be included in the criterion. The name is specified as a
+ * {@code List}, the first entry must be an {@code Integer} specifying the
+ * name type (0-8), the second entry must be a {@code String} or a byte
+ * array specifying the name (in string or ASN.1 DER encoded form)
+ *
+ * @param names
+ * the names collection or {@code null} to not perform this check.
+ * @throws IOException
+ * if the decoding of a name fails.
+ */
+ public void setSubjectAlternativeNames(Collection<List<?>> names)
+ throws IOException {
+ subjectAltNames = null;
+ if ((names == null) || (names.size() == 0)) {
+ return;
+ }
+ Iterator it = names.iterator();
+ while (it.hasNext()) {
+ List name = (List) it.next();
+ int tag = ((Integer) name.get(0)).intValue();
+ Object value = name.get(1);
+ if (value instanceof String) {
+ addSubjectAlternativeName(tag, (String) value);
+ } else if (value instanceof byte[]) {
+ addSubjectAlternativeName(tag, (byte[]) value);
+ } else {
+ throw new IOException(Messages.getString("security.57")); //$NON-NLS-1$
+ }
+ }
+ }
+
+ /**
+ * Adds a subject alternative name to the respective criterion.
+ *
+ * @param tag
+ * the type of the name
+ * @param name
+ * the name in string format.
+ * @throws IOException
+ * if parsing the name fails.
+ */
+ public void addSubjectAlternativeName(int tag, String name)
+ throws IOException {
+ GeneralName alt_name = new GeneralName(tag, name);
+ // create only if there was not any errors
+ if (subjectAltNames == null) {
+ subjectAltNames = new ArrayList[9];
+ }
+ if (subjectAltNames[tag] == null) {
+ subjectAltNames[tag] = new ArrayList();
+ }
+ subjectAltNames[tag].add(alt_name);
+ }
+
+ /**
+ * Adds a subject alternative name to the respective criterion.
+ *
+ * @param tag
+ * the type of the name.
+ * @param name
+ * the name in ASN.1 DER encoded form.
+ * @throws IOException
+ * if the decoding of the name fails.
+ */
+ public void addSubjectAlternativeName(int tag, byte[] name)
+ throws IOException {
+ GeneralName alt_name = new GeneralName(tag, name);
+ // create only if there was not any errors
+ if (subjectAltNames == null) {
+ subjectAltNames = new ArrayList[9];
+ }
+ if (subjectAltNames[tag] == null) {
+ subjectAltNames[tag] = new ArrayList();
+ }
+ subjectAltNames[tag].add(alt_name);
+ }
+
+ /**
+ * Returns the criterion for subject alternative names.
+ * <p>
+ * the certificate must contain all or at least one of the specified subject
+ * alternative names. The behavior is specified by
+ * {@link #getMatchAllSubjectAltNames}.
+ * <p>
+ * The subject alternative names is a collection with an entry for each name
+ * included in the criterion. The name is specified as a {@code List}, the
+ * first entry is an {@code Integer} specifying the name type (0-8), the
+ * second entry is byte array specifying the name in ASN.1 DER encoded form)
+ *
+ * @return the names collection or {@code null} if none specified.
+ */
+ public Collection<List<?>> getSubjectAlternativeNames() {
+ if (subjectAltNames == null) {
+ return null;
+ }
+ ArrayList result = new ArrayList();
+ for (int tag=0; tag<9; tag++) {
+ if (subjectAltNames[tag] != null) {
+ for (int name=0; name<subjectAltNames[tag].size(); name++) {
+ Object neim = subjectAltNames[tag].get(name);
+ if (neim instanceof byte[]) {
+ byte[] arr_neim = (byte[]) neim;
+ neim = new byte[arr_neim.length];
+ System.arraycopy(arr_neim, 0, neim, 0, arr_neim.length);
+ }
+ List list = new ArrayList(2);
+ list.add(Integer.valueOf(tag)); // android-changed
+ list.add(neim);
+ result.add(list);
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Sets the criterion for the name constraints.
+ * <p>
+ * The certificate must constraint subject and subject alternative names
+ * that match the specified name constraints.
+ * <p>
+ * The name constraints in ASN.1:
+ *
+ * <pre>
+ * NameConstraints ::= SEQUENCE {
+ * permittedSubtrees [0] GeneralSubtrees OPTIONAL,
+ * excludedSubtrees [1] GeneralSubtrees OPTIONAL }
+ *
+ * GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
+ *
+ * GeneralSubtree ::= SEQUENCE {
+ * base GeneralName,
+ * minimum [0] BaseDistance DEFAULT 0,
+ * maximum [1] BaseDistance OPTIONAL }
+ *
+ * BaseDistance ::= INTEGER (0..MAX)
+ *
+ * GeneralName ::= CHOICE {
+ * otherName [0] OtherName,
+ * rfc822Name [1] IA5String,
+ * dNSName [2] IA5String,
+ * x400Address [3] ORAddress,
+ * directoryName [4] Name,
+ * ediPartyName [5] EDIPartyName,
+ * uniformResourceIdentifier [6] IA5String,
+ * iPAddress [7] OCTET STRING,
+ * registeredID [8] OBJECT IDENTIFIER}
+ *
+ * </pre>
+ *
+ * @param bytes
+ * the name constraints in ASN.1 DER encoded format, or null to
+ * not check any constraints.
+ * @throws IOException
+ * if decoding the name constraints fail.
+ */
+ public void setNameConstraints(byte[] bytes) throws IOException {
+ this.nameConstraints = (bytes == null)
+ ? null
+ : (NameConstraints) NameConstraints.ASN1.decode(bytes);
+ }
+
+ /**
+ * Returns the criterion for the name constraints.
+ *
+ * @return the name constraints or {@code null} if none specified.
+ * @see #setNameConstraints
+ */
+ public byte[] getNameConstraints() {
+ return (nameConstraints == null)
+ ? null
+ : nameConstraints.getEncoded();
+ }
+
+ /**
+ * Sets the criterion for the basic constraints extension.
+ * <p>
+ * A value greater than or equal to zero indicates that a certificate must
+ * include a basic constraints extension with a path length of a least that
+ * value. A value of {@code -2} indicates that only end-entity certificates
+ * are accepted. A value of {@code -1} indicates that no check is done.
+ *
+ * @param pathLen
+ * the value specifying the criterion.
+ * @throws IllegalArgumentException
+ * if {@code pathLen} is less than {@code -2}.
+ */
+ public void setBasicConstraints(int pathLen) {
+ if (pathLen < -2) {
+ throw new IllegalArgumentException(Messages.getString("security.58")); //$NON-NLS-1$
+ }
+ this.pathLen = pathLen;
+ }
+
+ /**
+ * Returns the criterion for the basic constraints extension.
+ * <p>
+ * A value greater than or equal to zero indicates that a certificate must
+ * include a basic constraints extension with a path length of a least that
+ * value. A value of {@code -2} indicates that only end-entity certificates
+ * are accepted. A value of {@code -1} indicates that no check is done.
+ *
+ * @return the value of the criterion.
+ */
+ public int getBasicConstraints() {
+ return pathLen;
+ }
+
+ /**
+ * Sets the criterion for the policy constraint.
+ * <p>
+ * The certificate must have at least one of the specified certificate
+ * policy extensions. For an empty set the certificate must have at least
+ * some policies in its policy extension.
+ *
+ * @param policies
+ * the certificate policy OIDs, an empty set, or {@code null} to
+ * not perform this check.
+ * @throws IOException
+ * if parsing the specified OIDs fails.
+ */
+ public void setPolicy(Set<String> policies) throws IOException {
+ if (policies == null) {
+ this.policies = null;
+ return;
+ }
+ HashSet pols = new HashSet(policies.size());
+ Iterator it = policies.iterator();
+ while (it.hasNext()) {
+ String certPolicyId = (String) it.next();
+ checkOID(certPolicyId);
+ pols.add(certPolicyId);
+ }
+ this.policies = Collections.unmodifiableSet(pols);
+ }
+
+ /**
+ * Returns the criterion for the policy constraint.
+ * <p>
+ * The certificate must have at least one of the certificate policy
+ * extensions. For an empty set the certificate must have at least some
+ * policies in its policy extension.
+ *
+ * @return the certificate policy OIDs, an empty set, or {@code null} if not
+ * to be checked.
+ */
+ public Set<String> getPolicy() {
+ return policies;
+ }
+
+ /**
+ * Sets the criterion for the pathToNames constraint.
+ * <p>
+ * This allows to specify the complete set of names, a certificate's name
+ * constraints must permit.
+ * <p>
+ * The specified parameter {@code names} is a collection with an entry for
+ * each name to be included in the criterion. The name is specified as a
+ * {@code List}, the first entry must be an {@code Integer} specifying the
+ * name type (0-8), the second entry must be a {@code String} or a byte
+ * array specifying the name (in string or ASN.1 DER encoded form)
+ *
+ * @param names
+ * the names collection or {@code null} to not perform this
+ * check.
+ * @throws IOException
+ * if decoding fails.
+ */
+ public void setPathToNames(Collection<List<?>> names)
+ throws IOException {
+ pathToNames = null;
+ if ((names == null) || (names.size() == 0)) {
+ return;
+ }
+ Iterator it = names.iterator();
+ while (it.hasNext()) {
+ List name = (List) it.next();
+ int tag = ((Integer) name.get(0)).intValue();
+ Object value = name.get(1);
+ if (value instanceof String) {
+ addPathToName(tag, (String) value);
+ } else if (value instanceof byte[]) {
+ addPathToName(tag, (byte[]) value);
+ } else {
+ throw new IOException(Messages.getString("security.57")); //$NON-NLS-1$
+ }
+ }
+ }
+
+ /**
+ * Adds a {@literal "pathToName"} to the respective criterion.
+ *
+ * @param type
+ * the type of the name.
+ * @param name
+ * the name in string format.
+ * @throws IOException
+ * if parsing fails.
+ * @see #setPathToNames
+ */
+ public void addPathToName(int type, String name) throws IOException {
+ GeneralName path_name = new GeneralName(type, name);
+ // create only if there was not any errors
+ if (pathToNames == null) {
+ pathToNames = new ArrayList();
+ }
+ pathToNames.add(path_name);
+ }
+
+ /**
+ * Adds a {@literal "pathToName"} to the respective criterion.
+ *
+ * @param type
+ * the type of the name
+ * @param name
+ * the name in ASN.1 DER encoded form.
+ * @throws IOException
+ * if decoding fails.
+ * @see #setPathToNames
+ */
+ public void addPathToName(int type, byte[] name) throws IOException {
+ GeneralName path_name= new GeneralName(type, name);
+ // create only if there was not any errors
+ if (pathToNames == null) {
+ pathToNames = new ArrayList();
+ }
+ pathToNames.add(path_name);
+ }
+
+ /**
+ * Returns the criterion for the pathToNames constraint.
+ * <p>
+ * The constraint is a collection with an entry for each name to be included
+ * in the criterion. The name is specified as a {@code List}, the first
+ * entry is an {@code Integer} specifying the name type (0-8), the second
+ * entry is a byte array specifying the name in ASN.1 DER encoded form.
+ *
+ * @return the pathToNames constraint or {@code null} if none specified.
+ */
+ public Collection<List<?>> getPathToNames() {
+ if (pathToNames == null) {
+ return null;
+ }
+ ArrayList result = new ArrayList();
+ Iterator it = pathToNames.iterator();
+ while (it.hasNext()) {
+ GeneralName name = (GeneralName) it.next();
+ result.add(name.getAsList());
+ }
+ return result;
+ }
+
+ /**
+ * Returns a string representation of this {@code X509CertSelector}
+ * instance.
+ *
+ * @return a string representation of this {@code X509CertSelector}
+ * instance.
+ */
+ public String toString() {
+ // For convenient reading of the string representation
+ // all of the fields named according to the rfc 3280
+ // (http://www.ietf.org/rfc/rfc3280.txt).
+
+ StringBuilder result = new StringBuilder();
+ result.append("X509CertSelector: \n["); //$NON-NLS-1$
+ if (this.certificateEquals != null) {
+ result.append("\n certificateEquals: " + certificateEquals); //$NON-NLS-1$
+ }
+ if (this.serialNumber != null) {
+ //FIXME: needs DRL's BigInteger.toString implementation
+ //result.append("\n serialNumber: " + serialNumber);
+ }
+ if (this.issuer != null) {
+ result.append("\n issuer: " + issuer); //$NON-NLS-1$
+ }
+ if (this.subject != null) {
+ result.append("\n subject: " + subject); //$NON-NLS-1$
+ }
+ if (this.subjectKeyIdentifier != null) {
+ result.append("\n subjectKeyIdentifier: " //$NON-NLS-1$
+ + getBytesAsString(subjectKeyIdentifier));
+ }
+ if (this.authorityKeyIdentifier != null) {
+ result.append("\n authorityKeyIdentifier: " //$NON-NLS-1$
+ + getBytesAsString(authorityKeyIdentifier));
+ }
+ if (this.certificateValid != null) {
+ result.append("\n certificateValid: " + certificateValid); //$NON-NLS-1$
+ }
+ if (this.subjectPublicKeyAlgID != null) {
+ result.append("\n subjectPublicKeyAlgID: " //$NON-NLS-1$
+ + subjectPublicKeyAlgID);
+ }
+ if (this.privateKeyValid != null) {
+ result.append("\n privateKeyValid: " + privateKeyValid); //$NON-NLS-1$
+ }
+ if (this.subjectPublicKey != null) {
+ result.append("\n subjectPublicKey: " //$NON-NLS-1$
+ + getBytesAsString(subjectPublicKey));
+ }
+ if (this.keyUsage != null) {
+ result.append("\n keyUsage: \n ["); //$NON-NLS-1$
+ String[] kuNames = new String[] {
+ "digitalSignature", "nonRepudiation", "keyEncipherment", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ "dataEncipherment", "keyAgreement", "keyCertSign", "cRLSign", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ "encipherOnly", "decipherOnly" //$NON-NLS-1$ //$NON-NLS-2$
+ };
+ for (int i=0; i<9; i++) {
+ if (keyUsage[i]) {
+ result.append("\n " + kuNames[i]); //$NON-NLS-1$
+ }
+ }
+ result.append("\n ]"); //$NON-NLS-1$
+ }
+ if (this.extendedKeyUsage != null) {
+ result.append("\n extendedKeyUsage: " //$NON-NLS-1$
+ + extendedKeyUsage.toString());
+ }
+ result.append("\n matchAllNames: " + matchAllNames); //$NON-NLS-1$
+ result.append("\n pathLen: " + pathLen); //$NON-NLS-1$
+ if (this.subjectAltNames != null) {
+ result.append("\n subjectAltNames: \n ["); //$NON-NLS-1$
+ for (int i=0; i<9; i++) {
+ List names = this.subjectAltNames[i];
+ if (names != null) {
+ int size = names.size();
+ for (int j=0; j<size; j++) {
+ result.append("\n " //$NON-NLS-1$
+ + ((GeneralName)names.get(j)).toString());
+ }
+ }
+ }
+ result.append("\n ]"); //$NON-NLS-1$
+ }
+ if (this.nameConstraints != null) {
+ }
+ if (this.policies != null) {
+ result.append("\n policies: " + policies.toString()); //$NON-NLS-1$
+ }
+ if (this.pathToNames != null) {
+ result.append("\n pathToNames: \n ["); //$NON-NLS-1$
+ int size = pathToNames.size();
+ for (int i = 0; i < size; i++) {
+ result.append("\n " //$NON-NLS-1$
+ + ((GeneralName)pathToNames.get(i)).toString());
+ }
+ }
+ result.append("\n]"); //$NON-NLS-1$
+ return result.toString();
+ }
+
+ private String getBytesAsString(byte[] data) {
+ String result = ""; //$NON-NLS-1$
+ for (int i=0; i<data.length; i++) {
+ String tail = Integer.toHexString(0x00ff & data[i]);
+ if (tail.length() == 1) {
+ tail = "0" + tail; //$NON-NLS-1$
+ }
+ result += tail + " "; //$NON-NLS-1$
+ }
+ return result;
+ }
+
+ private byte[] getExtensionValue(X509Certificate cert, String oid) {
+ try {
+ byte[] bytes = cert.getExtensionValue(oid);
+ if (bytes == null) {
+ return null;
+ }
+ return (byte[]) ASN1OctetString.getInstance().decode(bytes);
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Returns whether the specified certificate matches all the criteria
+ * collected in this instance.
+ *
+ * @param certificate
+ * the certificate to check.
+ * @return {@code true} if the certificate matches all the criteria,
+ * otherwise {@code false}.
+ */
+ public boolean match(Certificate certificate) {
+ if (! (certificate instanceof X509Certificate)) {
+ return false;
+ }
+
+ X509Certificate cert = (X509Certificate) certificate;
+ if ((certificateEquals != null) &&
+ !certificateEquals.equals(cert)) {
+ return false;
+ }
+ if ((serialNumber != null) &&
+ !serialNumber.equals(cert.getSerialNumber())) {
+ return false;
+ }
+ if ((issuer != null) &&
+ !issuer.equals(cert.getIssuerX500Principal())) {
+ return false;
+ }
+ if ((subject != null) &&
+ !subject.equals(cert.getSubjectX500Principal())) {
+ return false;
+ }
+ if ((subjectKeyIdentifier != null) &&
+ !Arrays.equals(subjectKeyIdentifier,
+ // Here and later all of the extension OIDs
+ // are taken from rfc 3280 (http://www.ietf.org/rfc/rfc3280.txt)
+ getExtensionValue(cert, "2.5.29.14"))) { //$NON-NLS-1$
+ return false;
+ }
+ if ((authorityKeyIdentifier != null) &&
+ !Arrays.equals(authorityKeyIdentifier,
+ getExtensionValue(cert, "2.5.29.35"))) { //$NON-NLS-1$
+ return false;
+ }
+ if (certificateValid != null) {
+ try {
+ cert.checkValidity(certificateValid);
+ } catch(CertificateExpiredException e) {
+ return false;
+ } catch(CertificateNotYetValidException e) {
+ return false;
+ }
+ }
+ if (privateKeyValid != null) {
+ try {
+ byte[] bytes = getExtensionValue(cert, "2.5.29.16"); //$NON-NLS-1$
+ if (bytes == null) {
+ return false;
+ }
+ PrivateKeyUsagePeriod pkup = (PrivateKeyUsagePeriod)
+ PrivateKeyUsagePeriod.ASN1.decode(bytes);
+ Date notBefore = pkup.getNotBefore();
+ Date notAfter = pkup.getNotAfter();
+ if ((notBefore == null) && (notAfter == null)) {
+ return false;
+ }
+ if ((notBefore != null)
+ && notBefore.compareTo(privateKeyValid) > 0) {
+ return false;
+ }
+ if ((notAfter != null)
+ && notAfter.compareTo(privateKeyValid) < 0) {
+ return false;
+ }
+ } catch (IOException e) {
+ return false;
+ }
+ }
+ if (subjectPublicKeyAlgID != null) {
+ try {
+ byte[] encoding = cert.getPublicKey().getEncoded();
+ AlgorithmIdentifier ai = ((SubjectPublicKeyInfo)
+ SubjectPublicKeyInfo.ASN1.decode(encoding))
+ .getAlgorithmIdentifier();
+ if (!subjectPublicKeyAlgID.equals(ai.getAlgorithm())) {
+ return false;
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+ if (subjectPublicKey != null) {
+ if (!Arrays.equals(subjectPublicKey,
+ cert.getPublicKey().getEncoded())) {
+ return false;
+ }
+ }
+ if (keyUsage != null) {
+ boolean[] ku = cert.getKeyUsage();
+ if (ku != null) {
+ int i = 0;
+ int min_length = (ku.length < keyUsage.length) ? ku.length
+ : keyUsage.length;
+ for (; i < min_length; i++) {
+ if (keyUsage[i] && !ku[i]) {
+ // the specified keyUsage allows,
+ // but certificate does not.
+ return false;
+ }
+ }
+ for (; i<keyUsage.length; i++) {
+ if (keyUsage[i]) {
+ return false;
+ }
+ }
+ }
+ }
+ if (extendedKeyUsage != null) {
+ try {
+ List keyUsage = cert.getExtendedKeyUsage();
+ if (keyUsage != null) {
+ if (!keyUsage.containsAll(extendedKeyUsage)) {
+ return false;
+ }
+ }
+ } catch (CertificateParsingException e) {
+ return false;
+ }
+ }
+ if (pathLen != -1) {
+ int p_len = cert.getBasicConstraints();
+ if ((pathLen < 0) && (p_len >= 0)) {
+ // need end-entity but got CA
+ return false;
+ }
+ if ((pathLen > 0) && (pathLen > p_len)) {
+ // allowed _pathLen is small
+ return false;
+ }
+ }
+ if (subjectAltNames != null) {
+ PASSED:
+ try {
+ byte[] bytes = getExtensionValue(cert, "2.5.29.17"); //$NON-NLS-1$
+ if (bytes == null) {
+ return false;
+ }
+ List sans = ((GeneralNames) GeneralNames.ASN1.decode(bytes))
+ .getNames();
+ if ((sans == null) || (sans.size() == 0)) {
+ return false;
+ }
+ boolean[][] map = new boolean[9][];
+ // initialize the check map
+ for (int i=0; i<9; i++) {
+ map[i] = (subjectAltNames[i] == null)
+ ? new boolean[0]
+ : new boolean[subjectAltNames[i].size()];
+ }
+ Iterator it = sans.iterator();
+ while (it.hasNext()) {
+ GeneralName name = (GeneralName) it.next();
+ int tag = name.getTag();
+ for (int i=0; i<map[tag].length; i++) {
+ if (((GeneralName) subjectAltNames[tag].get(i))
+ .equals(name)) {
+ if (!matchAllNames) {
+ break PASSED;
+ }
+ map[tag][i] = true;
+ }
+ }
+ }
+ if (!matchAllNames) {
+ // there was not any match
+ return false;
+ }
+ // else check the map
+ for (int tag=0; tag<9; tag++) {
+ for (int name=0; name<map[tag].length; name++) {
+ if (!map[tag][name]) {
+ return false;
+ }
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+ if (nameConstraints != null) {
+ if (!nameConstraints.isAcceptable(cert)) {
+ return false;
+ }
+ }
+ if (policies != null) {
+ byte[] bytes = getExtensionValue(cert, "2.5.29.32"); //$NON-NLS-1$
+ if (bytes == null) {
+ return false;
+ }
+ if (policies.size() == 0) {
+ // if certificate has such extension than it has at least
+ // one policy in it.
+ return true;
+ }
+ PASSED:
+ try {
+ List policyInformations = ((CertificatePolicies)
+ CertificatePolicies.ASN1.decode(bytes))
+ .getPolicyInformations();
+ Iterator it = policyInformations.iterator();
+ while (it.hasNext()) {
+ if (policies.contains(((PolicyInformation) it.next())
+ .getPolicyIdentifier())) {
+ break PASSED;
+ }
+ }
+ return false;
+ } catch (IOException e) {
+ // the extension is invalid
+ return false;
+ }
+ }
+ if (pathToNames != null) {
+ byte[] bytes = getExtensionValue(cert, "2.5.29.30"); //$NON-NLS-1$
+ if (bytes != null) {
+ NameConstraints nameConstraints;
+ try {
+ nameConstraints =
+ (NameConstraints) NameConstraints.ASN1.decode(bytes);
+ } catch (IOException e) {
+ // the extension is invalid;
+ return false;
+ }
+ if (!nameConstraints.isAcceptable(pathToNames)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Clones this {@code X509CertSelector} instance.
+ *
+ * @return the cloned instance.
+ */
+ public Object clone() {
+ X509CertSelector result;
+
+ try {
+ result = (X509CertSelector) super.clone();
+ } catch (CloneNotSupportedException e) {
+ return null;
+ }
+
+ if (this.subjectKeyIdentifier != null) {
+ result.subjectKeyIdentifier =
+ new byte[this.subjectKeyIdentifier.length];
+ System.arraycopy(this.subjectKeyIdentifier, 0,
+ result.subjectKeyIdentifier, 0,
+ this.subjectKeyIdentifier.length);
+ }
+ if (this.authorityKeyIdentifier != null) {
+ result.authorityKeyIdentifier =
+ new byte[this.authorityKeyIdentifier.length];
+ System.arraycopy(this.authorityKeyIdentifier, 0,
+ result.authorityKeyIdentifier, 0,
+ this.authorityKeyIdentifier.length);
+ }
+ if (this.subjectPublicKey != null) {
+ result.subjectPublicKey = new byte[this.subjectPublicKey.length];
+ System.arraycopy(this.subjectPublicKey, 0, result.subjectPublicKey,
+ 0, this.subjectPublicKey.length);
+ }
+ if (this.keyUsage != null) {
+ result.keyUsage = new boolean[this.keyUsage.length];
+ System.arraycopy(this.keyUsage, 0, result.keyUsage, 0,
+ this.keyUsage.length);
+ }
+ result.extendedKeyUsage = (this.extendedKeyUsage == null)
+ ? null
+ : new HashSet(this.extendedKeyUsage);
+ if (this.subjectAltNames != null) {
+ result.subjectAltNames = new ArrayList[9];
+ for (int i=0; i<9; i++) {
+ if (this.subjectAltNames[i] != null) {
+ result.subjectAltNames[i] =
+ new ArrayList(this.subjectAltNames[i]);
+ }
+ }
+ }
+ result.policies = (this.policies == null)
+ ? null
+ : new HashSet(this.policies);
+ result.pathToNames = (this.pathToNames == null)
+ ? null
+ : new ArrayList(this.pathToNames);
+ return result;
+ }
+}
diff --git a/luni/src/main/java/java/security/cert/X509Certificate.java b/luni/src/main/java/java/security/cert/X509Certificate.java
new file mode 100644
index 0000000..e49901c
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/X509Certificate.java
@@ -0,0 +1,445 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.ByteArrayInputStream;
+import java.math.BigInteger;
+import java.security.Principal;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * Abstract base class for X.509 certificates.
+ * <p>
+ * This represents a standard way for accessing the attributes of X.509
+ * certificates.
+ * <p>
+ * The basic X.509 v3 format described in ASN.1:
+ *
+ * <pre>
+ * Certificate ::= SEQUENCE {
+ * tbsCertificate TBSCertificate,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING }
+ *
+ * TBSCertificate ::= SEQUENCE {
+ * version [0] EXPLICIT Version DEFAULT v1,
+ * serialNumber CertificateSerialNumber,
+ * signature AlgorithmIdentifier,
+ * issuer Name,
+ * validity Validity,
+ * subject Name,
+ * subjectPublicKeyInfo SubjectPublicKeyInfo,
+ * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
+ * -- If present, version must be v2 or v3
+ * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
+ * -- If present, version must be v2 or v3
+ * extensions [3] EXPLICIT Extensions OPTIONAL
+ * -- If present, version must be v3
+ * }
+ * </pre>
+ * <p>
+ * For more information consult RFC 2459
+ * "Internet X.509 Public Key Infrastructure Certificate and CRL Profile" at <a
+ * href
+ * ="http://www.ietf.org/rfc/rfc2459.txt">http://www.ietf.org/rfc/rfc2459.txt
+ * </a> .
+ */
+public abstract class X509Certificate
+ extends Certificate implements X509Extension {
+
+ private static final long serialVersionUID = -2491127588187038216L;
+
+ /**
+ * Creates a new {@code X509Certificate}.
+ */
+ protected X509Certificate() {
+ super("X.509"); //$NON-NLS-1$
+ }
+
+ /**
+ * Checks whether the certificate is currently valid.
+ * <p>
+ * The validity defined in ASN.1:
+ *
+ * <pre>
+ * validity Validity
+ *
+ * Validity ::= SEQUENCE {
+ * notBefore CertificateValidityDate,
+ * notAfter CertificateValidityDate }
+ *
+ * CertificateValidityDate ::= CHOICE {
+ * utcTime UTCTime,
+ * generalTime GeneralizedTime }
+ * </pre>
+ *
+ * @throws CertificateExpiredException
+ * if the certificate has expired.
+ * @throws CertificateNotYetValidException
+ * if the certificate is not yet valid.
+ */
+ public abstract void checkValidity()
+ throws CertificateExpiredException, CertificateNotYetValidException;
+
+ /**
+ * Checks whether the certificate is valid at the specified date.
+ *
+ * @param date
+ * the date to check the validity against.
+ * @throws CertificateExpiredException
+ * if the certificate has expired.
+ * @throws CertificateNotYetValidException
+ * if the certificate is not yet valid.
+ * @see #checkValidity()
+ */
+ public abstract void checkValidity(Date date)
+ throws CertificateExpiredException, CertificateNotYetValidException;
+
+ /**
+ * Returns the certificates {@code version} (version number).
+ * <p>
+ * The version defined is ASN.1:
+ *
+ * <pre>
+ * Version ::= INTEGER { v1(0), v2(1), v3(2) }
+ * </pre>
+ *
+ * @return the version number.
+ */
+ public abstract int getVersion();
+
+ /**
+ * Returns the {@code serialNumber} of the certificate.
+ * <p>
+ * The ASN.1 definition of {@code serialNumber}:
+ *
+ * <pre>
+ * CertificateSerialNumber ::= INTEGER
+ * </pre>
+ *
+ * @return the serial number.
+ */
+ public abstract BigInteger getSerialNumber();
+
+ /**
+ * Returns the {@code issuer} (issuer distinguished name) as an
+ * implementation specific {@code Principal} object.
+ * <p>
+ * The ASN.1 definition of {@code issuer}:
+ *
+ * <pre>
+ * issuer Name
+ *
+ * Name ::= CHOICE {
+ * RDNSequence }
+ *
+ * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+ *
+ * RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
+ *
+ * AttributeTypeAndValue ::= SEQUENCE {
+ * type AttributeType,
+ * value AttributeValue }
+ *
+ * AttributeType ::= OBJECT IDENTIFIER
+ *
+ * AttributeValue ::= ANY DEFINED BY AttributeType
+ * </pre>
+ *
+ * <b>replaced by:</b> {@link #getIssuerX500Principal()}.
+ *
+ * @return the {@code issuer} as an implementation specific {@code
+ * Principal}.
+ */
+ public abstract Principal getIssuerDN() ;
+
+ /**
+ * Returns the {@code issuer} (issuer distinguished name) as an {@code
+ * X500Principal}.
+ *
+ * @return the {@code issuer} (issuer distinguished name).
+ */
+ public X500Principal getIssuerX500Principal() {
+
+ try {
+ // TODO if there is no X.509 certificate provider installed
+ // should we try to access Harmony X509CertImpl via classForName?
+ CertificateFactory factory = CertificateFactory
+ .getInstance("X.509"); //$NON-NLS-1$
+
+ X509Certificate cert = (X509Certificate) factory
+ .generateCertificate(new ByteArrayInputStream(getEncoded()));
+
+ return cert.getIssuerX500Principal();
+
+ } catch (Exception e) {
+ throw new RuntimeException(Messages.getString("security.59"), e); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Returns the {@code subject} (subject distinguished name) as an
+ * implementation specific {@code Principal} object.
+ * <p>
+ * The ASN.1 definition of {@code subject}:
+ *
+ * <pre>
+ * subject Name
+ *
+ * Name ::= CHOICE {
+ * RDNSequence }
+ *
+ * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+ *
+ * RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
+ *
+ * AttributeTypeAndValue ::= SEQUENCE {
+ * type AttributeType,
+ * value AttributeValue }
+ *
+ * AttributeType ::= OBJECT IDENTIFIER
+ *
+ * AttributeValue ::= ANY DEFINED BY AttributeType
+ * </pre>
+ *
+ * <p>
+ * <b>replaced by:</b> {@link #getSubjectX500Principal()}.
+ *
+ * @return the {@code subject} (subject distinguished name).
+ */
+ public abstract Principal getSubjectDN();
+
+ /**
+ * Returns the {@code subject} (subject distinguished name) as an {@code
+ * X500Principal}.
+ *
+ * @return the {@code subject} (subject distinguished name)
+ */
+ public X500Principal getSubjectX500Principal() {
+
+ try {
+ // TODO if there is no X.509 certificate provider installed
+ // should we try to access Harmony X509CertImpl via classForName?
+ CertificateFactory factory = CertificateFactory
+ .getInstance("X.509"); //$NON-NLS-1$
+
+ X509Certificate cert = (X509Certificate) factory
+ .generateCertificate(new ByteArrayInputStream(getEncoded()));
+
+ return cert.getSubjectX500Principal();
+
+ } catch (Exception e) {
+ throw new RuntimeException(Messages.getString("security.5A"), e); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Returns the {@code notBefore} date from the validity period of the
+ * certificate.
+ *
+ * @return the start of the validity period.
+ */
+ public abstract Date getNotBefore();
+
+ /**
+ * Returns the {@code notAfter} date of the validity period of the
+ * certificate.
+ *
+ * @return the end of the validity period.
+ */
+ public abstract Date getNotAfter();
+
+ /**
+ * Returns the {@code tbsCertificate} information from this certificate in
+ * DER-encoded format.
+ *
+ * @return the DER-encoded certificate information.
+ * @throws CertificateEncodingException
+ * if an error occurs in encoding
+ */
+ public abstract byte[] getTBSCertificate()
+ throws CertificateEncodingException;
+
+ /**
+ * Returns the raw signature bits from the certificate.
+ *
+ * @return the raw signature bits from the certificate.
+ */
+ public abstract byte[] getSignature();
+
+ /**
+ * Returns the name of the algorithm for the certificate signature.
+ *
+ * @return the signature algorithm name.
+ */
+ public abstract String getSigAlgName();
+
+ /**
+ * Returns the OID of the signature algorithm from the certificate.
+ *
+ * @return the OID of the signature algorithm.
+ */
+ public abstract String getSigAlgOID();
+
+ /**
+ * Returns the parameters of the signature algorithm in DER-encoded format.
+ *
+ * @return the parameters of the signature algorithm, or {@code null} if
+ * none are used.
+ */
+ public abstract byte[] getSigAlgParams();
+
+ /**
+ * Returns the {@code issuerUniqueID} from the certificate.
+ *
+ * @return the {@code issuerUniqueID} or {@code null} if there's none in the
+ * certificate.
+ */
+ public abstract boolean[] getIssuerUniqueID();
+
+ /**
+ * Returns the {@code subjectUniqueID} from the certificate.
+ *
+ * @return the {@code subjectUniqueID} or null if there's none in the
+ * certificate.
+ */
+ public abstract boolean[] getSubjectUniqueID();
+
+ /**
+ * Returns the {@code KeyUsage} extension as a {@code boolean} array.
+ * <p>
+ * The ASN.1 definition of {@code KeyUsage}:
+ *
+ * <pre>
+ * KeyUsage ::= BIT STRING {
+ * digitalSignature (0),
+ * nonRepudiation (1),
+ * keyEncipherment (2),
+ * dataEncipherment (3),
+ * keyAgreement (4),
+ * keyCertSign (5),
+ * cRLSign (6),
+ * encipherOnly (7),
+ * decipherOnly (8) }
+ *
+ * </pre>
+ *
+ * @return the {@code KeyUsage} extension or {@code null} if there's none in
+ * the certificate.
+ */
+ public abstract boolean[] getKeyUsage();
+
+ /**
+ * Returns a read-only list of OID strings representing the {@code
+ * ExtKeyUsageSyntax} field of the extended key usage extension.
+ *
+ * @return the extended key usage extension, or {@code null} if there's none
+ * in the certificate.
+ * @throws CertificateParsingException
+ * if the extension decoding fails.
+ */
+ public List<String> getExtendedKeyUsage()
+ throws CertificateParsingException {
+ return null;
+ }
+
+ /**
+ * Returns the path length of the certificate constraints from the {@code
+ * BasicContraints} extension.
+ *
+ * @return the path length of the certificate constraints if the extension
+ * is present or {@code -1} if the extension is not present. {@code
+ * Integer.MAX_VALUE} if there's not limit.
+ */
+ public abstract int getBasicConstraints();
+
+ /**
+ * Returns a read-only list of the subject alternative names from the
+ * {@code SubjectAltName} extension.
+ * <p>
+ * The ASN.1 definition of {@code SubjectAltName}:
+ *
+ * <pre>
+ * SubjectAltName ::= GeneralNames
+ *
+ * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
+ *
+ * GeneralName ::= CHOICE {
+ * otherName [0] AnotherName,
+ * rfc822Name [1] IA5String,
+ * dNSName [2] IA5String,
+ * x400Address [3] ORAddress,
+ * directoryName [4] Name,
+ * ediPartyName [5] EDIPartyName,
+ * uniformResourceIdentifier [6] IA5String,
+ * iPAddress [7] OCTET STRING,
+ * registeredID [8] OBJECT IDENTIFIER }
+ *
+ * </pre>
+ *
+ * @return the subject alternative names or {@code null} if there are none
+ * in the certificate.
+ * @throws CertificateParsingException
+ * if decoding of the extension fails.
+ */
+ public Collection<List<?>> getSubjectAlternativeNames()
+ throws CertificateParsingException {
+ return null;
+ }
+
+ /**
+ * Returns a read-only list of the issuer alternative names from the {@code
+ * IssuerAltName} extension.
+ * <p>
+ * The ASN.1 definition of {@code IssuerAltName}:
+ *
+ * <pre>
+ * IssuerAltName ::= GeneralNames
+ *
+ * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
+ *
+ * GeneralName ::= CHOICE {
+ * otherName [0] AnotherName,
+ * rfc822Name [1] IA5String,
+ * dNSName [2] IA5String,
+ * x400Address [3] ORAddress,
+ * directoryName [4] Name,
+ * ediPartyName [5] EDIPartyName,
+ * uniformResourceIdentifier [6] IA5String,
+ * iPAddress [7] OCTET STRING,
+ * registeredID [8] OBJECT IDENTIFIER }
+ *
+ * </pre>
+ *
+ * @return the issuer alternative names of {@code null} if there are none in
+ * the certificate.
+ * @throws CertificateParsingException
+ * if decoding of the extension fails.
+ */
+ public Collection<List<?>> getIssuerAlternativeNames()
+ throws CertificateParsingException {
+ return null;
+ }
+}
+
diff --git a/luni/src/main/java/java/security/cert/X509Extension.java b/luni/src/main/java/java/security/cert/X509Extension.java
new file mode 100644
index 0000000..1543f3d
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/X509Extension.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.util.Set;
+
+/**
+ * The interface specifying an X.509 Certificate or CRL extension.
+ */
+public interface X509Extension {
+
+ /**
+ * Returns the set of OIDs of the extension(s) marked as CRITICAL, that this
+ * implementation manages.
+ *
+ * @return the set of extension OIDs marked as CRITIAL, an empty set if none
+ * are marked as CRITICAL, or {@code null} if no extensions are
+ * present.
+ */
+ public Set<String> getCriticalExtensionOIDs();
+
+ /**
+ * Returns the extension value as DER-encoded OCTET string for the specified
+ * OID.
+ *
+ * @param oid
+ * the object identifier to get the extension value for.
+ * @return the extension value as DER-encoded OCTET string, or {@code null}
+ * if no extension for the specified OID can be found.
+ */
+ public byte[] getExtensionValue(String oid);
+
+ /**
+ * Returns the set of OIDs of the extension(s) marked as NON-CRITICAL, that
+ * this implementation manages.
+ *
+ * @return the set of extension OIDs marked as NON-CRITIAL, an empty set if
+ * none are marked as NON-.CRITICAL, or {@code null} if no
+ * extensions are present.
+ */
+ public Set<String> getNonCriticalExtensionOIDs();
+
+ /**
+ * Returns whether this instance has an extension marked as CRITICAL that it
+ * cannot support.
+ *
+ * @return {@code true} if an unsupported CRITICAL extension is present,
+ * {@code false} otherwise.
+ */
+ public boolean hasUnsupportedCriticalExtension();
+}
diff --git a/luni/src/main/java/java/security/cert/package.html b/luni/src/main/java/java/security/cert/package.html
new file mode 100644
index 0000000..e39b38f
--- /dev/null
+++ b/luni/src/main/java/java/security/cert/package.html
@@ -0,0 +1,22 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
+</head>
+<html>
+<body>
+<p>
+This package provides all the classes and all the interfaces needed to generate, administer and verify
+X.509 certificates.
+Functionality for parsing certificate, extracting information from them, validating and
+verifying the information they contains are provided.
+Exception are generated mainly for three reasons:<br>
+- if the certificate's encoding is broken
+(CertificateEncodingException)<br>
+- if the certificate's time stamp is not valid
+(CertificateExpiredException)<br>
+- or if the validation's path is false (CertPathValidatorException).
+</p><p>
+The functionality to check the different entries and extension fields of X.509 certificates are also provided.
+</p>
+</body>
+</html>
diff --git a/luni/src/main/java/java/security/interfaces/DSAKey.java b/luni/src/main/java/java/security/interfaces/DSAKey.java
new file mode 100644
index 0000000..ac9aade
--- /dev/null
+++ b/luni/src/main/java/java/security/interfaces/DSAKey.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.interfaces;
+
+/**
+ * The base interface for Digital Signature Algorithm (DSA) public or private
+ * keys.
+ */
+public interface DSAKey {
+
+ /**
+ * Returns the DSA key parameters.
+ *
+ * @return the DSA key parameters.
+ */
+ public DSAParams getParams();
+
+}
diff --git a/luni/src/main/java/java/security/interfaces/DSAKeyPairGenerator.java b/luni/src/main/java/java/security/interfaces/DSAKeyPairGenerator.java
new file mode 100644
index 0000000..b7b5480
--- /dev/null
+++ b/luni/src/main/java/java/security/interfaces/DSAKeyPairGenerator.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.interfaces;
+
+import java.security.InvalidParameterException;
+import java.security.SecureRandom;
+
+/**
+ * The interface for key generators that can generate DSA key pairs.
+ */
+public interface DSAKeyPairGenerator {
+
+ /**
+ * Initializes this generator with the prime ({@code p}), subprime ({@code
+ * q}), and base ({@code g}) values from the specified parameters.
+ *
+ * @param params
+ * the parameter values.
+ * @param random
+ * the source of randomness.
+ * @throws InvalidParameterException
+ * if the specified parameter values are {@code null} or
+ * invalid.
+ */
+ public void initialize(DSAParams params, SecureRandom random)
+ throws InvalidParameterException;
+
+ /**
+ * Initializes this generator for the specified modulus length. Valid values
+ * for the modulus length are the multiples of 8 between 512 and 1024.
+ * <p>
+ * The parameter {@code genParams} specifies whether this method should
+ * generate new prime ({@code p}), subprime ({@code q}), and base ({@code g})
+ * values or whether
+ * it will use the pre-calculated values for the specified modulus
+ * length. Default parameters are available for modulus lengths of 512 and 1024
+ * bits.
+ *
+ * @param modlen
+ * the length of the modulus in bits.
+ * @param genParams
+ * whether new values should be generated.
+ * @param random
+ * the source of randomness.
+ * @throws InvalidParameterException
+ * if the specified modulus length is not valid, or if there are
+ * no pre-calculated values and {@code genParams} is {@code
+ * false}.
+ */
+ public void initialize(int modlen, boolean genParams, SecureRandom random)
+ throws InvalidParameterException;
+}
diff --git a/luni/src/main/java/java/security/interfaces/DSAParams.java b/luni/src/main/java/java/security/interfaces/DSAParams.java
new file mode 100644
index 0000000..62f2d00
--- /dev/null
+++ b/luni/src/main/java/java/security/interfaces/DSAParams.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.interfaces;
+
+import java.math.BigInteger;
+
+/**
+ * The interface for Digital Signature Algorithm (DSA) specific parameters.
+ */
+public interface DSAParams {
+
+ /**
+ * Returns the base ({@code g}) value.
+ *
+ * @return the base ({@code g}) value.
+ */
+ public BigInteger getG();
+
+ /**
+ * Returns the prime ({@code p}) value.
+ *
+ * @return the prime ({@code p}) value.
+ */
+ public BigInteger getP();
+
+ /**
+ * Returns the subprime ({@code q} value.
+ *
+ * @return the subprime ({@code q} value.
+ */
+ public BigInteger getQ();
+
+}
+
diff --git a/luni/src/main/java/java/security/interfaces/DSAPrivateKey.java b/luni/src/main/java/java/security/interfaces/DSAPrivateKey.java
new file mode 100644
index 0000000..6419440
--- /dev/null
+++ b/luni/src/main/java/java/security/interfaces/DSAPrivateKey.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.interfaces;
+
+import java.math.BigInteger;
+import java.security.PrivateKey;
+
+/**
+ * The interface for a Digital Signature Algorithm (DSA) private key.
+ */
+public interface DSAPrivateKey extends DSAKey, PrivateKey {
+
+ /**
+ * The serial version identifier.
+ */
+ public static final long serialVersionUID = 7776497482533790279L;
+
+ /**
+ * Returns the private key value {@code x}.
+ *
+ * @return the private key value {@code x}.
+ */
+ public BigInteger getX();
+
+}
diff --git a/luni/src/main/java/java/security/interfaces/DSAPublicKey.java b/luni/src/main/java/java/security/interfaces/DSAPublicKey.java
new file mode 100644
index 0000000..9642bf1
--- /dev/null
+++ b/luni/src/main/java/java/security/interfaces/DSAPublicKey.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.interfaces;
+
+import java.math.BigInteger;
+import java.security.PublicKey;
+
+/**
+ * The interface for a Digital Signature Algorithm (DSA) public key.
+ */
+public interface DSAPublicKey extends DSAKey, PublicKey {
+
+ /**
+ * The serial version identifier.
+ */
+ public static final long serialVersionUID = 1234526332779022332L;
+
+ /**
+ * Returns the public key value {@code y}.
+ *
+ * @return the public key value {@code y}.
+ */
+ public BigInteger getY();
+
+}
diff --git a/luni/src/main/java/java/security/interfaces/ECKey.java b/luni/src/main/java/java/security/interfaces/ECKey.java
new file mode 100644
index 0000000..5469392
--- /dev/null
+++ b/luni/src/main/java/java/security/interfaces/ECKey.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.interfaces;
+
+import java.security.spec.ECParameterSpec;
+
+/**
+ * The base interface for Elliptic Curve (EC) public or private keys.
+ */
+public interface ECKey {
+
+ /**
+ * Returns the EC key parameters.
+ *
+ * @return the EC key parameters.
+ */
+ public ECParameterSpec getParams();
+}
diff --git a/luni/src/main/java/java/security/interfaces/ECPrivateKey.java b/luni/src/main/java/java/security/interfaces/ECPrivateKey.java
new file mode 100644
index 0000000..254d2a6
--- /dev/null
+++ b/luni/src/main/java/java/security/interfaces/ECPrivateKey.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.interfaces;
+
+import java.math.BigInteger;
+import java.security.PrivateKey;
+
+/**
+ * The interface for an Elliptic Curve (EC) private key.
+ */
+public interface ECPrivateKey extends PrivateKey, ECKey {
+
+ /**
+ * The serial version identifier.
+ */
+ public static final long serialVersionUID = -7896394956925609184L;
+
+ /**
+ * Returns the private value {@code S}.
+ *
+ * @return the private value {@code S}.
+ */
+ public BigInteger getS();
+}
diff --git a/luni/src/main/java/java/security/interfaces/ECPublicKey.java b/luni/src/main/java/java/security/interfaces/ECPublicKey.java
new file mode 100644
index 0000000..8ad97fc
--- /dev/null
+++ b/luni/src/main/java/java/security/interfaces/ECPublicKey.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.interfaces;
+
+import java.security.spec.ECPoint;
+import java.security.PublicKey;
+
+/**
+ * The interface for an Elliptic Curve (EC) public key.
+ */
+public interface ECPublicKey extends PublicKey, ECKey {
+
+ /**
+ * The serial version identifier.
+ */
+ public static final long serialVersionUID = -3314988629879632826L;
+
+ /**
+ * Returns the public point {@code W} on an elliptic curve (EC).
+ *
+ * @return the public point {@code W} on an elliptic curve (EC).
+ */
+ public ECPoint getW();
+}
diff --git a/luni/src/main/java/java/security/interfaces/RSAKey.java b/luni/src/main/java/java/security/interfaces/RSAKey.java
new file mode 100644
index 0000000..2c9e6c1
--- /dev/null
+++ b/luni/src/main/java/java/security/interfaces/RSAKey.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.interfaces;
+
+import java.math.BigInteger;
+
+/**
+ * The base interface for PKCS#1 RSA public and private keys.
+ */
+public interface RSAKey {
+
+ /**
+ * Returns the modulus.
+ *
+ * @return the modulus.
+ */
+ public BigInteger getModulus();
+}
diff --git a/luni/src/main/java/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java b/luni/src/main/java/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java
new file mode 100644
index 0000000..d8aa1bf
--- /dev/null
+++ b/luni/src/main/java/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.interfaces;
+
+import java.math.BigInteger;
+import java.security.spec.RSAOtherPrimeInfo;
+
+/**
+ * The interface for a Multi-Prime RSA private key. Specified by <a
+ * href="http://www.rsa.com/rsalabs/node.asp?id=2125">PKCS #1 v2.0 Amendment 1:
+ * Multi-Prime RSA</a>.
+ */
+public interface RSAMultiPrimePrivateCrtKey extends RSAPrivateKey {
+
+ /**
+ * the serial version identifier.
+ */
+ public static final long serialVersionUID = 618058533534628008L;
+
+ /**
+ * Returns the CRT coefficient, {@code q^-1 mod p}.
+ *
+ * @return the CRT coefficient.
+ */
+ public BigInteger getCrtCoefficient();
+
+ /**
+ * Returns the information for the additional primes.
+ *
+ * @return the information for the additional primes, or {@code null} if
+ * there are only the two primes ({@code p, q}),
+ */
+ public RSAOtherPrimeInfo[] getOtherPrimeInfo();
+
+ /**
+ * Returns the prime factor {@code p} of {@code n}.
+ *
+ * @return the prime factor {@code p} of {@code n}.
+ */
+ public BigInteger getPrimeP();
+
+ /**
+ * Returns the prime factor {@code q} of {@code n}.
+ *
+ * @return the prime factor {@code q} of {@code n}.
+ */
+ public BigInteger getPrimeQ();
+
+ /**
+ * Returns the CRT exponent of the prime {@code p}.
+ *
+ * @return the CRT exponent of the prime {@code p}.
+ */
+ public BigInteger getPrimeExponentP();
+
+ /**
+ * Returns the CRT exponent of the prime {@code q}.
+ *
+ * @return the CRT exponent of the prime {@code q}.
+ */
+ public BigInteger getPrimeExponentQ();
+
+ /**
+ * Returns the public exponent {@code e}.
+ *
+ * @return the public exponent {@code e}.
+ */
+ public BigInteger getPublicExponent();
+}
diff --git a/luni/src/main/java/java/security/interfaces/RSAPrivateCrtKey.java b/luni/src/main/java/java/security/interfaces/RSAPrivateCrtKey.java
new file mode 100644
index 0000000..a670491
--- /dev/null
+++ b/luni/src/main/java/java/security/interfaces/RSAPrivateCrtKey.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.interfaces;
+
+import java.math.BigInteger;
+
+/**
+ * The interface for a PKCS#1 RSA private key using CRT information values.
+ */
+public interface RSAPrivateCrtKey extends RSAPrivateKey {
+
+ /**
+ * The serial version identifier.
+ */
+ public static final long serialVersionUID = -5682214253527700368L;
+
+ /**
+ * Returns the CRT coefficient, {@code q^-1 mod p}.
+ *
+ * @return the CRT coefficient.
+ */
+ public BigInteger getCrtCoefficient();
+
+ /**
+ * Returns the prime factor {@code p} of {@code n}.
+ *
+ * @return the prime factor {@code p} of {@code n}.
+ */
+ public BigInteger getPrimeP();
+
+ /**
+ * Returns the prime factor {@code q} of {@code n}.
+ *
+ * @return the prime factor {@code q} of {@code n}.
+ */
+ public BigInteger getPrimeQ();
+
+ /**
+ * Returns the CRT exponent of the primet {@code p}.
+ *
+ * @return the CRT exponent of the prime {@code p}.
+ */
+ public BigInteger getPrimeExponentP();
+
+ /**
+ * Returns the CRT exponent of the prime {@code q}.
+ *
+ * @return the CRT exponent of the prime {@code q}.
+ */
+ public BigInteger getPrimeExponentQ();
+
+ /**
+ * Returns the public exponent {@code e}.
+ *
+ * @return the public exponent {@code e}.
+ */
+ public BigInteger getPublicExponent();
+}
diff --git a/luni/src/main/java/java/security/interfaces/RSAPrivateKey.java b/luni/src/main/java/java/security/interfaces/RSAPrivateKey.java
new file mode 100644
index 0000000..0da15e9
--- /dev/null
+++ b/luni/src/main/java/java/security/interfaces/RSAPrivateKey.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.interfaces;
+
+import java.math.BigInteger;
+import java.security.PrivateKey;
+
+/**
+ * The interface for an PKCS#1 RSA private key.
+ */
+public interface RSAPrivateKey extends PrivateKey, RSAKey {
+
+ /**
+ * The serial version identifier.
+ */
+ public static final long serialVersionUID = 5187144804936595022L;
+
+ /**
+ * Returns the private exponent {@code d}.
+ *
+ * @return the private exponent {@code d}.
+ */
+ public BigInteger getPrivateExponent();
+}
diff --git a/luni/src/main/java/java/security/interfaces/RSAPublicKey.java b/luni/src/main/java/java/security/interfaces/RSAPublicKey.java
new file mode 100644
index 0000000..379351f
--- /dev/null
+++ b/luni/src/main/java/java/security/interfaces/RSAPublicKey.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.interfaces;
+
+import java.math.BigInteger;
+import java.security.PublicKey;
+
+/**
+ * The interface for a PKCS#1 RSA public key.
+ */
+public interface RSAPublicKey extends PublicKey, RSAKey {
+
+ /**
+ * The serial version identifier.
+ */
+ public static final long serialVersionUID = -8727434096241101194L;
+
+ /**
+ * Returns the public exponent {@code e}.
+ *
+ * @return the public exponent {@code e}.
+ */
+ public BigInteger getPublicExponent();
+
+}
diff --git a/luni/src/main/java/java/security/interfaces/package.html b/luni/src/main/java/java/security/interfaces/package.html
new file mode 100644
index 0000000..dd24196
--- /dev/null
+++ b/luni/src/main/java/java/security/interfaces/package.html
@@ -0,0 +1,14 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
+</head>
+<html>
+<body>
+<p>
+This package provides the interfaces needed to generate:
+(1) Keys for the RSA asymmetric encryption algorithm using the PKCS#1 standard;
+(2) Keys for the Digital Signature Algorithm (DSA) specified by FIPS-186;
+(3) Keys for a generic Elliptic Curve asymmetric encryption algorithm.
+</p>
+</body>
+</html>
diff --git a/luni/src/main/java/java/security/package.html b/luni/src/main/java/java/security/package.html
new file mode 100644
index 0000000..4c5e2b4
--- /dev/null
+++ b/luni/src/main/java/java/security/package.html
@@ -0,0 +1,35 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
+</head>
+<html>
+<body>
+<p>This package provides all the classes and interfaces that
+constitute the Java security framework. The content of this package can
+be divided into two parts:
+
+<ul>
+ <li>Classes implementing the access control infrastructure.
+ <p>The central class is <i>java.security.AccessController</i>
+ which checks if code, invoking sensitive resources, was granted the required
+ permissions.
+ <p>The class loader (<i>java.security.SecureClassLoader</i>) associates classes
+ with a protection domain (<i>java.security.ProtectionDomain</i>) which consists of a
+ code source (<i>java.security.CodeSource</i>) and the granted permissions
+ (<i>java.security.Permission</i>). The policy, defined through <i>java.security.Policy</i>, defines
+ which permissions are granted to classes loaded from a code source ( class
+ <i>java.security.CodeSource</i>).
+ <li>Classes and interfaces for the extensible cryptographic
+ <i>service provider infrastructure</i> (<b>SPI</b>) such as abstractions for certificates,
+ signatures, private and public keys. Also abstractions for the algorithms
+ they utilize are provided in this package.
+ <p>Security providers, as defined in <i>java.security.Providers</i>, can be
+ registered to provide
+ different implementations for a variety of security infrastructure,
+ such as key stores. Therefore the corresponding
+ service provider interface (i.e. <i>java.security.KeyStoreSpi</i>) must be
+ implemented.
+</ul>
+</p>
+</body>
+</html>
diff --git a/luni/src/main/java/java/security/security.properties b/luni/src/main/java/java/security/security.properties
new file mode 100644
index 0000000..cc16be7
--- /dev/null
+++ b/luni/src/main/java/java/security/security.properties
@@ -0,0 +1,120 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+# This is the system security properties file
+# It should be named: ${java.home}/lib/security/java.security
+
+
+#
+# Providers
+# See also: J2SE doc. "How to Implement a Provider for the JavaTM Cryptography Architecture"
+#
+# Harmony providers
+security.provider.1=org.apache.harmony.security.provider.cert.DRLCertFactory
+security.provider.2=org.apache.harmony.security.provider.crypto.CryptoProvider
+security.provider.3=org.apache.harmony.xnet.provider.jsse.JSSEProvider
+# Other Open Source providers
+security.provider.4=org.bouncycastle.jce.provider.BouncyCastleProvider
+
+#
+# Class to instantiate as a default Configuration implementation
+# See specification for javax.security.auth.login.Configuration class.
+#
+login.configuration.provider=org.apache.harmony.auth.login.DefaultConfiguration
+
+
+#
+# Flag to enable/disable append/overwrite this properties file by the
+# extra properties file passed on the command line with
+# -Djava.security.properties=<file|url> or -Djava.security.properties==<file|url>
+# Possible values: true/false.
+#
+security.allowCustomPropertiesFile=true
+
+
+# Class to instantiate as the default system Policy.
+# The class should be available via bootclasspath.
+# See specification for java.security.Policy class.
+policy.provider=org.apache.harmony.security.fortress.DefaultPolicy
+
+
+# The default is to have a single system-wide policy file,
+# and an optional policy file in the user's home directory.
+# It is possible to specify any number of policy files, via policy.url.n keys.
+# See also: "JavaTM 2 Platform Security Architecture.", chapter 3. Permissions and Security Policy
+policy.url.1=file:/${java.home}/lib/security/java.policy
+policy.url.2=file:/${user.home}/.java.policy
+
+
+# Flag to enable/disable properties expansion (${...}) in policy files.
+# Possible values: true/false.
+# See also: "JavaTM 2 Platform Security Architecture.", chapter 3. Permissions and Security Policy
+policy.expandProperties=true
+
+
+# Flag to enable/disable an extra policy to be passed on the command line
+# with -Djava.security.policy=<file|url>. Possible values: true/false.
+# See also: "JavaTM 2 Platform Security Architecture.", chapter 3. Permissions and Security Policy
+policy.allowSystemProperty=true
+
+
+# A comma-separated list of package prefixes that require
+# extra protection at ClassLoader's level.
+# See java/lang/SecurityManager#checkPackageAccess for more details.
+package.access=org.apache.harmony.security.fortress.,com.intel.fortress.,com.ibm.oti.
+
+
+# Class to instantiate as default JGSS manager.
+jgss.spi.manager=
+
+
+# The default SSLSocketFactory and SSLServerSocketFactory provider implementations.
+# See specification for
+# javax/net/ssl/SSLSocketFactory.html#getDefault()
+# javax/net/ssl/SSLServerSocketFactory.html#getDefault()
+
+# BEGIN android-removed
+ssl.SocketFactory.provider=org.apache.harmony.xnet.provider.jsse.OpenSSLSocketFactoryImpl
+# END android-removed
+
+# BEGIN android-added
+# Use the definition above to get the new, OpenSSL-based SSL implementation,
+# or use this one to get the old, Android-based SSL implementation.
+# ssl.SocketFactory.provider=javax.net.ssl.OldSSLSocketFactory
+# END android-added
+
+# For SSL server sockets, there's only the new, OpenSSL-based implementation.
+ssl.ServerSocketFactory.provider=org.apache.harmony.xnet.provider.jsse.OpenSSLServerSocketFactoryImpl
+
+# Default KeyStore type.
+# See specification for java/security/KeyStore.html#getDefaultType()
+keystore.type=BKS
+
+
+# Default KeyManagerFactory and TrustManagerFactory algorithms.
+# See specification for
+# javax/net/ssl/KeyManagerFactory.html#getDefaultAlgorithm()
+# javax/net/ssl/TrustManagerFactory.html#getDefaultAlgorithm()
+ssl.KeyManagerFactory.algorithm=X509
+ssl.TrustManagerFactory.algorithm=X509
+
+# system.scope is used to specify implementation class of IdentityScope
+# this class should can be loaded by boot classloader
+system.scope=org.apache.harmony.security.SystemScope
+
+# BEGIN android-added
+# The following non-standard property controls peer certificate validation.
+ssl.disablePeerCertificateChainVerification=false
+# END android-added
diff --git a/luni/src/main/java/java/security/spec/AlgorithmParameterSpec.java b/luni/src/main/java/java/security/spec/AlgorithmParameterSpec.java
new file mode 100644
index 0000000..0cbba76
--- /dev/null
+++ b/luni/src/main/java/java/security/spec/AlgorithmParameterSpec.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.spec;
+
+/**
+ * The marker interface for algorithm parameter specifications. The purpose is
+ * to group parameter specifications for algorithms.
+ */
+public interface AlgorithmParameterSpec {
+}
diff --git a/luni/src/main/java/java/security/spec/DSAParameterSpec.java b/luni/src/main/java/java/security/spec/DSAParameterSpec.java
new file mode 100644
index 0000000..e23a682
--- /dev/null
+++ b/luni/src/main/java/java/security/spec/DSAParameterSpec.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.spec;
+
+import java.math.BigInteger;
+import java.security.interfaces.DSAParams;
+
+/**
+ * The parameter specification used with the Digital Signature Algorithm (DSA).
+ */
+public class DSAParameterSpec implements AlgorithmParameterSpec, DSAParams {
+ // Prime
+ private final BigInteger p;
+ // Sub-prime
+ private final BigInteger q;
+ // Base
+ private final BigInteger g;
+
+ /**
+ * Creates a new {@code DSAParameterSpec} with the specified prime {@code p},
+ * sub-prime {@code q} and the base {@code g}.
+ *
+ * @param p
+ * the prime {@code p}.
+ * @param q
+ * the sub-prime {@code q}.
+ * @param g
+ * the base {@code g};
+ */
+ public DSAParameterSpec(BigInteger p, BigInteger q, BigInteger g) {
+ this.p = p;
+ this.q = q;
+ this.g = g;
+ }
+
+ /**
+ * Returns the base {@code g}.
+ *
+ * @return the base {@code g}.
+ */
+ public BigInteger getG() {
+ return g;
+ }
+
+ /**
+ * Returns the prime {@code p}.
+ *
+ * @return the prime {@code p}.
+ */
+ public BigInteger getP() {
+ return p;
+ }
+
+ /**
+ * Returns the sub-prime {@code q}.
+ *
+ * @return the sub-prime {@code q}.
+ */
+ public BigInteger getQ() {
+ return q;
+ }
+}
diff --git a/luni/src/main/java/java/security/spec/DSAPrivateKeySpec.java b/luni/src/main/java/java/security/spec/DSAPrivateKeySpec.java
new file mode 100644
index 0000000..6dc12c8
--- /dev/null
+++ b/luni/src/main/java/java/security/spec/DSAPrivateKeySpec.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.spec;
+
+import java.math.BigInteger;
+
+/**
+ * The parameters specifying a DSA private key.
+ */
+public class DSAPrivateKeySpec implements KeySpec {
+ // Private key
+ private final BigInteger x;
+ // Prime
+ private final BigInteger p;
+ // Sub-prime
+ private final BigInteger q;
+ // Base
+ private final BigInteger g;
+
+ /**
+ * Creates a new {@code DSAPrivateKeySpec} with the specified private key,
+ * prime, sub-prime and base.
+ *
+ * @param x
+ * the private key {@code x}.
+ * @param p
+ * the prime {@code p}.
+ * @param q
+ * the sub-prime {@code q}.
+ * @param g
+ * the base {@code g}.
+ */
+ public DSAPrivateKeySpec(BigInteger x, BigInteger p,
+ BigInteger q, BigInteger g) {
+ this.x = x;
+ this.p = p;
+ this.q = q;
+ this.g = g;
+ }
+
+ /**
+ * Returns the base {@code g}.
+ *
+ * @return the base {@code g}.
+ */
+ public BigInteger getG() {
+ return g;
+ }
+
+ /**
+ * Returns the prime {@code p}.
+ *
+ * @return the prime {@code p}.
+ */
+ public BigInteger getP() {
+ return p;
+ }
+
+ /**
+ * Returns the sub-prime {@code q}.
+ *
+ * @return the sub-prime {@code q}.
+ */
+ public BigInteger getQ() {
+ return q;
+ }
+
+ /**
+ * Returns the private key {@code x}.
+ *
+ * @return the private key {@code x}.
+ */
+ public BigInteger getX() {
+ return x;
+ }
+}
diff --git a/luni/src/main/java/java/security/spec/DSAPublicKeySpec.java b/luni/src/main/java/java/security/spec/DSAPublicKeySpec.java
new file mode 100644
index 0000000..af90919
--- /dev/null
+++ b/luni/src/main/java/java/security/spec/DSAPublicKeySpec.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.spec;
+
+import java.math.BigInteger;
+
+/**
+ * The parameters specifying a DSA public key.
+ */
+public class DSAPublicKeySpec implements KeySpec {
+ // Public key
+ private final BigInteger y;
+ // Prime
+ private final BigInteger p;
+ // Sub-prime
+ private final BigInteger q;
+ // Base
+ private final BigInteger g;
+
+ /**
+ * Creates a new {@code DSAPublicKeySpec} with the specified public key,
+ * prime, sub-prime and base.
+ *
+ * @param y
+ * the public key value {@code y}.
+ * @param p
+ * the prime {@code p}.
+ * @param q
+ * the sub-prime {@code q}.
+ * @param g
+ * the base {@code g}.
+ */
+ public DSAPublicKeySpec(BigInteger y, BigInteger p,
+ BigInteger q, BigInteger g) {
+ this.y = y;
+ this.p = p;
+ this.q = q;
+ this.g = g;
+ }
+
+ /**
+ * Returns the base {@code g}.
+ *
+ * @return the base {@code g}.
+ */
+ public BigInteger getG() {
+ return g;
+ }
+
+ /**
+ * Returns the prime {@code p}.
+ *
+ * @return the prime {@code p}.
+ */
+ public BigInteger getP() {
+ return p;
+ }
+
+ /**
+ * Returns the sub-prime {@code q}.
+ *
+ * @return the sub-prime {@code q}.
+ */
+ public BigInteger getQ() {
+ return q;
+ }
+
+ /**
+ * Returns the public key value {@code y}.
+ *
+ * @return the public key value {@code y}.
+ */
+ public BigInteger getY() {
+ return y;
+ }
+}
diff --git a/luni/src/main/java/java/security/spec/ECField.java b/luni/src/main/java/java/security/spec/ECField.java
new file mode 100644
index 0000000..b4c6be2
--- /dev/null
+++ b/luni/src/main/java/java/security/spec/ECField.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.spec;
+
+/**
+ * The base interface for a Finite Field of an Elliptic Curve.
+ */
+public interface ECField {
+
+ /**
+ * Returns the size of the field (in bits).
+ *
+ * @return the size of the field (in bits).
+ */
+ int getFieldSize();
+}
diff --git a/luni/src/main/java/java/security/spec/ECFieldF2m.java b/luni/src/main/java/java/security/spec/ECFieldF2m.java
new file mode 100644
index 0000000..e5a636a
--- /dev/null
+++ b/luni/src/main/java/java/security/spec/ECFieldF2m.java
@@ -0,0 +1,266 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.spec;
+
+import java.math.BigInteger;
+import java.util.Arrays;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * The parameters specifying a <i>characteristic 2 finite field</i> of an
+ * elliptic curve.
+ */
+public class ECFieldF2m implements ECField {
+ // Mid terms array length for trinomial basis
+ private static final int TPB_MID_LEN = 1;
+ // Mid terms array length for pentanomial basis
+ private static final int PPB_MID_LEN = 3;
+ // All terms number for trinomial basis
+ private static final int TPB_LEN = TPB_MID_LEN + 2;
+ // All terms number for pentanomial basis
+ private static final int PPB_LEN = PPB_MID_LEN + 2;
+ // m value
+ private final int m;
+ // Reduction polynomial
+ private final BigInteger rp;
+ // Mid term(s) of reduction polynomial
+ private final int[] ks;
+
+ /**
+ * Creates a new {@code ECFieldF2m} with {@code 2^m} elements with a normal
+ * basis.
+ *
+ * @param m
+ * the exponent {@code m} for the number of elements.
+ * @throws IllegalArgumentException
+ * if {@code m <= zero}.
+ */
+ public ECFieldF2m(int m) {
+ this.m = m;
+ if (this.m <= 0) {
+ throw new IllegalArgumentException(Messages.getString("security.75")); //$NON-NLS-1$
+ }
+ this.rp = null;
+ this.ks = null;
+ }
+
+ /**
+ * Creates a new {@code ECFieldF2m} with {@code 2^m} elements with a polynomial
+ * basis and the reduction polynomial based on {@code rp}.
+ * <p>
+ * The reduction polynomial must be either <i>trinomial</i> or
+ * <i>pentanomial</i>.
+ *
+ * @param m
+ * the exponent {@code m} for the number of elements.
+ * @param rp
+ * the base of the reduction polynomial with the n-th bit
+ * corresponding to the n-th coefficient of the reduction
+ * polynomial.
+ * @throws IllegalArgumentException
+ * if {@code m <= zero} or the {@code rp} is invalid.
+ */
+ public ECFieldF2m(int m, BigInteger rp) {
+ this.m = m;
+ if (this.m <= 0) {
+ throw new IllegalArgumentException(Messages.getString("security.75")); //$NON-NLS-1$
+ }
+ this.rp = rp;
+ if (this.rp == null) {
+ throw new NullPointerException(Messages.getString("security.76")); //$NON-NLS-1$
+ }
+ // the leftmost bit must be (m+1)-th one,
+ // set bits count must be 3 or 5,
+ // bits 0 and m must be set
+ int rp_bc = this.rp.bitCount();
+ if ((this.rp.bitLength() != (m+1)) ||
+ (rp_bc != TPB_LEN && rp_bc != PPB_LEN) ||
+ (!this.rp.testBit(0) || !this.rp.testBit(m)) ) {
+ throw new IllegalArgumentException(Messages.getString("security.77")); //$NON-NLS-1$
+ }
+
+ // setup ks using rp:
+ // allocate for mid terms only
+ ks = new int[rp_bc-2];
+ // find midterm orders and set ks accordingly
+ BigInteger rpTmp = rp.clearBit(0);
+ for (int i=ks.length-1; i>=0; i-- ) {
+ ks[i] = rpTmp.getLowestSetBit();
+ rpTmp = rpTmp.clearBit(ks[i]);
+ }
+ }
+
+ /**
+ * Creates a new {@code ECFieldF2m} with {@code 2^m} elements with
+ * a polynomial basis and the reduction polynomial based on {@code ks}.
+ * <p>
+ * The reduction polynomial must be either <i>trinomial</i> or
+ * <i>pentanomial</i>.
+ *
+ * @param m
+ * the exponent {@code m} for the number of elements.
+ * @param ks
+ * the base of the reduction polynomial with coefficients
+ * given in descending order.
+ * @throws IllegalArgumentException
+ * if {@code m <= zero} or the reduction polynomial is not
+ * valid.
+ */
+ public ECFieldF2m(int m, int[] ks) {
+ this.m = m;
+ if (this.m <= 0) {
+ throw new IllegalArgumentException(Messages.getString("security.75")); //$NON-NLS-1$
+ }
+ // Defensively copies array parameter
+ // to prevent subsequent modification.
+ // NPE as specified if ks is null
+ this.ks = new int[ks.length];
+ System.arraycopy(ks, 0, this.ks, 0, this.ks.length);
+
+ // no need to check for null already
+ if (this.ks.length != TPB_MID_LEN && this.ks.length != PPB_MID_LEN) {
+ // must be either trinomial or pentanomial basis
+ throw new IllegalArgumentException(Messages.getString("security.78")); //$NON-NLS-1$
+ }
+ // trinomial basis:
+ // check that m > k >= 1, where k is ks[0]
+ // pentanomial basis:
+ // check that m > k3 > k2 > k1 >= 1
+ // and kx in descending order, where
+ // k3 is ks[0], k2 is ks[1], k1 is ks[2]
+ boolean checkFailed = false;
+ int prev = this.m;
+ for (int i=0; i<this.ks.length; i++) {
+ if (this.ks[i] < prev) {
+ prev = this.ks[i];
+ continue;
+ }
+ checkFailed = true;
+ break;
+ }
+ if (checkFailed || prev < 1) {
+ throw new IllegalArgumentException(Messages.getString("security.79")); //$NON-NLS-1$
+ }
+
+ // Setup rp using ks:
+ // bits 0 and m always set
+ BigInteger rpTmp = BigInteger.ONE.setBit(this.m);
+ // set remaining bits according to ks
+ for (int i=0; i<this.ks.length; i++) {
+ rpTmp = rpTmp.setBit(this.ks[i]);
+ }
+ rp = rpTmp;
+ }
+
+ /**
+ * Returns whether the specified object equals to this finite field.
+ *
+ * @param obj
+ * the object to compare to this finite field.
+ * @return {@code true} if the specified object is equal to this finite field,
+ * otherwise {@code false}.
+ */
+ public boolean equals(Object obj) {
+ // object equals to itself
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof ECFieldF2m) {
+ ECFieldF2m o = (ECFieldF2m)obj;
+ // check m
+ if (this.m == o.m) {
+ // check rp
+ if (this.rp == null) {
+ if (o.rp == null) {
+ // fields both with normal basis
+ return true;
+ }
+ } else {
+ // at least this field with polynomial basis
+ // check that rp match
+ // return this.rp.equals(o.rp);
+ return Arrays.equals(this.ks, o.ks);
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns the size of this finite field (in bits).
+ *
+ * @return the size of this finite field (in bits).
+ */
+ public int getFieldSize() {
+ return m;
+ }
+
+ /**
+ * Returns the exponent {@code m} for this finite field, with {@code 2^m} as
+ * the number of elements.
+ *
+ * @return the exponent {@code m} for this finite field
+ */
+ public int getM() {
+ return m;
+ }
+
+ /**
+ * Returns a copy of the integer array containing the order of the middle
+ * term(s) of the reduction polynomial for a polynomial basis.
+ *
+ * @return a copy of the integer array containing the order of the middle
+ * term(s) of the reduction polynomial for a polynomial basis or
+ * {@code null} for a normal basis.
+ */
+ public int[] getMidTermsOfReductionPolynomial() {
+ // Defensively copies private array
+ // to prevent subsequent modification
+ // was: return ks == null ? null : (int[])ks.clone();
+ if (ks == null) {
+ return null;
+ } else {
+ int[] ret = new int[ks.length];
+ System.arraycopy(ks, 0, ret, 0, ret.length);
+ return ret;
+ }
+ }
+
+ /**
+ * Returns the base of the reduction polynomial with the n-th bit
+ * corresponding to the n-th coefficient of the reduction polynomial for a
+ * polynomial basis.
+ *
+ * @return the base of the reduction polynomial with the n-th bit
+ * corresponding to the n-th coefficient of the reduction polynomial
+ * for a polynomial basis or {@code null} for a normal basis.
+ */
+ public BigInteger getReductionPolynomial() {
+ return rp;
+ }
+
+ /**
+ * Returns the hashcode value for this finite field.
+ *
+ * @return the hashcode value for this finite field.
+ */
+ public int hashCode() {
+ return rp == null ? m : m + rp.hashCode();
+ }
+}
diff --git a/luni/src/main/java/java/security/spec/ECFieldFp.java b/luni/src/main/java/java/security/spec/ECFieldFp.java
new file mode 100644
index 0000000..b68238d
--- /dev/null
+++ b/luni/src/main/java/java/security/spec/ECFieldFp.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.spec;
+
+import java.math.BigInteger;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * The parameters specifying a <i>prime finite field</i> of an
+ * elliptic curve.
+ */
+public class ECFieldFp implements ECField {
+ // Prime
+ private final BigInteger p;
+
+ /**
+ * Creates a new prime finite field of an elliptic curve with the specified
+ * prime {@code p}.
+ *
+ * @param p
+ * the prime value {@code p}.
+ * @throws IllegalArgumentException
+ * if {@code p <= zero}.
+ */
+ public ECFieldFp(BigInteger p) {
+ this.p = p;
+
+ if (this.p == null) {
+ throw new NullPointerException(Messages.getString("security.83", "p")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if (this.p.signum() != 1) {
+ throw new IllegalArgumentException(Messages.getString("security.86", "p")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ /**
+ * Returns the size of the finite field (in bits).
+ *
+ * @return the size of the finite field (in bits).
+ */
+ public int getFieldSize() {
+ return p.bitLength();
+ }
+
+ /**
+ * Returns the prime value {@code p} for this finite field.
+ *
+ * @return the prime value {@code p} for this finite field.
+ */
+ public BigInteger getP() {
+ return p;
+ }
+
+ /**
+ * Returns whether the specified object is equal to this finite field.
+ *
+ * @param obj
+ * the object to compare to this finite field.
+ * @return {@code true} if the specified object is equal to this finite field,
+ * otherwise {@code false}.
+ */
+ public boolean equals(Object obj) {
+ // object equals itself
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof ECFieldFp) {
+ return (this.p.equals(((ECFieldFp)obj).p));
+ }
+ return false;
+ }
+
+ /**
+ * Returns the hashcode value for this finite field.
+ *
+ * @return the hashcode value for this finite field.
+ */
+ public int hashCode() {
+ return p.hashCode();
+ }
+}
diff --git a/luni/src/main/java/java/security/spec/ECGenParameterSpec.java b/luni/src/main/java/java/security/spec/ECGenParameterSpec.java
new file mode 100644
index 0000000..de4cd04
--- /dev/null
+++ b/luni/src/main/java/java/security/spec/ECGenParameterSpec.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.spec;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * The parameter specification used to generate elliptic curve domain parameters.
+ */
+public class ECGenParameterSpec implements AlgorithmParameterSpec {
+ // Standard (or predefined) name for EC domain
+ // parameters to be generated
+ private final String name;
+
+ /**
+ * Creates a new {@code ECGenParameterSpec} with the specified standard or
+ * predefined name of the to-be-generated domain parameter.
+ *
+ * @param name
+ * the name of the elliptic curve domain parameter.
+ */
+ public ECGenParameterSpec(String name) {
+ this.name = name;
+ if (this.name == null) {
+ throw new NullPointerException(Messages.getString("security.83", "name")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ /**
+ * Returns the name (standard or predefined) of the to-be-generated elliptic
+ * curve domain parameter.
+ *
+ * @return the name
+ */
+ public String getName() {
+ return name;
+ }
+}
diff --git a/luni/src/main/java/java/security/spec/ECParameterSpec.java b/luni/src/main/java/java/security/spec/ECParameterSpec.java
new file mode 100644
index 0000000..a1985db
--- /dev/null
+++ b/luni/src/main/java/java/security/spec/ECParameterSpec.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.spec;
+
+import java.math.BigInteger;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * The parameter specification used with Elliptic Curve Cryptography (ECC).
+ */
+public class ECParameterSpec implements AlgorithmParameterSpec {
+ // Elliptic curve for which this is parameter
+ private final EllipticCurve curve;
+ // Distinguished point on the elliptic curve called generator or base point
+ private final ECPoint generator;
+ // Order of the generator
+ private final BigInteger order;
+ // Cofactor
+ private final int cofactor;
+
+ /**
+ * Creates a new {@code ECParameterSpec} with the specified elliptic curve,
+ * the base point, the order of the generator (or base point) and the
+ * co-factor.
+ *
+ * @param curve
+ * the elliptic curve.
+ * @param generator
+ * the generator (or base point).
+ * @param order
+ * the order of the generator.
+ * @param cofactor
+ * the co-factor.
+ * @throws IllegalArgumentException
+ * if {@code order <= zero} or {@code cofactor <= zero}.
+ */
+ public ECParameterSpec(EllipticCurve curve, ECPoint generator,
+ BigInteger order, int cofactor) {
+ this.curve = curve;
+ this.generator = generator;
+ this.order = order;
+ this.cofactor = cofactor;
+ // throw NullPointerException if curve, generator or order is null
+ if (this.curve == null) {
+ throw new NullPointerException(Messages.getString("security.83", "curve")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if (this.generator == null) {
+ throw new NullPointerException(Messages.getString("security.83", "generator")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if (this.order == null) {
+ throw new NullPointerException(Messages.getString("security.83", "order")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ // throw IllegalArgumentException if order or cofactor is not positive
+ if (!(this.order.compareTo(BigInteger.ZERO) > 0)) {
+ throw new
+ IllegalArgumentException(Messages.getString("security.86", "order")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if (!(this.cofactor > 0)) {
+ throw new
+ IllegalArgumentException(Messages.getString("security.86", "cofactor")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ /**
+ * Returns the {@code cofactor}.
+ *
+ * @return the {@code cofactor}.
+ */
+ public int getCofactor() {
+ return cofactor;
+ }
+
+ /**
+ * Returns the elliptic curve.
+ *
+ * @return the elliptic curve.
+ */
+ public EllipticCurve getCurve() {
+ return curve;
+ }
+
+ /**
+ * Returns the generator (or base point).
+ *
+ * @return the generator (or base point).
+ */
+ public ECPoint getGenerator() {
+ return generator;
+ }
+
+ /**
+ * Returns the order of the generator.
+ *
+ * @return the order of the generator.
+ */
+ public BigInteger getOrder() {
+ return order;
+ }
+}
diff --git a/luni/src/main/java/java/security/spec/ECPoint.java b/luni/src/main/java/java/security/spec/ECPoint.java
new file mode 100644
index 0000000..0751757
--- /dev/null
+++ b/luni/src/main/java/java/security/spec/ECPoint.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.spec;
+
+import java.math.BigInteger;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * A Point on an Elliptic Curve in barycentric (or affine) coordinates.
+ */
+public class ECPoint {
+
+ /**
+ * The point on an Elliptic Curve at infinity.
+ */
+ public static final ECPoint POINT_INFINITY = new ECPoint();
+ // affine X coordinate of this point
+ private final BigInteger affineX;
+ // affine Y coordinate of this point
+ private final BigInteger affineY;
+
+ // Private ctor for POINT_INFINITY
+ private ECPoint() {
+ affineX = null;
+ affineY = null;
+ }
+
+ /**
+ * Creates a new point at the specified coordinates.
+ *
+ * @param affineX
+ * the x-coordinate.
+ * @param affineY
+ * the y-coordinate.
+ */
+ public ECPoint(BigInteger affineX, BigInteger affineY) {
+ this.affineX = affineX;
+ if (this.affineX == null) {
+ throw new NullPointerException(Messages.getString("security.83", "X")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ this.affineY = affineY;
+ if (this.affineY == null) {
+ throw new NullPointerException(Messages.getString("security.83", "Y")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ /**
+ * Returns the x-coordinate.
+ *
+ * @return the x-coordinate, or {@code null} for the infinite point.
+ */
+ public BigInteger getAffineX() {
+ return affineX;
+ }
+
+ /**
+ * Returns the y-coordinate.
+ *
+ * @return the y-coordinate, or {@code null} fot the infinite point.
+ */
+ public BigInteger getAffineY() {
+ return affineY;
+ }
+
+ /**
+ * Returns whether the specified object and this elliptic curve point are
+ * equal.
+ *
+ * @param other
+ * the object to compare.
+ * @return {@code true} if the specified object and this elliptic curve
+ * point are equal, otherwise {@code false}.
+ */
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (other instanceof ECPoint) {
+ if (this.affineX != null) {
+ ECPoint otherPoint = (ECPoint)other;
+ // no need to check for null in this case
+ return this.affineX.equals(otherPoint.affineX) &&
+ this.affineY.equals(otherPoint.affineY);
+ } else {
+ return other == POINT_INFINITY;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns the hashcode of this elliptic curve point.
+ *
+ * @return the hashcode of this elliptic curve point.
+ */
+ public int hashCode() {
+ if (this.affineX != null) {
+ return affineX.hashCode() * 31 + affineY.hashCode();
+ }
+ return 11;
+ }
+}
diff --git a/luni/src/main/java/java/security/spec/ECPrivateKeySpec.java b/luni/src/main/java/java/security/spec/ECPrivateKeySpec.java
new file mode 100644
index 0000000..1ddfec3
--- /dev/null
+++ b/luni/src/main/java/java/security/spec/ECPrivateKeySpec.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.spec;
+
+import java.math.BigInteger;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * The parameters specifying an Elliptic Curve (EC) private key.
+ */
+public class ECPrivateKeySpec implements KeySpec {
+ // Private value associated with this key
+ private final BigInteger s;
+ // Elliptic Curve domain parameters associated with this key
+ private final ECParameterSpec params;
+
+ /**
+ * Creates a new {@code ECPrivateKeySpec} with the specified private value
+ * {@code S} and parameter specification.
+ *
+ * @param s
+ * the private value {@code S}.
+ * @param params
+ * the domain parameter specification.
+ */
+ public ECPrivateKeySpec(BigInteger s, ECParameterSpec params) {
+ this.s = s;
+ this.params = params;
+ // throw NullPointerException if s or params is null
+ if (this.s == null) {
+ throw new NullPointerException(Messages.getString("security.83", "s")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if (this.params == null) {
+ throw new NullPointerException(Messages.getString("security.83", "params")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ /**
+ * Returns the domain parameter specification.
+ *
+ * @return the domain parameter specification.
+ */
+ public ECParameterSpec getParams() {
+ return params;
+ }
+
+ /**
+ * Returns the private value {@code S}.
+ *
+ * @return the private value {@code S}.
+ */
+ public BigInteger getS() {
+ return s;
+ }
+}
diff --git a/luni/src/main/java/java/security/spec/ECPublicKeySpec.java b/luni/src/main/java/java/security/spec/ECPublicKeySpec.java
new file mode 100644
index 0000000..0c88590
--- /dev/null
+++ b/luni/src/main/java/java/security/spec/ECPublicKeySpec.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.spec;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * The parameters specifying an Elliptic Curve (EC) public key.
+ */
+public class ECPublicKeySpec implements KeySpec {
+ // The public point
+ private final ECPoint w;
+ // The associated elliptic curve domain parameters
+ private final ECParameterSpec params;
+
+ /**
+ * Creates a new {@code ECPublicKey} with the specified public elliptic
+ * curve point and parameter specification.
+ *
+ * @param w
+ * the public elliptic curve point {@code W}.
+ * @param params
+ * the domain parameter specification.
+ * @throws IllegalArgumentException
+ * if the specified point {@code W} is at infinity.
+ */
+ public ECPublicKeySpec(ECPoint w, ECParameterSpec params) {
+ this.w = w;
+ this.params = params;
+ // throw NullPointerException if w or params is null
+ if (this.w == null) {
+ throw new NullPointerException(Messages.getString("security.83", "w")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if (this.params == null) {
+ throw new NullPointerException(Messages.getString("security.83", "params")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ // throw IllegalArgumentException if w is point at infinity
+ if (this.w.equals(ECPoint.POINT_INFINITY)) {
+ throw new IllegalArgumentException(
+ Messages.getString("security.84")); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Returns the domain parameter specification.
+ *
+ * @return the domain parameter specification.
+ */
+ public ECParameterSpec getParams() {
+ return params;
+ }
+
+ /**
+ * Returns the public elliptic curve point {@code W}.
+ *
+ * @return the public elliptic curve point {@code W}.
+ */
+ public ECPoint getW() {
+ return w;
+ }
+}
diff --git a/luni/src/main/java/java/security/spec/EllipticCurve.java b/luni/src/main/java/java/security/spec/EllipticCurve.java
new file mode 100644
index 0000000..45ff042
--- /dev/null
+++ b/luni/src/main/java/java/security/spec/EllipticCurve.java
@@ -0,0 +1,208 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.spec;
+
+import java.math.BigInteger;
+import java.util.Arrays;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * An Elliptic Curve with its necessary values.
+ */
+public class EllipticCurve {
+
+ // Underlying finite field
+ private final ECField field;
+
+ // The first coefficient of the equation defining this elliptic curve
+ private final BigInteger a;
+
+ // The second coefficient of the equation defining this elliptic curve
+ private final BigInteger b;
+
+ // Bytes used during this elliptic curve generation,
+ // if it was generated randomly
+ private final byte[] seed;
+
+ // Hash code
+ private volatile int hash;
+
+ /**
+ * Creates a new {@code EllipticCurve} with the specified field,
+ * coefficients and seed.
+ *
+ * @param field
+ * the finite field of this elliptic curve.
+ * @param a
+ * the coefficient {@code a}.
+ * @param b
+ * the coefficient {@code b}.
+ * @param seed
+ * the seed used for the generation of the curve.
+ * @throws IllegalArgumentException
+ * if the specified coefficients are not in the specified field.
+ */
+ public EllipticCurve(ECField field, BigInteger a, BigInteger b, byte[] seed) {
+ this.field = field;
+ if (this.field == null) {
+ throw new NullPointerException(Messages.getString("security.7A")); //$NON-NLS-1$
+ }
+ this.a = a;
+ if (this.a == null) {
+ throw new NullPointerException(Messages.getString("security.7B")); //$NON-NLS-1$
+ }
+ this.b = b;
+ if (this.b == null) {
+ throw new NullPointerException(Messages.getString("security.7C")); //$NON-NLS-1$
+ }
+ // make defensive copy
+ if (seed == null) {
+ this.seed = null;
+ } else {
+ this.seed = new byte[seed.length];
+ System.arraycopy(seed, 0, this.seed, 0, this.seed.length);
+ }
+ // check parameters for ECFieldFp and ECFieldF2m.
+ // Check invariant: a and b must be in the field.
+ // Check conditions for custom ECField are not specified.
+ if (this.field instanceof ECFieldFp) {
+ BigInteger p = ((ECFieldFp) this.field).getP();
+ if (this.a.signum() < 0 || this.a.compareTo(p) >= 0) {
+ throw new IllegalArgumentException(Messages.getString("security.7D")); //$NON-NLS-1$
+ }
+ if (this.b.signum() < 0 || this.b.compareTo(p) >= 0) {
+ throw new IllegalArgumentException(Messages.getString("security.7E")); //$NON-NLS-1$
+ }
+ } else if (this.field instanceof ECFieldF2m) {
+ int fieldSizeInBits = this.field.getFieldSize();
+ if (!(this.a.bitLength() <= fieldSizeInBits)) {
+ throw new IllegalArgumentException(Messages.getString("security.7D")); //$NON-NLS-1$
+ }
+ if (!(this.b.bitLength() <= fieldSizeInBits)) {
+ throw new IllegalArgumentException(Messages.getString("security.7E")); //$NON-NLS-1$
+ }
+ }
+ }
+
+ /**
+ * Creates a new {@code EllipticCurve} with the specified field and
+ * coefficients.
+ *
+ * @param field
+ * the finite field of this elliptic curve.
+ * @param a
+ * the coefficient {@code a}.
+ * @param b
+ * the coefficient {@code b}.
+ * @throws IllegalArgumentException
+ * if the specified coefficients are not in the specified field.
+ */
+ public EllipticCurve(ECField field, BigInteger a, BigInteger b) {
+ this(field, a, b, null);
+ }
+
+ /**
+ * Returns the coefficient {@code a} of this elliptic curve.
+ *
+ * @return the coefficient {@code a} of this elliptic curve.
+ */
+ public BigInteger getA() {
+ return a;
+ }
+
+ /**
+ * Returns the coefficient {@code b} of this elliptic curve.
+ *
+ * @return the coefficient {@code b} of this elliptic curve.
+ */
+ public BigInteger getB() {
+ return b;
+ }
+
+ /**
+ * Returns the finite field of this elliptic curve.
+ *
+ * @return the finite field of this elliptic curve.
+ */
+ public ECField getField() {
+ return field;
+ }
+
+ /**
+ * Returns a copy of the seed that was used to generate this elliptic curve.
+ *
+ * @return a copy of the seed that was used to generate this elliptic curve,
+ * or {@code null} if none specified.
+ */
+ public byte[] getSeed() {
+ if (seed == null) {
+ return null;
+ } else {
+ // return copy
+ byte[] ret = new byte[seed.length];
+ System.arraycopy(seed, 0, ret, 0, ret.length);
+ return ret;
+ }
+ }
+
+ /**
+ * Returns whether the specified object equals to this elliptic curve.
+ *
+ * @param other
+ * the object to compare.
+ * @return {@code true} if the specified object is equal to this elliptic
+ * curve, otherwise {@code false}.
+ */
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof EllipticCurve)) {
+ return false;
+ }
+ EllipticCurve otherEc = (EllipticCurve) other;
+ return this.field.equals(otherEc.field) && this.a.equals(otherEc.a)
+ && this.b.equals(otherEc.b)
+ && Arrays.equals(this.seed, otherEc.seed);
+ }
+
+ /**
+ * Returns the hashcode of this elliptic curve.
+ *
+ * @return the hashcode of this elliptic curve.
+ */
+ public int hashCode() {
+ // hash init is delayed
+ if (hash == 0) {
+ int hash0 = 11;
+ hash0 = hash0 * 31 + field.hashCode();
+ hash0 = hash0 * 31 + a.hashCode();
+ hash0 = hash0 * 31 + b.hashCode();
+ if (seed != null) {
+ for (int i = 0; i < seed.length; i++) {
+ hash0 = hash0 * 31 + seed[i];
+ }
+ } else {
+ hash0 = hash0 * 31;
+ }
+ hash = hash0;
+ }
+ return hash;
+ }
+}
diff --git a/luni/src/main/java/java/security/spec/EncodedKeySpec.java b/luni/src/main/java/java/security/spec/EncodedKeySpec.java
new file mode 100644
index 0000000..d34794c
--- /dev/null
+++ b/luni/src/main/java/java/security/spec/EncodedKeySpec.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.spec;
+
+/**
+ * The abstract key specification for a public or a private key in encoded
+ * format.
+ */
+public abstract class EncodedKeySpec implements KeySpec {
+ // Encoded key
+ private final byte[] encodedKey;
+
+ /**
+ * Creates a new {@code EncodedKeySpec} with the specified encoded key bytes.
+ *
+ * @param encodedKey
+ * the encoded key bytes.
+ */
+ public EncodedKeySpec(byte[] encodedKey) {
+ // Defensively copies parameter
+ // to prevent subsequent modification
+ this.encodedKey = new byte[encodedKey.length];
+ System.arraycopy(encodedKey, 0,
+ this.encodedKey, 0, this.encodedKey.length);
+ }
+
+ /**
+ * Returns the encoded key bytes.
+ *
+ * @return the encoded key bytes.
+ */
+ public byte[] getEncoded() {
+ // Defensively copies private array
+ // to prevent subsequent modification
+ byte[] ret = new byte[encodedKey.length];
+ System.arraycopy(encodedKey, 0, ret, 0, ret.length);
+ return ret;
+ }
+
+ /**
+ * Returns the name of the encoding format of this encoded key
+ * specification.
+ *
+ * @return the name of the encoding format of this encoded key
+ * specification.
+ */
+ public abstract String getFormat();
+}
diff --git a/luni/src/main/java/java/security/spec/InvalidKeySpecException.java b/luni/src/main/java/java/security/spec/InvalidKeySpecException.java
new file mode 100644
index 0000000..4ae5877
--- /dev/null
+++ b/luni/src/main/java/java/security/spec/InvalidKeySpecException.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.spec;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * The exception that is thrown when an invalid key specification is
+ * encountered.
+ */
+public class InvalidKeySpecException extends GeneralSecurityException {
+
+ /**
+ * The serial version identifier.
+ */
+ private static final long serialVersionUID = 3546139293998810778L;
+
+ /**
+ * Creates a new {@code InvalidKeySpecException} with the specified message.
+ *
+ * @param msg
+ * the detail message of this exception.
+ */
+ public InvalidKeySpecException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Creates a new {@code InvalidKeySpecException}.
+ */
+ public InvalidKeySpecException() {
+ }
+
+ /**
+ * Creates a new {@code InvalidKeySpecException} with the specified message
+ * and cause.
+ *
+ * @param message
+ * the detail message of this exception.
+ * @param cause
+ * the cause of this exception.
+ */
+ public InvalidKeySpecException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Creates a new {@code InvalidKeySpecException} with the specified cause.
+ *
+ * @param cause
+ * the cause of this exception.
+ */
+ public InvalidKeySpecException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/luni/src/main/java/java/security/spec/InvalidParameterSpecException.java b/luni/src/main/java/java/security/spec/InvalidParameterSpecException.java
new file mode 100644
index 0000000..e308dd8
--- /dev/null
+++ b/luni/src/main/java/java/security/spec/InvalidParameterSpecException.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.spec;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * The exception that is thrown when an invalid parameter specification is
+ * encountered.
+ */
+public class InvalidParameterSpecException extends GeneralSecurityException {
+
+ /**
+ * The serial version identifier.
+ */
+ private static final long serialVersionUID = -970468769593399342L;
+
+ /**
+ * Creates a new {@code InvalidParameterSpecException} with the specified
+ * message.
+ *
+ * @param msg
+ * the detail message for this exception.
+ */
+ public InvalidParameterSpecException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Creates a new {@code InvalidParameterSpecException}.
+ */
+ public InvalidParameterSpecException() {
+ }
+}
diff --git a/luni/src/main/java/java/security/spec/KeySpec.java b/luni/src/main/java/java/security/spec/KeySpec.java
new file mode 100644
index 0000000..fe8df1d
--- /dev/null
+++ b/luni/src/main/java/java/security/spec/KeySpec.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.spec;
+
+/**
+ * The marker interface for key specifications. The purpose is
+ * to group key specifications for cryptographic keys.
+ */
+public interface KeySpec {
+}
diff --git a/luni/src/main/java/java/security/spec/MGF1ParameterSpec.java b/luni/src/main/java/java/security/spec/MGF1ParameterSpec.java
new file mode 100644
index 0000000..6475d90
--- /dev/null
+++ b/luni/src/main/java/java/security/spec/MGF1ParameterSpec.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.spec;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * The parameter specification for the Mask Generation Function (MGF1) in
+ * the RSA-PSS Signature and OAEP Padding scheme.
+ * <p>
+ * Defined in the <a
+ * href="http://www.rsa.com/rsalabs/pubs/PKCS/html/pkcs-1.html">PKCS #1 v2.1</a>
+ * standard
+ */
+public class MGF1ParameterSpec implements AlgorithmParameterSpec {
+
+ /**
+ * The predefined MGF1 parameter specification with an "SHA-1" message
+ * digest.
+ */
+ public static final MGF1ParameterSpec SHA1 =
+ new MGF1ParameterSpec("SHA-1"); //$NON-NLS-1$
+
+ /**
+ * The predefined MGF1 parameter specification with an "SHA-256" message
+ * digest.
+ */
+ public static final MGF1ParameterSpec SHA256 =
+ new MGF1ParameterSpec("SHA-256"); //$NON-NLS-1$
+
+ /**
+ * The predefined MGF1 parameter specification with an "SHA-384" message
+ * digest.
+ */
+ public static final MGF1ParameterSpec SHA384 =
+ new MGF1ParameterSpec("SHA-384"); //$NON-NLS-1$
+
+ /**
+ * The predefined MGF1 parameter specification with an "SHA-512" message
+ * digest.
+ */
+ public static final MGF1ParameterSpec SHA512 =
+ new MGF1ParameterSpec("SHA-512"); //$NON-NLS-1$
+
+ // Message digest algorithm name
+ private final String mdName;
+
+ /**
+ * Creates a new {@code MGF1ParameterSpec} with the specified message digest
+ * algorithm name.
+ *
+ * @param mdName
+ * the name of the message digest algorithm.
+ */
+ public MGF1ParameterSpec(String mdName) {
+ this.mdName = mdName;
+ if (this.mdName == null) {
+ throw new NullPointerException(Messages.getString("security.80")); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Returns the name of the message digest algorithm.
+ *
+ * @return the name of the message digest algorithm.
+ */
+ public String getDigestAlgorithm() {
+ return mdName;
+ }
+}
diff --git a/luni/src/main/java/java/security/spec/PKCS8EncodedKeySpec.java b/luni/src/main/java/java/security/spec/PKCS8EncodedKeySpec.java
new file mode 100644
index 0000000..6910789
--- /dev/null
+++ b/luni/src/main/java/java/security/spec/PKCS8EncodedKeySpec.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.spec;
+
+/**
+ * The key specification for an encoded private key in ASN.1 format as defined
+ * in the PKCS#8 standard.
+ */
+public class PKCS8EncodedKeySpec extends EncodedKeySpec {
+
+ /**
+ * Creates a new {@code PKCS8EncodedKeySpec} with the specified encoded key
+ * bytes.
+ *
+ * @param encodedKey
+ * the encoded key bytes.
+ */
+ public PKCS8EncodedKeySpec(byte[] encodedKey) {
+ // Super class' ctor makes defensive parameter copy
+ super(encodedKey);
+ }
+
+ /**
+ * Returns a copy of the encoded key bytes.
+ *
+ * @return a copy of the encoded key bytes.
+ */
+ public byte[] getEncoded() {
+ // Super class' getEncoded() always returns a new array
+ return super.getEncoded();
+ }
+
+ /**
+ * Returns the name of the encoding format of this encoded key
+ * specification.
+ *
+ * @return the string "PKCS#8".
+ */
+ public final String getFormat() {
+ return "PKCS#8"; //$NON-NLS-1$
+ }
+}
diff --git a/luni/src/main/java/java/security/spec/PSSParameterSpec.java b/luni/src/main/java/java/security/spec/PSSParameterSpec.java
new file mode 100644
index 0000000..06c1d05
--- /dev/null
+++ b/luni/src/main/java/java/security/spec/PSSParameterSpec.java
@@ -0,0 +1,159 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.spec;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * The parameter specification for the RSA-PSS Signature scheme.
+ * <p>
+ * Defined in the <a
+ * href="http://www.rsa.com/rsalabs/pubs/PKCS/html/pkcs-1.html">PKCS #1 v2.1</a>
+ * standard.
+ */
+public class PSSParameterSpec implements AlgorithmParameterSpec {
+
+ /**
+ * The default parameter specification. It specifies the following parameters:
+ * <ul>
+ * <li>message digest: {@code "SHA-1"}</li>
+ * <li>mask generation function (<i>mgf</i>): {@code "MGF1"}</li>
+ * <li>parameters for the <i>mgf</i>: {@link MGF1ParameterSpec#SHA1}</li>
+ * <li>salt length: {@code 20}</li>
+ * <li>trailer field: {@code -1}</li>
+ * </ul>
+ */
+ public static final PSSParameterSpec DEFAULT = new PSSParameterSpec(20);
+
+ // Message digest algorithm name
+ private final String mdName;
+ // Mask generation function algorithm name
+ private final String mgfName;
+ // Mask generation function parameters
+ private final AlgorithmParameterSpec mgfSpec;
+ // Trailer field value
+ private final int trailerField;
+ // Salt length in bits
+ private final int saltLen;
+
+ /**
+ * Creates a new {@code PSSParameterSpec} with the specified salt length
+ * and the default values.
+ *
+ * @param saltLen
+ * the salt length (in bits).
+ * @throws IllegalArgumentException
+ * if {@code saltLen} is negative.
+ */
+ public PSSParameterSpec(int saltLen) {
+ if (saltLen < 0) {
+ throw new IllegalArgumentException(Messages.getString("security.7F")); //$NON-NLS-1$
+ }
+ this.saltLen = saltLen;
+ this.mdName = "SHA-1"; //$NON-NLS-1$
+ this.mgfName = "MGF1"; //$NON-NLS-1$
+ this.mgfSpec = MGF1ParameterSpec.SHA1;
+ this.trailerField = 1;
+ }
+
+ /**
+ * Creates a new {@code PSSParameterSpec} with the specified message digest
+ * name, mask generation function name, mask generation function parameters,
+ * salt length, and trailer field value.
+ *
+ * @param mdName
+ * the name of the message digest algorithm.
+ * @param mgfName
+ * the name of the mask generation function algorithm.
+ * @param mgfSpec
+ * the parameter for the mask generation function algorithm.
+ * @param saltLen
+ * the salt length (in bits).
+ * @param trailerField
+ * the trailer field value.
+ * @throws IllegalArgumentException
+ * if {@code saltLen} or {@code trailerField} is negative.
+ */
+ public PSSParameterSpec(String mdName, String mgfName,
+ AlgorithmParameterSpec mgfSpec, int saltLen, int trailerField) {
+
+ if (mdName == null) {
+ throw new NullPointerException(Messages.getString("security.80")); //$NON-NLS-1$
+ }
+ if (mgfName == null) {
+ throw new NullPointerException(Messages.getString("security.81")); //$NON-NLS-1$
+ }
+ if (saltLen < 0) {
+ throw new IllegalArgumentException(Messages.getString("security.7F")); //$NON-NLS-1$
+ }
+ if (trailerField < 0) {
+ throw new IllegalArgumentException(Messages.getString("security.82")); //$NON-NLS-1$
+ }
+ this.mdName = mdName;
+ this.mgfName = mgfName;
+ this.mgfSpec = mgfSpec;
+ this.saltLen = saltLen;
+ this.trailerField = trailerField;
+ }
+
+ /**
+ * Returns the length of the salt (in bits).
+ *
+ * @return the length of the salt (in bits).
+ */
+ public int getSaltLength() {
+ return saltLen;
+ }
+
+ /**
+ * Returns the name of the message digest algorithm.
+ *
+ * @return the name of the message digest algorithm.
+ */
+ public String getDigestAlgorithm() {
+ return mdName;
+ }
+
+ /**
+ * Returns the name of the mask generation function algorithm.
+ *
+ * @return the name of the mask generation function algorithm.
+ */
+ public String getMGFAlgorithm() {
+ return mgfName;
+ }
+
+ /**
+ * Returns the parameter for the mask generation function algorithm.
+ *
+ * @return the parameter for the mask generation function algorithm, or
+ * {@code null} if none specified.
+ */
+ public AlgorithmParameterSpec getMGFParameters() {
+ return mgfSpec;
+ }
+
+ /**
+ * Returns the trailer field value.
+ *
+ * @return the trailer field value.
+ */
+ public int getTrailerField() {
+ return trailerField;
+ }
+}
diff --git a/luni/src/main/java/java/security/spec/RSAKeyGenParameterSpec.java b/luni/src/main/java/java/security/spec/RSAKeyGenParameterSpec.java
new file mode 100644
index 0000000..2377c75
--- /dev/null
+++ b/luni/src/main/java/java/security/spec/RSAKeyGenParameterSpec.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.spec;
+
+import java.math.BigInteger;
+
+/**
+ * The parameter specification for generating an RSA key pair.
+ */
+public class RSAKeyGenParameterSpec implements AlgorithmParameterSpec {
+
+ /**
+ * The value of the public exponent {@code F0} = 3.
+ */
+ public static final BigInteger F0 = BigInteger.valueOf(3L);
+
+ /**
+ * The value of the public exponent {@code F4} = 65537.
+ */
+ public static final BigInteger F4 = BigInteger.valueOf(65537L);
+
+ // Key size
+ private final int keysize;
+ // Public Exponent
+ private final BigInteger publicExponent;
+
+ /**
+ * Creates a new {@code RSAKeyGenParameterSpec} with the specified key size
+ * and public exponent.
+ *
+ * @param keysize
+ * the size of the modulus (number of bits).
+ * @param publicExponent
+ * the value of the public exponent.
+ */
+ public RSAKeyGenParameterSpec(int keysize, BigInteger publicExponent) {
+ this.keysize = keysize;
+ this.publicExponent = publicExponent;
+ }
+
+ /**
+ * Returns the size of the modulus (number of bits).
+ *
+ * @return the size of the modulus (number of bits).
+ */
+ public int getKeysize() {
+ return keysize;
+ }
+
+ /**
+ * Returns the value of the public exponent.
+ *
+ * @return the value of the public exponent.
+ */
+ public BigInteger getPublicExponent() {
+ return publicExponent;
+ }
+}
diff --git a/luni/src/main/java/java/security/spec/RSAMultiPrimePrivateCrtKeySpec.java b/luni/src/main/java/java/security/spec/RSAMultiPrimePrivateCrtKeySpec.java
new file mode 100644
index 0000000..28469d7
--- /dev/null
+++ b/luni/src/main/java/java/security/spec/RSAMultiPrimePrivateCrtKeySpec.java
@@ -0,0 +1,205 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.spec;
+
+import java.math.BigInteger;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * The key specification of a RSA multi-prime private key with the Chinese
+ * Remainder Theorem (CRT) information values used.
+ * <p>
+ * Defined in the <a
+ * href="http://www.rsa.com/rsalabs/pubs/PKCS/html/pkcs-1.html">PKCS #1 v2.1</a>
+ * standard.
+ */
+public class RSAMultiPrimePrivateCrtKeySpec extends RSAPrivateKeySpec {
+ // Public Exponent
+ private final BigInteger publicExponent;
+ // Prime P
+ private final BigInteger primeP;
+ // Prime Q
+ private final BigInteger primeQ;
+ // Prime Exponent P
+ private final BigInteger primeExponentP;
+ // Prime Exponent Q
+ private final BigInteger primeExponentQ;
+ // CRT Coefficient
+ private final BigInteger crtCoefficient;
+ // Other Prime Info
+ private final RSAOtherPrimeInfo[] otherPrimeInfo;
+
+ /**
+ * Creates a new {@code RSAMultiPrimePrivateCrtKeySpec} with the specified
+ * modulus, public exponent, private exponent, prime factors, prime
+ * exponents, crt coefficient, and additional primes.
+ *
+ * @param modulus
+ * the modulus {@code n}.
+ * @param publicExponent
+ * the public exponent {@code e}.
+ * @param privateExponent
+ * the private exponent {@code d}.
+ * @param primeP
+ * the prime factor {@code p} of {@code n}.
+ * @param primeQ
+ * the prime factor {@code q} of {@code n}.
+ * @param primeExponentP
+ * the exponent of the prime {@code p}.
+ * @param primeExponentQ
+ * the exponent of the prime {@code q}.
+ * @param crtCoefficient
+ * the CRT coefficient {@code q^-1 mod p}.
+ * @param otherPrimeInfo
+ * the information for the additional primes or {@code null} if
+ * there are only the two primes ({@code p, q}).
+ * @throws IllegalArgumentException
+ * if {@code otherPrimeInfo} is not null but empty.
+ */
+ public RSAMultiPrimePrivateCrtKeySpec(
+ BigInteger modulus,
+ BigInteger publicExponent,
+ BigInteger privateExponent,
+ BigInteger primeP,
+ BigInteger primeQ,
+ BigInteger primeExponentP,
+ BigInteger primeExponentQ,
+ BigInteger crtCoefficient,
+ RSAOtherPrimeInfo[] otherPrimeInfo) {
+
+ super(modulus, privateExponent);
+
+ // Perform checks specified
+ if (modulus == null) {
+ throw new NullPointerException(Messages.getString("security.83", "modulus")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if (privateExponent == null) {
+ throw new NullPointerException(Messages.getString("security.83", "privateExponent")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if (publicExponent == null) {
+ throw new NullPointerException(Messages.getString("security.83", "publicExponent")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if (primeP == null) {
+ throw new NullPointerException(Messages.getString("security.83", "primeP")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if (primeQ == null) {
+ throw new NullPointerException(Messages.getString("security.83", "primeQ")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if (primeExponentP == null) {
+ throw new NullPointerException(Messages.getString("security.83", "primeExponentP")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if (primeExponentQ == null) {
+ throw new NullPointerException(Messages.getString("security.83", "primeExponentQ")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if (crtCoefficient == null) {
+ throw new NullPointerException(Messages.getString("security.83", "crtCoefficient")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ if (otherPrimeInfo != null) {
+ if (otherPrimeInfo.length == 0) {
+ throw new IllegalArgumentException(
+ Messages.getString("security.85")); //$NON-NLS-1$
+ }
+ // Clone array to prevent subsequent modification
+ this.otherPrimeInfo = new RSAOtherPrimeInfo[otherPrimeInfo.length];
+ System.arraycopy(otherPrimeInfo, 0,
+ this.otherPrimeInfo, 0, this.otherPrimeInfo.length);
+ } else {
+ this.otherPrimeInfo = null;
+ }
+ this.publicExponent = publicExponent;
+ this.primeP = primeP;
+ this.primeQ = primeQ;
+ this.primeExponentP = primeExponentP;
+ this.primeExponentQ = primeExponentQ;
+ this.crtCoefficient = crtCoefficient;
+ }
+
+ /**
+ * Returns the CRT coefficient, {@code q^-1 mod p}.
+ *
+ * @return the CRT coefficient, {@code q^-1 mod p}.
+ */
+ public BigInteger getCrtCoefficient() {
+ return crtCoefficient;
+ }
+
+ /**
+ * Returns the information for the additional primes.
+ *
+ * @return the information for the additional primes, or {@code null} if
+ * there are only the two primes ({@code p, q}).
+ */
+ public RSAOtherPrimeInfo[] getOtherPrimeInfo() {
+ // Clone array (if not null) to prevent subsequent modification
+ if (otherPrimeInfo == null) {
+ return null;
+ } else {
+ RSAOtherPrimeInfo[] ret =
+ new RSAOtherPrimeInfo[otherPrimeInfo.length];
+ System.arraycopy(otherPrimeInfo, 0, ret, 0, ret.length);
+ return ret;
+ }
+ }
+
+ /**
+ * Returns the exponent of the prime {@code p}.
+ *
+ * @return the exponent of the prime {@code p}.
+ */
+ public BigInteger getPrimeExponentP() {
+ return primeExponentP;
+ }
+
+ /**
+ * Returns the exponent of the prime {@code q}.
+ *
+ * @return the exponent of the prime {@code q}.
+ */
+ public BigInteger getPrimeExponentQ() {
+ return primeExponentQ;
+ }
+
+ /**
+ * Returns the prime factor {@code p}.
+ *
+ * @return the prime factor {@code p}.
+ */
+ public BigInteger getPrimeP() {
+ return primeP;
+ }
+
+ /**
+ * Returns the prime factor {@code q}.
+ *
+ * @return the prime factor {@code q}.
+ */
+ public BigInteger getPrimeQ() {
+ return primeQ;
+ }
+
+ /**
+ * Returns the public exponent {@code e}.
+ *
+ * @return the public exponent {@code e}.
+ */
+ public BigInteger getPublicExponent() {
+ return publicExponent;
+ }
+}
diff --git a/luni/src/main/java/java/security/spec/RSAOtherPrimeInfo.java b/luni/src/main/java/java/security/spec/RSAOtherPrimeInfo.java
new file mode 100644
index 0000000..177ddf5
--- /dev/null
+++ b/luni/src/main/java/java/security/spec/RSAOtherPrimeInfo.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.spec;
+
+import java.math.BigInteger;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * The additional prime information specified as triplet of primes, a prime
+ * exponent, and a Chinese Remainder Theorem (CRT) coefficient.
+ * <p>
+ * Defined in the <a
+ * href="http://www.rsa.com/rsalabs/pubs/PKCS/html/pkcs-1.html">PKCS #1 v2.1</a>
+ * standard.
+ */
+public class RSAOtherPrimeInfo {
+ // Prime
+ private final BigInteger prime;
+ // Prime Exponent
+ private final BigInteger primeExponent;
+ // CRT Coefficient
+ private final BigInteger crtCoefficient;
+
+ /**
+ * Creates a new {@code RSAOtherPrimeInfo} with the specified prime,
+ * exponent, and CRT coefficient.
+ *
+ * @param prime
+ * the prime factor.
+ * @param primeExponent
+ * the prime exponent.
+ * @param crtCoefficient
+ * the CRT coefficient.
+ */
+ public RSAOtherPrimeInfo(BigInteger prime,
+ BigInteger primeExponent, BigInteger crtCoefficient) {
+ if (prime == null) {
+ throw new NullPointerException(Messages.getString("security.83", "prime")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if (primeExponent == null) {
+ throw new NullPointerException(Messages.getString("security.83", "primeExponent")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if (crtCoefficient == null) {
+ throw new NullPointerException(Messages.getString("security.83", "crtCoefficient")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ this.prime = prime;
+ this.primeExponent = primeExponent;
+ this.crtCoefficient = crtCoefficient;
+ }
+
+ /**
+ * Returns the CRT coefficient.
+ *
+ * @return the CRT coefficient.
+ */
+ public final BigInteger getCrtCoefficient() {
+ return crtCoefficient;
+ }
+
+ /**
+ * Returns the prime factor.
+ *
+ * @return the prime factor.
+ */
+ public final BigInteger getPrime() {
+ return prime;
+ }
+
+ /**
+ * Returns the exponent.
+ *
+ * @return the exponent.
+ */
+ public final BigInteger getExponent() {
+ return primeExponent;
+ }
+}
diff --git a/luni/src/main/java/java/security/spec/RSAPrivateCrtKeySpec.java b/luni/src/main/java/java/security/spec/RSAPrivateCrtKeySpec.java
new file mode 100644
index 0000000..e786e9e
--- /dev/null
+++ b/luni/src/main/java/java/security/spec/RSAPrivateCrtKeySpec.java
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.spec;
+
+import java.math.BigInteger;
+
+/**
+ * The key specification of a RSA private key using Chinese Remainder Theorem
+ * (CRT) values.
+ * <p>
+ * Defined in the <a
+ * href="http://www.rsa.com/rsalabs/pubs/PKCS/html/pkcs-1.html">PKCS #1 v2.1</a>
+ * standard.
+ */
+public class RSAPrivateCrtKeySpec extends RSAPrivateKeySpec {
+ // Public Exponent
+ private final BigInteger publicExponent;
+ // Prime P
+ private final BigInteger primeP;
+ // Prime Q
+ private final BigInteger primeQ;
+ // Prime Exponent P
+ private final BigInteger primeExponentP;
+ // Prime Exponent Q
+ private final BigInteger primeExponentQ;
+ // CRT Coefficient
+ private final BigInteger crtCoefficient;
+
+ /**
+ * Creates a new {@code RSAMultiPrimePrivateCrtKeySpec} with the specified
+ * modulus, public exponent, private exponent, prime factors, prime
+ * exponents, crt coefficient, and additional primes.
+ *
+ * @param modulus
+ * the modulus {@code n}.
+ * @param publicExponent
+ * the public exponent {@code e}.
+ * @param privateExponent
+ * the private exponent {@code d}.
+ * @param primeP
+ * the prime factor {@code p} of {@code n}.
+ * @param primeQ
+ * the prime factor {@code q} of {@code n}.
+ * @param primeExponentP
+ * the exponent of the prime {@code p}.
+ * @param primeExponentQ
+ * the exponent of the prime {@code q}.
+ * @param crtCoefficient
+ * the CRT coefficient {@code q^-1 mod p}.
+ */
+ public RSAPrivateCrtKeySpec(BigInteger modulus,
+ BigInteger publicExponent,
+ BigInteger privateExponent,
+ BigInteger primeP,
+ BigInteger primeQ,
+ BigInteger primeExponentP,
+ BigInteger primeExponentQ,
+ BigInteger crtCoefficient) {
+
+ super(modulus, privateExponent);
+
+ this.publicExponent = publicExponent;
+ this.primeP = primeP;
+ this.primeQ = primeQ;
+ this.primeExponentP = primeExponentP;
+ this.primeExponentQ = primeExponentQ;
+ this.crtCoefficient = crtCoefficient;
+ }
+
+ /**
+ * Returns the CRT coefficient, {@code q^-1 mod p}.
+ *
+ * @return the CRT coefficient, {@code q^-1 mod p}.
+ */
+ public BigInteger getCrtCoefficient() {
+ return crtCoefficient;
+ }
+
+ /**
+ * Returns the exponent of the prime {@code p}.
+ *
+ * @return the exponent of the prime {@code p}.
+ */
+ public BigInteger getPrimeExponentP() {
+ return primeExponentP;
+ }
+
+ /**
+ * Returns the exponent of the prime {@code q}.
+ *
+ * @return the exponent of the prime {@code q}.
+ */
+ public BigInteger getPrimeExponentQ() {
+ return primeExponentQ;
+ }
+
+ /**
+ * Returns the prime factor {@code p}.
+ *
+ * @return the prime factor {@code p}.
+ */
+ public BigInteger getPrimeP() {
+ return primeP;
+ }
+
+ /**
+ * Returns the prime factor {@code q}.
+ *
+ * @return the prime factor {@code q}.
+ */
+ public BigInteger getPrimeQ() {
+ return primeQ;
+ }
+
+ /**
+ * Returns the public exponent {@code e}.
+ *
+ * @return the public exponent {@code e}.
+ */
+ public BigInteger getPublicExponent() {
+ return publicExponent;
+ }
+}
diff --git a/luni/src/main/java/java/security/spec/RSAPrivateKeySpec.java b/luni/src/main/java/java/security/spec/RSAPrivateKeySpec.java
new file mode 100644
index 0000000..c94420e
--- /dev/null
+++ b/luni/src/main/java/java/security/spec/RSAPrivateKeySpec.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.spec;
+
+import java.math.BigInteger;
+
+/**
+ * The key specification of a RSA private key.
+ * <p>
+ * Defined in the <a
+ * href="http://www.rsa.com/rsalabs/pubs/PKCS/html/pkcs-1.html">PKCS #1 v2.1</a>
+ * standard
+ */
+public class RSAPrivateKeySpec implements KeySpec {
+ // Modulus
+ private final BigInteger modulus;
+ // Private Exponent
+ private final BigInteger privateExponent;
+
+ /**
+ * Creates a new {@code RSAPrivateKeySpec} with the specified modulus and
+ * private exponent.
+ *
+ * @param modulus
+ * the modulus {@code n}.
+ * @param privateExponent
+ * the private exponent {@code e}
+ */
+ public RSAPrivateKeySpec(BigInteger modulus, BigInteger privateExponent) {
+ this.modulus = modulus;
+ this.privateExponent = privateExponent;
+ }
+
+ /**
+ * Returns the modulus {@code n}.
+ *
+ * @return the modulus {@code n}.
+ */
+ public BigInteger getModulus() {
+ return modulus;
+ }
+
+ /**
+ * Returns the private exponent {@code e}.
+ *
+ * @return the private exponent {@code e}.
+ */
+ public BigInteger getPrivateExponent() {
+ return privateExponent;
+ }
+}
diff --git a/luni/src/main/java/java/security/spec/RSAPublicKeySpec.java b/luni/src/main/java/java/security/spec/RSAPublicKeySpec.java
new file mode 100644
index 0000000..fe6de07
--- /dev/null
+++ b/luni/src/main/java/java/security/spec/RSAPublicKeySpec.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.spec;
+
+import java.math.BigInteger;
+
+/**
+ * The key specification of a RSA public key.
+ * <p>
+ * Defined in the <a
+ * href="http://www.rsa.com/rsalabs/pubs/PKCS/html/pkcs-1.html">PKCS #1 v2.1</a>
+ * standard.
+ */
+public class RSAPublicKeySpec implements KeySpec {
+ // Modulus
+ private final BigInteger modulus;
+ // Public Exponent
+ private final BigInteger publicExponent;
+
+ /**
+ * Creates a new {@code RSAPublicKeySpec} with the specified modulus and
+ * public exponent.
+ *
+ * @param modulus
+ * the modulus {@code n}.
+ * @param publicExponent
+ * the public exponent {@code d}.
+ */
+ public RSAPublicKeySpec(BigInteger modulus, BigInteger publicExponent) {
+ this.modulus = modulus;
+ this.publicExponent = publicExponent;
+ }
+
+ /**
+ * Returns the modulus {@code n}.
+ *
+ * @return the modulus {@code n}.
+ */
+ public BigInteger getModulus() {
+ return modulus;
+ }
+
+ /**
+ * Returns the public exponent {@code d}.
+ *
+ * @return the public exponent {@code d}.
+ */
+ public BigInteger getPublicExponent() {
+ return publicExponent;
+ }
+}
diff --git a/luni/src/main/java/java/security/spec/X509EncodedKeySpec.java b/luni/src/main/java/java/security/spec/X509EncodedKeySpec.java
new file mode 100644
index 0000000..61f3475
--- /dev/null
+++ b/luni/src/main/java/java/security/spec/X509EncodedKeySpec.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.spec;
+
+/**
+ * The key specification of an X.509 encoded key in ASN.1 format.
+ */
+public class X509EncodedKeySpec extends EncodedKeySpec {
+
+ /**
+ * Creates a new {@code X509EncodedKeySpec} with the specified encoded key
+ * bytes.
+ *
+ * @param encodedKey
+ * the encoded key bytes.
+ */
+ public X509EncodedKeySpec(byte[] encodedKey) {
+ // Super class' ctor makes defensive parameter copy
+ super(encodedKey);
+ }
+
+ /**
+ * Returns the encoded key bytes.
+ *
+ * @return the encoded key bytes.
+ */
+ public byte[] getEncoded() {
+ // Super class' getEncoded() always returns a new array
+ return super.getEncoded();
+ }
+
+ /**
+ * Returns the name of the encoding format of this encoded key
+ * specification.
+ *
+ * @return the string "X.509".
+ */
+ public final String getFormat() {
+ return "X.509"; //$NON-NLS-1$
+ }
+}
diff --git a/luni/src/main/java/java/security/spec/package.html b/luni/src/main/java/java/security/spec/package.html
new file mode 100644
index 0000000..d75aee6
--- /dev/null
+++ b/luni/src/main/java/java/security/spec/package.html
@@ -0,0 +1,18 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
+</head>
+<html>
+<body>
+<p>
+This package provides the classes and interfaces needed to specify keys and parameters for
+encryption and signing algorithms. The following standards are supported:
+(1) PKCS#1 RSA encryption standard;
+(2) FIPS-186 DSA (signature) standard;
+(3) PKCS#8 private key information standard.
+Keys may be specified via algorithm or in a more abstract and general way with ASN.1.
+The parameters for the Elliptic Curve (EC) encryption algorithm are only specified as
+input parameters to the relevant EC-generator.
+</p>
+</body>
+</html>