diff options
author | Peter Hallam <peterhal@google.com> | 2010-04-26 12:53:37 -0700 |
---|---|---|
committer | Peter Hallam <peterhal@google.com> | 2010-04-27 16:26:27 -0700 |
commit | cec4dd4b1d33f78997603d0f89c0d0e56e64dbcd (patch) | |
tree | e71d43da21749bfeb4524b0adec05c91d1f89a5f /luni/src/main/java/java/security | |
parent | f205f06be1ce65f132be1b7c850675086f26c0f7 (diff) | |
download | libcore-cec4dd4b1d33f78997603d0f89c0d0e56e64dbcd.zip libcore-cec4dd4b1d33f78997603d0f89c0d0e56e64dbcd.tar.gz libcore-cec4dd4b1d33f78997603d0f89c0d0e56e64dbcd.tar.bz2 |
merge more modules into luni
Diffstat (limited to 'luni/src/main/java/java/security')
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 "<all actions>". + * + * @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<T> permClass + * <dd>The class to which all {@code BasicPermission}s in this + * BasicPermissionCollection belongs. + * <dt>Hashtable<K,V> 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://*/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("www.example.com", "connect,resolve") + * sp1 = new SocketPermission("www.example.com", "resolve,connect") + * 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 "neutral" + * 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> |