From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- .../javax/crypto/keyring/AuthenticatedEntry.java | 176 +++++++++ .../gnu/javax/crypto/keyring/BaseKeyring.java | 158 ++++++++ .../gnu/javax/crypto/keyring/BinaryDataEntry.java | 111 ++++++ .../gnu/javax/crypto/keyring/CertPathEntry.java | 112 ++++++ .../gnu/javax/crypto/keyring/CertificateEntry.java | 128 ++++++ .../gnu/javax/crypto/keyring/CompressedEntry.java | 93 +++++ .../gnu/javax/crypto/keyring/EncryptedEntry.java | 191 +++++++++ .../classpath/gnu/javax/crypto/keyring/Entry.java | 179 +++++++++ .../gnu/javax/crypto/keyring/EnvelopeEntry.java | 439 +++++++++++++++++++++ .../javax/crypto/keyring/GnuPrivateKeyring.java | 368 +++++++++++++++++ .../gnu/javax/crypto/keyring/GnuPublicKeyring.java | 151 +++++++ .../gnu/javax/crypto/keyring/IKeyring.java | 162 ++++++++ .../gnu/javax/crypto/keyring/IPrivateKeyring.java | 144 +++++++ .../gnu/javax/crypto/keyring/IPublicKeyring.java | 82 ++++ .../crypto/keyring/MalformedKeyringException.java | 55 +++ .../crypto/keyring/MaskableEnvelopeEntry.java | 135 +++++++ .../javax/crypto/keyring/MeteredInputStream.java | 127 ++++++ .../crypto/keyring/PasswordAuthenticatedEntry.java | 286 ++++++++++++++ .../crypto/keyring/PasswordEncryptedEntry.java | 293 ++++++++++++++ .../crypto/keyring/PasswordProtectedEntry.java | 57 +++ .../gnu/javax/crypto/keyring/PrimitiveEntry.java | 112 ++++++ .../gnu/javax/crypto/keyring/PrivateKeyEntry.java | 194 +++++++++ .../gnu/javax/crypto/keyring/Properties.java | 203 ++++++++++ .../gnu/javax/crypto/keyring/PublicKeyEntry.java | 162 ++++++++ 24 files changed, 4118 insertions(+) create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/AuthenticatedEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/BaseKeyring.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/BinaryDataEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/CertPathEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/CertificateEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/CompressedEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/EncryptedEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/Entry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/EnvelopeEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/GnuPrivateKeyring.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/GnuPublicKeyring.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/IKeyring.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/IPrivateKeyring.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/IPublicKeyring.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/MalformedKeyringException.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/MeteredInputStream.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/PasswordProtectedEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/PrimitiveEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/PrivateKeyEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/Properties.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/PublicKeyEntry.java (limited to 'libjava/classpath/gnu/javax/crypto/keyring') diff --git a/libjava/classpath/gnu/javax/crypto/keyring/AuthenticatedEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/AuthenticatedEntry.java new file mode 100644 index 000000000..91c3bc6e2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/AuthenticatedEntry.java @@ -0,0 +1,176 @@ +/* AuthenticatedEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import gnu.java.security.Registry; +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; +import gnu.javax.crypto.mac.MacOutputStream; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.security.InvalidKeyException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; + +public final class AuthenticatedEntry + extends MaskableEnvelopeEntry + implements Registry +{ + public static final int TYPE = 2; + + public AuthenticatedEntry(String mac, int macLen, Properties properties) + { + super(TYPE, properties); + if (macLen <= 0) + throw new IllegalArgumentException("invalid mac length"); + this.properties.put("mac", mac); + this.properties.put("maclen", String.valueOf(macLen)); + setMasked(false); + } + + private AuthenticatedEntry() + { + super(TYPE); + setMasked(true); + } + + public static AuthenticatedEntry decode(DataInputStream in) + throws IOException + { + AuthenticatedEntry entry = new AuthenticatedEntry(); + entry.properties.decode(in); + if (! entry.properties.containsKey("mac")) + throw new MalformedKeyringException("no mac specified"); + if (! entry.properties.containsKey("maclen")) + throw new MalformedKeyringException("no mac length specified"); + return entry; + } + + /** + * Computes the mac over this envelope's data. This method must be + * called before this entry in encoded. + * + * @param key The key to authenticate with. + * @throws IOException If encoding fails. + * @throws InvalidKeyException If the supplied key is bad. + */ + public void authenticate(byte[] key) throws IOException, InvalidKeyException + { + if (isMasked()) + throw new IllegalStateException("entry is masked"); + IMac m = getMac(key); + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + MacOutputStream macout = new MacOutputStream(bout, m); + DataOutputStream out2 = new DataOutputStream(macout); + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry entry = (Entry) it.next(); + entry.encode(out2); + } + bout.write(m.digest()); + payload = bout.toByteArray(); + } + + /** + * Verifies this entry's payload. This method will unmask this entry, thus it + * must be called before accessing its contents. + * + * @param key The key to use to authenticate. + * @throws InvalidKeyException If the given key is improper. + */ + public void verify(byte[] key) throws InvalidKeyException + { + if (! isMasked() || payload == null) + return; + IMac m = getMac(key); + m.update(payload, 0, payload.length - m.macSize()); + byte[] macValue = new byte[m.macSize()]; + System.arraycopy(payload, payload.length - macValue.length, macValue, 0, + macValue.length); + if (! Arrays.equals(macValue, m.digest())) + throw new IllegalArgumentException("MAC verification failed"); + try + { + int len = payload.length - m.macSize(); + ByteArrayInputStream bais = new ByteArrayInputStream(payload, 0, len); + DataInputStream in = new DataInputStream(bais); + decodeEnvelope(in); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("malformed keyring fragment"); + } + setMasked(false); + payload = null; + } + + protected void encodePayload() throws IOException + { + if (payload == null) + throw new IllegalStateException("not authenticated"); + } + + private IMac getMac(byte[] key) throws InvalidKeyException + { + IMac mac = MacFactory.getInstance(properties.get("mac")); + if (mac == null) + throw new IllegalArgumentException("no such mac: " + properties.get("mac")); + int maclen = 0; + if (! properties.containsKey("maclen")) + throw new IllegalArgumentException("no MAC length"); + try + { + maclen = Integer.parseInt(properties.get("maclen")); + } + catch (NumberFormatException nfe) + { + throw new IllegalArgumentException("bad MAC length"); + } + HashMap macAttr = new HashMap(); + macAttr.put(IMac.MAC_KEY_MATERIAL, key); + macAttr.put(IMac.TRUNCATED_SIZE, Integer.valueOf(maclen)); + mac.init(macAttr); + return mac; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/BaseKeyring.java b/libjava/classpath/gnu/javax/crypto/keyring/BaseKeyring.java new file mode 100644 index 000000000..e93ca8fa3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/BaseKeyring.java @@ -0,0 +1,158 @@ +/* BaseKeyring.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import gnu.java.security.Registry; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +public abstract class BaseKeyring + implements IKeyring +{ + /** The top-level keyring data. */ + protected PasswordAuthenticatedEntry keyring; + protected CompressedEntry keyring2; + + public BaseKeyring() + { + } + + public void load(Map attributes) throws IOException + { + InputStream in = (InputStream) attributes.get(KEYRING_DATA_IN); + if (in == null) + throw new IllegalArgumentException("no input stream"); + char[] password = (char[]) attributes.get(KEYRING_PASSWORD); + if (password == null) + password = new char[0]; + + if (in.read() != Registry.GKR_MAGIC[0] + || in.read() != Registry.GKR_MAGIC[1] + || in.read() != Registry.GKR_MAGIC[2] + || in.read() != Registry.GKR_MAGIC[3]) + throw new MalformedKeyringException("magic"); + + load(in, password); + List l = keyring.getEntries(); + if (l.size() == 1 && (l.get(0) instanceof CompressedEntry)) + keyring2 = (CompressedEntry) l.get(0); + } + + public void store(Map attributes) throws IOException + { + OutputStream out = (OutputStream) attributes.get(KEYRING_DATA_OUT); + if (out == null) + throw new IllegalArgumentException("no output stream"); + char[] password = (char[]) attributes.get(KEYRING_PASSWORD); + if (password == null) + password = new char[0]; + if (keyring == null) + throw new IllegalStateException("empty keyring"); + + out.write(Registry.GKR_MAGIC); + store(out, password); + } + + public void reset() + { + keyring = null; + } + + public int size() + { + if (keyring == null) + throw new IllegalStateException("keyring not loaded"); + return ((StringTokenizer) aliases()).countTokens(); + } + + public Enumeration aliases() + { + if (keyring == null) + throw new IllegalStateException("keyring not loaded"); + return new StringTokenizer(keyring.getAliasList(), ";"); + } + + public boolean containsAlias(String alias) + { + if (keyring == null) + throw new IllegalStateException("keyring not loaded"); + return keyring.containsAlias(alias); + } + + public List get(String alias) + { + if (keyring == null) + throw new IllegalStateException("keyring not loaded"); + return keyring.get(alias); + } + + public void add(Entry entry) + { + if (keyring == null) + throw new IllegalStateException("keyring not loaded"); + if (keyring2 != null) + keyring2.add(entry); + else + keyring.add(entry); + } + + public void remove(String alias) + { + if (keyring == null) + throw new IllegalStateException("keyring not loaded"); + keyring.remove(alias); + } + + protected String fixAlias(String alias) + { + return alias.replace(';', '_'); + } + + protected abstract void load(InputStream in, char[] password) + throws IOException; + + protected abstract void store(OutputStream out, char[] password) + throws IOException; +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/BinaryDataEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/BinaryDataEntry.java new file mode 100644 index 000000000..8fb1e0f39 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/BinaryDataEntry.java @@ -0,0 +1,111 @@ +/* BinaryDataEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.Date; + +/** + * A binary data entry is a primitive entry that simply contains some amount of + * arbitrary binary data and an optional content type. + */ +public class BinaryDataEntry + extends PrimitiveEntry +{ + public static final int TYPE = 9; + + /** + * Creates a new binary data entry. + * + * @param contentType The content type of this entry. This parameter can be + * null if no content type is needed. + * @param data The data. + * @param creationDate The creation date. + * @param properties This entry's properties. + */ + public BinaryDataEntry(String contentType, byte[] data, Date creationDate, + Properties properties) + { + super(TYPE, creationDate, properties); + if (data == null) + throw new IllegalArgumentException("no data"); + payload = (byte[]) data.clone(); + if (contentType != null) + this.properties.put("content-type", contentType); + } + + private BinaryDataEntry() + { + super(TYPE); + } + + public static BinaryDataEntry decode(DataInputStream in) throws IOException + { + BinaryDataEntry entry = new BinaryDataEntry(); + entry.defaultDecode(in); + return entry; + } + + /** + * Returns the content type of this entry, or null if this + * property is not set. + * + * @return The content type. + */ + public String getContentType() + { + return properties.get("content-type"); + } + + /** + * Returns this object's data field. + * + * @return The data. + */ + public byte[] getData() + { + return getPayload(); + } + + protected void encodePayload() + { + // Empty. + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/CertPathEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/CertPathEntry.java new file mode 100644 index 000000000..e798a93ce --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/CertPathEntry.java @@ -0,0 +1,112 @@ +/* CertPathEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.util.Date; + +/** + * A primitive entry that contains a path of X.509 certificates. + */ +public final class CertPathEntry + extends PrimitiveEntry +{ + public static final int TYPE = 8; + private Certificate[] path; + + public CertPathEntry(Certificate[] path, Date creationDate, + Properties properties) + { + super(TYPE, creationDate, properties); + if (path == null || path.length == 0) + throw new IllegalArgumentException("no certificate path"); + this.path = (Certificate[]) path.clone(); + } + + private CertPathEntry() + { + super(TYPE); + } + + public static CertPathEntry decode(DataInputStream in) throws IOException + { + CertPathEntry entry = new CertPathEntry(); + entry.properties.decode(in); + entry.makeCreationDate(); + int len = in.readInt(); + MeteredInputStream in2 = new MeteredInputStream(in, len); + try + { + CertificateFactory fact = CertificateFactory.getInstance("X.509"); + entry.path = (Certificate[]) fact.generateCertificates(in2).toArray(new Certificate[0]); + } + catch (CertificateException ce) + { + throw new MalformedKeyringException(ce.toString()); + } + return entry; + } + + public Certificate[] getCertPath() + { + return path; + } + + protected void encodePayload() throws IOException + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + byte[] enc = null; + try + { + for (int i = 0; i < path.length; i++) + bout.write(path[i].getEncoded()); + } + catch (CertificateEncodingException cee) + { + throw new IOException(cee.toString()); + } + payload = bout.toByteArray(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/CertificateEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/CertificateEntry.java new file mode 100644 index 000000000..f574a4fe4 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/CertificateEntry.java @@ -0,0 +1,128 @@ +/* CertificateEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.DataInputStream; +import java.io.IOException; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.util.Date; + +/** + * An immutable class representing a trusted certificate entry. + */ +public final class CertificateEntry + extends PrimitiveEntry +{ + public static final int TYPE = 5; + /** The certificate. */ + private Certificate certificate; + + /** + * Creates a new certificate entry. + * + * @param certificate The certificate. + * @param creationDate The creation date. + * @param properties The alias. + * @throws IllegalArgumentException If any argument is null, or if the alias + * is empty. + */ + public CertificateEntry(Certificate certificate, Date creationDate, + Properties properties) + { + super(TYPE, creationDate, properties); + if (certificate == null) + throw new IllegalArgumentException("no certificate"); + this.certificate = certificate; + this.properties.put("type", certificate.getType()); + } + + private CertificateEntry() + { + super(TYPE); + } + + public static CertificateEntry decode(DataInputStream in) throws IOException + { + CertificateEntry entry = new CertificateEntry(); + entry.properties.decode(in); + entry.makeCreationDate(); + String type = entry.properties.get("type"); + if (type == null) + throw new MalformedKeyringException("no certificate type"); + int len = in.readInt(); + MeteredInputStream in2 = new MeteredInputStream(in, len); + try + { + CertificateFactory fact = CertificateFactory.getInstance(type); + entry.certificate = fact.generateCertificate(in2); + } + catch (CertificateException ce) + { + throw new MalformedKeyringException(ce.toString()); + } + if (! in2.limitReached()) + throw new MalformedKeyringException("extra data at end of payload"); + return entry; + } + + /** + * Returns this entry's certificate. + * + * @return The certificate. + */ + public Certificate getCertificate() + { + return certificate; + } + + protected void encodePayload() throws IOException + { + try + { + payload = certificate.getEncoded(); + } + catch (CertificateEncodingException cee) + { + throw new IOException(cee.toString()); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/CompressedEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/CompressedEntry.java new file mode 100644 index 000000000..8949a41e9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/CompressedEntry.java @@ -0,0 +1,93 @@ +/* CompressedEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Iterator; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.InflaterInputStream; + +public class CompressedEntry + extends EnvelopeEntry +{ + public static final int TYPE = 4; + + public CompressedEntry(Properties properties) + { + super(TYPE, properties); + this.properties.put("algorithm", "DEFLATE"); + } + + private CompressedEntry() + { + this(new Properties()); + } + + public static CompressedEntry decode(DataInputStream in) throws IOException + { + CompressedEntry entry = new CompressedEntry(); + entry.properties.decode(in); + String alg = entry.properties.get("algorithm"); + if (alg == null) + throw new MalformedKeyringException("no compression algorithm"); + if (! alg.equalsIgnoreCase("DEFLATE")) + throw new MalformedKeyringException("unsupported compression algorithm: " + + alg); + int len = in.readInt(); + MeteredInputStream min = new MeteredInputStream(in, len); + InflaterInputStream infin = new InflaterInputStream(min); + DataInputStream in2 = new DataInputStream(infin); + entry.decodeEnvelope(in2); + return entry; + } + + protected void encodePayload() throws IOException + { + ByteArrayOutputStream buf = new ByteArrayOutputStream(1024); + DeflaterOutputStream dout = new DeflaterOutputStream(buf); + DataOutputStream out2 = new DataOutputStream(dout); + for (Iterator it = entries.iterator(); it.hasNext();) + ((Entry) it.next()).encode(out2); + dout.finish(); + payload = buf.toByteArray(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/EncryptedEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/EncryptedEntry.java new file mode 100644 index 000000000..68a6c2c8a --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/EncryptedEntry.java @@ -0,0 +1,191 @@ +/* EncryptedEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.mode.ModeFactory; +import gnu.javax.crypto.pad.IPad; +import gnu.javax.crypto.pad.PadFactory; +import gnu.javax.crypto.pad.WrongPaddingException; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.security.InvalidKeyException; +import java.util.HashMap; +import java.util.Iterator; + +public class EncryptedEntry extends MaskableEnvelopeEntry implements Registry +{ + public static final int TYPE = 0; + + public EncryptedEntry(String cipher, String mode, Properties properties) + { + super(TYPE, properties); + if (cipher == null || mode == null) + throw new IllegalArgumentException("neither cipher nor mode can be null"); + properties.put("cipher", cipher); + properties.put("mode", mode); + setMasked(false); + } + + private EncryptedEntry() + { + super(TYPE, new Properties()); + setMasked(true); + } + + public static EncryptedEntry decode(DataInputStream in) throws IOException + { + EncryptedEntry entry = new EncryptedEntry(); + entry.defaultDecode(in); + if (! entry.properties.containsKey("cipher")) + throw new MalformedKeyringException("no cipher"); + if (! entry.properties.containsKey("cipher")) + throw new MalformedKeyringException("no cipher"); + return entry; + } + + public void decrypt(byte[] key, byte[] iv) throws IllegalArgumentException, + WrongPaddingException + { + if (! isMasked() || payload == null) + return; + IMode mode = getMode(key, iv, IMode.DECRYPTION); + IPad padding = null; + padding = PadFactory.getInstance("PKCS7"); + padding.init(mode.currentBlockSize()); + byte[] buf = new byte[payload.length]; + int count = 0; + for (int i = 0; i < payload.length; i++) + { + mode.update(payload, count, buf, count); + count += mode.currentBlockSize(); + } + int padlen = padding.unpad(buf, 0, buf.length); + int len = buf.length - padlen; + DataInputStream in = new DataInputStream(new ByteArrayInputStream(buf, 0, len)); + try + { + decodeEnvelope(in); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("decryption failed"); + } + setMasked(false); + payload = null; + } + + public void encrypt(byte[] key, byte[] iv) throws IOException + { + IMode mode = getMode(key, iv, IMode.ENCRYPTION); + IPad pad = PadFactory.getInstance("PKCS7"); + pad.init(mode.currentBlockSize()); + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + DataOutputStream out2 = new DataOutputStream(bout); + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry entry = (Entry) it.next(); + entry.encode(out2); + } + byte[] plaintext = bout.toByteArray(); + byte[] padding = pad.pad(plaintext, 0, plaintext.length); + payload = new byte[plaintext.length + padding.length]; + byte[] lastBlock = new byte[mode.currentBlockSize()]; + int l = mode.currentBlockSize() - padding.length; + System.arraycopy(plaintext, plaintext.length - l, lastBlock, 0, l); + System.arraycopy(padding, 0, lastBlock, l, padding.length); + int count = 0; + while (count + mode.currentBlockSize() < plaintext.length) + { + mode.update(plaintext, count, payload, count); + count += mode.currentBlockSize(); + } + mode.update(lastBlock, 0, payload, count); + } + + public void encodePayload() throws IOException + { + if (payload == null) + throw new IOException("not encrypted"); + } + + private IMode getMode(byte[] key, byte[] iv, int state) + { + IBlockCipher cipher = CipherFactory.getInstance(properties.get("cipher")); + if (cipher == null) + throw new IllegalArgumentException("no such cipher: " + properties.get("cipher")); + int blockSize = cipher.defaultBlockSize(); + if (properties.containsKey("block-size")) + { + try + { + blockSize = Integer.parseInt(properties.get("block-size")); + } + catch (NumberFormatException nfe) + { + throw new IllegalArgumentException("bad block size: " + + nfe.getMessage()); + } + } + IMode mode = ModeFactory.getInstance(properties.get("mode"), cipher, blockSize); + if (mode == null) + throw new IllegalArgumentException("no such mode: " + properties.get("mode")); + + HashMap modeAttr = new HashMap(); + modeAttr.put(IMode.KEY_MATERIAL, key); + modeAttr.put(IMode.STATE, Integer.valueOf(state)); + modeAttr.put(IMode.IV, iv); + try + { + mode.init(modeAttr); + } + catch (InvalidKeyException ike) + { + throw new IllegalArgumentException(ike.toString()); + } + return mode; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/Entry.java b/libjava/classpath/gnu/javax/crypto/keyring/Entry.java new file mode 100644 index 000000000..d45924940 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/Entry.java @@ -0,0 +1,179 @@ +/* Entry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import gnu.java.security.Configuration; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.logging.Logger; + +/** + * An immutable class representing a single entry in a keyring. + */ +public abstract class Entry +{ + private static final Logger log = Logger.getLogger(Entry.class.getName()); + private static final String[] TYPES = new String[] { + "Encrypted", + "PasswordEncrypted", + "Authenticated", + "PasswordAuthenticated", + "Compressed", + "Certificate", + "PublicKey", + "PrivateKey", + "CertPath", + "BinaryData" }; + /** This entry's type identifier. */ + protected int type; + /** This entry's property set. */ + protected Properties properties; + /** This entry's payload. */ + protected byte[] payload; + + /** + * Creates a new Entry. + * + * @param type This entry's type. + * @param properties This entry's properties. + * @throws IllegalArgumentException If the properties argument is null, or if + * the type is out of range. + */ + protected Entry(int type, Properties properties) + { + if (type < 0 || type > 255) + throw new IllegalArgumentException("invalid packet type"); + if (properties == null) + throw new IllegalArgumentException("no properties"); + this.type = type; + this.properties = (Properties) properties.clone(); + } + + /** + * Constructor for use by subclasses. + */ + protected Entry(final int type) + { + if (type < 0 || type > 255) + throw new IllegalArgumentException("invalid packet type"); + this.type = type; + properties = new Properties(); + } + + /** + * Returns this entry's properties object. The properties are cloned before + * being returned. + * + * @return The properties. + */ + public Properties getProperties() + { + return (Properties) properties.clone(); + } + + /** + * Returns this entry's payload data, or null if + */ + public byte[] getPayload() + { + if (payload == null) + return null; + return (byte[]) payload.clone(); + } + + /** + * This method is called when this entry needs to be written to an output + * stream. + * + * @param out The stream to write to. + * @throws IOException If an I/O exception occurs. + */ + public void encode(DataOutputStream out) throws IOException + { + if (payload == null) + encodePayload(); + if (out == null) + return; + out.write(type); + properties.encode(out); + out.writeInt(payload.length); + out.write(payload); + } + + public String toString() + { + return new StringBuilder("Entry{") + .append("type=").append(TYPES[type]) + .append(", properties=").append(properties) + .append(", payload=") + .append(payload == null ? "-" : "byte[" + payload.length + "]") + .append( "}") + .toString(); + } + + /** + * Generic decoding method, which simply decodes the properties field + * and reads the payload field. + * + * @param in The input data stream. + * @throws IOException If an I/O error occurs. + */ + protected void defaultDecode(DataInputStream in) throws IOException + { + properties = new Properties(); + properties.decode(in); + int len = in.readInt(); + if (len < 0) + throw new IOException("corrupt length"); + if (Configuration.DEBUG) + log.fine("About to instantiate new payload byte array for " + this); + payload = new byte[len]; + in.readFully(payload); + } + + /** + * This method is called of subclasses when the payload data needs to be + * created. + * + * @throws IOException If an encoding error occurs. + */ + protected abstract void encodePayload() throws IOException; +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/EnvelopeEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/EnvelopeEntry.java new file mode 100644 index 000000000..76aba7d7b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/EnvelopeEntry.java @@ -0,0 +1,439 @@ +/* EnvelopeEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import gnu.java.security.Configuration; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.StringTokenizer; +import java.util.logging.Logger; + +/** + * An envelope entry is a generic container for some number of primitive and + * other envelope entries. + */ +public abstract class EnvelopeEntry + extends Entry +{ + private static final Logger log = Logger.getLogger(EnvelopeEntry.class.getName()); + /** The envelope that contains this one (if any). */ + protected EnvelopeEntry containingEnvelope; + /** The contained entries. */ + protected List entries; + + public EnvelopeEntry(int type, Properties properties) + { + super(type, properties); + entries = new LinkedList(); + if (this.properties.get("alias-list") != null) + this.properties.remove("alias-list"); + } + + protected EnvelopeEntry(int type) + { + super(type); + entries = new LinkedList(); + } + + /** + * Adds an entry to this envelope. + * + * @param entry The entry to add. + */ + public void add(Entry entry) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "add", entry); + if (! containsEntry(entry)) + { + if (entry instanceof EnvelopeEntry) + ((EnvelopeEntry) entry).setContainingEnvelope(this); + entries.add(entry); + if (Configuration.DEBUG) + log.fine("Payload is " + (payload == null ? "" : "not ") + "null"); + makeAliasList(); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "add"); + } + + /** + * Tests if this envelope contains a primitive entry with the given alias. + * + * @param alias The alias to test. + * @return True if this envelope (or one of the contained envelopes) contains + * a primitive entry with the given alias. + */ + public boolean containsAlias(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "containsAlias", alias); + String aliases = getAliasList(); + if (Configuration.DEBUG) + log.fine("aliases = [" + aliases + "]"); + boolean result = false; + if (aliases != null) + { + StringTokenizer tok = new StringTokenizer(aliases, ";"); + while (tok.hasMoreTokens()) + if (tok.nextToken().equals(alias)) + { + result = true; + break; + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "containsAlias", + Boolean.valueOf(result)); + return result; + } + + /** + * Tests if this envelope contains the given entry. + * + * @param entry The entry to test. + * @return True if this envelope contains the given entry. + */ + public boolean containsEntry(Entry entry) + { + if (entry instanceof EnvelopeEntry) + return entries.contains(entry); + if (entry instanceof PrimitiveEntry) + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e.equals(entry)) + return true; + if ((e instanceof EnvelopeEntry) + && ((EnvelopeEntry) e).containsEntry(entry)) + return true; + } + return false; + } + + /** + * Returns a copy of all entries this envelope contains. + * + * @return All contained entries. + */ + public List getEntries() + { + return new ArrayList(entries); + } + + /** + * Gets all primitive entries that have the given alias. If there are any + * masked entries that contain the given alias, they will be returned as well. + * + * @param alias The alias of the entries to get. + * @return A list of all primitive entries that have the given alias. + */ + public List get(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "get", alias); + List result = new LinkedList(); + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof EnvelopeEntry) + { + EnvelopeEntry ee = (EnvelopeEntry) e; + if (! ee.containsAlias(alias)) + continue; + if (ee instanceof MaskableEnvelopeEntry) + { + MaskableEnvelopeEntry mee = (MaskableEnvelopeEntry) ee; + if (mee.isMasked()) + { + if (Configuration.DEBUG) + log.fine("Processing masked entry: " + mee); + result.add(mee); + continue; + } + } + if (Configuration.DEBUG) + log.fine("Processing unmasked entry: " + ee); + result.addAll(ee.get(alias)); + } + else if (e instanceof PrimitiveEntry) + { + PrimitiveEntry pe = (PrimitiveEntry) e; + if (pe.getAlias().equals(alias)) + result.add(e); + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "get", result); + return result; + } + + /** + * Returns the list of all aliases contained by this envelope, separated by a + * semicolon (';'). + * + * @return The list of aliases. + */ + public String getAliasList() + { + String list = properties.get("alias-list"); + if (list == null) + return ""; + else + return list; + } + + /** + * Removes the specified entry. + * + * @param entry The entry. + * @return True if an entry was removed. + */ + public boolean remove(Entry entry) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "remove", entry); + boolean ret = false; + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof EnvelopeEntry) + { + if (e == entry) + { + it.remove(); + ret = true; + break; + } + if (((EnvelopeEntry) e).remove(entry)) + { + ret = true; + break; + } + } + else if (e instanceof PrimitiveEntry) + { + if (((PrimitiveEntry) e).equals(entry)) + { + it.remove(); + ret = true; + break; + } + } + } + if (ret) + { + if (Configuration.DEBUG) + log.fine("State before: " + this); + payload = null; + makeAliasList(); + if (Configuration.DEBUG) + log.fine("State after: " + this); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "remove", Boolean.valueOf(ret)); + return ret; + } + + /** + * Removes all primitive entries that have the specified alias. + * + * @param alias The alias of the entries to remove. + * @return true if alias was present and was + * successfully trmoved. Returns false if + * alias was not present in the list of aliases in this + * envelope. + */ + public boolean remove(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "remove", alias); + boolean result = false; + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof EnvelopeEntry) + { + EnvelopeEntry ee = (EnvelopeEntry) e; + result = ee.remove(alias) || result; + } + else if (e instanceof PrimitiveEntry) + { + PrimitiveEntry pe = (PrimitiveEntry) e; + if (pe.getAlias().equals(alias)) + { + it.remove(); + result = true; + } + } + } + if (result) + { + if (Configuration.DEBUG) + log.fine("State before: " + this); + payload = null; + makeAliasList(); + if (Configuration.DEBUG) + log.fine("State after: " + this); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "remove", Boolean.valueOf(result)); + return result; + } + + public String toString() + { + return new StringBuilder("Envelope{") + .append(super.toString()) + .append(", entries=").append(entries) + .append("}") + .toString(); + } + + // Protected methods. + // ------------------------------------------------------------------------ + + protected void encodePayload() throws IOException + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + DataOutputStream out = new DataOutputStream(bout); + for (Iterator it = entries.iterator(); it.hasNext();) + ((Entry) it.next()).encode(out); + } + + protected void setContainingEnvelope(EnvelopeEntry e) + { + if (containingEnvelope != null) + throw new IllegalArgumentException("envelopes may not be shared"); + containingEnvelope = e; + } + + protected void decodeEnvelope(DataInputStream in) throws IOException + { + this.entries.clear(); + while (true) + { + int type = in.read(); + switch (type) + { + case EncryptedEntry.TYPE: + add(EncryptedEntry.decode(in)); + break; + case PasswordEncryptedEntry.TYPE: + add(PasswordEncryptedEntry.decode(in)); + break; + case PasswordAuthenticatedEntry.TYPE: + add(PasswordAuthenticatedEntry.decode(in)); + break; + case AuthenticatedEntry.TYPE: + add(AuthenticatedEntry.decode(in)); + break; + case CompressedEntry.TYPE: + add(CompressedEntry.decode(in)); + break; + case CertificateEntry.TYPE: + add(CertificateEntry.decode(in)); + break; + case PublicKeyEntry.TYPE: + add(PublicKeyEntry.decode(in)); + break; + case PrivateKeyEntry.TYPE: + add(PrivateKeyEntry.decode(in)); + break; + case CertPathEntry.TYPE: + add(CertPathEntry.decode(in)); + break; + case BinaryDataEntry.TYPE: + add(BinaryDataEntry.decode(in)); + break; + case -1: + return; + default: + throw new MalformedKeyringException("unknown type " + type); + } + } + } + + private void makeAliasList() + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "makeAliasList"); + if (! entries.isEmpty()) + { + StringBuilder buf = new StringBuilder(); + String aliasOrList; + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry entry = (Entry) it.next(); + aliasOrList = null; + if (entry instanceof EnvelopeEntry) + aliasOrList = ((EnvelopeEntry) entry).getAliasList(); + else if (entry instanceof PrimitiveEntry) + aliasOrList = ((PrimitiveEntry) entry).getAlias(); + else if (Configuration.DEBUG) + log.fine("Entry with no Alias. Ignored: " + entry); + if (aliasOrList != null) + { + aliasOrList = aliasOrList.trim(); + if (aliasOrList.trim().length() > 0) + { + buf.append(aliasOrList); + if (it.hasNext()) + buf.append(';'); + } + } + } + String aliasList = buf.toString(); + properties.put("alias-list", aliasList); + if (Configuration.DEBUG) + log.fine("alias-list=[" + aliasList + "]"); + if (containingEnvelope != null) + containingEnvelope.makeAliasList(); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "makeAliasList"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/GnuPrivateKeyring.java b/libjava/classpath/gnu/javax/crypto/keyring/GnuPrivateKeyring.java new file mode 100644 index 000000000..ab3933972 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/GnuPrivateKeyring.java @@ -0,0 +1,368 @@ +/* GnuPrivateKeyring.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.Key; +import java.security.PublicKey; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.util.Date; +import java.util.Iterator; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + */ +public class GnuPrivateKeyring + extends BaseKeyring + implements IPrivateKeyring +{ + private static final Logger log = Logger.getLogger(GnuPrivateKeyring.class.getName()); + public static final int USAGE = Registry.GKR_PRIVATE_KEYS + | Registry.GKR_PUBLIC_CREDENTIALS; + protected String mac; + protected int maclen; + protected String cipher; + protected String mode; + protected int keylen; + + public GnuPrivateKeyring(String mac, int maclen, String cipher, String mode, + int keylen) + { + keyring = new PasswordAuthenticatedEntry(mac, maclen, new Properties()); + keyring2 = new CompressedEntry(new Properties()); + keyring.add(keyring2); + this.mac = mac; + this.maclen = maclen; + this.cipher = cipher; + this.mode = mode; + this.keylen = keylen; + } + + public GnuPrivateKeyring() + { + this("HMAC-SHA-1", 20, "AES", "OFB", 16); + } + + public boolean containsPrivateKey(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "containsPrivateKey", alias); + boolean result = false; + if (containsAlias(alias)) + for (Iterator it = get(alias).iterator(); it.hasNext();) + if (it.next() instanceof PasswordAuthenticatedEntry) + { + result = true; + break; + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "containsPrivateKey", + Boolean.valueOf(result)); + return result; + } + + public Key getPrivateKey(String alias, char[] password) + throws UnrecoverableKeyException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "getPrivateKey", alias); + Key result = null; + if (containsAlias(alias)) + { + PasswordAuthenticatedEntry e1 = null; + for (Iterator it = get(alias).iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (Configuration.DEBUG) + log.finest("Entry: " + e); + if (e instanceof PasswordAuthenticatedEntry) + { + e1 = (PasswordAuthenticatedEntry) e; + break; + } + } + if (Configuration.DEBUG) + log.fine("e1 = " + e1); + if (e1 != null) + { + try + { + e1.verify(password); + } + catch (Exception e) + { + if (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "getPrivateKey", e); + throw new UnrecoverableKeyException("authentication failed"); + } + PasswordEncryptedEntry e2 = null; + for (Iterator it = e1.getEntries().iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof PasswordEncryptedEntry) + { + e2 = (PasswordEncryptedEntry) e; + break; + } + } + if (e2 != null) + { + try + { + e2.decrypt(password); + } + catch (Exception e) + { + log.throwing(this.getClass().getName(), "getPrivateKey", e); + throw new UnrecoverableKeyException("decryption failed"); + } + for (Iterator it = e2.get(alias).iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof PrivateKeyEntry) + { + result = ((PrivateKeyEntry) e).getKey(); + break; + } + } + } + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "getPrivateKey", + result == null ? "null" : result.getClass().getName()); + return result; + } + + public void putPrivateKey(String alias, Key key, char[] password) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "putPrivateKey", + new Object[] { alias, key.getClass().getName() }); + if (! containsPrivateKey(alias)) + { + alias = fixAlias(alias); + Properties p = new Properties(); + p.put("alias", alias); + PrivateKeyEntry pke = new PrivateKeyEntry(key, new Date(), p); + if (Configuration.DEBUG) + log.fine("About to encrypt the key..."); + PasswordEncryptedEntry enc; + enc = new PasswordEncryptedEntry(cipher, mode, keylen, new Properties()); + enc.add(pke); + try + { + enc.encode(null, password); + } + catch (IOException x) + { + if (Configuration.DEBUG) + log.log(Level.FINE, "Exception while encrypting the key. " + + "Rethrow as IllegalArgumentException", x); + throw new IllegalArgumentException(x.toString()); + } + if (Configuration.DEBUG) + log.fine("About to authenticate the encrypted key..."); + PasswordAuthenticatedEntry auth; + auth = new PasswordAuthenticatedEntry(mac, maclen, new Properties()); + auth.add(enc); + try + { + auth.encode(null, password); + } + catch (IOException x) + { + if (Configuration.DEBUG) + log.log(Level.FINE, "Exception while authenticating the encrypted " + + "key. Rethrow as IllegalArgumentException", x); + throw new IllegalArgumentException(x.toString()); + } + keyring.add(auth); + } + else if (Configuration.DEBUG) + log.fine("Keyring already contains alias: " + alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "putPrivateKey"); + } + + public boolean containsPublicKey(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "containsPublicKey", alias); + boolean result = false; + if (containsAlias(alias)) + for (Iterator it = get(alias).iterator(); it.hasNext();) + if (it.next() instanceof PublicKeyEntry) + { + result = true; + break; + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "containsPublicKey", + Boolean.valueOf(result)); + return result; + } + + public PublicKey getPublicKey(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "getPublicKey", alias); + PublicKey result = null; + if (containsAlias(alias)) + for (Iterator it = get(alias).iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof PublicKeyEntry) + { + result = ((PublicKeyEntry) e).getKey(); + break; + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "getPublicKey", + result == null ? "null" : result.getClass().getName()); + return result; + } + + public void putPublicKey(String alias, PublicKey key) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "putPublicKey", + new Object[] { alias, key.getClass().getName() }); + if (! containsPublicKey(alias)) + { + Properties p = new Properties(); + p.put("alias", fixAlias(alias)); + add(new PublicKeyEntry(key, new Date(), p)); + } + else if (Configuration.DEBUG) + log.fine("Keyring already contains alias: " + alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "putPublicKey"); + } + + public boolean containsCertPath(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "containsCertPath", alias); + boolean result = false; + if (containsAlias(alias)) + for (Iterator it = get(alias).iterator(); it.hasNext();) + if (it.next() instanceof CertPathEntry) + { + result = true; + break; + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "containsCertPath", + Boolean.valueOf(result)); + return result; + } + + public Certificate[] getCertPath(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "getCertPath", alias); + Certificate[] result = null; + if (containsAlias(alias)) + for (Iterator it = get(alias).iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof CertPathEntry) + { + result = ((CertPathEntry) e).getCertPath(); + break; + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "getCertPath", result); + return result; + } + + public void putCertPath(String alias, Certificate[] path) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "putCertPath", + new Object[] { alias, path }); + if (! containsCertPath(alias)) + { + Properties p = new Properties(); + p.put("alias", fixAlias(alias)); + add(new CertPathEntry(path, new Date(), p)); + } + else if (Configuration.DEBUG) + log.fine("Keyring already contains alias: " + alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "putCertPath"); + } + + protected void load(InputStream in, char[] password) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "load"); + if (in.read() != USAGE) + throw new MalformedKeyringException("incompatible keyring usage"); + if (in.read() != PasswordAuthenticatedEntry.TYPE) + throw new MalformedKeyringException( + "expecting password-authenticated entry tag"); + keyring = PasswordAuthenticatedEntry.decode(new DataInputStream(in), password); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "load"); + } + + protected void store(OutputStream out, char[] password) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "store"); + out.write(USAGE); + keyring.encode(new DataOutputStream(out), password); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "store"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/GnuPublicKeyring.java b/libjava/classpath/gnu/javax/crypto/keyring/GnuPublicKeyring.java new file mode 100644 index 000000000..d7387f892 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/GnuPublicKeyring.java @@ -0,0 +1,151 @@ +/* GnuPublicKeyring.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.cert.Certificate; +import java.util.Date; +import java.util.Iterator; +import java.util.logging.Logger; + +public class GnuPublicKeyring + extends BaseKeyring + implements IPublicKeyring +{ + private static final Logger log = Logger.getLogger(GnuPublicKeyring.class.getName()); + public static final int USAGE = Registry.GKR_CERTIFICATES; + + public GnuPublicKeyring(String mac, int macLen) + { + keyring = new PasswordAuthenticatedEntry(mac, macLen, new Properties()); + keyring2 = new CompressedEntry(new Properties()); + keyring.add(keyring2); + } + + public GnuPublicKeyring() + { + } + + public boolean containsCertificate(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "containsCertificate", alias); + boolean result = false; + if (containsAlias(alias)) + for (Iterator it = get(alias).iterator(); it.hasNext();) + if (it.next() instanceof CertificateEntry) + { + result = true; + break; + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "containsCertificate", + Boolean.valueOf(result)); + return result; + } + + public Certificate getCertificate(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "getCertificate", alias); + Certificate result = null; + if (containsAlias(alias)) + for (Iterator it = get(alias).iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof CertificateEntry) + { + result = ((CertificateEntry) e).getCertificate(); + break; + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "getCertificate", result); + return result; + } + + public void putCertificate(String alias, Certificate cert) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "putCertificate", + new Object[] { alias, cert }); + if (! containsCertificate(alias)) + { + Properties p = new Properties(); + p.put("alias", fixAlias(alias)); + add(new CertificateEntry(cert, new Date(), p)); + } + else if (Configuration.DEBUG) + log.fine("Keyring already contains alias: " + alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "putCertificate"); + } + + protected void load(InputStream in, char[] password) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "load"); + if (in.read() != USAGE) + throw new MalformedKeyringException("incompatible keyring usage"); + if (in.read() != PasswordAuthenticatedEntry.TYPE) + throw new MalformedKeyringException( + "expecting password-authenticated entry tag"); + DataInputStream dis = new DataInputStream(in); + keyring = PasswordAuthenticatedEntry.decode(dis, password); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "load"); + } + + protected void store(OutputStream out, char[] password) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "store"); + out.write(USAGE); + keyring.encode(new DataOutputStream(out), password); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "store"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/IKeyring.java b/libjava/classpath/gnu/javax/crypto/keyring/IKeyring.java new file mode 100644 index 000000000..141f2dcd4 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/IKeyring.java @@ -0,0 +1,162 @@ +/* IKeyring.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; + +/** + * The top-level interface to a keyring: a file that is used to store + * and protect public and private cryptographic keys. + *

+ * A keyring is modelled as a mapping of one alias to one or + * more entries (optionally of different types). + *

+ * See also the sub-interfaces {@link IPublicKeyring} and + * {@link IPrivateKeyring} for special types of keyrings --the + * difference being in the type of entries they contain. + */ +public interface IKeyring +{ + /** + * Property name for the source of data to load the keyring from. The value + * mapped must be a {@link java.io.InputStream}. + */ + public static final String KEYRING_DATA_IN = "gnu.crypto.keyring.data.in"; + + /** + * Property name for the data sink to store the keyring to. The value mapped + * must be a {@link java.io.OutputStream}. + */ + public static final String KEYRING_DATA_OUT = "gun.crypto.keyring.data.out"; + + /** + * Property name for the keyring's top-level password, used to authenticate + * and/or transform the store itself. The mapped value must be a char array. + */ + public static final String KEYRING_PASSWORD = "gnu.crypto.keyring.password"; + + /** + * Loads a keyring into memory. + *

+ * What happens to the current contents of this keyring? are the new ones + * merged with the current ones or do they simply replace them? + * + * @param attributes The attributes that designate the source where the store + * is to be loaded from. What happens + * @throws IllegalArgumentException If the attributes are inappropriate. + * @throws IOException If the keyring file cannot be read. + * @throws SecurityException If the given password is incorrect, or if the + * top-level authentication or decryption fails. + */ + void load(Map attributes) throws IOException; + + /** + * Stores the contents of this keyring to persistent storage as specified by + * the designated attributes. + * + * @param attributes the attributes that define where the contents of this + * keyring will be stored. + * @throws IOException if an exception occurs during the process. + */ + void store(Map attributes) throws IOException; + + /** + * Resets this keyring, clearing all sensitive data. This method always + * suceeds. + */ + void reset(); + + /** + * Returns the number of entries in this keyring. + * + * @return The number of current entries in this keyring. + */ + int size(); + + /** + * Returns an {@link Enumeration} of all aliases (instances of {@link String}) + * in this keyring. + * + * @return The enumeration of {@link String}s each representing an alias + * found in this keyring. + */ + Enumeration aliases(); + + /** + * Tests whether or not this keyring contains the given alias. + * + * @param alias The alias to check. + * @return true if this keyring contains the alias. + */ + boolean containsAlias(String alias); + + /** + * Returns a {@link List} of entries (instances of {@link Entry}) for the + * given alias, or null if there no such entry + * exists. + * + * @param alias The alias of the entry(ies) to return. + * @return A list of all entries (instances of {@link Entry} that have the + * given alias, or null if no one + * {@link Entry} can be found with the designated alias. + */ + List get(String alias); + + /** + * Adds a designated {@link Entry} to this keyring. + *

+ * What happens if there is already an entry with the same alias? + * + * @param entry The entry to put in this keyring. + */ + void add(Entry entry); + + /** + * Removes an entry with the designated alias from this + * keyring. Does nothing if there was no such entry. + *

+ * What happens if there are more than one? + * + * @param alias The alias of the entry to remove. + */ + void remove(String alias); +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/IPrivateKeyring.java b/libjava/classpath/gnu/javax/crypto/keyring/IPrivateKeyring.java new file mode 100644 index 000000000..3bfa10098 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/IPrivateKeyring.java @@ -0,0 +1,144 @@ +/* IPrivateKeyring.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.security.Key; +import java.security.PublicKey; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; + +/** + * An interface to private, or "personal", keyrings, which contain private + * credentials. The contract is that each such entry is known by a unique + * alias. + *

+ * What about public keys? and certificate-path? + */ +public interface IPrivateKeyring + extends IKeyring +{ + /** + * Tests if this keyring contains a private key entry with the given + * alias. + * + * @param alias The alias to check. + * @return true if this keyring contains a private key with the + * given alias; false otherwise. + */ + boolean containsPrivateKey(String alias); + + /** + * Returns the private key with the given alias. + * + * @param alias The alias of the private key to find. + * @param password The password of the private key. + * @return The private, or secret, key if one is found; null if + * none were found. + * @throws UnrecoverableKeyException If the private key could not be + * recovered, possibly due to a bad password. + */ + Key getPrivateKey(String alias, char[] password) + throws UnrecoverableKeyException; + + /** + * Adds a private key to this keyring. + * + * @param alias The alias of the private key. + * @param key The private key. + * @param password The password used to protect this private key. + */ + void putPrivateKey(String alias, Key key, char[] password); + + /** + * Checks if this keyring contains a public key with the given + * alias. + * + * @param alias The alias to test. + * @return true if this keyring contains a public key entry + * with the given alias; false + * otherwise. + */ + boolean containsPublicKey(String alias); + + /** + * Returns the public key with the given alias, or + * null if there is no such entry. + * + * @param alias The alias of the public key to find. + * @return The public key; or null if none were found. + */ + PublicKey getPublicKey(String alias); + + /** + * Sets a public key entry. + * + * @param alias The alias for this public key. + * @param key The public key. + */ + void putPublicKey(String alias, PublicKey key); + + /** + * Checks if this keyring contains a certificate path with the given + * alias. + * + * @param alias The alias to check. + * @return true if this keyring contains a certificate path + * with the given alias; false + * otherwise. + */ + boolean containsCertPath(String alias); + + /** + * Returns the certificate path with the given alias, or + * null if there is no such entry. + * + * @param alias The alias of the certificate path to find. + * @return The certificate path for the designated alias; or + * null if none were found. + */ + Certificate[] getCertPath(String alias); + + /** + * Sets a certificate path entry. + * + * @param alias The alias for this certificate path. + * @param path The certificate path. + */ + void putCertPath(String alias, Certificate[] path); +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/IPublicKeyring.java b/libjava/classpath/gnu/javax/crypto/keyring/IPublicKeyring.java new file mode 100644 index 000000000..d723f5ae9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/IPublicKeyring.java @@ -0,0 +1,82 @@ +/* IPublicKeyring.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.security.cert.Certificate; + +/** + * An interface for keyrings that contain trusted (by the owner) public + * credentials (incl. certificates). + * + * @see IKeyring + */ +public interface IPublicKeyring + extends IKeyring +{ + /** + * Tests if this keyring contains a certificate entry with the specified + * alias. + * + * @param alias The alias of the certificate to check. + * @return true if this keyring contains a certificate entry + * that has the given alias; false + * otherwise. + */ + boolean containsCertificate(String alias); + + /** + * Returns a certificate that has the given alias, or + * null if this keyring has no such entry. + * + * @param alias The alias of the certificate to find. + * @return The certificate with the designated alias, or + * null if none found. + */ + Certificate getCertificate(String alias); + + /** + * Adds a certificate in this keyring, with the given alias. + *

+ * What happens if there is already a certificate entry with this alias? + * + * @param alias The alias of this certificate entry. + * @param cert The certificate. + */ + void putCertificate(String alias, Certificate cert); +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/MalformedKeyringException.java b/libjava/classpath/gnu/javax/crypto/keyring/MalformedKeyringException.java new file mode 100644 index 000000000..f6b9d189b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/MalformedKeyringException.java @@ -0,0 +1,55 @@ +/* MalformedKeyringException.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.IOException; + +public class MalformedKeyringException + extends IOException +{ + public MalformedKeyringException() + { + super(); + } + + public MalformedKeyringException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java new file mode 100644 index 000000000..58254a437 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java @@ -0,0 +1,135 @@ +/* MaskableEnvelopeEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.util.ArrayList; +import java.util.List; + +/** + * An envelope entry that can be "masked" -- placed in a state where the + * envelope's contents cannot be accessed, due to the envelope not being fully + * decoded, for example. + */ +public abstract class MaskableEnvelopeEntry + extends EnvelopeEntry +{ + /** The masked state. */ + protected boolean masked; + + public MaskableEnvelopeEntry(int type, Properties properties) + { + super(type, properties); + } + + protected MaskableEnvelopeEntry(int type) + { + super(type); + } + + /** + * Sets the masked state to the specified value. + * + * @param masked The new masked state. + */ + protected final void setMasked(boolean masked) + { + this.masked = masked; + } + + /** + * Gets the masked state of this object. Certain operations on this object + * will fail if it is masked. + * + * @return The current masked state. + */ + public boolean isMasked() + { + return masked; + } + + public void add(Entry entry) + { + if (isMasked()) + throw new IllegalStateException("masked envelope"); + super.add(entry); + } + + public boolean containsEntry(Entry entry) + { + if (isMasked()) + throw new IllegalStateException("masked envelope"); + return super.containsEntry(entry); + } + + public List getEntries() + { + if (isMasked()) + throw new IllegalStateException("masked envelope"); + return new ArrayList(entries); + } + + public List get(String alias) + { + if (isMasked()) + throw new IllegalStateException("masked envelope"); + return super.get(alias); + } + + public boolean remove(Entry entry) + { + if (isMasked()) + throw new IllegalStateException("masked envelope"); + return super.remove(entry); + } + + public boolean remove(String alias) + { + if (isMasked()) + throw new IllegalStateException("masked envelope"); + return super.remove(alias); + } + + public String toString() + { + return new StringBuilder("MaskableEnvelope{") + .append(super.toString()) + .append(", masked=").append(masked) + .append("}").toString(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/MeteredInputStream.java b/libjava/classpath/gnu/javax/crypto/keyring/MeteredInputStream.java new file mode 100644 index 000000000..65f263359 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/MeteredInputStream.java @@ -0,0 +1,127 @@ +/* MeteredInputStream.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +final class MeteredInputStream + extends FilterInputStream +{ + private int count; + private final int limit; + + MeteredInputStream(InputStream in, int limit) + { + super(in); + if (limit < 0) + throw new IllegalArgumentException("limit must be nonnegative"); + this.limit = limit; + count = 0; + } + + /** + * Tests if the number of bytes read has reached the limit. + * + * @return True if the limit has been reached. + */ + public boolean limitReached() + { + return count == limit; + } + + public int available() throws IOException + { + return Math.min(in.available(), limit - count); + } + + public void close() throws IOException + { + in.close(); + } + + public void mark(int readLimit) + { + } + + public boolean markSupported() + { + return false; + } + + public int read() throws IOException + { + if (limitReached()) + return -1; + int i = in.read(); + if (i != -1) + count++; + return i; + } + + public int read(byte[] buf) throws IOException + { + return read(buf, 0, buf.length); + } + + public int read(byte[] buf, int off, int len) throws IOException + { + if (limitReached()) + return -1; + int i = in.read(buf, off, Math.min(len, limit - count)); + if (i != -1) + count += i; + return i; + } + + public void reset() throws IOException + { + } + + public long skip(long len) throws IOException + { + if (limitReached()) + return 0L; + len = Math.min(len, limit - count); + len = in.skip(len); + count += (int) len; + return len; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java new file mode 100644 index 000000000..d67300442 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java @@ -0,0 +1,286 @@ +/* PasswordAuthenticatedEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.PRNG; +import gnu.java.security.util.Util; +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; +import gnu.javax.crypto.mac.MacInputStream; +import gnu.javax.crypto.mac.MacOutputStream; +import gnu.javax.crypto.prng.IPBE; +import gnu.javax.crypto.prng.PRNGFactory; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.security.InvalidKeyException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.logging.Logger; + +/** + * An entry authenticated with a password-based MAC. + */ +public final class PasswordAuthenticatedEntry + extends MaskableEnvelopeEntry + implements PasswordProtectedEntry, Registry +{ + private static final Logger log = Logger.getLogger(PasswordAuthenticatedEntry.class.getName()); + public static final int TYPE = 3; + + public PasswordAuthenticatedEntry(String mac, int maclen, + Properties properties) + { + super(TYPE, properties); + if (mac == null || mac.length() == 0) + throw new IllegalArgumentException("no MAC specified"); + this.properties.put("mac", mac); + this.properties.put("maclen", String.valueOf(maclen)); + setMasked(false); + } + + private PasswordAuthenticatedEntry() + { + super(TYPE); + setMasked(true); + } + + public static PasswordAuthenticatedEntry decode(DataInputStream in, + char[] password) + throws IOException + { + PasswordAuthenticatedEntry entry = new PasswordAuthenticatedEntry(); + entry.properties.decode(in); + IMac mac = entry.getMac(password); + int len = in.readInt() - mac.macSize(); + MeteredInputStream min = new MeteredInputStream(in, len); + MacInputStream macin = new MacInputStream(min, mac); + DataInputStream in2 = new DataInputStream(macin); + entry.setMasked(false); + entry.decodeEnvelope(in2); + byte[] macValue = new byte[mac.macSize()]; + in.readFully(macValue); + if (! Arrays.equals(macValue, mac.digest())) + throw new MalformedKeyringException("MAC verification failed"); + return entry; + } + + public static PasswordAuthenticatedEntry decode(DataInputStream in) + throws IOException + { + PasswordAuthenticatedEntry entry = new PasswordAuthenticatedEntry(); + entry.defaultDecode(in); + if (! entry.properties.containsKey("mac")) + throw new MalformedKeyringException("no MAC"); + if (! entry.properties.containsKey("maclen")) + throw new MalformedKeyringException("no MAC length"); + if (! entry.properties.containsKey("salt")) + throw new MalformedKeyringException("no salt"); + return entry; + } + + public void verify(char[] password) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "verify"); + if (isMasked() && payload != null) + { + if (Configuration.DEBUG) + log.fine("payload to verify: " + Util.dumpString(payload)); + long tt = -System.currentTimeMillis(); + IMac m = null; + try + { + m = getMac(password); + } + catch (Exception x) + { + throw new IllegalArgumentException(x.toString(), x); + } + int limit = payload.length - m.macSize(); + m.update(payload, 0, limit); + byte[] macValue = new byte[m.macSize()]; + System.arraycopy(payload, payload.length - macValue.length, macValue, + 0, macValue.length); + if (! Arrays.equals(macValue, m.digest())) + throw new IllegalArgumentException("MAC verification failed"); + setMasked(false); + ByteArrayInputStream bais; + try + { + bais = new ByteArrayInputStream(payload, 0, limit); + DataInputStream in = new DataInputStream(bais); + decodeEnvelope(in); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("malformed keyring fragment"); + } + tt += System.currentTimeMillis(); + if (Configuration.DEBUG) + log.fine("Verified in " + tt + "ms."); + } + else if (Configuration.DEBUG) + log.fine("Skip verification; " + + (isMasked() ? "null payload" : "unmasked")); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "verify"); + } + + public void authenticate(char[] password) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "authenticate"); + long tt = -System.currentTimeMillis(); + long t1 = -System.currentTimeMillis(); + if (isMasked()) + throw new IllegalStateException("entry is masked"); + byte[] salt = new byte[8]; + PRNG.getInstance().nextBytes(salt); + t1 += System.currentTimeMillis(); + if (Configuration.DEBUG) + log.fine("-- Generated salt in " + t1 + "ms."); + properties.put("salt", Util.toString(salt)); + IMac m = getMac(password); + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + MacOutputStream macout = new MacOutputStream(bout, m); + DataOutputStream out2 = new DataOutputStream(macout); + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry entry = (Entry) it.next(); + if (Configuration.DEBUG) + log.fine("-- About to authenticate one " + entry); + t1 = -System.currentTimeMillis(); + entry.encode(out2); + t1 += System.currentTimeMillis(); + if (Configuration.DEBUG) + log.fine("-- Authenticated an Entry in " + t1 + "ms."); + } + bout.write(m.digest()); + payload = bout.toByteArray(); + if (Configuration.DEBUG) + log.fine("authenticated payload: " + Util.dumpString(payload)); + setMasked(true); + tt += System.currentTimeMillis(); + if (Configuration.DEBUG) + { + log.fine("Authenticated in " + tt + "ms."); + log.exiting(this.getClass().getName(), "authenticate"); + } + } + + public void encode(DataOutputStream out, char[] password) throws IOException + { + authenticate(password); + encode(out); + } + + protected void encodePayload(DataOutputStream out) throws IOException + { + if (payload == null) + { + log.fine("Null payload: " + this); + throw new IllegalStateException("mac not computed"); + } + } + + private IMac getMac(char[] password) throws MalformedKeyringException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "getMac"); + String saltString = properties.get("salt"); + if (saltString == null) + throw new MalformedKeyringException("no salt"); + byte[] salt = Util.toBytesFromString(saltString); + String macAlgorithm = properties.get("mac"); + IMac mac = MacFactory.getInstance(macAlgorithm); + if (mac == null) + throw new MalformedKeyringException("no such mac: " + macAlgorithm); + String macLenString = properties.get("maclen"); + if (macLenString == null) + throw new MalformedKeyringException("no MAC length"); + int maclen; + try + { + maclen = Integer.parseInt(macLenString); + } + catch (NumberFormatException nfe) + { + throw new MalformedKeyringException("bad MAC length"); + } + HashMap pbAttr = new HashMap(); + pbAttr.put(IPBE.PASSWORD, password); + pbAttr.put(IPBE.SALT, salt); + pbAttr.put(IPBE.ITERATION_COUNT, ITERATION_COUNT); + IRandom kdf = PRNGFactory.getInstance("PBKDF2-HMAC-SHA"); + kdf.init(pbAttr); + int keylen = mac.macSize(); + byte[] dk = new byte[keylen]; + try + { + kdf.nextBytes(dk, 0, keylen); + } + catch (LimitReachedException shouldNotHappen) + { + throw new Error(shouldNotHappen.toString()); + } + HashMap macAttr = new HashMap(); + macAttr.put(IMac.MAC_KEY_MATERIAL, dk); + macAttr.put(IMac.TRUNCATED_SIZE, Integer.valueOf(maclen)); + try + { + mac.init(macAttr); + } + catch (InvalidKeyException shouldNotHappen) + { + throw new Error(shouldNotHappen.toString()); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "getMac"); + return mac; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java new file mode 100644 index 000000000..0fa7431a8 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java @@ -0,0 +1,293 @@ +/* PasswordEncryptedEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.PRNG; +import gnu.java.security.util.Util; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.mode.ModeFactory; +import gnu.javax.crypto.pad.IPad; +import gnu.javax.crypto.pad.PadFactory; +import gnu.javax.crypto.pad.WrongPaddingException; +import gnu.javax.crypto.prng.IPBE; +import gnu.javax.crypto.prng.PRNGFactory; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.security.InvalidKeyException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.logging.Logger; + +/** + * An envelope that is encrypted with a password-derived key. + */ +public class PasswordEncryptedEntry + extends MaskableEnvelopeEntry + implements PasswordProtectedEntry, Registry +{ + private static final Logger log = Logger.getLogger(PasswordEncryptedEntry.class.getName()); + public static final int TYPE = 1; + + public PasswordEncryptedEntry(String cipher, String mode, int keylen, + Properties properties) + { + super(TYPE, properties); + if ((cipher == null || cipher.length() == 0) + || (mode == null || mode.length() == 0)) + throw new IllegalArgumentException("cipher nor mode can be empty"); + this.properties.put("cipher", cipher); + this.properties.put("mode", mode); + this.properties.put("keylen", String.valueOf(keylen)); + setMasked(false); + } + + private PasswordEncryptedEntry() + { + super(TYPE); + setMasked(true); + } + + public static PasswordEncryptedEntry decode(DataInputStream in, + char[] password) + throws IOException + { + PasswordEncryptedEntry entry = decode(in); + try + { + entry.decrypt(password); + } + catch (WrongPaddingException wpe) + { + throw new MalformedKeyringException("wrong padding in decrypted data"); + } + return entry; + } + + public static PasswordEncryptedEntry decode(DataInputStream in) + throws IOException + { + PasswordEncryptedEntry entry = new PasswordEncryptedEntry(); + entry.defaultDecode(in); + return entry; + } + + public void decrypt(char[] password) throws IllegalArgumentException, + WrongPaddingException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "decrypt"); + if (isMasked() && payload != null) + { + long tt = -System.currentTimeMillis(); + IMode mode = getMode(password, IMode.DECRYPTION); + IPad padding = PadFactory.getInstance("PKCS7"); + padding.init(mode.currentBlockSize()); + byte[] buf = new byte[payload.length]; + int count = 0; + while (count + mode.currentBlockSize() <= payload.length) + { + mode.update(payload, count, buf, count); + count += mode.currentBlockSize(); + } + int padlen = padding.unpad(buf, 0, buf.length); + setMasked(false); + int len = buf.length - padlen; + ByteArrayInputStream baos = new ByteArrayInputStream(buf, 0, len); + DataInputStream in = new DataInputStream(baos); + try + { + decodeEnvelope(in); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("decryption failed"); + } + tt += System.currentTimeMillis(); + log.fine("Decrypted in " + tt + "ms."); + } + else if (Configuration.DEBUG) + log.fine("Skip decryption; " + (isMasked() ? "null payload" : "unmasked")); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "decrypt"); + } + + public void encrypt(char[] password) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "encrypt", String.valueOf(password)); + long tt = -System.currentTimeMillis(); + long t1 = -System.currentTimeMillis(); + byte[] salt = new byte[8]; + PRNG.getInstance().nextBytes(salt); + t1 += System.currentTimeMillis(); + if (Configuration.DEBUG) + log.fine("-- Generated salt in " + t1 + "ms."); + properties.put("salt", Util.toString(salt)); + IMode mode = getMode(password, IMode.ENCRYPTION); + IPad pad = PadFactory.getInstance("PKCS7"); + pad.init(mode.currentBlockSize()); + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + DataOutputStream out2 = new DataOutputStream(bout); + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry entry = (Entry) it.next(); + if (Configuration.DEBUG) + log.fine("-- About to encode one " + entry); + t1 = -System.currentTimeMillis(); + entry.encode(out2); + t1 += System.currentTimeMillis(); + if (Configuration.DEBUG) + log.fine("-- Encoded an Entry in " + t1 + "ms."); + } + byte[] plaintext = bout.toByteArray(); + byte[] padding = pad.pad(plaintext, 0, plaintext.length); + payload = new byte[plaintext.length + padding.length]; + byte[] lastBlock = new byte[mode.currentBlockSize()]; + int l = mode.currentBlockSize() - padding.length; + System.arraycopy(plaintext, plaintext.length - l, lastBlock, 0, l); + System.arraycopy(padding, 0, lastBlock, l, padding.length); + int count = 0; + while (count + mode.currentBlockSize() < plaintext.length) + { + mode.update(plaintext, count, payload, count); + count += mode.currentBlockSize(); + } + mode.update(lastBlock, 0, payload, count); + setMasked(true); + tt += System.currentTimeMillis(); + if (Configuration.DEBUG) + { + log.fine("Encrypted in " + tt + "ms."); + log.exiting(this.getClass().getName(), "encrypt"); + } + } + + public void encode(DataOutputStream out, char[] password) throws IOException + { + encrypt(password); + encode(out); + } + + protected void encodePayload() throws IOException + { + if (payload == null) + { + if (Configuration.DEBUG) + log.fine("Null payload: " + this); + throw new IllegalStateException("not encrypted"); + } + } + + private IMode getMode(char[] password, int state) + { + String s = properties.get("salt"); + if (s == null) + throw new IllegalArgumentException("no salt"); + byte[] salt = Util.toBytesFromString(s); + IBlockCipher cipher = CipherFactory.getInstance(properties.get("cipher")); + if (cipher == null) + throw new IllegalArgumentException("no such cipher: " + + properties.get("cipher")); + int blockSize = cipher.defaultBlockSize(); + if (properties.containsKey("block-size")) + try + { + blockSize = Integer.parseInt(properties.get("block-size")); + } + catch (NumberFormatException nfe) + { + throw new IllegalArgumentException("bad block size: " + + nfe.getMessage()); + } + String modeName = properties.get("mode"); + IMode mode = ModeFactory.getInstance(modeName, cipher, blockSize); + if (mode == null) + throw new IllegalArgumentException("no such mode: " + modeName); + HashMap pbAttr = new HashMap(); + pbAttr.put(IPBE.PASSWORD, password); + pbAttr.put(IPBE.SALT, salt); + pbAttr.put(IPBE.ITERATION_COUNT, ITERATION_COUNT); + IRandom kdf = PRNGFactory.getInstance("PBKDF2-HMAC-SHA"); + kdf.init(pbAttr); + int keylen = 0; + if (! properties.containsKey("keylen")) + throw new IllegalArgumentException("no key length"); + try + { + keylen = Integer.parseInt(properties.get("keylen")); + } + catch (NumberFormatException nfe) + { + } + byte[] dk = new byte[keylen]; + byte[] iv = new byte[blockSize]; + try + { + kdf.nextBytes(dk, 0, keylen); + kdf.nextBytes(iv, 0, blockSize); + } + catch (LimitReachedException shouldNotHappen) + { + throw new Error(shouldNotHappen.toString()); + } + HashMap modeAttr = new HashMap(); + modeAttr.put(IMode.KEY_MATERIAL, dk); + modeAttr.put(IMode.STATE, Integer.valueOf(state)); + modeAttr.put(IMode.IV, iv); + try + { + mode.init(modeAttr); + } + catch (InvalidKeyException ike) + { + throw new IllegalArgumentException(ike.toString()); + } + return mode; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/PasswordProtectedEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/PasswordProtectedEntry.java new file mode 100644 index 000000000..a95f2e4a4 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/PasswordProtectedEntry.java @@ -0,0 +1,57 @@ +/* PasswordProtectedEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.DataOutputStream; +import java.io.IOException; + +public interface PasswordProtectedEntry +{ + /** The iteration count for password-based KDFs. */ + Integer ITERATION_COUNT = Integer.valueOf(1000); + + /** + * Encodes this entry, protected by a password. + * + * @param out The output stream to encode to. + * @param password The password. + * @throws IOException If an I/O error occurs. + */ + void encode(DataOutputStream out, char[] password) throws IOException; +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/PrimitiveEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/PrimitiveEntry.java new file mode 100644 index 000000000..8993de716 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/PrimitiveEntry.java @@ -0,0 +1,112 @@ +/* PrimitiveEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.util.Date; + +/** + * A primitive entry is an entry that contains a single cryptographic entity. + */ +public abstract class PrimitiveEntry + extends Entry +{ + /** The creation date. */ + protected Date creationDate; + + protected PrimitiveEntry(int type, Date creationDate, Properties properties) + { + super(type, properties); + if (creationDate == null) + this.creationDate = new Date(); + else + this.creationDate = (Date) creationDate.clone(); + if (! this.properties.containsKey("alias") + || this.properties.get("alias").length() == 0) + throw new IllegalArgumentException("primitive entries MUST have an alias"); + this.properties.put("creation-date", + String.valueOf(this.creationDate.getTime())); + } + + protected PrimitiveEntry(int type) + { + super(type); + } + + /** + * Returns the alias of this primitive entry. + * + * @return The alias. + */ + public String getAlias() + { + return properties.get("alias"); + } + + /** + * Returns the creation date of this primitive entry. + * + * @return The creation date. + */ + public Date getCreationDate() + { + return (Date) creationDate.clone(); + } + + public boolean equals(Object object) + { + if (! getClass().equals(object.getClass())) + return false; + return getAlias().equals(((PrimitiveEntry) object).getAlias()); + } + + protected final void makeCreationDate() throws MalformedKeyringException + { + String s = properties.get("creation-date"); + if (s == null) + throw new MalformedKeyringException("no creation date"); + try + { + creationDate = new Date(Long.parseLong(s)); + } + catch (NumberFormatException nfe) + { + throw new MalformedKeyringException("invalid creation date"); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/PrivateKeyEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/PrivateKeyEntry.java new file mode 100644 index 000000000..b2637316e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/PrivateKeyEntry.java @@ -0,0 +1,194 @@ +/* PrivateKeyEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import gnu.java.security.key.IKeyPairCodec; +import gnu.java.security.key.KeyPairCodecFactory; +import gnu.java.security.key.dss.DSSPrivateKey; +import gnu.java.security.key.rsa.GnuRSAPrivateKey; +import gnu.javax.crypto.key.GnuSecretKey; +import gnu.javax.crypto.key.dh.GnuDHPrivateKey; + +import java.io.DataInputStream; +import java.io.IOException; +import java.security.Key; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.util.Date; + +/** + * An immutable class representing a private or secret key entry. + */ +public final class PrivateKeyEntry + extends PrimitiveEntry +{ + public static final int TYPE = 7; + /** The key. */ + private Key key; + + /** + * Creates a new key entry. + * + * @param key The key. + * @param creationDate The entry creation date. + * @param properties The entry properties. + * @throws IllegalArgumentException If any parameter is null. + */ + public PrivateKeyEntry(Key key, Date creationDate, Properties properties) + { + super(TYPE, creationDate, properties); + if (key == null) + throw new IllegalArgumentException("no private key"); + if (! (key instanceof PrivateKey) && ! (key instanceof GnuSecretKey)) + throw new IllegalArgumentException("not a private or secret key"); + this.key = key; + } + + private PrivateKeyEntry() + { + super(TYPE); + } + + public static PrivateKeyEntry decode(DataInputStream in) throws IOException + { + PrivateKeyEntry entry = new PrivateKeyEntry(); + entry.defaultDecode(in); + String type = entry.properties.get("type"); + if (type == null) + throw new MalformedKeyringException("no key type"); + if (type.equalsIgnoreCase("RAW-DSS")) + { + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dss"); + entry.key = coder.decodePrivateKey(entry.payload); + } + else if (type.equalsIgnoreCase("RAW-RSA")) + { + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("rsa"); + entry.key = coder.decodePrivateKey(entry.payload); + } + else if (type.equalsIgnoreCase("RAW-DH")) + { + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dh"); + entry.key = coder.decodePrivateKey(entry.payload); + } + else if (type.equalsIgnoreCase("RAW")) + entry.key = new GnuSecretKey(entry.payload, null); + else if (type.equalsIgnoreCase("PKCS8")) + { + try + { + KeyFactory kf = KeyFactory.getInstance("RSA"); + PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(entry.payload); + entry.key = kf.generatePrivate(ks); + } + catch (Exception ignored) + { + } + if (entry.key == null) + { + try + { + KeyFactory kf = KeyFactory.getInstance("DSA"); + PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(entry.payload); + entry.key = kf.generatePrivate(ks); + } + catch (Exception ignored) + { + } + if (entry.key == null) + throw new MalformedKeyringException("could not decode PKCS#8 key"); + } + } + else + throw new MalformedKeyringException("unsupported key type " + type); + return entry; + } + + /** + * Returns this entry's key. + * + * @return The key. + */ + public Key getKey() + { + return key; + } + + protected void encodePayload() throws IOException + { + String format = key.getFormat(); + if (key instanceof DSSPrivateKey) + { + properties.put("type", "RAW-DSS"); + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dss"); + payload = coder.encodePrivateKey((PrivateKey) key); + } + else if (key instanceof GnuRSAPrivateKey) + { + properties.put("type", "RAW-RSA"); + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("rsa"); + payload = coder.encodePrivateKey((PrivateKey) key); + } + else if (key instanceof GnuDHPrivateKey) + { + properties.put("type", "RAW-DH"); + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dh"); + payload = coder.encodePrivateKey((PrivateKey) key); + } + else if (key instanceof GnuSecretKey) + { + properties.put("type", "RAW"); + payload = key.getEncoded(); + } + else if (format != null && format.equals("PKCS#8")) + { + properties.put("type", "PKCS8"); + payload = key.getEncoded(); + } + else + throw new IllegalArgumentException("unsupported private key"); + } + + public String toString() + { + return "PrivateKeyEntry{key=" + + (key == null ? "-" : key.getClass().getName()) + "}"; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/Properties.java b/libjava/classpath/gnu/javax/crypto/keyring/Properties.java new file mode 100644 index 000000000..f25c82e36 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/Properties.java @@ -0,0 +1,203 @@ +/* Properties.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * A set of (name => value) pairs used in keyring entries. + * Keys and values are simple strings, with the key never being empty and always + * treated case-insensitively. + */ +public class Properties + implements Cloneable +{ + private HashMap props; + + /** + * Creates a new properties object. + */ + public Properties() + { + props = new HashMap(); + } + + /** + * Removes all properties from this object. + */ + public void clear() + { + props.clear(); + } + + /** + * Creates a copy of this properties object. + * + * @return The copy. + */ + public Object clone() + { + Properties result = new Properties(); + result.props.putAll(props); + return result; + } + + /** + * Tests if this object contains a given property name. + * + * @param key The key to test. + * @return True if this object contains the given key. + */ + public boolean containsKey(String key) + { + if (key == null || key.length() == 0) + return false; + return props.containsKey(canonicalize(key)); + } + + /** + * Tests if this object contains a given property value. + * + * @param value The value to test. + * @return True if this object contains the given value. + */ + public boolean containsValue(String value) + { + if (value == null) + return false; + return props.containsValue(value); + } + + /** + * Adds a new property to this object. + * + * @param key The key, which can neither be null nor empty. + * @param value The value, which cannot be null. + * @return The old value mapped by the key, if any. + * @throws IllegalArgumentException If either the key or value parameter is + * null, or if the key is empty. + */ + public String put(String key, String value) + { + if (key == null || value == null || key.length() == 0) + throw new IllegalArgumentException("key nor value can be null"); + return (String) props.put(canonicalize(key), value); + } + + /** + * Returns the value mapped by the given key, or null if there is no such + * mapping. + * + * @param key + */ + public String get(String key) + { + if (key == null || key.length() == 0) + return null; + return (String) props.get(canonicalize(key)); + } + + /** + * Removes a key and its value from this object. + * + * @param key The key of the property to remove. + * @return The old value mapped by the key, if any. + */ + public String remove(String key) + { + if (key == null || key.length() == 0) + return null; + return (String) props.remove(canonicalize(key)); + } + + /** + * Decodes a set of properties from the given input stream. + * + * @param in The input stream. + * @throws IOException If an I/O error occurs. + */ + public void decode(DataInputStream in) throws IOException + { + int len = in.readInt(); + MeteredInputStream min = new MeteredInputStream(in, len); + DataInputStream in2 = new DataInputStream(min); + while (! min.limitReached()) + { + String name = in2.readUTF(); + String value = in2.readUTF(); + put(name, value); + } + } + + /** + * Encodes this set of properties to the given output stream. + * + * @param out The output stream to encode to. + * @throws IOException If an I/O error occurs. + */ + public void encode(DataOutputStream out) throws IOException + { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + DataOutputStream out2 = new DataOutputStream(buf); + for (Iterator it = props.entrySet().iterator(); it.hasNext();) + { + Map.Entry entry = (Map.Entry) it.next(); + out2.writeUTF((String) entry.getKey()); + out2.writeUTF((String) entry.getValue()); + } + out.writeInt(buf.size()); + buf.writeTo(out); + } + + public String toString() + { + return props.toString(); + } + + private String canonicalize(String key) + { + return key.toLowerCase(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/PublicKeyEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/PublicKeyEntry.java new file mode 100644 index 000000000..837706d19 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/PublicKeyEntry.java @@ -0,0 +1,162 @@ +/* PublicKeyEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import gnu.java.security.key.IKeyPairCodec; +import gnu.java.security.key.KeyPairCodecFactory; +import gnu.java.security.key.dss.DSSPublicKey; +import gnu.java.security.key.rsa.GnuRSAPublicKey; +import gnu.javax.crypto.key.dh.GnuDHPublicKey; + +import java.io.DataInputStream; +import java.io.IOException; +import java.security.KeyFactory; +import java.security.PublicKey; +import java.security.spec.X509EncodedKeySpec; +import java.util.Date; + +public final class PublicKeyEntry + extends PrimitiveEntry +{ + public static final int TYPE = 6; + private PublicKey key; + + public PublicKeyEntry(PublicKey key, Date creationDate, Properties properties) + { + super(TYPE, creationDate, properties); + if (key == null) + throw new IllegalArgumentException("no key specified"); + this.key = key; + } + + private PublicKeyEntry() + { + super(TYPE); + } + + public static PublicKeyEntry decode(DataInputStream in) throws IOException + { + PublicKeyEntry entry = new PublicKeyEntry(); + entry.defaultDecode(in); + String type = entry.properties.get("type"); + if (type == null) + throw new MalformedKeyringException("no key type"); + if (type.equalsIgnoreCase("RAW-DSS")) + { + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dss"); + entry.key = coder.decodePublicKey(entry.payload); + } + else if (type.equalsIgnoreCase("RAW-RSA")) + { + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("rsa"); + entry.key = coder.decodePublicKey(entry.payload); + } + else if (type.equalsIgnoreCase("RAW-DH")) + { + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dh"); + entry.key = coder.decodePublicKey(entry.payload); + } + else if (type.equalsIgnoreCase("X.509")) + { + try + { + KeyFactory kf = KeyFactory.getInstance("RSA"); + entry.key = kf.generatePublic(new X509EncodedKeySpec(entry.payload)); + } + catch (Exception x) + { + } + if (entry.key == null) + { + try + { + KeyFactory kf = KeyFactory.getInstance("DSA"); + entry.key = kf.generatePublic(new X509EncodedKeySpec(entry.payload)); + } + catch (Exception x) + { + } + if (entry.key == null) + throw new MalformedKeyringException("could not decode X.509 key"); + } + } + else + throw new MalformedKeyringException("unsupported public key type: " + type); + return entry; + } + + /** + * Returns the public key. + * + * @return The public key. + */ + public PublicKey getKey() + { + return key; + } + + protected void encodePayload() throws IOException + { + if (key instanceof DSSPublicKey) + { + properties.put("type", "RAW-DSS"); + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dss"); + payload = coder.encodePublicKey(key); + } + else if (key instanceof GnuRSAPublicKey) + { + properties.put("type", "RAW-RSA"); + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("rsa"); + payload = coder.encodePublicKey(key); + } + else if (key instanceof GnuDHPublicKey) + { + properties.put("type", "RAW-DH"); + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dh"); + payload = coder.encodePublicKey(key); + } + else if (key.getFormat() != null && key.getFormat().equals("X.509")) + { + properties.put("type", "X.509"); + payload = key.getEncoded(); + } + else + throw new IllegalArgumentException("cannot encode public key"); + } +} -- cgit v1.2.3