diff options
| author | mark <mark@138bc75d-0d04-0410-961f-82ee72b054a4> | 2006-03-10 21:46:48 +0000 |
|---|---|---|
| committer | mark <mark@138bc75d-0d04-0410-961f-82ee72b054a4> | 2006-03-10 21:46:48 +0000 |
| commit | ce57ab760f69de6db452def7ffbf5b114a2d8694 (patch) | |
| tree | ea38c56431c5d4528fb54254c3f8e50f517bede3 /libjava/classpath/gnu/javax/net | |
| parent | 50996fe55769882de3f410896032c887f0ff0d04 (diff) | |
| download | ppe42-gcc-ce57ab760f69de6db452def7ffbf5b114a2d8694.tar.gz ppe42-gcc-ce57ab760f69de6db452def7ffbf5b114a2d8694.zip | |
Imported GNU Classpath 0.90
* scripts/makemake.tcl: Set gnu/java/awt/peer/swing to ignore.
* gnu/classpath/jdwp/VMFrame.java (SIZE): New constant.
* java/lang/VMCompiler.java: Use gnu.java.security.hash.MD5.
* java/lang/Math.java: New override file.
* java/lang/Character.java: Merged from Classpath.
(start, end): Now 'int's.
(canonicalName): New field.
(CANONICAL_NAME, NO_SPACES_NAME, CONSTANT_NAME): New constants.
(UnicodeBlock): Added argument.
(of): New overload.
(forName): New method.
Updated unicode blocks.
(sets): Updated.
* sources.am: Regenerated.
* Makefile.in: Likewise.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@111942 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libjava/classpath/gnu/javax/net')
68 files changed, 19138 insertions, 0 deletions
diff --git a/libjava/classpath/gnu/javax/net/ssl/Base64.java b/libjava/classpath/gnu/javax/net/ssl/Base64.java new file mode 100644 index 00000000000..52989da69d3 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/Base64.java @@ -0,0 +1,311 @@ +/* Base64.java -- Base64 encoding and decoding. + Copyright (C) 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. + +-- +Base64 encoding derived from ISC's DHCP. Copyright notices from DHCP +follow. See http://www.isc.org/products/DHCP/. + +Copyright (c) 1996 by Internet Software Consortium. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM +DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL +INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING +FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION +WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +-- +Portions Copyright (c) 1995 by International Business Machines, Inc. + +International Business Machines, Inc. (hereinafter called IBM) grants +permission under its copyrights to use, copy, modify, and distribute +this Software with or without fee, provided that the above copyright +notice and all paragraphs of this notice appear in all copies, and +that the name of IBM not be used in connection with the marketing of +any product incorporating the Software or modifications thereof, +without specific, written prior permission. + +To the extent it has a right to do so, IBM grants an immunity from +suit under its patents, if any, for the use, sale or manufacture of +products to the extent that such products are used for performing +Domain Name System dynamic updates in TCP/IP networks by means of the +Software. No immunity is granted for any product per se or for any +other function of any product. + +THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, +DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE, EVEN IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH +DAMAGES. */ + + +package gnu.javax.net.ssl; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +public final class Base64 +{ + + // No constructor. + private Base64() { } + + // Class methods. + // ------------------------------------------------------------------------- + + /** Base-64 characters. */ + private static final String BASE_64 = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + /** Base-64 padding character. */ + private static final char BASE_64_PAD = '='; + + /** + * Base64 encode a byte array, returning the returning string. + * + * @param buf The byte array to encode. + * @param tw The total length of any line, 0 for unlimited. + * @return <tt>buf</tt> encoded in Base64. + */ + public static String encode(byte[] buf, int tw) + { + int srcLength = buf.length; + byte[] input = new byte[3]; + int[] output = new int[4]; + StringBuffer out = new StringBuffer(); + int i = 0; + int chars = 0; + + while (srcLength > 2) + { + input[0] = buf[i++]; + input[1] = buf[i++]; + input[2] = buf[i++]; + srcLength -= 3; + + output[0] = (input[0] & 0xff) >>> 2; + output[1] = ((input[0] & 0x03) << 4) + ((input[1] & 0xff) >>> 4); + output[2] = ((input[1] & 0x0f) << 2) + ((input[2] & 0xff) >>> 6); + output[3] = input[2] & 0x3f; + + out.append(BASE_64.charAt(output[0])); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + out.append(BASE_64.charAt(output[1])); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + out.append(BASE_64.charAt(output[2])); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + out.append(BASE_64.charAt(output[3])); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + } + + if (srcLength != 0) + { + input[0] = input[1] = input[2] = 0; + for (int j = 0; j < srcLength; j++) + { + input[j] = buf[i+j]; + } + output[0] = (input[0] & 0xff) >>> 2; + output[1] = ((input[0] & 0x03) << 4) + ((input[1] & 0xff) >>> 4); + output[2] = ((input[1] & 0x0f) << 2) + ((input[2] & 0xff) >>> 6); + + out.append(BASE_64.charAt(output[0])); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + out.append(BASE_64.charAt(output[1])); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + if (srcLength == 1) + { + out.append(BASE_64_PAD); + } + else + { + out.append(BASE_64.charAt(output[2])); + } + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + out.append(BASE_64_PAD); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + } + if (tw > 0) + { + out.append("\n"); + } + + return out.toString(); + } + + /** + * Decode a Base-64 string into a byte array. + * + * @param b64 The Base-64 encoded string. + * @return The decoded bytes. + * @throws java.io.IOException If the argument is not a valid Base-64 + * encoding. + */ + public static byte[] decode(String b64) throws IOException + { + ByteArrayOutputStream result = new ByteArrayOutputStream(b64.length() / 3); + int state = 0, i; + byte temp = 0; + + for (i = 0; i < b64.length(); i++) + { + if (Character.isWhitespace(b64.charAt(i))) + { + continue; + } + if (b64.charAt(i) == BASE_64_PAD) + { + break; + } + + int pos = BASE_64.indexOf(b64.charAt(i)); + if (pos < 0) + { + throw new IOException("non-Base64 character " + b64.charAt(i)); + } + switch (state) + { + case 0: + temp = (byte) (pos - BASE_64.indexOf('A') << 2); + state = 1; + break; + + case 1: + temp |= (byte) (pos - BASE_64.indexOf('A') >>> 4); + result.write(temp); + temp = (byte) ((pos - BASE_64.indexOf('A') & 0x0f) << 4); + state = 2; + break; + + case 2: + temp |= (byte) ((pos - BASE_64.indexOf('A') & 0x7f) >>> 2); + result.write(temp); + temp = (byte) ((pos - BASE_64.indexOf('A') & 0x03) << 6); + state = 3; + break; + + case 3: + temp |= (byte) (pos - BASE_64.indexOf('A') & 0xff); + result.write(temp); + state = 0; + break; + + default: + throw new Error("this statement should be unreachable"); + } + } + + if (i < b64.length() && b64.charAt(i) == BASE_64_PAD) + { + switch (state) + { + case 0: + case 1: + throw new IOException("malformed Base64 sequence"); + + case 2: + for ( ; i < b64.length(); i++) + { + if (!Character.isWhitespace(b64.charAt(i))) + { + break; + } + } + // We must see a second pad character here. + if (b64.charAt(i) != BASE_64_PAD) + { + throw new IOException("malformed Base64 sequence"); + } + i++; + // Fall-through. + + case 3: + i++; + for ( ; i < b64.length(); i++) + { + // We should only see whitespace after this. + if (!Character.isWhitespace(b64.charAt(i))) + { + System.err.println(b64.charAt(i)); + throw new IOException("malformed Base64 sequence"); + } + } + } + } + else + { + if (state != 0) + { + throw new IOException("malformed Base64 sequence"); + } + } + + return result.toByteArray(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/EntropySource.java b/libjava/classpath/gnu/javax/net/ssl/EntropySource.java new file mode 100644 index 00000000000..be840e5d697 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/EntropySource.java @@ -0,0 +1,62 @@ +/* EntropySource.java -- a source of random bits. + Copyright (C) 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.net.ssl; + +/** + * A generic interface for adding random bytes to an entropy pool. + */ +public interface EntropySource +{ + + /** + * Returns the estimated quality of this source. This value should be + * between 0 and 100 (the running quality is computed as a percentage, + * 100 percent being perfect-quality). + * + * @return The quality. + */ + double quality(); + + /** + * Returns a new buffer with the next random bytes to add. + * + * @return The next random bytes. + */ + byte[] nextBytes(); +} diff --git a/libjava/classpath/gnu/javax/net/ssl/NullManagerParameters.java b/libjava/classpath/gnu/javax/net/ssl/NullManagerParameters.java new file mode 100644 index 00000000000..0e933793262 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/NullManagerParameters.java @@ -0,0 +1,56 @@ +/* NullManagerParameters.java -- parameters for empty managers. + Copyright (C) 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.net.ssl; + +import javax.net.ssl.ManagerFactoryParameters; + +/** + * This empty class can be used to initialize {@link + * javax.net.ssl.KeyManagerFactory} and {@link + * javax.net.ssl.TrustManagerFactory} instances for the ``JessieX509'' + * algorithm, for cases when no keys or trusted certificates are + * desired or needed. + * + * <p>This is the default manager parameters object used in {@link + * javax.net.ssl.KeyManagerFactory} instances if no key stores are + * specified through security properties. + */ +public final class NullManagerParameters implements ManagerFactoryParameters +{ +} diff --git a/libjava/classpath/gnu/javax/net/ssl/PrivateCredentials.java b/libjava/classpath/gnu/javax/net/ssl/PrivateCredentials.java new file mode 100644 index 00000000000..f602f98ae22 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/PrivateCredentials.java @@ -0,0 +1,360 @@ +/* PrivateCredentials.java -- private key/certificate pairs. + Copyright (C) 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.net.ssl; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.EOFException; +import java.io.InputStream; +import java.io.IOException; + +import java.math.BigInteger; + +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.Security; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.spec.DSAPrivateKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.RSAPrivateCrtKeySpec; + +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; + +import javax.net.ssl.ManagerFactoryParameters; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; + +import gnu.javax.security.auth.callback.ConsoleCallbackHandler; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.mode.ModeFactory; +import gnu.javax.crypto.pad.WrongPaddingException; + +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; + +/** + * An instance of a manager factory parameters for holding a single + * certificate/private key pair, encoded in PEM format. + */ +public class PrivateCredentials implements ManagerFactoryParameters +{ + + // Fields. + // ------------------------------------------------------------------------- + + public static final String BEGIN_DSA = "-----BEGIN DSA PRIVATE KEY"; + public static final String END_DSA = "-----END DSA PRIVATE KEY"; + public static final String BEGIN_RSA = "-----BEGIN RSA PRIVATE KEY"; + public static final String END_RSA = "-----END RSA PRIVATE KEY"; + + private List privateKeys; + private List certChains; + + // Constructor. + // ------------------------------------------------------------------------- + + public PrivateCredentials() + { + privateKeys = new LinkedList(); + certChains = new LinkedList(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void add(InputStream certChain, InputStream privateKey) + throws CertificateException, InvalidKeyException, InvalidKeySpecException, + IOException, NoSuchAlgorithmException, WrongPaddingException + { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + Collection certs = cf.generateCertificates(certChain); + X509Certificate[] chain = (X509Certificate[]) certs.toArray(new X509Certificate[0]); + + String alg = null; + String line = readLine(privateKey); + String finalLine = null; + if (line.startsWith(BEGIN_DSA)) + { + alg = "DSA"; + finalLine = END_DSA; + } + else if (line.startsWith(BEGIN_RSA)) + { + alg = "RSA"; + finalLine = END_RSA; + } + else + throw new IOException("Unknown private key type."); + + boolean encrypted = false; + String cipher = null; + String salt = null; + StringBuffer base64 = new StringBuffer(); + while (true) + { + line = readLine(privateKey); + if (line == null) + throw new EOFException("premature end-of-file"); + else if (line.startsWith("Proc-Type: 4,ENCRYPTED")) + encrypted = true; + else if (line.startsWith("DEK-Info: ")) + { + int i = line.indexOf(','); + if (i < 0) + cipher = line.substring(10).trim(); + else + { + cipher = line.substring(10, i).trim(); + salt = line.substring(i + 1).trim(); + } + } + else if (line.startsWith(finalLine)) + break; + else if (line.length() > 0) + { + base64.append(line); + base64.append(System.getProperty("line.separator")); + } + } + + byte[] enckey = Base64.decode(base64.toString()); + if (encrypted) + { + enckey = decryptKey(enckey, cipher, toByteArray(salt)); + } + + DERReader der = new DERReader(enckey); + if (der.read().getTag() != DER.SEQUENCE) + throw new IOException("malformed DER sequence"); + der.read(); // version + + KeyFactory kf = KeyFactory.getInstance(alg); + KeySpec spec = null; + if (alg.equals("DSA")) + { + BigInteger p = (BigInteger) der.read().getValue(); + BigInteger q = (BigInteger) der.read().getValue(); + BigInteger g = (BigInteger) der.read().getValue(); + der.read(); // y + BigInteger x = (BigInteger) der.read().getValue(); + spec = new DSAPrivateKeySpec(x, p, q, g); + } + else + { + spec = new RSAPrivateCrtKeySpec( + (BigInteger) der.read().getValue(), // modulus + (BigInteger) der.read().getValue(), // pub exponent + (BigInteger) der.read().getValue(), // priv expenent + (BigInteger) der.read().getValue(), // prime p + (BigInteger) der.read().getValue(), // prime q + (BigInteger) der.read().getValue(), // d mod (p-1) + (BigInteger) der.read().getValue(), // d mod (q-1) + (BigInteger) der.read().getValue()); // coefficient + } + privateKeys.add(kf.generatePrivate(spec)); + certChains.add(chain); + } + + public List getPrivateKeys() + { + if (isDestroyed()) + { + throw new IllegalStateException("this object is destroyed"); + } + return privateKeys; + } + + public List getCertChains() + { + return certChains; + } + + public void destroy() + { + privateKeys.clear(); + privateKeys = null; + } + + public boolean isDestroyed() + { + return (privateKeys == null); + } + + // Own methods. + // ------------------------------------------------------------------------- + + private String readLine(InputStream in) throws IOException + { + boolean eol_is_cr = System.getProperty("line.separator").equals("\r"); + StringBuffer str = new StringBuffer(); + while (true) + { + int i = in.read(); + if (i == -1) + { + if (str.length() > 0) + break; + else + return null; + } + else if (i == '\r') + { + if (eol_is_cr) + break; + } + else if (i == '\n') + break; + else + str.append((char) i); + } + return str.toString(); + } + + private byte[] decryptKey(byte[] ct, String cipher, byte[] salt) + throws IOException, InvalidKeyException, WrongPaddingException + { + byte[] pt = new byte[ct.length]; + IMode mode = null; + if (cipher.equals("DES-EDE3-CBC")) + { + mode = ModeFactory.getInstance("CBC", "TripleDES", 8); + HashMap attr = new HashMap(); + attr.put(IMode.KEY_MATERIAL, deriveKey(salt, 24)); + attr.put(IMode.IV, salt); + attr.put(IMode.STATE, new Integer(IMode.DECRYPTION)); + mode.init(attr); + } + else if (cipher.equals("DES-CBC")) + { + mode = ModeFactory.getInstance("CBC", "DES", 8); + HashMap attr = new HashMap(); + attr.put(IMode.KEY_MATERIAL, deriveKey(salt, 8)); + attr.put(IMode.IV, salt); + attr.put(IMode.STATE, new Integer(IMode.DECRYPTION)); + mode.init(attr); + } + else + throw new IllegalArgumentException("unknown cipher: " + cipher); + + for (int i = 0; i < ct.length; i += 8) + mode.update(ct, i, pt, i); + + int pad = pt[pt.length-1]; + if (pad < 1 || pad > 8) + throw new WrongPaddingException(); + for (int i = pt.length - pad; i < pt.length; i++) + { + if (pt[i] != pad) + throw new WrongPaddingException(); + } + + byte[] result = new byte[pt.length - pad]; + System.arraycopy(pt, 0, result, 0, result.length); + return result; + } + + private byte[] deriveKey(byte[] salt, int keylen) + throws IOException + { + CallbackHandler passwordHandler = new ConsoleCallbackHandler(); + try + { + Class c = Class.forName(Security.getProperty("jessie.password.handler")); + passwordHandler = (CallbackHandler) c.newInstance(); + } + catch (Exception x) { } + + PasswordCallback passwdCallback = + new PasswordCallback("Enter PEM passphrase: ", false); + try + { + passwordHandler.handle(new Callback[] { passwdCallback }); + } + catch (UnsupportedCallbackException uce) + { + throw new IOException("specified handler cannot handle passwords"); + } + char[] passwd = passwdCallback.getPassword(); + + IMessageDigest md5 = HashFactory.getInstance("MD5"); + byte[] key = new byte[keylen]; + int count = 0; + while (count < keylen) + { + for (int i = 0; i < passwd.length; i++) + md5.update((byte) passwd[i]); + md5.update(salt, 0, salt.length); + byte[] digest = md5.digest(); + int len = Math.min(digest.length, keylen - count); + System.arraycopy(digest, 0, key, count, len); + count += len; + if (count >= keylen) + break; + md5.reset(); + md5.update(digest, 0, digest.length); + } + passwdCallback.clearPassword(); + return key; + } + + private byte[] toByteArray(String hex) + { + hex = hex.toLowerCase(); + byte[] buf = new byte[hex.length() / 2]; + int j = 0; + for (int i = 0; i < buf.length; i++) + { + buf[i] = (byte) ((Character.digit(hex.charAt(j++), 16) << 4) | + Character.digit(hex.charAt(j++), 16)); + } + return buf; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/SRPManagerParameters.java b/libjava/classpath/gnu/javax/net/ssl/SRPManagerParameters.java new file mode 100644 index 00000000000..a2a745e1b50 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/SRPManagerParameters.java @@ -0,0 +1,81 @@ +/* SRPManagerParameters.java -- Wrapper for SRP PasswordFile. + Copyright (C) 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.net.ssl; + +import javax.net.ssl.ManagerFactoryParameters; +import gnu.javax.crypto.sasl.srp.PasswordFile; + +/** + * Instances of this class are used to initialize {@link + * javax.net.ssl.TrustManagerFactory} instances for the ``SRP'' algorithm. + */ +public class SRPManagerParameters implements ManagerFactoryParameters +{ + + // Field. + // ------------------------------------------------------------------------- + + private final PasswordFile file; + + // Constructor. + // ------------------------------------------------------------------------- + + /** + * Initializes these parameters with the specified SRP password file. + * + * @param file The SRP password file object. + * @throws NullPointerException if <i>file</i> is <code>null</code>. + */ + public SRPManagerParameters(PasswordFile file) + { + if (file == null) + { + throw new NullPointerException(); + } + this.file = file; + } + + // Instance method. + // ------------------------------------------------------------------------- + + public PasswordFile getPasswordFile() + { + return file; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/SRPTrustManager.java b/libjava/classpath/gnu/javax/net/ssl/SRPTrustManager.java new file mode 100644 index 00000000000..664fa4cab19 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/SRPTrustManager.java @@ -0,0 +1,99 @@ +/* SRPTrustManager.java -- interface to SRP trust managers. + Copyright (C) 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.net.ssl; + +import gnu.javax.crypto.sasl.srp.PasswordFile; + +import java.math.BigInteger; +import java.security.KeyPair; +import javax.net.ssl.TrustManager; + +/** + * A trust manager for secure remote password (SRP) key exchange cipher + * suites. This is a read-only interface to the {@link + * gnu.crypto.sasl.srp.PasswordFile} class, with convenience methods to + * generate session key pairs. + */ +public interface SRPTrustManager extends TrustManager +{ + + // Methods. + // ------------------------------------------------------------------------- + + /** + * Tests if the configured password file contains the specified user name. + * + * @param user The user name. + * @return True if the password file has an entry for <i>user</i> + */ + boolean contains(String user); + + /** + * Create and return a session SRP key pair for the given user name. + * + * @param user The user name to generate the key pair for. + * @return The session key pair, or <code>null</code> if there is no + * entry for <i>user</i>. + */ + KeyPair getKeyPair(String user); + + /** + * Returns the salt value for the given user. + * + * @param user The user name. + * @return The salt for <i>user</i>'s entry, or <code>null</code>. + */ + byte[] getSalt(String user); + + /** + * Returns the password verifier for the given user. + * + * @param user The user name. + * @return <i>user</i>'s password verifier, or <code>null</code>. + */ + BigInteger getVerifier(String user); + + /** + * Returns a reference to the SRP {@link PasswordFile} used by this + * {@link TrustManager}. + * + * @return a reference to the SRP password file in use. + */ + PasswordFile getPasswordFile(); +} diff --git a/libjava/classpath/gnu/javax/net/ssl/StaticTrustAnchors.java b/libjava/classpath/gnu/javax/net/ssl/StaticTrustAnchors.java new file mode 100644 index 00000000000..0c2c3cca8a8 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/StaticTrustAnchors.java @@ -0,0 +1,1942 @@ +/* StaticTrustAnchors.java -- static list of CA certificates. + Copyright (C) 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.net.ssl; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +import java.util.LinkedList; + +import javax.net.ssl.ManagerFactoryParameters; + +/** + * This class implements a simple set of trust anchors suitable for + * initializing a TrustManagerFactory for the "JessieX509" algorithm. + * + * <p>The important field of this class is the {@link #CA_CERTS} + * constant, which contains an array of commonly accepted CA + * certificates. + */ +public class StaticTrustAnchors implements ManagerFactoryParameters +{ + + // Fields. + // ------------------------------------------------------------------------- + + private X509Certificate[] certs; + + // Constructor. + // ------------------------------------------------------------------------- + + public StaticTrustAnchors(X509Certificate[] certs) + { + this.certs = (X509Certificate[]) certs.clone(); + } + + // Class method. + // ------------------------------------------------------------------------- + + public static X509Certificate generate(CertificateFactory factory, + String encoded) + { + try + { + ByteArrayInputStream in = + new ByteArrayInputStream(encoded.getBytes("UTF-8")); + return (X509Certificate) factory.generateCertificate(in); + } + catch (Exception x) + { + return null; + } + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public X509Certificate[] getCertificates() + { + return (X509Certificate[]) certs.clone(); + } + + // Constant. + // ------------------------------------------------------------------------- + + /** + * A list of known certificate authority certificates. This set of + * certificates is the same as the default CA certificates used by + * Mozilla. + */ + public static final StaticTrustAnchors CA_CERTS; + + // Static initializer. + // ------------------------------------------------------------------------- + + static + { + LinkedList certs = new LinkedList(); + CertificateFactory factory = null; + + try + { + factory = CertificateFactory.getInstance("X.509"); + } + catch (CertificateException ce) + { + throw new Error(ce.toString()); + } + + X509Certificate cert = generate(factory, + // ABAecom_=sub.__Am._Bankers_Assn.=_Root_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDtTCCAp2gAwIBAgIRANAeQJAAAEZSAAAAAQAAAAQwDQYJKoZIhvcNAQEF\n" + + "BQAwgYkxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJEQzETMBEGA1UEBxMKV2Fz\n" + + "aGluZ3RvbjEXMBUGA1UEChMOQUJBLkVDT00sIElOQy4xGTAXBgNVBAMTEEFC\n" + + "QS5FQ09NIFJvb3QgQ0ExJDAiBgkqhkiG9w0BCQEWFWFkbWluQGRpZ3NpZ3Ry\n" + + "dXN0LmNvbTAeFw05OTA3MTIxNzMzNTNaFw0wOTA3MDkxNzMzNTNaMIGJMQsw\n" + + "CQYDVQQGEwJVUzELMAkGA1UECBMCREMxEzARBgNVBAcTCldhc2hpbmd0b24x\n" + + "FzAVBgNVBAoTDkFCQS5FQ09NLCBJTkMuMRkwFwYDVQQDExBBQkEuRUNPTSBS\n" + + "b290IENBMSQwIgYJKoZIhvcNAQkBFhVhZG1pbkBkaWdzaWd0cnVzdC5jb20w\n" + + "ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx0xHgeVVDBwhMywVC\n" + + "AOINg0Y95JO6tgbTDVm9PsHOQ2cBiiGo77zM0KLMsFWWU4RmBQDaREmA2FQK\n" + + "pSWGlO1jVv9wbKOhGdJ4vmgqRF4vz8wYXke8OrFGPR7wuSw0X4x8TAgpnUBV\n" + + "6zx9g9618PeKgw6hTLQ6pbNfWiKX7BmbwQVo/ea3qZGULOR4SCQaJRk665Wc\n" + + "OQqKz0Ky8BzVX/tr7WhWezkscjiw7pOp03t3POtxA6k4ShZsiSrK2jMTecJV\n" + + "jO2cu/LLWxD4LmE1xilMKtAqY9FlWbT4zfn0AIS2V0KFnTKo+SpU+/94Qby9\n" + + "cSj0u5C8/5Y0BONFnqFGKECBAgMBAAGjFjAUMBIGA1UdEwEB/wQIMAYBAf8C\n" + + "AQgwDQYJKoZIhvcNAQEFBQADggEBAARvJYbk5pYntNlCwNDJALF/VD6Hsm0k\n" + + "qS8Kfv2kRLD4VAe9G52dyntQJHsRW0mjpr8SdNWJt7cvmGQlFLdh6X9ggGvT\n" + + "ZOirvRrWUfrAtF13Gn9kCF55xgVM8XrdTX3O5kh7VNJhkoHWG9YA8A6eKHeg\n" + + "TYjHInYZw8eeG6Z3ePhfm1bR8PIXrI6dWeYf/le22V7hXZ9F7GFoGUHhsiAm\n" + + "/lowdiT/QHI8eZ98IkirRs3bs4Ysj78FQdPB4xTjQRcm0HyncUwZ6EoPclgx\n" + + "fexgeqMiKL0ZJGA/O4dzwGvky663qyVDslUte6sGDnVdNOVdc22esnVApVnJ\n" + + "TzFxiNmIf1Q=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // AOL_Time_Warner_Root_Certification_Authority_1.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIID5jCCAs6gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMC\n" + + "VVMxHTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNB\n" + + "bWVyaWNhIE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIg\n" + + "Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyOTA2MDAw\n" + + "MFoXDTM3MTEyMDE1MDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRB\n" + + "T0wgVGltZSBXYXJuZXIgSW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUg\n" + + "SW5jLjE3MDUGA1UEAxMuQU9MIFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNh\n" + + "dGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n" + + "ggEBAJnej8Mlo2k06AX3dLm/WpcZuS+U0pPlLYnKhHw/EEMbjIt8hFj4JHxI\n" + + "zyr9wBXZGH6EGhfT257XyuTZ16pYUYfw8ItITuLCxFlpMGK2MKKMCxGZYTVt\n" + + "fu/FsRkGIBKOQuHfD5YQUqjPnF+VFNivO3ULMSAfRC+iYkGzuxgh28pxPIzs\n" + + "trkNn+9R7017EvILDOGsQI93f7DKeHEMXRZxcKLXwjqFzQ6axOAAsNUl6twr\n" + + "5JQtOJyJQVdkKGUZHLZEtMgxa44Be3ZZJX8VHIQIfHNlIAqhBC4aMqiaILGc\n" + + "LCFZ5/vP7nAtCMpjPiybkxlqpMKX/7eGV4iFbJ4VFitNLLMCAwEAAaNjMGEw\n" + + "DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUoTYwFsuGkABFgFOxj8jYPXy+\n" + + "XxIwHwYDVR0jBBgwFoAUoTYwFsuGkABFgFOxj8jYPXy+XxIwDgYDVR0PAQH/\n" + + "BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQCKIBilvrMvtKaEAEAwKfq0FHNM\n" + + "eUWn9nDg6H5kHgqVfGphwu9OH77/yZkfB2FK4V1Mza3u0FIy2VkyvNp5ctZ7\n" + + "CegCgTXTCt8RHcl5oIBN/lrXVtbtDyqvpxh1MwzqwWEFT2qaifKNuZ8u77Bf\n" + + "WgDrvq2g+EQFZ7zLBO+eZMXpyD8Fv8YvBxzDNnGGyjhmSs3WuEvGbKeXO/oT\n" + + "LW4jYYehY0KswsuXn2Fozy1MBJ3XJU8KDk2QixhWqJNIV9xvrr2eZ1d3iVCz\n" + + "vhGbRWeDhhmH05i9CBoWH1iCC+GWaQVLjuyDUTEH1dSf/1l7qG6Fz9NLqUmw\n" + + "X7A5KGgOc90lmt4S\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // AOL_Time_Warner_Root_Certification_Authority_2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIF5jCCA86gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMC\n" + + "VVMxHTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNB\n" + + "bWVyaWNhIE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIg\n" + + "Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyOTA2MDAw\n" + + "MFoXDTM3MDkyODIzNDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRB\n" + + "T0wgVGltZSBXYXJuZXIgSW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUg\n" + + "SW5jLjE3MDUGA1UEAxMuQU9MIFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNh\n" + + "dGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC\n" + + "ggIBALQ3WggWmRToVbEbJGv8x4vmh6mJ7ouZzU9AhqS2TcnZsdw8TQ2FTBVs\n" + + "RotSeJ/4I/1n9SQ6aF3Q92RhQVSji6UI0ilbm2BPJoPRYxJWSXakFsKlnUWs\n" + + "i4SVqBax7J/qJBrvuVdcmiQhLE0OcR+mrF1FdAOYxFSMFkpBd4aVdQxHAWZg\n" + + "/BXxD+r1FHjHDtdugRxev17nOirYlxcwfACtCJ0zr7iZYYCLqJV+FNwSbKTQ\n" + + "2O9ASQI2+W6p1h2WVgSysy0WVoaP2SBXgM1nEG2wTPDaRrbqJS5Gr42whTg0\n" + + "ixQmgiusrpkLjhTXUr2eacOGAgvqdnUxCc4zGSGFQ+aJLZ8lN2fxI2rSAG2X\n" + + "+Z/nKcrdH9cG6rjJuQkhn8g/BsXS6RJGAE57COtCPStIbp1n3UsC5ETzkxml\n" + + "J85per5n0/xQpCyrw2u544BMzwVhSyvcG7mm0tCq9Stz+86QNZ8MUhy/XCFh\n" + + "EVsVS6kkUfykXPcXnbDS+gfpj1bkGoxoigTTfFrjnqKhynFbotSg5ymFXQNo\n" + + "Kk/SBtc9+cMDLz9l+WceR0DTYw/j1Y75hauXTLPXJuuWCpTehTacyH+BCQJJ\n" + + "Kg71ZDIMgtG6aoIbs0t0EfOMd9afv9w3pKdVBC/UMejTRrkDfNoSTllkt1Ex\n" + + "MVCgyhwn2RAurda9EGYrw7AiShJbAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMB\n" + + "Af8wHQYDVR0OBBYEFE9pbQN+nZ8HGEO8txBO1b+pxCAoMB8GA1UdIwQYMBaA\n" + + "FE9pbQN+nZ8HGEO8txBO1b+pxCAoMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG\n" + + "9w0BAQUFAAOCAgEAO/Ouyuguh4X7ZVnnrREUpVe8WJ8kEle7+z802u6teio0\n" + + "cnAxa8cZmIDJgt43d15Ui47y6mdPyXSEkVYJ1eV6moG2gcKtNuTxVBFT8zRF\n" + + "ASbI5Rq8NEQh3q0l/HYWdyGQgJhXnU7q7C+qPBR7V8F+GBRn7iTGvboVsNIY\n" + + "vbdVgaxTwOjdaRITQrcCtQVBynlQboIOcXKTRuidDV29rs4prWPVVRaAMCf/\n" + + "drr3uNZK49m1+VLQTkCpx+XCMseqdiThawVQ68W/ClTluUI8JPu3B5wwn3la\n" + + "5uBAUhX0/Kr0VvlEl4ftDmVyXr4m+02kLQgH3thcoNyBM5kYJRF3p+v9WAks\n" + + "mWsbivNSPxpNSGDxoPYzAlOL7SUJuA0t7Zdz7NeWH45gDtoQmy8YJPamTQr5\n" + + "O8t1wswvziRpyQoijlmn94IM19drNZxDAGrElWe6nEXLuA4399xOAU++CrYD\n" + + "062KRffaJ00psUjf5BHklka9bAI+1lHIlRcBFanyqqryvy9lG2/QuRqT9Y41\n" + + "xICHPpQvZuTpqP9BnHAqTyo5GJUefvthATxRCC4oGKQWDzH9OmwjkyB24f0H\n" + + "hdFbP9IcczLd+rn4jM8Ch3qaluTtT4mNU0OrDhPAARW0eTjb/G49nlG2uBOL\n" + + "Z8/5fNkiHfZdxRwBL5joeiQYvITX+txyW/fBOmg=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // AddTrust_External_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJT\n" + + "RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4\n" + + "dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5h\n" + + "bCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzEL\n" + + "MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1B\n" + + "ZGRUcnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1\n" + + "c3QgRXh0ZXJuYWwgQ0EgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\n" + + "AQoCggEBALf3GjPm8gAELTngTlvtH7xsD821+iO2zt6bETOXpClMfZOfvUq8\n" + + "k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfwTz/oMp50\n" + + "ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504\n" + + "B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDez\n" + + "eWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5\n" + + "aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0WicCAwEAAaOB\n" + + "3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0PBAQD\n" + + "AgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6\n" + + "xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU\n" + + "cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdv\n" + + "cmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJ\n" + + "KoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl\n" + + "j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5R\n" + + "xNKWt9x+Tu5w/Rw56wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjT\n" + + "K3rMUUKhemPR5ruhxSvCNr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1\n" + + "n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHx\n" + + "REzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49O\n" + + "hgQ=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // AddTrust_Low-Value_Services_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJT\n" + + "RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU\n" + + "UCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3Qw\n" + + "HhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJT\n" + + "RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU\n" + + "UCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3Qw\n" + + "ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwze\n" + + "xODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY654eyNAbFvAWlA3yCyykQruGI\n" + + "gb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWroulpOj0O\n" + + "M3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1Lc\n" + + "sRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5\n" + + "mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG\n" + + "9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0OBBYEFJWxtPCU\n" + + "tr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTADAQH/\n" + + "MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQsw\n" + + "CQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk\n" + + "ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAx\n" + + "IENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0\n" + + "MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0Ph\n" + + "iVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9\n" + + "tTEv2dB8Xfjea4MYeDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL\n" + + "/bscVjby/rK25Xa71SJlpz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlV\n" + + "g3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6\n" + + "tkD9xOQ14R0WHNC8K47Wcdk=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // AddTrust_Public_Services_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJT\n" + + "RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU\n" + + "UCBOZXR3b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAe\n" + + "Fw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNF\n" + + "MRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQ\n" + + "IE5ldHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIB\n" + + "IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+\n" + + "A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c\n" + + "+OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1id9NEHif2\n" + + "P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKX\n" + + "C1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8R\n" + + "s3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9\n" + + "BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQWBBSBPjfYkrAf\n" + + "d59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zCB\n" + + "jgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkG\n" + + "A1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU\n" + + "cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENB\n" + + "IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmu\n" + + "G7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL\n" + + "+YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbj\n" + + "PGsye/Kf8Lb93/AoGEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bY\n" + + "GozH7ZxOmuASu7VqTITh4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6\n" + + "NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9HEufOX1362Kqx\n" + + "My3ZdvJOOjMMK7MtkAY=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // AddTrust_Qualified_Certificates_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJT\n" + + "RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU\n" + + "UCBOZXR3b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9v\n" + + "dDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYT\n" + + "AlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3Qg\n" + + "VFRQIE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBS\n" + + "b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoek\n" + + "n0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKk\n" + + "IhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3KP0q6p6z\n" + + "sLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1t\n" + + "UvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R\n" + + "+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvES\n" + + "a0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0GA1UdDgQWBBQ5\n" + + "lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw\n" + + "AwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkw\n" + + "ZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL\n" + + "ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVh\n" + + "bGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2Vh\n" + + "lRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxG\n" + + "GuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx9\n" + + "5dr6h+sNNVJn0J6XdgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKF\n" + + "Yqa0p9m9N5xotS1WfbC3P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVA\n" + + "wRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQw\n" + + "dOUeqN48Jzd/g66ed8/wMLH/S5noxqE=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // America_Online_Root_Certification_Authority_1.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJV\n" + + "UzEcMBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1l\n" + + "cmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4X\n" + + "DTAyMDUyODA2MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkGA1UEBhMCVVMx\n" + + "HDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJp\n" + + "Y2EgT25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIw\n" + + "DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCa\n" + + "xlCyfqXfaE0bfA+2l2h9LaaLl+lkhsmj76CGv2BlnEtUiMJIxUo5vxTjWVXl\n" + + "GbR0yLQFOVwWpeKVBeASrlmLojNoWBym1BW32J/X3HGrfpq/m44zDyL9Hy7n\n" + + "BzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsWOqMFf6Dch9Wc/HKpoH145Lcx\n" + + "VR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb2xzTa5qGUwew76wGePiE\n" + + "mf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQkoO3rHl+Ee5fSfwMCu\n" + + "JKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAdBgNV\n" + + "HQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAUAK3Zo/Z5\n" + + "9m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUA\n" + + "A4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkF\n" + + "Zu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B6UlwGBaXCBOM\n" + + "IOAbLjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTI\n" + + "dGcL+oiroQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43g\n" + + "Kd8hdIaC2y+CMMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j\n" + + "8uB9Gr784N/Xx6dssPmuujz9dLQR6FgNgLzTqIA6me11zEZ7\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // America_Online_Root_Certification_Authority_2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJV\n" + + "UzEcMBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1l\n" + + "cmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4X\n" + + "DTAyMDUyODA2MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkGA1UEBhMCVVMx\n" + + "HDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJp\n" + + "Y2EgT25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIw\n" + + "DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssN\n" + + "t79Hc9PwVU3dxgz6sWYFas14tNwC206B89enfHG8dWOgXeMHDEjsJcQDIPT/\n" + + "DjsS/5uN4cbVG7RtIuOx238hZK+GvFciKtZHgVdEglZTvYYUAQv8f3SkWq7x\n" + + "uhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2JxhP7JsowtS013wMPgwr38oE\n" + + "18aO6lhOqKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9BoInLRBYBbV4Bbkv2wxr\n" + + "kJB+FFk4u5QkE+XRnRTf04JNRvCAOVIyD+OEsnpD8l7eXz8d3eOyG6ChKiMD\n" + + "bi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0gBe4lL8BPeraunzgWGcX\n" + + "uVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67Xnfn6KVu\n" + + "Y8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEqZ8A9\n" + + "W6Wa6897GqidFEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZ\n" + + "o2C7HK2JNDJiuEMhBnIMoVxtRsX6Kc8w3onccVvdtjc+31D1uAclJuW8tf48\n" + + "ArO3+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnjB453cMor9H124Hhn\n" + + "AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3Op\n" + + "aaEg5+31IqEjFNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNee\n" + + "MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypL\n" + + "M7PmG2tZTiLMubekJcmnxPBUlgtk87FYT15R/LKXeydlwuXK5w0MJXti4/qf\n" + + "tIe3RUavg6WXSIylvfEWK5t2LHo1YGwRgJfMqZJS5ivmae2p+DYtLHe/YUjR\n" + + "Ywu5W1LtGLBDQiKmsXeu3mnFzcccobGlHBD7GL4acN3Bkku+KVqdPzW+5X1R\n" + + "+FXgJXUjhx5c3LqdsKyzadsXg8n33gy8CNyRnqjQ1xU3c6U1uPx+xURABsPr\n" + + "+CKAXEfOAuMRn0T//ZoyzH1kUQ7rVyZ2OuMeIjzCpjbdGe+n/BLzJsBZMYVM\n" + + "nNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgOZtMADjMSW7yV5TKQqLPGbIOt\n" + + "d+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2FAjgQ5ANh1NolNscI\n" + + "WC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUXOm/9riW99XJZ\n" + + "ZLF0KjhfGEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPbAZO1XB4Y\n" + + "3WRayhgoPmMEEf0cjQAPuDffZ4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQlZvqz\n" + + "2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuPcX/9XhmgD0uRuMRUvAaw\n" + + "RY8mkaKO/qk=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Baltimore_CyberTrust_Code_Signing_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDpjCCAo6gAwIBAgIEAgAAvzANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQG\n" + + "EwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0\n" + + "MS8wLQYDVQQDEyZCYWx0aW1vcmUgQ3liZXJUcnVzdCBDb2RlIFNpZ25pbmcg\n" + + "Um9vdDAeFw0wMDA1MTcxNDAxMDBaFw0yNTA1MTcyMzU5MDBaMGcxCzAJBgNV\n" + + "BAYTAklFMRIwEAYDVQQKEwlCYWx0aW1vcmUxEzARBgNVBAsTCkN5YmVyVHJ1\n" + + "c3QxLzAtBgNVBAMTJkJhbHRpbW9yZSBDeWJlclRydXN0IENvZGUgU2lnbmlu\n" + + "ZyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyHGaGBKO\n" + + "etv5mvxBr9jy9AmOrT/+Zzc82skmULGxPsvoTnMA8rLc88VG+wnvGJbOp+Cc\n" + + "hF0gDnqgqjaL+ii2eC6z7OhH8wTwkCO06q/lU7gF90ddK4bxp6TGOzW20g1S\n" + + "Qdf0knXhogpQVoe+lwt7M4UQuSgY7jPqSBHXW5FHdiLU7s9d56hOHJ2Wkd2c\n" + + "vXQJqHJhqrAhOvE9LANWCdLB3MO1x1Q3q+YmorJGcXPKEYjuvOdk99ARGnNA\n" + + "WshJLA+375B/aIAEOAsbDzvU9aCzwo7hNLSAmW2edtSSKUCxldI3pGcSf+Bi\n" + + "u641xZk2gkS45ngYM2Fxk1stjZ94lYLrbQIDAQABo1owWDATBgNVHSUEDDAK\n" + + "BggrBgEFBQcDAzAdBgNVHQ4EFgQUyEE0XBUVBOVA8tGrmm8kknqHQlowEgYD\n" + + "VR0TAQH/BAgwBgEB/wIBAzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEF\n" + + "BQADggEBAFJ0qpVLIozHPZak/l36L7W86/AL6VY4HdFtDaG8aIvwxYClJDT9\n" + + "8pYYEYahNvU351RA1WQfw19wQmstOceeUgXO52py0o1yP0dQg6vHjSXJsOOn\n" + + "UxaVpmpT6hidj3ipd3ca+bSXR1mIJyi1yuEu1z4Oog24IkQD49FjsEE6ofWk\n" + + "Lfd2HgRUmXgyQNcrfE26ppyweW4Hvozs7tc4aVvBDFZon/7r0eHIiPnyzX++\n" + + "hbREZwBQPvQmA2Tqd33oXj4cN0fI1uqk8zY8l8I5cgWUGSXD1zdBD8Efh4r9\n" + + "qr7psWRX5NuSoc/hSeg7H5ETWsOP2SVYSYBHD8YDrqzjv7fAqio=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Baltimore_CyberTrust_Mobile_Commerce_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICfTCCAeagAwIBAgIEAgAAuDANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG\n" + + "EwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0\n" + + "MSkwJwYDVQQDEyBCYWx0aW1vcmUgQ3liZXJUcnVzdCBNb2JpbGUgUm9vdDAe\n" + + "Fw0wMDA1MTIxODIwMDBaFw0yMDA1MTIyMzU5MDBaMGExCzAJBgNVBAYTAklF\n" + + "MRIwEAYDVQQKEwlCYWx0aW1vcmUxEzARBgNVBAsTCkN5YmVyVHJ1c3QxKTAn\n" + + "BgNVBAMTIEJhbHRpbW9yZSBDeWJlclRydXN0IE1vYmlsZSBSb290MIGfMA0G\n" + + "CSqGSIb3DQEBAQUAA4GNADCBiQKBgQCjbbE4Vqz8tVYh3sCQXSZHgsZ9jx+g\n" + + "hY8vu9ThHB3yJB8osC+5pKVvoiIgZP6ERzx+K2xparjUwJaOjFINzW9B1L8E\n" + + "rqeBLy2YSNLBlKO1GV1dUWT0jkGwm8AtIqBexthaEmO8EUpeJhId4iYF5g9f\n" + + "Ih96X3aUrs9aKA6rRdoiMQIDAQABo0IwQDAdBgNVHQ4EFgQUyeKPwAImWrbA\n" + + "B+N/lAcY2y6lmnAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYw\n" + + "DQYJKoZIhvcNAQEFBQADgYEAUwgLJgl4QnPU7Hp3Rw3jCzNx764zFE37+v0a\n" + + "t1H15JkcBnHXKRnX5hUgUVFGbU/eGEmY0Ph4u3HojQEG1ddkj5TfR/6ghWk2\n" + + "qS9CemhKEtaLC3BECqQE7yaIwTVxOF0bW0hC8OeUHHCVNKir9avieK318FL9\n" + + "m+pCDOjYVL5TZvU=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Baltimore_CyberTrust_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQG\n" + + "EwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0\n" + + "MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUx\n" + + "MjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNV\n" + + "BAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZ\n" + + "QmFsdGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQAD\n" + + "ggEPADCCAQoCggEBAKMEuyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+h\n" + + "Xe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gR\n" + + "QKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/CG9VwcPCP\n" + + "wBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1\n" + + "pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNT\n" + + "Px8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkC\n" + + "AwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1BE3wMBIGA1Ud\n" + + "EwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUA\n" + + "A4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkT\n" + + "I7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx\n" + + "jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/\n" + + "oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67\n" + + "G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H\n" + + "RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Digital_Signature_Trust_Co._Global_CA_1.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQG\n" + + "EwJVUzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREw\n" + + "DwYDVQQLEwhEU1RDQSBFMTAeFw05ODEyMTAxODEwMjNaFw0xODEyMTAxODQw\n" + + "MjNaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVy\n" + + "ZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEB\n" + + "AQUAA4GLADCBhwKBgQCgbIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlR\n" + + "EmlvMVW5SXIACH7TpWJENySZj9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+Lth\n" + + "zfNHwJmm8fOR6Hh8AMthyUQncWlVSn5JTe2io74CTADKAqjuAQIxZA9SLRN0\n" + + "dja1erQtcQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBoBgNVHR8E\n" + + "YTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwg\n" + + "U2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTExDTALBgNV\n" + + "BAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMTAxODEwMjNagQ8yMDE4MTIx\n" + + "MDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFGp5fpFpRhgTCgJ3\n" + + "pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i+DAMBgNV\n" + + "HRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3\n" + + "DQEBBQUAA4GBACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lN\n" + + "QseSJqBcNJo4cvj9axY+IO6CizEqkzaFI4iKPANo08kJD038bKTaKHKTDomA\n" + + "sH3+gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4RbyhkwS7hp86W0N6\n" + + "w4pl\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Digital_Signature_Trust_Co._Global_CA_2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIID2DCCAsACEQDQHkCLAAACfAAAAAIAAAABMA0GCSqGSIb3DQEBBQUAMIGp\n" + + "MQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBM\n" + + "YWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENv\n" + + "LjERMA8GA1UECxMIRFNUQ0EgWDExFjAUBgNVBAMTDURTVCBSb290Q0EgWDEx\n" + + "ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODEyMDEx\n" + + "ODE4NTVaFw0wODExMjgxODE4NTVaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UE\n" + + "CBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0Rp\n" + + "Z2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgWDEx\n" + + "FjAUBgNVBAMTDURTVCBSb290Q0EgWDExITAfBgkqhkiG9w0BCQEWEmNhQGRp\n" + + "Z3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n" + + "ANLGJrbnpT3BxGjVUG9TxW9JEwm4ryxIjRRqoxdfWvnTLnUv2Chi0ZMv/E3U\n" + + "q4flCMeZ55I/db3rJbQVwZsZPdJEjdd0IG03Ao9pk1uKxBmd9LIO/BZsubEF\n" + + "koPRhSxglD5FVaDZqwgh5mDoO3TymVBRaNADLbGAvqPYUrBEzUNKcI5YhZXh\n" + + "TizWLUFv1oTnyJhEykfbLCSlaSbPa7gnYsP0yXqSI+0TZ4KuRS5F5X5yP4Wd\n" + + "lGIQ5jyRoa13AOAV7POEgHJ6jm5gl8ckWRA0g1vhpaRptlc1HHhZxtMvOnNn\n" + + "7pTKBBMFYgZwI7P0fO5F2WQLW0mqpEPOJsREEmy43XkCAwEAATANBgkqhkiG\n" + + "9w0BAQUFAAOCAQEAojeyP2n714Z5VEkxlTMr89EJFEliYIalsBHiUMIdBlc+\n" + + "LegzZL6bqq1fG03UmZWii5rJYnK1aerZWKs17RWiQ9a2vAd5ZWRzfdd5ynvV\n" + + "WlHG4VMElo04z6MXrDlxawHDi1M8Y+nuecDkvpIyZHqzH5eUYr3qsiAVlfuX\n" + + "8ngvYzZAOONGDx3drJXK50uQe7FLqdTF65raqtWjlBRGjS0f8zrWkzr2Pnn8\n" + + "6Oawde3uPclwx12qgUtGJRzHbBXjlU4PqjI3lAoXJJIThFjSY28r9+ZbYgsT\n" + + "F7ANUkz+/m9c4pFuHf2kYtdo+o56T9II2pPc8JIRetDccpMMc5NihWjQ9A==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Digital_Signature_Trust_Co._Global_CA_3.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQG\n" + + "EwJVUzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREw\n" + + "DwYDVQQLEwhEU1RDQSBFMjAeFw05ODEyMDkxOTE3MjZaFw0xODEyMDkxOTQ3\n" + + "MjZaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVy\n" + + "ZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEB\n" + + "AQUAA4GLADCBhwKBgQC/k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fB\n" + + "w18DW9Fvrn5C6mYjuGODVvsoLeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87e\n" + + "ZfCocfdPJmyMvMa1795JJ/9IKn3oTQPMx7JSxhcxEzu1TdvIxPbDDyQq2gyd\n" + + "55FbgM2UnQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBoBgNVHR8E\n" + + "YTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwg\n" + + "U2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTIxDTALBgNV\n" + + "BAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMDkxOTE3MjZagQ8yMDE4MTIw\n" + + "OTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFB6CTShlgDzJQW6s\n" + + "NS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5WzAMBgNV\n" + + "HRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3\n" + + "DQEBBQUAA4GBAEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHR\n" + + "xdf0CiUPPXiBng+xZ8SQTGPdXqfiup/1902lMXucKS1M/mQ+7LZT/uqb7YLb\n" + + "dHVLB3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1mPnHfxsb1gYgAlih\n" + + "w6ID\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Digital_Signature_Trust_Co._Global_CA_4.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIID2DCCAsACEQDQHkCLAAB3bQAAAAEAAAAEMA0GCSqGSIb3DQEBBQUAMIGp\n" + + "MQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBM\n" + + "YWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENv\n" + + "LjERMA8GA1UECxMIRFNUQ0EgWDIxFjAUBgNVBAMTDURTVCBSb290Q0EgWDIx\n" + + "ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODExMzAy\n" + + "MjQ2MTZaFw0wODExMjcyMjQ2MTZaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UE\n" + + "CBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0Rp\n" + + "Z2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgWDIx\n" + + "FjAUBgNVBAMTDURTVCBSb290Q0EgWDIxITAfBgkqhkiG9w0BCQEWEmNhQGRp\n" + + "Z3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n" + + "ANx18IzAdZaawGIfJvfE4Zrq4FZzW5nNAUSoCLbVp9oaBBg5kkp4o4HC9Xd6\n" + + "ULRw/5qrxsfKboNPQpj7Jgva3G3WqZlVUmfpKAOS3OWwBZoPFflrWXJW8vo5\n" + + "/Kpo7g8fEIMv/J36F5bdguPmRX3AS4BEH+0s4IT9kVySVGkl5WJp3OXuAFK9\n" + + "MwutdQKFp2RQLcUZGTDAJtvJ0/0uma1ZtQtN1EGuhUhDWdy3qOKi3sOP17ih\n" + + "YqZoUFLkzzGnlIXan0YyF1bl8utmPRL/Q9uY73fPy4GNNLHGUEom0eQ+QVCv\n" + + "bK4iNC7Va26Dunm4dmVI2gkpZGMiuftHdoWMhkTLCdsCAwEAATANBgkqhkiG\n" + + "9w0BAQUFAAOCAQEAtTYOXeFhKFoRZcA/gwN5Tb4opgsHAlKFzfiR0BBstWog\n" + + "WxyQ2TA8xkieil5k+aFxd+8EJx8H6+Qm93N0yUQYGmbT4EOvkTvRyyzYdFQ6\n" + + "HE3K1GjNI3wdEJ5F6fYAbqbNGf9PLCmPV03Ed5K+4EwJ+11EhmYhqLkyolbV\n" + + "6YyDfFk/xPEL553snr2cGA4+wjl5KLcDDQjLxufZATdQEOzMYRZA1K8xdHv8\n" + + "PzGn0EdzMzkbzE5q10mDEQb+64JYMzJM8FasHpwvVpp7wUocpf1VNs78lk30\n" + + "sPDst2yC7S8xmUJMqbINuBVd8d+6ybVK1GSYsyapMMj9puyrliGtf8J4tg==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Entrust.net_Global_Secure_Personal_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEgzCCA+ygAwIBAgIEOJ725DANBgkqhkiG9w0BAQQFADCBtDEUMBIGA1UE\n" + + "ChMLRW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9HQ0NB\n" + + "X0NQUyBpbmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsT\n" + + "HChjKSAyMDAwIEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1\n" + + "c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMDAy\n" + + "MDcxNjE2NDBaFw0yMDAyMDcxNjQ2NDBaMIG0MRQwEgYDVQQKEwtFbnRydXN0\n" + + "Lm5ldDFAMD4GA1UECxQ3d3d3LmVudHJ1c3QubmV0L0dDQ0FfQ1BTIGluY29y\n" + + "cC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDIwMDAg\n" + + "RW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xp\n" + + "ZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA\n" + + "A4GNADCBiQKBgQCTdLS25MVL1qFof2LV7PdRV7NySpj10InJrWPNTTVRaoTU\n" + + "rcloeW+46xHbh65cJFET8VQlhK8pK5/jgOLZy93GRUk0iJBeAZfv6lOm3fzB\n" + + "3ksqJeTpNfpVBQbliXrqpBFXO/x8PTbNZzVtpKklWb1m9fkn5JVn1j+SgF7y\n" + + "NH0rhQIDAQABo4IBnjCCAZowEQYJYIZIAYb4QgEBBAQDAgAHMIHdBgNVHR8E\n" + + "gdUwgdIwgc+ggcyggcmkgcYwgcMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUAw\n" + + "PgYDVQQLFDd3d3cuZW50cnVzdC5uZXQvR0NDQV9DUFMgaW5jb3JwLiBieSBy\n" + + "ZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMjAwMCBFbnRydXN0\n" + + "Lm5ldCBMaW1pdGVkMTMwMQYDVQQDEypFbnRydXN0Lm5ldCBDbGllbnQgQ2Vy\n" + + "dGlmaWNhdGlvbiBBdXRob3JpdHkxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQw\n" + + "IoAPMjAwMDAyMDcxNjE2NDBagQ8yMDIwMDIwNzE2NDY0MFowCwYDVR0PBAQD\n" + + "AgEGMB8GA1UdIwQYMBaAFISLdP3FjcD/J20gN0V8/i3OutN9MB0GA1UdDgQW\n" + + "BBSEi3T9xY3A/ydtIDdFfP4tzrrTfTAMBgNVHRMEBTADAQH/MB0GCSqGSIb2\n" + + "fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQQFAAOBgQBObzWA\n" + + "O9GK9Q6nIMstZVXQkvTnhLUGJoMShAusO7JE7r3PQNsgDrpuFOow4DtifH+L\n" + + "a3xKp9U1PL6oXOpLu5OOgGarDyn9TS2/GpsKkMWr2tGzhtQvJFJcem3G8v7l\n" + + "TRowjJDyutdKPkN+1MhQGof4T4HHdguEOnKdzmVml64mXg==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Entrust.net_Global_Secure_Server_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIElTCCA/6gAwIBAgIEOJsRPDANBgkqhkiG9w0BAQQFADCBujEUMBIGA1UE\n" + + "ChMLRW50cnVzdC5uZXQxPzA9BgNVBAsUNnd3dy5lbnRydXN0Lm5ldC9TU0xf\n" + + "Q1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc\n" + + "KGMpIDIwMDAgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVz\n" + + "dC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe\n" + + "Fw0wMDAyMDQxNzIwMDBaFw0yMDAyMDQxNzUwMDBaMIG6MRQwEgYDVQQKEwtF\n" + + "bnRydXN0Lm5ldDE/MD0GA1UECxQ2d3d3LmVudHJ1c3QubmV0L1NTTF9DUFMg\n" + + "aW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykg\n" + + "MjAwMCBFbnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5l\n" + + "dCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0G\n" + + "CSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHwV9OcfHO8GCGD9JYf9Mzly0XonUw\n" + + "tZZkJi9ow0SrqHXmAGc0V55lxyKbc+bT3QgON1WqJUaBbL3+qPZ1V1eMkGxK\n" + + "wz6LS0MKyRFWmponIpnPVZ5h2QLifLZ8OAfc439PmrkDQYC2dWcTC5/oVzbI\n" + + "XQA23mYU2m52H083jIITiQIDAQABo4IBpDCCAaAwEQYJYIZIAYb4QgEBBAQD\n" + + "AgAHMIHjBgNVHR8EgdswgdgwgdWggdKggc+kgcwwgckxFDASBgNVBAoTC0Vu\n" + + "dHJ1c3QubmV0MT8wPQYDVQQLFDZ3d3cuZW50cnVzdC5uZXQvU1NMX0NQUyBp\n" + + "bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAy\n" + + "MDAwIEVudHJ1c3QubmV0IExpbWl0ZWQxOjA4BgNVBAMTMUVudHJ1c3QubmV0\n" + + "IFNlY3VyZSBTZXJ2ZXIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxDTALBgNV\n" + + "BAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMDAyMDQxNzIwMDBagQ8yMDIwMDIw\n" + + "NDE3NTAwMFowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFMtswGvjuz7L/CKc\n" + + "/vuLkpyw8m4iMB0GA1UdDgQWBBTLbMBr47s+y/winP77i5KcsPJuIjAMBgNV\n" + + "HRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkq\n" + + "hkiG9w0BAQQFAAOBgQBi24GRzsiad0Iv7L0no1MPUBvqTpLwqa+poLpIYcvv\n" + + "yQbvH9X07t9WLebKahlzqlO+krNQAraFJnJj2HVQYnUUt7NQGj/KEQALhUVp\n" + + "bbalrlHhStyCP2yMNLJ3a9kC9n8O6mUE8c1UyrrJzOCE98g+EZfTYAkYvAX/\n" + + "bIkz8OwVDw==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Entrust.net_Premium_2048_Secure_Server_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UE\n" + + "ChMLRW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNf\n" + + "MjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsT\n" + + "HChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1\n" + + "c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEy\n" + + "MjQxNzUwNTFaFw0xOTEyMjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0\n" + + "Lm5ldDFAMD4GA1UECxQ3d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29y\n" + + "cC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkg\n" + + "RW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2Vy\n" + + "dGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEF\n" + + "AAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4\n" + + "QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/EC\n" + + "DNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuXMlBvPci6Zgzj\n" + + "/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzWnLLP\n" + + "KQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZd\n" + + "enoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH\n" + + "4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB\n" + + "0RGAvtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJ\n" + + "FrlwMB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0B\n" + + "AQUFAAOCAQEAWUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFh\n" + + "fGPjK50xA3B20qMooPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVU\n" + + "KcgF7bISKo30Axv/55IQh7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaoho\n" + + "wXkCIryqptau37AUX7iH0N18f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2\n" + + "+z7pnIkPFc4YsIV4IU9rTw76NmfNB/L/CNDi3tm/Kq+4h4YhPATKt5Rof888\n" + + "6ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVyvUxFnmG6v4SBkgPR0ml8xQ==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Entrust.net_Secure_Personal_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIE7TCCBFagAwIBAgIEOAOR7jANBgkqhkiG9w0BAQQFADCByTELMAkGA1UE\n" + + "BhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUgwRgYDVQQLFD93d3cuZW50\n" + + "cnVzdC5uZXQvQ2xpZW50X0NBX0luZm8vQ1BTIGluY29ycC4gYnkgcmVmLiBs\n" + + "aW1pdHMgbGlhYi4xJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExp\n" + + "bWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0\n" + + "aW9uIEF1dGhvcml0eTAeFw05OTEwMTIxOTI0MzBaFw0xOTEwMTIxOTU0MzBa\n" + + "MIHJMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNV\n" + + "BAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5mby9DUFMgaW5jb3Jw\n" + + "LiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMpIDE5OTkgRW50\n" + + "cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xpZW50\n" + + "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GL\n" + + "ADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/Bo6oT9n3V5z8GKUZSv\n" + + "x1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux5zDeg7K6PvHV\n" + + "iTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zmAqTmT173\n" + + "iwIBA6OCAeAwggHcMBEGCWCGSAGG+EIBAQQEAwIABzCCASIGA1UdHwSCARkw\n" + + "ggEVMIHkoIHhoIHepIHbMIHYMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50\n" + + "cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0Ff\n" + + "SW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UE\n" + + "CxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50\n" + + "cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYD\n" + + "VQQDEwRDUkwxMCygKqAohiZodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9D\n" + + "bGllbnQxLmNybDArBgNVHRAEJDAigA8xOTk5MTAxMjE5MjQzMFqBDzIwMTkx\n" + + "MDEyMTkyNDMwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUxPucKXuXzUyW\n" + + "/O5bs8qZdIuV6kwwHQYDVR0OBBYEFMT7nCl7l81MlvzuW7PKmXSLlepMMAwG\n" + + "A1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI\n" + + "hvcNAQEEBQADgYEAP66K8ddmAwWePvrqHEa7pFuPeJoSSJn59DXeDDYHAmsQ\n" + + "OokUgZwxpnyyQbJq5wcBoUv5nyU7lsqZwz6hURzzwy5E97BnRqqS5TvaHBkU\n" + + "ODDV4qIxJS7x7EU47fgGWANzYrAQMY9Av2TgXD7FTx/aEkP/TOYGJqibGapE\n" + + "PHayXOw=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Entrust.net_Secure_Server_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UE\n" + + "BhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50\n" + + "cnVzdC5uZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl\n" + + "MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UE\n" + + "AxMxRW50cnVzdC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1\n" + + "dGhvcml0eTAeFw05OTA1MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQsw\n" + + "CQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3\n" + + "dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlh\n" + + "Yi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVkMTow\n" + + "OAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp\n" + + "b24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0\n" + + "VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/I0dNxScZgSYMVHIN\n" + + "iC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3wkrYKZImZNHk\n" + + "mGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OCAdcwggHT\n" + + "MBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHboIHY\n" + + "pIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5\n" + + "BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChs\n" + + "aW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBM\n" + + "aW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENl\n" + + "cnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNo\n" + + "dHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAi\n" + + "gA8xOTk5MDUyNTE2MDk0MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMC\n" + + "AQYwHwYDVR0jBBgwFoAU8BdiE1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYE\n" + + "FPAXYhNVPbP/CgBr+1CEl/PtYtAaMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9\n" + + "B0EABAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEFBQADgYEAkNwwAvpkdMKn\n" + + "CqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN95K+8cPV1ZVqBLssziY2Zcgx\n" + + "xufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd2cNgQ4xYDiKWL2KjLB+6\n" + + "rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Equifax_Secure_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQG\n" + + "EwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1\n" + + "cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4\n" + + "MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgx\n" + + "LTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0\n" + + "eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2R\n" + + "FGiYCh7+2gRvE4RiIcPRfM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO\n" + + "/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuv\n" + + "K9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAGA1UdHwRp\n" + + "MGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEt\n" + + "MCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5\n" + + "MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjAL\n" + + "BgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gjIBBPM5iQn9Qw\n" + + "HQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMBAf8w\n" + + "GgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GB\n" + + "AFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y\n" + + "7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2u\n" + + "FHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Equifax_Secure_Global_eBusiness_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJV\n" + + "UzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1\n" + + "aWZheCBTZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0\n" + + "MDAwMFoXDTIwMDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoT\n" + + "E0VxdWlmYXggU2VjdXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJl\n" + + "IEdsb2JhbCBlQnVzaW5lc3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw\n" + + "gYkCgYEAuucXkAJlsTRVPEnCUdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQy\n" + + "td4zjTov2/KaelpzmKNc6fuKcxtc58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORR\n" + + "OhI8bIpaVIRw28HFkM9yRcuoWcDNM50/o5brhTMhHD4ePmBudpxnhcXIw2EC\n" + + "AwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAHMA8GA1UdEwEB/wQFMAMBAf8w\n" + + "HwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0OBBYEFL6o\n" + + "oHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUAA4GBADDiAVGqx+pf\n" + + "2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkAZ70Br83gcfxa\n" + + "z2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv8qIYNMR1\n" + + "pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Equifax_Secure_eBusiness_CA_1.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJV\n" + + "UzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1\n" + + "aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcN\n" + + "MjAwNjIxMDQwMDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZh\n" + + "eCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2lu\n" + + "ZXNzIENBLTEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fe\n" + + "k6lfWg0XTzQaDJj0ItlZ1MRoRvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5\n" + + "/VGcqiTZ9J2DKocKIdMSODRsjQBuWqDZQu4aIZX5UkxVWsUPOE9G+m34LjXW\n" + + "HXzr4vCwdYDIqROsvojvOm6rXyo4YgKwEnv+j6YDAgMBAAGjZjBkMBEGCWCG\n" + + "SAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEp4\n" + + "MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRKeDJSEdtZFjZe38EUNkBq\n" + + "R3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZMzfmpTMANmvPMZWnm\n" + + "JXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+WB5Hh1Q+WKG1\n" + + "tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN/Bf+KpYr\n" + + "tWKmpj29f5JZzVoqgrI3eQ==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Equifax_Secure_eBusiness_CA_2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQG\n" + + "EwJVUzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlm\n" + + "YXggU2VjdXJlIGVCdXNpbmVzcyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5\n" + + "MDYyMzEyMTQ0NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkVxdWlmYXgg\n" + + "U2VjdXJlMSYwJAYDVQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0Et\n" + + "MjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF\n" + + "7Y6yEb3+6+e0dMKP/wXn2Z0GvxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKD\n" + + "pkWNYmi7hRsgcDKqQM2mll/EcTc/BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HM\n" + + "HMg3OrmXUqesxWoklE6ce8/AatbfIb0CAwEAAaOCAQkwggEFMHAGA1UdHwRp\n" + + "MGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORXF1aWZheCBT\n" + + "ZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNpbmVzcyBDQS0y\n" + + "MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkwNjIzMTIxNDQ1WjAL\n" + + "BgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBqy/3YIHqngnYw\n" + + "HQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQFMAMBAf8w\n" + + "GgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GB\n" + + "AAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy\n" + + "0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkt\n" + + "y3D1E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // GTE_CyberTrust_Global_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgw\n" + + "FgYDVQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRy\n" + + "dXN0IFNvbHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3Qg\n" + + "R2xvYmFsIFJvb3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1\n" + + "MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYD\n" + + "VQQLEx5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMT\n" + + "GkdURSBDeWJlclRydXN0IEdsb2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUA\n" + + "A4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4usJTQGz0O9pTAipTHBsiQl8i4\n" + + "ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcqlHHK6XALn\n" + + "ZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8F\n" + + "LztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3rGwnpXtlR22ciYaQqPEh3\n" + + "46B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l93PR2VX2bY1QY6fDq\n" + + "81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0PlZPvy5TYnh+d\n" + + "XIVtx6quTx8itc2VrbqnzPmrC3p/\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // GTE_CyberTrust_Root_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIB+jCCAWMCAgGjMA0GCSqGSIb3DQEBBAUAMEUxCzAJBgNVBAYTAlVTMRgw\n" + + "FgYDVQQKEw9HVEUgQ29ycG9yYXRpb24xHDAaBgNVBAMTE0dURSBDeWJlclRy\n" + + "dXN0IFJvb3QwHhcNOTYwMjIzMjMwMTAwWhcNMDYwMjIzMjM1OTAwWjBFMQsw\n" + + "CQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMRwwGgYDVQQD\n" + + "ExNHVEUgQ3liZXJUcnVzdCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB\n" + + "iQKBgQC45k+625h8cXyvRLfTD0bZZOWTwUKOx7pJjTUteueLveUFMVnGsS8K\n" + + "DPufpz+iCWaEVh43KRuH6X4MypqfpX/1FZSj1aJGgthoTNE3FQZor734sLPw\n" + + "KfWVWgkWYXcKIiXUT0Wqx73llt/51KiOQswkwB6RJ0q1bQaAYznEol44AwID\n" + + "AQABMA0GCSqGSIb3DQEBBAUAA4GBABKzdcZfHeFhVYAA1IFLezEPI2PnPfMD\n" + + "+fQ2qLvZ46WXTeorKeDWanOB5sCJo9Px4KWlIjeaY8JIILTbcuPI9tl8vrGv\n" + + "U9oUtCG41tWW4/5ODFlitppK+ULdjG+BqXH/9ApybW1EDp3zdHSo1TRJ6V6e\n" + + "6bR64eVaH4QwnNOfpSXY\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // GeoTrust_Global_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYT\n" + + "AlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVz\n" + + "dCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBC\n" + + "MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UE\n" + + "AxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n" + + "MIIBCgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEH\n" + + "CIjaWC9mOSm9BXiLnTjoBbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlC\n" + + "GDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7\n" + + "csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAj\n" + + "Nvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdRe\n" + + "JivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQAB\n" + + "o1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9\n" + + "qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1luMrMTjANBgkq\n" + + "hkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Qzxpe\n" + + "R+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWV\n" + + "Yrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF\n" + + "PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot\n" + + "2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeX\n" + + "xx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm\n" + + "Mw==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // GlobalSign_Root_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDdTCCAl2gAwIBAgILAgAAAAAA1ni3lAUwDQYJKoZIhvcNAQEEBQAwVzEL\n" + + "MAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNV\n" + + "BAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05\n" + + "ODA5MDExMjAwMDBaFw0xNDAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkw\n" + + "FwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRsw\n" + + "GQYDVQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUA\n" + + "A4IBDwAwggEKAoIBAQDaDuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR\n" + + "4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc\n" + + "71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4\n" + + "bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgK\n" + + "OOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMW\n" + + "ea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DP\n" + + "AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIABjAdBgNVHQ4EFgQUYHtmGkUNl8qJ\n" + + "UC99BM00qP/8/UswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOC\n" + + "AQEArqqf/LfSyx9fOSkoGJ40yWxPbxrwZKJwSk8ThptgKJ7ogUmYfQq75bCd\n" + + "PTbbjwVR/wkxKh/diXeeDy5slQTthsu0AD+EAk2AaioteAuubyuig0SDH81Q\n" + + "gkwkr733pbTIWg/050deSY43lv6aiAU62cDbKYfmGZZHpzqmjIs8d/5GY6dT\n" + + "2iHRrH5Jokvmw2dZL7OKDrssvamqQnw1wdh/1acxOk5jQzmvCLBhNIzTmKlD\n" + + "NPYPhyk7ncJWWJh3w/cbrPad+D6qp1RF8PX51TFl/mtYnHGzHtdS6jIX/EBg\n" + + "Hcl5JLL2bP2oZg6C3ZjL2sJETy6ge/L3ayx2EYRGinij4w==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // RSA_Root_Certificate_1.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlD\n" + + "ZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu\n" + + "Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRp\n" + + "b24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNv\n" + + "bS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYy\n" + + "NjAwMjIzM1oXDTE5MDYyNjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0\n" + + "IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4x\n" + + "NTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24g\n" + + "QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x\n" + + "IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3\n" + + "DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFlLWLU2f\n" + + "NUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChM\n" + + "MFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqYJJgpp0lZpd34\n" + + "t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliEZwgs3x/b\n" + + "e0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJn0Wu\n" + + "PIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A\n" + + "PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // RSA_Security_1024_v3.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICXDCCAcWgAwIBAgIQCgEBAQAAAnwAAAALAAAAAjANBgkqhkiG9w0BAQUF\n" + + "ADA6MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0Eg\n" + + "U2VjdXJpdHkgMTAyNCBWMzAeFw0wMTAyMjIyMTAxNDlaFw0yNjAyMjIyMDAx\n" + + "NDlaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJT\n" + + "QSBTZWN1cml0eSAxMDI0IFYzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB\n" + + "gQDV3f5mCc8kPD6ugU5OisRpgFtZO9+5TUzKtS3DJy08rwBCbbwoppbPf9dY\n" + + "rIMKo1W1exeQFYRMiu4mmdxY78c4pqqv0I5CyGLXq6yp+0p9v+r+Ek3d/yYt\n" + + "bzZUaMjShFbuklNhCbM/OZuoyZu9zp9+1BlqFikYvtc6adwlWzMaUQIDAQAB\n" + + "o2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSME\n" + + "GDAWgBTEwBykB5T9zU0B1FTapQxf3q4FWjAdBgNVHQ4EFgQUxMAcpAeU/c1N\n" + + "AdRU2qUMX96uBVowDQYJKoZIhvcNAQEFBQADgYEAPy1q4yZDlX2Jl2X7deRy\n" + + "HUZXxGFraZ8SmyzVWujAovBDleMf6XbN3Ou8k6BlCsdNT1+nr6JGFLkM88y9\n" + + "am63nd4lQtBU/55oc2PcJOsiv6hy8l4A4Q1OOkNumU4/iXgDmMrzVcydro7B\n" + + "qkWY+o8aoI2II/EVQQ2lRj6RP4vr93E=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // RSA_Security_2048_v3.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUF\n" + + "ADA6MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0Eg\n" + + "U2VjdXJpdHkgMjA0OCBWMzAeFw0wMTAyMjIyMDM5MjNaFw0yNjAyMjIyMDM5\n" + + "MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJT\n" + + "QSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n" + + "CgKCAQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37\n" + + "RqtBaB4Y6lXIL5F4iSj7Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E\n" + + "0S1PRsNO3Ng3OTsor8udGuorryGlwSMiuLgbWhOHV4PR8CDn6E8jQrAApX2J\n" + + "6elhc5SYcSa8LWrg903w8bYqODGBDSnhAMFRD0xS+ARaqn1y07iHKrtjEAMq\n" + + "s6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2PcYJk5qjEoAAVZkZR73QpXzD\n" + + "uvsf9/UP+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszACwIDAQABo2Mw\n" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAW\n" + + "gBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4EFgQUB8NRMKSq6UWuNST6\n" + + "/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmYv/3V\n" + + "EhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5g\n" + + "EydxiKRz44Rj0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+\n" + + "f00/FGj1EVDVwfSQpQgdMWD/YIwjVAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJq\n" + + "aHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395nzIlQnQFgCi/vcEk\n" + + "llgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kA\n" + + "pKnXwiJPZ9d37CAFYd4=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // TC_TrustCenter__Germany__Class_2_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDXDCCAsWgAwIBAgICA+owDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYT\n" + + "AkRFMRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYD\n" + + "VQQKEzFUQyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3\n" + + "b3JrcyBHbWJIMSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAyIENB\n" + + "MSkwJwYJKoZIhvcNAQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAe\n" + + "Fw05ODAzMDkxMTU5NTlaFw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJE\n" + + "RTEQMA4GA1UECBMHSGFtYnVyZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UE\n" + + "ChMxVEMgVHJ1c3RDZW50ZXIgZm9yIFNlY3VyaXR5IGluIERhdGEgTmV0d29y\n" + + "a3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTEp\n" + + "MCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVAdHJ1c3RjZW50ZXIuZGUwgZ8w\n" + + "DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANo46O0yAClxgwENv4wB3NrGrTmk\n" + + "qYov1YtcaF9QxmL1Zr3KkSLsqh1R1z2zUbKDTl3LSbDwTFXlay3HhQswHJJO\n" + + "gtTKAu33b77c4OMUuAVT8pr0VotanoWT0bSCVq5Nu6hLVxa8/vhYnvgpjbB7\n" + + "zXjJT6yLZwzxnPv8V5tXXE8NAgMBAAGjazBpMA8GA1UdEwEB/wQFMAMBAf8w\n" + + "DgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3LnRy\n" + + "dXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G\n" + + "CSqGSIb3DQEBBAUAA4GBAIRS+yjf/x91AbwBvgRWl2p0QiQxg/lGsQaKic+W\n" + + "LDO/jLVfenKhhQbOhvgFjuj5Jcrag4wGrOs2bYWRNAQ29ELw+HkuCkhcq8xR\n" + + "T3h2oNmsGb0q0WkEKJHKNhAngFdb0lz1wlurZIFjdFH0l7/NEij3TWZ/p/Ac\n" + + "ASZ4smZHcFFk\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // TC_TrustCenter__Germany__Class_3_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDXDCCAsWgAwIBAgICA+swDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYT\n" + + "AkRFMRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYD\n" + + "VQQKEzFUQyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3\n" + + "b3JrcyBHbWJIMSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAzIENB\n" + + "MSkwJwYJKoZIhvcNAQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAe\n" + + "Fw05ODAzMDkxMTU5NTlaFw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJE\n" + + "RTEQMA4GA1UECBMHSGFtYnVyZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UE\n" + + "ChMxVEMgVHJ1c3RDZW50ZXIgZm9yIFNlY3VyaXR5IGluIERhdGEgTmV0d29y\n" + + "a3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTEp\n" + + "MCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVAdHJ1c3RjZW50ZXIuZGUwgZ8w\n" + + "DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALa0wTUFLg2N7KBAahwOJ6ZQkmtQ\n" + + "GwfeLud2zODa/ISoXoxjaitN2U4CdhHBC/KNecoAtvGwDtf7pBc9r6tpepYn\n" + + "v68zoZoqWarEtTcI8hKlMbZD9TKWcSgoq40oht+77uMMfTDWw1Krj10nnGvA\n" + + "o+cFa1dJRLNu6mTP0o56UHd3AgMBAAGjazBpMA8GA1UdEwEB/wQFMAMBAf8w\n" + + "DgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3LnRy\n" + + "dXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G\n" + + "CSqGSIb3DQEBBAUAA4GBABY9xs3Bu4VxhUafPiCPUSiZ7C1FIWMjWwS7TJC4\n" + + "iJIETb19AaM/9uzO8d7+feXhPrvGq14L3T2WxMup1Pkm5gZOngylerpuw3yC\n" + + "GdHHsbHD2w2Om0B8NwvxXej9H5CIpQ5ON2QhqE6NtJ/x3kit1VYYUimLRzQS\n" + + "CdS7kjXvD9s0\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Thawte_Personal_Basic_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDITCCAoqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMC\n" + + "WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du\n" + + "MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm\n" + + "aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFBl\n" + + "cnNvbmFsIEJhc2ljIENBMSgwJgYJKoZIhvcNAQkBFhlwZXJzb25hbC1iYXNp\n" + + "Y0B0aGF3dGUuY29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVow\n" + + "gcsxCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNV\n" + + "BAcTCUNhcGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAm\n" + + "BgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24xITAfBgNV\n" + + "BAMTGFRoYXd0ZSBQZXJzb25hbCBCYXNpYyBDQTEoMCYGCSqGSIb3DQEJARYZ\n" + + "cGVyc29uYWwtYmFzaWNAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOB\n" + + "jQAwgYkCgYEAvLyTU23AUE+CFeZIlDWmWr5vQvoPR+53dXLdjUmbllegeNTK\n" + + "P1GzaQuRdhciB5dqxFGTS+CN7zeVoQxN2jSQHReJl+A1OFdKwPQIcOk8RHtQ\n" + + "fmGakOMj04gRRif1CwcOu93RfyAKiLlWCy4cgNrx454p7xS9CkT7G1sY0b8j\n" + + "kyECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOB\n" + + "gQAt4plrsD16iddZopQBHyvdEktTwq1/qqcAXJFAVyVKOKqEcLnZgA+le1z7\n" + + "c8a914phXAPjLSeoF+CEhULcXpvGt7Jtu3Sv5D/Lp7ew4F2+eIMllNLbgQ95\n" + + "B21P9DkVWlIBe94y1k049hJcBlDfBVu9FEuh3ym6O0GN92NWod8isQ==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Thawte_Personal_Freemail_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDLTCCApagAwIBAgIBADANBgkqhkiG9w0BAQQFADCB0TELMAkGA1UEBhMC\n" + + "WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du\n" + + "MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm\n" + + "aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEkMCIGA1UEAxMbVGhhd3RlIFBl\n" + + "cnNvbmFsIEZyZWVtYWlsIENBMSswKQYJKoZIhvcNAQkBFhxwZXJzb25hbC1m\n" + + "cmVlbWFpbEB0aGF3dGUuY29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIz\n" + + "NTk1OVowgdExCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUx\n" + + "EjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRp\n" + + "bmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24x\n" + + "JDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBGcmVlbWFpbCBDQTErMCkGCSqG\n" + + "SIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhhd3RlLmNvbTCBnzANBgkq\n" + + "hkiG9w0BAQEFAAOBjQAwgYkCgYEA1GnX1LCUZFtx6UfYDFG26nKRsIRefS0N\n" + + "j3sS34UldSh0OkIsYyeflXtL734Zhx2G6qPduc6WZBrCFG5ErHzmj+hND3Ef\n" + + "QDimAKOHePb5lIZererAXnbr2RSjXW56fAylS1V/Bhkpf56aJtVquzgkCGqY\n" + + "x7Hao5iR/Xnb5VrEHLkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq\n" + + "hkiG9w0BAQQFAAOBgQDH7JJ+Tvj1lqVnYiqk8E0RYNBvjWBYYawmu1I1XAjP\n" + + "MPuoSpaKH2JCI4wXD/S6ZJwXrEcp352YXtJsYHFcoqzceePnbgBHH7UNKOgC\n" + + "neSa/RP0ptl8sfjcXyMmCZGAc9AUG95DqYMl8uacLxXK/qarigd1iwzdUYRr\n" + + "5PjRzneigQ==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Thawte_Personal_Premium_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDKTCCApKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBzzELMAkGA1UEBhMC\n" + + "WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du\n" + + "MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm\n" + + "aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEjMCEGA1UEAxMaVGhhd3RlIFBl\n" + + "cnNvbmFsIFByZW1pdW0gQ0ExKjAoBgkqhkiG9w0BCQEWG3BlcnNvbmFsLXBy\n" + + "ZW1pdW1AdGhhd3RlLmNvbTAeFw05NjAxMDEwMDAwMDBaFw0yMDEyMzEyMzU5\n" + + "NTlaMIHPMQswCQYDVQQGEwJaQTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIw\n" + + "EAYDVQQHEwlDYXBlIFRvd24xGjAYBgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5n\n" + + "MSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMSMw\n" + + "IQYDVQQDExpUaGF3dGUgUGVyc29uYWwgUHJlbWl1bSBDQTEqMCgGCSqGSIb3\n" + + "DQEJARYbcGVyc29uYWwtcHJlbWl1bUB0aGF3dGUuY29tMIGfMA0GCSqGSIb3\n" + + "DQEBAQUAA4GNADCBiQKBgQDJZtn4B0TPuYwu8KHvE0VsBd/eJxZRNkERbGw7\n" + + "7f4QfRKe5ZtCmv5gMcNmt3M6SK5O0DI3lIi1DbbZ8/JE2dWIEt12TfIa/G8j\n" + + "Hnrx2JhFTgcQ7xZC0EN1bUre4qrJMf8fAHB8Zs8QJQi6+u4A6UYDZicRFTuq\n" + + "W/KY3TZCstqIdQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3\n" + + "DQEBBAUAA4GBAGk2ifc0KjNyL2071CKyuG+axTZmDhs8obF1Wub9NdP4qPIH\n" + + "b4Vnjt4rueIXsDqg8A6iAJrf8xQVbrvIhVqYgPn/vnQdPfP+MCXRNzRn+qVx\n" + + "eTBhKXLA4CxM+1bkOqhv5TJZUtt1KFBZDPgLGeSs2a+WjS9Q2wfD6h+rM+D1\n" + + "KzGJ\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Thawte_Premium_Server_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMC\n" + + "WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du\n" + + "MR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2Vy\n" + + "dGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3Rl\n" + + "IFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNl\n" + + "cnZlckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1\n" + + "OVowgc4xCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQ\n" + + "BgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMUVGhhd3RlIENvbnN1bHRpbmcg\n" + + "Y2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24x\n" + + "ITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3\n" + + "DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0B\n" + + "AQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhI\n" + + "NTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQug2SBhRz1JPL\n" + + "lyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/qgeN\n" + + "9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B\n" + + "AQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI\n" + + "hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZ\n" + + "a4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcU\n" + + "Qg==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Thawte_Server_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMC\n" + + "WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du\n" + + "MR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2Vy\n" + + "dGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3Rl\n" + + "IFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0\n" + + "ZS5jb20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkG\n" + + "A1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2Fw\n" + + "ZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UE\n" + + "CxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQ\n" + + "VGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRz\n" + + "QHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I\n" + + "/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC\n" + + "6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCXL+eQbcAoQpnX\n" + + "TEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzARMA8G\n" + + "A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWD\n" + + "TSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e\n" + + "QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdni\n" + + "TCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Thawte_Time_Stamping_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICoTCCAgqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBizELMAkGA1UEBhMC\n" + + "WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmls\n" + + "bGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmlj\n" + + "YXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwHhcNOTcw\n" + + "MTAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBizELMAkGA1UEBhMCWkExFTAT\n" + + "BgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzAN\n" + + "BgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24x\n" + + "HzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwgZ8wDQYJKoZIhvcN\n" + + "AQEBBQADgY0AMIGJAoGBANYrWHhhRYZT6jR7UZztsOYuGA7+4F+oJ9O0yeB8\n" + + "WU4WDnNUYMF/9p8u6TqFJBU820cEY8OexJQaWt9MevPZQx08EHp5JduQ/vBR\n" + + "5zDWQQD9nyjfeb6Uu522FOMjhdepQeBMpHmwKxqL8vg7ij5FrHGSALSQQZj7\n" + + "X+36ty6K+Ig3AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN\n" + + "AQEEBQADgYEAZ9viwuaHPUCDhjc1fR/OmsMMZiCouqoEiYbC9RAIDb/LogWK\n" + + "0E02PvTX72nGXuSwlG9KuefeW4i2e9vjJ+V2w/A1wcu1J5szedyQpgCed/r8\n" + + "zSeUQhac0xxo7L9c3eWpexAKMnRUEzGLhQOEkbdYATAUOK8oyvyxUBkZCayJ\n" + + "SdM=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // UTN-USER_First-Network_Applications.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUF\n" + + "ADCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0\n" + + "IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEw\n" + + "HwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVU\n" + + "Ti1VU0VSRmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0\n" + + "ODM5WhcNMTkwNzA5MTg1NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgT\n" + + "AlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVT\n" + + "RVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVz\n" + + "dC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3QtTmV0d29yayBBcHBsaWNh\n" + + "dGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCz+5Gh5DZV\n" + + "hawGNFugmliy+LUPBXeDrjKxdpJo7CNKyXY/45y2N3kDuatpjQclthln5LAb\n" + + "GHNhSuh+zdMvZOOmfAz6F4CjDUeJT1FxL+78P/m4FoCHiZMlIJpDgmkkdihZ\n" + + "NaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXuOzr0hAReYFmnjDRy7rh4\n" + + "xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1axwiP8vv\n" + + "/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6gyN7i\n" + + "gEL66S/ozjIEj3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQD\n" + + "AgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPqGydvguul49Uuo1hXf\n" + + "8NPhahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9jcmwudXNlcnRydXN0\n" + + "LmNvbS9VVE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0G\n" + + "CSqGSIb3DQEBBQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXh\n" + + "i6r/fWRRzwr/vH3YIWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUq\n" + + "f9FuVSTiuwL7MT++6LzsQCv4AdRWOOTKRIK1YSAhZ2X28AvnNPilwpyjXEAf\n" + + "hZOVBt5P1CeptqX8Fs1zMT+4ZSfP1FMa8Kxun08FDAOBp4QpxFq9ZFdyrTvP\n" + + "NximmMatBrTcCKME1SmklpoSZ0qMYEWd8SOasACcaLWYUNPvji6SZbFIPiG+\n" + + "FTAqDbUMo2s/rn9X9R+WfN9v3YIwLGUbQErNaLly7HF27FSOH4UMAWr6pjis\n" + + "H8SE\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // ValiCert_Class_1_VA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlD\n" + + "ZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu\n" + + "Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRp\n" + + "b24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNv\n" + + "bS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYy\n" + + "NTIyMjM0OFoXDTE5MDYyNTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0\n" + + "IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4x\n" + + "NTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24g\n" + + "QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x\n" + + "IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3\n" + + "DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu9OqNSLwxlBfw\n" + + "8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m\n" + + "+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8YTfwggtFzVXSN\n" + + "dnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0LBwGlN+V\n" + + "YH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLWI8so\n" + + "gTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPw\n" + + "nXS3qT6gpf+2SQMT2iLM7XGCK5nPOrf1LXLI\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // ValiCert_Class_2_VA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlD\n" + + "ZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu\n" + + "Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRp\n" + + "b24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNv\n" + + "bS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYy\n" + + "NjAwMTk1NFoXDTE5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0\n" + + "IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4x\n" + + "NTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24g\n" + + "QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x\n" + + "IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3\n" + + "DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZUcOBVXc\n" + + "65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQ\n" + + "b7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QSv4dk+NoS/zcn\n" + + "wbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9vUJSZSWI4\n" + + "OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTuIYEZ\n" + + "oDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC\n" + + "W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // ValiCert_OCSP_Responder.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDSDCCArGgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBsjEkMCIGA1UEBxMb\n" + + "VmFsaUNlcnQgVmFsaWRhdGlvbiBOZXR3b3JrMRcwFQYDVQQKEw5WYWxpQ2Vy\n" + + "dCwgSW5jLjEsMCoGA1UECxMjQ2xhc3MgMSBWYWxpZGF0aW9uIEF1dGhvcml0\n" + + "eSAtIE9DU1AxITAfBgNVBAMTGGh0dHA6Ly93d3cudmFsaWNlcnQubmV0LzEg\n" + + "MB4GCSqGSIb3DQEJARYRaW5mb0B2YWxpY2VydC5jb20wHhcNMDAwMjEyMTE1\n" + + "MDA1WhcNMDUwMjEwMTE1MDA1WjCBsjEkMCIGA1UEBxMbVmFsaUNlcnQgVmFs\n" + + "aWRhdGlvbiBOZXR3b3JrMRcwFQYDVQQKEw5WYWxpQ2VydCwgSW5jLjEsMCoG\n" + + "A1UECxMjQ2xhc3MgMSBWYWxpZGF0aW9uIEF1dGhvcml0eSAtIE9DU1AxITAf\n" + + "BgNVBAMTGGh0dHA6Ly93d3cudmFsaWNlcnQubmV0LzEgMB4GCSqGSIb3DQEJ\n" + + "ARYRaW5mb0B2YWxpY2VydC5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ\n" + + "AoGBAMeML6fDQIc7PdfEmlgUZArDCDliGs/S66nxaXSKyg5adsyiUk7Q88R6\n" + + "tfimHLujp6RTh1uNwAC71WYk53TGFsivyANi1TKHolKRRJSVqEdDbaVInPZM\n" + + "ddVPYufJ/3v0JIynvCh2tTKgJXO3Ry94+Eb5hxTwd/wKd+hP/Ywf+mLZAgMB\n" + + "AAGjbDBqMA8GCSsGAQUFBzABBQQCBQAwEwYDVR0lBAwwCgYIKwYBBQUHAwkw\n" + + "CwYDVR0PBAQDAgGGMDUGCCsGAQUFBwEBBCkwJzAlBggrBgEFBQcwAYYZaHR0\n" + + "cDovL29jc3AyLnZhbGljZXJ0Lm5ldDANBgkqhkiG9w0BAQUFAAOBgQAVxeC4\n" + + "NHISBiCoYpWT0byTupCr3E6Njo2YTOMy9Ss/s5f7qqKtQJetaL1crVMO0Kaz\n" + + "DawamY2qMB7PDnD/ArB3ZYPN2gdcUs1Zu6LI4rQWg4/UlXmTLei/RJMxkjDT\n" + + "NDTxEPshrC70w11kY3qZ4ZqrQh1IZqZ3N7hVPK3+ZbBi6Q==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_1_Public_Primary_Certification_Authority.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8x\n" + + "CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UE\n" + + "CxMuQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv\n" + + "cml0eTAeFw05NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNV\n" + + "BAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh\n" + + "c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCB\n" + + "nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Rm/baNWYS2ZSHH2Z965jeu3\n" + + "noaACpEO+jglr0aIguVzqKCbJF0NH8xlbgyw0FaEGIeaBpsQoXPftFg5a27B\n" + + "9hXVqKg/qhIGjTGsf7A01480Z4gJzRQR4k5FVmkfeAKA2txHkSm7NsljXMXg\n" + + "1y2He6G3MrB7MLoqLzGq7qNn2tsCAwEAATANBgkqhkiG9w0BAQIFAAOBgQBM\n" + + "P7iLxmjf7kMzDl3ppssHhE16M/+SG/Q2rdiVIjZoEWx8QszznC7EBz8UsA9P\n" + + "/5CSdvnivErpj82ggAr3xSnxgiJduLHdgSOjeyUVRjB5FvjqBUuUfx3CHMjj\n" + + "t/QQQDwTw18fU+hI5Ia0e6E1sHslurjTjqs/OJ0ANACY89FxlA==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_1_Public_Primary_Certification_Authority_-_G2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcEx\n" + + "CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UE\n" + + "CxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv\n" + + "cml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAt\n" + + "IEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBU\n" + + "cnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVow\n" + + "gcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoG\n" + + "A1UECxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1\n" + + "dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5j\n" + + "LiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2ln\n" + + "biBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCq\n" + + "0Lq+Fi24g9TK0g+8djHKlNgdk4xWArzZbxpvUjZudVYKVdPfQ4chEWWKfo+9\n" + + "Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIqWpDBucSmFc/IReumXY6c\n" + + "PvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQIDAQABMA0G\n" + + "CSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0Jh9Zr\n" + + "bWB85a7FkCMMXErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2ul\n" + + "uIncrKTdcu1OofdPvAbT6shkdHvClUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4i\n" + + "P/68DzFc6PLZ\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_1_Public_Primary_Certification_Authority_-_G3.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHK\n" + + "MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNV\n" + + "BAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5\n" + + "IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBD\n" + + "BgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlm\n" + + "aWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3\n" + + "MTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24s\n" + + "IEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNV\n" + + "BAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQg\n" + + "dXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFBy\n" + + "aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI\n" + + "hvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4nN493GwTFtl63SRR\n" + + "ZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO8ESlV8dAWB6j\n" + + "Rx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjVojYJrKsh\n" + + "JlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjbPG7P\n" + + "oBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP2\n" + + "6KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHh\n" + + "v2Vrn5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQ\n" + + "BfGfMY1aqtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/N\n" + + "y9Sn2WCVhDr4wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUf\n" + + "xJM8/XmPBNQ+T+r3ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFM\n" + + "DSZl4kSAHsef493oCtrspSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5\n" + + "SCJ5ShkPshw+IHTZasO+8ih4E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXV\n" + + "OBRgmaNL3gaWcSzy27YfpO8/7g==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_1_Public_Primary_OCSP_Responder.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDnjCCAwegAwIBAgIQK2jUo0aexTsoCas4XX8nIDANBgkqhkiG9w0BAQUF\n" + + "ADBfMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1\n" + + "BgNVBAsTLkNsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB\n" + + "dXRob3JpdHkwHhcNMDAwODA0MDAwMDAwWhcNMDQwODAzMjM1OTU5WjCBpzEX\n" + + "MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy\n" + + "dXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczov\n" + + "L3d3dy52ZXJpc2lnbi5jb20vUlBBIChjKTAwMS4wLAYDVQQDEyVDbGFzcyAx\n" + + "IFB1YmxpYyBQcmltYXJ5IE9DU1AgUmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEB\n" + + "AQUAA4GNADCBiQKBgQC57V56Ondfzl86UvzNZPdxtW9qlsZZklWUXS9bLsER\n" + + "6iaKy6eBPPZaRN56Ey/9WlHZezcmSsAnPwQDalbBgyzhb1upVFAkSsYuekyh\n" + + "WzdUJCExH6F4GHansXDaItBq/gdiQMb39pt9DAa4S8co5GYjhFHvRreT2IEz\n" + + "y+U2rMboBQIDAQABo4IBEDCCAQwwIAYDVR0RBBkwF6QVMBMxETAPBgNVBAMT\n" + + "CE9DU1AgMS0xMDEGA1UdHwQqMCgwJqAkoCKGIGh0dHA6Ly9jcmwudmVyaXNp\n" + + "Z24uY29tL3BjYTEuY3JsMBMGA1UdJQQMMAoGCCsGAQUFBwMJMEIGCCsGAQUF\n" + + "BwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJpc2lnbi5j\n" + + "b20vb2NzcC9zdGF0dXMwRAYDVR0gBD0wOzA5BgtghkgBhvhFAQcBATAqMCgG\n" + + "CCsGAQUFBwIBFhxodHRwczovL3d3dy52ZXJpc2lnbi5jb20vUlBBMAkGA1Ud\n" + + "EwQCMAAwCwYDVR0PBAQDAgeAMA0GCSqGSIb3DQEBBQUAA4GBAHCQ3bjkvlMX\n" + + "fH8C6dX3i5mTMWCNfuZgayTvYKzSzpHegG0JpNO4OOVEynJeDS3Bd5y9LAN4\n" + + "KY2kpXeH9fErJq3MB2w6VFoo4AnzTQoEytRYaQuns/XdAaXn3PAfusFdkI2z\n" + + "6k/BEVmXarIrE7HarZehs7GgIFvKMquNzxPwHynD\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_2_Public_Primary_Certification_Authority.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICPDCCAaUCEC0b/EoXjaOR6+f/9YtFvgswDQYJKoZIhvcNAQECBQAwXzEL\n" + + "MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQL\n" + + "Ey5DbGFzcyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y\n" + + "aXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UE\n" + + "BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz\n" + + "cyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGf\n" + + "MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2WoujDWojg4BrzzmH9CETMwZM\n" + + "JaLtVRKXxaeAufqDwSCg+i8VDXyhYGt+eSz6Bg86rvYbb7HS/y8oUl+DfUvE\n" + + "erf4Zh+AVPy3wo5ZShRXRtGak75BkQO7FYCTXOvnzAhsPz6zSvz/S2wj1VCC\n" + + "JkQZjiPDceoZJEcEnnW/yKYAHwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBAIob\n" + + "K/o5wXTXXtgZZKJYSi034DNHD6zt96rbHuSLBlxgJ8pFUs4W7z8GZOeUaHxg\n" + + "MxURaa+dYo2jA1Rrpr7l7gUYYAS/QoD90KioHgE796Ncr6Pc5iaAIzy4RHT3\n" + + "Cq5Ji2F4zCS/iIqnDupzGUH9TQPwiNHleI2lKk/2lw0Xd8rY\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_2_Public_Primary_Certification_Authority_-_G2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHB\n" + + "MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNV\n" + + "BAsTM0NsYXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRo\n" + + "b3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIEluYy4g\n" + + "LSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24g\n" + + "VHJ1c3QgTmV0d29yazAeFw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTla\n" + + "MIHBMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6\n" + + "BgNVBAsTM0NsYXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB\n" + + "dXRob3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIElu\n" + + "Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNp\n" + + "Z24gVHJ1c3QgTmV0d29yazCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA\n" + + "p4gBIXQs5xoD8JjhlzwPIQjxnNuX6Zr8wgQGE75fUsjMHiwSViy4AWkszJkf\n" + + "rbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRCwiNPStjwDqL7MWzJ5m+Z\n" + + "Jwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cCAwEAATAN\n" + + "BgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9jinb3/\n" + + "7aHmZuovCfTK1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAX\n" + + "rXfMSTWqz9iP0b63GJZHc2pUIjRkLbYWm1lbtFFZOrMLFPQS32eg9K0yZF6x\n" + + "RnInjBJ7xUS0rg==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_2_Public_Primary_Certification_Authority_-_G3.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcox\n" + + "CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UE\n" + + "CxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkg\n" + + "VmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMG\n" + + "A1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZp\n" + + "Y2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcx\n" + + "NjIzNTk1OVowgcoxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwg\n" + + "SW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UE\n" + + "CxMxKGMpIDE5OTkgVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1\n" + + "c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJp\n" + + "bWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMIIBIjANBgkqhkiG\n" + + "9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwoNwtUs22e5LeWUJ92lvuCwTY+zYVY8\n" + + "1nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6tW8UvxDOJxOeBUebMXoT\n" + + "2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUYwZF7C9UT\n" + + "AJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9okoqQ\n" + + "HgiBVrKtaaNS0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjN\n" + + "qWm6o+sdDZykIKbBoMXRRkwXbdKsZj+WjOCE1Db/IlnF+RFgqF8EffIa9iVC\n" + + "YQ/ESrg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0JhU8wI1NQ0kdvekh\n" + + "ktdmnLfexbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf\n" + + "0xwLRtxyID+u7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydE\n" + + "p85EXdQbkJgNHkKUsQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377B\n" + + "MnMiIYtYgXsVkXq642RIsH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab\n" + + "5iXiQkWquJCtvgiPqQtCGJTPcjnhsUPgKM+351psE2tJs//jGHyJizNdrDPX\n" + + "p/naOlXJWBD5qu9ats9LS98q\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_2_Public_Primary_OCSP_Responder.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDnjCCAwegAwIBAgIQCUYX5h3Y1BygDKBi6HmKpzANBgkqhkiG9w0BAQUF\n" + + "ADBfMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1\n" + + "BgNVBAsTLkNsYXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB\n" + + "dXRob3JpdHkwHhcNMDAwODAxMDAwMDAwWhcNMDQwNzMxMjM1OTU5WjCBpzEX\n" + + "MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy\n" + + "dXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczov\n" + + "L3d3dy52ZXJpc2lnbi5jb20vUlBBIChjKTAwMS4wLAYDVQQDEyVDbGFzcyAy\n" + + "IFB1YmxpYyBQcmltYXJ5IE9DU1AgUmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEB\n" + + "AQUAA4GNADCBiQKBgQDQymMxYX9ENHwFfQs9apDLeUt3Cj9LxyPlwGItfpx+\n" + + "PoiHkdCs6E1Jh6KWkIrdBKUCP4yb6Yn+YqDiWr3I3bR45qVCkwhnAcAgTddc\n" + + "9F3as+M3plIaLExlTYqH2aij8UlUuzxcgFFoxvtJ/wtVqxXd+5rBuR10DbKM\n" + + "RF2J/J/5gwIDAQABo4IBEDCCAQwwIAYDVR0RBBkwF6QVMBMxETAPBgNVBAMT\n" + + "CE9DU1AgMS0yMDEGA1UdHwQqMCgwJqAkoCKGIGh0dHA6Ly9jcmwudmVyaXNp\n" + + "Z24uY29tL3BjYTIuY3JsMBMGA1UdJQQMMAoGCCsGAQUFBwMJMEIGCCsGAQUF\n" + + "BwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJpc2lnbi5j\n" + + "b20vb2NzcC9zdGF0dXMwRAYDVR0gBD0wOzA5BgtghkgBhvhFAQcBATAqMCgG\n" + + "CCsGAQUFBwIBFhxodHRwczovL3d3dy52ZXJpc2lnbi5jb20vUlBBMAkGA1Ud\n" + + "EwQCMAAwCwYDVR0PBAQDAgeAMA0GCSqGSIb3DQEBBQUAA4GBAB99CW4kRnUE\n" + + "nPMmm+M5bhfvvL2iG9IChIar0ECXLMRDiDcZayKoA3FQnSDcNmAgmnMtc1Vs\n" + + "WJsswrQ0LHozQsqR2elDr88e4PXEeqs/cmMeqTfhWzuIsxOGgpBXy1f/9Fa+\n" + + "It3jl6jhvCJDwt1N2/aBnpIUnjkPE1TegtjAXjSN\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_3_Public_Primary_Certification_Authority.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzEL\n" + + "MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQL\n" + + "Ey5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y\n" + + "aXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UE\n" + + "BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz\n" + + "cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGf\n" + + "MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69q\n" + + "RUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94f56TuZoAqiN91qyFomNFx3In\n" + + "zPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Olhec9vn2a\n" + + "/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBALtM\n" + + "EivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Dolbwdj2wsqFHMc9ikwFPw\n" + + "TtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNycAA9WjQKZ7aKQRUzk\n" + + "uxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_3_Public_Primary_Certification_Authority_-_G2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcEx\n" + + "CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UE\n" + + "CxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv\n" + + "cml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAt\n" + + "IEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBU\n" + + "cnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVow\n" + + "gcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoG\n" + + "A1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1\n" + + "dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5j\n" + + "LiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2ln\n" + + "biBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDM\n" + + "XtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4pO0M8RcPO/mn+SXX\n" + + "wc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg013gfqLptQ5GV\n" + + "j0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwIDAQABMA0G\n" + + "CSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSkU01U\n" + + "bSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i\n" + + "F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo\n" + + "1KpYoJ2daZH9\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_3_Public_Primary_Certification_Authority_-_G3.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHK\n" + + "MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNV\n" + + "BAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5\n" + + "IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBD\n" + + "BgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlm\n" + + "aWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3\n" + + "MTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24s\n" + + "IEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNV\n" + + "BAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQg\n" + + "dXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFBy\n" + + "aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI\n" + + "hvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2\n" + + "R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2tKmFZpGcmTNDo\n" + + "vFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUccLwg\n" + + "TS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+V\n" + + "k7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ\n" + + "Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJ\n" + + "OxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my\n" + + "/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f\n" + + "j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoA\n" + + "Wii/gt/4uhMdUIaC/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8S\n" + + "GhJouPtmmRQURVyu565pF4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbb\n" + + "o27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh\n" + + "/sVFuq1ruQp6Tk9LhO5L8X3dEQ==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_3_Public_Primary_OCSP_Responder.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDojCCAwugAwIBAgIQLpaev7ZibOx76XPM42zBhDANBgkqhkiG9w0BAQUF\n" + + "ADBfMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1\n" + + "BgNVBAsTLkNsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB\n" + + "dXRob3JpdHkwHhcNMDAwODA0MDAwMDAwWhcNMDQwODAzMjM1OTU5WjCBpzEX\n" + + "MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy\n" + + "dXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczov\n" + + "L3d3dy52ZXJpc2lnbi5jb20vUlBBIChjKTAwMS4wLAYDVQQDEyVDbGFzcyAz\n" + + "IFB1YmxpYyBQcmltYXJ5IE9DU1AgUmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEB\n" + + "AQUAA4GNADCBiQKBgQDx5AgOg7t140jluNum8Lmr6Txix141W9ACVBHYydFW\n" + + "uXZLuat65s269gwE1n7WsAplrE454/H3LaMlOe+wi8++2wxdbnD0B81w9zrA\n" + + "PjUW7XiMQ8/CJi5H1oZ9nPG+1mcMIiWkymXmH3p4KC8/BdsEIb/hRWb+PLeC\n" + + "7Vq4FhW5VQIDAQABo4IBFDCCARAwIAYDVR0RBBkwF6QVMBMxETAPBgNVBAMT\n" + + "CE9DU1AgMS0zMDUGA1UdHwQuMCwwKqAooCaGJGh0dHA6Ly9jcmwudmVyaXNp\n" + + "Z24uY29tL3BjYTMuMS4xLmNybDATBgNVHSUEDDAKBggrBgEFBQcDCTBCBggr\n" + + "BgEFBQcBAQQ2MDQwMgYIKwYBBQUHMAGmJhYkaHR0cDovL29jc3AudmVyaXNp\n" + + "Z24uY29tL29jc3Avc3RhdHVzMEQGA1UdIAQ9MDswOQYLYIZIAYb4RQEHAQEw\n" + + "KjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL1JQQTAJ\n" + + "BgNVHRMEAjAAMAsGA1UdDwQEAwIHgDANBgkqhkiG9w0BAQUFAAOBgQAC9lNj\n" + + "wKke8tCLMzCPSJtMsFa0g3FKvtxQ2PW24AvbvXhP6c8JNNopSZ0Bc1qRkYJU\n" + + "LBMK03cjzzf8Y96n4/a3tWlFKEnDkdyqRxypiJksBSqNjYr6YuJatwAgXTnE\n" + + "KMLL/J6oia5bPY4S6jKy/OsU1wkVGsDNG9W1FU5B1ZbjTg==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_4_Public_Primary_Certification_Authority_-_G2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDAjCCAmsCEDKIjprS9esTR/h/xCA3JfgwDQYJKoZIhvcNAQEFBQAwgcEx\n" + + "CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UE\n" + + "CxMzQ2xhc3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv\n" + + "cml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAt\n" + + "IEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBU\n" + + "cnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVow\n" + + "gcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoG\n" + + "A1UECxMzQ2xhc3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1\n" + + "dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5j\n" + + "LiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2ln\n" + + "biBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6\n" + + "8OTP+cSuhVS5B1f5j8V/aBH4xBewRNzjMHPVKmIquNDMHO0oW369atyzkSTK\n" + + "QWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDHqGKB3FtKqsGgtG7rL+VX\n" + + "xbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHwIDAQABMA0G\n" + + "CSqGSIb3DQEBBQUAA4GBAIWMEsGnuVAVess+rLhDityq3RS6iYF+ATwjcSGI\n" + + "L4LcY/oCRaxFWdcqWERbt5+BO5JoPeI3JPV7bI92NZYJqFmduc4jq3TWg/0y\n" + + "cyfYaT5DdPauxYma51N86Xv2S/PBZYPejYqcPIiNOVn8qj8ijaHBZlCBckzt\n" + + "ImRPT8qAkbYp\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_4_Public_Primary_Certification_Authority_-_G3.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHK\n" + + "MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNV\n" + + "BAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5\n" + + "IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBD\n" + + "BgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlm\n" + + "aWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3\n" + + "MTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24s\n" + + "IEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNV\n" + + "BAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQg\n" + + "dXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFBy\n" + + "aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI\n" + + "hvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1GQ9Wzsy1HyDkniYl\n" + + "S+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ+mGuqPKljYXC\n" + + "KtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0GbdU6LM8BDc\n" + + "VHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLmNxdL\n" + + "MEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY\n" + + "ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDD\n" + + "Zq3/ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1Wr\n" + + "IhVZPMq1CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXtt\n" + + "mhwwjIDLk5Mqg6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csK\n" + + "vE+MW8VLADsfKoKmfjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluP\n" + + "QSjA1egtTaRezarZ7c7c2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kP\n" + + "mF6Z6PDQpLv1U70qzlmwr25/bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr\n" + + "9Xgn2uf3ZkPznoM+IKrDNWCRzg==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_RSA_Secure_Server_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICNDCCAaECEAKtZn5ORf5eV288mBle3cAwDQYJKoZIhvcNAQECBQAwXzEL\n" + + "MAkGA1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMu\n" + + "MS4wLAYDVQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9y\n" + + "aXR5MB4XDTk0MTEwOTAwMDAwMFoXDTEwMDEwNzIzNTk1OVowXzELMAkGA1UE\n" + + "BhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYD\n" + + "VQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGb\n" + + "MA0GCSqGSIb3DQEBAQUAA4GJADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6O\n" + + "LDfO6zV4ZFQD5YRAUcm/jwjiioII0haGN1XpsSECrXZogZoFokvJSyVmIlZs\n" + + "iAeP94FZbYQHZXATcXY+m3dM41CJVphIuR2nKRoTLkoRWZweFdVJVCxzOmmC\n" + + "sZc5nG1wZ0jl3S3WyB57AgMBAAEwDQYJKoZIhvcNAQECBQADfgBl3X7hsuyw\n" + + "4jrg7HFGmhkRuNPHoLQDQCYCPgmc4RKz0Vr2N6W3YQO2WxZpO8ZECAyIUwxr\n" + + "l0nHPjXcbLm7qt9cuzovk2C2qUtN8iD3zV9/ZHuO3ABc1/p3yjkWWW8O6tO1\n" + + "g39NTUJWdrTJXwT4OPjr0l91X817/OWOgHz8UA==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Secure_Server_OCSP_Responder.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDnzCCAwygAwIBAgIRAP9F1SddJPuzwjkkU1fhT94wDQYJKoZIhvcNAQEF\n" + + "BQAwXzELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5\n" + + "LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24g\n" + + "QXV0aG9yaXR5MB4XDTAwMDgwNDAwMDAwMFoXDTA0MDgwMzIzNTk1OVowgZ4x\n" + + "FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU\n" + + "cnVzdCBOZXR3b3JrMTswOQYDVQQLEzJUZXJtcyBvZiB1c2UgYXQgaHR0cHM6\n" + + "Ly93d3cudmVyaXNpZ24uY29tL1JQQSAoYykwMDElMCMGA1UEAxMcU2VjdXJl\n" + + "IFNlcnZlciBPQ1NQIFJlc3BvbmRlcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAw\n" + + "gYkCgYEAuFGZZIUO7rMKaPC/Y3YdU/X8oXiMM+6f9L452psPTUepjyDoS0S9\n" + + "zs17kNEw6JDEJXuJKN699pMd/7n/krWpjeSuzOLDB4Nqo3IQASdiIqY1Jjkt\n" + + "ns9gDPxHpNfQQninHWzQy08VpykKtJVFxLHnWgnXOZXYHTWewr2zXcEMSx8C\n" + + "AwEAAaOCAR0wggEZMCAGA1UdEQQZMBekFTATMREwDwYDVQQDEwhPQ1NQIDEt\n" + + "NDA+BgNVHR8ENzA1MDOgMaAvhi1odHRwOi8vY3JsLnZlcmlzaWduLmNvbS9S\n" + + "U0FTZWN1cmVTZXJ2ZXItcC5jcmwwEwYDVR0lBAwwCgYIKwYBBQUHAwkwQgYI\n" + + "KwYBBQUHAQEENjA0MDIGCCsGAQUFBzABpiYWJGh0dHA6Ly9vY3NwLnZlcmlz\n" + + "aWduLmNvbS9vY3NwL3N0YXR1czBEBgNVHSAEPTA7MDkGC2CGSAGG+EUBBwEB\n" + + "MCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LnZlcmlzaWduLmNvbS9SUEEw\n" + + "CQYDVR0TBAIwADALBgNVHQ8EBAMCB4AwDQYJKoZIhvcNAQEFBQADfgAAsxBT\n" + + "ZpxJky4xoAJC0lhXfmah/huKYRhQQCweK0Gl1tv/rAgcWgVtAlwqtpZPR9u+\n" + + "TtvOzLqGuBjOsRKRX2P380g+zPFNE+RtCZR4AJLLoyCdBgtqoEMHztEZbI8Y\n" + + "dZqfFzP9qSa44+LewqjEWop/mNYHBmvMVp6GcM7U7w==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Time_Stamping_Authority_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDzTCCAzagAwIBAgIQU2GyYK7bcY6nlLMTM/QHCTANBgkqhkiG9w0BAQUF\n" + + "ADCBwTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTww\n" + + "OgYDVQQLEzNDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24g\n" + + "QXV0aG9yaXR5IC0gRzIxOjA4BgNVBAsTMShjKSAxOTk4IFZlcmlTaWduLCBJ\n" + + "bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAsTFlZlcmlT\n" + + "aWduIFRydXN0IE5ldHdvcmswHhcNMDAwOTI2MDAwMDAwWhcNMTAwOTI1MjM1\n" + + "OTU5WjCBpTEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl\n" + + "cmlTaWduIFRydXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBh\n" + + "dCBodHRwczovL3d3dy52ZXJpc2lnbi5jb20vcnBhIChjKTAwMSwwKgYDVQQD\n" + + "EyNWZXJpU2lnbiBUaW1lIFN0YW1waW5nIEF1dGhvcml0eSBDQTCBnzANBgkq\n" + + "hkiG9w0BAQEFAAOBjQAwgYkCgYEA0hmdZ8IAIVlizrQJIkRpivglWtvtDbc2\n" + + "fk7gu5Q+kCWHwmFHKdm9VLhjzCx9abQzNvQ3B5rB3UBU/OB4naCTuQk9I1F/\n" + + "RMIUdNsKvsvJMDRAmD7Q1yUQgZS9B0+c1lQn3y6ov8uQjI11S7zi6ESHzeZB\n" + + "CiVu6PQkAsVSD27smHUCAwEAAaOB3zCB3DAPBgNVHRMECDAGAQH/AgEAMEUG\n" + + "A1UdIAQ+MDwwOgYMYIZIAYb4RQEHFwEDMCowKAYIKwYBBQUHAgEWHGh0dHBz\n" + + "Oi8vd3d3LnZlcmlzaWduLmNvbS9ycGEwMQYDVR0fBCowKDAmoCSgIoYgaHR0\n" + + "cDovL2NybC52ZXJpc2lnbi5jb20vcGNhMy5jcmwwCwYDVR0PBAQDAgEGMEIG\n" + + "CCsGAQUFBwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJp\n" + + "c2lnbi5jb20vb2NzcC9zdGF0dXMwDQYJKoZIhvcNAQEFBQADgYEAgnBold+2\n" + + "DcIBcBlK0lRWHqzyRUyHuPU163hLBanInTsZIS5wNEqi9YngFXVF5yg3ADQn\n" + + "Keg3S/LvRJdrF1Eaw1adPBqK9kpGRjeM+sv1ZFo4aC4cw+9wzrhGBha/937n\n" + + "tag+RaypJXUie28/sJyU58dzq6wf7iWbwBbtt8pb8BQ=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Visa_International_Global_Root_2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDgDCCAmigAwIBAgICAx4wDQYJKoZIhvcNAQEFBQAwYTELMAkGA1UEBhMC\n" + + "VVMxDTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25h\n" + + "bCBTZXJ2aWNlIEFzc29jaWF0aW9uMRIwEAYDVQQDEwlHUCBSb290IDIwHhcN\n" + + "MDAwODE2MjI1MTAwWhcNMjAwODE1MjM1OTAwWjBhMQswCQYDVQQGEwJVUzEN\n" + + "MAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNl\n" + + "cnZpY2UgQXNzb2NpYXRpb24xEjAQBgNVBAMTCUdQIFJvb3QgMjCCASIwDQYJ\n" + + "KoZIhvcNAQEBBQADggEPADCCAQoCggEBAKkBcLWqxEDwq2omYXkZAPy/mzdZ\n" + + "DK9vZBv42pWUJGkzEXDK41Z0ohdXZFwgBuHW73G3O/erwWnQSaSxBNf0V2KJ\n" + + "XLB1LRckaeNCYOTudNargFbYiCjh+20i/SN8RnNPflRzHqgsVVh1t0zzWkWl\n" + + "Ahr62p3DRcMiXvOL8WAp0sdftAw6UYPvMPjU58fy+pmjIlC++QU3o63tmsPm\n" + + "7IgbthknGziLgE3sucfFicv8GjLtI/C1AVj59o/ghalMCXI5Etuz9c9OYmTa\n" + + "xhkVOmMd6RdVoUwiPDQyRvhlV7or7zaMavrZ2UT0qt2E1w0cslSsMoW0ZA3e\n" + + "QbuxNMYBhjJk1Z8CAwEAAaNCMEAwHQYDVR0OBBYEFJ59SzS/ca3CBfYDdYDO\n" + + "qU8axCRMMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqG\n" + + "SIb3DQEBBQUAA4IBAQAhpXYUVfmtJ3CPPPTVbMjMCqujmAuKBiPFyWHbmQdp\n" + + "NSYx/scuhMKZYdQN6X0uEyt8joW2hcdLzzW2LEc9zikv2G+fiRxkk78IvXbQ\n" + + "kIqUs38oW26sTTMs7WXcFsziza6kPWKSBpUmv9+55CCmc2rBvveURNZNbyoL\n" + + "axhNdBA2aGpawWqn3TYpjLgwi08hPwAuVDAHOrqK5MOeyti12HvOdUVmB/Rt\n" + + "Ldh6yumJivIj2C/LbgA2T/vwLwHMD8AiZfSr4k5hLQOCfZEWtTDVFN5ex5D8\n" + + "ofyrEK9ca3CnB+8phuiyJccg/ybdd+95RBTEvd07xQObdyPsoOy7Wjm1zK0G\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Visa_eCommerce_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUF\n" + + "ADBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlz\n" + + "YSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMT\n" + + "E1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0\n" + + "MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UE\n" + + "CxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAa\n" + + "BgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA\n" + + "A4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh\n" + + "28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8bRaVK7362\n" + + "rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81\n" + + "q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtF\n" + + "Wsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0\n" + + "lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaLdXe6YJ2E5/4t\n" + + "AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G\n" + + "A1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOC\n" + + "AQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR\n" + + "zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKht\n" + + "cbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGI\n" + + "xHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu\n" + + "YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/\n" + + "hC3euiInlhBx6yLt398znM/jra6O1I7mT1GvFpLgXPYHDw==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // beTRUSTed_Root_CA-Baltimore_Implementation.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIFajCCBFKgAwIBAgIEPLU9RjANBgkqhkiG9w0BAQUFADBmMRIwEAYDVQQK\n" + + "EwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEzMDEG\n" + + "A1UEAxMqYmVUUlVTVGVkIFJvb3QgQ0EtQmFsdGltb3JlIEltcGxlbWVudGF0\n" + + "aW9uMB4XDTAyMDQxMTA3Mzg1MVoXDTIyMDQxMTA3Mzg1MVowZjESMBAGA1UE\n" + + "ChMJYmVUUlVTVGVkMRswGQYDVQQLExJiZVRSVVNUZWQgUm9vdCBDQXMxMzAx\n" + + "BgNVBAMTKmJlVFJVU1RlZCBSb290IENBLUJhbHRpbW9yZSBJbXBsZW1lbnRh\n" + + "dGlvbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALx+xDmcjOPW\n" + + "HIb/ymKt4H8wRXqOGrO4x/nRNv8i805qX4QQ+2aBw5R5MdKR4XeOGCrDFN5R\n" + + "9U+jK7wYFuK13XneIviCfsuBH/0nLI/6l2Qijvj/YaOcGx6Sj8CoCd8JEey3\n" + + "fTGaGuqDIQY8n7pc/5TqarjDa1U0Tz0yH92BFODEPM2dMPgwqZfT7syj0B9f\n" + + "HBOB1BirlNFjw55/NZKeX0Tq7PQiXLfoPX2k+YmpkbIq2eszh+6l/ePazIjm\n" + + "iSZuxyuC0F6dWdsU7JGDBcNeDsYq0ATdcT0gTlgn/FP7eHgZFLL8kFKJOGJg\n" + + "B7Sg7KxrUNb9uShr71ItOrL/8QFArDcCAwEAAaOCAh4wggIaMA8GA1UdEwEB\n" + + "/wQFMAMBAf8wggG1BgNVHSAEggGsMIIBqDCCAaQGDysGAQQBsT4AAAEJKIOR\n" + + "MTCCAY8wggFIBggrBgEFBQcCAjCCAToaggE2UmVsaWFuY2Ugb24gb3IgdXNl\n" + + "IG9mIHRoaXMgQ2VydGlmaWNhdGUgY3JlYXRlcyBhbiBhY2tub3dsZWRnbWVu\n" + + "dCBhbmQgYWNjZXB0YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5k\n" + + "YXJkIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHVzZSwgdGhlIENlcnRpZmlj\n" + + "YXRpb24gUHJhY3RpY2UgU3RhdGVtZW50IGFuZCB0aGUgUmVseWluZyBQYXJ0\n" + + "eSBBZ3JlZW1lbnQsIHdoaWNoIGNhbiBiZSBmb3VuZCBhdCB0aGUgYmVUUlVT\n" + + "VGVkIHdlYiBzaXRlLCBodHRwOi8vd3d3LmJldHJ1c3RlZC5jb20vcHJvZHVj\n" + + "dHNfc2VydmljZXMvaW5kZXguaHRtbDBBBggrBgEFBQcCARY1aHR0cDovL3d3\n" + + "dy5iZXRydXN0ZWQuY29tL3Byb2R1Y3RzX3NlcnZpY2VzL2luZGV4Lmh0bWww\n" + + "HQYDVR0OBBYEFEU9w6nR3D8kVpgccxiIav+DR+22MB8GA1UdIwQYMBaAFEU9\n" + + "w6nR3D8kVpgccxiIav+DR+22MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0B\n" + + "AQUFAAOCAQEASZK8o+6svfoNyYt5hhwjdrCAWXf82n+0S9/DZEtqTg6t8n1Z\n" + + "dwWtColzsPq8y9yNAIiPpqCy6qxSJ7+hSHyXEHu67RMdmgduyzFiEuhjA6p9\n" + + "beP4G3YheBufS0OM00mG9htc9i5gFdPp43t1P9ACg9AYgkHNZTfqjjJ+vWuZ\n" + + "XTARyNtIVBw74acT02pIk/c9jH8F6M7ziCpjBLjqflh8AXtb4cV97yHgjQ5d\n" + + "UX2xZ/2jvTg2xvI4hocalmhgRvsoFEdV4aeADGvi6t9NfJBIoDa9CReJf8Py\n" + + "05yc493EG931t3GzUwWJBtDLSoDByFOQtTwxiBdQn8nEDovYqAJjDQ==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // beTRUSTed_Root_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIFLDCCBBSgAwIBAgIEOU99hzANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQG\n" + + "EwJXVzESMBAGA1UEChMJYmVUUlVTVGVkMRswGQYDVQQDExJiZVRSVVNUZWQg\n" + + "Um9vdCBDQXMxGjAYBgNVBAMTEWJlVFJVU1RlZCBSb290IENBMB4XDTAwMDYy\n" + + "MDE0MjEwNFoXDTEwMDYyMDEzMjEwNFowWjELMAkGA1UEBhMCV1cxEjAQBgNV\n" + + "BAoTCWJlVFJVU1RlZDEbMBkGA1UEAxMSYmVUUlVTVGVkIFJvb3QgQ0FzMRow\n" + + "GAYDVQQDExFiZVRSVVNUZWQgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD\n" + + "ggEPADCCAQoCggEBANS0c3oTCjhVAb6JVuGUntS+WutKNHUbYSnE4a0IYCF4\n" + + "SP+00PpeQY1hRIfo7clY+vyTmt9P6j41ffgzeubx181vSUs9Ty1uDoM6GHh3\n" + + "o8/n9E1z2Jo7Gh2+lVPPIJfCzz4kUmwMjmVZxXH/YgmPqsWPzGCgc0rXOD8V\n" + + "cr+il7dw6K/ifhYGTPWqZCZyByWtNfwYsSbX2P8ZDoMbjNx4RWc0PfSvHI3k\n" + + "bWvtILNnmrRhyxdviTX/507AMhLn7uzf/5cwdO2NR47rtMNE5qdMf1ZD6Li8\n" + + "tr76g5fmu/vEtpO+GRg+jIG5c4gW9JZDnGdzF5DYCW5jrEq2I8QBoa2k5MUC\n" + + "AwEAAaOCAfgwggH0MA8GA1UdEwEB/wQFMAMBAf8wggFZBgNVHSAEggFQMIIB\n" + + "TDCCAUgGCisGAQQBsT4BAAAwggE4MIIBAQYIKwYBBQUHAgIwgfQagfFSZWxp\n" + + "YW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVz\n" + + "IGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0\n" + + "ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGFuZCBjZXJ0aWZpY2F0aW9u\n" + + "IHByYWN0aWNlIHN0YXRlbWVudCwgd2hpY2ggY2FuIGJlIGZvdW5kIGF0IGJl\n" + + "VFJVU1RlZCdzIHdlYiBzaXRlLCBodHRwczovL3d3dy5iZVRSVVNUZWQuY29t\n" + + "L3ZhdWx0L3Rlcm1zMDEGCCsGAQUFBwIBFiVodHRwczovL3d3dy5iZVRSVVNU\n" + + "ZWQuY29tL3ZhdWx0L3Rlcm1zMDQGA1UdHwQtMCswKaAnoCWkIzAhMRIwEAYD\n" + + "VQQKEwliZVRSVVNUZWQxCzAJBgNVBAYTAldXMB0GA1UdDgQWBBQquZtpLjub\n" + + "2M3eKjEENGvKBxirZzAfBgNVHSMEGDAWgBQquZtpLjub2M3eKjEENGvKBxir\n" + + "ZzAOBgNVHQ8BAf8EBAMCAf4wDQYJKoZIhvcNAQEFBQADggEBAHlh26Nebhax\n" + + "6nZR+csVm8tpvuaBa58oH2U+3RGFktToQb9+M70j5/Egv6S0phkBxoyNNXxl\n" + + "pE8JpNbYIxUFE6dDea/bow6be3ga8wSGWsb2jCBHOElQBp1yZzrwmAOtlmdE\n" + + "/D8QDYZN5AA7KXvOOzuZhmElQITcE2K3+spZ1gMe1lMBzW1MaFVA4e5rxyoA\n" + + "AEiCswoBw2AqDPeCNe5IhpbkdNQ96gFxugR1QKepfzk5mlWXKWWuGVUlBXJH\n" + + "0+gY3Ljpr0NzARJ0o+FcXxVdJPP55PS2Z2cS52QiivalQaYctmBjRYoQtLpG\n" + + "EK5BV2VsPyMQPyEQWbfkQN0mDCP2qq4=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // beTRUSTed_Root_CA_-_Entrust_Implementation.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIGUTCCBTmgAwIBAgIEPLVPQDANBgkqhkiG9w0BAQUFADBmMRIwEAYDVQQK\n" + + "EwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEzMDEG\n" + + "A1UEAxMqYmVUUlVTVGVkIFJvb3QgQ0EgLSBFbnRydXN0IEltcGxlbWVudGF0\n" + + "aW9uMB4XDTAyMDQxMTA4MjQyN1oXDTIyMDQxMTA4NTQyN1owZjESMBAGA1UE\n" + + "ChMJYmVUUlVTVGVkMRswGQYDVQQLExJiZVRSVVNUZWQgUm9vdCBDQXMxMzAx\n" + + "BgNVBAMTKmJlVFJVU1RlZCBSb290IENBIC0gRW50cnVzdCBJbXBsZW1lbnRh\n" + + "dGlvbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALr0RAOqEmq1\n" + + "Q+xVkrYwfTVXDNvzDSduTPdQqJtOK2/b9a0cS12zqcH+e0TrW6MFDR/FNCsw\n" + + "ACnxeECypP869AGIF37m1CbTukzqMvtDd5eHI8XbQ6P1KqNRXuE70mVpflUV\n" + + "m3rnafdE4Fe1FehmYA8NA/uCjqPoEXtsvsdjDheT389Lrm5zdeDzqrmkwAkb\n" + + "hepxKYhBMvnwKg5sCfJ0a2ZsUhMfGLzUPvfYbiCeyv78IZTuEyhL11xeDGbu\n" + + "6bsPwTSxfwh28z0mcMmLJR1iJAzqHHVOwBLkuhMdMCktVjMFu5dZfsZJT4nX\n" + + "LySotohAtWSSU1Yk5KKghbNekLQSM80CAwEAAaOCAwUwggMBMIIBtwYDVR0g\n" + + "BIIBrjCCAaowggGmBg8rBgEEAbE+AAACCSiDkTEwggGRMIIBSQYIKwYBBQUH\n" + + "AgIwggE7GoIBN1JlbGlhbmNlIG9uIG9yIHVzZSBvZiB0aGlzIENlcnRpZmlj\n" + + "YXRlIGNyZWF0ZXMgYW4gYWNrbm93bGVkZ21lbnQgYW5kIGFjY2VwdGFuY2Ug\n" + + "b2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29u\n" + + "ZGl0aW9ucyBvZiB1c2UsIHRoZSBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0\n" + + "YXRlbWVudCBhbmQgdGhlIFJlbHlpbmcgUGFydHkgQWdyZWVtZW50LCB3aGlj\n" + + "aCBjYW4gYmUgZm91bmQgYXQgdGhlIGJlVFJVU1RlZCB3ZWIgc2l0ZSwgaHR0\n" + + "cHM6Ly93d3cuYmV0cnVzdGVkLmNvbS9wcm9kdWN0c19zZXJ2aWNlcy9pbmRl\n" + + "eC5odG1sMEIGCCsGAQUFBwIBFjZodHRwczovL3d3dy5iZXRydXN0ZWQuY29t\n" + + "L3Byb2R1Y3RzX3NlcnZpY2VzL2luZGV4Lmh0bWwwEQYJYIZIAYb4QgEBBAQD\n" + + "AgAHMIGJBgNVHR8EgYEwfzB9oHugeaR3MHUxEjAQBgNVBAoTCWJlVFJVU1Rl\n" + + "ZDEbMBkGA1UECxMSYmVUUlVTVGVkIFJvb3QgQ0FzMTMwMQYDVQQDEypiZVRS\n" + + "VVNUZWQgUm9vdCBDQSAtIEVudHJ1c3QgSW1wbGVtZW50YXRpb24xDTALBgNV\n" + + "BAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMjA0MTEwODI0MjdagQ8yMDIyMDQx\n" + + "MTA4NTQyN1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFH1w5a44iwY/qhwa\n" + + "j/nPJDCqhIQWMB0GA1UdDgQWBBR9cOWuOIsGP6ocGo/5zyQwqoSEFjAMBgNV\n" + + "HRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIEkDANBgkq\n" + + "hkiG9w0BAQUFAAOCAQEAKrgXzh8QlOu4mre5X+za95IkrNySO8cgjfKZ5V04\n" + + "ocI07cUTWVwFtStPYZuR+0H8/NU8TZh2BvWBfevdkObRVlTa4y0MnxEylCIB\n" + + "evZsLHRnBMylj44ss0O1lKLQfelifwa+JwGDnjr9iu6YQ0pr17WXOzq/T220\n" + + "Y/ozADQuLW2WyXvKmWO6vvT2MKAtmJbpVkQFqUSjYRDrgqFnXbxdJ3Wqiig2\n" + + "KjiS2d2kXgClzMx8KSreKJCrt+G2/30lC0DYqjSjLd4H61/OCt3Kfjp9JsFi\n" + + "aDrmLzfzgYYhxKlkqu9FNtEaZnz46TfW1mG+oq1I59/mdP7TbX3SJdysYlep\n" + + "9w==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // beTRUSTed_Root_CA_-_RSA_Implementation.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIFaDCCBFCgAwIBAgIQO1nHe81bV569N1KsdrSqGjANBgkqhkiG9w0BAQUF\n" + + "ADBiMRIwEAYDVQQKEwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBS\n" + + "b290IENBczEvMC0GA1UEAxMmYmVUUlVTVGVkIFJvb3QgQ0EgLSBSU0EgSW1w\n" + + "bGVtZW50YXRpb24wHhcNMDIwNDExMTExODEzWhcNMjIwNDEyMTEwNzI1WjBi\n" + + "MRIwEAYDVQQKEwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290\n" + + "IENBczEvMC0GA1UEAxMmYmVUUlVTVGVkIFJvb3QgQ0EgLSBSU0EgSW1wbGVt\n" + + "ZW50YXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkujQw\n" + + "CY5X0LkGLG9uJIAiv11DpvpPrILnHGhwhRujbrWqeNluB0s/6d/16uhUoWGK\n" + + "Di9pdRi3DOUUjXFumLhV/AyV0Jtu4S2I1DpAa5LxmZZk3tv/ePTulh1HiXzU\n" + + "vrmIdyM6CeYEnm2qXtLIvZpOGd+J6lsOfsPktPDgaTuID0GQ+NRxQyTBjyZL\n" + + "O1bp/4xsN+lFrYWMU8NghpBKlsmzVLC7F/AcRdnUGxlkVgoZ98zh/4avflhe\n" + + "rHqQH8koOUV7orbHnB/ahdQhhlkwk75TMzf270HPM8ercmsl9fNTGwxMLvF1\n" + + "S++gh/f+ihXQbNXL+WhTuXAVE8L1LvtDNXUtAgMBAAGjggIYMIICFDAMBgNV\n" + + "HRMEBTADAQH/MIIBtQYDVR0gBIIBrDCCAagwggGkBg8rBgEEAbE+AAADCSiD\n" + + "kTEwggGPMEEGCCsGAQUFBwIBFjVodHRwOi8vd3d3LmJldHJ1c3RlZC5jb20v\n" + + "cHJvZHVjdHNfc2VydmljZXMvaW5kZXguaHRtbDCCAUgGCCsGAQUFBwICMIIB\n" + + "OhqCATZSZWxpYW5jZSBvbiBvciB1c2Ugb2YgdGhpcyBDZXJ0aWZpY2F0ZSBj\n" + + "cmVhdGVzIGFuIGFja25vd2xlZGdtZW50IGFuZCBhY2NlcHRhbmNlIG9mIHRo\n" + + "ZSB0aGVuIGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5kIGNvbmRpdGlv\n" + + "bnMgb2YgdXNlLCB0aGUgQ2VydGlmaWNhdGlvbiBQcmFjdGljZSBTdGF0ZW1l\n" + + "bnQgYW5kIHRoZSBSZWx5aW5nIFBhcnR5IEFncmVlbWVudCwgd2hpY2ggY2Fu\n" + + "IGJlIGZvdW5kIGF0IHRoZSBiZVRSVVNUZWQgd2ViIHNpdGUsIGh0dHA6Ly93\n" + + "d3cuYmV0cnVzdGVkLmNvbS9wcm9kdWN0c19zZXJ2aWNlcy9pbmRleC5odG1s\n" + + "MAsGA1UdDwQEAwIBBjAfBgNVHSMEGDAWgBSp7BR++dlDzFMrFK3P9/BZiUHN\n" + + "GTAdBgNVHQ4EFgQUqewUfvnZQ8xTKxStz/fwWYlBzRkwDQYJKoZIhvcNAQEF\n" + + "BQADggEBANuXsHXqDMTBmMpWBcCorSZIry0g6IHHtt9DwSwddUvUQo3neqh0\n" + + "3GZCWYez9Wlt2ames30cMcH1VOJZJEnl7r05pmuKmET7m9cqg5c0Lcd9NUwt\n" + + "NLg+DcTsiCevnpL9UGGCqGAHFFPMZRPB9kdEadIxyKbdLrML3kqNWz2rDcI1\n" + + "UqJWN8wyiyiFQpyRQHpwKzg21eFzGh/l+n5f3NacOzDq28BbJ1zTcwfBwvNM\n" + + "m2+fG8oeqqg4MwlYsq78B+g23FW6L09A/nq9BqaBwZMifIYRCgZ3SK41ty8y\n" + + "mmFei74pnykkiFY5LKjSq5YDWtRIn7lAhAuYaPsBQ9Yb4gmxlxw=\n" + + "-----END CERTIFICATE-----\n"); + + CA_CERTS = new StaticTrustAnchors((X509Certificate[]) certs.toArray(new X509Certificate[0])); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Alert.java b/libjava/classpath/gnu/javax/net/ssl/provider/Alert.java new file mode 100644 index 00000000000..c31e1bef5ca --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Alert.java @@ -0,0 +1,474 @@ +/* Alert.java -- SSL Alert message. + Copyright (C) 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.net.ssl.provider; + +import java.io.EOFException; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * An alert message in the SSL protocol. Alerts are sent both as warnings + * which may allow execution to continue, or they may be fatal, which will + * halt this session. An alert object is composed of two enums -- the level, + * which indicates the seriousness of the alert, and the description, which + * indicates the reason for the alert. + * + * <pre> + * struct { + * AlertLevel level; + * AlertDescription description; + * } + * </pre> + */ +final class Alert implements Constructed +{ + + // Fields. + // ------------------------------------------------------------------------- + + /** The alert level enumerated. */ + private final Level level; + + /** The alert description enumerated. */ + private final Description description; + + // Constructor. + // ------------------------------------------------------------------------- + + Alert(Level level, Description description) + { + this.level = level; + this.description = description; + } + + // Class method. + // ------------------------------------------------------------------------- + + static Alert read(InputStream in) throws IOException + { + Level level = Level.read(in); + Description desc = Description.read(in); + return new Alert(level, desc); + } + + static Alert forName(String name) + { + if (name == null) + { + return new Alert(Level.FATAL, Description.INTERNAL_ERROR); + } + Description desc = Description.INTERNAL_ERROR; + if (name.equals("close_notify")) + { + desc = Description.CLOSE_NOTIFY; + } + else if (name.equals("unexpected_message")) + { + desc = Description.UNEXPECTED_MESSAGE; + } + else if (name.equals("bad_record_mac")) + { + desc = Description.BAD_RECORD_MAC; + } + else if (name.equals("DECRYPTION_FAILED")) + { + desc = Description.DECRYPTION_FAILED; + } + else if (name.equals("record_overflow")) + { + desc = Description.RECORD_OVERFLOW; + } + else if (name.equals("decompression_failure")) + { + desc = Description.DECOMPRESSION_FAILURE; + } + else if (name.equals("handshake_failure")) + { + desc = Description.HANDSHAKE_FAILURE; + } + else if (name.equals("no_certificate")) + { + desc = Description.NO_CERTIFICATE; + } + else if (name.equals("bad_certificate")) + { + desc = Description.BAD_CERTIFICATE; + } + else if (name.equals("unsupported_certificate")) + { + desc = Description.UNSUPPORTED_CERTIFICATE; + } + else if (name.equals("certificate_revoked")) + { + desc = Description.CERTIFICATE_REVOKED; + } + else if (name.equals("certificate_expired")) + { + desc = Description.CERTIFICATE_EXPIRED; + } + else if (name.equals("certificate_unknown")) + { + desc = Description.CERTIFICATE_UNKNOWN; + } + else if (name.equals("illegal_parameter")) + { + desc = Description.ILLEGAL_PARAMETER; + } + else if (name.equals("unknown_ca")) + { + desc = Description.UNKNOWN_CA; + } + else if (name.equals("access_denied")) + { + desc = Description.ACCESS_DENIED; + } + else if (name.equals("decode_error")) + { + desc = Description.DECODE_ERROR; + } + else if (name.equals("decrypt_error")) + { + desc = Description.DECRYPT_ERROR; + } + else if (name.equals("export_restriction")) + { + desc = Description.EXPORT_RESTRICTION; + } + else if (name.equals("protocol_version")) + { + desc = Description.PROTOCOL_VERSION; + } + else if (name.equals("insufficient_security")) + { + desc = Description.INSUFFICIENT_SECURITY; + } + else if (name.equals("internal_error")) + { + desc = Description.INTERNAL_ERROR; + } + else if (name.equals("user_canceled")) + { + desc = Description.USER_CANCELED; + } + else if (name.equals("no_renegotiation")) + { + desc = Description.NO_RENEGOTIATION; + } + else if (name.equals("unsupported_extension")) + { + desc = Description.UNSUPPORTED_EXTENSION; + } + else if (name.equals("certificate_unobtainable")) + { + desc = Description.CERTIFICATE_UNOBTAINABLE; + } + else if (name.equals("unrecognized_name")) + { + desc = Description.UNRECOGNIZED_NAME; + } + else if (name.equals("bad_certificate_status_response")) + { + desc = Description.BAD_CERTIFICATE_STATUS_RESPONSE; + } + else if (name.equals("bad_certificate_hash_value")) + { + desc = Description.BAD_CERTIFICATE_HASH_VALUE; + } + else if (name.equals("unknown_srp_username")) + { + desc = Description.UNKNOWN_SRP_USERNAME; + } + else if (name.equals("missing_srp_username")) + { + desc = Description.MISSING_SRP_USERNAME; + } + return new Alert(Level.FATAL, desc); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + out.write((byte) level.getValue()); + out.write((byte) description.getValue()); + } + + byte[] getEncoded() + { + return new byte[] { (byte) level.getValue(), + (byte) description.getValue() }; + } + + Level getLevel() + { + return level; + } + + Description getDescription() + { + return description; + } + + public String toString() + { + String nl = System.getProperty("line.separator"); + return "struct {" + nl + + " level = " + level + ";" + nl + + " description = " + description + ";" + nl + + "} Alert;" + nl; + } + + // Inner classes. + // ------------------------------------------------------------------------- + + /** + * The level enumeration. + * + * <pre> + * enum { warning(1), fatal(2), (255) } AlertLevel; + * </pre> + */ + static final class Level implements Enumerated + { + + // Constants and fields. + // ----------------------------------------------------------------------- + + static final Level WARNING = new Level(1), FATAL = new Level(2); + + private final int value; + + // Constructor. + // ----------------------------------------------------------------------- + + private Level(int value) + { + this.value = value; + } + + // Class method. + // ----------------------------------------------------------------------- + + static Level read(InputStream in) throws IOException + { + int i = in.read(); + if (i == -1) + { + throw new EOFException("unexpected end of stream"); + } + switch (i & 0xFF) + { + case 1: return WARNING; + case 2: return FATAL; + default: return new Level(i); + } + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public byte[] getEncoded() + { + return new byte[] { (byte) value }; + } + + public int getValue() + { + return value; + } + + public String toString() + { + switch (value) + { + case 1: return "warning"; + case 2: return "fatal"; + default: return "unknown(" + value + ")"; + } + } + } + + /** + * The description enumeration. + */ + static final class Description implements Enumerated + { + + // Constants and fields. + // ----------------------------------------------------------------------- + + static final Description + CLOSE_NOTIFY = new Description( 0), + UNEXPECTED_MESSAGE = new Description( 10), + BAD_RECORD_MAC = new Description( 20), + DECRYPTION_FAILED = new Description( 21), + RECORD_OVERFLOW = new Description( 22), + DECOMPRESSION_FAILURE = new Description( 30), + HANDSHAKE_FAILURE = new Description( 40), + NO_CERTIFICATE = new Description( 41), + BAD_CERTIFICATE = new Description( 42), + UNSUPPORTED_CERTIFICATE = new Description( 43), + CERTIFICATE_REVOKED = new Description( 44), + CERTIFICATE_EXPIRED = new Description( 45), + CERTIFICATE_UNKNOWN = new Description( 46), + ILLEGAL_PARAMETER = new Description( 47), + UNKNOWN_CA = new Description( 48), + ACCESS_DENIED = new Description( 49), + DECODE_ERROR = new Description( 50), + DECRYPT_ERROR = new Description( 51), + EXPORT_RESTRICTION = new Description( 60), + PROTOCOL_VERSION = new Description( 70), + INSUFFICIENT_SECURITY = new Description( 71), + INTERNAL_ERROR = new Description( 80), + USER_CANCELED = new Description( 90), + NO_RENEGOTIATION = new Description(100), + UNSUPPORTED_EXTENSION = new Description(110), + CERTIFICATE_UNOBTAINABLE = new Description(111), + UNRECOGNIZED_NAME = new Description(112), + BAD_CERTIFICATE_STATUS_RESPONSE = new Description(113), + BAD_CERTIFICATE_HASH_VALUE = new Description(114), + UNKNOWN_SRP_USERNAME = new Description(120), + MISSING_SRP_USERNAME = new Description(121); + + private final int value; + + // Constructor. + // ----------------------------------------------------------------------- + + private Description(int value) + { + this.value = value; + } + + // Class method. + // ----------------------------------------------------------------------- + + static Description read(InputStream in) throws IOException + { + int i = in.read(); + if (i == -1) + { + throw new EOFException("unexpected end of input stream"); + } + switch (i) + { + case 0: return CLOSE_NOTIFY; + case 10: return UNEXPECTED_MESSAGE; + case 20: return BAD_RECORD_MAC; + case 21: return DECRYPTION_FAILED; + case 22: return RECORD_OVERFLOW; + case 30: return DECOMPRESSION_FAILURE; + case 40: return HANDSHAKE_FAILURE; + case 41: return NO_CERTIFICATE; + case 42: return BAD_CERTIFICATE; + case 43: return UNSUPPORTED_CERTIFICATE; + case 44: return CERTIFICATE_REVOKED; + case 45: return CERTIFICATE_EXPIRED; + case 46: return CERTIFICATE_UNKNOWN; + case 47: return ILLEGAL_PARAMETER; + case 48: return UNKNOWN_CA; + case 49: return ACCESS_DENIED; + case 50: return DECODE_ERROR; + case 51: return DECRYPT_ERROR; + case 60: return EXPORT_RESTRICTION; + case 70: return PROTOCOL_VERSION; + case 71: return INSUFFICIENT_SECURITY; + case 80: return INTERNAL_ERROR; + case 90: return USER_CANCELED; + case 100: return NO_RENEGOTIATION; + case 120: return UNKNOWN_SRP_USERNAME; + case 121: return MISSING_SRP_USERNAME; + default: return new Description(i); + } + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public byte[] getEncoded() + { + return new byte[] { (byte) value }; + } + + public int getValue() + { + return value; + } + + public String toString() + { + switch (value) + { + case 0: return "close_notify"; + case 10: return "unexpected_message"; + case 20: return "bad_record_mac"; + case 21: return "decryption_failed"; + case 22: return "record_overflow"; + case 30: return "decompression_failure"; + case 40: return "handshake_failure"; + case 42: return "bad_certificate"; + case 43: return "unsupported_certificate"; + case 44: return "certificate_revoked"; + case 45: return "certificate_expired"; + case 46: return "certificate_unknown"; + case 47: return "illegal_parameter"; + case 48: return "unknown_ca"; + case 49: return "access_denied"; + case 50: return "decode_error"; + case 51: return "decrypt_error"; + case 60: return "export_restriction"; + case 70: return "protocol_version"; + case 71: return "insufficient_security"; + case 80: return "internal_error"; + case 90: return "user_canceled"; + case 100: return "no_renegotiation"; + case 110: return "unsupported_extension"; + case 111: return "certificate_unobtainable"; + case 112: return "unrecognized_name"; + case 113: return "bad_certificate_status_response"; + case 114: return "bad_certificate_hash_value"; + case 120: return "unknown_srp_username"; + case 121: return "missing_srp_username"; + default: return "unknown(" + value + ")"; + } + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/AlertException.java b/libjava/classpath/gnu/javax/net/ssl/provider/AlertException.java new file mode 100644 index 00000000000..666efe5ac0d --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/AlertException.java @@ -0,0 +1,76 @@ +/* AlertException.java -- exceptions generated by SSL alerts. + Copyright (C) 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.net.ssl.provider; + +import javax.net.ssl.SSLException; + +class AlertException extends SSLException +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final Alert alert; + private final boolean isLocal; + + // Constructor. + // ------------------------------------------------------------------------- + + AlertException(Alert alert, boolean isLocal) + { + super(alert.getDescription().toString()); + this.alert = alert; + this.isLocal = isLocal; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String getMessage() + { + return alert.getDescription() + ": " + + (isLocal ? "locally generated; " : "remotely generated; ") + + alert.getLevel(); + } + + public Alert getAlert () + { + return alert; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Certificate.java b/libjava/classpath/gnu/javax/net/ssl/provider/Certificate.java new file mode 100644 index 00000000000..b1d6b2a0143 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Certificate.java @@ -0,0 +1,194 @@ +/* Certificate.java -- SSL Certificate message. + Copyright (C) 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.net.ssl.provider; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.EOFException; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.StringWriter; + +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +import java.util.LinkedList; + +import javax.net.ssl.SSLProtocolException; + +final class Certificate implements Handshake.Body +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final X509Certificate[] certs; + + // Constructors. + // ------------------------------------------------------------------------- + + Certificate(X509Certificate[] certs) + { + if (certs == null) + { + throw new NullPointerException(); + } + this.certs = certs; + } + + // Class methods. + // ------------------------------------------------------------------------- + + static Certificate read(InputStream in, CertificateType type) + throws IOException + { + if (type == CertificateType.X509) + { + int len = (in.read() & 0xFF) << 16 | (in.read() & 0xFF) << 8 + | (in.read() & 0xFF); + byte[] buf = new byte[len]; + int count = 0; + while (count < len) + { + int l = in.read(buf, count, len - count); + if (l == -1) + { + throw new EOFException("unexpected end of stream"); + } + count += l; + } + try + { + LinkedList certs = new LinkedList(); + CertificateFactory fact = CertificateFactory.getInstance("X.509"); + ByteArrayInputStream bin = new ByteArrayInputStream(buf); + count = 0; + while (count < len) + { + int len2 = (bin.read() & 0xFF) << 16 | (bin.read() & 0xFF) << 8 + | (bin.read() & 0xFF); + certs.add(fact.generateCertificate(bin)); + count += len2 + 3; + } + return new Certificate((X509Certificate[]) + certs.toArray(new X509Certificate[certs.size()])); + } + catch (CertificateException ce) + { + SSLProtocolException sslpe = new SSLProtocolException(ce.getMessage()); + sslpe.initCause (ce); + throw sslpe; + } + } + else if (type == CertificateType.OPEN_PGP) + { + throw new UnsupportedOperationException("not yet implemented"); + } + else + throw new Error("unsupported certificate type "+type); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + try + { + for (int i = 0; i < certs.length; i++) + { + byte[] enc = certs[i].getEncoded(); + bout.write((enc.length >>> 16) & 0xFF); + bout.write((enc.length >>> 8) & 0xFF); + bout.write( enc.length & 0xFF); + bout.write(enc); + } + } + catch (CertificateEncodingException cee) + { + throw new Error("cannot encode certificates"); + } + catch (IOException ignored) + { + } + out.write(bout.size() >>> 16 & 0xFF); + out.write(bout.size() >>> 8 & 0xFF); + out.write(bout.size() & 0xFF); + bout.writeTo(out); + } + + X509Certificate[] getCertificates() + { + return certs; + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println("struct {"); + out.println(" certificateList ="); + for (int i = 0; i < certs.length; i++) + { + BufferedReader r = + new BufferedReader(new StringReader(certs[i].toString())); + String s; + try + { + while ((s = r.readLine()) != null) + { + out.print(" "); + out.println(s); + } + } + catch (IOException ignored) + { + } + } + out.println("} Certificate;"); + return str.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequest.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequest.java new file mode 100644 index 00000000000..0f788039b0b --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequest.java @@ -0,0 +1,285 @@ +/* CertificateRequest.java -- SSL CertificateRequest message. + Copyright (C) 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.net.ssl.provider; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.EOFException; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +import java.util.LinkedList; +import java.security.Principal; + +final class CertificateRequest implements Handshake.Body +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final ClientType[] types; + private final Principal[] authorities; + + // Constructor. + // ------------------------------------------------------------------------- + + CertificateRequest(ClientType[] types, Principal[] authorities) + { + if (types == null) + { + throw new NullPointerException(); + } + this.types = types; + if (authorities == null) + { + throw new NullPointerException(); + } + this.authorities = authorities; + } + + // Class methods. + // ------------------------------------------------------------------------- + + static CertificateRequest read(InputStream in) throws IOException + { + DataInputStream din = new DataInputStream(in); + ClientType[] types = new ClientType[din.readUnsignedByte()]; + for (int i = 0; i < types.length; i++) + { + types[i] = ClientType.read(din); + } + + LinkedList authorities = new LinkedList(); + byte[] buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + ByteArrayInputStream bin = new ByteArrayInputStream(buf); + try + { + String x500name = Util.getSecurityProperty("jessie.x500.class"); + if (x500name == null) + { + x500name = "org.metastatic.jessie.pki.X500Name"; + } + Class x500class = null; + ClassLoader cl = ClassLoader.getSystemClassLoader(); + if (cl != null) + { + x500class = cl.loadClass(x500name); + } + else + { + x500class = Class.forName(x500name); + } + Constructor c = x500class.getConstructor(new Class[] { new byte[0].getClass() }); + while (bin.available() > 0) + { + buf = new byte[(bin.read() & 0xFF) << 8 | (bin.read() & 0xFF)]; + bin.read(buf); + authorities.add(c.newInstance(new Object[] { buf })); + } + } + catch (IOException ioe) + { + throw ioe; + } + catch (Exception ex) + { + throw new Error(ex.toString()); + } + return new CertificateRequest(types, + (Principal[]) authorities.toArray(new Principal[authorities.size()])); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + out.write(types.length); + for (int i = 0; i < types.length; i++) + { + out.write(types[i].getValue()); + } + + try + { + Class x500class = authorities[0].getClass(); + Method m = x500class.getMethod("getEncoded", null); + for (int i = 0; i < authorities.length; i++) + { + byte[] buf = (byte[]) m.invoke(authorities[i], null); + bout.write(buf.length >>> 8 & 0xFF); + bout.write(buf.length & 0xFF); + bout.write(buf, 0, buf.length); + } + } + catch (Exception ex) + { + throw new Error(ex.toString()); + } + out.write(bout.size() >>> 8 & 0xFF); + out.write(bout.size() & 0xFF); + bout.writeTo(out); + } + + ClientType[] getTypes() + { + return types; + } + + String[] getTypeStrings() + { + try + { + return (String[]) Util.transform(types, String.class, "toString", null); + } + catch (Exception x) + { + return null; + } + } + + Principal[] getAuthorities() + { + return authorities; + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println("struct {"); + out.print(" types = "); + for (int i = 0; i < types.length; i++) + { + out.print(types[i]); + if (i != types.length - 1) + out.print(", "); + } + out.println(";"); + out.println(" authorities ="); + for (int i = 0; i < authorities.length; i++) + { + out.print(" "); + out.print(authorities[i].getName()); + if (i != types.length - 1) + out.println(","); + } + out.println(";"); + out.println("} CertificateRequest;"); + return str.toString(); + } + + // Inner class. + // ------------------------------------------------------------------------- + + static final class ClientType implements Enumerated + { + + // Constants and fields. + // ----------------------------------------------------------------------- + + static final ClientType + RSA_SIGN = new ClientType(1), DSS_SIGN = new ClientType(2), + RSA_FIXED_DH = new ClientType(3), DSS_FIXED_DH = new ClientType(4); + + private final int value; + + // Constructor. + // ----------------------------------------------------------------------- + + private ClientType(int value) + { + this.value = value; + } + + // Class method. + // ----------------------------------------------------------------------- + + static ClientType read(InputStream in) throws IOException + { + int i = in.read(); + if (i == -1) + { + throw new EOFException("unexpected end of input stream"); + } + switch (i & 0xFF) + { + case 1: return RSA_SIGN; + case 2: return DSS_SIGN; + case 3: return RSA_FIXED_DH; + case 4: return DSS_FIXED_DH; + default: return new ClientType(i); + } + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public byte[] getEncoded() + { + return new byte[] { (byte) value }; + } + + public int getValue() + { + return value; + } + + public String toString() + { + switch (value) + { + case 1: return "rsa_sign"; + case 2: return "dss_sign"; + case 3: return "rsa_fixed_dh"; + case 4: return "dss_fixed_dh"; + default: return "unknown(" + value + ")"; + } + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateType.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateType.java new file mode 100644 index 00000000000..c5705939f74 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateType.java @@ -0,0 +1,104 @@ +/* CertificateType.java -- the certificate type extension. + Copyright (C) 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.net.ssl.provider; + +import java.io.EOFException; +import java.io.InputStream; +import java.io.IOException; + +final class CertificateType implements Enumerated +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + static final CertificateType X509 = new CertificateType(0); + static final CertificateType OPEN_PGP = new CertificateType(1); + + private final int value; + + // Constructor. + // ------------------------------------------------------------------------- + + private CertificateType(int value) + { + this.value = value; + } + + // Class method. + // ------------------------------------------------------------------------- + + static CertificateType read(InputStream in) throws IOException + { + int value = in.read(); + if (value == -1) + { + throw new EOFException("unexpected end of input stream"); + } + switch (value & 0xFF) + { + case 0: return X509; + case 1: return OPEN_PGP; + default: return new CertificateType(value); + } + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public byte[] getEncoded() + { + return new byte[] { (byte) value }; + } + + public int getValue() + { + return value; + } + + public String toString() + { + switch (value) + { + case 0: return "X.509"; + case 1: return "OpenPGP"; + default: return "unknown(" + value + ")"; + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateVerify.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateVerify.java new file mode 100644 index 00000000000..e0bf130f189 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateVerify.java @@ -0,0 +1,95 @@ +/* CertificateVerify.java -- SSL CertificateVerify message. + Copyright (C) 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.net.ssl.provider; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.StringWriter; +import java.security.PublicKey; + +final class CertificateVerify extends Signature implements Handshake.Body +{ + + // Contstructor. + // ------------------------------------------------------------------------- + + CertificateVerify(Object sigValue, String sigAlg) + { + super(sigValue, sigAlg); + } + + // Class method. + // -------------------------------------------------------------------------- + + static Signature read(InputStream in, CipherSuite suite, PublicKey key) + throws IOException + { + Signature sig = Signature.read(in, suite, key); + return new CertificateVerify(sig.getSigValue(), sig.getSigAlg()); + } + + // Instance method. + // ------------------------------------------------------------------------- + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println("struct {"); + BufferedReader r = new BufferedReader(new StringReader(super.toString())); + String s; + try + { + while ((s = r.readLine()) != null) + { + out.print(" "); + out.println(s); + } + } + catch (IOException ignored) + { + } + out.println("} CertificateVerify;"); + return str.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CipherSuite.java b/libjava/classpath/gnu/javax/net/ssl/provider/CipherSuite.java new file mode 100644 index 00000000000..de916817b92 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/CipherSuite.java @@ -0,0 +1,754 @@ +/* CipherSuite.java -- Supported cipher suites. + Copyright (C) 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.net.ssl.provider; + +import java.io.DataInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; + +import java.lang.reflect.Field; + +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.Security; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import javax.crypto.Cipher; +import javax.crypto.Mac; +import javax.crypto.NoSuchPaddingException; + +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.mode.ModeFactory; + +final class CipherSuite implements Constructed +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + private static final List tlsSuiteNames = new LinkedList(); + private static final HashMap namesToSuites = new HashMap(); + + // SSL CipherSuites. + static final CipherSuite SSL_NULL_WITH_NULL_NULL = + new CipherSuite("null", "null", "null", "null", 0, 0x00, 0x00, + "SSL_NULL_WITH_NULL_NULL", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_NULL_MD5 = + new CipherSuite("null", "RSA", "RSA", "SSLMAC-MD5", 0, 0x00, 0x01, + "SSL_RSA_WITH_NULL_MD5", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_NULL_SHA = + new CipherSuite("null", "RSA", "RSA", "SSLMAC-SHA", 0, 0x00, 0x02, + "SSL_RSA_WITH_NULL_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_EXPORT_WITH_RC4_40_MD5 = + new CipherSuite("RC4", "RSA", "RSA", "SSLMAC-MD5", 5, 0x00, 0x03, + "SSL_RSA_EXPORT_WITH_RC4_40_MD5", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_RC4_128_MD5 = + new CipherSuite("RC4", "RSA", "RSA", "SSLMAC-MD5", 16, 0x00, 0x04, + "SSL_RSA_WITH_RC4_128_MD5", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_RC4_128_SHA = + new CipherSuite("RC4", "RSA", "RSA", "SSLMAC-SHA", 16, 0x00, 0x05, + "SSL_RSA_WITH_RC4_128_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite("DES", "RSA", "RSA", "SSLMAC-SHA", 5, 0x00, 0x08, + "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_DES_CBC_SHA = + new CipherSuite("DES", "RSA", "RSA", "SSLMAC-SHA", 8, 0x00, 0x09, + "SSL_RSA_WITH_DES_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "RSA", "RSA", "SSLMAC-SHA", 24, 0x00, 0x0A, + "SSL_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite("DES", "DH", "DSS", "SSLMAC-SHA", 5, 0x00, 0x0B, + "SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DH_DSS_WITH_DES_CBC_SHA = + new CipherSuite("DES", "DH", "DSS", "SSLMAC-SHA", 8, 0x00, 0x0C, + "SSL_DH_DSS_WITH_DES_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "DH", "DSS", "SSLMAC-SHA", 24, 0x00, 0x0D, + "SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite("DES", "DH", "RSA", "SSLMAC-SHA", 5, 0x00, 0x0E, + "SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DH_RSA_WITH_DES_CBC_SHA = + new CipherSuite("DES", "DH", "RSA", "SSLMAC-SHA", 8, 0x00, 0x0F, + "SSL_DH_RSA_WITH_DES_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "DH", "RSA", "SSLMAC-SHA", 24, 0x00, 0x10, + "SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite("DES", "DHE", "DSS", "SSLMAC-SHA", 5, 0x00, 0x11, + "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_DSS_WITH_DES_CBC_SHA = + new CipherSuite("DES", "DHE", "DSS", "SSLMAC-SHA", 8, 0x00, 0x12, + "SSL_DHE_DSS_WITH_DES_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "DHE", "DSS", "SSLMAC-SHA", 24, 0x00, 0x13, + "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite("DES", "DHE", "RSA", "SSLMAC-SHA", 5, 0x00, 0x14, + "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_RSA_WITH_DES_CBC_SHA = + new CipherSuite("DES", "DHE", "RSA", "SSLMAC-SHA", 8, 0x00, 0x15, + "SSL_DHE_RSA_WITH_DES_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "DHE", "RSA", "SSLMAC-SHA", 24, 0x00, 0x16, + "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.SSL_3); + + // AES CipherSuites. + static final CipherSuite SSL_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "RSA", "RSA", "SSLMAC-SHA", 16, 0x00, 0x2F, + "SSL_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DH_DSS_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "DH", "DSS", "SSLMAC-SHA", 16, 0x00, 0x30, + "SSL_DH_DSS_WITH_AES_128_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DH_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "DH", "RSA", "SSLMAC-SHA", 16, 0x00, 0x31, + "SSL_DH_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_DSS_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "DHE", "DSS", "SSLMAC-SHA", 16, 0x00, 0x32, + "SSL_DHE_DSS_WITH_AES_128_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "DHE", "RSA", "SSLMAC-SHA", 16, 0x00, 0x33, + "SSL_DHE_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "RSA", "RSA", "SSLMAC-SHA", 32, 0x00, 0x35, + "SSL_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DH_DSS_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "DH", "DSS", "SSLMAC-SHA", 32, 0x00, 0x36, + "SSL_DH_DSS_WITH_AES_256_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DH_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "DH", "RSA", "SSLMAC-SHA", 32, 0x00, 0x37, + "SSL_DH_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_DSS_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "DHE", "DSS", "SSLMAC-SHA", 32, 0x00, 0x38, + "SSL_DHE_DSS_WITH_AES_256_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "DHE", "RSA", "SSLMAC-SHA", 32, 0x00, 0x39, + "SSL_DHE_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.SSL_3); + + // Ciphersuites from the OpenPGP extension draft. + static final CipherSuite SSL_DHE_DSS_WITH_CAST_128_CBC_SHA = + new CipherSuite("CAST5", "DHE", "DSS", "HMAC-SHA", 16, 0x00, 0x70, + "SSL_DHE_DSS_WITH_CAST_128_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_DSS_WITH_CAST_128_CBC_RMD = + new CipherSuite("CAST5", "DHE", "DSS", "HMAC-RIPEMD-160", 16, 0x00, 0x71, + "SSL_DHE_DSS_WITH_CAST_128_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_DSS_WITH_3DES_EDE_CBC_RMD = + new CipherSuite("TripleDES", "DHE", "DSS", "HMAC-RIPEMD-160", 24, 0x00, 0x72, + "SSL_DHE_DSS_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_DSS_WITH_AES_128_CBC_RMD = + new CipherSuite("AES", "DHE", "DSS", "HMAC-RIPEMD-160", 16, 0x00, 0x73, + "SSL_DHE_DSS_WITH_AES_128_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_DSS_WITH_AES_256_CBC_RMD = + new CipherSuite("AES", "DHE", "DSS", "HMAC-RIPEMD-160", 32, 0x00, 0x74, + "SSL_DHE_DSS_WITH_AES_256_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_RSA_WITH_CAST_128_CBC_SHA = + new CipherSuite("CAST5", "DHE", "RSA", "HMAC-SHA", 16, 0x00, 0x75, + "SSL_DHE_RSA_WITH_CAST_128_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_RSA_WITH_CAST_128_CBC_RMD = + new CipherSuite("CAST5", "DHE", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x76, + "SSL_DHE_RSA_WITH_CAST_128_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_RSA_WITH_3DES_EDE_CBC_RMD = + new CipherSuite("TripleDES", "DHE", "RSA", "HMAC-RIPEMD-160", 24, 0x00, 0x77, + "SSL_DHE_RSA_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_RSA_WITH_AES_128_CBC_RMD = + new CipherSuite("AES", "DHE", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x78, + "SSL_DHE_RSA_WITH_AES_128_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_RSA_WITH_AES_256_CBC_RMD = + new CipherSuite("AES", "DHE", "RSA", "HMAC-RIPEMD-160", 32, 0x00, 0x79, + "SSL_DHE_RSA_WITH_AES_256_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_CAST_128_CBC_SHA = + new CipherSuite("CAST5", "RSA", "RSA", "HMAC-SHA", 16, 0x00, 0x7A, + "SSL_RSA_WITH_CAST_128_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_CAST_128_CBC_RMD = + new CipherSuite("CAST5", "RSA", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x7B, + "SSL_RSA_WITH_CAST_128_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_3DES_EDE_CBC_RMD = + new CipherSuite("TripleDES", "RSA", "RSA", "HMAC-RIPEMD-160", 24, 0x00, 0x7C, + "SSL_RSA_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_AES_128_CBC_RMD = + new CipherSuite("AES", "RSA", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x7D, + "SSL_RSA_WITH_AES_128_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_AES_256_CBC_RMD = + new CipherSuite("AES", "RSA", "RSA", "HMAC-RIPEMD-160", 32, 0x00, 0x7E, + "SSL_RSA_WITH_AES_256_CBC_RMD", ProtocolVersion.SSL_3); + + static final CipherSuite TLS_NULL_WITH_NULL_NULL = + new CipherSuite("null", "null", "null", "null", 0, 0x00, 0x00, + "TLS_NULL_WITH_NULL_NULL", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_NULL_MD5 = + new CipherSuite("null", "RSA", "RSA", "HMAC-MD5", 0, 0x00, 0x01, + "TLS_RSA_WITH_NULL_MD5", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_NULL_SHA = + new CipherSuite("null", "RSA", "RSA", "HMAC-SHA", 0, 0x00, 0x02, + "TLS_RSA_WITH_NULL_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_EXPORT_WITH_RC4_40_MD5 = + new CipherSuite("RC4", "RSA", "RSA", "HMAC-MD5", 5, 0x00, 0x03, + "TLS_RSA_EXPORT_WITH_RC4_40_MD5", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_RC4_128_MD5 = + new CipherSuite("RC4", "RSA", "RSA", "HMAC-MD5", 16, 0x00, 0x04, + "TLS_RSA_WITH_RC4_128_MD5", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_RC4_128_SHA = + new CipherSuite("RC4", "RSA", "RSA", "HMAC-SHA", 16, 0x00, 0x05, + "TLS_RSA_WITH_RC4_128_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite("DES", "RSA", "RSA", "HMAC-SHA", 5, 0x00, 0x08, + "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_DES_CBC_SHA = + new CipherSuite("DES", "RSA", "RSA", "HMAC-SHA", 8, 0x00, 0x09, + "TLS_RSA_WITH_DES_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "RSA", "RSA", "HMAC-SHA", 24, 0x00, 0x0A, + "TLS_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite("DES", "DH", "DSS", "HMAC-SHA", 5, 0x00, 0x0B, + "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DH_DSS_WITH_DES_CBC_SHA = + new CipherSuite("DES", "DH", "DSS", "HMAC-SHA", 8, 0x00, 0x0C, + "TLS_DH_DSS_WITH_DES_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "DH", "DSS", "HMAC-SHA", 24, 0x00, 0x0D, + "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite("DES", "DH", "RSA", "HMAC-SHA", 5, 0x00, 0x0E, + "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DH_RSA_WITH_DES_CBC_SHA = + new CipherSuite("DES", "DH", "RSA", "HMAC-SHA", 8, 0x00, 0x0F, + "TLS_DH_RSA_WITH_DES_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "DH", "RSA", "HMAC-SHA", 24, 0x00, 0x10, + "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite("DES", "DHE", "DSS", "HMAC-SHA", 5, 0x00, 0x11, + "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_DSS_WITH_DES_CBC_SHA = + new CipherSuite("DES", "DHE", "DSS", "HMAC-SHA", 8, 0x00, 0x12, + "TLS_DHE_DSS_WITH_DES_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "DHE", "DSS", "HMAC-SHA", 24, 0x00, 0x13, + "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite("DES", "DHE", "RSA", "HMAC-SHA", 5, 0x00, 0x14, + "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_RSA_WITH_DES_CBC_SHA = + new CipherSuite("DES", "DHE", "RSA", "HMAC-SHA", 8, 0x00, 0x15, + "TLS_DHE_RSA_WITH_DES_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "DHE", "RSA", "HMAC-SHA", 24, 0x00, 0x16, + "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1); + + // AES CipherSuites. + static final CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "RSA", "RSA", "HMAC-SHA", 16, 0x00, 0x2F, + "TLS_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DH_DSS_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "DH", "DSS", "HMAC-SHA", 16, 0x00, 0x30, + "TLS_DH_DSS_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DH_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "DH", "RSA", "HMAC-SHA", 16, 0x00, 0x31, + "TLS_DH_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "DHE", "DSS", "HMAC-SHA", 16, 0x00, 0x32, + "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "DHE", "RSA", "HMAC-SHA", 16, 0x00, 0x33, + "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "RSA", "RSA", "HMAC-SHA", 32, 0x00, 0x35, + "TLS_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DH_DSS_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "DH", "DSS", "HMAC-SHA", 32, 0x00, 0x36, + "TLS_DH_DSS_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DH_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "DH", "RSA", "HMAC-SHA", 32, 0x00, 0x37, + "TLS_DH_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "DHE", "DSS", "HMAC-SHA", 32, 0x00, 0x38, + "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "DHE", "RSA", "HMAC-SHA", 32, 0x00, 0x39, + "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1); + + // Secure remote password (SRP) ciphersuites + static final CipherSuite TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "SRP", "anon", "HMAC-SHA", 24, 0x00, 0x50, + "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "SRP", "RSA", "HMAC-SHA", 24, 0x00, 0x51, + "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "SRP", "DSS", "HMAC-SHA", 24, 0x00, 0x52, + "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_SRP_SHA_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "SRP", "anon", "HMAC-SHA", 16, 0x00, 0x53, + "TLS_SRP_SHA_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "SRP", "RSA", "HMAC-SHA", 16, 0x00, 0x54, + "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "SRP", "DSS", "HMAC-SHA", 16, 0x00, 0x55, + "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_SRP_SHA_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "SRP", "anon", "HMAC-SHA", 32, 0x00, 0x56, + "TLS_SRP_SHA_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "SRP", "RSA", "HMAC-SHA", 32, 0x00, 0x57, + "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "SRP", "DSS", "HMAC-SHA", 32, 0x00, 0x58, + "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1); + + // Ciphersuites from the OpenPGP extension draft. + static final CipherSuite TLS_DHE_DSS_WITH_CAST_128_CBC_SHA = + new CipherSuite("CAST5", "DHE", "DSS", "HMAC-SHA", 16, 0x00, 0x70, + "TLS_DHE_DSS_WITH_CAST_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_DSS_WITH_CAST_128_CBC_RMD = + new CipherSuite("CAST5", "DHE", "DSS", "HMAC-RIPEMD-160", 16, 0x00, 0x71, + "TLS_DHE_DSS_WITH_CAST_128_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD = + new CipherSuite("TripleDES", "DHE", "DSS", "HMAC-RIPEMD-160", 24, 0x00, 0x72, + "TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_RMD = + new CipherSuite("AES", "DHE", "DSS", "HMAC-RIPEMD-160", 16, 0x00, 0x73, + "TLS_DHE_DSS_WITH_AES_128_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_RMD = + new CipherSuite("AES", "DHE", "DSS", "HMAC-RIPEMD-160", 32, 0x00, 0x74, + "TLS_DHE_DSS_WITH_AES_256_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_RSA_WITH_CAST_128_CBC_SHA = + new CipherSuite("CAST5", "DHE", "RSA", "HMAC-SHA", 16, 0x00, 0x75, + "TLS_DHE_RSA_WITH_CAST_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_RSA_WITH_CAST_128_CBC_RMD = + new CipherSuite("CAST5", "DHE", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x76, + "TLS_DHE_RSA_WITH_CAST_128_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD = + new CipherSuite("TripleDES", "DHE", "RSA", "HMAC-RIPEMD-160", 24, 0x00, 0x77, + "TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_RMD = + new CipherSuite("AES", "DHE", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x78, + "TLS_DHE_RSA_WITH_AES_128_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_RMD = + new CipherSuite("AES", "DHE", "RSA", "HMAC-RIPEMD-160", 32, 0x00, 0x79, + "TLS_DHE_RSA_WITH_AES_256_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_CAST_128_CBC_SHA = + new CipherSuite("CAST5", "RSA", "RSA", "HMAC-SHA", 16, 0x00, 0x7A, + "TLS_RSA_WITH_CAST_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_CAST_128_CBC_RMD = + new CipherSuite("CAST5", "RSA", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x7B, + "TLS_RSA_WITH_CAST_128_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_RMD = + new CipherSuite("TripleDES", "RSA", "RSA", "HMAC-RIPEMD-160", 24, 0x00, 0x7C, + "TLS_RSA_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_AES_128_CBC_RMD = + new CipherSuite("AES", "RSA", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x7D, + "TLS_RSA_WITH_AES_128_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_AES_256_CBC_RMD = + new CipherSuite("AES", "RSA", "RSA", "HMAC-RIPEMD-160", 32, 0x00, 0x7E, + "TLS_RSA_WITH_AES_256_CBC_RMD", ProtocolVersion.TLS_1); + + private final String cipherName; + private final String kexName; + private final String sigName; + private final String macName; + private final boolean exportable; + private final boolean isStream; + private final int keyLength; + private final byte[] id; + private final String name; + private final ProtocolVersion version; + + // Constructors. + // ------------------------------------------------------------------------- + + private CipherSuite(String cipherName, String kexName, String sigName, + String macName, int keyLength, int id1, int id2, + String name, ProtocolVersion version) + { + this.cipherName = cipherName.intern(); + this.kexName = kexName.intern(); + this.sigName = sigName.intern(); + this.macName = macName.intern(); + this.exportable = keyLength <= 5; + this.isStream = cipherName.equals("null") || cipherName.equals("RC4"); + this.keyLength = keyLength; + this.id = new byte[] { (byte) id1, (byte) id2 }; + this.name = name.intern(); + this.version = version; + namesToSuites.put(name, this); + if (name.startsWith("TLS")) + { + tlsSuiteNames.add(name); + } + } + + private CipherSuite(byte[] id) + { + cipherName = null; + kexName = null; + sigName = null; + macName = null; + exportable = false; + isStream = false; + keyLength = 0; + this.id = id; + name = null; + version = null; + } + + // Class methods. + // ------------------------------------------------------------------------- + + /** + * Returns the cipher suite for the given name, or null if there is no + * such suite. + * + * @return The named cipher suite. + */ + static CipherSuite forName(String name) + { + return (CipherSuite) namesToSuites.get(name); + } + + static List availableSuiteNames() + { + return tlsSuiteNames; + } + + static CipherSuite read(InputStream in) throws IOException + { + DataInputStream din = new DataInputStream(in); + byte[] id = new byte[2]; + din.readFully(id); + return new CipherSuite(id); + } + + static IMode getCipher(String cbcCipherName) + { + IBlockCipher cipher = CipherFactory.getInstance(cbcCipherName); + if (cipher == null) + { + return null; + } + return ModeFactory.getInstance("CBC", cipher, cipher.defaultBlockSize()); + } + + static Cipher getJCECipher (final String name) + throws NoSuchAlgorithmException, NoSuchPaddingException + { + final String provider = Util.getSecurityProperty ("jessie.with.jce.provider"); + if (name.equals ("RC4")) + { + if (provider != null) + { + try + { + return Cipher.getInstance (name, provider); + } + catch (NoSuchProviderException nsae) + { + // Fall through. Try any available provider. + } + } + + return Cipher.getInstance (name); + } + else + { + // Oh, hey! Look! Something else Sun doesn't understand: SSLv3 padding + // is different than TLSv1 in subtle, but important, ways. But they + // sorta look the same, so why not make them equivalent? + // + // There should be a seperate padding "TLS1Padding". + if (provider != null) + { + try + { + return Cipher.getInstance (name + "/CBC/SSL3Padding", provider); + } + catch (NoSuchProviderException nspe) + { + // Fall through. Try any available provider. + } + } + return Cipher.getInstance (name + "/CBC/SSL3Padding"); + } + } + + static IMac getMac(String macName) + { + if (macName.startsWith("SSLMAC-")) + { + return new SSLHMac(macName.substring(7)); + } + else + { + return MacFactory.getInstance(macName); + } + } + + static Mac getJCEMac (final String name) + throws NoSuchAlgorithmException + { + final String provider = Util.getSecurityProperty ("jessie.with.jce.provider"); + if (provider != null) + { + try + { + return Mac.getInstance (name, provider); + } + catch (NoSuchProviderException nspe) + { + // Fall through. Try any available provider. + } + } + return Mac.getInstance (name); + } + + // Intance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + out.write(id); + } + + CipherSuite resolve(ProtocolVersion version) + { + if (version == ProtocolVersion.SSL_3) + { + if (id[0] == 0x00) switch (id[1]) + { + case 0x00: return SSL_NULL_WITH_NULL_NULL; + case 0x01: return SSL_RSA_WITH_NULL_MD5; + case 0x02: return SSL_RSA_WITH_NULL_SHA; + case 0x03: return SSL_RSA_EXPORT_WITH_RC4_40_MD5; + case 0x04: return SSL_RSA_WITH_RC4_128_MD5; + case 0x05: return SSL_RSA_WITH_RC4_128_SHA; + case 0x08: return SSL_RSA_EXPORT_WITH_DES40_CBC_SHA; + case 0x09: return SSL_RSA_WITH_DES_CBC_SHA; + case 0x0A: return SSL_RSA_WITH_3DES_EDE_CBC_SHA; + case 0x0B: return SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA; + case 0x0C: return SSL_DH_DSS_WITH_DES_CBC_SHA; + case 0x0D: return SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA; + case 0x0E: return SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA; + case 0x0F: return SSL_DH_RSA_WITH_DES_CBC_SHA; + case 0x10: return SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA; + case 0x11: return SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA; + case 0x12: return SSL_DHE_DSS_WITH_DES_CBC_SHA; + case 0x13: return SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA; + case 0x14: return SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA; + case 0x15: return SSL_DHE_RSA_WITH_DES_CBC_SHA; + case 0x16: return SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA; + case 0x2F: return SSL_RSA_WITH_AES_128_CBC_SHA; + case 0x30: return SSL_DH_DSS_WITH_AES_128_CBC_SHA; + case 0x31: return SSL_DH_RSA_WITH_AES_128_CBC_SHA; + case 0x32: return SSL_DHE_DSS_WITH_AES_128_CBC_SHA; + case 0x33: return SSL_DHE_RSA_WITH_AES_128_CBC_SHA; + case 0x35: return SSL_RSA_WITH_AES_256_CBC_SHA; + case 0x36: return SSL_DH_DSS_WITH_AES_256_CBC_SHA; + case 0x37: return SSL_DH_RSA_WITH_AES_256_CBC_SHA; + case 0x38: return SSL_DHE_DSS_WITH_AES_256_CBC_SHA; + case 0x39: return SSL_DHE_RSA_WITH_AES_256_CBC_SHA; + } + } + else if (version == ProtocolVersion.TLS_1 || + version == ProtocolVersion.TLS_1_1) + { + if (id[0] == 0x00) switch (id[1]) + { + case 0x00: return TLS_NULL_WITH_NULL_NULL; + case 0x01: return TLS_RSA_WITH_NULL_MD5; + case 0x02: return TLS_RSA_WITH_NULL_SHA; + case 0x03: return TLS_RSA_EXPORT_WITH_RC4_40_MD5; + case 0x04: return TLS_RSA_WITH_RC4_128_MD5; + case 0x05: return TLS_RSA_WITH_RC4_128_SHA; + case 0x08: return TLS_RSA_EXPORT_WITH_DES40_CBC_SHA; + case 0x09: return TLS_RSA_WITH_DES_CBC_SHA; + case 0x0A: return TLS_RSA_WITH_3DES_EDE_CBC_SHA; + case 0x0B: return TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA; + case 0x0C: return TLS_DH_DSS_WITH_DES_CBC_SHA; + case 0x0D: return TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA; + case 0x0E: return TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA; + case 0x0F: return TLS_DH_RSA_WITH_DES_CBC_SHA; + case 0x10: return TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA; + case 0x11: return TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA; + case 0x12: return TLS_DHE_DSS_WITH_DES_CBC_SHA; + case 0x13: return TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA; + case 0x14: return TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA; + case 0x15: return TLS_DHE_RSA_WITH_DES_CBC_SHA; + case 0x16: return TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA; + case 0x2F: return TLS_RSA_WITH_AES_128_CBC_SHA; + case 0x30: return TLS_DH_DSS_WITH_AES_128_CBC_SHA; + case 0x31: return TLS_DH_RSA_WITH_AES_128_CBC_SHA; + case 0x32: return TLS_DHE_DSS_WITH_AES_128_CBC_SHA; + case 0x33: return TLS_DHE_RSA_WITH_AES_128_CBC_SHA; + case 0x35: return TLS_RSA_WITH_AES_256_CBC_SHA; + case 0x36: return TLS_DH_DSS_WITH_AES_256_CBC_SHA; + case 0x37: return TLS_DH_RSA_WITH_AES_256_CBC_SHA; + case 0x38: return TLS_DHE_DSS_WITH_AES_256_CBC_SHA; + case 0x39: return TLS_DHE_RSA_WITH_AES_256_CBC_SHA; + case 0x50: return TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA; + case 0x51: return TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA; + case 0x52: return TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA; + case 0x53: return TLS_SRP_SHA_WITH_AES_128_CBC_SHA; + case 0x54: return TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA; + case 0x55: return TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA; + case 0x56: return TLS_SRP_SHA_WITH_AES_256_CBC_SHA; + case 0x57: return TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA; + case 0x58: return TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA; + case 0x70: return TLS_DHE_DSS_WITH_CAST_128_CBC_SHA; + case 0x71: return TLS_DHE_DSS_WITH_CAST_128_CBC_RMD; + case 0x72: return TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD; + case 0x73: return TLS_DHE_DSS_WITH_AES_128_CBC_RMD; + case 0x74: return TLS_DHE_DSS_WITH_AES_256_CBC_RMD; + case 0x75: return TLS_DHE_RSA_WITH_CAST_128_CBC_SHA; + case 0x76: return TLS_DHE_RSA_WITH_CAST_128_CBC_RMD; + case 0x77: return TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD; + case 0x78: return TLS_DHE_RSA_WITH_AES_128_CBC_RMD; + case 0x79: return TLS_DHE_RSA_WITH_AES_256_CBC_RMD; + case 0x7A: return TLS_RSA_WITH_CAST_128_CBC_SHA; + case 0x7B: return TLS_RSA_WITH_CAST_128_CBC_RMD; + case 0x7C: return TLS_RSA_WITH_3DES_EDE_CBC_RMD; + case 0x7D: return TLS_RSA_WITH_AES_128_CBC_RMD; + case 0x7E: return TLS_RSA_WITH_AES_256_CBC_RMD; + } + } + return this; + } + + String getCipher() + { + return cipherName; + } + + int getKeyLength() + { + return keyLength; + } + + String getKeyExchange() + { + return kexName; + } + + String getSignature() + { + return sigName; + } + + String getMac() + { + return macName; + } + + boolean isExportable() + { + return exportable; + } + + boolean isStreamCipher() + { + return isStream; + } + + String getAuthType() + { + if (kexName.equals("RSA")) + { + if (isExportable()) + { + return "RSA_EXPORT"; + } + return "RSA"; + } + return kexName + "_" + sigName; + } + + byte[] getId() + { + return id; + } + + ProtocolVersion getVersion() + { + return version; + } + + public boolean equals(Object o) + { + if (!(o instanceof CipherSuite)) + { + return false; + } + if (o == this) + return true; + byte[] id = ((CipherSuite) o).getId(); + return id[0] == this.id[0] && + id[1] == this.id[1]; + } + + public int hashCode() + { + if (version == null) + { + return 0xFFFF0000 | (id[0] & 0xFF) << 8 | (id[1] & 0xFF); + } + return version.getMajor() << 24 | version.getMinor() << 16 + | (id[0] & 0xFF) << 8 | (id[1] & 0xFF); + } + + public String toString() + { + if (name == null) + { + return "UNKNOWN { " + (id[0] & 0xFF) + ", " + (id[1] & 0xFF) + " }"; + } + return name; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientHello.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHello.java new file mode 100644 index 00000000000..259051df129 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHello.java @@ -0,0 +1,253 @@ +/* ClientHello.java -- SSL ClientHello message. + Copyright (C) 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.net.ssl.provider; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.StringWriter; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import javax.net.ssl.SSLProtocolException; + +final class ClientHello implements Handshake.Body +{ + + // Fields. + // ------------------------------------------------------------------------- + + private ProtocolVersion version; + private Random random; + private byte[] sessionId; + private List suites; + private List comp; + private List extensions; + + // Constructor. + // ------------------------------------------------------------------------- + + ClientHello(ProtocolVersion version, Random random, + byte[] sessionId, List suites, List comp) + { + this(version, random, sessionId, suites, comp, null); + } + + ClientHello(ProtocolVersion version, Random random, + byte[] sessionId, List suites, List comp, List extensions) + { + this.version = version; + this.random = random; + this.sessionId = sessionId; + this.suites = suites; + this.comp = comp; + this.extensions = extensions; + } + + // Class methods. + // ------------------------------------------------------------------------- + + static ClientHello read(InputStream in) throws IOException + { + ProtocolVersion vers = ProtocolVersion.read(in); + Random rand = Random.read(in); + byte[] id = new byte[in.read() & 0xFF]; + in.read(id); + int len = (in.read() & 0xFF) << 8 | (in.read() & 0xFF); + ArrayList suites = new ArrayList(len / 2); + for (int i = 0; i < len; i += 2) + { + suites.add(CipherSuite.read(in).resolve(vers)); + } + len = in.read() & 0xFF; + ArrayList comp = new ArrayList(len); + for (int i = 0; i < len; i++) + { + comp.add(CompressionMethod.read(in)); + } + + List ext = null; + // Since parsing MAY need to continue into the extensions fields, or it + // may end here, the specified input stream MUST be a ByteArrayInputStream + // over all the data this hello contains. Otherwise this will mess up + // the data stream. + if (in.available() > 0) // then we have extensions. + { + ext = new LinkedList(); + len = (in.read() & 0xFF) << 8 | (in.read() & 0xFF); + int count = 0; + while (count < len) + { + Extension e = Extension.read(in); + ext.add(e); + count += e.getValue().length + 4; + } + } + return new ClientHello(vers, rand, id, suites, comp, ext); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + version.write(out); + random.write(out); + out.write(sessionId.length); + out.write(sessionId); + out.write((suites.size() << 1) >>> 8 & 0xFF); + out.write((suites.size() << 1) & 0xFF); + for (Iterator i = suites.iterator(); i.hasNext(); ) + { + ((CipherSuite) i.next()).write(out); + } + out.write(comp.size()); + for (Iterator i = comp.iterator(); i.hasNext(); ) + { + out.write(((CompressionMethod) i.next()).getValue()); + } + if (extensions != null) + { + ByteArrayOutputStream out2 = new ByteArrayOutputStream(); + for (Iterator i = extensions.iterator(); i.hasNext(); ) + { + ((Extension) i.next()).write(out2); + } + out.write(out2.size() >>> 8 & 0xFF); + out.write(out2.size() & 0xFF); + out2.writeTo(out); + } + } + + ProtocolVersion getVersion() + { + return version; + } + + Random getRandom() + { + return random; + } + + byte[] getSessionId() + { + return sessionId; + } + + List getCipherSuites() + { + return suites; + } + + List getCompressionMethods() + { + return comp; + } + + List getExtensions() + { + return extensions; + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println("struct {"); + out.println(" version = " + version + ";"); + BufferedReader r = new BufferedReader(new StringReader(random.toString())); + String s; + try + { + while ((s = r.readLine()) != null) + { + out.print(" "); + out.println(s); + } + } + catch (IOException ignored) + { + } + out.println(" sessionId = " + Util.toHexString(sessionId, ':') + ";"); + out.println(" cipherSuites = {"); + for (Iterator i = suites.iterator(); i.hasNext(); ) + { + out.print(" "); + out.println(i.next()); + } + out.println(" };"); + out.print(" compressionMethods = { "); + for (Iterator i = comp.iterator(); i.hasNext(); ) + { + out.print(i.next()); + if (i.hasNext()) + out.print(", "); + } + out.println(" };"); + if (extensions != null) + { + out.println(" extensions = {"); + for (Iterator i = extensions.iterator(); i.hasNext(); ) + { + r = new BufferedReader(new StringReader(i.next().toString())); + try + { + while ((s = r.readLine()) != null) + { + out.print(" "); + out.println(s); + } + } + catch (IOException ignored) + { + } + } + out.println(" };"); + } + out.println("} ClientHello;"); + return str.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchange.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchange.java new file mode 100644 index 00000000000..828aa8d5e93 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchange.java @@ -0,0 +1,181 @@ +/* ClientKeyExchange.java -- SSL ClientKeyExchange message. + Copyright (C) 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.net.ssl.provider; + +import java.io.BufferedReader; +import java.io.DataInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.StringWriter; + +import java.math.BigInteger; + +import java.security.PublicKey; +import java.security.interfaces.RSAKey; +import javax.crypto.interfaces.DHPublicKey; + +final class ClientKeyExchange implements Handshake.Body +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final Object exObject; + + // Constructors. + // ------------------------------------------------------------------------- + + ClientKeyExchange(byte[] encryptedSecret) + { + exObject = encryptedSecret; + } + + ClientKeyExchange(BigInteger bigint) + { + exObject = bigint; + } + + // Class method. + // ------------------------------------------------------------------------- + + static ClientKeyExchange read(InputStream in, CipherSuite suite, + PublicKey key) + throws IOException + { + DataInputStream din = new DataInputStream(in); + if (suite.getKeyExchange().equals("RSA")) + { + int len = 0; + if (suite.getVersion() == ProtocolVersion.SSL_3) + { + len = (((RSAKey) key).getModulus().bitLength()+7) / 8; + } + else + { + len = din.readUnsignedShort(); + } + byte[] buf = new byte[len]; + din.readFully(buf); + return new ClientKeyExchange(buf); + } + else if (suite.getKeyExchange().equals("SRP")) + { + byte[] buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + return new ClientKeyExchange(new BigInteger(1, buf)); + } + else if (key == null || !(key instanceof DHPublicKey)) // explicit. + { + byte[] buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + return new ClientKeyExchange(new BigInteger(1, buf)); + } + else + { + return new ClientKeyExchange(new byte[0]); + } + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + throw new UnsupportedOperationException("use write(java.io.OutputStream,ProtocolVersion) instead"); + } + + public void write(OutputStream out, ProtocolVersion version) throws IOException + { + if (exObject instanceof byte[]) + { + byte[] b = (byte[]) exObject; + if (b.length > 0) + { + if (version != ProtocolVersion.SSL_3) + { + out.write(b.length >>> 8 & 0xFF); + out.write(b.length & 0xFF); + } + out.write(b); + } + } + else + { + byte[] bigint = ((BigInteger) exObject).toByteArray(); + if (bigint[0] == 0x00) + { + out.write(bigint.length - 1 >>> 8 & 0xFF); + out.write(bigint.length - 1 & 0xFF); + out.write(bigint, 1, bigint.length - 1); + } + else + { + out.write(bigint.length >>> 8 & 0xFF); + out.write(bigint.length & 0xFF); + out.write(bigint); + } + } + } + + Object getExchangeObject() + { + return exObject; + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println("struct {"); + if (exObject instanceof byte[] && ((byte[]) exObject).length > 0) + { + out.println(" encryptedPreMasterSecret ="); + out.print(Util.hexDump((byte[]) exObject, " ")); + } + else if (exObject instanceof BigInteger) + { + out.println(" clientPublic = " + ((BigInteger) exObject).toString(16) + ";"); + } + out.println("} ClientKeyExchange;"); + return str.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethod.java b/libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethod.java new file mode 100644 index 00000000000..c2fdf05f9a3 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethod.java @@ -0,0 +1,104 @@ +/* CompressionMethod.java -- the compression method enum. + Copyright (C) 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.net.ssl.provider; + +import java.io.EOFException; +import java.io.InputStream; +import java.io.IOException; + +final class CompressionMethod implements Enumerated +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + static final CompressionMethod NULL = new CompressionMethod(0), + ZLIB = new CompressionMethod(1); + + private final int value; + + // Constructor. + // ------------------------------------------------------------------------- + + private CompressionMethod(int value) + { + this.value = value; + } + + // Class method. + // ------------------------------------------------------------------------- + + static CompressionMethod read(InputStream in) throws IOException + { + int value = in.read(); + if (value == -1) + { + throw new EOFException("unexpected end of input stream"); + } + switch (value & 0xFF) + { + case 0: return NULL; + case 1: return ZLIB; + default: return new CompressionMethod(value); + } + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public byte[] getEncoded() + { + return new byte[] { (byte) value }; + } + + public int getValue() + { + return value; + } + + public String toString() + { + switch (value) + { + case 0: return "null"; + case 1: return "zlib"; + default: return "unknown(" + value + ")"; + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Constructed.java b/libjava/classpath/gnu/javax/net/ssl/provider/Constructed.java new file mode 100644 index 00000000000..ee3f56a7f47 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Constructed.java @@ -0,0 +1,57 @@ +/* Constructed.java -- constructed type. + Copyright (C) 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.net.ssl.provider; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * The base interface to SSL constructed types. + */ +interface Constructed +{ + + /** + * Writes this structure's encoded form to the given output stream. + * + * @param out The output stream. + * @throws IOException If an I/O error occurs. + */ + void write(OutputStream out) throws IOException; +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ContentType.java b/libjava/classpath/gnu/javax/net/ssl/provider/ContentType.java new file mode 100644 index 00000000000..336809467e4 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ContentType.java @@ -0,0 +1,135 @@ +/* ContentType.java -- record layer content type. + Copyright (C) 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.net.ssl.provider; + +import java.io.EOFException; +import java.io.InputStream; +import java.io.IOException; + +/** + * The content type enumeration, which marks packets in the record layer. + * + * <pre>enum { change_cipher_spec(20), alert(21), handshake(22), + * application_data(23), (255) } ContentType;</pre> + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +final class ContentType implements Enumerated +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + static final ContentType CLIENT_HELLO_V2 = new ContentType( 1); + static final ContentType CHANGE_CIPHER_SPEC = new ContentType(20); + static final ContentType ALERT = new ContentType(21); + static final ContentType HANDSHAKE = new ContentType(22); + static final ContentType APPLICATION_DATA = new ContentType(23); + + private int value; + + // Constructors. + // ------------------------------------------------------------------------ + + private ContentType(int value) + { + this.value = value; + } + + // Class methods. + // ------------------------------------------------------------------------ + + static final ContentType read(InputStream in) throws IOException + { + int value = in.read(); + if (value == -1) + { + throw new EOFException("unexpected end of input stream"); + } + switch (value & 0xFF) + { + case 1: return CLIENT_HELLO_V2; + case 20: return CHANGE_CIPHER_SPEC; + case 21: return ALERT; + case 22: return HANDSHAKE; + case 23: return APPLICATION_DATA; + default: return new ContentType(value); + } + } + + // Instance methods. + // ------------------------------------------------------------------------ + + public byte[] getEncoded() + { + return new byte[] { (byte) value }; + } + + public int getValue() + { + return value; + } + + public boolean equals(Object o) + { + if (o == null || !(o instanceof ContentType)) + { + return false; + } + return ((ContentType) o).value == value; + } + + public int hashCode() + { + return getValue(); + } + + public String toString() + { + switch (value) + { + case 1: return "v2_client_hello"; + case 20: return "change_cipher_spec"; + case 21: return "alert"; + case 22: return "handshake"; + case 23: return "application_data"; + default: return "unknown(" + value + ")"; + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Context.java b/libjava/classpath/gnu/javax/net/ssl/provider/Context.java new file mode 100644 index 00000000000..2bd7193f265 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Context.java @@ -0,0 +1,334 @@ +/* Context.java -- SSLContext implementation. + Copyright (C) 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.net.ssl.provider; + +import java.io.File; +import java.io.InputStream; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyStoreException; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.SecureRandom; +import java.security.Security; +import java.security.UnrecoverableKeyException; +import java.sql.SQLException; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContextSpi; +import javax.net.ssl.SSLSessionContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509KeyManager; +import javax.net.ssl.X509TrustManager; + +import gnu.javax.net.ssl.NullManagerParameters; +import gnu.javax.net.ssl.SRPTrustManager; +import gnu.javax.net.ssl.StaticTrustAnchors; + +/** + * This is Jessie's implementation of a {@link javax.net.ssl.SSLContext} + * engine, and is available under the algorithm names ``SSLv3'', ``SSL'', + * ``TLSv1'', and ``TLS''. + */ +public final class Context extends SSLContextSpi +{ + + // Fields. + // ------------------------------------------------------------------------- + + private SessionContext clientSessions; + private SessionContext serverSessions; + private X509KeyManager keyManager; + private X509TrustManager trustManager; + private SRPTrustManager srpTrustManager; + private SecureRandom random; + + // Constructor. + // ------------------------------------------------------------------------- + + public Context() + { + String codec = Util.getSecurityProperty("jessie.clientSessionContext.codec"); + String codecClass = null; + if (codec == null) + { + codec = "null"; + } + if (codec.equalsIgnoreCase("xml")) + { + codecClass = "gnu.javax.net.ssl.provider.XMLSessionContext"; + } + else if (codec.equalsIgnoreCase("jdbc")) + { + codecClass = "gnu.javax.net.ssl.provider.JDBCSessionContext"; + } + else if (codec.equalsIgnoreCase("null")) + { + codecClass = "gnu.javax.net.ssl.provider.SessionContext"; + } + else + { + throw new IllegalArgumentException("no such codec: " + codec); + } + try + { + ClassLoader cl = Context.class.getClassLoader(); + if (cl == null) + { + cl = ClassLoader.getSystemClassLoader(); + } + clientSessions = (SessionContext) cl.loadClass(codecClass).newInstance(); + } + catch (Exception ex) + { + ex.printStackTrace(); + throw new IllegalArgumentException(ex.toString()); + } + + codec = Util.getSecurityProperty("jessie.serverSessionContext.codec"); + if (codec == null) + { + codec = "null"; + } + if (codec.equalsIgnoreCase("xml")) + { + codecClass = "gnu.javax.net.ssl.provider.XMLSessionContext"; + } + else if (codec.equalsIgnoreCase("jdbc")) + { + codecClass = "gnu.javax.net.ssl.provider.JDBCSessionContext"; + } + else if (codec.equalsIgnoreCase("null")) + { + codecClass = "gnu.javax.net.ssl.provider.SessionContext"; + } + else + { + throw new IllegalArgumentException("no such codec: " + codec); + } + try + { + ClassLoader cl = Context.class.getClassLoader(); + if (cl == null) + { + cl = ClassLoader.getSystemClassLoader(); + } + serverSessions = (SessionContext) cl.loadClass(codecClass).newInstance(); + } + catch (Exception ex) + { + ex.printStackTrace(); + throw new IllegalArgumentException(ex.toString()); + } + } + + // Engine methods. + // ------------------------------------------------------------------------- + + protected SSLSessionContext engineGetClientSessionContext() + { + return clientSessions; + } + + protected SSLSessionContext engineGetServerSessionContext() + { + return serverSessions; + } + + protected javax.net.ssl.SSLServerSocketFactory engineGetServerSocketFactory() + { + if (keyManager == null || (trustManager == null && srpTrustManager == null) + || random == null) + { + throw new IllegalStateException(); + } + return new SSLServerSocketFactory(trustManager, srpTrustManager, keyManager, + random, serverSessions); + } + + protected javax.net.ssl.SSLSocketFactory engineGetSocketFactory() + { + if (keyManager == null || trustManager == null || random == null) + { + throw new IllegalStateException(); + } + return new SSLSocketFactory(trustManager, keyManager, random, clientSessions); + } + + protected void engineInit(KeyManager[] keyManagers, + TrustManager[] trustManagers, SecureRandom random) + throws KeyManagementException + { + keyManager = null; + trustManager = null; + srpTrustManager = null; + if (keyManagers != null) + { + for (int i = 0; i < keyManagers.length; i++) + { + if (keyManagers[i] instanceof X509KeyManager) + { + keyManager = (X509KeyManager) keyManagers[i]; + break; + } + } + } + if (keyManager == null) + { + keyManager = defaultKeyManager(); + } + if (trustManagers != null) + { + for (int i = 0; i < trustManagers.length; i++) + { + if (trustManagers[i] instanceof X509TrustManager) + { + if (trustManager == null) + { + trustManager = (X509TrustManager) trustManagers[i]; + } + } + else if (trustManagers[i] instanceof SRPTrustManager) + { + if (srpTrustManager == null) + { + srpTrustManager = (SRPTrustManager) trustManagers[i]; + } + } + } + } + if (trustManager == null && srpTrustManager == null) + { + trustManager = defaultTrustManager(); + } + if (random != null) + { + this.random = random; + } + else + { + this.random = defaultRandom(); + } + } + + // Own methods. + // ------------------------------------------------------------------------- + + private X509KeyManager defaultKeyManager() throws KeyManagementException + { + KeyManagerFactory fact = null; + try + { + fact = KeyManagerFactory.getInstance("JessieX509", "Jessie"); + } + catch (NoSuchAlgorithmException nsae) + { + throw new KeyManagementException(); + } + catch (NoSuchProviderException nspe) + { + throw new KeyManagementException(); + } + try + { + fact.init(null, null); + return (X509KeyManager) fact.getKeyManagers()[0]; + } + catch (NoSuchAlgorithmException nsae) { } + catch (KeyStoreException kse) { } + catch (UnrecoverableKeyException uke) { } + catch (IllegalStateException ise) { } + + try + { + fact.init(new NullManagerParameters()); + return (X509KeyManager) fact.getKeyManagers()[0]; + } + catch (Exception shouldNotHappen) + { + throw new Error(shouldNotHappen.toString()); + } + } + + private X509TrustManager defaultTrustManager() throws KeyManagementException + { + try + { + TrustManagerFactory fact = + TrustManagerFactory.getInstance("JessieX509", "Jessie"); + fact.init(StaticTrustAnchors.CA_CERTS); + return (X509TrustManager) fact.getTrustManagers()[0]; + } + catch (NoSuchAlgorithmException nsae) + { + throw new KeyManagementException(nsae.toString()); + } + catch (NoSuchProviderException nspe) + { + throw new KeyManagementException(nspe.toString()); + } + catch (InvalidAlgorithmParameterException kse) + { + throw new KeyManagementException(kse.toString()); + } + } + + private SecureRandom defaultRandom() throws KeyManagementException + { + String alg = Util.getSecurityProperty("jessie.secure.random"); + if (alg == null) + { + alg = "Fortuna"; + } + SecureRandom rand = null; + try + { + rand = SecureRandom.getInstance(alg); + } + catch (NoSuchAlgorithmException nsae) + { + throw new KeyManagementException(nsae.toString()); + } + + return rand; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/DiffieHellman.java b/libjava/classpath/gnu/javax/net/ssl/provider/DiffieHellman.java new file mode 100644 index 00000000000..ad48c795906 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/DiffieHellman.java @@ -0,0 +1,285 @@ +/* DiffieHellman.java -- Diffie-Hellman key exchange. + Copyright (C) 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.net.ssl.provider; + +import java.math.BigInteger; +import gnu.javax.crypto.key.dh.GnuDHPrivateKey; + +/** + * <p>Simple implementation of two-party Diffie-Hellman key agreement.</p> + * + * <p>The primes used in this class are from the following documents:</p> + * + * <ul> + * <li>D. Harkins and D. Carrel, "The Internet Key Exchange (IKE)", <a + * href="http://www.ietf.org/rfc/rfc2409.txt">RFC 2409</a>.</li> + * <li>T. Kivinen and M. Kojo, "More Modular + * Exponential (MODP) Diffie-Hellman groups for Internet Key Exchange + * (IKE)", <a href="http://www.ietf.org/rfc/rfc3526.txt">RFC + * 3526</a>.</li> + * </li> + * + * <p>The generator for all these primes is 2.</p> + */ +final class DiffieHellman +{ + + // Class method. + // ------------------------------------------------------------------------- + + /** + * Get the system's Diffie-Hellman parameters, in which <i>g</i> is 2 + * and <i>p</i> is determined by the property + * <code>"jessie.keypool.dh.group"</code>. The default value for <i>p</i> + * is 18, corresponding to {@link #GROUP_18}. + */ + static GnuDHPrivateKey getParams() + { + BigInteger p = DiffieHellman.GROUP_5; + String group = Util.getSecurityProperty("jessie.key.dh.group"); + if (group != null) + { + group = group.trim(); + if (group.equals("1")) + p = DiffieHellman.GROUP_1; + else if (group.equals("2")) + p = DiffieHellman.GROUP_2; + else if (group.equals("5")) + p = DiffieHellman.GROUP_5; + else if (group.equals("14")) + p = DiffieHellman.GROUP_14; + else if (group.equals("15")) + p = DiffieHellman.GROUP_15; + else if (group.equals("16")) + p = DiffieHellman.GROUP_16; + else if (group.equals("17")) + p = DiffieHellman.GROUP_17; + else if (group.equals("18")) + p = DiffieHellman.GROUP_18; + } + return new GnuDHPrivateKey(null, p, DH_G, null); + } + + // Constants. + // ------------------------------------------------------------------------- + + /** + * The generator for all Diffie Hellman groups below. + */ + static final BigInteger DH_G = BigInteger.valueOf(2L); + + /** + * p = 2^768 - 2 ^704 - 1 + 2^64 * { [2^638 pi] + 149686 } + */ + static final BigInteger GROUP_1 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF", 16); + + /** + * p = 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 } + */ + static final BigInteger GROUP_2 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" + + "FFFFFFFFFFFFFFFF", 16); + + /** + * This prime p = 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 }. + */ + static final BigInteger GROUP_5 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", 16); + + /** + * p = 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 }. + */ + static final BigInteger GROUP_14 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + + "15728E5A8AACAA68FFFFFFFFFFFFFFFF", 16); + + /** + * p = 2^3072 - 2^3008 - 1 + 2^64 * { [2^2942 pi] + 1690314 }. + */ + static final BigInteger GROUP_15 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" + + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" + + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" + + "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF", 16); + + /** + * p = 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 }. + */ + static final BigInteger GROUP_16 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" + + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" + + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" + + "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" + + "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" + + "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" + + "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" + + "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" + + "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" + + "FFFFFFFFFFFFFFFF", 16); + + static final BigInteger GROUP_17 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" + + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" + + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" + + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" + + "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8" + + "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C" + + "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718" + + "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D" + + "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D" + + "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226" + + "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC" + + "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26" + + "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB" + + "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2" + + "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127" + + "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" + + "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406" + + "AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918" + + "DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151" + + "2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03" + + "F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F" + + "BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" + + "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B" + + "B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632" + + "387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E" + + "6DCC4024FFFFFFFFFFFFFFFF", 16); + + /** + * p = 2^8192 - 2^8128 - 1 + 2^64 * { [2^8062 pi] + 4743158 }. + * + * <p>This value, while quite large, is estimated to provide the equivalent + * cryptographic strength of a symmetric key between 190 and 320 bits. + */ + static final BigInteger GROUP_18 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" + + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" + + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" + + "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" + + "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" + + "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" + + "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" + + "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" + + "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" + + "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" + + "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" + + "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" + + "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" + + "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" + + "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" + + "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" + + "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" + + "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" + + "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" + + "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4" + + "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300" + + "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568" + + "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9" + + "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B" + + "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A" + + "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36" + + "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1" + + "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92" + + "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47" + + "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" + + "60C980DD98EDD3DFFFFFFFFFFFFFFFFF", 16); + +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/DigestInputStream.java b/libjava/classpath/gnu/javax/net/ssl/provider/DigestInputStream.java new file mode 100644 index 00000000000..dd138b436a1 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/DigestInputStream.java @@ -0,0 +1,103 @@ +/* DigestInputStream.java -- digesting input stream. + Copyright (C) 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.net.ssl.provider; + +import java.io.FilterInputStream; +import java.io.InputStream; +import java.io.IOException; + +import gnu.java.security.hash.IMessageDigest; + +final class DigestInputStream extends FilterInputStream +{ + + // Fields. + // ------------------------------------------------------------------------- + + private IMessageDigest md5, sha; + private boolean digesting; + + // Constructor. + // ------------------------------------------------------------------------- + + DigestInputStream(InputStream in, IMessageDigest md5, IMessageDigest sha) + { + super(in); + if (md5 == null || sha == null) + throw new NullPointerException(); + this.md5 = md5; + this.sha = sha; + digesting = true; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + void setDigesting(boolean digesting) + { + this.digesting = digesting; + } + + public int read() throws IOException + { + int i = in.read(); + if (digesting && i != -1) + { + md5.update((byte) i); + sha.update((byte) i); + } + 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 + { + int ret = in.read(buf, off, len); + if (digesting && ret != -1) + { + md5.update(buf, off, ret); + sha.update(buf, off, ret); + } + return ret; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/DigestOutputStream.java b/libjava/classpath/gnu/javax/net/ssl/provider/DigestOutputStream.java new file mode 100644 index 00000000000..f1548459e8c --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/DigestOutputStream.java @@ -0,0 +1,107 @@ +/* DigestOutputStream.java -- digesting output stream. + Copyright (C) 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.net.ssl.provider; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import gnu.java.security.hash.IMessageDigest; + +final class DigestOutputStream extends FilterOutputStream +{ + + // Fields. + // ------------------------------------------------------------------------- + + private IMessageDigest md5, sha; + private boolean digesting; + + // Constructor. + // ------------------------------------------------------------------------- + + DigestOutputStream(OutputStream out, IMessageDigest md5, IMessageDigest sha) + { + super(out); + this.md5 = md5; + this.sha = sha; + digesting = true; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + void setDigesting(boolean digesting) + { + this.digesting = digesting; + } + + public void write(int b) throws IOException + { + if (digesting) + { + md5.update((byte) b); + sha.update((byte) b); + } + out.write(b); + } + + public void write(byte[] buf) throws IOException + { + write(buf, 0, buf.length); + } + + public void write(byte[] buf, int off, int len) throws IOException + { + if (buf == null) + { + throw new NullPointerException(); + } + if (off < 0 || len < 0 || off+len > buf.length) + { + throw new ArrayIndexOutOfBoundsException(); + } + if (digesting) + { + md5.update(buf, off, len); + sha.update(buf, off, len); + } + out.write(buf, off, len); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Enumerated.java b/libjava/classpath/gnu/javax/net/ssl/provider/Enumerated.java new file mode 100644 index 00000000000..8875addab3f --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Enumerated.java @@ -0,0 +1,79 @@ +/* Enumerated.java -- Interface to enumerated types. + Copyright (C) 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.net.ssl.provider; + +/** + * An enumerated type in the SSL protocols. Enumerated values take on + * one of a set of possible numeric values, which are not specifically + * ordered, and may be extensible to a maximum value. + * + * <pre>enum { e1(v1), e2(v2), ... [[, (n) ]] }</pre> + * + * <p>Enumerated types are encoded as big-endian multibyte integers, + * which take up the least possible number of bytes. Thus, an + * enumeration with up to 255 values will be encoded in a single byte, + * and so on. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +interface Enumerated +{ + + /** + * Returns the encoded value of this enumerated value, which is + * appropriate to send over-the-wire. + * + * @return The encoded value. + */ + byte[] getEncoded(); + + /** + * Returns the numeric value of this enumerated value. + * + * @return The numeric value. + */ + int getValue(); + + /** + * Returns a string representation of this enumerated value. + * + * @return The string. + */ + String toString(); +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Extension.java b/libjava/classpath/gnu/javax/net/ssl/provider/Extension.java new file mode 100644 index 00000000000..1c79dd5cb26 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Extension.java @@ -0,0 +1,214 @@ +/* Extension.java -- A TLS hello extension. + Copyright (C) 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.net.ssl.provider; + +import java.io.EOFException; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; + +final class Extension implements Constructed +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final Type type; + private final byte[] value; + + // Constructor. + // ------------------------------------------------------------------------- + + Extension(Type type, byte[] value) + { + if (type == null || value == null) + { + throw new NullPointerException(); + } + this.type = type; + this.value = value; + } + + // Class method. + // ------------------------------------------------------------------------- + + static Extension read(InputStream in) throws IOException + { + Type t = Type.read(in); + int len = (in.read() & 0xFF) << 8 | (in.read() & 0xFF); + byte[] v = new byte[len]; + int count = 0; + while (count < len) + { + int l = in.read(v, count, len - count); + if (l == -1) + { + throw new EOFException("unexpected end of extension"); + } + count += l; + } + return new Extension(t, v); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + out.write(type.getEncoded()); + out.write(value.length >>> 8 & 0xFF); + out.write(value.length & 0xFF); + out.write(value); + } + + Type getType() + { + return type; + } + + byte[] getValue() + { + return value; + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println("struct {"); + out.println(" type = " + type + ";"); + out.println(" value ="); + out.println(Util.hexDump(value, " ")); + out.println("} Extension;"); + return str.toString(); + } + + // Inner class. + // ------------------------------------------------------------------------- + + static final class Type implements Enumerated + { + + // Constants and fields. + // ----------------------------------------------------------------------- + + static final Type SERVER_NAME = new Type(0); + static final Type MAX_FRAGMENT_LENGTH = new Type(1); + static final Type CLIENT_CERTIFICATE_URL = new Type(2); + static final Type TRUSTED_CA_KEYS = new Type(3); + static final Type TRUNCATED_HMAC = new Type(4); + static final Type STATUS_REQUEST = new Type(5); + static final Type SRP = new Type(6); + static final Type CERT_TYPE = new Type(7); + + private final int value; + + // Constructor. + // ----------------------------------------------------------------------- + + private Type(int value) + { + this.value = value; + } + + // Class methods. + // ----------------------------------------------------------------------- + + static Type read(InputStream in) throws IOException + { + int i = in.read(); + if (i == -1) + { + throw new EOFException("unexpected end of input stream"); + } + int value = (i & 0xFF) << 8; + i = in.read(); + if (i == -1) + { + throw new EOFException("unexpected end of input stream"); + } + value |= i & 0xFF; + switch (value) + { + case 0: return SERVER_NAME; + case 1: return MAX_FRAGMENT_LENGTH; + case 2: return CLIENT_CERTIFICATE_URL; + case 3: return TRUSTED_CA_KEYS; + case 4: return TRUNCATED_HMAC; + case 5: return STATUS_REQUEST; + case 6: return SRP; + case 7: return CERT_TYPE; + default: return new Type(value); + } + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public byte[] getEncoded() + { + return new byte[] { + (byte) (value >>> 8 & 0xFF), (byte) (value & 0xFF) + }; + } + + public int getValue() + { + return value; + } + + public String toString() + { + switch (value) + { + case 0: return "server_name"; + case 1: return "max_fragment_length"; + case 2: return "client_certificate_url"; + case 3: return "trusted_ca_keys"; + case 4: return "truncated_hmac"; + case 5: return "status_request"; + case 6: return "srp"; + case 7: return "cert_type"; + default: return "unknown(" + value + ")"; + } + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Extensions.java b/libjava/classpath/gnu/javax/net/ssl/provider/Extensions.java new file mode 100644 index 00000000000..9ed9619f06f --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Extensions.java @@ -0,0 +1,159 @@ +/* Extensions.java -- various static extension utilities. + Copyright (C) 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.net.ssl.provider; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import javax.security.auth.x500.X500Principal; + +import gnu.java.security.x509.X500DistinguishedName; + +final class Extensions +{ + + // Constants. + // ------------------------------------------------------------------------- + + private static final Integer _512 = new Integer(512), + _1024 = new Integer(1024), _2048 = new Integer(2048), + _4096 = new Integer(4096); + + // Class methods only. + private Extensions() { } + + // Class methods. + // ------------------------------------------------------------------------- + + static List getServerName(Extension ex) + { + LinkedList l = new LinkedList(); + byte[] buf = ex.getValue(); + int pos = 0; + try + { + while (pos < buf.length) + { + if (buf[pos++] != 0) + break; + int len = (buf[pos++] & 0xFF) << 8; + len |= buf[pos++] & 0xFF; + l.add(new String(buf, pos, len, "UTF-8")); + pos += len; + } + } + catch (Exception x) + { + } + return Collections.unmodifiableList(l); + } + + static List getClientCertTypes(Extension ex) throws IOException + { + List l = new LinkedList(); + ByteArrayInputStream in = new ByteArrayInputStream(ex.getValue()); + final int len = in.read() & 0xFF; + for (int i = 0; i < len; i++) + { + l.add(CertificateType.read(in)); + } + return Collections.unmodifiableList(l); + } + + static CertificateType getServerCertType(Extension ex) throws IOException + { + return CertificateType.read(new ByteArrayInputStream(ex.getValue())); + } + + static Integer getMaxFragmentLength(Extension ex) + { + switch (ex.getValue()[0] & 0xFF) + { + case 1: return _512; + case 2: return _1024; + case 3: return _2048; + case 4: return _4096; + } + throw new IllegalArgumentException(); + } + + static Object[] getTrustedCA(Extension ex) + { + byte[] buf = ex.getValue(); + int type = buf[0] & 0xFF; + try + { + switch (type) + { + case 0: + return new Object[] { new Integer(type), null }; + case 1: + case 3: + return new Object[] { new Integer(type), + Util.trim(buf, 1, 20) }; + case 2: + return new Object[] { new Integer(type), + new X500Principal(Util.trim(buf, 1, 20)) }; + } + } + catch (Exception x) + { + } + throw new IllegalArgumentException(); + } + + static String getSRPUsername(Extension ex) + { + int len = ex.getValue()[0] & 0xFF; + if (len > ex.getValue().length - 1) + throw new IllegalArgumentException(); + try + { + return new String(ex.getValue(), 1, len, "UTF-8"); + } + catch (UnsupportedEncodingException uee) + { + throw new Error(uee.toString()); + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Finished.java b/libjava/classpath/gnu/javax/net/ssl/provider/Finished.java new file mode 100644 index 00000000000..8b9c220a527 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Finished.java @@ -0,0 +1,143 @@ +/* Finished.java -- SSL Finished message. + Copyright (C) 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.net.ssl.provider; + +import java.io.DataInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; + +final class Finished implements Handshake.Body +{ + + // Fields. + // ------------------------------------------------------------------------- + + /** TLSv1.x verify data. */ + private final byte[] verifyData; + + /** SSLv3 message digest pair. */ + private final byte[] md5, sha; + + // Constructor. + // ------------------------------------------------------------------------- + + Finished(byte[] verifyData) + { + this.verifyData = verifyData; + md5 = sha = null; + } + + Finished(byte[] md5, byte[] sha) + { + this.md5 = md5; + this.sha = sha; + verifyData = null; + } + + // Class methods. + // ------------------------------------------------------------------------- + + static Finished read(InputStream in, CipherSuite suite) + throws IOException + { + DataInputStream din = new DataInputStream(in); + if (suite.getVersion().equals(ProtocolVersion.SSL_3)) + { + byte[] md5 = new byte[16]; + byte[] sha = new byte[20]; + din.readFully(md5); + din.readFully(sha); + return new Finished(md5, sha); + } + else + { + byte[] buf = new byte[12]; + din.readFully(buf); + return new Finished(buf); + } + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + if (verifyData != null) + out.write(verifyData); + else + { + out.write(md5); + out.write(sha); + } + } + + byte[] getVerifyData() + { + return verifyData; + } + + byte[] getMD5Hash() + { + return md5; + } + + byte[] getSHAHash() + { + return sha; + } + + public String toString() + { + String nl = System.getProperty("line.separator"); + if (verifyData != null) + { + return "struct {" + nl + + " verifyData = " + Util.toHexString(verifyData, ':') + ";" + nl + + "} Finished;" + nl; + } + else + { + return "struct {" + nl + + " md5Hash = " + Util.toHexString(md5, ':') + ";" + nl + + " shaHash = " + Util.toHexString(sha, ':') + ";" + nl + + "} Finished;" + nl; + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/GNUSecurityParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/GNUSecurityParameters.java new file mode 100644 index 00000000000..a04c3fd5c15 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/GNUSecurityParameters.java @@ -0,0 +1,490 @@ +/* GNUSecurityParameters.java -- SSL security parameters. + Copyright (C) 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.net.ssl.provider; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; + +import java.security.SecureRandom; +import java.security.Security; +import java.util.Arrays; +import java.util.zip.DataFormatException; +import java.util.zip.Deflater; +import java.util.zip.Inflater; + +import javax.net.ssl.SSLException; + +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mode.IMode; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; + +/** + * This class implements the {@link SecurityParameters} interface, using the + * GNU Crypto interface for ciphers and macs, and the JZlib package for + * record compression. + */ +class GNUSecurityParameters implements SecurityParameters +{ + + // Fields. + // ------------------------------------------------------------------------- + + private static final boolean DEBUG_RECORD_LAYER = false; + private static final PrintWriter debug = new PrintWriter (System.err, true); + + /** + * The CBC block cipher, if any. + */ + IMode inCipher, outCipher; + + /** + * The RC4 PRNG, if any. + */ + IRandom inRandom, outRandom; + + /** + * The MAC algorithm. + */ + IMac inMac, outMac; + + long inSequence, outSequence; + Session session; + ProtocolVersion version; + int fragmentLength; + private Inflater inflater; + private Deflater deflater; + + // Constructors. + // ------------------------------------------------------------------------- + + GNUSecurityParameters (Session session) + { + inSequence = 0; + outSequence = 0; + this.session = session; + fragmentLength = 16384; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void reset() + { + inSequence = 0L; + outSequence = 0L; + inCipher = null; + outCipher = null; + inMac = null; + outMac = null; + inRandom = null; + outRandom = null; + deflater = null; + inflater = null; + } + + public ProtocolVersion getVersion() + { + return version; + } + + public void setVersion(ProtocolVersion version) + { + this.version = version; + } + + public void setInCipher(Object inCipher) + { + if (inCipher instanceof IMode) + { + this.inCipher = (IMode) inCipher; + inRandom = null; + } + else + { + inRandom = (IRandom) inCipher; + this.inCipher = null; + } + } + + public void setOutCipher(Object outCipher) + { + if (outCipher instanceof IMode) + { + this.outCipher = (IMode) outCipher; + outRandom = null; + } + else + { + outRandom = (IRandom) outCipher; + this.outCipher = null; + } + } + + public void setInMac(Object inMac) + { + this.inMac = (IMac) inMac; + inSequence = 0L; + } + + public void setOutMac(Object outMac) + { + this.outMac = (IMac) outMac; + outSequence = 0L; + } + + public void setDeflating (boolean deflate) + { + if (deflate) + { + if (deflater == null) + deflater = new Deflater(); + } + else + deflater = null; + } + + public void setInflating (boolean inflate) + { + if (inflate) + { + if (inflater == null) + inflater = new Inflater(); + } + else + inflater = null; + } + + public int getFragmentLength() + { + return fragmentLength; + } + + public void setFragmentLength (int fragmentLength) + { + this.fragmentLength = fragmentLength; + } + + /** + * Decrypt, verify, and decompress a fragment, returning the transformed + * fragment. + * + * @param fragment The fragment to decrypt. + * @param version The protocol version of the fragment's record. + * @param type The content type of the record. + * @return The decrypted fragment. + * @throws MacException If the MAC could not be verified. + * @throws OverflowException If the inflated data is too large. + * @throws SSLException If decompressing fails. + */ + public synchronized byte[] decrypt (byte[] fragment, ProtocolVersion version, + ContentType type) + throws MacException, OverflowException, SSLException + { + boolean badPadding = false; + + // Decrypt the ciphertext, if it is encrypted. + if (inCipher != null) + { + int bs = inCipher.currentBlockSize (); + for (int i = 0; i < fragment.length; i += bs) + { + inCipher.update (fragment, i, fragment, i); + } + int padLen = fragment[fragment.length-1] & 0xFF; + int len = fragment.length - padLen - 1; + if (version == ProtocolVersion.SSL_3) + { + // SSLv3 requires that the padding length not exceed the + // cipher's block size. + if (padLen >= bs) + { + badPadding = true; + } + } + else + { + for (int i = len; i < fragment.length; i++) + { + // If the TLS padding is wrong, throw a MAC exception below. + if ((fragment[i] & 0xFF) != padLen) + { + badPadding = true; + } + } + } + fragment = Util.trim (fragment, len); + } + else if (inRandom != null) + { + transformRC4 (fragment, 0, fragment.length, fragment, 0, inRandom); + } + + // Check the MAC. + if (inMac != null) + { + inMac.update ((byte) (inSequence >>> 56)); + inMac.update ((byte) (inSequence >>> 48)); + inMac.update ((byte) (inSequence >>> 40)); + inMac.update ((byte) (inSequence >>> 32)); + inMac.update ((byte) (inSequence >>> 24)); + inMac.update ((byte) (inSequence >>> 16)); + inMac.update ((byte) (inSequence >>> 8)); + inMac.update ((byte) inSequence); + inMac.update ((byte) type.getValue()); + if (version != ProtocolVersion.SSL_3) + { + inMac.update ((byte) version.getMajor()); + inMac.update ((byte) version.getMinor()); + } + int macLen = inMac.macSize (); + int fragLen = fragment.length - macLen; + inMac.update ((byte) (fragLen >>> 8)); + inMac.update ((byte) fragLen); + inMac.update (fragment, 0, fragLen); + byte[] mac = inMac.digest (); + inMac.reset (); + for (int i = 0; i < macLen; i++) + { + if (fragment[i + fragLen] != mac[i]) + { + throw new MacException(); + } + } + if (badPadding) + { + throw new MacException(); + } + fragment = Util.trim (fragment, fragLen); + } + + if (inflater != null) + { + byte[] buf = new byte[1024]; + ByteArrayOutputStream bout = new ByteArrayOutputStream (fragment.length << 1); + inflater.setInput (fragment); + int len; + try + { + while ((len = inflater.inflate (buf)) > 0) + { + bout.write (buf, 0, len); + if (bout.size() > fragmentLength + 1024) + throw new OverflowException ("inflated data too large"); + } + } + catch (DataFormatException dfe) + { + throw new SSLException (String.valueOf (dfe)); + } + fragment = bout.toByteArray(); + inflater.reset(); + } + + inSequence++; + return fragment; + } + + /** + * Compress, MAC, encrypt, and write a record. The fragment of the + * record is taken from <i>buf</i> as <i>len</i> bytes starting at + * <i>offset</i>. <i>len</i> <b>must</b> be smaller than or equal to + * the configured fragment length. + * + * @param buf The fragment bytes. + * @param off The offset from whence to read. + * @param len The size of the fragment. + * @param type The content-type for this record. + * @param out The output stream to write the record to. + * @throws IOException If an I/O error occurs. + * @throws SSLException If compression fails. + * @throws OverflowException If compression inflates the data beyond + * the fragment length plus 1024 bytes. + */ + public synchronized byte[] encrypt (byte[] buf, int off, int len, + ContentType type) + throws SSLException, OverflowException + { + // If we are compressing, do it. + if (deflater != null) + { + byte[] buf2 = new byte[1024]; + ByteArrayOutputStream bout = new ByteArrayOutputStream (len >>> 1); + deflater.setInput (buf, off, len); + deflater.finish(); + len = 0; + while ((len = deflater.deflate (buf2)) > 0) + bout.write (buf2, 0, len); + // This should technically never happen for zlib. + if (bout.size() > fragmentLength + 1024) + throw new OverflowException ("deflated data too large"); + buf = bout.toByteArray(); + off = 0; + len = buf.length; + deflater.reset(); + } + + // If there is a MAC, compute it. + byte[] mac = new byte[0]; + if (outMac != null) + { + outMac.update((byte) (outSequence >>> 56)); + outMac.update((byte) (outSequence >>> 48)); + outMac.update((byte) (outSequence >>> 40)); + outMac.update((byte) (outSequence >>> 32)); + outMac.update((byte) (outSequence >>> 24)); + outMac.update((byte) (outSequence >>> 16)); + outMac.update((byte) (outSequence >>> 8)); + outMac.update((byte) outSequence); + outMac.update((byte) type.getValue()); + if (version != ProtocolVersion.SSL_3) + { + outMac.update((byte) version.getMajor()); + outMac.update((byte) version.getMinor()); + } + outMac.update((byte) (len >>> 8)); + outMac.update((byte) len); + outMac.update(buf, off, len); + mac = outMac.digest(); + outMac.reset(); + } + outSequence++; + + // Compute padding if needed. + byte[] pad = new byte[0]; + if (outCipher != null) + { + int padLen = outCipher.currentBlockSize() - + ((len + mac.length + 1) % outCipher.currentBlockSize()); + // Use a random amount of padding if the protocol is TLS. + if (version != ProtocolVersion.SSL_3 && session.random != null) + { + padLen += (Math.abs(session.random.nextInt ()) & 7) * + outCipher.currentBlockSize(); + while (padLen > 255) + { + padLen -= outCipher.currentBlockSize(); + } + } + pad = new byte[padLen+1]; + Arrays.fill (pad, (byte) padLen); + } + + // Write the record header. + final int fraglen = len + mac.length + pad.length; + + // Encrypt and write the fragment. + if (outCipher != null) + { + byte[] buf2 = new byte[fraglen]; + System.arraycopy (buf, off, buf2, 0, len); + System.arraycopy (mac, 0, buf2, len, mac.length); + System.arraycopy (pad, 0, buf2, len + mac.length, pad.length); + int bs = outCipher.currentBlockSize (); + for (int i = 0; i < fraglen; i += bs) + { + outCipher.update (buf2, i, buf2, i); + } + return buf2; + } + else if (outRandom != null) + { + byte[] buf2 = new byte[fraglen]; + transformRC4 (buf, off, len, buf2, 0, outRandom); + transformRC4 (mac, 0, mac.length, buf2, len, outRandom); + return buf2; + } + else + { + if (mac.length == 0) + { + return Util.trim (buf, off, len); + } + else + { + return Util.concat (Util.trim (buf, off, len), mac); + } + } + } + + // Own methods. + // ------------------------------------------------------------------------- + + /** + * Encrypt/decrypt a byte array with the RC4 stream cipher. + * + * @param in The input data. + * @param off The input offset. + * @param len The number of bytes to transform. + * @param out The output buffer. + * @param outOffset The offest into the output buffer. + * @param random The ARCFOUR PRNG. + */ + private static void transformRC4(byte[] in, int off, int len, + byte[] out, int outOffset, IRandom random) + { + if (random == null) + { + throw new IllegalStateException(); + } + if (in == null || out == null) + { + throw new NullPointerException(); + } + if (off < 0 || off + len > in.length || + outOffset < 0 || outOffset + len > out.length) + { + throw new ArrayIndexOutOfBoundsException(); + } + + try + { + for (int i = 0; i < len; i++) + { + out[outOffset+i] = (byte) (in[off+i] ^ random.nextByte()); + } + } + catch (LimitReachedException cannotHappen) + { + throw new Error(cannotHappen.toString()); + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Handshake.java b/libjava/classpath/gnu/javax/net/ssl/provider/Handshake.java new file mode 100644 index 00000000000..ef9e72381c1 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Handshake.java @@ -0,0 +1,440 @@ +/* Handshake.java -- SSL handshake message. + Copyright (C) 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.net.ssl.provider; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.EOFException; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.StringWriter; + +import java.security.PublicKey; + +import java.util.ArrayList; +import java.util.Collections; + +import javax.net.ssl.SSLProtocolException; + +final class Handshake implements Constructed +{ + + // Fields. + // ------------------------------------------------------------------------- + + private static final buffer BUF = new buffer(); + + private final Type type; + private final Body body; + + // Constructors. + // ------------------------------------------------------------------------- + + Handshake(Type type, Body body) + { + this.type = type; + this.body = body; + } + + // Class methods. + // ------------------------------------------------------------------------- + + static Handshake read(byte[] buffer) throws IOException + { + return read(new ByteArrayInputStream(buffer)); + } + + static Handshake read(byte[] buffer, CipherSuite suite, PublicKey key) + throws IOException + { + return read(new ByteArrayInputStream(buffer), suite, key); + } + + static Handshake read(InputStream in) throws IOException + { + return read(in, null, null); + } + + static Handshake read(InputStream in, CipherSuite suite, PublicKey key) + throws IOException + { + return read(in, suite, key, null); + } + + static Handshake read(InputStream in, CertificateType certType) + throws IOException + { + return read(in, null, null, certType); + } + + static Handshake read(InputStream in, CipherSuite suite, PublicKey key, + CertificateType certType) + throws IOException + { + Type type = Type.read(in); + byte[] lenbuf = new byte[3]; + in.read(lenbuf); + int len = (lenbuf[0] & 0xFF) << 16 | (lenbuf[1] & 0xFF) << 8 + | (lenbuf[2] & 0xFF); + Body body = null; + if (type == Type.HELLO_REQUEST) + { + body = null; + } + else if (type == Type.CLIENT_HELLO) + { + // Most likely a V2 hello. If the first byte is 0x30, and if this + // is not a V2 client hello, then it is a V3 client hello with + // at least 1.5 million cipher specs, which is unlikely. + if (lenbuf[0] == 3 && (lenbuf[1] >= 0 && lenbuf[1] <= 2)) + { + ProtocolVersion vers = null; + switch (lenbuf[1]) + { + case 0: + vers = ProtocolVersion.SSL_3; + break; + case 1: + vers = ProtocolVersion.TLS_1; + break; + case 2: + vers = ProtocolVersion.TLS_1_1; + break; + } + int specLen = (lenbuf[2] & 0xFF) << 8 | (in.read() & 0xFF); + int idLen = (in.read() & 0xFF) << 8 | (in.read() & 0xFF); + int chalLen = (in.read() & 0xFF) << 8 | (in.read() & 0xFF); + + ArrayList suites = new ArrayList(specLen / 3); + for (int i = 0; i < specLen; i += 3) + { + if (in.read() == 0) + { + suites.add(CipherSuite.read(in).resolve(vers)); + } + else + { + in.read(); + in.read(); + } + } + byte[] id = new byte[idLen]; + in.read(id); + byte[] challenge = new byte[chalLen]; + in.read(challenge); + if (challenge.length > 32) + challenge = Util.trim(challenge, 32); + else if (challenge.length < 32) + { + byte[] b = new byte[32]; + System.arraycopy(challenge, 0, b, b.length - challenge.length, + challenge.length); + challenge = b; + } + int time = (challenge[0] & 0xFF) << 24 | (challenge[1] & 0xFF) << 16 + | (challenge[2] & 0xFF) << 8 | (challenge[3] & 0xFF); + Random rand = new Random(time, Util.trim(challenge, 4, 28)); + return new Handshake(Handshake.Type.CLIENT_HELLO, + new ClientHello(vers, rand, id, suites, + Collections.singletonList(CompressionMethod.NULL))); + } + // Since hello messages may contain extensions, we read the whole + // thing here. + byte[] buf = new byte[len]; + int count = 0; + while (count < len) + { + int l = in.read(buf, count, len - count); + if (l == -1) + { + throw new EOFException("unexpected end of input stream"); + } + count += l; + } + body = ClientHello.read(new ByteArrayInputStream(buf)); + } + else if (type == Type.SERVER_HELLO) + { + byte[] buf = new byte[len]; + int count = 0; + while (count < len) + { + int l = in.read(buf, count, len - count); + if (l == -1) + { + throw new EOFException("unexpected end of input stream"); + } + count += l; + } + body = ServerHello.read(new ByteArrayInputStream(buf)); + } + else if (type == Type.CERTIFICATE) + { + body = Certificate.read(in, certType); + } + else if (type == Type.SERVER_KEY_EXCHANGE) + { + body = ServerKeyExchange.read(in, suite, key); + } + else if (type == Type.CERTIFICATE_REQUEST) + { + body = CertificateRequest.read(in); + } + else if (type == Type.CERTIFICATE_VERIFY) + { + body = (CertificateVerify) CertificateVerify.read(in, suite, key); + } + else if (type == Type.CLIENT_KEY_EXCHANGE) + { + body = ClientKeyExchange.read(in, suite, key); + } + else if (type == Type.SERVER_HELLO_DONE) + { + body = null; + } + else if (type == Type.FINISHED) + { + body = Finished.read(in, suite); + } + else + { + throw new SSLProtocolException("unknown HandshakeType: " + + type.getValue()); + } + + return new Handshake(type, body); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) + { + throw new UnsupportedOperationException(); + } + + public int write(OutputStream out, ProtocolVersion version) + throws IOException + { + out.write(type.getValue()); + if (body == null) + { + out.write(0); + out.write(0); + out.write(0); + return 4; + } + else + { + ByteArrayOutputStream bout = BUF.getBuffer(); + bout.reset(); + if (body instanceof ServerKeyExchange) + { + ((ServerKeyExchange) body).write(bout, version); + } + else if (body instanceof ClientKeyExchange) + { + ((ClientKeyExchange) body).write(bout, version); + } + else if (body instanceof CertificateVerify) + { + ((CertificateVerify) body).write(bout, version); + } + else + { + body.write(bout); + } + out.write(bout.size() >>> 16 & 0xFF); + out.write(bout.size() >>> 8 & 0xFF); + out.write(bout.size() & 0xFF); + bout.writeTo(out); + return 4 + bout.size(); + } + } + + Type getType() + { + return type; + } + + Body getBody() + { + return body; + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + String nl = System.getProperty("line.separator"); + StringBuffer buf = new StringBuffer(); + out.println("struct {"); + out.println(" type = " + type + ";"); + if (body != null) + { + BufferedReader r = new BufferedReader(new StringReader(body.toString())); + String s; + try + { + while ((s = r.readLine()) != null) + { + out.print(" "); + out.println(s); + } + } + catch (IOException ignored) + { + } + } + out.println("} Handshake;"); + return str.toString(); + } + + // Inner class. + // ------------------------------------------------------------------------- + + static interface Body extends Constructed + { + } + + static class Type implements Enumerated + { + + // Constants and fields. + // ----------------------------------------------------------------------- + + public static final Type + HELLO_REQUEST = new Type( 0), CLIENT_HELLO = new Type( 1), + SERVER_HELLO = new Type( 2), CERTIFICATE = new Type(11), + SERVER_KEY_EXCHANGE = new Type(12), CERTIFICATE_REQUEST = new Type(13), + SERVER_HELLO_DONE = new Type(14), CERTIFICATE_VERIFY = new Type(15), + CLIENT_KEY_EXCHANGE = new Type(16), FINISHED = new Type(20), + CERTIFICATE_URL = new Type(21), CERTIFICATE_STATUS = new Type(22); + + private final int value; + + // Constructor. + // ----------------------------------------------------------------------- + + private Type(int value) + { + this.value = value; + } + + // Class methods. + // ----------------------------------------------------------------------- + + public static Type read(InputStream in) throws IOException + { + int i = in.read(); + if (i == -1) + { + throw new EOFException("unexpected end of input stream"); + } + switch (i & 0xFF) + { + case 0: return HELLO_REQUEST; + case 1: return CLIENT_HELLO; + case 2: return SERVER_HELLO; + case 11: return CERTIFICATE; + case 12: return SERVER_KEY_EXCHANGE; + case 13: return CERTIFICATE_REQUEST; + case 14: return SERVER_HELLO_DONE; + case 15: return CERTIFICATE_VERIFY; + case 16: return CLIENT_KEY_EXCHANGE; + case 20: return FINISHED; + case 21: return CERTIFICATE_URL; + case 22: return CERTIFICATE_STATUS; + default: return new Type(i); + } + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public byte[] getEncoded() + { + return new byte[] { (byte) value }; + } + + public int getValue() + { + return value; + } + + public String toString() + { + switch (value) + { + case 0: return "hello_request"; + case 1: return "client_hello"; + case 2: return "server_hello"; + case 11: return "certificate"; + case 12: return "server_key_exchange"; + case 13: return "certificate_request"; + case 14: return "server_hello_done"; + case 15: return "certificate_verify"; + case 16: return "client_key_exchange"; + case 20: return "finished"; + case 21: return "certificate_url"; + case 22: return "certificate_status"; + default: return "unknown(" + value + ")"; + } + } + } + + private static class buffer extends ThreadLocal + { + static final int SIZE = 2048; + + protected Object initialValue() + { + return new ByteArrayOutputStream(SIZE); + } + + ByteArrayOutputStream getBuffer() + { + return (ByteArrayOutputStream) get(); + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/JCESecurityParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/JCESecurityParameters.java new file mode 100644 index 00000000000..6663c97b59d --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/JCESecurityParameters.java @@ -0,0 +1,307 @@ +/* JCESecurityParameters.java -- JCE-based security parameters. + Copyright (C) 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.net.ssl.provider; + +import java.io.ByteArrayOutputStream; + +import java.util.Arrays; +import java.util.zip.DataFormatException; +import java.util.zip.Deflater; +import java.util.zip.Inflater; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.Mac; + +import javax.net.ssl.SSLException; + +class JCESecurityParameters implements SecurityParameters +{ + + // Fields. + // ------------------------------------------------------------------------- + + private Cipher inCipher, outCipher; + private Mac inMac, outMac; + private Inflater inflater; + private Deflater deflater; + private int fragmentLength; + private long inSequence, outSequence; + private ProtocolVersion version; + + // Constructors. + // ------------------------------------------------------------------------- + + JCESecurityParameters () + { + fragmentLength = 16384; + inSequence = 0L; + outSequence = 0L; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void reset() + { + inCipher = null; + outCipher = null; + inMac = null; + outMac = null; + deflater = null; + inflater = null; + } + + public void setInCipher (Object inCipher) + { + this.inCipher = (Cipher) inCipher; + } + + public void setOutCipher (Object outCipher) + { + this.outCipher = (Cipher) outCipher; + } + + public void setInMac (Object inMac) + { + this.inMac = (Mac) inMac; + inSequence = 0L; + } + + public void setOutMac (Object outMac) + { + this.outMac = (Mac) outMac; + outSequence = 0L; + } + + public void setDeflating (boolean deflate) + { + if (deflate) + { + if (deflater == null) + deflater = new Deflater(); + } + else + deflater = null; + } + + public void setInflating (boolean inflate) + { + if (inflate) + { + if (inflater == null) + inflater = new Inflater(); + } + else + inflater = null; + } + + public int getFragmentLength() + { + return fragmentLength; + } + + public void setFragmentLength (int fragmentLength) + { + this.fragmentLength = fragmentLength; + } + + public ProtocolVersion getVersion() + { + return version; + } + + public void setVersion (ProtocolVersion version) + { + this.version = version; + } + + public synchronized byte[] decrypt (byte[] fragment, ProtocolVersion version, + ContentType type) + throws MacException, OverflowException, SSLException + { + boolean badpad = false; + if (inCipher != null) + { + // We imagine that the JCE would be used in cases where hardware + // acceleration is available, since it isn't really that useful for + // pure Java crypto. We decrypt (and encrypt, below) in one go + // to minimize (potential) calls to native methods. + try + { + fragment = inCipher.doFinal (fragment); + } + catch (BadPaddingException bpe) + { + badpad = true; + } + catch (IllegalBlockSizeException ibse) + { + badpad = true; + } + } + + if (inMac != null) + { + int macLen = inMac.getMacLength(); + int fragLen = fragment.length - macLen; + byte[] mac = Util.trim (fragment, fragLen, macLen); + fragment = Util.trim (fragment, fragLen); + inMac.update ((byte) (inSequence >>> 56)); + inMac.update ((byte) (inSequence >>> 48)); + inMac.update ((byte) (inSequence >>> 40)); + inMac.update ((byte) (inSequence >>> 32)); + inMac.update ((byte) (inSequence >>> 24)); + inMac.update ((byte) (inSequence >>> 16)); + inMac.update ((byte) (inSequence >>> 8)); + inMac.update ((byte) inSequence); + inMac.update ((byte) type.getValue()); + if (version != ProtocolVersion.SSL_3) + { + inMac.update ((byte) version.getMajor()); + inMac.update ((byte) version.getMinor()); + } + inMac.update ((byte) (fragLen >>> 8)); + inMac.update ((byte) fragLen); + inMac.update (fragment); + if (!Arrays.equals (mac, inMac.doFinal()) || badpad) + throw new MacException(); + } + + if (inflater != null) + { + byte[] buf = new byte[1024]; + ByteArrayOutputStream bout = new ByteArrayOutputStream (fragment.length << 1); + inflater.setInput (fragment); + int len; + try + { + while ((len = inflater.inflate (buf)) > 0) + { + bout.write (buf, 0, len); + if (bout.size() > fragmentLength + 1024) + throw new OverflowException ("inflated data too large"); + } + } + catch (DataFormatException dfe) + { + throw new SSLException (String.valueOf (dfe)); + } + fragment = bout.toByteArray(); + inflater.reset(); + } + + inSequence++; + return fragment; + } + + public synchronized byte[] encrypt (byte[] fragment, int off, int len, + ContentType type) + throws OverflowException, SSLException + { + if (deflater != null) + { + byte[] buf = new byte[1024]; + ByteArrayOutputStream bout = new ByteArrayOutputStream (len >>> 1); + deflater.setInput (fragment, off, len); + deflater.finish(); + len = 0; + while ((len = deflater.deflate (buf)) > 0) + bout.write (buf, 0, len); + // This should technically never happen for zlib. + if (bout.size() > fragmentLength + 1024) + throw new OverflowException ("deflated data too large"); + fragment = bout.toByteArray(); + off = 0; + len = fragment.length; + deflater.reset(); + } + + if (outMac != null) + { + outMac.update ((byte) (inSequence >>> 56)); + outMac.update ((byte) (inSequence >>> 48)); + outMac.update ((byte) (inSequence >>> 40)); + outMac.update ((byte) (inSequence >>> 32)); + outMac.update ((byte) (inSequence >>> 24)); + outMac.update ((byte) (inSequence >>> 16)); + outMac.update ((byte) (inSequence >>> 8)); + outMac.update ((byte) inSequence); + outMac.update ((byte) type.getValue()); + if (version != ProtocolVersion.SSL_3) + { + outMac.update ((byte) version.getMajor()); + outMac.update ((byte) version.getMinor()); + } + outMac.update ((byte) (len >>> 8)); + outMac.update ((byte) len); + outMac.update (fragment, off, len); + fragment = Util.concat (fragment, outMac.doFinal()); + off = 0; + len = fragment.length; + } + + if (outCipher != null) + { + try + { + fragment = outCipher.doFinal (fragment, off, len); + } + catch (BadPaddingException shouldNeverHappen) + { + // This is nonsensical. Don't even pretend that we can handle this. + throw new RuntimeException ("bad padding thrown while encrypting"); + } + catch (IllegalBlockSizeException ibse) + { + // Ditto. + throw new RuntimeException ("illegal block size thrown while encrypting"); + } + off = 0; + len = fragment.length; + } + + outSequence++; + if (off == 0 && len == fragment.length) + return fragment; + else + return Util.trim (fragment, off, len); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/JDBCSessionContext.java b/libjava/classpath/gnu/javax/net/ssl/provider/JDBCSessionContext.java new file mode 100644 index 00000000000..2b9b1403425 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/JDBCSessionContext.java @@ -0,0 +1,356 @@ +/* JDBCSessionContext.java -- database persistent sessions. + Copyright (C) 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.net.ssl.provider; + +import java.io.ByteArrayOutputStream; +import java.io.InputStream; + +import java.security.SecureRandom; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Timestamp; +import java.sql.Types; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Enumeration; +import java.util.TreeSet; +import java.util.Vector; + +import javax.net.ssl.SSLSession; + +/** + * The SQL table this class stores sessions in, called <tt>SESSIONS</tt>, + * looks like this: + * + * <blockquote><pre> + * TABLE SESSIONS ( + * ID VARBINARY(32) PRIMARY KEY UNIQUE NOT NULL, + * CREATED TIMESTAMP NOT NULL, + * LAST_ACCESSED TIMESTAMP NOT NULL, + * PROTOCOL VARCHAR(7) NOT NULL, + * SUITE VARCHAR(255) NOT NULL, + * PEER_HOST TEXT NOT NULL, + * PEER_CERT_TYPE VARCHAR(32), + * PEER_CERTS BLOB, + * CERT_TYPE VARCHAR(32), + * CERTS BLOB, + * SECRET VARBINARY(48) NOT NULL + * ) + * </pre></blockquote> + * + * <p>Note that the master secret for sessions is not protected before + * being inserted into the database; it is up to the system to protect + * the stored data from unauthorized access. + */ +class JDBCSessionContext extends SessionContext +{ + + // Fields. + // ------------------------------------------------------------------------- + + protected Connection connection; + protected PreparedStatement selectById; + protected PreparedStatement insert; + protected PreparedStatement selectTimestamp; + protected PreparedStatement updateTimestamp; + protected PreparedStatement deleteSession; + + // Constructor. + // ------------------------------------------------------------------------- + + JDBCSessionContext() throws SQLException + { + String url = Util.getSecurityProperty("jessie.SessionContext.jdbc.url"); + String user = Util.getSecurityProperty("jessie.SessionContext.jdbc.user"); + String passwd = Util.getSecurityProperty("jessie.SessionContext.jdbc.password"); + if (url == null) + { + throw new IllegalArgumentException("no JDBC URL"); + } + if (user == null || passwd == null) + { + connection = DriverManager.getConnection(url); + } + else + { + connection = DriverManager.getConnection(url, user, passwd); + } + selectById = + connection.prepareStatement("SELECT * FROM SESSIONS WHERE ID = ?"); + insert = connection.prepareStatement("INSERT INTO SESSIONS VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + selectTimestamp = + connection.prepareStatement("SELECT CREATED FROM SESSIONS WHERE ID = ?"); + updateTimestamp = + connection.prepareStatement("UPDATE SESSIONS SET LAST_ACCESSED = ? WHERE ID = ?"); + deleteSession = + connection.prepareStatement("DELETE FROM SESSIONS WHERE ID = ?"); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public synchronized Enumeration getIds() + { + Vector ids = new Vector(); + try + { + Statement stmt = connection.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT ID FROM SESSIONS"); + while (rs.next()) + { + byte[] id = rs.getBytes("ID"); + ids.add(id); + } + } + catch (SQLException sqle) + { + } + return ids.elements(); + } + + public synchronized SSLSession getSession(byte[] sessionId) + { + Session session = (Session) super.getSession(sessionId); + if (session == null) + { + try + { + selectById.setBytes(1, sessionId); + ResultSet rs = selectById.executeQuery(); + if (rs.next()) + { + session = new Session(rs.getTimestamp("CREATED").getTime()); + session.enabledSuites = new ArrayList(SSLSocket.supportedSuites); + session.enabledProtocols = new TreeSet(SSLSocket.supportedProtocols); + session.random = new SecureRandom(); + session.context = this; + session.sessionId = new Session.ID(rs.getBytes("ID")); + session.setLastAccessedTime(rs.getTimestamp("LAST_ACCESSED").getTime()); + long elapsed = System.currentTimeMillis() - session.getLastAccessedTime(); + if ((int) (elapsed / 1000L) > timeout) + { + removeSession(session.sessionId); + return null; + } + session.peerHost = rs.getString("PEER_HOST"); + String protocol = rs.getString("PROTOCOL"); + if (protocol.equals("SSLv3")) + { + session.protocol = ProtocolVersion.SSL_3; + } + else if (protocol.equals("TLSv1")) + { + session.protocol = ProtocolVersion.TLS_1; + } + else if (protocol.equals("TLSv1.1")) + { + session.protocol = ProtocolVersion.TLS_1_1; + } + else + { + return null; + } + session.cipherSuite = CipherSuite.forName(rs.getString("SUITE")); + String type = rs.getString("PEER_CERT_TYPE"); + boolean wasNull = rs.wasNull(); + InputStream certs = null; + if (!wasNull) + { + certs = rs.getBinaryStream("PEER_CERTS"); + wasNull = rs.wasNull(); + } + if (!wasNull) + { + CertificateFactory cf = CertificateFactory.getInstance(type); + session.peerCerts = (Certificate[]) + cf.generateCertificates(certs).toArray(new Certificate[0]); + session.peerVerified = true; + } + type = rs.getString("CERT_TYPE"); + wasNull = rs.wasNull(); + if (!wasNull) + { + certs = rs.getBinaryStream("CERTS"); + wasNull = rs.wasNull(); + } + if (!wasNull) + { + CertificateFactory cf = CertificateFactory.getInstance(type); + session.localCerts = (Certificate[]) + cf.generateCertificates(certs).toArray(new Certificate[0]); + } + session.masterSecret = rs.getBytes("SECRET"); + if (cacheSize == 0 || sessions.size() < cacheSize) + { + sessions.put(session.sessionId, session); + } + } + } + catch (Exception ex) + { + } + } + return session; + } + + synchronized boolean addSession(Session.ID id, Session s) + { + if (containsSessionID(id)) + { + return false; + } + try + { + insert.setBytes(1, id.getId()); + insert.setTimestamp(2, new Timestamp(s.getCreationTime())); + insert.setTimestamp(3, new Timestamp(s.getLastAccessedTime())); + insert.setString(4, s.getProtocol()); + insert.setString(5, s.getCipherSuite()); + insert.setString(6, s.peerHost); + if (s.peerCerts != null && s.peerCerts.length > 0) + { + insert.setString(7, s.peerCerts[0].getType()); + insert.setBytes(8, certs(s.peerCerts)); + } + else + { + insert.setNull(7, Types.VARCHAR); + insert.setNull(8, Types.LONGVARBINARY); + } + if (s.localCerts != null && s.localCerts.length > 0) + { + insert.setString(9, s.localCerts[0].getType()); + insert.setBytes(10, certs(s.localCerts)); + } + else + { + insert.setNull(9, Types.VARCHAR); + insert.setNull(10, Types.LONGVARBINARY); + } + insert.setBytes(11, s.masterSecret); + insert.executeUpdate(); + super.addSession(id, s); + } + catch (SQLException sqle) + { + return false; + } + return true; + } + + synchronized boolean containsSessionID(Session.ID sessionId) + { + try + { + selectTimestamp.setBytes(1, sessionId.getId()); + ResultSet rs = selectTimestamp.executeQuery(); + if (!rs.next()) + { + return false; + } + Timestamp ts = rs.getTimestamp("CREATED"); + if (rs.wasNull()) + { + return false; + } + long elapsed = System.currentTimeMillis() - ts.getTime(); + if ((int) (elapsed / 1000) > timeout) + { + removeSession(sessionId); + return false; + } + return true; + } + catch (SQLException sqle) + { + return false; + } + } + + protected boolean removeSession(Session.ID sessionId) + { + super.removeSession(sessionId); + try + { + deleteSession.setBytes(1, sessionId.getId()); + return deleteSession.executeUpdate() > 0; + } + catch (SQLException sqle) + { + } + return false; + } + + synchronized void notifyAccess(Session session) + { + try + { + updateTimestamp.setTimestamp(1, new Timestamp(session.getLastAccessedTime())); + updateTimestamp.setBytes(2, session.getId()); + updateTimestamp.executeUpdate(); + } + catch (SQLException sqle) + { + } + } + + private byte[] certs(Certificate[] certs) + { + ByteArrayOutputStream out = new ByteArrayOutputStream(2048); + for (int i = 0; i < certs.length; i++) + { + try + { + out.write(certs[i].getEncoded()); + } + catch (Exception x) + { + } + } + return out.toByteArray(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Jessie.java b/libjava/classpath/gnu/javax/net/ssl/provider/Jessie.java new file mode 100644 index 00000000000..14b671d0230 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Jessie.java @@ -0,0 +1,91 @@ +/* Jessie.java -- JESSIE's JSSE provider. + Copyright (C) 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.net.ssl.provider; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.Provider; + +/** + * This is the security provider for Jessie. It implements the following + * algorithms: + * + * <pre> + * {@link javax.net.ssl.SSLContext}.SSLv3 + * {@link javax.net.ssl.SSLContext}.SSL + * {@link javax.net.ssl.SSLContext}.TLSv1 + * {@link javax.net.ssl.SSLContext}.TLS + * {@link javax.net.ssl.KeyManagerFactory}.JessieX509 + * {@link javax.net.ssl.TrustManagerFactory}.JessieX509 + * {@link javax.net.ssl.TrustManagerFactory}.SRP + * </pre> + * + */ +public class Jessie extends Provider +{ + + public static final String VERSION = "1.0.0"; + public static final double VERSION_DOUBLE = 1.0; + + public Jessie() + { + super("Jessie", VERSION_DOUBLE, + "Implementing SSLv3, TLSv1 SSL Contexts; X.509 Key Manager Factories;" + + System.getProperty("line.separator") + + "X.509 and SRP Trust Manager Factories, continuously-seeded secure random." ); + + AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + put("SSLContext.SSLv3", Context.class.getName()); + put("Alg.Alias.SSLContext.SSL", "SSLv3"); + put("Alg.Alias.SSLContext.TLSv1", "SSLv3"); + put("Alg.Alias.SSLContext.TLS", "SSLv3"); + //put("Alg.Alias.SSLContext.TLSv1.1", "SSLv3"); + + put("KeyManagerFactory.JessieX509", X509KeyManagerFactory.class.getName()); + put("TrustManagerFactory.JessieX509", X509TrustManagerFactory.class.getName()); + put("TrustManagerFactory.SRP", SRPTrustManagerFactory.class.getName()); + + return null; + } + }); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/JessieDHPrivateKey.java b/libjava/classpath/gnu/javax/net/ssl/provider/JessieDHPrivateKey.java new file mode 100644 index 00000000000..1997458dd24 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/JessieDHPrivateKey.java @@ -0,0 +1,99 @@ +/* JessieDHPrivateKey.java -- simple DH private key. + Copyright (C) 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.net.ssl.provider; + +import java.math.BigInteger; + +import javax.crypto.interfaces.DHPrivateKey; +import javax.crypto.spec.DHParameterSpec; + +class JessieDHPrivateKey implements DHPrivateKey +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final DHParameterSpec params; + private final BigInteger x; + + // Constructor. + // ------------------------------------------------------------------------- + + JessieDHPrivateKey(DHParameterSpec params, BigInteger x) + { + this.params = params; + this.x = x; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String getAlgorithm() + { + return "Diffie-Hellman"; + } + + public String getFormat() + { + return "NONE"; + } + + public byte[] getEncoded() + { + return null; + } + + public DHParameterSpec getParams() + { + return params; + } + + public BigInteger getX() + { + return x; + } + + public String toString() + { + String nl = System.getProperty("line.separator"); + return "P: " + params.getP() + nl + + "G: " + params.getG() + nl + + "X: " + x; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/JessieDHPublicKey.java b/libjava/classpath/gnu/javax/net/ssl/provider/JessieDHPublicKey.java new file mode 100644 index 00000000000..dc6587288e6 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/JessieDHPublicKey.java @@ -0,0 +1,99 @@ +/* JessieDHPublicKey.java -- simple DH public key. + Copyright (C) 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.net.ssl.provider; + +import java.math.BigInteger; + +import javax.crypto.interfaces.DHPublicKey; +import javax.crypto.spec.DHParameterSpec; + +class JessieDHPublicKey implements DHPublicKey +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final DHParameterSpec params; + private final BigInteger y; + + // Constructor. + // ------------------------------------------------------------------------- + + JessieDHPublicKey(DHParameterSpec params, BigInteger y) + { + this.params = params; + this.y = y; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String getAlgorithm() + { + return "Diffie-Hellman"; + } + + public String getFormat() + { + return "NONE"; + } + + public byte[] getEncoded() + { + return null; + } + + public DHParameterSpec getParams() + { + return params; + } + + public BigInteger getY() + { + return y; + } + + public String toString() + { + String nl = System.getProperty("line.separator"); + return "P: " + params.getP() + nl + + "G: " + params.getG() + nl + + "Y: " + y; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/JessieRSAPrivateKey.java b/libjava/classpath/gnu/javax/net/ssl/provider/JessieRSAPrivateKey.java new file mode 100644 index 00000000000..4ec71a7aad3 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/JessieRSAPrivateKey.java @@ -0,0 +1,98 @@ +/* JessieRSAPrivateKey.java -- simple RSA private key. + Copyright (C) 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.net.ssl.provider; + +import java.math.BigInteger; +import java.security.interfaces.RSAPrivateKey; + +class JessieRSAPrivateKey implements RSAPrivateKey +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final BigInteger modulus; + private final BigInteger exponent; + + // Constructor. + // ------------------------------------------------------------------------- + + JessieRSAPrivateKey(BigInteger modulus, BigInteger exponent) + { + this.modulus = modulus; + this.exponent = exponent; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String getAlgorithm() + { + return "RSA"; + } + + public String getFormat() + { + return "NONE"; + } + + public byte[] getEncoded() + { + return null; + } + + public BigInteger getModulus() + { + return modulus; + } + + public BigInteger getPrivateExponent() + { + return exponent; + } + + public String toString() + { + String nl = System.getProperty("line.separator"); + return "RSAPrivateKey {" + nl + + " modulus = " + modulus.toString(16) + ";" + nl + + " exponent = " + exponent.toString(16) + ";" + nl + + "};"; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/JessieRSAPublicKey.java b/libjava/classpath/gnu/javax/net/ssl/provider/JessieRSAPublicKey.java new file mode 100644 index 00000000000..19921d98c67 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/JessieRSAPublicKey.java @@ -0,0 +1,98 @@ +/* JessieRSAPublicKey.java -- simple RSA public key. + Copyright (C) 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.net.ssl.provider; + +import java.math.BigInteger; +import java.security.interfaces.RSAPublicKey; + +class JessieRSAPublicKey implements RSAPublicKey +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final BigInteger modulus; + private final BigInteger exponent; + + // Constructor. + // ------------------------------------------------------------------------- + + JessieRSAPublicKey(BigInteger modulus, BigInteger exponent) + { + this.modulus = modulus; + this.exponent = exponent; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String getAlgorithm() + { + return "RSA"; + } + + public String getFormat() + { + return "NONE"; + } + + public byte[] getEncoded() + { + return null; + } + + public BigInteger getModulus() + { + return modulus; + } + + public BigInteger getPublicExponent() + { + return exponent; + } + + public String toString() + { + String nl = System.getProperty("line.separator"); + return "RSAPublicKey {" + nl + + " modulus = " + modulus.toString(16) + ";" + nl + + " exponent = " + exponent.toString(16) + ";" + nl + + "};"; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/KeyPool.java b/libjava/classpath/gnu/javax/net/ssl/provider/KeyPool.java new file mode 100644 index 00000000000..e342700c269 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/KeyPool.java @@ -0,0 +1,119 @@ +/* KeyPool.java -- A set of ephemeral key pairs. + Copyright (C) 2001, 2002, 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.net.ssl.provider; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.SecureRandom; +import java.security.Security; +import java.util.LinkedList; +import javax.crypto.spec.DHParameterSpec; + +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.Prime2; + +final class KeyPool +{ + + // Fields. + // ------------------------------------------------------------------------- + + private static final BigInteger ONE = BigInteger.ONE; + private static final BigInteger TWO = BigInteger.valueOf(2L); + private static final BigInteger E = BigInteger.valueOf(65537L); + private static final SecureRandom RANDOM = new SecureRandom (); + + // Constructor. + // ------------------------------------------------------------------------- + + private KeyPool() + { + } + + // Class methods. + // ------------------------------------------------------------------------- + + /** + * Generate an export-class (512 bit) RSA key pair. + * + * @return The new key pair. + */ + static KeyPair generateRSAKeyPair() + { + BigInteger p, q, n, d; + + // Simplified version of GNU Crypto's RSAKeyPairGenerator. + + int M = 256; + BigInteger lower = TWO.pow(255); + BigInteger upper = TWO.pow(256).subtract(ONE); + byte[] kb = new byte[32]; + while (true) + { + nextBytes(kb); + p = new BigInteger(1, kb).setBit(0); + if (p.compareTo(lower) >= 0 && p.compareTo(upper) <= 0 && + Prime2.isProbablePrime(p) && p.gcd(E).equals(ONE)) + break; + } + + while (true) + { + nextBytes(kb); + q = new BigInteger(1, kb).setBit(0); + n = q.multiply(p); + if (n.bitLength() == 512 && Prime2.isProbablePrime(q) && + q.gcd(E).equals(ONE)) + break; + } + + d = E.modInverse(p.subtract(ONE).multiply(q.subtract(ONE))); + + return new KeyPair(new JessieRSAPublicKey(n, E), + new JessieRSAPrivateKey(n, d)); + } + + private static void nextBytes(byte[] buf) + { + RANDOM.nextBytes (buf); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/MacException.java b/libjava/classpath/gnu/javax/net/ssl/provider/MacException.java new file mode 100644 index 00000000000..b8c479fdbe7 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/MacException.java @@ -0,0 +1,53 @@ +/* MacException.java -- signals a bad record MAC. + Copyright (C) 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.net.ssl.provider; + +import java.io.IOException; + +class MacException extends IOException +{ + + // Constructor. + // ------------------------------------------------------------------------- + + MacException() + { + super(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/OverflowException.java b/libjava/classpath/gnu/javax/net/ssl/provider/OverflowException.java new file mode 100644 index 00000000000..93bdcaec5ed --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/OverflowException.java @@ -0,0 +1,57 @@ +/* OverflowException.java -- signals an input overflow. + Copyright (C) 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.net.ssl.provider; + +import java.io.IOException; + +class OverflowException extends IOException +{ + + // Constructors. + // ------------------------------------------------------------------------- + + OverflowException() + { + } + + OverflowException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ProtocolVersion.java b/libjava/classpath/gnu/javax/net/ssl/provider/ProtocolVersion.java new file mode 100644 index 00000000000..5f5d1d979aa --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ProtocolVersion.java @@ -0,0 +1,180 @@ +/* ProtocolVersion.java -- An SSL version number. + Copyright (C) 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.net.ssl.provider; + +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; + +final class ProtocolVersion implements Comparable, Constructed +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + static final ProtocolVersion SSL_3 = new ProtocolVersion(3, 0); + static final ProtocolVersion TLS_1 = new ProtocolVersion(3, 1); + static final ProtocolVersion TLS_1_1 = new ProtocolVersion(3, 2); + + private final int major; + private final int minor; + + // Constructor. + // ------------------------------------------------------------------------- + + private ProtocolVersion(int major, int minor) + { + this.major = major; + this.minor = minor; + } + + // Class methods. + // ------------------------------------------------------------------------- + + static ProtocolVersion read(InputStream in) throws IOException + { + int major = in.read() & 0xFF; + int minor = in.read() & 0xFF; + return getInstance(major, minor); + } + + static ProtocolVersion getInstance(int major, int minor) + { + if (major == 3) + { + switch (minor) + { + case 0: return SSL_3; + case 1: return TLS_1; + case 2: return TLS_1_1; + } + } + return new ProtocolVersion(major, minor); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + out.write(major); + out.write(minor); + } + + byte[] getEncoded() + { + return new byte[] { + (byte) major, (byte) minor + }; + } + + int getMajor() + { + return major; + } + + int getMinor() + { + return minor; + } + + public boolean equals(Object o) + { + if (o == null || !(o instanceof ProtocolVersion)) + { + return false; + } + return ((ProtocolVersion) o).major == this.major + && ((ProtocolVersion) o).minor == this.minor; + } + + public int hashCode() + { + return major << 8 | minor; + } + + public int compareTo(Object o) + { + if (o == null || !(o instanceof ProtocolVersion)) + { + return 1; + } + if (this.equals(o)) + { + return 0; + } + if (major > ((ProtocolVersion) o).major) + { + return 1; + } + else if (major < ((ProtocolVersion) o).major) + { + return -1; + } + if (minor > ((ProtocolVersion) o).minor) + { + return 1; + } + else if (minor < ((ProtocolVersion) o).minor) + { + return -1; + } + return 0; + } + + public String toString() + { + if (this == SSL_3) + { + return "SSLv3"; + } + else if (this == TLS_1) + { + return "TLSv1"; + } + else if (this == TLS_1_1) + { + return "TLSv1.1"; + } + else + { + return "Unsupported; major=" + major + " minor=" + minor; + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Random.java b/libjava/classpath/gnu/javax/net/ssl/provider/Random.java new file mode 100644 index 00000000000..c42592b147b --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Random.java @@ -0,0 +1,124 @@ +/* Random.java -- SSL Random structure. + Copyright (C) 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.net.ssl.provider; + +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; + +class Random implements Constructed +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final int gmtUnixTime; + private final byte[] randomBytes; + + // Constructors. + // ------------------------------------------------------------------------- + + Random(int gmtUnixTime, byte[] randomBytes) + { + this.gmtUnixTime = gmtUnixTime; + this.randomBytes = (byte[]) randomBytes.clone(); + } + + // Class methods. + // ------------------------------------------------------------------------- + + static Random read(InputStream in) throws IOException + { + int time = (in.read() & 0xFF) << 24 | (in.read() & 0xFF) << 16 + | (in.read() & 0xFF) << 8 | (in.read() & 0xFF); + byte[] buf = new byte[28]; + in.read(buf); + return new Random(time, buf); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + out.write((gmtUnixTime >>> 24) & 0xFF); + out.write((gmtUnixTime >>> 16) & 0xFF); + out.write((gmtUnixTime >>> 8) & 0xFF); + out.write(gmtUnixTime & 0xFF); + out.write(randomBytes); + } + + byte[] getEncoded() + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(32); + try + { + write(bout); + } + catch (IOException cantHappen) + { + throw new Error(cantHappen.toString()); + } + return bout.toByteArray(); + } + + int getTime() + { + return gmtUnixTime; + } + + byte[] getRandomBytes() + { + return randomBytes; + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println("struct {"); + out.println(" gmt_unix_time = " + gmtUnixTime + ";"); + out.println(" random_bytes = " + Util.toHexString(randomBytes, ':') + ";"); + out.println("} Random;"); + return str.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/RecordInput.java b/libjava/classpath/gnu/javax/net/ssl/provider/RecordInput.java new file mode 100644 index 00000000000..d4ba5b596d6 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/RecordInput.java @@ -0,0 +1,232 @@ +/* RecordInput.java -- record layer input. + Copyright (C) 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.net.ssl.provider; + +import gnu.classpath.SystemProperties; +import gnu.classpath.debug.Component; +import gnu.classpath.debug.SystemLogger; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.PrintWriter; + +import java.util.logging.Logger; + +import javax.net.ssl.SSLProtocolException; + +class RecordInput +{ + + // Fields. + // ------------------------------------------------------------------------- + + private static final boolean DEBUG_RECORD_LAYER = true; + private static final Logger logger = SystemLogger.SYSTEM; + + private byte[] fragment; + private int index; + private ContentType type; + + private final DataInputStream in; + private Session session; + + // Constructor. + // ------------------------------------------------------------------------- + + RecordInput (final InputStream in, final Session session) + { + this.in = new DataInputStream (in); + this.session = session; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + synchronized int available (ContentType type) throws IOException + { + if (fragment == null) + { + readRecord (); + } + if (type != this.type) + { + return 0; + } + return fragment.length - index; + } + + void setSession (Session session) + { + this.session = session; + } + + synchronized int read (byte[] buf, int off, int len, ContentType type) + throws IOException + { + if (off < 0 || len < 0 || off + len > buf.length) + { + throw new ArrayIndexOutOfBoundsException ("size=" + buf.length + + " off=" + off + " len=" + len); + } + if (fragment == null || index >= fragment.length) + { + readRecord (); + } + if (type != this.type) + { + return 0; + } + len = Math.min (len, fragment.length - index); + System.arraycopy (fragment, index, buf, off, len); + index += len; + return len; + } + + boolean pollClose () throws IOException + { + if (fragment == null || index >= fragment.length) + { + try + { + readRecord(); + } + catch (AlertException ae) + { + Alert alert = ae.getAlert(); + if (alert.getDescription() == Alert.Description.CLOSE_NOTIFY) + { + return true; + } + throw ae; + } + } + return false; + } + + private void readRecord() throws IOException + { + type = ContentType.read (in); + if ((type.getValue() & 0x80) != 0 || (type.getValue() & 0x40) != 0) + { + in.read(); + if ((type.getValue() & 0x40) != 0) + { + in.read(); + } + type = ContentType.read(in); + if (type != ContentType.CLIENT_HELLO_V2) + { + throw new SSLProtocolException("unsupported V2 message"); + } + type = ContentType.HANDSHAKE; + // Record this message, and re-present it as a normal handshake + // layer message. ClientHello will handle the real parsing. + ByteArrayOutputStream buffer = new ByteArrayOutputStream (256); + buffer.write(1); // The type we just read. + RecordingInputStream in2 = new RecordingInputStream (in, buffer); + ProtocolVersion version = ProtocolVersion.read (in2); + if (version.compareTo (ProtocolVersion.SSL_3) < 0) + { + throw new SSLProtocolException("unsupported client version"); + } + int len = (in2.read() & 0xFF) << 8 | (in2.read() & 0xFF); + len += (in2.read() & 0xFF) << 8 | (in2.read() & 0xFF); + len += (in2.read() & 0xFF) << 8 | (in2.read() & 0xFF); + int count = 0; + while (count < len) + { + int l = (int) in2.skip(len - count); + if (l > 0) + { + count += l; + } + } + fragment = buffer.toByteArray (); + index = 0; + + // We can't be encrypted/MACed/compressed here, since a V2 message + // will only be sent as the first message, and only by the client. + return; + } + ProtocolVersion v = ProtocolVersion.read (in); + int len = in.readUnsignedShort (); + if (len > session.params.getFragmentLength() + 2048) + { + throw new OverflowException(); + } + fragment = new byte [len]; + in.readFully (fragment); + + if (DEBUG_RECORD_LAYER) + { + logger.log (Component.SSL_RECORD_LAYER, + ">> READ RECORD <<{4}" + + "struct {{4}" + + " type = {0};{4}" + + " version = {1};{4}" + + " length = {2};{4}" + + "{3}{4}" + + "} TLSCiphertext;", new Object[] + { + type, v, new Integer (len), + Util.hexDump (fragment, " "), + SystemProperties.getProperty ("line.separator") + }); + } + + fragment = session.params.decrypt (fragment, v, type); + index = 0; + + if (session.random != null) + session.random.setSeed (fragment); + + if (type == ContentType.ALERT) + { + Alert alert = Alert.read (new ByteArrayInputStream (fragment)); + session.currentAlert = alert; + } + if (session.currentAlert != null) + { + throw new AlertException (session.currentAlert, false); + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/RecordInputStream.java b/libjava/classpath/gnu/javax/net/ssl/provider/RecordInputStream.java new file mode 100644 index 00000000000..14cf829ac67 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/RecordInputStream.java @@ -0,0 +1,106 @@ +/* RecordInputStream.java -- record layer input stream interface. + Copyright (C) 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.net.ssl.provider; + +import java.io.IOException; +import java.io.InputStream; + +class RecordInputStream extends InputStream +{ + + // Fields. + // ------------------------------------------------------------------------- + + /** + * The record input instance. + */ + private final RecordInput in; + + /** + * The content type this stream is reading. + */ + private final ContentType type; + + // Constructor. + // ------------------------------------------------------------------------- + + RecordInputStream (RecordInput in, ContentType type) + { + this.in = in; + this.type = type; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public int available () throws IOException + { + return in.available (type); + } + + public int read () throws IOException + { + byte[] b = new byte[1]; + int ret; + while ((ret = read (b)) != 1) + { + if (ret == -1) + { + return -1; + } + Thread.yield (); + } + return b[0] & 0xFF; + } + + public int read (byte[] buf) throws IOException + { + return read (buf, 0, buf.length); + } + + public int read (byte[] buf, int off, int len) throws IOException + { + return in.read (buf, off, len, type); + } + + public String toString () + { + return RecordInputStream.class.getName () + " [ type=" + type + " ]"; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/RecordOutputStream.java b/libjava/classpath/gnu/javax/net/ssl/provider/RecordOutputStream.java new file mode 100644 index 00000000000..3bf228f2d69 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/RecordOutputStream.java @@ -0,0 +1,189 @@ +/* RecordOutputStream.java -- record layer output. + Copyright (C) 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.net.ssl.provider; + +import gnu.classpath.SystemProperties; +import gnu.classpath.debug.Component; +import gnu.classpath.debug.SystemLogger; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; + +import java.util.logging.Logger; + +/** + * An output stream for writing data to the record layer. All data written + * to this stream (through any of the write methods) is immediately sent + * as a full record, so it is advisable to write large arrays to the stream + * instead of one byte at a time (alternatively, a {@link + * java.io.BufferedOutputStream} can be used). + */ +class RecordOutputStream extends FilterOutputStream +{ + + // Fields. + // ------------------------------------------------------------------------- + + private static final boolean DEBUG_RECORD_LAYER = true; + private static final Logger logger = SystemLogger.SYSTEM; + + /** + * The content type of this output stream. + */ + private final ContentType type; + + /** + * The security parameters. + */ + private final SecurityParameters params; + + private final boolean emitEmpty; + + private static final byte[] ZERO = new byte[0]; + + // Constructor. + // ------------------------------------------------------------------------- + + RecordOutputStream (final OutputStream out, final ContentType type, + final SecurityParameters params) + { + super (out); + this.type = type; + this.params = params; + String empty = Util.getSecurityProperty ("jessie.emit.empty.records"); + if (empty == null) + { + // IE panics if it gets an empty record; so, leave this false + // for the default. + empty = "false"; + } + emitEmpty = Boolean.valueOf (empty).booleanValue () && + type == ContentType.APPLICATION_DATA; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write (int b) throws IOException + { + write (new byte[] { (byte) b }); + } + + public void write (byte[] buf) throws IOException + { + write (buf, 0, buf.length); + } + + public void write (byte[] buf, int off, int len) throws IOException + { + if (off < 0 || len < 0 || off + len > buf.length) + { + throw new ArrayIndexOutOfBoundsException ("size=" + buf.length + + " off=" + off + " len=" + len); + } + + int count = 0; + int len2 = 0; + do + { + if (emitEmpty) + { + byte[] fragment = params.encrypt (ZERO, 0, 0, type); + if (DEBUG_RECORD_LAYER) + { + logger.log (Component.SSL_RECORD_LAYER, + ">> WRITING RECORD <<{4}" + + "struct {{4}" + + " type = {0};{4}" + + " version = {1};{4}" + + " length = {2};{4}" + + "{3}{4}" + + "} TLSCiphertext;", new Object[] + { + type, params.getVersion (), new Integer (fragment.length), + Util.hexDump (fragment, " "), + SystemProperties.getProperty ("line.separator") + }); + } + out.write (type.getValue()); + params.getVersion().write (out); + out.write ((fragment.length >>> 8) & 0xFF); + out.write ( fragment.length & 0xFF); + out.write (fragment); + out.flush (); + } + len2 = Math.min (len - count, params.getFragmentLength()); + if (DEBUG_RECORD_LAYER) + { + logger.log (Component.SSL_RECORD_LAYER, + "writing chunk size={0}", new Integer (len2)); + } + synchronized (out) + { + byte[] fragment = params.encrypt (buf, off + count, len2, type); + if (DEBUG_RECORD_LAYER) + { + logger.log (Component.SSL_RECORD_LAYER, + ">> WRITING RECORD <<{4}" + + "struct {{4}" + + " type = {0};{4}" + + " version = {1};{4}" + + " length = {2};{4}" + + "{3}{4}" + + "} TLSCiphertext;", new Object[] + { + type, params.getVersion (), new Integer (fragment.length), + Util.hexDump (fragment, " "), + SystemProperties.getProperty ("line.separator") + }); + } + out.write (type.getValue()); + params.getVersion().write (out); + out.write ((fragment.length >>> 8) & 0xFF); + out.write ( fragment.length & 0xFF); + out.write (fragment); + out.flush (); + } + count += len2; + } + while (count < len); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/RecordingInputStream.java b/libjava/classpath/gnu/javax/net/ssl/provider/RecordingInputStream.java new file mode 100644 index 00000000000..d81b652d516 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/RecordingInputStream.java @@ -0,0 +1,131 @@ +/* RecordingInputStream.java -- Input stream that records data. + Copyright (C) 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.net.ssl.provider; + +import java.io.ByteArrayOutputStream; +import java.io.FilterInputStream; +import java.io.InputStream; +import java.io.IOException; + +/** + * A filter input stream that records every byte read from the underlying + * input stream. This class is useful for protocols that require portions + * of the communication to be saved, such as the handshake and key + * derivation in SSL. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +class RecordingInputStream extends FilterInputStream +{ + + // Fields. + // ------------------------------------------------------------------------- + + protected ByteArrayOutputStream sink; + + // Constructors. + // ------------------------------------------------------------------------- + + RecordingInputStream(InputStream in) + { + this(in, new ByteArrayOutputStream()); + } + + RecordingInputStream(InputStream in, ByteArrayOutputStream sink) + { + super(in); + this.sink = sink; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public synchronized int read() throws IOException + { + int i = in.read(); + sink.write(i); + return i; + } + + public synchronized int read(byte[] buf, int off, int len) throws IOException + { + int l = in.read(buf, off, len); + sink.write(buf, off, l); + return l; + } + + public synchronized int read(byte[] buf) throws IOException + { + return read(buf, 0, buf.length); + } + + public synchronized long skip(long len) throws IOException + { + long l = 0; + int i = 0; + byte[] buf = new byte[1024]; + while (l < len) + { + i = read(buf, 0, (int) Math.min((long) buf.length, len - l)); + if (i == -1) + break; + l += i; + } + return l; + } + + /** + * Returns all bytes recorded after this instance was created, or the last + * call to {@link resetSink()}. + * + * @return The recorded bytes. + */ + byte[] getBytes() + { + return sink.toByteArray(); + } + + /** + * Clears the recording buffer off all previously-recorded bytes. + */ + void resetSink() + { + sink.reset(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java b/libjava/classpath/gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java new file mode 100644 index 00000000000..5822afe0596 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java @@ -0,0 +1,225 @@ +/* SRPTrustManagerFactory.java -- trust manager for SRP. + Copyright (C) 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.net.ssl.provider; + +import java.io.IOException; +import java.math.BigInteger; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyPair; +import java.security.KeyStore; +import java.security.Security; + +import java.util.HashMap; + +import javax.net.ssl.ManagerFactoryParameters; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactorySpi; + +import gnu.java.security.key.IKeyPairGenerator; +import gnu.javax.crypto.key.srp6.SRPKeyPairGenerator; +import gnu.javax.crypto.sasl.srp.PasswordFile; +import gnu.javax.crypto.sasl.srp.SRP; + +import gnu.javax.net.ssl.SRPManagerParameters; +import gnu.javax.net.ssl.SRPTrustManager; + +/** + * This is an implementation of a {@link javax.net.ssl.TrustManagerFactory} + * engine for the ``SRP'' algorithm. You must initialize instances of this + * algorithm with {@link SRPManagerParameters}. + */ +public class SRPTrustManagerFactory extends TrustManagerFactorySpi +{ + + // Field. + // ------------------------------------------------------------------------- + + private Manager current; + + // Constructor. + // ------------------------------------------------------------------------- + + public SRPTrustManagerFactory() + { + super(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + protected TrustManager[] engineGetTrustManagers() + { + if (current == null) + throw new IllegalStateException("not initialized"); + return new TrustManager[] { current }; + } + + protected void engineInit(KeyStore ks) + { + throw new IllegalArgumentException("only accepts SRPManagerParameters"); + } + + protected void engineInit(ManagerFactoryParameters params) + throws InvalidAlgorithmParameterException + { + if (params == null) + { + try + { + String srpPasswd = Util.getSecurityProperty("jessie.srp.password.file"); + if (srpPasswd == null) + { + current = new Manager(new PasswordFile()); + return; + } + String srpPasswd2 = Util.getSecurityProperty("jessie.srp.password.file2"); + if (srpPasswd2 == null) + srpPasswd2 = srpPasswd + "2"; + String srpConfig = Util.getSecurityProperty("jessie.srp.config"); + if (srpConfig == null) + srpConfig = srpPasswd + ".conf"; + current = new Manager(new PasswordFile(srpPasswd, srpPasswd2, srpConfig)); + return; + } + catch (IOException ioe) + { + throw new InvalidAlgorithmParameterException("default initialization failed: " + + ioe.toString()); + } + } + if (params instanceof SRPManagerParameters) + { + current = new Manager(((SRPManagerParameters) params).getPasswordFile()); + return; + } + throw new InvalidAlgorithmParameterException(); + } + + // Inner class. + // ------------------------------------------------------------------------- + + private class Manager implements SRPTrustManager + { + + // Field. + // ----------------------------------------------------------------------- + + private final PasswordFile file; + + // Constructor. + // ----------------------------------------------------------------------- + + Manager(PasswordFile file) + { + this.file = file; + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public boolean contains(String user) + { + try + { + return file.contains(user); + } + catch (IOException ioe) { } + return false; + } + + public KeyPair getKeyPair(String user) + { + try + { + if (file.contains(user)) + { + SRP srp = SRP.instance("SHA"); + String[] ent = file.lookup(user, "SHA"); + String[] cnf = file.lookupConfig(ent[2]); + BigInteger v, N, g; + v = new BigInteger(1, gnu.java.security.util.Util.fromBase64(ent[0])); + N = new BigInteger(1, gnu.java.security.util.Util.fromBase64(cnf[0])); + g = new BigInteger(1, gnu.java.security.util.Util.fromBase64(cnf[1])); + IKeyPairGenerator kpg = new SRPKeyPairGenerator(); + HashMap attr = new HashMap(); + attr.put(SRPKeyPairGenerator.SHARED_MODULUS, N); + attr.put(SRPKeyPairGenerator.GENERATOR, g); + attr.put(SRPKeyPairGenerator.USER_VERIFIER, v); + kpg.setup(attr); + return kpg.generate(); + } + } + catch (IOException ioe) { } + return null; + } + + public byte[] getSalt(String user) + { + try + { + if (file.contains(user)) + { + return gnu.java.security.util.Util.fromBase64(file.lookup(user, "SHA")[1]); + } + } + catch (IOException ioe) { } + return null; + } + + public BigInteger getVerifier(String user) + { + try + { + if (file.contains(user)) + { + return new BigInteger(1, + gnu.java.security.util.Util.fromBase64(file.lookup(user, "SHA")[0])); + } + } + catch (IOException ioe) { } + return null; + } + + public PasswordFile getPasswordFile() + { + return file; + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLHMac.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLHMac.java new file mode 100644 index 00000000000..002b3077fcb --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLHMac.java @@ -0,0 +1,158 @@ +/* SSLHMac.java -- SSLv3's MAC algorithm. + Copyright (C) 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.net.ssl.provider; + +import java.util.Arrays; +import java.util.Map; + +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.javax.crypto.mac.IMac; + +/** + * The MAC function in SSLv3. This mac is defined as: + * + * <pre> + * hash(MAC_write_secret, pad_2 + + * hash(MAC_write_secret + pad_1 + data));</pre> + * + * <p><tt>hash</tt> is e.g. MD5 or SHA-1, <tt>pad_1</tt> is the value + * 0x36 48 times for MD5 and 40 times for SHA-1, and <tt>pad_2</tt> is + * the value 0x5c repeated similarly. + */ +class SSLHMac implements IMac, Cloneable +{ + + // Fields. + // ------------------------------------------------------------------------- + + static final byte PAD1 = 0x36; + static final byte PAD2 = 0x5c; + + protected IMessageDigest md; + protected byte[] key; + protected final byte[] pad1, pad2; + + // Constructors. + // ------------------------------------------------------------------------- + + SSLHMac(String mdName) + { + super(); + this.md = HashFactory.getInstance(mdName); + if (mdName.equalsIgnoreCase("MD5")) + { + pad1 = new byte[48]; + pad2 = new byte[48]; + } + else + { + pad1 = new byte[40]; + pad2 = new byte[40]; + } + Arrays.fill(pad1, PAD1); + Arrays.fill(pad2, PAD2); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException cnse) + { + throw new Error(); + } + } + + public String name() + { + return "SSLHMac-" + md.name(); + } + + public int macSize() + { + return md.hashSize(); + } + + public void init(Map attributes) + { + key = (byte[]) attributes.get(MAC_KEY_MATERIAL); + if (key == null) + throw new NullPointerException(); + reset(); + } + + public void reset() + { + md.reset(); + md.update(key, 0, key.length); + md.update(pad1, 0, pad1.length); + } + + public byte[] digest() + { + byte[] h1 = md.digest(); + md.update(key, 0, key.length); + md.update(pad2, 0, pad2.length); + md.update(h1, 0, h1.length); + byte[] result = md.digest(); + reset(); + return result; + } + + public void update(byte b) + { + md.update(b); + } + + public void update(byte[] buf, int off, int len) + { + md.update(buf, off, len); + } + + public boolean selfTest() + { + return true; // XXX + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLRSASignature.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLRSASignature.java new file mode 100644 index 00000000000..2f8c6cfe665 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLRSASignature.java @@ -0,0 +1,235 @@ +/* SSLRSASignature.java -- SSL's RSA signature algorithm. + Copyright (C) 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.net.ssl.provider; + +import java.math.BigInteger; + +import java.security.InvalidKeyException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +import java.util.Arrays; +import java.util.Map; + +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.sig.ISignature; +import gnu.java.security.sig.rsa.RSA; + +/** + * The RSA signature algorithm as used in the SSL protocol. Note that this + * is different from the RSA signature used to verify certificates. + * + * <p>This signature scheme works as follows:</p> + * + * <blockquote><p><pre>digitally-signed struct { + * opaque md5_hash[16]; + * opaque sha_hash[20]; + * }</pre></p></blockquote> + * + * <p>Where a <code>digitally-signed struct</code> is RSA-encrypted with + * block type 0 or 1 according to PKCS #1, version 1.5.</p> + */ +final class SSLRSASignature implements ISignature +{ + + // Fields. + // ------------------------------------------------------------------------- + + private RSAPublicKey pubkey; + private RSAPrivateKey privkey; + private final IMessageDigest md5, sha; + private boolean initVerify = false, initSign = false; + + // Constructor. + // ------------------------------------------------------------------------- + + SSLRSASignature() + { + this(HashFactory.getInstance("MD5"), HashFactory.getInstance("SHA-1")); + } + + SSLRSASignature(IMessageDigest md5, IMessageDigest sha) + { + this.md5 = md5; + this.sha = sha; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String name() + { + return "RSA/SSL"; + } + + public void setupVerify(Map attrib) + { + PublicKey key = (PublicKey) attrib.get(VERIFIER_KEY); + if (key == null) + { + if (initSign) + { + return; // re-use. + } + throw new IllegalArgumentException("no key supplied"); + } + if (!(key instanceof RSAPublicKey)) + { + throw new IllegalArgumentException("not an RSA key"); + } + pubkey = (RSAPublicKey) key; + privkey = null; + initSign = false; + initVerify = true; + } + + public void setupSign(Map attrib) + { + PrivateKey key = (PrivateKey) attrib.get(SIGNER_KEY); + if (key == null) + { + if (initVerify) + { + return; // re-use. + } + throw new IllegalArgumentException("no key supplied"); + } + if (!(key instanceof RSAPrivateKey)) + { + throw new IllegalArgumentException("not an RSA key"); + } + privkey = (RSAPrivateKey) key; + pubkey = null; + initVerify = false; + initSign = true; + } + + public void update(byte b) + { + if (!initVerify && !initSign) + { + throw new IllegalStateException(); + } + md5.update(b); + sha.update(b); + } + + public void update(byte[] buf, int off, int len) + { + if (!initVerify && !initSign) + { + throw new IllegalStateException(); + } + md5.update(buf, off, len); + sha.update(buf, off, len); + } + + public Object sign() + { + if (!initSign) + { + throw new IllegalStateException(); + } + // Pad the hash results with RSA block type 1. + final int k = (privkey.getModulus().bitLength() + 7) >>> 3; + final byte[] d = Util.concat(md5.digest(), sha.digest()); + if (k - 11 < d.length) + { + throw new IllegalArgumentException("message too long"); + } + final byte[] eb = new byte[k]; + eb[0] = 0x00; + eb[1] = 0x01; + for (int i = 2; i < k - d.length - 1; i++) + { + eb[i] = (byte) 0xFF; + } + System.arraycopy(d, 0, eb, k - d.length, d.length); + BigInteger EB = new BigInteger(eb); + + // Private-key encrypt the padded hashes. + BigInteger EM = RSA.sign(privkey, EB); + return Util.trim(EM); + } + + public boolean verify(Object signature) + { + if (!initVerify) + { + throw new IllegalStateException(); + } + // Public-key decrypt the signature representative. + BigInteger EM = new BigInteger(1, (byte[]) signature); + BigInteger EB = RSA.verify(pubkey, EM); + + // Unpad the decrypted message. + int i = 0; + final byte[] eb = EB.toByteArray(); + if (eb[0] == 0x00) + { + for (i = 0; i < eb.length && eb[i] == 0x00; i++); + } + else if (eb[0] == 0x01) + { + for (i = 1; i < eb.length && eb[i] != 0x00; i++) + { + if (eb[i] != (byte) 0xFF) + { + throw new IllegalArgumentException("bad padding"); + } + } + i++; + } + else + { + throw new IllegalArgumentException("decryption failed"); + } + byte[] d1 = Util.trim(eb, i, eb.length - i); + byte[] d2 = Util.concat(md5.digest(), sha.digest()); + return Arrays.equals(d1, d2); + } + + public Object clone() + { + throw new UnsupportedOperationException(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLRandom.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLRandom.java new file mode 100644 index 00000000000..0b28f1044a7 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLRandom.java @@ -0,0 +1,165 @@ +/* SSLRandom.java -- SSLv3 pseudo-random function. + Copyright (C) 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.net.ssl.provider; + +import java.util.Map; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; + +class SSLRandom implements IRandom +{ + + // Fields. + // ------------------------------------------------------------------------- + + static final String SECRET = "jessie.sslprng.secret"; + static final String SEED = "jessie.sslprng.seed"; + + private final IMessageDigest md5, sha; + private byte[] secret; + private byte[] buffer; + private byte pad; + private byte[] seed; + private int idx; + + // Constructor. + // ------------------------------------------------------------------------- + + SSLRandom() + { + md5 = HashFactory.getInstance("MD5"); + sha = HashFactory.getInstance("SHA-1"); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void init(Map attrib) + { + secret = (byte[]) attrib.get(SECRET); + seed = (byte[]) attrib.get(SEED); + + if (secret == null || seed == null) + throw new NullPointerException(); + + pad = (byte) 'A'; + try { buffer = nextBlock(); } + catch (LimitReachedException cantHappen) { } + } + + public String name() + { + return "SSLRandom"; + } + + public Object clone() + { + throw new UnsupportedOperationException(); + } + + public byte nextByte() throws LimitReachedException + { + if (buffer == null) + throw new IllegalStateException(); + if (idx >= buffer.length) + buffer = nextBlock(); + return buffer[idx++]; + } + + public void nextBytes(byte[] buf, int off, int len) + throws LimitReachedException + { + if (buffer == null) + throw new IllegalStateException(); + if (buf == null) + throw new NullPointerException(); + if (off < 0 || len < 0 || off+len > buf.length) + throw new IndexOutOfBoundsException(); + int count = 0; + while (count < len) + { + if (idx >= buffer.length) + buffer = nextBlock(); + int l = Math.min(buffer.length-idx, len-count); + System.arraycopy(buffer, idx, buf, off+count, l); + count += l; + idx += l; + } + } + + public boolean selfTest() + { + return true; // XXX + } + + // For future versions of GNU Crypto. No-ops. + public void addRandomByte (byte b) + { + } + + public void addRandomBytes(byte[] buffer) { + addRandomBytes(buffer, 0, buffer.length); + } + + public void addRandomBytes (byte[] b, int i, int j) + { + } + + // Own methods. + // ------------------------------------------------------------------------- + + private byte[] nextBlock() throws LimitReachedException + { + int count = pad - 'A' + 1; + if (count > 26) + throw new LimitReachedException(); + for (int i = 0; i < count; i++) + sha.update(pad); + sha.update(secret, 0, secret.length); + sha.update(seed, 0, seed.length); + byte[] b = sha.digest(); + md5.update(secret, 0, secret.length); + md5.update(b, 0, b.length); + idx = 0; + pad++; + return md5.digest(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocket.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocket.java new file mode 100644 index 00000000000..ee96b8d1bdf --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocket.java @@ -0,0 +1,283 @@ +/* SSLServerSocket.java -- SSL server socket. + Copyright (C) 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.net.ssl.provider; + +import java.io.IOException; + +import java.net.InetAddress; +import java.net.Socket; + +import java.security.SecureRandom; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.SortedSet; +import java.util.TreeSet; + +import javax.net.ssl.X509KeyManager; +import javax.net.ssl.X509TrustManager; + +import gnu.javax.net.ssl.SRPTrustManager; + +class SSLServerSocket extends javax.net.ssl.SSLServerSocket +{ + + // Fields. + // ------------------------------------------------------------------------- + + private SessionContext sessions; + private SortedSet enabledProtocols = new TreeSet(SSLSocket.supportedProtocols); + private List enabledSuites = new ArrayList(SSLSocket.supportedSuites); + private boolean clientMode = false; + private boolean needClientAuth = false; + private boolean wantClientAuth = false; + private boolean createSessions = true; + private SRPTrustManager srpTrustManager; + private X509TrustManager trustManager; + private X509KeyManager keyManager; + private SecureRandom random; + + // Constructors. + // ------------------------------------------------------------------------- + + SSLServerSocket() throws IOException + { + super(); + } + + SSLServerSocket(int port) throws IOException + { + super(port); + } + + SSLServerSocket(int port, int backlog) throws IOException + { + super(port, backlog); + } + + SSLServerSocket(int port, int backlog, InetAddress address) + throws IOException + { + super(port, backlog, address); + } + + // SSL methods. + // ------------------------------------------------------------------------- + + public String[] getSupportedCipherSuites() + { + return (String[]) CipherSuite.availableSuiteNames().toArray(new String[0]); + } + + public String[] getEnabledCipherSuites() + { + synchronized (enabledSuites) + { + String[] s = new String[enabledSuites.size()]; + int i = 0; + for (Iterator it = enabledSuites.iterator(); it.hasNext(); ) + s[i++] = it.next().toString(); + return s; + } + } + + public void setEnabledCipherSuites(String[] suites) + { + if (suites == null || suites.length == 0) + throw new IllegalArgumentException(); + for (int i = 0; i < suites.length; i++) + if (CipherSuite.forName(suites[i]) == null) + throw new IllegalArgumentException("unsupported suite: " + + suites[i]); + synchronized (enabledSuites) + { + enabledSuites.clear(); + for (int i = 0; i < suites.length; i++) + { + CipherSuite suite = CipherSuite.forName(suites[i]); + if (!enabledSuites.contains(suite)) + enabledSuites.add(suite); + } + } + } + + public String[] getSupportedProtocols() + { + return new String[] { "SSLv3", "TLSv1", "TLSv1.1" }; + } + + public String[] getEnabledProtocols() + { + synchronized (enabledProtocols) + { + String[] s = new String[enabledProtocols.size()]; + int i = 0; + for (Iterator it = enabledProtocols.iterator(); it.hasNext(); ) + s[i++] = it.next().toString(); + return s; + } + } + + public void setEnabledProtocols(String[] protocols) + { + if (protocols == null || protocols.length == 0) + throw new IllegalArgumentException(); + for (int i = 0; i < protocols.length; i++) + { + if (!(protocols[i].equalsIgnoreCase("SSLv3") || + protocols[i].equalsIgnoreCase("TLSv1") || + protocols[i].equalsIgnoreCase("TLSv1.1"))) + { + throw new + IllegalArgumentException("unsupported protocol: " + + protocols[i]); + } + } + synchronized (enabledProtocols) + { + enabledProtocols.clear(); + for (int i = 0; i < protocols.length; i++) + { + if (protocols[i].equalsIgnoreCase("SSLv3")) + enabledProtocols.add(ProtocolVersion.SSL_3); + else if (protocols[i].equalsIgnoreCase("TLSv1")) + enabledProtocols.add(ProtocolVersion.TLS_1); + else + enabledProtocols.add(ProtocolVersion.TLS_1_1); + } + } + } + + public void setUseClientMode(boolean clientMode) + { + this.clientMode = clientMode; + } + + public boolean getUseClientMode() + { + return clientMode; + } + + public void setNeedClientAuth(boolean needClientAuth) + { + this.needClientAuth = needClientAuth; + } + + public boolean getNeedClientAuth() + { + return needClientAuth; + } + + public void setWantClientAuth(boolean wantClientAuth) + { + this.wantClientAuth = wantClientAuth; + } + + public boolean getWantClientAuth() + { + return wantClientAuth; + } + + // I misspelled this method in javax.net.SSLServerSocket, and that version + // made it into kaffe 1.1.4. + public void setEnabledSessionCreation(boolean createSessions) + { + setEnableSessionCreation(createSessions); + } + + public void setEnableSessionCreation(boolean createSessions) + { + this.createSessions = createSessions; + } + + public boolean getEnableSessionCreation() + { + return createSessions; + } + + // Socket methods. + // ------------------------------------------------------------------------- + + public Socket accept() throws IOException + { + SSLSocket socket = new SSLSocket(); + implAccept(socket); + socket.setUseClientMode(clientMode); + socket.setNeedClientAuth(needClientAuth); + socket.setWantClientAuth(wantClientAuth); + socket.setEnableSessionCreation(createSessions); + socket.setSessionContext(sessions); + socket.setEnabledCipherSuites(new ArrayList(enabledSuites)); + socket.setEnabledProtocols(new TreeSet(enabledProtocols)); + socket.setSRPTrustManager(srpTrustManager); + socket.setTrustManager(trustManager); + socket.setKeyManager(keyManager); + socket.setRandom(random); + return socket; + } + + // Package methods. + // ------------------------------------------------------------------------- + + void setSessionContext(SessionContext sessions) + { + this.sessions = sessions; + } + + void setKeyManager(X509KeyManager keyManager) + { + this.keyManager = keyManager; + } + + void setTrustManager(X509TrustManager trustManager) + { + this.trustManager = trustManager; + } + + void setSRPTrustManager(SRPTrustManager srpTrustManager) + { + this.srpTrustManager = srpTrustManager; + } + + void setRandom(SecureRandom random) + { + this.random = random; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketFactory.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketFactory.java new file mode 100644 index 00000000000..72fb512c582 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketFactory.java @@ -0,0 +1,136 @@ +/* SSLServerSocketFactory.java -- factory for SSL server sockets. + Copyright (C) 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.net.ssl.provider; + +import java.io.IOException; + +import java.net.InetAddress; +import java.net.ServerSocket; + +import java.security.SecureRandom; + +import javax.net.ssl.X509KeyManager; +import javax.net.ssl.X509TrustManager; + +import gnu.javax.net.ssl.SRPTrustManager; + +class SSLServerSocketFactory extends javax.net.ssl.SSLServerSocketFactory +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final SessionContext sessions; + private final X509KeyManager keyManager; + private final X509TrustManager trustManager; + private final SRPTrustManager srpTrustManager; + private final SecureRandom random; + + // Constructor. + // ------------------------------------------------------------------------- + + SSLServerSocketFactory(X509TrustManager trustManager, + SRPTrustManager srpTrustManager, + X509KeyManager keyManager, + SecureRandom random, + SessionContext sessions) + { + super(); + this.trustManager = trustManager; + this.srpTrustManager = srpTrustManager; + this.keyManager = keyManager; + this.random = random; + this.sessions = sessions; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String[] getDefaultCipherSuites() + { + return getSupportedCipherSuites(); + } + + public String[] getSupportedCipherSuites() + { + return (String[]) CipherSuite.availableSuiteNames().toArray(new String[0]); + } + + public ServerSocket createServerSocket() throws IOException + { + SSLServerSocket socket = new SSLServerSocket(); + setup(socket); + return socket; + } + + public ServerSocket createServerSocket(int port) throws IOException + { + SSLServerSocket socket = new SSLServerSocket(port); + setup(socket); + return socket; + } + + public ServerSocket createServerSocket(int port, int backlog) + throws IOException + { + SSLServerSocket socket = new SSLServerSocket(port, backlog); + setup(socket); + return socket; + } + + public ServerSocket createServerSocket(int port, int backlog, InetAddress addr) + throws IOException + { + SSLServerSocket socket = new SSLServerSocket(port, backlog, addr); + setup(socket); + return socket; + } + + // Own methods. + // ------------------------------------------------------------------------- + + private void setup(SSLServerSocket socket) + { + socket.setSessionContext(sessions); + socket.setKeyManager(keyManager); + socket.setTrustManager(trustManager); + socket.setSRPTrustManager(srpTrustManager); + socket.setRandom(random); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocket.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocket.java new file mode 100644 index 00000000000..a564659c02c --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocket.java @@ -0,0 +1,3530 @@ +/* SSLSocket.java -- the SSL socket class. + Copyright (C) 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.net.ssl.provider; + +import java.io.BufferedOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; + +import java.math.BigInteger; + +import java.net.InetAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketException; + +import java.nio.channels.SocketChannel; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Principal; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Security; +import java.security.SecureRandom; +import java.security.cert.X509Certificate; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.DSAPublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.SortedSet; +import java.util.TreeSet; + +import java.util.logging.Logger; + +import javax.crypto.Cipher; +import javax.crypto.Mac; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.interfaces.DHPublicKey; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import javax.net.ssl.HandshakeCompletedEvent; +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLProtocolException; +import javax.net.ssl.SSLSession; +import javax.net.ssl.X509KeyManager; +import javax.net.ssl.X509TrustManager; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.ConfirmationCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.TextInputCallback; + +import gnu.classpath.debug.Component; +import gnu.classpath.debug.SystemLogger; + +import gnu.java.security.Registry; +import gnu.javax.security.auth.callback.DefaultCallbackHandler; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.javax.crypto.key.IKeyAgreementParty; +import gnu.javax.crypto.key.KeyAgreementFactory; +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.OutgoingMessage; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.dh.DiffieHellmanKeyAgreement; +import gnu.javax.crypto.key.dh.ElGamalKeyAgreement; +import gnu.javax.crypto.key.dh.GnuDHPrivateKey; +import gnu.javax.crypto.key.dh.GnuDHPublicKey; +import gnu.javax.crypto.key.srp6.SRPPrivateKey; +import gnu.javax.crypto.key.srp6.SRPPublicKey; +import gnu.javax.crypto.key.srp6.SRP6KeyAgreement; +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.prng.ARCFour; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.javax.crypto.sasl.srp.SRPAuthInfoProvider; +import gnu.javax.crypto.sasl.srp.SRPRegistry; +import gnu.java.security.sig.ISignature; +import gnu.java.security.sig.SignatureFactory; +import gnu.java.security.sig.dss.DSSSignature; +import gnu.java.security.sig.rsa.EME_PKCS1_V1_5; +import gnu.java.security.sig.rsa.RSA; + +import gnu.javax.net.ssl.SRPTrustManager; + +/** + * This is the core of the Jessie SSL implementation; it implements the {@link + * javax.net.ssl.SSLSocket} for normal and "wrapped" sockets, and handles all + * protocols implemented by this library. + */ +final class SSLSocket extends javax.net.ssl.SSLSocket +{ + + // This class is almost unbearably large and complex, but is laid out + // as follows: + // + // 1. Fields. + // 2. Constructors. + // 3. SSLSocket methods. These are the public methods defined in + // javax.net.ssl.SSLSocket. + // 4. Socket methods. These override the public methods of java.net.Socket, + // and delegate the method call to either the underlying socket if this is + // a wrapped socket, or to the superclass. + // 5. Package-private methods that various pieces of Jessie use. + // 6. Private methods. These compose the SSL handshake. + // + // Each part is preceeded by a form feed. + +// Constants and fields. + // ------------------------------------------------------------------------- + + // Debuggery. + private static final boolean DEBUG_HANDSHAKE_LAYER = true; + private static final boolean DEBUG_KEY_EXCHANGE = false; + private static final Logger logger = SystemLogger.SYSTEM; + + // Fields for using this class as a wrapped socket. + private Socket underlyingSocket; + private int underlyingPort; + private boolean autoClose; + + // Cryptography fields. + SessionContext sessionContext; + Session session; + LinkedList handshakeListeners; + private boolean clientMode, wantClientAuth, needClientAuth, createSessions; + private boolean handshakeDone; + + // I/O fields. + private String remoteHost; + private InputStream socketIn; + private OutputStream socketOut; + private InputStream applicationIn; + private OutputStream applicationOut; + private InputStream handshakeIn; + private OutputStream handshakeOut; +// private ThreadGroup recordLayer; + RecordInput recordInput; +// RecordOutput recordOutput; + private long handshakeTime; + + private SocketChannel channel; + + static SortedSet supportedProtocols = new TreeSet(); + static List supportedSuites = new ArrayList(30); + +// Static initializer. + // ------------------------------------------------------------------------- + + static + { + //supportedProtocols.add(ProtocolVersion.TLS_1_1); + supportedProtocols.add(ProtocolVersion.TLS_1); + supportedProtocols.add(ProtocolVersion.SSL_3); + + // These are in preference order. It's my preference order, but I'm not + // a total idiot. + supportedSuites.add(CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_RSA_WITH_RC4_128_MD5); + supportedSuites.add(CipherSuite.TLS_RSA_WITH_RC4_128_SHA); + supportedSuites.add(CipherSuite.TLS_DHE_DSS_WITH_DES_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DHE_RSA_WITH_DES_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DH_DSS_WITH_DES_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DH_RSA_WITH_DES_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_RSA_WITH_DES_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_RSA_EXPORT_WITH_DES40_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_RSA_EXPORT_WITH_RC4_40_MD5); + supportedSuites.add(CipherSuite.TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_RSA_WITH_NULL_MD5); + supportedSuites.add(CipherSuite.TLS_RSA_WITH_NULL_SHA); + } + +// Constructors. + // ------------------------------------------------------------------------- + + SSLSocket(Socket socket, String host, int port, boolean autoClose) + throws IOException + { + underlyingSocket = socket; + remoteHost = host; + underlyingPort = port; + this.autoClose = autoClose; + initialize(); + } + + SSLSocket (Socket socket, SocketChannel channel) throws IOException + { + underlyingSocket = socket; + this.channel = channel; + initialize (); + } + + SSLSocket() throws IOException + { + super(); + initialize(); + } + + SSLSocket(InetAddress addr, int port) throws IOException + { + super(addr, port); + initialize(); + remoteHost = addr.getHostName(); + if (remoteHost == null) + { + remoteHost = addr.getHostAddress(); + } + } + + SSLSocket(InetAddress addr, int port, InetAddress laddr, int lport) + throws IOException + { + super(addr, port, laddr, lport); + initialize(); + remoteHost = addr.getHostName(); + if (remoteHost == null) + remoteHost = addr.getHostAddress(); + } + + SSLSocket(String host, int port) throws IOException + { + super(host, port); + initialize(); + remoteHost = host; + } + + SSLSocket(String host, int port, InetAddress laddr, int lport) + throws IOException + { + super(host, port, laddr, lport); + initialize(); + remoteHost = host; + } + + private void initialize() + { + session = new Session(); + session.enabledSuites = new ArrayList(supportedSuites); + session.enabledProtocols = new TreeSet(supportedProtocols); + session.protocol = ProtocolVersion.TLS_1; + session.params.setVersion (ProtocolVersion.TLS_1); + handshakeListeners = new LinkedList(); + handshakeDone = false; + } + +// SSL methods. + // ------------------------------------------------------------------------- + + public void addHandshakeCompletedListener(HandshakeCompletedListener l) + { + synchronized (handshakeListeners) + { + if (l == null) + throw new NullPointerException(); + if (!handshakeListeners.contains(l)) + handshakeListeners.add(l); + } + } + + public void removeHandshakeCompletedListener(HandshakeCompletedListener l) + { + synchronized (handshakeListeners) + { + handshakeListeners.remove(l); + } + } + + public String[] getEnabledProtocols() + { + synchronized (session.enabledProtocols) + { + try + { + return (String[]) Util.transform(session.enabledProtocols.toArray(), + String.class, "toString", null); + } + catch (Exception x) + { + RuntimeException re = new RuntimeException (x.getMessage()); + re.initCause (x); + throw re; + } + } + } + + public void setEnabledProtocols(String[] protocols) + { + if (protocols == null || protocols.length == 0) + throw new IllegalArgumentException(); + for (int i = 0; i < protocols.length; i++) + { + if (!(protocols[i].equalsIgnoreCase("SSLv3") || + protocols[i].equalsIgnoreCase("TLSv1") || + protocols[i].equalsIgnoreCase("TLSv1.1"))) + { + throw new + IllegalArgumentException("unsupported protocol: " + + protocols[i]); + } + } + synchronized (session.enabledProtocols) + { + session.enabledProtocols.clear(); + for (int i = 0; i < protocols.length; i++) + { + if (protocols[i].equalsIgnoreCase("SSLv3")) + { + session.enabledProtocols.add(ProtocolVersion.SSL_3); + } + else if (protocols[i].equalsIgnoreCase("TLSv1")) + { + session.enabledProtocols.add(ProtocolVersion.TLS_1); + } + else + { + session.enabledProtocols.add(ProtocolVersion.TLS_1_1); + } + } + } + } + + public String[] getSupportedProtocols() + { + return new String[] { /* "TLSv1.1", */ "TLSv1", "SSLv3" }; + } + + public String[] getEnabledCipherSuites() + { + synchronized (session.enabledSuites) + { + try + { + return (String[]) Util.transform(session.enabledSuites.toArray(), + String.class, "toString", null); + } + catch (Exception x) + { + RuntimeException re = new RuntimeException (x.getMessage()); + re.initCause (x); + throw re; + } + } + } + + public void setEnabledCipherSuites(String[] suites) + { + if (suites == null || suites.length == 0) + throw new IllegalArgumentException(); + for (int i = 0; i < suites.length; i++) + if (CipherSuite.forName(suites[i]) == null) + throw new IllegalArgumentException("unsupported suite: " + + suites[i]); + synchronized (session.enabledSuites) + { + session.enabledSuites.clear(); + for (int i = 0; i < suites.length; i++) + { + CipherSuite suite = CipherSuite.forName(suites[i]); + if (!session.enabledSuites.contains(suite)) + { + session.enabledSuites.add(suite); + } + } + } + } + + public String[] getSupportedCipherSuites() + { + return (String[]) CipherSuite.availableSuiteNames().toArray(new String[52]); + } + + public SSLSession getSession() + { + return session; + } + + public boolean getEnableSessionCreation() + { + return createSessions; + } + + public void setEnableSessionCreation(boolean flag) + { + createSessions = flag; + } + + public boolean getNeedClientAuth() + { + return needClientAuth; + } + + public void setNeedClientAuth(boolean flag) + { + needClientAuth = flag; + } + + public boolean getWantClientAuth() + { + return wantClientAuth; + } + + public void setWantClientAuth(boolean flag) + { + wantClientAuth = flag; + } + + public boolean getUseClientMode() + { + return clientMode; + } + + public void setUseClientMode(boolean flag) + { + this.clientMode = flag; + } + + public synchronized void startHandshake() throws IOException + { + if (DEBUG_HANDSHAKE_LAYER) + { + logger.log (Component.SSL_HANDSHAKE, "startHandshake called in {0}", + Thread.currentThread()); + handshakeTime = System.currentTimeMillis(); + } + if (handshakeDone) + { + if (clientMode) + { + handshakeDone = false; + doClientHandshake(); + } + else + { + Handshake req = new Handshake(Handshake.Type.HELLO_REQUEST, null); + req.write (handshakeOut, session.protocol); + handshakeOut.flush(); +// recordOutput.setHandshakeAvail(req.write(handshakeOut, session.protocol)); + } + return; + } + if (recordInput == null) + { + setupIO(); + } + if (clientMode) + { + doClientHandshake(); + } + else + { + doServerHandshake(); + } + } + +// Socket methods. + // ------------------------------------------------------------------------- + + public InetAddress getInetAddress() + { + if (underlyingSocket != null) + { + return underlyingSocket.getInetAddress(); + } + else + { + return super.getInetAddress(); + } + } + + public InetAddress getLocalAddress() + { + if (underlyingSocket != null) + { + return underlyingSocket.getLocalAddress(); + } + else + { + return super.getLocalAddress(); + } + } + + public int getPort() + { + if (underlyingSocket != null) + { + return underlyingSocket.getPort(); + } + else + { + return super.getPort(); + } + } + + public int getLocalPort() + { + if (underlyingSocket != null) + { + return underlyingSocket.getLocalPort(); + } + else + { + return super.getLocalPort(); + } + } + + public InputStream getInputStream() throws IOException + { + if (applicationIn == null) + { + setupIO(); + } + return applicationIn; + } + + public OutputStream getOutputStream() throws IOException + { + if (applicationOut == null) + { + setupIO(); + } + return applicationOut; + } + + public void setTcpNoDelay(boolean flag) throws SocketException + { + if (underlyingSocket != null) + { + underlyingSocket.setTcpNoDelay(flag); + } + else + { + super.setTcpNoDelay(flag); + } + } + + public boolean getTcpNoDelay() throws SocketException + { + if (underlyingSocket != null) + { + return underlyingSocket.getTcpNoDelay(); + } + else + { + return super.getTcpNoDelay(); + } + } + + public void setSoLinger(boolean flag, int linger) throws SocketException + { + if (underlyingSocket != null) + { + underlyingSocket.setSoLinger(flag, linger); + } + else + { + super.setSoLinger(flag, linger); + } + } + + public int getSoLinger() throws SocketException + { + if (underlyingSocket != null) + { + return underlyingSocket.getSoLinger(); + } + else + { + return super.getSoLinger(); + } + } + + public void sendUrgentData(int data) throws IOException + { + throw new UnsupportedOperationException("not implemented"); + } + + public void setSoTimeout(int timeout) throws SocketException + { + if (underlyingSocket != null) + { + underlyingSocket.setSoTimeout(timeout); + } + else + { + super.setSoTimeout(timeout); + } + } + + public int getSoTimeout() throws SocketException + { + if (underlyingSocket != null) + { + return underlyingSocket.getSoTimeout(); + } + else + { + return super.getSoTimeout(); + } + } + + public void setSendBufferSize(int size) throws SocketException + { + if (underlyingSocket != null) + { + underlyingSocket.setSendBufferSize(size); + } + else + { + super.setSendBufferSize(size); + } + } + + public int getSendBufferSize() throws SocketException + { + if (underlyingSocket != null) + { + return underlyingSocket.getSendBufferSize(); + } + else + { + return super.getSendBufferSize(); + } + } + + public void setReceiveBufferSize(int size) throws SocketException + { + if (underlyingSocket != null) + { + underlyingSocket.setReceiveBufferSize(size); + } + else + { + super.setReceiveBufferSize(size); + } + } + + public int getReceiveBufferSize() throws SocketException + { + if (underlyingSocket != null) + { + return underlyingSocket.getReceiveBufferSize(); + } + else + { + return super.getReceiveBufferSize(); + } + } + + public synchronized void close() throws IOException + { + if (recordInput == null) + { + if (underlyingSocket != null) + { + if (autoClose) + underlyingSocket.close(); + } + else + super.close(); + return; + } +// while (recordOutput.applicationDataPending()) Thread.yield(); + Alert close = new Alert (Alert.Level.WARNING, Alert.Description.CLOSE_NOTIFY); + sendAlert (close); + long wait = System.currentTimeMillis() + 60000L; + while (session.currentAlert == null && !recordInput.pollClose()) + { + + Thread.yield(); + if (wait <= System.currentTimeMillis()) + { + break; + } + } + boolean gotClose = session.currentAlert != null && + session.currentAlert.getDescription() == Alert.Description.CLOSE_NOTIFY; +// recordInput.setRunning(false); +// recordOutput.setRunning(false); +// recordLayer.interrupt(); + recordInput = null; +// recordOutput = null; +// recordLayer = null; + if (underlyingSocket != null) + { + if (autoClose) + underlyingSocket.close(); + } + else + super.close(); + if (!gotClose) + { + session.invalidate(); + throw new SSLException("did not receive close notify"); + } + } + + public String toString() + { + if (underlyingSocket != null) + { + return SSLSocket.class.getName() + " [ " + underlyingSocket + " ]"; + } + else + { + return SSLSocket.class.getName() + " [ " + super.toString() + " ]"; + } + } + + // Configuration insanity begins here. + + public void connect(SocketAddress saddr) throws IOException + { + if (underlyingSocket != null) + { + underlyingSocket.connect(saddr); + } + else + { + super.connect(saddr); + } + } + + public void connect(SocketAddress saddr, int timeout) throws IOException + { + if (underlyingSocket != null) + { + underlyingSocket.connect(saddr, timeout); + } + else + { + super.connect(saddr, timeout); + } + } + + public void bind(SocketAddress saddr) throws IOException + { + if (underlyingSocket != null) + { + underlyingSocket.bind(saddr); + } + else + { + super.bind(saddr); + } + } + + public SocketAddress getLocalSocketAddress() + { + if (underlyingSocket != null) + { + return underlyingSocket.getLocalSocketAddress(); + } + else + { + return super.getLocalSocketAddress(); + } + } + + public SocketChannel getChannel() + { + return channel; + } + + public boolean isBound() + { + if (underlyingSocket != null) + { + return underlyingSocket.isBound(); + } + else + { + return super.isBound(); + } + //throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public boolean isClosed() + { + if (underlyingSocket != null) + { + return underlyingSocket.isClosed(); + } + else + { + return super.isClosed(); + } + //throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + //public SocketAddress getRemoteSocketAddress() + //{ + // if (underlyingSocket != null) + // { + // return underlyingSocket.getRemoteSocketAddress(); + // } + // else + // { + // return super.getRemoteSocketAddress(); + // } + //} + + public void setOOBInline(boolean flag) throws SocketException + { + //if (underlyingSocket != null) + // { + // underlyingSocket.setOOBInline(flag); + // } + //else + // { + // super.setOOBInline(flag); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public boolean getOOBInline() throws SocketException + { + //if (underlyingSocket != null) + // { + // return underlyingSocket.getOOBInline(); + // } + //else + // { + // return super.getOOBInline(); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public void setKeepAlive(boolean flag) throws SocketException + { + //if (underlyingSocket != null) + // { + // underlyingSocket.setKeepAlive(flag); + // } + //else + // { + // super.setKeepAlive(flag); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public boolean getKeepAlive() throws SocketException + { + //if (underlyingSocket != null) + // { + // return underlyingSocket.getKeepAlive(); + // } + //else + // { + // return super.getKeepAlive(); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public void setTrafficClass(int clazz) throws SocketException + { + //if (underlyingSocket != null) + // { + // underlyingSocket.setTrafficClass(clazz); + // } + //else + // { + // super.setTrafficClass(clazz); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public int getTrafficClass() throws SocketException + { + //if (underlyingSocket != null) + // { + // return underlyingSocket.getTrafficClass(); + // } + //else + // { + // return super.getTrafficClass(); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public void setReuseAddress(boolean flag) throws SocketException + { + //if (underlyingSocket != null) + // { + // underlyingSocket.setReuseAddress(flag); + // } + //else + // { + // super.setReuseAddress(flag); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public boolean getReuseAddress() throws SocketException + { + //if (underlyingSocket != null) + // { + // return underlyingSocket.getReuseAddress(); + // } + //else + // { + // return super.getReuseAddress(); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public void shutdownInput() throws IOException + { + //if (underlyingSocket != null) + // { + // underlyingSocket.shutdownInput(); + // } + //else + // { + // super.shutdownInput(); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public void shutdownOutput() throws IOException + { + //if (underlyingSocket != null) + // { + // underlyingSocket.shutdownOutput(); + // } + //else + // { + // super.shutdownOutput(); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public boolean isConnected() + { + if (underlyingSocket != null) + { + return underlyingSocket.isConnected(); + } + else + { + return super.isConnected(); + } + //throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public boolean isInputShutdown() + { + //if (underlyingSocket != null) + // { + // return underlyingSocket.isInputShutdown(); + // } + //else + // { + // return super.isInputShutdown(); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public boolean isOutputShutdown() + { + //if (underlyingSocket != null) + // { + // return underlyingSocket.isOutputShutdown(); + // } + //else + // { + // return super.isOutputShutdown(); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + protected void finalize() + { + if (session.currentAlert == null) + { + try + { + close(); + } + catch (Exception ignore) { } + } + } + +// Package methods. + // ------------------------------------------------------------------------- + + void setSessionContext(SessionContext sessionContext) + { + this.sessionContext = sessionContext; + } + + void setEnabledCipherSuites(List suites) + { + session.enabledSuites = suites; + } + + void setEnabledProtocols(SortedSet protocols) + { + session.enabledProtocols = protocols; + } + + void setSRPTrustManager(SRPTrustManager srpTrustManager) + { + session.srpTrustManager = srpTrustManager; + } + + void setTrustManager(X509TrustManager trustManager) + { + session.trustManager = trustManager; + } + + void setKeyManager(X509KeyManager keyManager) + { + session.keyManager = keyManager; + } + + void setRandom(SecureRandom random) + { + session.random = random; + } + + void sendAlert (Alert alert) throws IOException + { + RecordOutputStream out = + new RecordOutputStream (socketOut, ContentType.ALERT, session.params); + out.write (alert.getEncoded ()); + } + + /** + * Gets the most-recently-received alert message. + * + * @return The alert message. + */ + Alert checkAlert() + { + return session.currentAlert; + } + + synchronized void checkHandshakeDone() throws IOException + { + if (!handshakeDone) + { + startHandshake(); + } + Alert alert = session.currentAlert; + if (alert != null && alert.getLevel() == Alert.Level.FATAL) + { + throw new AlertException(alert, false); + } + if (handshakeIn.available() > 0 && !clientMode) + { + handshakeDone = false; + startHandshake(); + } + } + +// Own methods. + // ------------------------------------------------------------------------- + + private static final byte[] SENDER_CLIENT = + new byte[] { 0x43, 0x4C, 0x4E, 0x54 }; + private static final byte[] SENDER_SERVER = + new byte[] { 0x53, 0x52, 0x56, 0x52 }; + + private void changeCipherSpec () throws IOException + { + RecordOutputStream out = + new RecordOutputStream (socketOut, ContentType.CHANGE_CIPHER_SPEC, session.params); + out.write (1); + } + + private void readChangeCipherSpec () throws IOException + { + RecordInputStream in = + new RecordInputStream (recordInput, ContentType.CHANGE_CIPHER_SPEC); + if (in.read() != 1) + { + throw new SSLProtocolException ("bad change cipher spec message"); + } + } + + /** + * Initializes the application data streams and starts the record layer + * threads. + */ + private synchronized void setupIO() throws IOException + { + if (recordInput != null) + { + return; + } + if (underlyingSocket != null) + { + socketIn = underlyingSocket.getInputStream(); + socketOut = underlyingSocket.getOutputStream(); + } + else + { + socketIn = super.getInputStream(); + socketOut = super.getOutputStream(); + } +// recordLayer = new ThreadGroup("record_layer"); +// recordInput = new RecordInput(in, session, recordLayer); +// recordOutput = new RecordOutput(out, session, recordLayer); +// recordInput.setRecordOutput(recordOutput); +// recordLayer.setDaemon(true); +// recordInput.start(); +// recordOutput.start(); + recordInput = new RecordInput (socketIn, session); + applicationIn = new SSLSocketInputStream( + new RecordInputStream (recordInput, ContentType.APPLICATION_DATA), this); + applicationOut = new SSLSocketOutputStream( + new RecordOutputStream (socketOut, ContentType.APPLICATION_DATA, session.params), this); + handshakeIn = new SSLSocketInputStream( + new RecordInputStream (recordInput, ContentType.HANDSHAKE), this, false); + handshakeOut = new BufferedOutputStream (new SSLSocketOutputStream( + new RecordOutputStream (socketOut, ContentType.HANDSHAKE, session.params), this, false), 8096); + } + + private void handshakeCompleted () + { + handshakeDone = true; + HandshakeCompletedEvent event = new HandshakeCompletedEvent (this, session); + for (Iterator it = handshakeListeners.iterator (); it.hasNext (); ) + { + try + { + ((HandshakeCompletedListener) it.next ()).handshakeCompleted (event); + } + catch (Throwable t) { } + } + if (createSessions) + { + synchronized (session) + { + sessionContext.addSession (session.sessionId, session); + session.access (); + } + } + + if (DEBUG_HANDSHAKE_LAYER) + { + logger.log (Component.SSL_HANDSHAKE, "Handshake finished in {0}", + Thread.currentThread()); + handshakeTime = System.currentTimeMillis() - handshakeTime; + logger.log (Component.SSL_HANDSHAKE, "Elapsed time {0}s", + new Long (handshakeTime / 1000)); + } + } + + /* + * Perform the client handshake. The process looks like this: + * + * ClientHello --> + * ServerHello <-- + * Certificate* <-- + * ServerKeyExchange* <-- + * CertificateRequest* <-- + * ServerHelloDone* <-- + * Certificate* --> + * ClientKeyExchange --> + * CertificateVerify* --> + * [ChangeCipherSpec] --> + * Finished --> + * [ChangeCipherSpec] <-- + * Finished <-- + * + * With --> denoting output and <-- denoting input. * denotes optional + * messages. + * + * Alternatively, this may be an abbreviated handshake if we are resuming + * a session: + * + * ClientHello --> + * ServerHello <-- + * [ChangeCipherSpec] <-- + * Finished <-- + * [ChangeCipherSpec] --> + * Finished --> + */ + private void doClientHandshake() throws IOException + { + if (DEBUG_HANDSHAKE_LAYER) + { + logger.log (Component.SSL_HANDSHAKE, "starting client handshake in {0}", + Thread.currentThread()); + } + + IMessageDigest md5 = HashFactory.getInstance(Registry.MD5_HASH); + IMessageDigest sha = HashFactory.getInstance(Registry.SHA160_HASH); + DigestInputStream din = new DigestInputStream(handshakeIn, md5, sha); + DigestOutputStream dout = new DigestOutputStream(handshakeOut, md5, sha); + Session continuedSession = null; + byte[] sessionId = new byte[0]; + List extensions = null; + String user = null; + CertificateType certType = CertificateType.X509; + + // Look through the available sessions to see if an appropriate one is + // available. + for (Enumeration e = sessionContext.getIds(); e.hasMoreElements(); ) + { + byte[] id = (byte[]) e.nextElement(); + continuedSession = (Session) sessionContext.getSession(id); + if (continuedSession == null) + { + continue; + } + if (!session.enabledProtocols.contains(continuedSession.protocol)) + { + continue; + } + if (continuedSession.getPeerHost().equals(remoteHost)) + { + sessionId = id; + break; + } + } + + // If a SRP suite is enabled, ask for a username so we can include it + // with our extensions list. + for (Iterator i = session.enabledSuites.iterator(); i.hasNext(); ) + { + CipherSuite s = (CipherSuite) i.next(); + if (s.getKeyExchange() == "SRP") + { + extensions = new LinkedList(); + user = askUserName(remoteHost); + byte[] b = user.getBytes("UTF-8"); + if (b.length > 255) + { + handshakeFailure(); + throw new SSLException("SRP username too long"); + } + extensions.add(new Extension(Extension.Type.SRP, + Util.concat(new byte[] { (byte) b.length }, b))); + + break; + } + } + + // If the jessie.fragment.length property is set, add the appropriate + // extension to the list. The fragment length is only actually set if + // the server responds with the same extension. + try + { + int flen = Integer.parseInt(Util.getSecurityProperty("jessie.fragment.length")); + byte[] ext = new byte[1]; + if (flen == 512) + ext[0] = 1; + else if (flen == 1024) + ext[0] = 2; + else if (flen == 2048) + ext[0] = 3; + else if (flen == 4096) + ext[0] = 4; + else + throw new NumberFormatException(); + if (extensions == null) + extensions = new LinkedList(); + extensions.add(new Extension(Extension.Type.MAX_FRAGMENT_LENGTH, ext)); + } + catch (NumberFormatException nfe) { } + + // FIXME: set certificate types. + + // Send the client hello. + ProtocolVersion version = session.protocol; + Random clientRandom = + new Random(Util.unixTime(), session.random.generateSeed(28)); + session.protocol = (ProtocolVersion) session.enabledProtocols.last(); + List comp = new ArrayList(2); + comp.add(CompressionMethod.ZLIB); + comp.add(CompressionMethod.NULL); + ClientHello clientHello = + new ClientHello(session.protocol, clientRandom, sessionId, + session.enabledSuites, comp, extensions); + Handshake msg = new Handshake(Handshake.Type.CLIENT_HELLO, clientHello); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write (dout, version); +// recordOutput.setHandshakeAvail(msg.write(dout, version)); + dout.flush(); +// try +// { +// Thread.sleep(150); +// } +// catch (InterruptedException ie) +// { +// } + + // Receive the server hello. + msg = Handshake.read(din); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + if (msg.getType() != Handshake.Type.SERVER_HELLO) + { + throwUnexpectedMessage(); + } + ServerHello serverHello = (ServerHello) msg.getBody(); + Random serverRandom = serverHello.getRandom(); + version = serverHello.getVersion(); + + // If we don't directly support the server's protocol version, choose + // the highest one we support that is less than the server's version. + if (!session.enabledProtocols.contains(version)) + { + ProtocolVersion v1 = null, v2 = null; + for (Iterator it = session.enabledProtocols.iterator(); + it.hasNext(); ) + { + v1 = (ProtocolVersion) it.next(); + if (v1.compareTo(version) > 0) + break; + v2 = v1; + } + version = v1; + } + + // The server's version is either unsupported by us (unlikely) or the user + // has only enabled incompatible versions. + if (version == null) + { + Alert.Description desc = null; + if (serverHello.getVersion() == ProtocolVersion.SSL_3) + { + desc = Alert.Description.HANDSHAKE_FAILURE; + } + else + { + desc = Alert.Description.PROTOCOL_VERSION; + } + Alert alert = new Alert(Alert.Level.FATAL, desc); + sendAlert(alert); + session.currentAlert = alert; + fatal(); + throw new AlertException(alert, true); + } + + if (serverHello.getExtensions() != null) + { + for (Iterator it = serverHello.getExtensions().iterator(); + it.hasNext(); ) + { + Extension e = (Extension) it.next(); + if (e.getType() == Extension.Type.MAX_FRAGMENT_LENGTH) + { + int len = Extensions.getMaxFragmentLength(e).intValue(); + session.params.setFragmentLength(len); +// recordOutput.setFragmentLength(len); +// recordInput.setFragmentLength(len); + } + else if (e.getType() == Extension.Type.CERT_TYPE) + { + certType = Extensions.getServerCertType(e); + } + } + } + + CipherSuite suite = serverHello.getCipherSuite().resolve(version); + boolean newSession = true; + if (sessionId.length > 0 && + Arrays.equals(sessionId, serverHello.getSessionId())) + { + SecurityParameters params = session.params; + SecureRandom random = session.random; + session = (Session) continuedSession.clone(); + session.params = params; + session.random = random; + recordInput.setSession(session); +// recordOutput.setSession(session); + suite = session.cipherSuite; + newSession = false; + } + else + { + sessionContext.removeSession(new Session.ID(sessionId)); + } + if (newSession) + { + session.peerHost = remoteHost; + session.sessionId = new Session.ID(serverHello.getSessionId()); + session.cipherSuite = suite; + } + session.params.reset(); +// session.params.setInMac(null); +// session.params.setOutMac(null); +// session.params.setInRandom(null); +// session.params.setOutRandom(null); +// session.params.setInCipher(null); +// session.params.setOutCipher(null); + session.currentAlert = null; + session.valid = true; + session.protocol = version; + + // If the server responded with the same session id that we sent, we + // assume that the session will be continued, and skip the bulk of the + // handshake. + if (newSession) + { + PublicKey serverKey = null, serverKex = null; + KeyPair clientKeys = null, clientKex = null; + CertificateRequest certReq; + boolean sendKeyExchange = false; + BigInteger srp_x = null; + IKeyAgreementParty clientKA = null; + IncomingMessage in; // used for key agreement protocol exchange + OutgoingMessage out = null; + + if (suite.getKeyExchange() == "SRP") + { + String password = askPassword(user); + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, + "SRP: password read is ''{0}''", password); + } + byte[] userSrpPassword = password.getBytes("UTF-8"); + + // instantiate and setup client-side key agreement party + clientKA = KeyAgreementFactory.getPartyAInstance(Registry.SRP_TLS_KA); + Map clientAttributes = new HashMap(); + clientAttributes.put(SRP6KeyAgreement.HASH_FUNCTION, + Registry.SHA160_HASH); + clientAttributes.put(SRP6KeyAgreement.USER_IDENTITY, user); + clientAttributes.put(SRP6KeyAgreement.USER_PASSWORD, userSrpPassword); + try + { + clientKA.init(clientAttributes); + // initiate the exchange + out = clientKA.processMessage(null); + } + catch (KeyAgreementException x) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x); + } + throwHandshakeFailure(); + } + } + + if (suite.getSignature() != "anon") + { + msg = Handshake.read(din, certType); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + if (msg.getType() != Handshake.Type.CERTIFICATE) + { + throwUnexpectedMessage(); + } + Certificate serverCertificate = (Certificate) msg.getBody(); + X509Certificate[] peerCerts = serverCertificate.getCertificates(); + try + { + session.trustManager.checkServerTrusted(peerCerts, + suite.getAuthType()); + if (suite.getSignature() == "RSA" && + !(peerCerts[0].getPublicKey() instanceof RSAPublicKey)) + throw new InvalidKeyException("improper public key"); + if (suite.getKeyExchange() == "DH" && + !(peerCerts[0].getPublicKey() instanceof DHPublicKey)) + throw new InvalidKeyException("improper public key"); + if (suite.getKeyExchange() == "DHE") + { + if (suite.getSignature() == "RSA" && + !(peerCerts[0].getPublicKey() instanceof RSAPublicKey)) + throw new InvalidKeyException("improper public key"); + if (suite.getSignature() == "DSS" && + !(peerCerts[0].getPublicKey() instanceof DSAPublicKey)) + throw new InvalidKeyException("improper public key"); + } + session.peerCerts = peerCerts; + session.peerVerified = true; + } + catch (InvalidKeyException ike) + { + throwHandshakeFailure(); + } + catch (Exception x) + { + if (!checkCertificates(peerCerts)) + { + peerUnverified(peerCerts); + SSLPeerUnverifiedException e = + new SSLPeerUnverifiedException ("could not verify peer certificate: "+ + peerCerts[0].getSubjectDN()); + e.initCause (x); + throw e; + } + session.peerCerts = peerCerts; + session.peerVerified = true; + } + serverKey = peerCerts[0].getPublicKey(); + serverKex = serverKey; + } + + msg = Handshake.read(din, suite, serverKey); + + // Receive the server's key exchange. + if (msg.getType() == Handshake.Type.SERVER_KEY_EXCHANGE) + { + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + ServerKeyExchange skex = (ServerKeyExchange) msg.getBody(); + serverKex = skex.getPublicKey(); + if (suite.getSignature() != "anon") + { + ISignature sig = null; + if (suite.getSignature() == "RSA") + { + sig = new SSLRSASignature(); + } + else if (suite.getSignature() == "DSS") + { + sig = SignatureFactory.getInstance(Registry.DSS_SIG); + } + sig.setupVerify(Collections.singletonMap( + ISignature.VERIFIER_KEY, serverKey)); + byte[] buf = clientRandom.getEncoded(); + sig.update(buf, 0, buf.length); + buf = serverRandom.getEncoded(); + sig.update(buf, 0, buf.length); + if (suite.getKeyExchange() == "RSA") + { + updateSig(sig, ((RSAPublicKey) serverKex).getModulus()); + updateSig(sig, ((RSAPublicKey) serverKex).getPublicExponent()); + } + else if (suite.getKeyExchange() == "DHE") + { + updateSig(sig, ((DHPublicKey) serverKex).getParams().getP()); + updateSig(sig, ((DHPublicKey) serverKex).getParams().getG()); + updateSig(sig, ((DHPublicKey) serverKex).getY()); + } + else if (suite.getKeyExchange() == "SRP") + { + updateSig(sig, ((SRPPublicKey) serverKex).getN()); + updateSig(sig, ((SRPPublicKey) serverKex).getG()); + byte[] srpSalt = skex.getSRPSalt(); + sig.update((byte) srpSalt.length); + sig.update(srpSalt, 0, srpSalt.length); + updateSig(sig, ((SRPPublicKey) serverKex).getY()); + } + if (!sig.verify(skex.getSignature().getSigValue())) + { + throwHandshakeFailure(); + } + } + + if (suite.getKeyExchange() == "SRP") + { + // use server's key exchange data to continue + // agreement protocol by faking a received incoming + // message. again the following code can be broken + // into multiple blocks for more accurate exception + // handling + try + { + out = new OutgoingMessage(); + out.writeMPI(((SRPPublicKey) serverKex).getN()); + out.writeMPI(((SRPPublicKey) serverKex).getG()); + out.writeMPI(new BigInteger(1, skex.getSRPSalt())); + out.writeMPI(((SRPPublicKey) serverKex).getY()); + + in = new IncomingMessage(out.toByteArray()); + + out = clientKA.processMessage(in); + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "clientKA isComplete? {0}", + Boolean.valueOf (clientKA.isComplete())); + } + } + catch (KeyAgreementException x) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x); + } + throwHandshakeFailure(); + } + } + msg = Handshake.read(din, suite, serverKey); + } + + // See if the server wants us to send our certificates. + certReq = null; + if (msg.getType() == Handshake.Type.CERTIFICATE_REQUEST) + { + if (suite.getSignature() == "anon") + { + throwHandshakeFailure(); + } + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + certReq = (CertificateRequest) msg.getBody(); + msg = Handshake.read(din); + } + + // Read ServerHelloDone. + if (msg.getType() != Handshake.Type.SERVER_HELLO_DONE) + { + throwUnexpectedMessage(); + } + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + + // Send our certificate chain if the server asked for it. + if (certReq != null) + { + String alias = session.keyManager.chooseClientAlias( + certReq.getTypeStrings(), certReq.getAuthorities(), null); + if (alias == null && version == ProtocolVersion.SSL_3) + { + Alert alert = + new Alert(Alert.Level.WARNING, Alert.Description.NO_CERTIFICATE); + sendAlert(alert); + } + else + { + X509Certificate[] chain = + session.keyManager.getCertificateChain(alias); + PrivateKey key = session.keyManager.getPrivateKey(alias); + if (chain == null) + { + chain = new X509Certificate[0]; + } + Certificate cert = new Certificate(chain); + msg = new Handshake(Handshake.Type.CERTIFICATE, cert); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write(dout, version); +// recordOutput.setHandshakeAvail(msg.write(dout, version));; + dout.flush(); + if (chain.length > 0) + { + session.localCerts = chain; + clientKeys = new KeyPair(chain[0].getPublicKey(), key); + } + } + } + + // Send our key exchange. + byte[] preMasterSecret = null; + ClientKeyExchange ckex = null; + if (suite.getKeyExchange() == "RSA") + { + ProtocolVersion v = + (ProtocolVersion) session.enabledProtocols.last(); + byte[] b = new byte[46]; + session.random.nextBytes (b); + preMasterSecret = Util.concat(v.getEncoded(), b); + EME_PKCS1_V1_5 pkcs1 = EME_PKCS1_V1_5.getInstance((RSAPublicKey) serverKex); + BigInteger bi = new BigInteger(1, + pkcs1.encode(preMasterSecret, session.random)); + bi = RSA.encrypt((RSAPublicKey) serverKex, bi); + ckex = new ClientKeyExchange(Util.trim(bi)); + } + else if (suite.getKeyExchange().startsWith("DH")) + { + if (clientKeys == null || + !(clientKeys.getPublic() instanceof DHPublicKey)) + { + GnuDHPrivateKey tmpKey = + new GnuDHPrivateKey(null, ((DHPublicKey) serverKex).getParams().getP(), + ((DHPublicKey) serverKex).getParams().getG(), null); + clientKA = KeyAgreementFactory.getPartyBInstance(Registry.DH_KA); + Map attr = new HashMap(); + attr.put(DiffieHellmanKeyAgreement.KA_DIFFIE_HELLMAN_OWNER_PRIVATE_KEY, + tmpKey); + attr.put(DiffieHellmanKeyAgreement.SOURCE_OF_RANDOMNESS, + session.random); + try + { + clientKA.init(attr); + out = new OutgoingMessage(); + out.writeMPI(((DHPublicKey) serverKex).getY()); + in = new IncomingMessage(out.toByteArray()); + out = clientKA.processMessage(in); + in = new IncomingMessage(out.toByteArray()); + ckex = new ClientKeyExchange(in.readMPI()); + } + catch (KeyAgreementException kae) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae); + } + internalError(); + RuntimeException re = new RuntimeException (kae.getMessage()); + re.initCause (kae); + throw re; + } + } + else + { + clientKA = KeyAgreementFactory.getPartyBInstance(Registry.ELGAMAL_KA); + Map attr = new HashMap(); + attr.put(ElGamalKeyAgreement.KA_ELGAMAL_RECIPIENT_PRIVATE_KEY, + clientKeys.getPrivate()); + try + { + // The key exchange is already complete here; our public + // value was sent with our certificate. + clientKA.init(attr); + } + catch (KeyAgreementException kae) + { + if (DEBUG_KEY_EXCHANGE) + logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae); + internalError(); + RuntimeException re = new RuntimeException (kae.getMessage()); + re.initCause (kae); + throw re; + } + ckex = new ClientKeyExchange(new byte[0]); + } + } + else if (suite.getKeyExchange() == "SRP") + { + // at this point, out --the outgoing message-- already contains + // what we want. so... + BigInteger A = null; + try + { + in = new IncomingMessage(out.toByteArray()); + A = in.readMPI(); + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "client A:{0}", A); + } + } + catch (KeyAgreementException x) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x); + } + throwHandshakeFailure(); + } + ckex = new ClientKeyExchange(A); + } + msg = new Handshake(Handshake.Type.CLIENT_KEY_EXCHANGE, ckex); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write (dout, version); +// recordOutput.setHandshakeAvail(msg.write(dout, version));; + + // Generate the master secret. + if (suite.getKeyExchange().startsWith("DH")) + { + try + { + preMasterSecret = clientKA.getSharedSecret(); + } + catch (KeyAgreementException kae) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae); + } + internalError(); + RuntimeException re = new RuntimeException (kae.getMessage()); + re.initCause (kae); + throw re; + } + } + else if (suite.getKeyExchange() == "SRP") + { + try + { + preMasterSecret = clientKA.getSharedSecret(); + } + catch (KeyAgreementException x) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x); + } + throwHandshakeFailure(); + } + finally + { + clientKA = null; + } + } + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "preMasterSecret:\n{0}", + Util.toHexString (preMasterSecret, ':')); + logger.log (Component.SSL_KEY_EXCHANGE, "client.random:\n{0}", + Util.toHexString(clientRandom.getEncoded(), ':')); + logger.log (Component.SSL_KEY_EXCHANGE, "server.random:\n{0}", + Util.toHexString(serverRandom.getEncoded(), ':')); + } + IRandom genSecret = null; + if (version == ProtocolVersion.SSL_3) + { + genSecret = new SSLRandom(); + HashMap attr = new HashMap(); + attr.put(SSLRandom.SECRET, preMasterSecret); + attr.put(SSLRandom.SEED, + Util.concat(clientRandom.getEncoded(), serverRandom.getEncoded())); + genSecret.init(attr); + } + else + { + genSecret = new TLSRandom(); + HashMap attr = new HashMap(); + attr.put(TLSRandom.SECRET, preMasterSecret); + attr.put(TLSRandom.SEED, + Util.concat(("master secret").getBytes("UTF-8"), + Util.concat(clientRandom.getEncoded(), serverRandom.getEncoded()))); + genSecret.init(attr); + } + session.masterSecret = new byte[48]; + try + { + genSecret.nextBytes(session.masterSecret, 0, 48); + for (int i = 0; i < preMasterSecret.length; i++) + { + preMasterSecret[i] = 0; + } + } + catch (LimitReachedException shouldNotHappen) + { + internalError(); + RuntimeException re = new RuntimeException (shouldNotHappen.getMessage()); + re.initCause (shouldNotHappen); + throw re; + } + + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "masterSecret: {0}", + Util.toHexString(session.masterSecret, ':')); + } + + // Send our certificate verify message. + if (certReq != null && clientKeys != null) + { + IMessageDigest vMD5 = (IMessageDigest) md5.clone(); + IMessageDigest vSHA = (IMessageDigest) sha.clone(); + PrivateKey key = clientKeys.getPrivate(); + Object sig = null; + String sigAlg = null; + try + { + if (key instanceof DSAPrivateKey) + { + sig = DSSSignature.sign((DSAPrivateKey) key, vSHA.digest(), + session.random); + sigAlg = "DSS"; + } + else if (key instanceof RSAPrivateKey) + { + SSLRSASignature rsa = new SSLRSASignature(vMD5, vSHA); + rsa.setupSign(Collections.singletonMap(ISignature.SIGNER_KEY, key)); + sig = rsa.sign(); + sigAlg = "RSA"; + } + else + { + throw new InvalidKeyException("no appropriate key"); + } + } + catch (Exception x) + { + throwHandshakeFailure(); + } + CertificateVerify verify = new CertificateVerify(sig, sigAlg); + msg = new Handshake(Handshake.Type.CERTIFICATE_VERIFY, verify); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write(dout, version); +// recordOutput.setHandshakeAvail(msg.write(dout, version));; + } + dout.flush(); + } + + byte[][] keys = null; + try + { + keys = generateKeys(serverRandom.getEncoded(), + clientRandom.getEncoded(), version); + } + catch (Exception x) + { + internalError(); + RuntimeException re = new RuntimeException (x.getMessage()); + re.initCause (x); + throw re; + } + + session.params.setVersion (version); + + // Initialize the algorithms with the derived keys. + Object readMac = null, writeMac = null; + Object readCipher = null, writeCipher = null; + try + { + if (session.params instanceof GNUSecurityParameters) + { + HashMap attr = new HashMap(); + writeMac = CipherSuite.getMac(suite.getMac()); + readMac = CipherSuite.getMac(suite.getMac()); + attr.put(IMac.MAC_KEY_MATERIAL, keys[0]); + ((IMac) writeMac).init(attr); + attr.put(IMac.MAC_KEY_MATERIAL, keys[1]); + ((IMac) readMac).init(attr); + if (suite.getCipher() == "RC4") + { + writeCipher = new ARCFour(); + readCipher = new ARCFour(); + attr.clear(); + attr.put(ARCFour.ARCFOUR_KEY_MATERIAL, keys[2]); + ((ARCFour) writeCipher).init(attr); + attr.put(ARCFour.ARCFOUR_KEY_MATERIAL, keys[3]); + ((ARCFour) readCipher).init(attr); + } + else if (!suite.isStreamCipher()) + { + writeCipher = CipherSuite.getCipher(suite.getCipher()); + readCipher = CipherSuite.getCipher(suite.getCipher()); + attr.clear(); + attr.put(IMode.KEY_MATERIAL, keys[2]); + attr.put(IMode.IV, keys[4]); + attr.put(IMode.STATE, new Integer(IMode.ENCRYPTION)); + ((IMode) writeCipher).init(attr); + attr.put(IMode.KEY_MATERIAL, keys[3]); + attr.put(IMode.IV, keys[5]); + attr.put(IMode.STATE, new Integer(IMode.DECRYPTION)); + ((IMode) readCipher).init(attr); + } + } + else // JCESecurityParameters + { + writeMac = CipherSuite.getJCEMac (suite.getMac()); + readMac = CipherSuite.getJCEMac (suite.getMac()); + writeCipher = CipherSuite.getJCECipher (suite.getCipher()); + readCipher = CipherSuite.getJCECipher (suite.getCipher()); + ((Mac) writeMac).init (new SecretKeySpec (keys[0], suite.getMac())); + ((Mac) readMac).init (new SecretKeySpec (keys[1], suite.getMac())); + if (!suite.isStreamCipher()) + { + ((Cipher) writeCipher).init (Cipher.ENCRYPT_MODE, + new SecretKeySpec (keys[2], suite.getCipher()), + new IvParameterSpec (keys[4])); + ((Cipher) readCipher).init (Cipher.DECRYPT_MODE, + new SecretKeySpec (keys[3], suite.getCipher()), + new IvParameterSpec (keys[5])); + } + else + { + ((Cipher) writeCipher).init (Cipher.ENCRYPT_MODE, + new SecretKeySpec (keys[2], suite.getCipher())); + ((Cipher) readCipher).init (Cipher.DECRYPT_MODE, + new SecretKeySpec (keys[3], suite.getCipher())); + } + } + } + // These should technically never happen, if our key generation is not + // broken. + catch (InvalidKeyException ike) + { + internalError(); + RuntimeException re = new RuntimeException (ike.getMessage()); + re.initCause(ike); + throw re; + } + catch (InvalidAlgorithmParameterException iape) + { + internalError(); + RuntimeException re = new RuntimeException (iape.getMessage()); + re.initCause (iape); + throw re; + } + // These indicate a configuration error with the JCA. + catch (NoSuchAlgorithmException nsae) + { + session.enabledSuites.remove (suite); + internalError(); + SSLException x = new SSLException ("suite " + suite + " not available in this configuration"); + x.initCause (nsae); + throw x; + } + catch (NoSuchPaddingException nspe) + { + session.enabledSuites.remove (suite); + internalError(); + SSLException x = new SSLException ("suite " + suite + " not available in this configuration"); + x.initCause (nspe); + throw x; + } + + Finished finis = null; + + if (newSession) + { + changeCipherSpec(); + session.params.setDeflating(serverHello.getCompressionMethod() == CompressionMethod.ZLIB); + session.params.setOutMac(writeMac); + session.params.setOutCipher(writeCipher); + finis = generateFinished(version, (IMessageDigest) md5.clone(), + (IMessageDigest) sha.clone(), true); + msg = new Handshake(Handshake.Type.FINISHED, finis); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write(dout, version); + dout.flush(); + } + + if (session.currentAlert != null && + session.currentAlert.getLevel() == Alert.Level.FATAL) + { + fatal(); + throw new AlertException(session.currentAlert, false); + } + + synchronized (session.params) + { + readChangeCipherSpec (); + session.params.setInflating(serverHello.getCompressionMethod() == CompressionMethod.ZLIB); + session.params.setInMac(readMac); + session.params.setInCipher(readCipher); + session.params.notifyAll(); + } + + Finished verify = generateFinished(version, (IMessageDigest) md5.clone(), + (IMessageDigest) sha.clone(), false); + + msg = Handshake.read(din, suite, null); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + if (msg.getType() != Handshake.Type.FINISHED) + { + throwUnexpectedMessage(); + } + finis = (Finished) msg.getBody(); + if (version == ProtocolVersion.SSL_3) + { + if (!Arrays.equals(finis.getMD5Hash(), verify.getMD5Hash()) || + !Arrays.equals(finis.getSHAHash(), verify.getSHAHash())) + { + throwHandshakeFailure(); + } + } + else + { + if (!Arrays.equals(finis.getVerifyData(), verify.getVerifyData())) + { + throwHandshakeFailure(); + } + } + + if (!newSession) + { + changeCipherSpec(); + session.params.setDeflating(serverHello.getCompressionMethod() == CompressionMethod.ZLIB); + session.params.setOutMac(writeMac); + session.params.setOutCipher(writeCipher); + finis = generateFinished(version, md5, sha, true); + msg = new Handshake(Handshake.Type.FINISHED, finis); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write(dout, version); + dout.flush(); + } + + handshakeCompleted(); + } + + /** + * Perform the server handshake. + */ + private void doServerHandshake() throws IOException + { + if (DEBUG_HANDSHAKE_LAYER) + { + logger.log (Component.SSL_HANDSHAKE, "doing server handshake in {0}", + Thread.currentThread()); + } + + if (remoteHost == null) + { + remoteHost = getInetAddress().getHostName(); + } + if (remoteHost == null) + { + remoteHost = getInetAddress().getHostAddress(); + } + + IMessageDigest md5 = HashFactory.getInstance(Registry.MD5_HASH); + IMessageDigest sha = HashFactory.getInstance(Registry.SHA160_HASH); + DigestInputStream din = new DigestInputStream(handshakeIn, md5, sha); + DigestOutputStream dout = new DigestOutputStream(handshakeOut, md5, sha); + + // Read the client hello. + Handshake msg = Handshake.read(din); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + if (msg.getType() != Handshake.Type.CLIENT_HELLO) + { + throwUnexpectedMessage(); + } + ClientHello clientHello = (ClientHello) msg.getBody(); + Random clientRandom = clientHello.getRandom(); + ProtocolVersion version = clientHello.getVersion(); + ProtocolVersion server = + (ProtocolVersion) session.enabledProtocols.last(); + CompressionMethod comp; + if (clientHello.getCompressionMethods().contains(CompressionMethod.ZLIB)) + comp = CompressionMethod.ZLIB; + else + comp = CompressionMethod.NULL; + if (!session.enabledProtocols.contains(version) + && version.compareTo(server) < 0) + { + Alert alert = new Alert(Alert.Level.FATAL, + Alert.Description.PROTOCOL_VERSION); + sendAlert(alert); + session.currentAlert = alert; + throw new AlertException(alert, true); + } + + // Look through the extensions sent by the client (if any), and react to + // them appropriately. + List extensions = null; + String remoteUser = null; + if (clientHello.getExtensions() != null) + { + for (Iterator it = clientHello.getExtensions().iterator(); it.hasNext();) + { + Extension ex = (Extension) it.next(); + if (ex.getType() == Extension.Type.SERVER_NAME) + { + if (extensions == null) + { + extensions = new LinkedList(); + } + extensions.add(ex); + } + else if (ex.getType() == Extension.Type.MAX_FRAGMENT_LENGTH) + { + int maxLen = Extensions.getMaxFragmentLength(ex).intValue(); +// recordInput.setFragmentLength(maxLen); +// recordOutput.setFragmentLength(maxLen); + session.params.setFragmentLength(maxLen); + if (extensions == null) + { + extensions = new LinkedList(); + } + extensions.add(ex); + } + else if (ex.getType() == Extension.Type.SRP) + { + if (extensions == null) + { + extensions = new LinkedList(); + } + byte[] b = ex.getValue(); + remoteUser = new String(ex.getValue(), 1, b[0] & 0xFF, "UTF-8"); + session.putValue("srp-username", remoteUser); + } + } + } + + CipherSuite suite = selectSuite(clientHello.getCipherSuites(), version); + if (suite == null) + { + return; + } + + // If the selected suite turns out to be SRP, set up the key exchange + // objects. + IKeyAgreementParty serverKA = null; + IncomingMessage in; + OutgoingMessage out = null; + if (suite.getKeyExchange() == "SRP") + { + // FIXME + // Uhm, I don't think this can happen, because if remoteUser is null + // we cannot choose an SRP ciphersuite... + if (remoteUser == null) + { + Alert alert = new Alert(Alert.Level.FATAL, + Alert.Description.MISSING_SRP_USERNAME); + sendAlert(alert); + throw new AlertException(alert, true); + } + + SRPAuthInfoProvider srpDB = new SRPAuthInfoProvider(); + Map dbAttributes = new HashMap(); + dbAttributes.put(SRPRegistry.PASSWORD_DB, + session.srpTrustManager.getPasswordFile()); + srpDB.activate(dbAttributes); + + // FIXME + // We can also fake that the user exists, and generate a dummy (and + // invalid) master secret, and let the handshake fail at the Finished + // message. This is better than letting the connecting side know that + // the username they sent isn't valid. + // + // But how to implement this? + if (!srpDB.contains(remoteUser)) + { + Alert alert = new Alert(Alert.Level.FATAL, + Alert.Description.UNKNOWN_SRP_USERNAME); + sendAlert(alert); + throw new AlertException(alert, true); + } + + serverKA = KeyAgreementFactory.getPartyBInstance(Registry.SRP_TLS_KA); + Map serverAttributes = new HashMap(); + serverAttributes.put(SRP6KeyAgreement.HASH_FUNCTION, + Registry.SHA160_HASH); + serverAttributes.put(SRP6KeyAgreement.HOST_PASSWORD_DB, srpDB); + + try + { + serverKA.init(serverAttributes); + out = new OutgoingMessage(); + out.writeString(remoteUser); + in = new IncomingMessage(out.toByteArray()); + out = serverKA.processMessage(in); + } + catch (KeyAgreementException x) + { + throwHandshakeFailure(); + } + } + + // Check if the session specified by the client's ID corresponds + // to a saved session, and if so, continue it. + boolean newSession = true; + if (DEBUG_HANDSHAKE_LAYER) + { + logger.log (Component.SSL_HANDSHAKE, "saved sessions: {0}", sessionContext); + } + if (sessionContext.containsSessionID( + new Session.ID(clientHello.getSessionId()))) + { + Session old = session; + session = (Session) sessionContext.getSession(clientHello.getSessionId()); + if (!clientHello.getCipherSuites().contains(session.cipherSuite)) + { + throwHandshakeFailure(); + } + if (session.getPeerHost().equals(remoteHost) && + old.enabledProtocols.contains(session.protocol)) + { + session = (Session) session.clone(); + suite = session.cipherSuite; + newSession = false; + recordInput.setSession(session); + session.currentAlert = null; + session.params = old.params; + session.random = old.random; + } + else + { + if (DEBUG_HANDSHAKE_LAYER) + { + logger.log (Component.SSL_HANDSHAKE, "rejected section; hosts equal? {0}, same suites? {1}", + new Object[] { Boolean.valueOf (session.getPeerHost().equals(remoteHost)), + Boolean.valueOf (old.enabledProtocols.contains(session.protocol)) }); + } + session = old; + session.peerHost = remoteHost; + newSession = true; + } + } + else if (DEBUG_HANDSHAKE_LAYER) + { + logger.log (Component.SSL_HANDSHAKE, "rejected session; have session id? {0}, saved sessions: {1}", + new Object[] { Boolean.valueOf (sessionContext.containsSessionID(new Session.ID(clientHello.getSessionId()))), + sessionContext }); + } + if (newSession) + { + byte[] buf = new byte[32]; + Session.ID sid = null; + do + { + session.random.nextBytes(buf); + sid = new Session.ID(buf); + } + while (sessionContext.containsSessionID(sid)); + session.sessionId = sid; + } + session.valid = true; + session.peerHost = remoteHost; + session.cipherSuite = suite; + session.protocol = version; + session.params.setVersion (version); + + // Send the server hello. + Random serverRandom = new Random(Util.unixTime(), + session.random.generateSeed(28)); + ServerHello serverHello = new ServerHello(version, serverRandom, + session.getId(), suite, + comp, extensions); + msg = new Handshake(Handshake.Type.SERVER_HELLO, serverHello); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write(dout, version); +// recordOutput.setHandshakeAvail(msg.write(dout, version)); + dout.flush(); + + if (newSession) + { + X509Certificate[] certs = null; + PrivateKey serverKey = null; + if (suite.getSignature() != "anon") + { + // Send our CA-issued certificate to the client. + String alias = session.keyManager.chooseServerAlias(suite.getAuthType(), + null, null); + certs = session.keyManager.getCertificateChain(alias); + serverKey = session.keyManager.getPrivateKey(alias); + if (certs == null || serverKey == null) + { + throwHandshakeFailure(); + } + session.localCerts = certs; + Certificate serverCert = new Certificate(certs); + msg = new Handshake(Handshake.Type.CERTIFICATE, serverCert); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write(dout, version); +// recordOutput.setHandshakeAvail(msg.write(dout, version));; + dout.flush(); + } + + // If the certificate we sent does not contain enough information to + // do the key exchange (in the case of ephemeral Diffie-Hellman, + // export RSA, and SRP) we send a signed public key to be used for the + // key exchange. + KeyPair signPair = null; + if (certs != null) + { + signPair = new KeyPair(certs[0].getPublicKey(), serverKey); + } + KeyPair kexPair = signPair; + ServerKeyExchange skex = null; + + // Set up our key exchange, and/or prepare our ServerKeyExchange + // message. + if ((suite.getKeyExchange() == "RSA" && suite.isExportable() && + ((RSAPrivateKey) serverKey).getModulus().bitLength() > 512)) + { + kexPair = KeyPool.generateRSAKeyPair(); + RSAPublicKey pubkey = (RSAPublicKey) kexPair.getPublic(); + Signature s = null; + if (suite.getSignature() != "anon") + { + SSLRSASignature sig = new SSLRSASignature(); + sig.setupSign(Collections.singletonMap(ISignature.SIGNER_KEY, + signPair.getPrivate())); + byte[] buf = clientRandom.getEncoded(); + sig.update(buf, 0, buf.length); + buf = serverRandom.getEncoded(); + sig.update(buf, 0, buf.length); + updateSig(sig, pubkey.getModulus()); + updateSig(sig, pubkey.getPublicExponent()); + s = new Signature(sig.sign(), "RSA"); + } + skex = new ServerKeyExchange(pubkey, s); + } + else if (suite.getKeyExchange() == "DH") + { + serverKA = KeyAgreementFactory.getPartyBInstance(Registry.ELGAMAL_KA); + Map attr = new HashMap(); + attr.put(ElGamalKeyAgreement.KA_ELGAMAL_RECIPIENT_PRIVATE_KEY, + serverKey); + try + { + serverKA.init(attr); + } + catch (KeyAgreementException kae) + { + if (DEBUG_KEY_EXCHANGE) + logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae); + internalError(); + RuntimeException re = new RuntimeException (kae.getMessage()); + re.initCause (kae); + throw re; + } + // We don't send a ServerKeyExchange for this suite. + } + else if (suite.getKeyExchange() == "DHE") + { + serverKA = KeyAgreementFactory.getPartyAInstance(Registry.DH_KA); + Map attr = new HashMap(); + GnuDHPrivateKey servParams = DiffieHellman.getParams(); + attr.put(DiffieHellmanKeyAgreement.KA_DIFFIE_HELLMAN_OWNER_PRIVATE_KEY, + servParams); + attr.put(DiffieHellmanKeyAgreement.SOURCE_OF_RANDOMNESS, + session.random); + BigInteger serv_y = null; + try + { + serverKA.init(attr); + out = serverKA.processMessage(null); + in = new IncomingMessage(out.toByteArray()); + serv_y = in.readMPI(); + } + catch (KeyAgreementException kae) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "DHE exception", kae); + } + internalError(); + RuntimeException re = new RuntimeException (kae.getMessage()); + re.initCause (kae); + throw re; + } + GnuDHPublicKey pubkey = + new GnuDHPublicKey(null, servParams.getParams().getP(), + servParams.getParams().getG(), serv_y); + Signature s = null; + if (suite.getSignature() != "anon") + { + ISignature sig = null; + if (suite.getSignature() == "RSA") + { + sig = new SSLRSASignature(); + } + else + { + sig = SignatureFactory.getInstance(Registry.DSS_SIG); + } + sig.setupSign(Collections.singletonMap(ISignature.SIGNER_KEY, + signPair.getPrivate())); + byte[] buf = clientRandom.getEncoded(); + sig.update(buf, 0, buf.length); + buf = serverRandom.getEncoded(); + sig.update(buf, 0, buf.length); + updateSig(sig, pubkey.getParams().getP()); + updateSig(sig, pubkey.getParams().getG()); + updateSig(sig, pubkey.getY()); + s = new Signature(sig.sign(), suite.getSignature()); + } + skex = new ServerKeyExchange(pubkey, s); + } + else if (suite.getKeyExchange() == "SRP") + { + BigInteger N = null; + BigInteger g = null; + BigInteger salt = null; + BigInteger B = null; + try + { + in = new IncomingMessage(out.toByteArray()); + N = in.readMPI(); + g = in.readMPI(); + salt = in.readMPI(); + B = in.readMPI(); + } + catch (KeyAgreementException x) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x); + } + throwHandshakeFailure(); + } + Signature s = null; + final byte[] srpSalt = Util.trim(salt); + if (suite.getSignature() != "anon") + { + ISignature sig = null; + if (suite.getSignature() == "RSA") + { + sig = new SSLRSASignature(); + } + else + { + sig = SignatureFactory.getInstance(Registry.DSS_SIG); + } + sig.setupSign(Collections.singletonMap(ISignature.SIGNER_KEY, + signPair.getPrivate())); + byte[] buf = clientRandom.getEncoded(); + sig.update(buf, 0, buf.length); + buf = serverRandom.getEncoded(); + sig.update(buf, 0, buf.length); + updateSig(sig, N); + updateSig(sig, g); + sig.update((byte) srpSalt.length); + sig.update(srpSalt, 0, srpSalt.length); + updateSig(sig, B); + s = new Signature(sig.sign(), suite.getSignature()); + } + final SRPPublicKey pubkey = new SRPPublicKey(N, g, B); + skex = new ServerKeyExchange(pubkey, s, srpSalt); + } + if (skex != null) + { + msg = new Handshake(Handshake.Type.SERVER_KEY_EXCHANGE, skex); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write(dout, version); +// recordOutput.setHandshakeAvail(msg.write(dout, version));; + dout.flush(); + } + + // If we are configured to want or need client authentication, then + // ask for it. + if (wantClientAuth || needClientAuth) + { + Principal[] auths = null; + CertificateRequest.ClientType[] types = + new CertificateRequest.ClientType[] { + CertificateRequest.ClientType.RSA_SIGN, + CertificateRequest.ClientType.DSS_SIGN, + CertificateRequest.ClientType.RSA_FIXED_DH, + CertificateRequest.ClientType.DSS_FIXED_DH + }; + try + { + auths = (Principal[]) + Util.transform(session.trustManager.getAcceptedIssuers(), + Principal.class, "getSubjectDN", null); + } + catch (Exception x) + { + internalError(); + RuntimeException re = new RuntimeException (x.getMessage()); + re.initCause (x); + throw re; + } + CertificateRequest req = new CertificateRequest(types, auths); + msg = new Handshake(Handshake.Type.CERTIFICATE_REQUEST, req); + msg.write(dout, version); + dout.flush(); + } + + // Send our server hello done. + msg = new Handshake(Handshake.Type.SERVER_HELLO_DONE, null); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write(dout, version); + dout.flush(); + + if (suite.getKeyExchange() == "RSA") + { + msg = Handshake.read(din, suite, kexPair.getPublic()); + } + else + { + msg = Handshake.read(din, suite, null); + } + boolean clientCertOk = false; + boolean clientCanSign = false; + X509Certificate[] clientChain = null; + PublicKey clientKey = null; + + // Read the client's certificate, if sent. + if (msg.getType() == Handshake.Type.CERTIFICATE) + { + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + Certificate cliCert = (Certificate) msg.getBody(); + clientChain = cliCert.getCertificates(); + try + { + session.trustManager.checkClientTrusted(clientChain, + suite.getAuthType()); + session.peerCerts = clientChain; + session.peerVerified = true; + clientKey = clientChain[0].getPublicKey(); + } + catch (Exception x) + { + } + clientCanSign = ((clientKey instanceof DSAPublicKey) || + (clientKey instanceof RSAPublicKey)); + if (suite.getKeyExchange().startsWith("DH")) + { + msg = Handshake.read(din, suite, clientKey); + } + else + { + msg = Handshake.read(din, suite, kexPair.getPublic()); + } + } + + // If we require client authentication, and the client sent an + // unverifiable certificate or no certificate at all, drop the + // connection. + if (!session.peerVerified && needClientAuth) + { + throwHandshakeFailure(); + } + + // Read the client key exchange. + if (msg.getType() != Handshake.Type.CLIENT_KEY_EXCHANGE) + { + throwUnexpectedMessage(); + } + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + ClientKeyExchange ckex = (ClientKeyExchange) msg.getBody(); + byte[] preMasterSecret = null; + if (suite.getKeyExchange() == "RSA") + { + byte[] enc = (byte[]) ckex.getExchangeObject(); + BigInteger bi = new BigInteger(1, enc); + try + { + bi = RSA.decrypt(kexPair.getPrivate(), bi); + EME_PKCS1_V1_5 pkcs1 = EME_PKCS1_V1_5.getInstance( + (RSAPrivateKey) kexPair.getPrivate()); + preMasterSecret = pkcs1.decode(Util.concat(new byte[1], bi.toByteArray())); + //rsa.init(kexPair); + //preMasterSecret = rsa.decrypt(enc); + } + catch (Exception x) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "RSA exception", x); + } + // Generate a fake pre-master secret if the RSA decryption + // fails. + byte[] b = new byte[46]; + session.random.nextBytes (b); + preMasterSecret = Util.concat(version.getEncoded(), b); + } + } + else if (suite.getKeyExchange().startsWith("DH")) + { + try + { + out = new OutgoingMessage(); + if (clientKey == null) + out.writeMPI((BigInteger) ckex.getExchangeObject()); + else + out.writeMPI(((DHPublicKey) clientKey).getY()); + in = new IncomingMessage(out.toByteArray()); + serverKA.processMessage(in); + preMasterSecret = serverKA.getSharedSecret(); + } + catch (KeyAgreementException kae) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae); + } + internalError(); + RuntimeException re = new RuntimeException (kae.getMessage()); + re.initCause (kae); + throw re; + } + } + else if (suite.getKeyExchange() == "SRP") + { + BigInteger A = (BigInteger) ckex.getExchangeObject(); + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "SRP: client A: {0}", A); + } + try + { + out = new OutgoingMessage(); + out.writeMPI(A); + in = new IncomingMessage(out.toByteArray()); + out = serverKA.processMessage(in); + preMasterSecret = serverKA.getSharedSecret(); + } + catch (KeyAgreementException x) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x); + } + throwHandshakeFailure(); + } + finally + { + serverKA = null; + } + } + + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "preMasterSecret:\n{0}", + Util.toHexString(preMasterSecret, ':')); + logger.log (Component.SSL_KEY_EXCHANGE, "client.random:\n{0}", + Util.toHexString(clientRandom.getEncoded(), ':')); + logger.log (Component.SSL_KEY_EXCHANGE, "server.random:\n{0}", + Util.toHexString(serverRandom.getEncoded(), ':')); + } + + // Generate the master secret. + IRandom genSecret = null; + if (version == ProtocolVersion.SSL_3) + { + genSecret = new SSLRandom(); + HashMap attr = new HashMap(); + attr.put(SSLRandom.SECRET, preMasterSecret); + attr.put(SSLRandom.SEED, Util.concat(clientRandom.getEncoded(), + serverRandom.getEncoded())); + genSecret.init(attr); + } + else + { + genSecret = new TLSRandom(); + HashMap attr = new HashMap(); + attr.put(TLSRandom.SECRET, preMasterSecret); + attr.put(TLSRandom.SEED, + Util.concat(("master secret").getBytes("UTF-8"), + Util.concat(clientRandom.getEncoded(), + serverRandom.getEncoded()))); + genSecret.init(attr); + } + session.masterSecret = new byte[48]; + try + { + genSecret.nextBytes(session.masterSecret, 0, 48); + for (int i = 0; i < preMasterSecret.length; i++) + { + preMasterSecret[i] = 0; + } + } + catch (LimitReachedException shouldNotHappen) + { + internalError(); + RuntimeException re = new RuntimeException(); + re.initCause (shouldNotHappen); + throw re; + } + + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "masterSecret: {0}", + Util.toHexString(session.masterSecret, ':')); + } + + // Read the client's certificate verify message, if needed. + if (clientCanSign && (wantClientAuth || needClientAuth)) + { + msg = Handshake.read(din); + if (msg.getType() != Handshake.Type.CERTIFICATE_VERIFY) + { + throwUnexpectedMessage(); + } + CertificateVerify verify = (CertificateVerify) msg.getBody(); + if (clientChain != null && clientChain.length > 0) + { + IMessageDigest cvMD5 = (IMessageDigest) md5.clone(); + IMessageDigest cvSHA = (IMessageDigest) sha.clone(); + clientKey = clientChain[0].getPublicKey(); + if (clientKey instanceof RSAPublicKey) + { + SSLRSASignature sig = new SSLRSASignature(cvMD5, cvSHA); + sig.setupVerify(Collections.singletonMap(ISignature.VERIFIER_KEY, clientKey)); + if (!sig.verify(verify.getSigValue())) + { + handshakeFailure(); + throw new SSLHandshakeException("client certificate verify failed"); + } + } + else if (clientKey instanceof DSAPublicKey) + { + try + { + if (!DSSSignature.verify((DSAPublicKey) clientKey, cvSHA.digest(), + (BigInteger[]) verify.getSigValue())) + { + throw new Exception("client's certificate could not be verified"); + } + } + catch (Exception x) + { + handshakeFailure(); + SSLHandshakeException e = new SSLHandshakeException (x.getMessage()); + e.initCause (x); + throw e; + } + } + } + } + } + + // Generate the session keys. + byte[][] keys = null; + try + { + keys = generateKeys(serverRandom.getEncoded(), + clientRandom.getEncoded(), version); + } + catch (Exception x) + { + internalError(); + RuntimeException re = new RuntimeException (x.getMessage()); + re.initCause (x); + throw re; + } + + // Initialize the algorithms with the derived keys. + Object readMac = null, writeMac = null; + Object readCipher = null, writeCipher = null; + try + { + if (session.params instanceof GNUSecurityParameters) + { + HashMap attr = new HashMap(); + writeMac = CipherSuite.getMac(suite.getMac()); + readMac = CipherSuite.getMac(suite.getMac()); + attr.put(IMac.MAC_KEY_MATERIAL, keys[1]); + ((IMac) writeMac).init(attr); + attr.put(IMac.MAC_KEY_MATERIAL, keys[0]); + ((IMac) readMac).init(attr); + if (suite.getCipher() == "RC4") + { + writeCipher = new ARCFour(); + readCipher = new ARCFour(); + attr.clear(); + attr.put(ARCFour.ARCFOUR_KEY_MATERIAL, keys[3]); + ((ARCFour) writeCipher).init(attr); + attr.put(ARCFour.ARCFOUR_KEY_MATERIAL, keys[2]); + ((ARCFour) readCipher).init(attr); + } + else if (!suite.isStreamCipher()) + { + writeCipher = CipherSuite.getCipher(suite.getCipher()); + readCipher = CipherSuite.getCipher(suite.getCipher()); + attr.clear(); + attr.put(IMode.KEY_MATERIAL, keys[3]); + attr.put(IMode.IV, keys[5]); + attr.put(IMode.STATE, new Integer(IMode.ENCRYPTION)); + ((IMode) writeCipher).init(attr); + attr.put(IMode.KEY_MATERIAL, keys[2]); + attr.put(IMode.IV, keys[4]); + attr.put(IMode.STATE, new Integer(IMode.DECRYPTION)); + ((IMode) readCipher).init(attr); + } + } + else // JCESecurityParameters + { + writeMac = CipherSuite.getJCEMac (suite.getMac()); + readMac = CipherSuite.getJCEMac (suite.getMac()); + writeCipher = CipherSuite.getJCECipher (suite.getCipher()); + readCipher = CipherSuite.getJCECipher (suite.getCipher()); + ((Mac) writeMac).init (new SecretKeySpec (keys[1], suite.getMac())); + ((Mac) readMac).init (new SecretKeySpec (keys[0], suite.getMac())); + if (!suite.isStreamCipher()) + { + ((Cipher) writeCipher).init (Cipher.ENCRYPT_MODE, + new SecretKeySpec (keys[3], suite.getCipher()), + new IvParameterSpec (keys[5])); + ((Cipher) readCipher).init (Cipher.DECRYPT_MODE, + new SecretKeySpec (keys[2], suite.getCipher()), + new IvParameterSpec (keys[4])); + } + else + { + ((Cipher) writeCipher).init (Cipher.ENCRYPT_MODE, + new SecretKeySpec (keys[3], suite.getCipher())); + ((Cipher) readCipher).init (Cipher.DECRYPT_MODE, + new SecretKeySpec (keys[2], suite.getCipher())); + } + } + } + // These should technically never happen, if our key generation is not + // broken. + catch (InvalidKeyException ike) + { + internalError(); + RuntimeException re = new RuntimeException (ike.getMessage()); + re.initCause (ike); + throw new RuntimeException (String.valueOf (ike)); + } + catch (InvalidAlgorithmParameterException iape) + { + internalError(); + RuntimeException re = new RuntimeException (iape.getMessage()); + re.initCause (iape); + throw re; + } + // These indicate a configuration error with the JCA. + catch (NoSuchAlgorithmException nsae) + { + session.enabledSuites.remove (suite); + internalError(); + SSLException e = new SSLException ("suite " + suite + " not available in this configuration"); + e.initCause (nsae); + throw e; + } + catch (NoSuchPaddingException nspe) + { + session.enabledSuites.remove (suite); + internalError(); + SSLException e = new SSLException ("suite " + suite + " not available in this configuration"); + e.initCause (nspe); + throw e; + } + + Finished finis = null; + // If we are continuing a session, we send our Finished message first. + if (!newSession) + { + changeCipherSpec(); + session.params.setDeflating(comp == CompressionMethod.ZLIB); + session.params.setOutMac(writeMac); + session.params.setOutCipher(writeCipher); + finis = generateFinished(version, (IMessageDigest) md5.clone(), + (IMessageDigest) sha.clone(), false); + msg = new Handshake(Handshake.Type.FINISHED, finis); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write(dout, version); + dout.flush(); + } + + if (session.currentAlert != null && + session.currentAlert.getLevel() == Alert.Level.FATAL) + { + fatal(); + throw new AlertException(session.currentAlert, false); + } + + // Wait until we receive a ChangeCipherSpec, then change the crypto + // algorithms for the incoming side. + synchronized (session.params) + { + readChangeCipherSpec (); + session.params.setInflating(comp == CompressionMethod.ZLIB); + session.params.setInMac(readMac); + session.params.setInCipher(readCipher); + session.params.notifyAll(); + } + + // Receive and verify the client's finished message. + Finished verify = generateFinished(version, (IMessageDigest) md5.clone(), + (IMessageDigest) sha.clone(), true); + msg = Handshake.read(din, suite, null); + if (msg.getType() != Handshake.Type.FINISHED) + { + throwUnexpectedMessage(); + } + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + finis = (Finished) msg.getBody(); + if (version == ProtocolVersion.SSL_3) + { + if (!Arrays.equals(finis.getMD5Hash(), verify.getMD5Hash()) || + !Arrays.equals(finis.getSHAHash(), verify.getSHAHash())) + { + throwHandshakeFailure(); + } + } + else + { + if (!Arrays.equals(finis.getVerifyData(), verify.getVerifyData())) + { + throwHandshakeFailure(); + } + } + + // Send our Finished message last for new sessions. + if (newSession) + { + changeCipherSpec(); + session.params.setDeflating(comp == CompressionMethod.ZLIB); + session.params.setOutMac(writeMac); + session.params.setOutCipher(writeCipher); + finis = generateFinished(version, md5, sha, false); + msg = new Handshake(Handshake.Type.FINISHED, finis); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write(dout, version); + dout.flush(); + } + + handshakeCompleted(); + } + + /** + * Generate the keys from the master secret. + * + * @param server The server's random value. + * @param client The client's random value. + * @param activeVersion The negotiated protocol version. + * @return The generated keys. + */ + private byte[][] generateKeys(byte[] server, byte[] client, + ProtocolVersion activeVersion) + throws LimitReachedException, IOException + { + CipherSuite suite = session.cipherSuite; + int macLen = (suite.getMac().indexOf("MD5") >= 0) ? 16 : 20; + int keyLen = suite.getKeyLength(); + int ivLen = 0; + if (suite.getCipher().indexOf("DES") >= 0) + { + ivLen = 8; + } + else if (suite.getCipher() == "AES") + { + ivLen = 16; + } + byte[][] keyMaterial = new byte[6][]; + keyMaterial[0] = new byte[macLen]; // client_write_MAC_secret + keyMaterial[1] = new byte[macLen]; // server_write_MAC_secret + keyMaterial[2] = new byte[keyLen]; // client_write_key + keyMaterial[3] = new byte[keyLen]; // server_write_key + keyMaterial[4] = new byte[ivLen]; // client_write_IV + keyMaterial[5] = new byte[ivLen]; // server_write_IV + IRandom prf = null; + if (activeVersion == ProtocolVersion.SSL_3) + { + prf = new SSLRandom(); + HashMap attr = new HashMap(); + attr.put(SSLRandom.SECRET, session.masterSecret); + attr.put(SSLRandom.SEED, Util.concat(server, client)); + prf.init(attr); + } + else + { + prf = new TLSRandom(); + HashMap attr = new HashMap(); + attr.put(TLSRandom.SECRET, session.masterSecret); + attr.put(TLSRandom.SEED, Util.concat("key expansion".getBytes("UTF-8"), + Util.concat(server, client))); + prf.init(attr); + } + for (int i = 0; i < keyMaterial.length; i++) + { + prf.nextBytes(keyMaterial[i], 0, keyMaterial[i].length); + } + + // Exportable ciphers transform their keys once more, and use a + // nonsecret IV for block ciphers. + if (suite.isExportable()) + { + int finalLen = suite.getCipher() == "DES" ? 8 : 16; + if (activeVersion == ProtocolVersion.SSL_3) + { + IMessageDigest md5 = HashFactory.getInstance(Registry.MD5_HASH); + md5.update(keyMaterial[2], 0, keyMaterial[2].length); + md5.update(client, 0, client.length); + md5.update(server, 0, server.length); + keyMaterial[2] = Util.trim(md5.digest(), finalLen); + md5.update(keyMaterial[3], 0, keyMaterial[3].length); + md5.update(server, 0, server.length); + md5.update(client, 0, client.length); + keyMaterial[3] = Util.trim(md5.digest(), finalLen); + if (!suite.isStreamCipher()) + { + md5.update(client, 0, client.length); + md5.update(server, 0, server.length); + keyMaterial[4] = Util.trim(md5.digest(), ivLen); + md5.update(server, 0, server.length); + md5.update(client, 0, client.length); + keyMaterial[5] = Util.trim(md5.digest(), ivLen); + } + } + else + { + HashMap attr = new HashMap(); + attr.put(TLSRandom.SECRET, keyMaterial[2]); + attr.put(TLSRandom.SEED, + Util.concat("client write key".getBytes("UTF-8"), + Util.concat(client, server))); + prf.init(attr); + keyMaterial[2] = new byte[finalLen]; + prf.nextBytes(keyMaterial[2], 0, finalLen); + attr.put(TLSRandom.SECRET, keyMaterial[3]); + attr.put(TLSRandom.SEED, + Util.concat("server write key".getBytes("UTF-8"), + Util.concat(client, server))); + prf.init(attr); + keyMaterial[3] = new byte[finalLen]; + prf.nextBytes(keyMaterial[3], 0, finalLen); + if (!suite.isStreamCipher()) + { + attr.put(TLSRandom.SECRET, new byte[0]); + attr.put(TLSRandom.SEED, Util.concat("IV block".getBytes("UTF-8"), + Util.concat(client, server))); + prf.init(attr); + prf.nextBytes(keyMaterial[4], 0, keyMaterial[4].length); + prf.nextBytes(keyMaterial[5], 0, keyMaterial[5].length); + } + } + } + + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "Generated keys:"); + for (int i = 0; i < keyMaterial.length; i++) + logger.log (Component.SSL_KEY_EXCHANGE, "[{0}] {1}", + new Object[] { new Integer (i), + Util.toHexString(keyMaterial[i], ':') }); + } + + return keyMaterial; + } + + /** + * Generate a "finished" message, based on the hashes of the handshake + * messages, the agreed version, and a label. + * + * @param version The agreed version. + * @param md5 The current state of the handshake MD5 hash. + * @param sha The current state of the handshake SHA hash. + * @param client Should be true if the message is generated by the client. + */ + private Finished generateFinished(ProtocolVersion version, IMessageDigest md5, + IMessageDigest sha, boolean client) + { + if (version == ProtocolVersion.SSL_3) + { + if (client) + { + md5.update(SENDER_CLIENT, 0, 4); + } + else + { + md5.update(SENDER_SERVER, 0, 4); + } + byte[] ms = session.masterSecret; + md5.update(ms, 0, ms.length); + for (int i = 0; i < 48; i++) + { + md5.update(SSLHMac.PAD1); + } + byte[] b = md5.digest(); + md5.update(ms, 0, ms.length); + for (int i = 0; i < 48; i++) + { + md5.update(SSLHMac.PAD2); + } + md5.update(b, 0, b.length); + + if (client) + { + sha.update(SENDER_CLIENT, 0, 4); + } + else + { + sha.update(SENDER_SERVER, 0, 4); + } + sha.update(ms, 0, ms.length); + for (int i = 0; i < 40; i++) + { + sha.update(SSLHMac.PAD1); + } + b = sha.digest(); + sha.update(ms, 0, ms.length); + for (int i = 0; i < 40; i++) + { + sha.update(SSLHMac.PAD2); + } + sha.update(b, 0, b.length); + return new Finished(md5.digest(), sha.digest()); + } + else + { + byte[] h1 = md5.digest(); + byte[] h2 = sha.digest(); + String label = client ? "client finished" : "server finished"; + byte[] seed = null; + try + { + seed = Util.concat(label.getBytes("UTF-8"), Util.concat(h1, h2)); + } + catch (java.io.UnsupportedEncodingException uee) + { + RuntimeException re = new RuntimeException (uee.getMessage()); + re.initCause (uee); + throw re; + } + IRandom prf = new TLSRandom(); + HashMap attr = new HashMap(); + attr.put(TLSRandom.SECRET, session.masterSecret); + attr.put(TLSRandom.SEED, seed); + prf.init(attr); + byte[] finishedValue = new byte[12]; + try + { + prf.nextBytes(finishedValue, 0, 12); + } + catch (LimitReachedException lre) + { + RuntimeException re = new RuntimeException (lre.getMessage()); + re.initCause (lre); + throw re; + } + return new Finished(finishedValue); + } + } + + /** + * Send a fatal unexpected_message alert. + */ + private Alert unexpectedMessage() throws IOException + { + Alert alert = new Alert(Alert.Level.FATAL, + Alert.Description.UNEXPECTED_MESSAGE); + sendAlert(alert); + fatal(); + return alert; + } + + private void throwUnexpectedMessage() throws IOException + { + throw new AlertException(unexpectedMessage(), true); + } + + /** + * Send a fatal handshake_failure alert. + */ + private Alert handshakeFailure() throws IOException + { + Alert alert = new Alert(Alert.Level.FATAL, + Alert.Description.HANDSHAKE_FAILURE); + sendAlert(alert); + fatal(); + return alert; + } + + private void throwHandshakeFailure() throws IOException + { + throw new AlertException(handshakeFailure(), true); + } + + /** + * Send an internal_error alert. + */ + private Alert internalError() throws IOException + { + Alert alert = new Alert(Alert.Level.FATAL, + Alert.Description.INTERNAL_ERROR); + sendAlert(alert); + fatal(); + return alert; + } + + private void throwInternalError() throws IOException + { + throw new AlertException(internalError(), true); + } + + private Alert peerUnverified(X509Certificate[] chain) throws IOException + { + Alert alert = new Alert(Alert.Level.FATAL, + Alert.Description.HANDSHAKE_FAILURE); + sendAlert(alert); + fatal(); + return alert; + } + + private void throwPeerUnverified(X509Certificate[] chain) throws IOException + { + peerUnverified (chain); + throw new SSLPeerUnverifiedException("could not verify: "+ + chain[0].getSubjectDN()); + } + + /** + * Grab the first suite that is both in the client's requested suites + * and in our enabled suites, and for which we have the proper + * credentials. + * + * @param suites The client's requested suites. + * @param version The version being negotiated. + * @return The selected cipher suite. + * @throws SSLException If no appropriate suite can be selected. + */ + private CipherSuite selectSuite(List suites, ProtocolVersion version) + throws IOException + { + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "selectSuite req:{0} suites:{1}", + new Object[] { suites, session.enabledSuites }); + boolean srpSuiteNoUser = false; + for (Iterator i = suites.iterator(); i.hasNext(); ) + { + CipherSuite herSuite = (CipherSuite) i.next(); + for (Iterator j = session.enabledSuites.iterator(); j.hasNext(); ) + { + CipherSuite mySuite = (CipherSuite) j.next(); + if (!mySuite.equals(herSuite)) + { + continue; + } + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0} == {1}", + new Object[] { mySuite, herSuite }); + if (mySuite.getSignature() != "anon" && session.keyManager != null && + session.keyManager.chooseServerAlias(mySuite.getAuthType(), null, null) == null) + { + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}: no certificate/private key", + mySuite); + continue; + } + if (mySuite.getKeyExchange() == "SRP") + { + if (session.getValue("srp-username") == null) + { + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "no SRP username"); + srpSuiteNoUser = true; + continue; + } + if (session.srpTrustManager == null) + { + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "no SRP password file"); + continue; + } + } + return mySuite.resolve(version); + } + } + Alert alert = null; + if (srpSuiteNoUser) + { + alert = new Alert(Alert.Level.WARNING, + Alert.Description.MISSING_SRP_USERNAME); + sendAlert(alert); + return null; + } + else + alert = new Alert(Alert.Level.FATAL, + Alert.Description.INSUFFICIENT_SECURITY); + sendAlert(alert); + fatal(); + throw new AlertException(alert, true); + } + + /** + * Ask the user for their user name. + * + * @param remoteHost The remote host being connected to. + * @return The user name. + */ + private String askUserName(String remoteHost) + { + CallbackHandler handler = new DefaultCallbackHandler(); + try + { + Class c = Class.forName(Util.getSecurityProperty("jessie.srp.user.handler")); + handler = (CallbackHandler) c.newInstance(); + } + catch (Exception x) { } + TextInputCallback user = + new TextInputCallback("User name for " + remoteHost + ": ", + Util.getProperty("user.name")); + try + { + handler.handle(new Callback[] { user }); + } + catch (Exception x) { } + return user.getText(); + } + + /** + * Ask the user for a password. + * + * @param user The user name. + * @return The password. + */ + private String askPassword(String user) + { + CallbackHandler handler = new DefaultCallbackHandler(); + try + { + Class c = Class.forName(Util.getSecurityProperty("jessie.srp.password.handler")); + handler = (CallbackHandler) c.newInstance(); + } + catch (Exception x) { } + PasswordCallback passwd = new PasswordCallback(user + "'s password: ", false); + try + { + handler.handle(new Callback[] { passwd }); + } + catch (Exception x) { } + return new String(passwd.getPassword()); + } + + /** + * Ask the user (via a callback) if they will accept a certificate that + * could not be verified. + * + * @param chain The certificate chain in question. + * @return true if the user accepts the certificate chain. + */ + private boolean checkCertificates(X509Certificate[] chain) + { + CallbackHandler handler = new DefaultCallbackHandler(); + try + { + Class c = Class.forName(Util.getSecurityProperty("jessie.certificate.handler")); + handler = (CallbackHandler) c.newInstance(); + } + catch (Exception x) + { + } + String nl = Util.getProperty("line.separator"); + ConfirmationCallback confirm = new ConfirmationCallback( + "The server's certificate could not be verified. There is no proof" + nl + + "that this server is who it claims to be, or that their certificate" + nl + + "is valid. Do you wish to continue connecting?", + ConfirmationCallback.ERROR, ConfirmationCallback.YES_NO_OPTION, + ConfirmationCallback.NO); + try + { + handler.handle(new Callback[] { confirm }); + } + catch (Exception x) + { + return false; + } + return confirm.getSelectedIndex() == ConfirmationCallback.YES; + } + + /** + * Update a signature object with a BigInteger, trimming the leading + * "00" octet if present. + * + * @param sig The signature being updated. + * @param bi The integer to feed into the signature. + */ + private void updateSig(ISignature sig, BigInteger bi) + { + byte[] buf = Util.trim(bi); + sig.update((byte) (buf.length >>> 8)); + sig.update((byte) buf.length); + sig.update(buf, 0, buf.length); + } + + /** + * Teardown everything on fatal errors. + */ + private void fatal() throws IOException + { + if (session != null) + { + session.invalidate(); + } +// recordInput.setRunning(false); +// recordOutput.setRunning(false); + if (underlyingSocket != null) + { + underlyingSocket.close(); + } + else + { + super.close(); + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketFactory.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketFactory.java new file mode 100644 index 00000000000..24a8389c117 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketFactory.java @@ -0,0 +1,133 @@ +/* SSLSocketFactory.java -- factory for SSL sockets. + Copyright (C) 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.net.ssl.provider; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; +import java.security.SecureRandom; + +import javax.net.ssl.X509TrustManager; +import javax.net.ssl.X509KeyManager; + +class SSLSocketFactory extends javax.net.ssl.SSLSocketFactory +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final X509TrustManager trustManager; + private final X509KeyManager keyManager; + private final SecureRandom random; + private final SessionContext sessionContext; + + // Constructor. + // ------------------------------------------------------------------------- + + SSLSocketFactory(X509TrustManager trustManager, X509KeyManager keyManager, + SecureRandom random, SessionContext sessionContext) + { + this.trustManager = trustManager; + this.keyManager = keyManager; + this.random = random; + this.sessionContext = sessionContext; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String[] getDefaultCipherSuites() + { + return (String[]) CipherSuite.availableSuiteNames().toArray(new String[0]); + } + + public String[] getSupportedCipherSuites() + { + return getDefaultCipherSuites(); + } + + public Socket createSocket(Socket socket, String host, int port, boolean autoClose) + throws IOException + { + return setup(new SSLSocket(socket, host, port, autoClose)); + } + + public Socket createSocket() throws IOException + { + return setup(new SSLSocket()); + } + + public Socket createSocket(String host, int port) + throws IOException, UnknownHostException + { + return setup(new SSLSocket(host, port)); + } + + public Socket createSocket(String host, int port, InetAddress localAddr, int localPort) + throws IOException, UnknownHostException + { + return setup(new SSLSocket(host, port, localAddr, localPort)); + } + + public Socket createSocket(InetAddress address, int port) throws IOException + { + return setup(new SSLSocket(address, port)); + } + + public Socket createSocket(InetAddress address, int port, + InetAddress localAddr, int localPort) + throws IOException + { + return setup(new SSLSocket(address, port, localAddr, localPort)); + } + + // Own methods. + // ------------------------------------------------------------------------- + + private SSLSocket setup(SSLSocket s) + { + s.setTrustManager(trustManager); + s.setKeyManager(keyManager); + s.setRandom(random); + s.setSessionContext(sessionContext); + s.setUseClientMode(true); + return s; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketInputStream.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketInputStream.java new file mode 100644 index 00000000000..69202ca33d8 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketInputStream.java @@ -0,0 +1,181 @@ +/* SSLSocketInputStream.java -- InputStream for SSL sockets. + Copyright (C) 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.net.ssl.provider; + +import java.io.EOFException; +import java.io.FilterInputStream; +import java.io.InputStream; +import java.io.IOException; +import javax.net.ssl.SSLException; + +class SSLSocketInputStream extends FilterInputStream +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final SSLSocket socket; + private final boolean checkHandshake; + + // Constructors. + // ------------------------------------------------------------------------- + + SSLSocketInputStream(InputStream in, SSLSocket socket) + { + this(in, socket, true); + } + + SSLSocketInputStream(InputStream in, SSLSocket socket, boolean checkHandshake) + { + super(in); + this.socket = socket; + this.checkHandshake = checkHandshake; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public int available() throws IOException + { + if (checkHandshake) + { + socket.checkHandshakeDone(); + } + int ret = 0; + try + { + ret = super.available(); + } + catch (AlertException ae) + { + Alert alert = ae.getAlert (); + if (alert.getDescription () == Alert.Description.CLOSE_NOTIFY) + { + return -1; + } + else + { + throw ae; + } + } + return ret; + } + + public int read() throws IOException + { + if (checkHandshake) + { + socket.checkHandshakeDone(); + } + int ret = 0; + try + { + ret = in.read(); + } + catch (AlertException ae) + { + Alert alert = ae.getAlert (); + if (alert.getDescription () == Alert.Description.CLOSE_NOTIFY) + { + return -1; + } + else + { + throw ae; + } + } + return ret; + } + + 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 (checkHandshake) + { + socket.checkHandshakeDone(); + } + if (buf == null) + { + throw new NullPointerException(); + } + if (off < 0 || len < 0 || off + len > buf.length) + { + throw new ArrayIndexOutOfBoundsException(); + } + int ret = 0; + try + { + ret = in.read(buf, off, len); + } + catch (AlertException ae) + { + Alert alert = ae.getAlert (); + if (alert.getDescription () == Alert.Description.CLOSE_NOTIFY) + { + return -1; + } + else + { + throw ae; + } + } + return ret; + } + + // Own methods. + // ------------------------------------------------------------------------- + + private boolean checkAlert() throws IOException + { + Alert alert = socket.checkAlert(); + if (alert == null) return false; + if (alert.getLevel().equals(Alert.Level.FATAL)) + throw new AlertException(alert, false); + if (alert.getDescription().equals(Alert.Description.CLOSE_NOTIFY)) + { + try { return (in.available() <= 0); } + catch (IOException ioe) { } + } + return false; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketOutputStream.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketOutputStream.java new file mode 100644 index 00000000000..fe769a85fba --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketOutputStream.java @@ -0,0 +1,115 @@ +/* SSLSocketOutputStream.java -- output stream for SSL sockets. + Copyright (C) 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.net.ssl.provider; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import javax.net.ssl.SSLException; + +class SSLSocketOutputStream extends FilterOutputStream +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final SSLSocket socket; + private final boolean checkHandshake; + + // Constructor. + // ------------------------------------------------------------------------- + + SSLSocketOutputStream(OutputStream out, SSLSocket socket) + { + this(out, socket, true); + } + + SSLSocketOutputStream(OutputStream out, SSLSocket socket, + boolean checkHandshake) + { + super(out); + this.socket = socket; + this.checkHandshake = checkHandshake; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(int b) throws IOException + { + if (checkHandshake) + { + socket.checkHandshakeDone(); + } + checkAlert(); + out.write(b); + checkAlert(); + } + + public void write(byte[] buf) throws IOException + { + write(buf, 0, buf.length); + } + + public void write(byte[] buf, int off, int len) throws IOException + { + if (checkHandshake) + { + socket.checkHandshakeDone(); + } + if (buf == null) + throw new NullPointerException(); + if (off < 0 || len < 0 || off + len > buf.length) + throw new ArrayIndexOutOfBoundsException(); + checkAlert(); + out.write(buf, off, len); + checkAlert(); + } + + // Own methods. + // ------------------------------------------------------------------------- + + private synchronized void checkAlert() throws SSLException + { + Alert alert = socket.checkAlert(); + if (alert == null) return; + if (alert.getLevel().equals(Alert.Level.FATAL)) + throw new AlertException(alert, false); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SecurityParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/SecurityParameters.java new file mode 100644 index 00000000000..aa06680e200 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SecurityParameters.java @@ -0,0 +1,178 @@ +/* SecurityParameters.java -- SSL security parameters. + Copyright (C) 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.net.ssl.provider; + +import javax.net.ssl.SSLException; + +/** + * The interface that all security parameters used by Jessie must implement. + * Security parameters handle all transforming of data, including encryption, + * authentication, and compression. + */ +interface SecurityParameters +{ + + // Methods. + // ------------------------------------------------------------------------- + + /** + * Decrypts, verifies, and inflates a fragment received. The fragment is + * just the data field of a text object, without the version, type, and + * length fields. An exception is thrown if any step fails. + * + * @param fragment The fragment being decrypted. + * @param version The version field of the received text. + * @param type The type field of the received text. + * @return The decrypted fragment. + * @throws MacException If the MAC could not be verified, or if the padding + * on the decrypted fragment is incorrect. + * @throws OverflowException If the processed text overflows the configured + * maximum fragment size. + * @throws SSLException If any other error occurs. + */ + byte[] decrypt (byte[] fragment, ProtocolVersion version, ContentType type) + throws MacException, OverflowException, SSLException; + + /** + * Deflates, authenticates, and encrypts a fragment to be sent. + * + * @param buf The fragment being encrypted. + * @param off The offset into the buffer to start at. + * @param len The number of bytes in this fragment. + * @param type The content type of this text. + * @return The encrypted fragment. + * @throws OverflowException If deflating increases the size of the fragment + * too much. + * @throws SSLException If any other error occurs. + */ + byte[] encrypt (byte[] buf, int off, int len, ContentType type) + throws OverflowException, SSLException; + + /** + * Set all crypto primitives to <code>null</code>, meaning that any calls + * to {@link #encrypt(byte[],int,int,org.metastatic.jessie.provider.ContentType)} or + * {@link #decrypt(byte[],org.metastatic.jessie.provider.ProtocolVersion,org.metastatic.jessie.provider.ContentType}) + * will perform the identity transformation. + */ + void reset(); + + /** + * Returns the version of texts being sent. + * + * @return The version. + */ + ProtocolVersion getVersion(); + + /** + * Sets the version of texts being sent. This affects the {@link + * #encrypt(byte[],int,int,org.metastatic.jessie.provider.ContentType)} + * method. + * + * @param version The version to set. + */ + void setVersion (ProtocolVersion version); + + /** + * Turns zlib deflating on or off. + * + * @param deflate Whether or not to deflate outgoing fragments. + */ + void setDeflating (boolean deflate); + + /** + * Turns zlib inflating on or off. + * + * @param inflate Whether or not to inflate incoming fragments. + */ + void setInflating (boolean inflate); + + /** + * Returns the maximum size that plaintext fragments may be. + * + * @return The fragment length. + */ + int getFragmentLength(); + + /** + * Sets the maximum size that plaintext fragments may be. + * + * @param fragmentLength The new fragment length. + */ + void setFragmentLength (int fragmentLength); + + /** + * Set the cipher used to decrypt incoming fragments. The parameter must be + * appropriate for the implementation. + * + * @param cipher The cipher. + * @throws ClassCastException If the argument is not appropriate for the + * implementation. + */ + void setInCipher (Object cipher); + + /** + * Set the cipher used to encrypt outgoing fragments. The parameter must be + * appropriate for the implementation. + * + * @param cipher The cipher. + * @throws ClassCastException If the argument is not appropriate for the + * implementation. + */ + void setOutCipher (Object cipher); + + /** + * Set the MAC used to verify incoming fragments. The parameter must be + * appropriate for the implementation. + * + * @param mac The MAC. + * @throws ClassCastException If the argument is not appropriate for the + * implementation. + */ + void setInMac (Object mac); + + /** + * Set the MAC used to authenticating outgoinging fragments. The parameter + * must be appropriate for the implementation. + * + * @param mac The MAC. + * @throws ClassCastException If the argument is not appropriate for the + * implementation. + */ + void setOutMac (Object mac); +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerHello.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHello.java new file mode 100644 index 00000000000..8b7853c7f40 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHello.java @@ -0,0 +1,216 @@ +/* ServerHello.java -- SSL ServerHello message. + Copyright (C) 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.net.ssl.provider; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.StringWriter; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import javax.net.ssl.SSLProtocolException; + +class ServerHello implements Handshake.Body +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final ProtocolVersion version; + private final Random random; + private final byte[] sessionId; + private final CipherSuite suite; + private final CompressionMethod comp; + private final List extensions; + + // Constructor. + // ------------------------------------------------------------------------- + + ServerHello(ProtocolVersion version, Random random, + byte[] sessionId, CipherSuite suite, + CompressionMethod comp) + { + this(version, random, sessionId, suite, comp, null); + } + + ServerHello(ProtocolVersion version, Random random, + byte[] sessionId, CipherSuite suite, + CompressionMethod comp, List extensions) + { + this.version = version; + this.random = random; + this.sessionId = sessionId; + this.suite = suite; + this.comp = comp; + this.extensions = extensions; + } + + // Class methods. + // ------------------------------------------------------------------------- + + static ServerHello read(InputStream in) throws IOException + { + ProtocolVersion vers = ProtocolVersion.read(in); + Random rand = Random.read(in); + byte[] id = new byte[in.read() & 0xFF]; + in.read(id); + CipherSuite suite = CipherSuite.read(in).resolve(vers); + CompressionMethod comp = CompressionMethod.read(in); + List ext = null; + if (in.available() > 0) + { + ext = new LinkedList(); + int len = (in.read() >>> 8 & 0xFF) | (in.read() & 0xFF); + int count = 0; + while (count < len) + { + Extension e = Extension.read(in); + ext.add(e); + count += e.getValue().length + 4; + } + } + return new ServerHello(vers, rand, id, suite, comp, ext); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + version.write(out); + random.write(out); + out.write(sessionId.length); + out.write(sessionId); + suite.write(out); + out.write(comp.getValue()); + if (extensions != null) + { + ByteArrayOutputStream out2 = new ByteArrayOutputStream(); + for (Iterator i = extensions.iterator(); i.hasNext(); ) + ((Extension) i.next()).write(out2); + out.write(out2.size() >>> 8 & 0xFF); + out.write(out2.size() & 0xFF); + out2.writeTo(out); + } + } + + ProtocolVersion getVersion() + { + return version; + } + + Random getRandom() + { + return random; + } + + byte[] getSessionId() + { + return (byte[]) sessionId.clone(); + } + + CipherSuite getCipherSuite() + { + return suite; + } + + CompressionMethod getCompressionMethod() + { + return comp; + } + + List getExtensions() + { + return extensions; + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println("struct {"); + out.println(" version = " + version + ";"); + BufferedReader r = new BufferedReader(new StringReader(random.toString())); + String s; + try + { + while ((s = r.readLine()) != null) + { + out.print(" "); + out.println(s); + } + } + catch (IOException ignored) + { + } + out.println(" sessionId = " + Util.toHexString(sessionId, ':') + ";"); + out.println(" cipherSuite = " + suite + ";"); + out.println(" compressionMethod = " + comp + ";"); + if (extensions != null) + { + out.println(" extensions = {"); + for (Iterator i = extensions.iterator(); i.hasNext(); ) + { + r = new BufferedReader(new StringReader(i.next().toString())); + try + { + while ((s = r.readLine()) != null) + { + out.print(" "); + out.println(s); + } + } + catch (IOException ignored) + { + } + } + out.println(" };"); + } + out.println("} ServerHello;"); + return str.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchange.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchange.java new file mode 100644 index 00000000000..58304159300 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchange.java @@ -0,0 +1,286 @@ +/* ServerKeyExchange.java -- SSL ServerKeyExchange message. + Copyright (C) 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.net.ssl.provider; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.StringWriter; + +import java.math.BigInteger; + +import java.security.PublicKey; +import java.security.interfaces.RSAPublicKey; + +import javax.crypto.interfaces.DHPublicKey; +import javax.crypto.spec.DHParameterSpec; + +import javax.net.ssl.SSLProtocolException; + +import gnu.javax.crypto.key.dh.GnuDHPublicKey; +import gnu.javax.crypto.key.srp6.SRPPublicKey; + +class ServerKeyExchange implements Handshake.Body +{ + + // Fields. + // ------------------------------------------------------------------------- + + private PublicKey publicKey; + private Signature signature; + private byte[] srpSalt; + + // Constructor. + // ------------------------------------------------------------------------- + + ServerKeyExchange(PublicKey publicKey, Signature signature) + { + this(publicKey, signature, null); + } + + ServerKeyExchange(PublicKey publicKey, Signature signature, byte[] srpSalt) + { + this.publicKey = publicKey; + this.signature = signature; + this.srpSalt = srpSalt; + } + + // Class methods. + // ------------------------------------------------------------------------- + + static ServerKeyExchange read(InputStream in, CipherSuite suite, + PublicKey serverKey) + throws IOException + { + DataInputStream din = new DataInputStream(in); + PublicKey key = null; + byte[] salt = null; + String kex = suite.getKeyExchange(); + if (kex.equals("DHE")) + { + BigInteger p, g, y; + byte[] buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + p = new BigInteger(1, buf); + buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + g = new BigInteger(1, buf); + buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + y = new BigInteger(1, buf); + key = new GnuDHPublicKey(null, p, g, y); + } + else if (kex.equals("RSA")) + { + BigInteger n, e; + byte[] buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + n = new BigInteger(1, buf); + buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + e = new BigInteger(1, buf); + key = new JessieRSAPublicKey(n, e); + } + else if (kex.equals("SRP")) + { + BigInteger N, g, B; + byte[] buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + N = new BigInteger(1, buf); + buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + g = new BigInteger(1, buf); + salt = new byte[din.readUnsignedByte()]; + din.readFully(salt); + buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + B = new BigInteger(1, buf); + try + { + key = new SRPPublicKey(N, g, B); + } + catch (IllegalArgumentException iae) + { + throw new SSLProtocolException(iae.getMessage()); + } + } + else + { + throw new SSLProtocolException("invalid kex algorithm"); + } + + Signature sig = null; + if (!suite.getSignature().equals("anon")) + { + sig = Signature.read(in, suite, serverKey); + } + return new ServerKeyExchange(key, sig, salt); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + write(out, ProtocolVersion.TLS_1); + } + + public void write(OutputStream out, ProtocolVersion version) + throws IOException + { + if (publicKey instanceof DHPublicKey) + { + writeBigint(out, ((DHPublicKey) publicKey).getParams().getP()); + writeBigint(out, ((DHPublicKey) publicKey).getParams().getG()); + writeBigint(out, ((DHPublicKey) publicKey).getY()); + } + else if (publicKey instanceof RSAPublicKey) + { + writeBigint(out, ((RSAPublicKey) publicKey).getModulus()); + writeBigint(out, ((RSAPublicKey) publicKey).getPublicExponent()); + } + else if (publicKey instanceof SRPPublicKey) + { + writeBigint(out, ((SRPPublicKey) publicKey).getN()); + writeBigint(out, ((SRPPublicKey) publicKey).getG()); + out.write(srpSalt.length); + out.write(srpSalt); + writeBigint(out, ((SRPPublicKey) publicKey).getY()); + } + if (signature != null) + { + signature.write(out, version); + } + } + + PublicKey getPublicKey() + { + return publicKey; + } + + Signature getSignature() + { + return signature; + } + + byte[] getSRPSalt() + { + return srpSalt; + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println("struct {"); + out.println(" publicKey = struct {"); + if (publicKey instanceof DHPublicKey) + { + out.println(" p = " + + ((DHPublicKey) publicKey).getParams().getP().toString(16) + + ";"); + out.println(" g = " + + ((DHPublicKey) publicKey).getParams().getG().toString(16) + + ";"); + out.println(" y = " + ((DHPublicKey) publicKey).getY().toString(16) + + ";"); + out.println(" } DHPublicKey;"); + } + else if (publicKey instanceof RSAPublicKey) + { + out.println(" modulus = " + + ((RSAPublicKey) publicKey).getModulus().toString(16) + + ";"); + out.println(" exponent = " + + ((RSAPublicKey) publicKey).getPublicExponent().toString(16) + + ";"); + out.println(" } RSAPublicKey;"); + } + else if (publicKey instanceof SRPPublicKey) + { + out.println(" N = "+((SRPPublicKey) publicKey).getN().toString(16)+";"); + out.println(" g = "+((SRPPublicKey) publicKey).getG().toString(16)+";"); + out.println(" salt = " + Util.toHexString(srpSalt, ':') + ";"); + out.println(" B = "+((SRPPublicKey) publicKey).getY().toString(16)+";"); + out.println(" } SRPPublicKey;"); + } + if (signature != null) + { + out.println(" signature ="); + BufferedReader r = new BufferedReader(new StringReader(signature.toString())); + String s; + try + { + while ((s = r.readLine()) != null) + { + out.print(" "); + out.println(s); + } + } + catch (IOException ignored) + { + } + } + out.println("} ServerKeyExchange;"); + return str.toString(); + } + + private void writeBigint(OutputStream out, BigInteger bigint) + throws IOException + { + byte[] b = bigint.toByteArray(); + if (b[0] == 0x00) + { + out.write((b.length - 1) >>> 8 & 0xFF); + out.write((b.length - 1) & 0xFF); + out.write(b, 1, b.length - 1); + } + else + { + out.write(b.length >>> 8 & 0xFF); + out.write(b.length & 0xFF); + out.write(b); + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Session.java b/libjava/classpath/gnu/javax/net/ssl/provider/Session.java new file mode 100644 index 00000000000..e13758b0330 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Session.java @@ -0,0 +1,381 @@ +/* Session.java -- SSL and TLS session data. + Copyright (C) 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.net.ssl.provider; + +import java.security.SecureRandom; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLPermission; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSessionBindingEvent; +import javax.net.ssl.SSLSessionBindingListener; +import javax.net.ssl.SSLSessionContext; +import javax.net.ssl.X509KeyManager; +import javax.net.ssl.X509TrustManager; +import javax.security.cert.X509Certificate; + +import gnu.javax.net.ssl.SRPTrustManager; + +/** + * A generic SSL session implementation for SSL and TLS. + */ +final class Session implements SSLSession +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + private static final SSLPermission GET_SESSION_CONTEXT_PERMISSION = + new SSLPermission("getSSLSessionContext"); + + private final long creationTime; + private Date lastAccessedTime; + ID sessionId; + Certificate[] localCerts; + Certificate[] peerCerts; + X509Certificate[] peerCertChain; + String peerHost; + boolean peerVerified; + SessionContext context; + HashMap values; + boolean valid; + List enabledSuites; + CipherSuite cipherSuite; + SortedSet enabledProtocols; + ProtocolVersion protocol; + byte[] masterSecret; + SRPTrustManager srpTrustManager; + X509TrustManager trustManager; + X509KeyManager keyManager; + SecureRandom random; + SecurityParameters params; + Alert currentAlert; + + // Constructor. + // ------------------------------------------------------------------------- + + Session() + { + this(System.currentTimeMillis()); + } + + Session(long creationTime) + { + peerVerified = false; + valid = true; + this.creationTime = creationTime; + lastAccessedTime = new Date(0L); + values = new HashMap(); + if (("true").equalsIgnoreCase (Util.getSecurityProperty ("jessie.with.jce"))) + params = new JCESecurityParameters(); + else + params = new GNUSecurityParameters (this); + } + + // Public instance methods. + // ------------------------------------------------------------------------- + + protected Object clone() + { + Session result = new Session(creationTime); + result.lastAccessedTime = lastAccessedTime; + result.sessionId = sessionId; + result.localCerts = (localCerts != null ? (Certificate[]) localCerts.clone() : null); + result.peerCerts = (peerCerts != null ? (Certificate[]) peerCerts.clone() : null); + result.peerHost = peerHost; + result.peerVerified = peerVerified; + result.context = context; + result.values = values; + result.enabledSuites = new ArrayList(enabledSuites); + result.cipherSuite = cipherSuite; + result.enabledProtocols = new TreeSet(enabledProtocols); + result.protocol = protocol; + result.masterSecret = masterSecret; + result.keyManager = keyManager; + result.srpTrustManager = srpTrustManager; + result.trustManager = trustManager; + result.random = random; + return result; + } + + public String getCipherSuite() + { + return cipherSuite.toString(); + } + + public long getCreationTime() + { + return creationTime; + } + + public byte[] getId() + { + return (sessionId != null ? sessionId.getId() : null); + } + + public long getLastAccessedTime() + { + return lastAccessedTime.getTime(); + } + + public Certificate[] getLocalCertificates() + { + return (Certificate[]) (localCerts != null ? localCerts.clone() : null); + } + + public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException + { + if (!peerVerified) + { + throw new SSLPeerUnverifiedException("peer not verified"); + } + return (Certificate[]) (peerCerts != null ? peerCerts.clone() : null); + } + + public X509Certificate[] getPeerCertificateChain() + throws SSLPeerUnverifiedException + { + if (!peerVerified) + { + throw new SSLPeerUnverifiedException("peer not verified"); + } + if (peerCerts == null) + { + return null; + } + if (peerCertChain != null) + { + return (X509Certificate[]) peerCertChain.clone(); + } + try + { + peerCertChain = new X509Certificate[peerCerts.length]; + for (int i = 0; i < peerCerts.length; i++) + { + peerCertChain[i] = X509Certificate.getInstance(peerCerts[i].getEncoded()); + } + return (X509Certificate[]) peerCertChain.clone(); + } + catch (javax.security.cert.CertificateException ce) + { + return null; + } + catch (CertificateException ce2) + { + return null; + } + } + + public String getPeerHost() + { + return peerHost; + } + + public String getProtocol() + { + return protocol.toString(); + } + + public SSLSessionContext getSessionContext() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + { + sm.checkPermission(GET_SESSION_CONTEXT_PERMISSION); + } + return context; + } + + public String[] getValueNames() + { + Set names = values.keySet(); + return (String[]) names.toArray(new String[names.size()]); + } + + public Object getValue(String name) + { + return values.get(name); + } + + public void putValue(String name, Object value) + { + values.put(name, value); + if (value instanceof SSLSessionBindingListener) + { + ((SSLSessionBindingListener) value).valueBound( + new SSLSessionBindingEvent(this, name)); + } + } + + public void removeValue(String name) + { + Object value = values.remove(name); + if (value != null && (value instanceof SSLSessionBindingListener)) + { + ((SSLSessionBindingListener) value).valueUnbound( + new SSLSessionBindingEvent(this, name)); + } + } + + public void invalidate() + { + if (masterSecret != null) + { + for (int i = 0; i < masterSecret.length; i++) + { + masterSecret[i] = 0; + } + masterSecret = null; + } + valid = false; + } + + synchronized void access() + { + lastAccessedTime.setTime(System.currentTimeMillis()); + context.notifyAccess(this); + } + + void setLastAccessedTime(long lastAccessedTime) + { + this.lastAccessedTime.setTime(lastAccessedTime); + } + + // Inner classes. + // ------------------------------------------------------------------------- + + /** + * A byte array with appropriate <code>equals()</code>, + * <code>hashCode()</code>, and <code>compareTo()</code> semantics. + */ + static final class ID implements Comparable + { + + // Fields. + // ----------------------------------------------------------------------- + + /** The ID itself. */ + private final byte[] id; + + // Constructor. + // ----------------------------------------------------------------------- + + /** + * Creates a new ID. + * + * @param id The ID. The array is not cloned. + */ + ID(byte[] id) + { + if (id == null) + { + throw new IllegalArgumentException(); + } + this.id = id; + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public byte[] getId() + { + return (byte[]) id.clone(); + } + + public boolean equals(Object other) + { + if (other == null || !(other instanceof ID)) + { + return false; + } + return Arrays.equals(id, ((ID) other).id); + } + + public int hashCode() + { + int code = 0; + for (int i = 0; i < id.length; i++) + { + code |= (id[i] & 0xFF) << ((i & 3) << 3); + } + return code; + } + + public int compareTo(Object other) + { + if (other == null || !(other instanceof ID)) + { + return 1; + } + byte[] id2 = ((ID) other).id; + if (id.length != id2.length) + { + return (id.length < id2.length) ? -1 : 1; + } + for (int i = 0; i < id.length; i++) + { + if (id[i] < id2[i]) + { + return -1; + } + else if (id[i] > id2[i]) + { + return 1; + } + } + return 0; + } + + public String toString() + { + return Util.toHexString(id, ':'); + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SessionContext.java b/libjava/classpath/gnu/javax/net/ssl/provider/SessionContext.java new file mode 100644 index 00000000000..9e265429aab --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SessionContext.java @@ -0,0 +1,250 @@ +/* SessionContext.java -- Implementation of a session context. + Copyright (C) 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.net.ssl.provider; + +import java.security.Security; + +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Vector; + +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSessionContext; + +/** + * A collection of SSL sessions. This implementation is a memory-only + * store; subclasses may implement persistent storage. + */ +class SessionContext implements SSLSessionContext +{ + + // Fields. + // ------------------------------------------------------------------------- + + /** The map of Session.ID objects to Sessions. */ + protected final HashMap sessions; + + /** The number of sessions to cache. */ + protected int cacheSize; + + /** The session timeout, in seconds. */ + protected int timeout; + + // Constructor. + // ------------------------------------------------------------------------- + + SessionContext() + { + sessions = new HashMap(); + cacheSize = 0; + try + { + timeout = Integer.parseInt(Util.getSecurityProperty("jessie.session.timeout")); + } + catch (Exception x) + { + // Default 24-hour timeout. + timeout = 86400; + } + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public synchronized Enumeration getIds() + { + Vector ids = new Vector(); + for(Iterator i = sessions.keySet().iterator(); i.hasNext(); ) + { + Session.ID id = (Session.ID) i.next(); + ids.add(id.getId()); + } + return ids.elements(); + } + + public synchronized SSLSession getSession(byte[] sessionId) + { + Session session = (Session) sessions.get(new Session.ID(sessionId)); + if (session == null) + return null; + long elapsed = System.currentTimeMillis() - session.getLastAccessedTime(); + if ((int) (elapsed / 1000) > timeout) + { + removeSession(session.sessionId); + session.invalidate(); + return null; + } + if (!session.valid) + { + removeSession(session.sessionId); + session.invalidate(); + return null; + } + return session; + } + + public int getSessionCacheSize() + { + return cacheSize; + } + + public void setSessionCacheSize(int cacheSize) + { + if (cacheSize < 0) + throw new IllegalArgumentException(); + this.cacheSize = cacheSize; + } + + public int getSessionTimeout() + { + return timeout; + } + + public void setSessionTimeout(int timeout) + { + if (timeout <= 0) + throw new IllegalArgumentException(); + this.timeout = timeout; + } + + public String toString() + { + return sessions.keySet().toString(); + } + + // Package methods. + // ------------------------------------------------------------------------- + + /** + * Adds a session to this context. This method: + * + * <ol> + * <li>Will do nothing if the cache already contains the given ID.</li> + * <li>Will do nothing if the cache limit has been reached (and is + * not zero).</li> + * <li>Will remove any invalid sessions in the cache before trying to insert + * the new one.</li> + * <li>Will remove any expired sessions before trying to insert the new + * one.</li> + * </ol> + * + * @param sessionId This session's ID. + * @param session The session to add. + * @return True if the session was added, false otherwise. + */ + synchronized boolean addSession(Session.ID sessionId, Session session) + { + if (sessions.containsKey(sessionId)) + return false; + if (cacheSize > 0 && sessions.size() > cacheSize) + { + boolean removed = false; + for (Iterator i = sessions.values().iterator(); i.hasNext(); ) + { + Session s = (Session) i.next(); + long elapsed = System.currentTimeMillis() - s.getCreationTime(); + if (!s.valid) + { + removeSession(session.sessionId); + removed = true; + } + else if ((int) (elapsed / 1000) > timeout) + { + removeSession(session.sessionId); + removed = true; + } + } + if (removed) + { + sessions.put(sessionId, session); + session.context = this; + session.sessionId = sessionId; + return true; + } + return false; + } + else + { + sessions.put(sessionId, session); + session.context = this; + session.sessionId = sessionId; + return true; + } + } + + /** + * Returns whether or not a session with the given ID is cached by this + * context. + */ + synchronized boolean containsSessionID(Session.ID sessionId) + { + Session s = (Session) sessions.get(sessionId); + if (s == null) + { + return false; + } + long elapsed = System.currentTimeMillis() - s.getCreationTime(); + if (!s.valid || (int) (elapsed / 1000) > timeout) + { + removeSession(sessionId); + return false; + } + return true; + } + + /** + * Removes a session from this context. + * + * @param sessionId The ID of the session to remove. + */ + synchronized boolean removeSession(Session.ID sessionId) + { + return sessions.remove(sessionId) != null; + } + + /** + * Notifies this context of an access event on a session. + * + * @param session The session that was accessed. + */ + void notifyAccess(Session session) + { + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Signature.java b/libjava/classpath/gnu/javax/net/ssl/provider/Signature.java new file mode 100644 index 00000000000..c9be641431f --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Signature.java @@ -0,0 +1,158 @@ +/* Signature.java -- SSL signature message. + Copyright (C) 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.net.ssl.provider; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; + +import java.math.BigInteger; + +import java.security.PublicKey; +import java.security.interfaces.RSAKey; + +import java.util.Arrays; + +import gnu.java.security.der.*; + +class Signature implements Constructed +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final Object sigValue; + private final String sigAlg; + + // Constructor. + // ------------------------------------------------------------------------- + + Signature(Object sigValue, String sigAlg) + { + this.sigValue = sigValue; + this.sigAlg = sigAlg; + } + + // Class method. + // ------------------------------------------------------------------------- + + static Signature read(InputStream in, CipherSuite suite, PublicKey key) + throws IOException + { + Object sigValue = null; + DataInputStream din = new DataInputStream(in); + int len = din.readUnsignedShort(); + sigValue = new byte[len]; + din.readFully((byte[]) sigValue); + if (suite.getSignature() == "DSS") + { + DERReader der = new DERReader(new ByteArrayInputStream((byte[]) sigValue)); + if (der.read().getTag() != DER.SEQUENCE) + { + throw new IOException("expecting DER SEQUENCE"); + } + BigInteger r = (BigInteger) der.read().getValue(); + BigInteger s = (BigInteger) der.read().getValue(); + sigValue = new BigInteger[] { r, s }; + } + return new Signature(sigValue, suite.getSignature()); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + write(out, ProtocolVersion.TLS_1); + } + + public void write(OutputStream out, ProtocolVersion version) + throws IOException + { + byte[] result = null; + if (sigValue instanceof byte[]) + { + result = (byte[]) sigValue; + } + else + { + DERValue r = new DERValue(DER.INTEGER, ((BigInteger[]) sigValue)[0]); + DERValue s = new DERValue(DER.INTEGER, ((BigInteger[]) sigValue)[1]); + DERValue sig = new DERValue(DER.SEQUENCE|DER.CONSTRUCTED, + Arrays.asList(new Object[] { r, s })); + result = sig.getEncoded(); + } + out.write(result.length >>> 8 & 0xFF); + out.write(result.length & 0xFF); + out.write(result); + } + + Object getSigValue() + { + return sigValue; + } + + String getSigAlg() + { + return sigAlg; + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println("struct {"); + if (sigAlg.equals("RSA")) + { + out.print(Util.hexDump((byte[]) sigValue, " ")); + } + else + { + out.println(" r = " + ((BigInteger[]) sigValue)[0].toString(16) + ";"); + out.println(" s = " + ((BigInteger[]) sigValue)[1].toString(16) + ";"); + } + out.println("} Signature;"); + return str.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SynchronizedRandom.java b/libjava/classpath/gnu/javax/net/ssl/provider/SynchronizedRandom.java new file mode 100644 index 00000000000..4e22f08be08 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SynchronizedRandom.java @@ -0,0 +1,104 @@ +/* SynchronizedRandom.java -- Thread-safe IRandom wrapper. + Copyright (C) 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.net.ssl.provider; + +import java.util.Map; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; + +class SynchronizedRandom implements IRandom +{ + + // Field. + // ------------------------------------------------------------------------- + + private final IRandom random; + + // Constructor. + // ------------------------------------------------------------------------- + + SynchronizedRandom(IRandom random) + { + this.random = random; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String name() + { + return random.name(); + } + + public synchronized void init(Map attrib) + { + random.init(attrib); + } + + public synchronized byte nextByte() + throws IllegalStateException, LimitReachedException + { + return random.nextByte(); + } + + public synchronized void nextBytes(byte[] buf, int off, int len) + throws IllegalStateException, LimitReachedException + { + random.nextBytes(buf, off, len); + } + + public synchronized Object clone() + throws CloneNotSupportedException + { + return new SynchronizedRandom((IRandom) random.clone()); + } + + // For future versions of GNU Crypto. No-ops. + public void addRandomByte (byte b) + { + } + + public void addRandomBytes(byte[] buffer) { + addRandomBytes(buffer, 0, buffer.length); + } + + public void addRandomBytes (byte[] b, int i, int j) + { + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/TLSHMac.java b/libjava/classpath/gnu/javax/net/ssl/provider/TLSHMac.java new file mode 100644 index 00000000000..18aa8f5f4c7 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/TLSHMac.java @@ -0,0 +1,138 @@ +/* TLSHMac.java -- HMAC used in TLS. + Copyright (C) 2001, 2002, 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.net.ssl.provider; + +import java.security.InvalidKeyException; +import java.util.HashMap; +import java.util.Map; + +import gnu.java.security.hash.IMessageDigest; +import gnu.javax.crypto.mac.HMac; + +/** + * The operation of this HMac is identical to normal HMacs, but this one + * allows keys with short lengths (including zero). + */ +class TLSHMac extends HMac +{ + + // Constants. + // ------------------------------------------------------------------------- + + private static final byte IPAD_BYTE = 0x36; + private static final byte OPAD_BYTE = 0x5C; + + // Constructor. + // ------------------------------------------------------------------------- + + TLSHMac(IMessageDigest hash) + { + super(hash); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void init(Map attributes) + throws InvalidKeyException, IllegalStateException + { + Integer ts = (Integer) attributes.get(TRUNCATED_SIZE); + truncatedSize = (ts == null ? macSize : ts.intValue()); + if (truncatedSize < (macSize / 2)) { + throw new IllegalArgumentException("Truncated size too small"); + } else if (truncatedSize < 10) { + throw new IllegalArgumentException("Truncated size less than 80 bits"); + } + + // we dont use/save the key outside this method + byte[] K = (byte[]) attributes.get(MAC_KEY_MATERIAL); + if (K == null) { // take it as an indication to re-use previous key if set + if (ipadHash == null) + { + throw new InvalidKeyException("Null key"); + } + // we already went through the motions; ie. up to step #4. re-use + underlyingHash = (IMessageDigest) ipadHash.clone(); + return; + } + + if (K.length > blockSize) + { + // (0) replace K with HASH(K) if K is larger than the hash's + // block size. Then pad with zeros until it is the correct + // size (the next `if'). + underlyingHash.update(K, 0, K.length); + K = underlyingHash.digest(); + } + if (K.length < blockSize) + { + // (1) append zeros to the end of K to create a B byte string + // (e.g., if K is of length 20 bytes and B=64, then K will be + // appended with 44 zero bytes 0x00) + int limit = (K.length > blockSize) ? blockSize : K.length; + byte[] newK = new byte[blockSize]; + System.arraycopy(K, 0, newK, 0, limit); + K = newK; + } + + underlyingHash.reset(); + opadHash = (IMessageDigest) underlyingHash.clone(); + if (ipad == null) + { + ipad = new byte[blockSize]; + } + // (2) XOR (bitwise exclusive-OR) the B byte string computed in step + // (1) with ipad + // (3) append the stream of data 'text' to the B byte string resulting + // from step (2) + // (4) apply H to the stream generated in step (3) + for (int i = 0; i < blockSize; i++) + { + ipad[i] = (byte)(K[i] ^ IPAD_BYTE); + } + for (int i = 0; i < blockSize; i++) + { + opadHash.update((byte)(K[i] ^ OPAD_BYTE)); + } + + underlyingHash.update(ipad, 0, blockSize); + ipadHash = (IMessageDigest) underlyingHash.clone(); + K = null; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/TLSRandom.java b/libjava/classpath/gnu/javax/net/ssl/provider/TLSRandom.java new file mode 100644 index 00000000000..ded632928f1 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/TLSRandom.java @@ -0,0 +1,252 @@ +/* TLSRandom.java -- The TLS pseudo-random function. + Copyright (C) 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.net.ssl.provider; + +import java.security.InvalidKeyException; +import java.util.HashMap; +import java.util.Map; + +import gnu.java.security.hash.HashFactory; +import gnu.javax.crypto.mac.IMac; +import gnu.java.security.prng.IRandom; + +class TLSRandom implements IRandom +{ + + // Fields. + // ------------------------------------------------------------------------- + + /** + * Property name for the secret that will be used to initialize the HMACs. + */ + static final String SECRET = "jessie.tls.prng.secret"; + + /** + * Property name for the seed. + */ + static final String SEED = "jessie.tls.prng.seed"; + + private final IMac hmac_sha, hmac_md5; + private byte[] sha_a, md5_a; + private byte[] seed; + private final byte[] buffer; + private int idx; + private boolean init; + + // Constructors. + // ------------------------------------------------------------------------- + + TLSRandom() + { + hmac_sha = new TLSHMac(HashFactory.getInstance("SHA1")); + hmac_md5 = new TLSHMac(HashFactory.getInstance("MD5")); + buffer = new byte[80]; // 80 == LCM of 16 and 20. + idx = 0; + init = false; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException shouldNotHappen) + { + throw new Error(); + } + } + + public void init(Map attributes) + { + HashMap sha_attr = new HashMap(); + HashMap md5_attr = new HashMap(); + byte[] secret = (byte[]) attributes.get(SECRET); + if (secret != null) + { + int l = (secret.length >>> 1) + (secret.length & 1); + byte[] s1 = Util.trim(secret, 0, l); + byte[] s2 = Util.trim(secret, secret.length - l, l); + md5_attr.put(IMac.MAC_KEY_MATERIAL, s1); + sha_attr.put(IMac.MAC_KEY_MATERIAL, s2); + try + { + hmac_md5.init(md5_attr); + hmac_sha.init(sha_attr); + } + catch (InvalidKeyException ike) + { + throw new Error(ike.toString()); + } + } + else if (!init) + { + throw new IllegalArgumentException("no secret supplied"); + } + // else re-use + + byte[] seeed = (byte[]) attributes.get(SEED); + if (seeed != null) + { + seed = (byte[]) seeed.clone(); + } + else if (!init) + { + throw new IllegalArgumentException("no seed supplied"); + } + // else re-use + + // A(0) is the seed, A(1) = HMAC_hash(secret, A(0)). + hmac_md5.update(seed, 0, seed.length); + md5_a = hmac_md5.digest(); + hmac_md5.reset(); + hmac_sha.update(seed, 0, seed.length); + sha_a = hmac_sha.digest(); + hmac_sha.reset(); + fillBuffer(); + init = true; + } + + public String name() + { + return "TLSRandom"; + } + + public byte nextByte() + { + if (!init) + throw new IllegalStateException(); + if (idx >= buffer.length) + fillBuffer(); + return buffer[idx++]; + } + + public void nextBytes(byte[] buf, int off, int len) + { + if (!init) + throw new IllegalStateException(); + if (buf == null) + throw new NullPointerException(); + if (off < 0 || off > buf.length || off + len > buf.length) + throw new ArrayIndexOutOfBoundsException(); + int count = 0; + if (idx >= buffer.length) + fillBuffer(); + while (count < len) + { + int l = Math.min(buffer.length-idx, len-count); + System.arraycopy(buffer, idx, buf, off+count, l); + idx += l; + count += l; + if (count < len && idx >= buffer.length) + fillBuffer(); + } + } + + // For future versions of GNU Crypto. No-ops. + public void addRandomByte (byte b) + { + } + + public void addRandomBytes(byte[] buffer) { + addRandomBytes(buffer, 0, buffer.length); + } + + public void addRandomBytes (byte[] b, int i, int j) + { + } + + // Own methods. + // ------------------------------------------------------------------------- + + /* + * The PRF is defined as: + * + * PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR + * P_SHA-1(S2, label + seed); + * + * P_hash is defined as: + * + * P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) + + * HMAC_hash(secret, A(2) + seed) + + * HMAC_hash(secret, A(3) + seed) + ... + * + * And A() is defined as: + * + * A(0) = seed + * A(i) = HMAC_hash(secret, A(i-1)) + * + * For simplicity, we compute an 80-byte block on each call, which + * corresponds to five iterations of MD5, and four of SHA-1. + */ + private synchronized void fillBuffer() + { + int len = hmac_md5.macSize(); + for (int i = 0; i < buffer.length; i += len) + { + hmac_md5.update(md5_a, 0, md5_a.length); + hmac_md5.update(seed, 0, seed.length); + byte[] b = hmac_md5.digest(); + hmac_md5.reset(); + System.arraycopy(b, 0, buffer, i, len); + hmac_md5.update(md5_a, 0, md5_a.length); + md5_a = hmac_md5.digest(); + hmac_md5.reset(); + } + len = hmac_sha.macSize(); + for (int i = 0; i < buffer.length; i += len) + { + hmac_sha.update(sha_a, 0, sha_a.length); + hmac_sha.update(seed, 0, seed.length); + byte[] b = hmac_sha.digest(); + hmac_sha.reset(); + for (int j = 0; j < len; j++) + { + buffer[j + i] ^= b[j]; + } + hmac_sha.update(sha_a, 0, sha_a.length); + sha_a = hmac_sha.digest(); + hmac_sha.reset(); + } + idx = 0; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Util.java b/libjava/classpath/gnu/javax/net/ssl/provider/Util.java new file mode 100644 index 00000000000..15790dd26f8 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Util.java @@ -0,0 +1,422 @@ +/* Util.java -- Miscellaneous utility methods. + Copyright (C) 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.net.ssl.provider; + +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.math.BigInteger; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.Security; + +/** + * A collection of useful class methods. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +final class Util +{ + + // Constants. + // ------------------------------------------------------------------------- + + static final String HEX = "0123456789abcdef"; + + // Static methods only. + private Util() { } + + // Class methods. + // ------------------------------------------------------------------------- + + /** + * Convert a hexadecimal string into its byte representation. + * + * @param hex The hexadecimal string. + * @return The converted bytes. + */ + static byte[] toByteArray(String hex) + { + hex = hex.toLowerCase(); + byte[] buf = new byte[hex.length() / 2]; + int j = 0; + for (int i = 0; i < buf.length; i++) + { + buf[i] = (byte) ((Character.digit(hex.charAt(j++), 16) << 4) | + Character.digit(hex.charAt(j++), 16)); + } + return buf; + } + + /** + * Convert a byte array to a hexadecimal string, as though it were a + * big-endian arbitrarily-sized integer. + * + * @param buf The bytes to format. + * @param off The offset to start at. + * @param len The number of bytes to format. + * @return A hexadecimal representation of the specified bytes. + */ + static String toHexString(byte[] buf, int off, int len) + { + StringBuffer str = new StringBuffer(); + for (int i = 0; i < len; i++) + { + str.append(HEX.charAt(buf[i+off] >>> 4 & 0x0F)); + str.append(HEX.charAt(buf[i+off] & 0x0F)); + } + return str.toString(); + } + + /** + * See {@link #toHexString(byte[],int,int)}. + */ + static String toHexString(byte[] buf) + { + return Util.toHexString(buf, 0, buf.length); + } + + /** + * Convert a byte array to a hexadecimal string, separating octets + * with the given character. + * + * @param buf The bytes to format. + * @param off The offset to start at. + * @param len The number of bytes to format. + * @param sep The character to insert between octets. + * @return A hexadecimal representation of the specified bytes. + */ + static String toHexString(byte[] buf, int off, int len, char sep) + { + StringBuffer str = new StringBuffer(); + for (int i = 0; i < len; i++) + { + str.append(HEX.charAt(buf[i+off] >>> 4 & 0x0F)); + str.append(HEX.charAt(buf[i+off] & 0x0F)); + if (i < len - 1) + str.append(sep); + } + return str.toString(); + } + + /** + * See {@link #toHexString(byte[],int,int,char)}. + */ + static String toHexString(byte[] buf, char sep) + { + return Util.toHexString(buf, 0, buf.length, sep); + } + + /** + * Create a representation of the given byte array similar to the + * output of <code>`hexdump -C'</code>, which is + * + * <p><pre>OFFSET SIXTEEN-BYTES-IN-HEX PRINTABLE-BYTES</pre> + * + * <p>The printable bytes show up as-is if they are printable and + * not a newline character, otherwise showing as '.'. + * + * @param buf The bytes to format. + * @param off The offset to start at. + * @param len The number of bytes to encode. + * @param prefix A string to prepend to every line. + * @return The formatted string. + */ + static String hexDump(byte[] buf, int off, int len, String prefix) + { + String nl = getProperty("line.separator"); + StringBuffer str = new StringBuffer(); + int i = 0; + while (i < len) + { + if (prefix != null) + str.append(prefix); + str.append(Util.formatInt(i+off, 16, 8)); + str.append(" "); + String s = Util.toHexString(buf, i+off, Math.min(16, len-i), ' '); + str.append(s); + for (int j = 56 - (56 - s.length()); j < 56; j++) + str.append(" "); + for (int j = 0; j < Math.min(16, len - i); j++) + { + if ((buf[i+off+j] & 0xFF) < 0x20 || (buf[i+off+j] & 0xFF) > 0x7E) + str.append('.'); + else + str.append((char) (buf[i+off+j] & 0xFF)); + } + str.append(nl); + i += 16; + } + return str.toString(); + } + + /** + * See {@link #hexDump(byte[],int,int,String)}. + */ + static String hexDump(byte[] buf, int off, int len) + { + return hexDump(buf, off, len, ""); + } + + /** + * See {@link #hexDump(byte[],int,int,String)}. + */ + static String hexDump(byte[] buf, String prefix) + { + return hexDump(buf, 0, buf.length, prefix); + } + + /** + * See {@link #hexDump(byte[],int,int,String)}. + */ + static String hexDump(byte[] buf) + { + return hexDump(buf, 0, buf.length); + } + + /** + * Format an integer into the specified radix, zero-filled. + * + * @param i The integer to format. + * @param radix The radix to encode to. + * @param len The target length of the string. The string is + * zero-padded to this length, but may be longer. + * @return The formatted integer. + */ + static String formatInt(int i, int radix, int len) + { + String s = Integer.toString(i, radix); + StringBuffer buf = new StringBuffer(); + for (int j = 0; j < len - s.length(); j++) + buf.append("0"); + buf.append(s); + return buf.toString(); + } + + /** + * Concatenate two byte arrays into one. + * + * @param b1 The first byte array. + * @param b2 The second byte array. + * @return The concatenation of b1 and b2. + */ + static byte[] concat(byte[] b1, byte[] b2) + { + byte[] b3 = new byte[b1.length+b2.length]; + System.arraycopy(b1, 0, b3, 0, b1.length); + System.arraycopy(b2, 0, b3, b1.length, b2.length); + return b3; + } + + /** + * See {@link #trim(byte[],int,int)}. + */ + static byte[] trim(byte[] buffer, int len) + { + return trim(buffer, 0, len); + } + + /** + * Returns a portion of a byte array, possibly zero-filled. + * + * @param buffer The byte array to trim. + * @param off The offset to begin reading at. + * @param len The number of bytes to return. This value can be larger + * than <i>buffer.length - off</i>, in which case the rest of the + * returned byte array will be filled with zeros. + * @throws IndexOutOfBoundsException If <i>off</i> or <i>len</i> is + * negative, or if <i>off</i> is larger than the byte array's + * length. + * @return The trimmed byte array. + */ + static byte[] trim(byte[] buffer, int off, int len) + { + if (off < 0 || len < 0 || off > buffer.length) + throw new IndexOutOfBoundsException("max=" + buffer.length + + " off=" + off + " len=" + len); + if (off == 0 && len == buffer.length) + return buffer; + byte[] b = new byte[len]; + System.arraycopy(buffer, off, b, 0, Math.min(len, buffer.length - off)); + return b; + } + + /** + * Returns the byte array representation of the given big integer with + * the leading zero byte (if any) trimmed off. + * + * @param bi The integer to trim. + * @return The byte representation of the big integer, with any leading + * zero removed. + */ + static byte[] trim(BigInteger bi) + { + byte[] buf = bi.toByteArray(); + if (buf[0] == 0x00 && !bi.equals(BigInteger.ZERO)) + { + return trim(buf, 1, buf.length - 1); + } + else + { + return buf; + } + } + + /** + * Returns the integer value of <code>{@link + * java.lang.System#currentTimeMillis()} / 1000</code>. + * + * @return The current time, in seconds. + */ + static int unixTime() + { + return (int) (System.currentTimeMillis() / 1000L); + } + + /** + * Transform an Object array into another by calling the given method + * on each object. The returned object array will have the runtime + * type of <i>returnType</i>. For example, the following will transform + * array of objects into their String representations, returning a String + * array. For example: + * + * <blockquote><p><code> + * String[] strings = (String[]) Util.transform(array, String.class, + * "toString", null); + * </code></p></blockquote> + * + * <p>If any element of the given array is <tt>null</tt>, then that + * entry in the returned array will also be <tt>null</tt>. + * + * @param array The array to transform. It does not need to be of + * uniform type. + * @param returnType The desired return type of the returned array. + * This must by the <i>component</i> type, not the array type. + * @param method The name of the method to invoke from each object. + * @param args The arguments to pass to the method, or <tt>null</tt> + * if the method takes no arguments. + * @throws InvocationTargetException If an exception occurs while + * calling <i>method</i> of any object. + * @throws NoSuchMethodException If <i>method</i> is not the name of + * a valid method of any component of the array. + * @throws ClassCastException If the returned object from the method + * is not assignable to the return type. + * @throws IllegalArgumentException If <i>args</i> is not appropriate + * for <i>method</i> + * @throws IllegalAccessException If <i>method</i> is not accessible. + * @throws SecurityException If <i>method</i> is not accessible. + * @return An array containing the output of <i>method</i> called on + * each element of <i>array</i> with <i>args</i>. The return type + * of the array will be an array of <i>returnType</i>. + */ + static Object[] transform(Object[] array, Class returnType, + String method, Object[] args) + throws InvocationTargetException, NoSuchMethodException, + IllegalAccessException + { + if (args == null) + args = new Object[0]; + Object[] result = (Object[]) Array.newInstance(returnType, array.length); + Class[] argsClasses = new Class[args.length]; + for (int i = 0; i < args.length; i++) + { + argsClasses[i] = args[i].getClass(); + } + for (int i = 0; i < array.length; i++) + { + if (array[i] == null) + { + result[i] = null; + continue; + } + Class objClass = array[i].getClass(); + Method objMethod = objClass.getMethod(method, argsClasses); + Object o = objMethod.invoke(array[i], args); + if (!returnType.isAssignableFrom(o.getClass())) + throw new ClassCastException(); + result[i] = o; + } + return result; + } + + /** + * Get a system property as a privileged action. + * + * @param name The name of the property to get. + * @return The property named <i>name</i>, or null if the property is + * not set. + * @throws SecurityException If the Jessie code still does not have + * permission to read the property. + */ + static String getProperty(final String name) + { + return (String) AccessController.doPrivileged( + new PrivilegedAction() + { + public Object run() + { + return System.getProperty(name); + } + } + ); + } + + /** + * Get a security property as a privileged action. + * + * @param name The name of the property to get. + * @return The property named <i>name</i>, or null if the property is + * not set. + * @throws SecurityException If the Jessie code still does not have + * permission to read the property. + */ + static String getSecurityProperty(final String name) + { + return (String) AccessController.doPrivileged( + new PrivilegedAction() + { + public Object run() + { + return Security.getProperty(name); + } + } + ); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java b/libjava/classpath/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java new file mode 100644 index 00000000000..476655c45da --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java @@ -0,0 +1,359 @@ +/* X509KeyManagerFactory.java -- X.509 key manager factory. + Copyright (C) 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.net.ssl.provider; + +import java.io.FileInputStream; +import java.io.IOException; +import java.net.Socket; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Enumeration; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.Principal; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Security; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.DSAPublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.List; + +import javax.crypto.interfaces.DHPrivateKey; +import javax.crypto.interfaces.DHPublicKey; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactorySpi; +import javax.net.ssl.ManagerFactoryParameters; +import javax.net.ssl.X509KeyManager; + +import gnu.javax.net.ssl.NullManagerParameters; +import gnu.javax.net.ssl.PrivateCredentials; + +/** + * This class implements a {@link javax.net.ssl.KeyManagerFactory} engine + * for the ``JessieX509'' algorithm. + */ +public class X509KeyManagerFactory extends KeyManagerFactorySpi +{ + + // Fields. + // ------------------------------------------------------------------------- + + private Manager current; + + // Constructor. + // ------------------------------------------------------------------------- + + public X509KeyManagerFactory() + { + super(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + protected KeyManager[] engineGetKeyManagers() + { + if (current == null) + { + throw new IllegalStateException(); + } + return new KeyManager[] { current }; + } + + protected void engineInit(ManagerFactoryParameters params) + throws InvalidAlgorithmParameterException + { + if (params instanceof NullManagerParameters) + { + current = new Manager(Collections.EMPTY_MAP, Collections.EMPTY_MAP); + } + else if (params instanceof PrivateCredentials) + { + List chains = ((PrivateCredentials) params).getCertChains(); + List keys = ((PrivateCredentials) params).getPrivateKeys(); + int i = 0; + HashMap certMap = new HashMap(); + HashMap keyMap = new HashMap(); + Iterator c = chains.iterator(); + Iterator k = keys.iterator(); + while (c.hasNext() && k.hasNext()) + { + certMap.put(String.valueOf(i), c.next()); + keyMap.put(String.valueOf(i), k.next()); + i++; + } + current = new Manager(keyMap, certMap); + } + else + { + throw new InvalidAlgorithmParameterException(); + } + } + + protected void engineInit(KeyStore store, char[] passwd) + throws KeyStoreException, NoSuchAlgorithmException, + UnrecoverableKeyException + { + if (store == null) + { + String s = Util.getProperty("javax.net.ssl.keyStoreType"); + if (s == null) + s = KeyStore.getDefaultType(); + store = KeyStore.getInstance(s); + s = Util.getProperty("javax.net.ssl.keyStore"); + if (s == null) + return; + String p = Util.getProperty("javax.net.ssl.keyStorePassword"); + try + { + store.load(new FileInputStream(s), p != null ? p.toCharArray() : null); + } + catch (IOException ioe) + { + throw new KeyStoreException(ioe.toString()); + } + catch (CertificateException ce) + { + throw new KeyStoreException(ce.toString()); + } + } + + HashMap p = new HashMap(); + HashMap c = new HashMap(); + Enumeration aliases = store.aliases(); + UnrecoverableKeyException exception = null; + while (aliases.hasMoreElements()) + { + String alias = (String) aliases.nextElement(); + if (!store.isKeyEntry(alias)) + { + continue; + } + X509Certificate[] chain = null; + Certificate[] chain2 = store.getCertificateChain (alias); + if (chain2 != null && chain2.length > 0 && + (chain2[0] instanceof X509Certificate)) + { + chain = toX509Chain(chain2); + } + else + { + continue; + } + PrivateKey key = null; + try + { + key = (PrivateKey) store.getKey(alias, passwd); + } + catch (UnrecoverableKeyException uke) + { + exception = uke; + continue; + } + if (key == null) + { + continue; + } + p.put(alias, key); + c.put(alias, chain); + } + if (p.isEmpty () && c.isEmpty ()) + { + if (exception != null) + { + throw exception; + } + throw new KeyStoreException ("no private credentials found"); + } + current = this.new Manager(p, c); + } + + private static X509Certificate[] toX509Chain(Certificate[] chain) + { + if (chain instanceof X509Certificate[]) + { + return (X509Certificate[]) chain; + } + X509Certificate[] _chain = new X509Certificate[chain.length]; + for (int i = 0; i < chain.length; i++) + _chain[i] = (X509Certificate) chain[i]; + return _chain; + } + + // Inner class. + // ------------------------------------------------------------------------- + + private class Manager implements X509KeyManager + { + // Fields. + // ----------------------------------------------------------------------- + + private final Map privateKeys; + private final Map certChains; + + // Constructor. + // ----------------------------------------------------------------------- + + Manager(Map privateKeys, Map certChains) + { + this.privateKeys = privateKeys; + this.certChains = certChains; + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public String chooseClientAlias(String[] keyTypes, Principal[] issuers, + Socket socket) + { + for (int i = 0; i < keyTypes.length; i++) + { + String[] s = getClientAliases(keyTypes[i], issuers); + if (s.length > 0) + return s[0]; + } + return null; + } + + public String[] getClientAliases(String keyType, Principal[] issuers) + { + return getAliases(keyType, issuers); + } + + public String chooseServerAlias(String keyType, Principal[] issuers, + Socket socket) + { + String[] s = getServerAliases(keyType, issuers); + if (s.length > 0) + return s[0]; + return null; + } + + public String[] getServerAliases(String keyType, Principal[] issuers) + { + return getAliases(keyType, issuers); + } + + private String[] getAliases(String keyType, Principal[] issuers) + { + LinkedList l = new LinkedList(); + for (Iterator i = privateKeys.keySet().iterator(); i.hasNext(); ) + { + String alias = (String) i.next(); + X509Certificate[] chain = getCertificateChain(alias); + if (chain.length == 0) + continue; + PrivateKey privKey = getPrivateKey(alias); + if (privKey == null) + continue; + PublicKey pubKey = chain[0].getPublicKey(); + if (keyType.equals("RSA") || keyType.equals("DHE_RSA") || + keyType.equals("SRP_RSA") || keyType.equals("rsa_sign")) + { + if (!(privKey instanceof RSAPrivateKey) || + !(pubKey instanceof RSAPublicKey)) + continue; + } + if (keyType.equals("DHE_DSS") || keyType.equals("dss_sign") || + keyType.equals("SRP_DSS")) + { + if (!(privKey instanceof DSAPrivateKey) || + !(pubKey instanceof DSAPublicKey)) + continue; + } + if (keyType.equals("DH_RSA") || keyType.equals("rsa_fixed_dh")) + { + if (!(privKey instanceof DHPrivateKey) || + !(pubKey instanceof DHPublicKey)) + continue; + if (!chain[0].getSigAlgName().equalsIgnoreCase("RSA")) + continue; + } + if (keyType.equals("DH_DSS") || keyType.equals("dss_fixed_dh")) + { + if (!(privKey instanceof DHPrivateKey) || + !(pubKey instanceof DHPublicKey)) + continue; + if (!chain[0].getSigAlgName().equalsIgnoreCase("DSA")) + continue; + } + if (issuers == null || issuers.length == 0) + { + l.add(alias); + continue; + } + for (int j = 0; j < issuers.length; j++) + if (chain[0].getIssuerDN().equals(issuers[j])) + { + l.add(alias); + break; + } + } + return (String[]) l.toArray(new String[l.size()]); + } + + public X509Certificate[] getCertificateChain(String alias) + { + X509Certificate[] c = (X509Certificate[]) certChains.get(alias); + return c != null ? (X509Certificate[]) c.clone() : null; + } + + public PrivateKey getPrivateKey(String alias) + { + return (PrivateKey) privateKeys.get(alias); + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java b/libjava/classpath/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java new file mode 100644 index 00000000000..4f049e916d9 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java @@ -0,0 +1,298 @@ +/* X509TrustManagerFactory.java -- X.509 trust manager factory. + Copyright (C) 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.net.ssl.provider; + +import java.io.FileInputStream; +import java.io.IOException; + +import java.util.Arrays; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.LinkedList; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Security; +import java.security.SignatureException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import javax.net.ssl.ManagerFactoryParameters; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactorySpi; +import javax.net.ssl.X509TrustManager; + +import gnu.javax.net.ssl.NullManagerParameters; +import gnu.javax.net.ssl.StaticTrustAnchors; + +/** + * This class implements a {@link javax.net.ssl.TrustManagerFactory} engine + * for the ``JessieX509'' algorithm. + */ +public class X509TrustManagerFactory extends TrustManagerFactorySpi +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + /** + * The location of the JSSE key store. + */ + private static final String JSSE_CERTS = Util.getProperty("java.home") + + Util.getProperty("file.separator") + "lib" + + Util.getProperty("file.separator") + "security" + + Util.getProperty("file.separator") + "jssecerts"; + + /** + * The location of the system key store, containing the CA certs. + */ + private static final String CA_CERTS = Util.getProperty("java.home") + + Util.getProperty("file.separator") + "lib" + + Util.getProperty("file.separator") + "security" + + Util.getProperty("file.separator") + "cacerts"; + + private Manager current; + + // Construtors. + // ------------------------------------------------------------------------- + + public X509TrustManagerFactory() + { + super(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + protected TrustManager[] engineGetTrustManagers() + { + if (current == null) + { + throw new IllegalStateException("not initialized"); + } + return new TrustManager[] { current }; + } + + protected void engineInit(ManagerFactoryParameters params) + throws InvalidAlgorithmParameterException + { + if (params instanceof StaticTrustAnchors) + { + current = new Manager(((StaticTrustAnchors) params).getCertificates()); + } + else if (params instanceof NullManagerParameters) + { + current = new Manager(new X509Certificate[0]); + } + else + { + throw new InvalidAlgorithmParameterException(); + } + } + + protected void engineInit(KeyStore store) throws KeyStoreException + { + if (store == null) + { + String s = Util.getProperty("javax.net.ssl.trustStoreType"); + if (s == null) + s = KeyStore.getDefaultType(); + store = KeyStore.getInstance(s); + try + { + s = Util.getProperty("javax.net.ssl.trustStore"); + FileInputStream in = null; + if (s == null) + { + try + { + in = new FileInputStream(JSSE_CERTS); + } + catch (IOException e) + { + in = new FileInputStream(CA_CERTS); + } + } + else + { + in = new FileInputStream(s); + } + String p = Util.getProperty("javax.net.ssl.trustStorePassword"); + store.load(in, p != null ? p.toCharArray() : null); + } + catch (IOException ioe) + { + throw new KeyStoreException(ioe.toString()); + } + catch (CertificateException ce) + { + throw new KeyStoreException(ce.toString()); + } + catch (NoSuchAlgorithmException nsae) + { + throw new KeyStoreException(nsae.toString()); + } + } + + LinkedList l = new LinkedList(); + Enumeration aliases = store.aliases(); + while (aliases.hasMoreElements()) + { + String alias = (String) aliases.nextElement(); + if (!store.isCertificateEntry(alias)) + continue; + Certificate c = store.getCertificate(alias); + if (!(c instanceof X509Certificate)) + continue; + l.add(c); + } + current = this.new Manager((X509Certificate[]) + l.toArray(new X509Certificate[l.size()])); + } + + // Inner class. + // ------------------------------------------------------------------------- + + /** + * The actual manager implementation returned. + */ + private class Manager implements X509TrustManager + { + + // Fields. + // ----------------------------------------------------------------------- + + private final X509Certificate[] trusted; + + // Constructor. + // ----------------------------------------------------------------------- + + Manager(X509Certificate[] trusted) + { + this.trusted = trusted; + } + + // Instance methodns. + // ----------------------------------------------------------------------- + + public void checkClientTrusted(X509Certificate[] chain, String authType) + throws CertificateException + { + checkTrusted(chain, authType); + } + + public void checkServerTrusted(X509Certificate[] chain, String authType) + throws CertificateException + { + checkTrusted(chain, authType); + } + + public X509Certificate[] getAcceptedIssuers() + { + if (trusted == null) + return new X509Certificate[0]; + return (X509Certificate[]) trusted.clone(); + } + + // Own methods. + // ----------------------------------------------------------------------- + + private void checkTrusted(X509Certificate[] chain, String authType) + throws CertificateException + { + // NOTE: this is not a full-featured path validation algorithm. + // + // Step 0: check if the target is valid now. + chain[0].checkValidity(); + + // Step 1: verify that the chain is complete and valid. + for (int i = 1; i < chain.length; i++) + { + chain[i].checkValidity(); + try + { + chain[i-1].verify(chain[i].getPublicKey()); + } + catch (NoSuchAlgorithmException nsae) + { + throw new CertificateException(nsae.toString()); + } + catch (NoSuchProviderException nspe) + { + throw new CertificateException(nspe.toString()); + } + catch (InvalidKeyException ike) + { + throw new CertificateException(ike.toString()); + } + catch (SignatureException se) + { + throw new CertificateException(se.toString()); + } + } + + // Step 2: verify that the root of the chain was issued by a trust anchor. + if (trusted == null || trusted.length == 0) + throw new CertificateException("no trust anchors"); + for (int i = 0; i < trusted.length; i++) + { + try + { + trusted[i].checkValidity(); + chain[chain.length-1].verify(trusted[i].getPublicKey()); + return; + } + catch (Exception e) + { + } + //catch (CertificateException ce) { } + //catch (NoSuchAlgorithmException nsae) { } + //catch (NoSuchProviderException nspe) { } + //catch (InvalidKeyException ike) { } + //catch (SignatureException se) { } + } + throw new CertificateException(); + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/XMLSessionContext.java b/libjava/classpath/gnu/javax/net/ssl/provider/XMLSessionContext.java new file mode 100644 index 00000000000..dcfa9d4adc9 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/XMLSessionContext.java @@ -0,0 +1,619 @@ +/* XMLSessionContext.java -- XML-encoded persistent SSL sessions. + Copyright (C) 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.net.ssl.provider; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.PrintStream; + +import java.security.SecureRandom; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateFactory; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.TreeSet; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.mode.ModeFactory; +import gnu.javax.crypto.prng.IPBE; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.PRNGFactory; + +import gnu.javax.net.ssl.Base64; + +/** + * An implementation of session contexts that stores session data on the + * filesystem in a simple XML-encoded file. + */ +class XMLSessionContext extends SessionContext +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final File file; + private final IRandom pbekdf; + private final boolean compress; + private final SecureRandom random; + private boolean encoding; + + // Constructor. + // ------------------------------------------------------------------------- + + XMLSessionContext() throws IOException, SAXException + { + file = new File(Util.getSecurityProperty("jessie.SessionContext.xml.file")); + String password = Util.getSecurityProperty("jessie.SessionContext.xml.password"); + compress = new Boolean(Util.getSecurityProperty("jessie.SessionContext.xml.compress")).booleanValue(); + if (password == null) + { + password = ""; + } + pbekdf = PRNGFactory.getInstance("PBKDF2-HMAC-SHA1"); + HashMap kdfattr = new HashMap(); + kdfattr.put(IPBE.PASSWORD, password.toCharArray()); + // Dummy salt. This is replaced by a real salt when encoding. + kdfattr.put(IPBE.SALT, new byte[8]); + kdfattr.put(IPBE.ITERATION_COUNT, new Integer(1000)); + pbekdf.init(kdfattr); + encoding = false; + if (file.exists()) + { + decode(); + } + encoding = true; + random = new SecureRandom (); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + synchronized boolean addSession(Session.ID sessionId, Session session) + { + boolean ret = super.addSession(sessionId, session); + if (ret && encoding) + { + try + { + encode(); + } + catch (IOException ioe) + { + } + } + return ret; + } + + synchronized void notifyAccess(Session session) + { + try + { + encode(); + } + catch (IOException ioe) + { + } + } + + synchronized boolean removeSession(Session.ID sessionId) + { + if (super.removeSession(sessionId)) + { + try + { + encode(); + } + catch (Exception x) + { + } + return true; + } + return false; + } + + private void decode() throws IOException, SAXException + { + SAXParser parser = null; + try + { + parser = SAXParserFactory.newInstance().newSAXParser(); + } + catch (Exception x) + { + throw new Error(x.toString()); + } + SAXHandler handler = new SAXHandler(this, pbekdf); + InputStream in = null; + if (compress) + in = new GZIPInputStream(new FileInputStream(file)); + else + in = new FileInputStream(file); + parser.parse(in, handler); + } + + private void encode() throws IOException + { + IMode cipher = ModeFactory.getInstance("CBC", "AES", 16); + HashMap cipherAttr = new HashMap(); + IMac mac = MacFactory.getInstance("HMAC-SHA1"); + HashMap macAttr = new HashMap(); + byte[] key = new byte[32]; + byte[] iv = new byte[16]; + byte[] mackey = new byte[20]; + byte[] salt = new byte[8]; + byte[] encryptedSecret = new byte[48]; + cipherAttr.put(IMode.KEY_MATERIAL, key); + cipherAttr.put(IMode.IV, iv); + cipherAttr.put(IMode.STATE, new Integer(IMode.ENCRYPTION)); + macAttr.put(IMac.MAC_KEY_MATERIAL, mackey); + PrintStream out = null; + if (compress) + { + out = new PrintStream(new GZIPOutputStream(new FileOutputStream(file))); + } + else + { + out = new PrintStream(new FileOutputStream(file)); + } + out.println("<?xml version=\"1.0\"?>"); + out.println("<!DOCTYPE sessions ["); + out.println(" <!ELEMENT sessions (session*)>"); + out.println(" <!ATTLIST sessions size CDATA \"0\">"); + out.println(" <!ATTLIST sessions timeout CDATA \"86400\">"); + out.println(" <!ELEMENT session (peer, certificates?, secret)>"); + out.println(" <!ATTLIST session id CDATA #REQUIRED>"); + out.println(" <!ATTLIST session protocol (SSLv3|TLSv1|TLSv1.1) #REQUIRED>"); + out.println(" <!ATTLIST session suite CDATA #REQUIRED>"); + out.println(" <!ATTLIST session created CDATA #REQUIRED>"); + out.println(" <!ATTLIST session timestamp CDATA #REQUIRED>"); + out.println(" <!ELEMENT peer (certificates?)>"); + out.println(" <!ATTLIST peer host CDATA #REQUIRED>"); + out.println(" <!ELEMENT certificates (#PCDATA)>"); + out.println(" <!ATTLIST certificates type CDATA \"X.509\">"); + out.println(" <!ELEMENT secret (#PCDATA)>"); + out.println(" <!ATTLIST secret salt CDATA #REQUIRED>"); + out.println("]>"); + out.println(); + out.print("<sessions size=\""); + out.print(cacheSize); + out.print("\" timeout=\""); + out.print(timeout); + out.println("\">"); + for (Iterator it = sessions.entrySet().iterator(); it.hasNext(); ) + { + Map.Entry entry = (Map.Entry) it.next(); + Session.ID id = (Session.ID) entry.getKey(); + Session session = (Session) entry.getValue(); + if (!session.valid) + { + continue; + } + out.print("<session id=\""); + out.print(Base64.encode(id.getId(), 0)); + out.print("\" suite=\""); + out.print(session.getCipherSuite()); + out.print("\" protocol=\""); + out.print(session.getProtocol()); + out.print("\" created=\""); + out.print(session.getCreationTime()); + out.print("\" timestamp=\""); + out.print(session.getLastAccessedTime()); + out.println("\">"); + out.print("<peer host=\""); + out.print(session.getPeerHost()); + out.println("\">"); + Certificate[] certs = session.getPeerCertificates(); + if (certs != null && certs.length > 0) + { + out.print("<certificates type=\""); + out.print(certs[0].getType()); + out.println("\">"); + for (int i = 0; i < certs.length; i++) + { + out.println("-----BEGIN CERTIFICATE-----"); + try + { + out.print(Base64.encode(certs[i].getEncoded(), 70)); + } + catch (CertificateEncodingException cee) + { + throw new IOException(cee.toString()); + } + out.println("-----END CERTIFICATE-----"); + } + out.println("</certificates>"); + } + out.println("</peer>"); + certs = session.getLocalCertificates(); + if (certs != null && certs.length > 0) + { + out.print("<certificates type=\""); + out.print(certs[0].getType()); + out.println("\">"); + for (int i = 0; i < certs.length; i++) + { + out.println("-----BEGIN CERTIFICATE-----"); + try + { + out.print(Base64.encode(certs[i].getEncoded(), 70)); + } + catch (CertificateEncodingException cee) + { + throw new IOException(cee.toString()); + } + out.println("-----END CERTIFICATE-----"); + } + out.println("</certificates>"); + } + random.nextBytes (salt); + pbekdf.init(Collections.singletonMap(IPBE.SALT, salt)); + try + { + pbekdf.nextBytes(key, 0, key.length); + pbekdf.nextBytes(iv, 0, iv.length); + pbekdf.nextBytes(mackey, 0, mackey.length); + cipher.reset(); + cipher.init(cipherAttr); + mac.init(macAttr); + } + catch (Exception ex) + { + throw new Error(ex.toString()); + } + for (int i = 0; i < session.masterSecret.length; i += 16) + { + cipher.update(session.masterSecret, i, encryptedSecret, i); + } + mac.update(encryptedSecret, 0, encryptedSecret.length); + byte[] macValue = mac.digest(); + out.print("<secret salt=\""); + out.print(Base64.encode(salt, 0)); + out.println("\">"); + out.print(Base64.encode(Util.concat(encryptedSecret, macValue), 70)); + out.println("</secret>"); + out.println("</session>"); + } + out.println("</sessions>"); + out.close(); + } + + // Inner class. + // ------------------------------------------------------------------------- + + private class SAXHandler extends DefaultHandler + { + + // Field. + // ----------------------------------------------------------------------- + + private SessionContext context; + private Session current; + private IRandom pbekdf; + private StringBuffer buf; + private String certType; + private int state; + private IMode cipher; + private HashMap cipherAttr; + private IMac mac; + private HashMap macAttr; + private byte[] key; + private byte[] iv; + private byte[] mackey; + + private static final int START = 0; + private static final int SESSIONS = 1; + private static final int SESSION = 2; + private static final int PEER = 3; + private static final int PEER_CERTS = 4; + private static final int CERTS = 5; + private static final int SECRET = 6; + + // Constructor. + // ----------------------------------------------------------------------- + + SAXHandler(SessionContext context, IRandom pbekdf) + { + this.context = context; + this.pbekdf = pbekdf; + buf = new StringBuffer(); + state = START; + cipher = ModeFactory.getInstance("CBC", "AES", 16); + cipherAttr = new HashMap(); + mac = MacFactory.getInstance("HMAC-SHA1"); + macAttr = new HashMap(); + key = new byte[32]; + iv = new byte[16]; + mackey = new byte[20]; + cipherAttr.put(IMode.KEY_MATERIAL, key); + cipherAttr.put(IMode.IV, iv); + cipherAttr.put(IMode.STATE, new Integer(IMode.DECRYPTION)); + macAttr.put(IMac.MAC_KEY_MATERIAL, mackey); + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public void startElement(String u, String n, String qname, Attributes attr) + throws SAXException + { + qname = qname.toLowerCase(); + switch (state) + { + case START: + if (qname.equals("sessions")) + { + try + { + timeout = Integer.parseInt(attr.getValue("timeout")); + cacheSize = Integer.parseInt(attr.getValue("size")); + if (timeout <= 0 || cacheSize < 0) + throw new SAXException("timeout or cache size out of range"); + } + catch (NumberFormatException nfe) + { + throw new SAXException(nfe); + } + state = SESSIONS; + } + else + throw new SAXException("expecting sessions"); + break; + + case SESSIONS: + if (qname.equals("session")) + { + try + { + current = new Session(Long.parseLong(attr.getValue("created"))); + current.enabledSuites = new ArrayList(SSLSocket.supportedSuites); + current.enabledProtocols = new TreeSet(SSLSocket.supportedProtocols); + current.context = context; + current.sessionId = new Session.ID(Base64.decode(attr.getValue("id"))); + current.setLastAccessedTime(Long.parseLong(attr.getValue("timestamp"))); + } + catch (Exception ex) + { + throw new SAXException(ex); + } + String prot = attr.getValue("protocol"); + if (prot.equals("SSLv3")) + current.protocol = ProtocolVersion.SSL_3; + else if (prot.equals("TLSv1")) + current.protocol = ProtocolVersion.TLS_1; + else if (prot.equals("TLSv1.1")) + current.protocol = ProtocolVersion.TLS_1_1; + else + throw new SAXException("bad protocol: " + prot); + current.cipherSuite = CipherSuite.forName(attr.getValue("suite")); + state = SESSION; + } + else + throw new SAXException("expecting session"); + break; + + case SESSION: + if (qname.equals("peer")) + { + current.peerHost = attr.getValue("host"); + state = PEER; + } + else if (qname.equals("certificates")) + { + certType = attr.getValue("type"); + state = CERTS; + } + else if (qname.equals("secret")) + { + byte[] salt = null; + try + { + salt = Base64.decode(attr.getValue("salt")); + } + catch (IOException ioe) + { + throw new SAXException(ioe); + } + pbekdf.init(Collections.singletonMap(IPBE.SALT, salt)); + state = SECRET; + } + else + throw new SAXException("bad element: " + qname); + break; + + case PEER: + if (qname.equals("certificates")) + { + certType = attr.getValue("type"); + state = PEER_CERTS; + } + else + throw new SAXException("bad element: " + qname); + break; + + default: + throw new SAXException("bad element: " + qname); + } + } + + public void endElement(String uri, String name, String qname) + throws SAXException + { + qname = qname.toLowerCase(); + switch (state) + { + case SESSIONS: + if (qname.equals("sessions")) + state = START; + else + throw new SAXException("expecting sessions"); + break; + + case SESSION: + if (qname.equals("session")) + { + current.valid = true; + context.addSession(current.sessionId, current); + state = SESSIONS; + } + else + throw new SAXException("expecting session"); + break; + + case PEER: + if (qname.equals("peer")) + state = SESSION; + else + throw new SAXException("unexpected element: " + qname); + break; + + case PEER_CERTS: + if (qname.equals("certificates")) + { + try + { + CertificateFactory fact = CertificateFactory.getInstance(certType); + current.peerCerts = (Certificate[]) + fact.generateCertificates(new ByteArrayInputStream( + buf.toString().getBytes())).toArray(new Certificate[0]); + } + catch (Exception ex) + { + throw new SAXException(ex); + } + current.peerVerified = true; + state = PEER; + } + else + throw new SAXException("unexpected element: " + qname); + break; + + case CERTS: + if (qname.equals("certificates")) + { + try + { + CertificateFactory fact = CertificateFactory.getInstance(certType); + current.localCerts = (Certificate[]) + fact.generateCertificates(new ByteArrayInputStream( + buf.toString().getBytes())).toArray(new Certificate[0]); + } + catch (Exception ex) + { + throw new SAXException(ex); + } + state = SESSION; + } + else + throw new SAXException("unexpected element: " + qname); + break; + + case SECRET: + if (qname.equals("secret")) + { + byte[] encrypted = null; + try + { + encrypted = Base64.decode(buf.toString()); + if (encrypted.length != 68) + throw new IOException("encrypted secret not 68 bytes long"); + pbekdf.nextBytes(key, 0, key.length); + pbekdf.nextBytes(iv, 0, iv.length); + pbekdf.nextBytes(mackey, 0, mackey.length); + cipher.reset(); + cipher.init(cipherAttr); + mac.init(macAttr); + } + catch (Exception ex) + { + throw new SAXException(ex); + } + mac.update(encrypted, 0, 48); + byte[] macValue = mac.digest(); + for (int i = 0; i < macValue.length; i++) + { + if (macValue[i] != encrypted[48+i]) + throw new SAXException("MAC mismatch"); + } + current.masterSecret = new byte[48]; + for (int i = 0; i < current.masterSecret.length; i += 16) + { + cipher.update(encrypted, i, current.masterSecret, i); + } + state = SESSION; + } + else + throw new SAXException("unexpected element: " + qname); + break; + + default: + throw new SAXException("unexpected element: " + qname); + } + buf.setLength(0); + } + + public void characters(char[] ch, int off, int len) throws SAXException + { + if (state != CERTS && state != PEER_CERTS && state != SECRET) + { + throw new SAXException("illegal character data"); + } + buf.append(ch, off, len); + } + } +} |

