harmony-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ge...@apache.org
Subject svn commit: r423275 [4/7] - in /incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org: ./ apache/ apache/harmony/ apache/harmony/security/ apache/harmony/security/provider/ apache/harmony/security/provider/jsse/
Date Tue, 18 Jul 2006 22:50:14 GMT
Added: incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/PRF.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/PRF.java?rev=423275&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/PRF.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/PRF.java Tue Jul 18 15:50:12 2006
@@ -0,0 +1,202 @@
+/*
+ *  Copyright 2006 The Apache Software Foundation or its licensors, as applicable.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * @author Alexander Y. Kleymenov
+ * @version $Revision$
+ */
+
+package org.apache.harmony.security.provider.jsse;
+
+import java.security.GeneralSecurityException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import javax.net.ssl.SSLException;
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * This class provides functionality for computation
+ * of PRF values for TLS (http://www.ietf.org/rfc/rfc2246.txt) 
+ * and SSL v3 (http://wp.netscape.com/eng/ssl3) protocols.
+ */
+public class PRF {
+    private static Logger.Stream logger = Logger.getStream("prf");
+
+    private static Mac md5_mac;
+    private static Mac sha_mac;
+    protected static MessageDigest md5;
+    protected static MessageDigest sha;
+    private static int md5_mac_length;
+    private static int sha_mac_length;
+    
+    static private void init() {
+        try {
+            md5_mac = Mac.getInstance("HmacMD5");
+            sha_mac = Mac.getInstance("HmacSHA1");
+        } catch (NoSuchAlgorithmException e) {
+            throw new AlertException(AlertProtocol.INTERNAL_ERROR,
+                    new SSLException(
+                "There is no provider of HmacSHA1 or HmacMD5 "
+                + "algorithms installed in the system"));
+        }
+        md5_mac_length = md5_mac.getMacLength();
+        sha_mac_length = sha_mac.getMacLength();
+        try {
+            md5 = MessageDigest.getInstance("MD5");
+            sha = MessageDigest.getInstance("SHA-1");
+        } catch (Exception e) {
+            throw new AlertException(AlertProtocol.INTERNAL_ERROR,
+                    new SSLException(
+                    "Could not initialize the Digest Algorithms."));
+        }
+    }
+
+    /**
+     * Computes the value of SSLv3 pseudo random function.
+     * @param   out:    the buffer to fill up with the value of the function.
+     * @param   secret: the buffer containing the secret value to generate prf.
+     * @param   seed:   the seed to be used.
+     */
+    static synchronized void computePRF_SSLv3(byte[] out, byte[] secret, byte[] seed) {
+        if (sha == null) {
+            init();
+        }
+        int pos = 0;
+        int iteration = 1;
+        byte[] digest;
+        while (pos < out.length) {
+            byte[] pref = new byte[iteration];
+            Arrays.fill(pref, (byte) (64 + iteration++));
+            sha.update(pref);
+            sha.update(secret);
+            sha.update(seed);
+            md5.update(secret);
+            md5.update(sha.digest());
+            digest = md5.digest(); // length == 16
+            if (pos + 16 > out.length) {
+                System.arraycopy(digest, 0, out, pos, out.length - pos);
+                pos = out.length;
+            } else {
+                System.arraycopy(digest, 0, out, pos, 16);
+                pos += 16;
+            }
+        }
+    }
+
+    /**
+     * Computes the value of TLS pseudo random function.
+     * @param   out:    the buffer to fill up with the value of the function.
+     * @param   secret: the buffer containing the secret value to generate prf.
+     * @param   str_bytes:  the label bytes to be used.
+     * @param   seed:   the seed to be used.
+     */
+    synchronized static void computePRF(byte[] out, byte[] secret,
+            byte[] str_byts, byte[] seed) throws GeneralSecurityException {
+        if (sha_mac == null) {
+            init();
+        }
+        // Do concatenation of the label with the seed:
+        // (metterings show that is is faster to concatenate the arrays
+        // and to call HMAC.update on cancatenation, than twice call for
+        // each of the part, i.e.:
+        // time(HMAC.update(label+seed))
+        //          < time(HMAC.update(label)) + time(HMAC.update(seed))
+        // but it takes more memmory (approximaty on 4%)
+        /*
+        byte[] tmp_seed = new byte[seed.length + str_byts.length];
+        System.arraycopy(str_byts, 0, tmp_seed, 0, str_byts.length);
+        System.arraycopy(seed, 0, tmp_seed, str_byts.length, seed.length);
+        seed = tmp_seed;
+        */
+        SecretKeySpec keyMd5;
+        SecretKeySpec keySha1;
+        if ((secret == null) || (secret.length == 0)) {
+            secret = new byte[8];
+            keyMd5 = new SecretKeySpec(secret, "HmacMD5");
+            keySha1 = new SecretKeySpec(secret, "HmacSHA1");
+        } else {
+            int length = secret.length >> 1; // division by 2
+            int offset = secret.length & 1;  // remainder
+            keyMd5 = new SecretKeySpec(secret, 0, length + offset,
+                    "HmacMD5");
+            keySha1 = new SecretKeySpec(secret, length, length
+                    + offset, "HmacSHA1");
+        }
+
+        //byte[] str_byts = label.getBytes();
+
+        if (logger != null) {
+            logger.println("secret["+secret.length+"]: ");
+            logger.printAsHex(16, "", " ", secret);
+            logger.println("label["+str_byts.length+"]: ");
+            logger.printAsHex(16, "", " ", str_byts);
+            logger.println("seed["+seed.length+"]: ");
+            logger.printAsHex(16, "", " ", seed);
+            logger.println("MD5 key:");
+            logger.printAsHex(16, "", " ", keyMd5.getEncoded());
+            logger.println("SHA1 key:");
+            logger.printAsHex(16, "", " ", keySha1.getEncoded());
+        }
+
+        md5_mac.init(keyMd5);
+        sha_mac.init(keySha1);
+
+        int pos = 0;
+        md5_mac.update(str_byts);
+        byte[] hash = md5_mac.doFinal(seed); // A(1)
+        while (pos < out.length) {
+            md5_mac.update(hash);
+            md5_mac.update(str_byts);
+            md5_mac.update(seed);
+            if (pos + md5_mac_length < out.length) {
+                md5_mac.doFinal(out, pos);
+                pos += md5_mac_length;
+            } else {
+                System.arraycopy(md5_mac.doFinal(), 0, out,
+                        pos, out.length - pos);
+                break;
+            }
+            // make A(i)
+            hash = md5_mac.doFinal(hash);
+        }
+        if (logger != null) {
+            logger.println("P_MD5:");
+            logger.printAsHex(md5_mac_length, "", " ", out);
+        }
+
+        pos = 0;
+        sha_mac.update(str_byts);
+        hash = sha_mac.doFinal(seed); // A(1)
+        byte[] sha1hash;
+        while (pos < out.length) {
+            sha_mac.update(hash);
+            sha_mac.update(str_byts);
+            sha1hash = sha_mac.doFinal(seed);
+            for (int i = 0; (i < sha_mac_length) & (pos < out.length); i++) {
+                out[pos++] ^= sha1hash[i];
+            }
+            // make A(i)
+            hash = sha_mac.doFinal(hash);
+        }
+
+        if (logger != null) {
+            logger.println("PRF:");
+            logger.printAsHex(sha_mac_length, "", " ", out);
+        }
+    }
+}

Added: incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ProtocolVersion.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ProtocolVersion.java?rev=423275&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ProtocolVersion.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ProtocolVersion.java Tue Jul 18 15:50:12 2006
@@ -0,0 +1,163 @@
+/*
+ *  Copyright 2006 The Apache Software Foundation or its licensors, as applicable.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * @author Boris Kuznetsov
+ * @version $Revision$
+ */
+package org.apache.harmony.security.provider.jsse;
+
+import java.util.Hashtable;
+
+/**
+ * 
+ * Represents Protocol Version
+ */
+public class ProtocolVersion {
+
+    /**
+     * Protocol name
+     */
+    public final String name;
+
+    /**
+     * Protocol version as byte array
+     */
+    public final byte[] version;
+
+    /**
+     * Protocols supported by this provider implementaton
+     */
+    public static final String[] supportedProtocols = new String[] { "TLSv1",
+            "SSLv3" };
+
+    private static Hashtable protocolsByName = new Hashtable(4);
+
+    private ProtocolVersion(String name, byte[] version) {
+        this.name = name;
+        this.version = version;
+    }
+
+    /**
+     * Compares this ProtocolVersion to the specified object.
+     */
+    public boolean equals(Object o) {
+        if (o instanceof ProtocolVersion
+                && this.version[0] == ((ProtocolVersion) o).version[0]
+                && this.version[1] == ((ProtocolVersion) o).version[1]) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * 
+     * Returns true if protocol version is supported
+     * 
+     * @param version
+     */
+    public static boolean isSupported(byte[] version) {
+        if (version[0] != 3 || (version[1] != 0 && version[1] != 1)) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Returns ProtocolVersion
+     * 
+     * @param version
+     * @return
+     */
+    public static ProtocolVersion getByVersion(byte[] version) {
+        if (version[0] == 3) {
+            if (version[1] == 1) {
+                return TLSv1;
+            }
+            if (version[1] == 0) {
+                return SSLv3;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns true if provider supports protocol version
+     * 
+     * @param name
+     * @return
+     */
+    public static boolean isSupported(String name) {
+        return protocolsByName.containsKey(name);
+    }
+
+    /**
+     * Returns ProtocolVersion
+     * 
+     * @param name
+     * @return
+     */
+    public static ProtocolVersion getByName(String name) {
+        return (ProtocolVersion) protocolsByName.get(name);
+    }
+
+    /**
+     * Highest protocol version supported by provider implementation
+     * 
+     * @param protocols
+     * @return
+     */
+    public static ProtocolVersion getLatestVersion(String[] protocols) {
+        if (protocols == null || protocols.length == 0) {
+            return null;
+        }
+        ProtocolVersion latest = getByName(protocols[0]);
+        ProtocolVersion current;
+        for (int i = 1; i < protocols.length; i++) {
+            current = getByName(protocols[i]);
+            if (current == null) {
+                continue;
+            }
+            if ((latest == null)
+                    || (latest.version[0] < current.version[0])
+                    || (latest.version[0] == current.version[0] && latest.version[1] < current.version[1])) {
+                latest = current;
+            }
+        }
+        return latest;
+
+    }
+
+    /**
+     * SSL 3.0 protocol version
+     */
+    public static ProtocolVersion SSLv3 = new ProtocolVersion("SSLv3",
+            new byte[] { 3, 0 });
+
+    /**
+     * TLS 1.0 protocol version
+     */
+    public static ProtocolVersion TLSv1 = new ProtocolVersion("TLSv1",
+            new byte[] { 3, 1 });
+
+    static {
+        protocolsByName.put(SSLv3.name, SSLv3);
+        protocolsByName.put(TLSv1.name, TLSv1);
+        protocolsByName.put("SSL", SSLv3);
+        protocolsByName.put("TLS", TLSv1);
+    }
+
+}
\ No newline at end of file

Added: incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/SSLBufferedInput.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/SSLBufferedInput.java?rev=423275&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/SSLBufferedInput.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/SSLBufferedInput.java Tue Jul 18 15:50:12 2006
@@ -0,0 +1,81 @@
+/*
+ *  Copyright 2006 The Apache Software Foundation or its licensors, as applicable.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * @author Alexander Y. Kleymenov
+ * @version $Revision$
+ */
+
+package org.apache.harmony.security.provider.jsse;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * This is a wrapper input stream for ByteBuffer data source.
+ * Among with the read functionality it provides info
+ * about number of cunsumed bytes from the source ByteBuffer.
+ * The source ByteBuffer object can be reseted.
+ * So one instance of this wrapper can be reused for several
+ * ByteBuffer data sources.
+ */
+public class SSLBufferedInput extends SSLInputStream {
+
+    private ByteBuffer in;
+    private int bytik;
+    private int consumed = 0;
+
+    /**
+     * Constructor
+     */
+    protected SSLBufferedInput() {}
+
+    /**
+     * Sets the buffer as a data source
+     */
+    protected void setSourceBuffer(ByteBuffer in) {
+        consumed = 0;
+        this.in = in;
+    }
+
+    /**
+     * Returns the number of bytes available for reading.
+     */
+    public int available() throws IOException {
+        // in assumption that the buffer has been set
+        return in.remaining();
+    }
+
+    /**
+     * Returns the number of consumed bytes.
+     */
+    protected int consumed() {
+        return consumed;
+    }
+
+    /**
+     * Reads the following byte value. If there are no bytes in the source 
+     * buffer, method throws java.nio.BufferUnderflowException.
+     */
+    public int read() throws IOException {
+        // TODO: implement optimized read(int) 
+        // and read(byte[], int, int) methods
+        bytik = in.get() & 0x00FF;
+        consumed ++;
+        return bytik;
+    }
+}
+

Added: incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/SSLContextImpl.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/SSLContextImpl.java?rev=423275&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/SSLContextImpl.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/SSLContextImpl.java Tue Jul 18 15:50:12 2006
@@ -0,0 +1,88 @@
+/*
+ *  Copyright 2006 The Apache Software Foundation or its licensors, as applicable.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * @author Alexander Y. Kleymenov
+ * @version $Revision$
+ */
+
+package org.apache.harmony.security.provider.jsse;
+
+import java.security.KeyManagementException;
+import java.security.SecureRandom;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContextSpi;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSessionContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+
+/**
+ * Implementation of SSLContext service provider interface.
+ */
+public class SSLContextImpl extends SSLContextSpi {
+
+    protected SSLParameters sslParameters;
+
+    public SSLContextImpl() {
+        super();
+    }
+
+    public void engineInit(KeyManager[] kms, TrustManager[] tms,
+            SecureRandom sr) throws KeyManagementException {
+        sslParameters = new SSLParameters(kms, tms, sr);
+    }
+
+    public SSLSocketFactory engineGetSocketFactory() {
+        if (sslParameters == null) {
+            throw new IllegalStateException("SSLContext is not initiallized.");
+        }
+        return new SSLSocketFactoryImpl(sslParameters);
+    }
+
+    public SSLServerSocketFactory engineGetServerSocketFactory() {
+        if (sslParameters == null) {
+            throw new IllegalStateException("SSLContext is not initiallized.");
+        }
+        return new SSLServerSocketFactoryImpl(sslParameters);
+    }
+
+    public SSLEngine engineCreateSSLEngine(String host, int port) {
+        if (sslParameters == null) {
+            throw new IllegalStateException("SSLContext is not initiallized.");
+        }
+        return new SSLEngineImpl(host, port,
+                (SSLParameters) sslParameters.clone());
+    }
+
+    public SSLEngine engineCreateSSLEngine() {
+        if (sslParameters == null) {
+            throw new IllegalStateException("SSLContext is not initiallized.");
+        }
+        return new SSLEngineImpl((SSLParameters) sslParameters.clone());
+    }
+
+    public SSLSessionContext engineGetServerSessionContext() {
+        return sslParameters.getServerSessionContext();
+    }
+
+    public SSLSessionContext engineGetClientSessionContext() {
+        return sslParameters.getClientSessionContext();
+    }
+}
+

Added: incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/SSLEngineAppData.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/SSLEngineAppData.java?rev=423275&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/SSLEngineAppData.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/SSLEngineAppData.java Tue Jul 18 15:50:12 2006
@@ -0,0 +1,98 @@
+/*
+ *  Copyright 2006 The Apache Software Foundation or its licensors, as applicable.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * @author Alexander Y. Kleymenov
+ * @version $Revision$
+ */
+
+package org.apache.harmony.security.provider.jsse;
+
+import java.nio.ByteBuffer;
+import javax.net.ssl.SSLException;
+
+/**
+ * This class is used to retrieve the application data
+ * arrived for the SSLEngine.
+ */
+public class SSLEngineAppData implements Appendable {
+
+    /**
+     * Buffer containing received application data.
+     */
+    byte[] buffer;
+
+    /**
+     * Constructor
+     */
+    protected SSLEngineAppData() {}
+
+    /**
+     * Stores received data. The source data is not cloned, 
+     * just the array reference is remembered into the buffer field.
+     */
+    public void append(byte[] src) {
+        if (buffer != null) {
+            throw new AlertException(
+                AlertProtocol.INTERNAL_ERROR,
+                new SSLException("Attempt to override the data"));
+        }
+        buffer = src;
+    }
+
+    /**
+     * Places the data from the buffer into the array of destination
+     * ByteBuffer objects.
+     */
+    protected int placeTo(ByteBuffer[] dsts, int offset, int length) {
+        if (buffer == null) {
+            return 0;
+        }
+        int pos = 0;
+        int len = buffer.length;
+        int rem;
+        // write data to the buffers
+        for (int i=offset; i<offset+length; i++) {
+            rem = dsts[i].remaining();
+            // TODO: optimization work - use hasArray, array(), arraycopy
+            if (len - pos < rem) {
+                // can fully write remaining data into buffer
+                dsts[i].put(buffer, pos, len - pos);
+                pos = len;
+                // data was written, exit
+                break;
+            } else {
+                // write chunk of data
+                dsts[i].put(buffer, pos, rem);
+                pos += rem;
+            }
+        }
+        if (pos != len) {
+            // The data did not feet into the buffers,
+            // it should not happen, because the destination buffers
+            // had been checked for the space before record unwrapping.
+            // But if it so, we should allert about internal error.
+            throw new AlertException(
+                AlertProtocol.INTERNAL_ERROR,
+                new SSLException(
+                    "The received application data could not be fully written"
+                    + "into the destination buffers"));
+        }
+        buffer = null;
+        return len;
+    }
+}
+

Added: incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/SSLEngineDataStream.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/SSLEngineDataStream.java?rev=423275&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/SSLEngineDataStream.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/SSLEngineDataStream.java Tue Jul 18 15:50:12 2006
@@ -0,0 +1,95 @@
+/*
+ *  Copyright 2006 The Apache Software Foundation or its licensors, as applicable.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * @author Alexander Y. Kleymenov
+ * @version $Revision$
+ */
+
+package org.apache.harmony.security.provider.jsse;
+
+import java.nio.ByteBuffer;
+
+/**
+ * This class provides the DataStream functionality
+ * implemented over the array of ByteBuffer instances.
+ * Among with the data chunks read functionality
+ * it provides the info about amount of consumed data.
+ * The source ByteBuffer objects can be replaced by other.
+ * So one instance of this wrapper can be reused for several
+ * data sources.
+ */
+public class SSLEngineDataStream implements DataStream {
+
+    private ByteBuffer[] srcs;
+    private int offset;
+    private int limit;
+
+    private int available;
+    private int consumed;
+
+    protected SSLEngineDataStream() {}
+
+    protected void setSourceBuffers(ByteBuffer[] srcs, int offset, int length) {
+        this.srcs = srcs;
+        this.offset = offset;
+        this.limit = offset+length;
+        this.consumed = 0;
+        this.available = 0;
+        for (int i=offset; i<limit; i++) {
+            if (srcs[i] == null) {
+                throw new IllegalStateException(
+                        "Some of the input parameters are null");
+            }
+            available += srcs[i].remaining();
+        }
+    }
+
+    public int available() {
+        return available;
+    }
+
+    public boolean hasData() {
+        return available > 0;
+    }
+
+    public byte[] getData(int length) {
+        // TODO: optimization work:
+        // use ByteBuffer.get(byte[],int,int)
+        // and ByteBuffer.hasArray() methods
+        int len = (length < available) ? length : available;
+        available -= len;
+        consumed += len;
+        byte[] res = new byte[len];
+        int pos = 0;
+        loop:
+        for (; offset<limit; offset++) {
+            while (srcs[offset].hasRemaining()) {
+                res[pos++] = srcs[offset].get();
+                len --;
+                if (len == 0) {
+                    break loop;
+                }
+            }
+        }
+        return res;
+    }
+
+    protected int consumed() {
+        return consumed;
+    }
+}
+

Added: incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/SSLEngineImpl.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/SSLEngineImpl.java?rev=423275&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/SSLEngineImpl.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/SSLEngineImpl.java Tue Jul 18 15:50:12 2006
@@ -0,0 +1,746 @@
+/*
+ *  Copyright 2006 The Apache Software Foundation or its licensors, as applicable.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * @author Alexander Y. Kleymenov
+ * @version $Revision$
+ */
+
+package org.apache.harmony.security.provider.jsse;
+
+import java.io.IOException;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.nio.ReadOnlyBufferException;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSession;
+
+/**
+ * Implementation of SSLEngine.
+ * @see javax.net.ssl.SSLEngine class documentation for more information.
+ */
+public class SSLEngineImpl extends SSLEngine {
+
+    // indicates if peer mode was set
+    private boolean peer_mode_was_set = false;
+    // indicates if handshake has been started
+    private boolean handshake_started = false;
+    // indicates if inbound operations finished
+    private boolean isInboundDone = false;
+    // indicates if outbound operations finished
+    private boolean isOutboundDone = false;
+    // indicates if close_notify alert had been sent to another peer
+    private boolean close_notify_was_sent = false;
+    // indicates if close_notify alert had been received from another peer
+    private boolean close_notify_was_received = false;
+    // indicates if engine was closed (it means that
+    // all the works on it are done, except (probably) some finalizing work)
+    private boolean engine_was_closed = false;
+    // indicates if engine was shutted down (it means that
+    // all cleaning work had been done and the engine is not operable)
+    private boolean engine_was_shutteddown = false;
+
+    // record protocol to be used
+    protected SSLRecordProtocol recordProtocol;
+    // input stream for record protocol
+    private SSLBufferedInput recProtIS;
+    // handshake protocol to be used
+    private HandshakeProtocol handshakeProtocol;
+    // alert protocol to be used
+    private AlertProtocol alertProtocol;
+    // place where application data will be stored
+    private SSLEngineAppData appData;
+    // outcoming application data stream
+    private SSLEngineDataStream dataStream = new SSLEngineDataStream();
+    // active session object
+    private SSLSessionImpl session;
+
+    // peer configuration parameters
+    protected SSLParameters sslParameters;
+
+    // in case of emergency situations when data could not be
+    // placed in destination buffers it will be stored in this
+    // fields
+    private byte[] remaining_wrapped_data = null;
+    private byte[] remaining_hsh_data = null;
+
+    // logger
+    private Logger.Stream logger = Logger.getStream("engine");
+
+    /**
+     * Ctor
+     * @param   sslParameters:  SSLParameters
+     */
+    protected SSLEngineImpl(SSLParameters sslParameters) {
+        super();
+        this.sslParameters = sslParameters;
+    }
+
+    /**
+     * Ctor
+     * @param   host:   String
+     * @param   port:   int
+     * @param   sslParameters:  SSLParameters
+     */
+    protected SSLEngineImpl(String host, int port, SSLParameters sslParameters) {
+        super(host, port);
+        this.sslParameters = sslParameters;
+    }
+
+    /**
+     * Starts the handshake.
+     * @throws  SSLException
+     * @see javax.net.ssl.SSLEngine#beginHandshake() method documentation
+     * for more information
+     */
+    public void beginHandshake() throws SSLException {
+        if (engine_was_closed) {
+            throw new SSLException("Engine has already been closed.");
+        }
+        if (!peer_mode_was_set) {
+            throw new IllegalStateException("Client/Server mode was not set");
+        }
+        if (!handshake_started) {
+            handshake_started = true;
+            if (getUseClientMode()) {
+                handshakeProtocol = new ClientHandshakeImpl(this);
+            } else {
+                handshakeProtocol = new ServerHandshakeImpl(this);
+            }
+            appData = new SSLEngineAppData();
+            alertProtocol = new AlertProtocol();
+            recProtIS = new SSLBufferedInput();
+            recordProtocol = new SSLRecordProtocol(handshakeProtocol,
+                    alertProtocol, recProtIS, appData);
+        }
+        handshakeProtocol.start();
+    }
+
+    /**
+     * Closes inbound operations of this engine
+     * @throws  SSLException
+     * @see javax.net.ssl.SSLEngine#closeInbound() method documentation
+     * for more information
+     */
+    public void closeInbound() throws SSLException {
+        if (logger != null) {
+            logger.println("closeInbound() "+isInboundDone);
+        }
+        if (isInboundDone) {
+            return;
+        }
+        isInboundDone = true;
+        engine_was_closed = true;
+        if (handshake_started) {
+            if (!close_notify_was_received) {
+                if (session != null) {
+                    session.invalidate();
+                }
+                alertProtocol.alert(AlertProtocol.FATAL,
+                        AlertProtocol.INTERNAL_ERROR);
+                throw new SSLException("Inbound is closed before close_notify "
+                        + "alert has been received.");
+            }
+        } else {
+            // engine is closing before initial handshake has been made
+            shutdown();
+        }
+    }
+
+    /**
+     * Closes outbound operations of this engine
+     * @see javax.net.ssl.SSLEngine#closeOutbound() method documentation
+     * for more information
+     */
+    public void closeOutbound() {
+        if (logger != null) {
+            logger.println("closeOutbound() "+isOutboundDone);
+        }
+        if (isOutboundDone) {
+            return;
+        }
+        isOutboundDone = true;
+        if (handshake_started) {
+            // initial handshake had been started
+            alertProtocol.alert(AlertProtocol.WARNING,
+                    AlertProtocol.CLOSE_NOTIFY);
+            close_notify_was_sent = true;
+        } else {
+            // engine is closing before initial handshake has been made
+            shutdown();
+        }
+        engine_was_closed = true;
+    }
+
+    /**
+     * Returns handshake's delegated tasks to be run
+     * @return the delegated task to be executed.
+     * @see javax.net.ssl.SSLEngine#getDelegatedTask() method documentation
+     * for more information
+     */
+    public Runnable getDelegatedTask() {
+        return handshakeProtocol.getTask();
+    }
+
+    /**
+     * Returns names of supported cipher suites.
+     * @return array of strings containing the names of supported cipher suites
+     * @see javax.net.ssl.SSLEngine#getSupportedCipherSuites() method
+     * documentation for more information
+     */
+    public String[] getSupportedCipherSuites() {
+        return CipherSuite.getSupportedCipherSuiteNames();
+    }
+
+    // --------------- SSLParameters based methods ---------------------
+
+    /**
+     * This method works according to the specification of implemented class.
+     * @see javax.net.ssl.SSLEngine#getEnabledCipherSuites() method
+     * documentation for more information
+     */
+    public String[] getEnabledCipherSuites() {
+        return sslParameters.getEnabledCipherSuites();
+    }
+
+    /**
+     * This method works according to the specification of implemented class.
+     * @see javax.net.ssl.SSLEngine#setEnabledCipherSuites(String) method
+     * documentation for more information
+     */
+    public void setEnabledCipherSuites(String[] suites) {
+        sslParameters.setEnabledCipherSuites(suites);
+    }
+
+    /**
+     * This method works according to the specification of implemented class.
+     * @see javax.net.ssl.SSLEngine#getSupportedProtocols() method
+     * documentation for more information
+     */
+    public String[] getSupportedProtocols() {
+        return (String[]) ProtocolVersion.supportedProtocols.clone();
+    }
+
+    /**
+     * This method works according to the specification of implemented class.
+     * @see javax.net.ssl.SSLEngine#getEnabledProtocols() method
+     * documentation for more information
+     */
+    public String[] getEnabledProtocols() {
+        return sslParameters.getEnabledProtocols();
+    }
+
+    /**
+     * This method works according to the specification of implemented class.
+     * @see javax.net.ssl.SSLEngine#setEnabledProtocols(String) method
+     * documentation for more information
+     */
+    public void setEnabledProtocols(String[] protocols) {
+        sslParameters.setEnabledProtocols(protocols);
+    }
+
+    /**
+     * This method works according to the specification of implemented class.
+     * @see javax.net.ssl.SSLEngine#setUseClientMode(boolean) method
+     * documentation for more information
+     */
+    public void setUseClientMode(boolean mode) {
+        if (handshake_started) {
+            throw new IllegalArgumentException(
+            "Could not change the mode after the initial handshake has begun.");
+        }
+        sslParameters.setUseClientMode(mode);
+        peer_mode_was_set = true;
+    }
+
+    /**
+     * This method works according to the specification of implemented class.
+     * @see javax.net.ssl.SSLEngine#getUseClientMode() method
+     * documentation for more information
+     */
+    public boolean getUseClientMode() {
+        return sslParameters.getUseClientMode();
+    }
+
+    /**
+     * This method works according to the specification of implemented class.
+     * @see javax.net.ssl.SSLEngine#setNeedClientAuth(boolean) method
+     * documentation for more information
+     */
+    public void setNeedClientAuth(boolean need) {
+        sslParameters.setNeedClientAuth(need);
+    }
+
+    /**
+     * This method works according to the specification of implemented class.
+     * @see javax.net.ssl.SSLEngine#getNeedClientAuth() method
+     * documentation for more information
+     */
+    public boolean getNeedClientAuth() {
+        return sslParameters.getNeedClientAuth();
+    }
+
+    /**
+     * This method works according to the specification of implemented class.
+     * @see javax.net.ssl.SSLEngine#setWantClientAuth(boolean) method
+     * documentation for more information
+     */
+    public void setWantClientAuth(boolean want) {
+        sslParameters.setWantClientAuth(want);
+    }
+
+    /**
+     * This method works according to the specification of implemented class.
+     * @see javax.net.ssl.SSLEngine#getWantClientAuth() method
+     * documentation for more information
+     */
+    public boolean getWantClientAuth() {
+        return sslParameters.getWantClientAuth();
+    }
+
+    /**
+     * This method works according to the specification of implemented class.
+     * @see javax.net.ssl.SSLEngine#setEnableSessionCreation(boolean) method
+     * documentation for more information
+     */
+    public void setEnableSessionCreation(boolean flag) {
+        sslParameters.setEnableSessionCreation(flag);
+    }
+
+    /**
+     * This method works according to the specification of implemented class.
+     * @see javax.net.ssl.SSLEngine#getEnableSessionCreation() method
+     * documentation for more information
+     */
+    public boolean getEnableSessionCreation() {
+        return sslParameters.getEnableSessionCreation();
+    }
+
+    // -----------------------------------------------------------------
+
+    /**
+     * This method works according to the specification of implemented class.
+     * @see javax.net.ssl.SSLEngine#getHandshakeStatus() method
+     * documentation for more information
+     */
+    public SSLEngineResult.HandshakeStatus getHandshakeStatus() {
+        if (!handshake_started || engine_was_shutteddown) {
+            // initial handshake has not been started yet
+            return SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
+        }
+        if (alertProtocol.hasAlert()) {
+            // need to send an alert
+            return SSLEngineResult.HandshakeStatus.NEED_WRAP;
+        }
+        if (close_notify_was_sent && !close_notify_was_received) {
+            // waiting for "close_notify" response
+            return SSLEngineResult.HandshakeStatus.NEED_UNWRAP;
+        }
+        return handshakeProtocol.getStatus();
+    }
+
+    /**
+     * This method works according to the specification of implemented class.
+     * @see javax.net.ssl.SSLEngine#getSession() method
+     * documentation for more information
+     */
+    public SSLSession getSession() {
+        if (session != null) {
+            return session;
+        } else {
+            return SSLSessionImpl.NULL_SESSION;
+        }
+    }
+
+    /**
+     * This method works according to the specification of implemented class.
+     * @see javax.net.ssl.SSLEngine#isInboundDone() method
+     * documentation for more information
+     */
+    public boolean isInboundDone() {
+        return isInboundDone || engine_was_closed;
+    }
+
+    /**
+     * This method works according to the specification of implemented class.
+     * @see javax.net.ssl.SSLEngine#isOutboundDone() method
+     * documentation for more information
+     */
+    public boolean isOutboundDone() {
+        return isOutboundDone;
+    }
+
+    /**
+     * Decodes one complete SSL/TLS record provided in the source buffer.
+     * If decoded record contained application data, this data will
+     * be placed in the destination buffers.
+     * For more information about TLS record fragmentation see
+     * TLS v 1 specification (http://www.ietf.org/rfc/rfc2246.txt) p 6.2.
+     * @param src source buffer containing SSL/TLS record.
+     * @param dsts destination buffers to place received application data.
+     * @see javax.net.ssl.SSLEngine#unwrap(ByteBuffer,ByteBuffer[],int,int)
+     * method documentation for more information
+     */
+    public SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts,
+                                int offset, int length) throws SSLException {
+        if (engine_was_shutteddown) {
+            return new SSLEngineResult(SSLEngineResult.Status.CLOSED,
+                    SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING, 0, 0);
+        }
+        if ((src == null) || (dsts == null)) {
+            throw new IllegalStateException(
+                    "Some of the input parameters are null");
+        }
+
+        if (!handshake_started) {
+            beginHandshake();
+        }
+
+        SSLEngineResult.HandshakeStatus handshakeStatus = getHandshakeStatus();
+        // If is is initial handshake or connection closure stage,
+        // check if this call was made in spite of handshake status
+        if ((session == null || engine_was_closed) && (
+                    handshakeStatus.equals(
+                        SSLEngineResult.HandshakeStatus.NEED_WRAP) ||
+                    handshakeStatus.equals(
+                        SSLEngineResult.HandshakeStatus.NEED_TASK))) {
+            return new SSLEngineResult(
+                    getEngineStatus(), handshakeStatus, 0, 0);
+        }
+
+        if (src.remaining() < recordProtocol.getMinRecordSize()) {
+            return new SSLEngineResult(
+                    SSLEngineResult.Status.BUFFER_UNDERFLOW,
+                    getHandshakeStatus(), 0, 0);
+        }
+
+        try {
+            src.mark();
+            // check the destination buffers and count their capacity
+            int capacity = 0;
+            for (int i=offset; i<offset+length; i++) {
+                if (dsts[i] == null) {
+                    throw new IllegalStateException(
+                            "Some of the input parameters are null");
+                }
+                if (dsts[i].isReadOnly()) {
+                    throw new ReadOnlyBufferException();
+                }
+                capacity += dsts[i].remaining();
+            }
+            if (capacity < recordProtocol.getDataSize(src.remaining())) {
+                return new SSLEngineResult(
+                        SSLEngineResult.Status.BUFFER_OVERFLOW,
+                        getHandshakeStatus(), 0, 0);
+            }
+            recProtIS.setSourceBuffer(src);
+            // unwrap the record contained in source buffer, pass it
+            // to appropriate client protocol (alert, handshake, or app)
+            // and retrieve the type of unwrapped data
+            int type = recordProtocol.unwrap();
+            // process the data and return the result
+            switch (type) {
+                case ContentType.HANDSHAKE:
+                case ContentType.CHANGE_CIPHER_SPEC:
+                    if (handshakeProtocol.getStatus().equals(
+                            SSLEngineResult.HandshakeStatus.FINISHED)) {
+                        session = recordProtocol.getSession();
+                    }
+                    break;
+                case ContentType.APPLICATION_DATA:
+                    break;
+                case ContentType.ALERT:
+                    if (alertProtocol.isFatalAlert()) {
+                        alertProtocol.setProcessed();
+                        if (session != null) {
+                            session.invalidate();
+                        }
+                        String description = "Fatal alert received "
+                            + alertProtocol.getAlertDescription();
+                        shutdown();
+                        throw new SSLException(description);
+                    } else {
+                        if (logger != null) {
+                            logger.println("Warning allert has been received: "
+                                + alertProtocol.getAlertDescription());
+                        }
+                        switch(alertProtocol.getDescriptionCode()) {
+                            case AlertProtocol.CLOSE_NOTIFY:
+                                alertProtocol.setProcessed();
+                                close_notify_was_received = true;
+                                if (!close_notify_was_sent) {
+                                    closeOutbound();
+                                    closeInbound();
+                                } else {
+                                    closeInbound();
+                                    shutdown();
+                                }
+                                break;
+                            case AlertProtocol.NO_RENEGOTIATION:
+                                alertProtocol.setProcessed();
+                                if (session == null) {
+                                    // message received during the initial 
+                                    // handshake
+                                    throw new AlertException(
+                                        AlertProtocol.HANDSHAKE_FAILURE,
+                                        new SSLHandshakeException(
+                                            "Received no_renegotiation "
+                                            + "during the initial handshake"));
+                                } else {
+                                    // just stop the handshake
+                                    handshakeProtocol.stop();
+                                }
+                                break;
+                            default:
+                                alertProtocol.setProcessed();
+                        }
+                    }
+                    break;
+            }
+            return new SSLEngineResult(getEngineStatus(), getHandshakeStatus(),
+                    recProtIS.consumed(), 
+                    // place the app. data (if any) into the dest. buffers 
+                    // and get the number of produced bytes:
+                    appData.placeTo(dsts, offset, length));
+        } catch (BufferUnderflowException e) {
+            // there was not enought data ource buffer to make complete packet
+            src.reset();
+            return new SSLEngineResult(SSLEngineResult.Status.BUFFER_UNDERFLOW,
+                    getHandshakeStatus(), 0, 0);
+        } catch (AlertException e) {
+            // fatal alert occured
+            alertProtocol.alert(AlertProtocol.FATAL, e.getDescriptionCode());
+            engine_was_closed = true;
+            src.reset();
+            if (session != null) {
+                session.invalidate();
+            }
+            // shutdown work will be made after the alert will be sent
+            // to another peer (by wrap method)
+            throw e.getReason();
+        } catch (SSLException e) {
+            throw e;
+        } catch (IOException e) {
+            alertProtocol.alert(AlertProtocol.FATAL,
+                    AlertProtocol.INTERNAL_ERROR);
+            engine_was_closed = true;
+            // shutdown work will be made after the alert will be sent
+            // to another peer (by wrap method)
+            throw new SSLException(e.getMessage());
+        }
+    }
+
+    /**
+     * Encodes the application data into SSL/TLS record. If handshake status
+     * of the engine differs from NOT_HANDSHAKING the operation can work
+     * without consuming of the source data.
+     * For more information about TLS record fragmentation see
+     * TLS v 1 specification (http://www.ietf.org/rfc/rfc2246.txt) p 6.2.
+     * @param srcs the source buffers with application data to be encoded
+     * into SSL/TLS record.
+     * @param offset the offset in the destination buffers array pointing to
+     * the first buffer with the source data.
+     * @param len specifies the maximum number of buffers to be procesed.
+     * @param dst the destination buffer where encoded data will be placed.
+     * @see javax.net.ssl.SSLEngine#wrap(ByteBuffer[],int,int,ByteBuffer) method
+     * documentation for more information
+     */
+    public SSLEngineResult wrap(ByteBuffer[] srcs, int offset,
+                            int len, ByteBuffer dst) throws SSLException {
+        if (engine_was_shutteddown) {
+            return new SSLEngineResult(SSLEngineResult.Status.CLOSED,
+                    SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING, 0, 0);
+        }
+        if ((srcs == null) || (dst == null)) {
+            throw new IllegalStateException(
+                    "Some of the input parameters are null");
+        }
+        if (dst.isReadOnly()) {
+            throw new ReadOnlyBufferException();
+        }
+
+        if (!handshake_started) {
+            beginHandshake();
+        }
+
+        SSLEngineResult.HandshakeStatus handshakeStatus = getHandshakeStatus();
+        // If it is an initial handshake or connection closure stage,
+        // check if this call was made in spite of handshake status
+        if ((session == null || engine_was_closed) && (
+                handshakeStatus.equals(
+                        SSLEngineResult.HandshakeStatus.NEED_UNWRAP) ||
+                handshakeStatus.equals(
+                        SSLEngineResult.HandshakeStatus.NEED_TASK))) {
+            return new SSLEngineResult(
+                    getEngineStatus(), handshakeStatus, 0, 0);
+        }
+
+        int capacity = dst.remaining();
+        int produced = 0;
+
+        if (alertProtocol.hasAlert()) {
+            // we have an alert to be sent
+            if (capacity < recordProtocol.getRecordSize(2)) {
+                return new SSLEngineResult(
+                        SSLEngineResult.Status.BUFFER_OVERFLOW,
+                        handshakeStatus, 0, 0);
+            }
+            byte[] alert_data = alertProtocol.wrap();
+            // place the alert record into destination
+            dst.put(alert_data);
+            if (alertProtocol.isFatalAlert()) {
+                alertProtocol.setProcessed();
+                if (session != null) {
+                    session.invalidate();
+                }
+                // fatal alert has been sent, so shut down the engine
+                shutdown();
+                return new SSLEngineResult(
+                        SSLEngineResult.Status.CLOSED,
+                        SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING,
+                        0, alert_data.length);
+            } else {
+                alertProtocol.setProcessed();
+                // check if the works on this engine have been done
+                if (close_notify_was_sent && close_notify_was_received) {
+                    shutdown();
+                    return new SSLEngineResult(SSLEngineResult.Status.CLOSED,
+                            SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING,
+                            0, alert_data.length);
+                }
+                return new SSLEngineResult(
+                        getEngineStatus(),
+                        getHandshakeStatus(),
+                        0, alert_data.length);
+            }
+        }
+
+        if (capacity < recordProtocol.getMinRecordSize()) {
+            if (logger != null) {
+                logger.println("Capacity of the destination("
+                        +capacity+") < MIN_PACKET_SIZE("
+                        +recordProtocol.getMinRecordSize()+")");
+            }
+            return new SSLEngineResult(SSLEngineResult.Status.BUFFER_OVERFLOW,
+                        handshakeStatus, 0, 0);
+        }
+
+        try {
+            if (!handshakeStatus.equals(
+                        SSLEngineResult.HandshakeStatus.NEED_WRAP)) {
+                // so we wraps application data
+                dataStream.setSourceBuffers(srcs, offset, len);
+                if ((capacity < SSLRecordProtocol.MAX_SSL_PACKET_SIZE) &&
+                    (capacity < recordProtocol.getRecordSize(
+                                                 dataStream.available()))) {
+                    if (logger != null) {
+                        logger.println("The destination buffer("
+                                +capacity+") can not take the resulting packet("
+                                + recordProtocol.getRecordSize(
+                                    dataStream.available())+")");
+                    }
+                    return new SSLEngineResult(
+                            SSLEngineResult.Status.BUFFER_OVERFLOW,
+                            handshakeStatus, 0, 0);
+                }
+                if (remaining_wrapped_data == null) {
+                    remaining_wrapped_data =
+                        recordProtocol.wrap(ContentType.APPLICATION_DATA,
+                                dataStream);
+                }
+                if (capacity < remaining_wrapped_data.length) {
+                    // It should newer happen because we checked the destination
+                    // buffer size, but there is a possibility
+                    // (if dest buffer was filled outside)
+                    // so we just remember the data into remaining_wrapped_data
+                    // and will enclose it during the the next call
+                    return new SSLEngineResult(
+                            SSLEngineResult.Status.BUFFER_OVERFLOW,
+                            handshakeStatus, dataStream.consumed(), 0);
+                } else {
+                    dst.put(remaining_wrapped_data);
+                    produced = remaining_wrapped_data.length;
+                    remaining_wrapped_data = null;
+                    return new SSLEngineResult(getEngineStatus(), 
+                            handshakeStatus, dataStream.consumed(), produced);
+                }
+            } else {
+                if (remaining_hsh_data == null) {
+                    remaining_hsh_data = handshakeProtocol.wrap();
+                }
+                if (capacity < remaining_hsh_data.length) {
+                    // It should newer happen because we checked the destination
+                    // buffer size, but there is a possibility
+                    // (if dest buffer was filled outside)
+                    // so we just remember the data into remaining_hsh_data
+                    // and will enclose it during the the next call
+                    return new SSLEngineResult(
+                            SSLEngineResult.Status.BUFFER_OVERFLOW,
+                            handshakeStatus, 0, 0);
+                } else {
+                    dst.put(remaining_hsh_data);
+                    produced = remaining_hsh_data.length;
+                    remaining_hsh_data = null;
+
+                    handshakeStatus = handshakeProtocol.getStatus();
+                    if (handshakeStatus.equals(
+                            SSLEngineResult.HandshakeStatus.FINISHED)) {
+                        session = recordProtocol.getSession();
+                    }
+                }
+                return new SSLEngineResult(
+                        getEngineStatus(), getHandshakeStatus(), 0, produced);
+            }
+        } catch (AlertException e) {
+            // fatal alert occured
+            alertProtocol.alert(AlertProtocol.FATAL, e.getDescriptionCode());
+            engine_was_closed = true;
+            if (session != null) {
+                session.invalidate();
+            }
+            // shutdown work will be made after the alert will be sent
+            // to another peer (by wrap method)
+            throw e.getReason();
+        }
+    }
+
+    // Shutdownes the engine and makes all cleanup work.
+    private void shutdown() {
+        engine_was_closed = true;
+        engine_was_shutteddown = true;
+        isOutboundDone = true;
+        isInboundDone = true;
+        if (handshake_started) {
+            alertProtocol.shutdown();
+            alertProtocol = null;
+            handshakeProtocol.shutdown();
+            handshakeProtocol = null;
+            recordProtocol.shutdown();
+            recordProtocol = null;
+        }
+    }
+
+
+    private SSLEngineResult.Status getEngineStatus() {
+        return (engine_was_closed)
+            ? SSLEngineResult.Status.CLOSED
+            : SSLEngineResult.Status.OK;
+    }
+}
+

Added: incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/SSLInputStream.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/SSLInputStream.java?rev=423275&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/SSLInputStream.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/SSLInputStream.java Tue Jul 18 15:50:12 2006
@@ -0,0 +1,134 @@
+/*
+ *  Copyright 2006 The Apache Software Foundation or its licensors, as applicable.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * @author Alexander Y. Kleymenov
+ * @version $Revision$
+ */
+
+package org.apache.harmony.security.provider.jsse;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * This class is a base for all input stream classes used
+ * in protocol implementation. It extends an InputStream with
+ * some additional read methods allowing to read TLS specific
+ * data types such as uint8, uint32 etc (see TLS v 1 specification
+ * at http://www.ietf.org/rfc/rfc2246.txt).
+ */
+public abstract class SSLInputStream extends InputStream {
+
+    /**
+     * @see java.io.InputStream#available()
+     */
+    public abstract int available() throws IOException;
+
+    /**
+     * Reads the following byte value. Note that in the case of
+     * reaching of the end of the data this methods throws the
+     * exception, not return -1. The type of exception depends
+     * on implementation. It was done for simplifying and speeding
+     * up of processing of such cases.
+     * @see SSLStreamedInput#read()
+     * @see SSLBufferedInput#read()
+     * @see HandshakeIODataStream#read()
+     */
+    public abstract int read() throws IOException;
+
+    /**
+     * @see java.io.InputStream#skip()
+     */
+    public long skip(long n) throws IOException {
+        long skept = n;
+        while (n > 0) {
+            read();
+            n--;
+        }
+        return skept;
+    }
+
+    /**
+     * Reads and returns uint8 value.
+     */
+    public int readUint8() throws IOException {
+        return read() & 0x00FF;
+    }
+
+    /**
+     * Reads and returns uint16 value.
+     */
+    public int readUint16() throws IOException {
+        return (read() << 8) | (read() & 0x00FF);
+    }
+
+    /**
+     * Reads and returns uint24 value.
+     */
+    public int readUint24() throws IOException {
+        return (read() << 16) | (read() << 8) | (read() & 0x00FF);
+    }
+
+    /**
+     * Reads and returns uint32 value.
+     */
+    public long readUint32() throws IOException {
+        return (read() << 24) | (read() << 16)
+              | (read() << 8) | (read() & 0x00FF);
+    }
+
+    /**
+     * Reads and returns uint64 value.
+     */
+    public long readUint64() throws IOException {
+        return (read() << 56) | (read() << 48)
+              | (read() << 40) | (read() << 32)
+              | (read() << 24) | (read() << 16)
+              | (read() << 8) | (read() & 0x00FF);
+    }
+
+    /**
+     * Returns the vector of opaque values of specified length;
+     * @param length - the length of the vector to be read.
+     * @return the read data
+     * @throws IOException if read operation could not be finished.
+     */
+    public byte[] read(int length) throws IOException {
+        byte[] res = new byte[length];
+        for (int i=0; i<length; i++) {
+            res[i] = (byte) read();
+        }
+        return res;
+    }
+
+    /**
+     * @see java.io.InputStream#read(byte[],int,int)
+     */
+    public int read(byte[] b, int off, int len) throws IOException {
+        int read_b;
+        int i = 0;
+        do {
+            if ((read_b = read()) == -1) {
+                return (i == 0) ? -1 : i;
+            }
+            b[off+i] = (byte) read_b;
+            i++;
+        } while ((available() != 0) && (i<len));
+        return i;
+    }
+}
+

Added: incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/SSLParameters.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/SSLParameters.java?rev=423275&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/SSLParameters.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/SSLParameters.java Tue Jul 18 15:50:12 2006
@@ -0,0 +1,377 @@
+/*
+ *  Copyright 2006 The Apache Software Foundation or its licensors, as applicable.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * @author Alexander Y. Kleymenov
+ * @version $Revision$
+ */
+
+package org.apache.harmony.security.provider.jsse;
+
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509KeyManager;
+import javax.net.ssl.X509TrustManager;
+
+/**
+ * The instances of this class incapsulate all the info
+ * about enabled cipher suites and protocols,
+ * as well as the information about client/server mode of
+ * ssl socket, whether it require/want client authentication or not,
+ * and controls whether new SSL sessions may be established by this
+ * socket or not.
+ */
+public class SSLParameters {
+
+    // default source of authentication keys
+    private static X509KeyManager defaultKeyManager;
+    // default source of authentication trust decisions
+    private static X509TrustManager defaultTrustManager;
+    // default source of random numbers
+    private static SecureRandom defaultSecureRandom;
+    // default SSL parameters
+    private static SSLParameters defaultParameters;
+
+    // client session context contains the set of reusable
+    // client-side SSL sessions
+    private SSLSessionContextImpl clientSessionContext =
+        new SSLSessionContextImpl();
+    // server session context contains the set of reusable
+    // server-side SSL sessions
+    private SSLSessionContextImpl serverSessionContext =
+        new SSLSessionContextImpl();
+    // source of authentication keys
+    private X509KeyManager keyManager;
+    // source of authentication trust decisions
+    private X509TrustManager trustManager;
+    // source of random numbers
+    private SecureRandom secureRandom;
+
+    // cipher suites available for SSL connection
+    protected CipherSuite[] enabledCipherSuites;
+    // string representations of available cipher suites
+    private String[] enabledCipherSuiteNames = null;
+
+    // protocols available for SSL connection
+    private String[] enabledProtocols = ProtocolVersion.supportedProtocols;
+    
+    // if the peer with this parameters tuned to work in client mode
+    private boolean client_mode = true;
+    // if the peer with this parameters tuned to require client authentication
+    private boolean need_client_auth = false;
+    // if the peer with this parameters tuned to request client authentication
+    private boolean want_client_auth = false;
+    // if the peer with this parameters allowed to cteate new SSL session
+    private boolean enable_session_creation = true;
+
+    /**
+     * Creates an instance of SSLParameters.
+     */
+    private SSLParameters() {
+        this.enabledCipherSuites = CipherSuite.defaultCipherSuites;
+    }
+
+    /**
+     * Initializes the parameters. Naturally this constructor is used
+     * in SSLContextImpl.engineInit method which dirrectly passes its 
+     * parameters. In other words this constructor holds all
+     * the functionality provided by SSLContext.init method.
+     * @see SSLContext.init(KeyManager,TrustManager,SecureRandom)
+     * for more information
+     */
+    protected SSLParameters(KeyManager[] kms, TrustManager[] tms,
+            SecureRandom sr) throws KeyManagementException {
+        this();
+    	try {
+            // initialize key manager
+            boolean initialize_default = false;
+            // It's not described by the spec of SSLContext what should happen 
+            // if the arrays of length 0 are specified. This implementation
+            // behave as for null arrays (i.e. use installed security providers)
+            if ((kms == null) || (kms.length == 0)) {
+                if (defaultKeyManager == null) {
+                    KeyManagerFactory kmf = KeyManagerFactory.getInstance(
+                            KeyManagerFactory.getDefaultAlgorithm());
+                    kmf.init(null, null);            	
+                    kms = kmf.getKeyManagers();
+                    // tell that we are trying to initialize defaultKeyManager
+                    initialize_default = true;
+                } else {
+                    keyManager = defaultKeyManager;
+                }
+            }
+            if (keyManager == null) { // was not initialized by default
+                for (int i = 0; i < kms.length; i++) {
+                    if (kms[i] instanceof X509KeyManager) {
+                        keyManager = (X509KeyManager)kms[i];
+                        break;
+                    }
+                }
+                if (keyManager == null) {
+                    throw new KeyManagementException("No X509KeyManager found");
+                }
+                if (initialize_default) {
+                    // found keyManager is default key manager
+                    defaultKeyManager = keyManager;
+                }
+            }
+            
+            // initialize trust manager
+            initialize_default = false;
+            if ((tms == null) || (tms.length == 0)) {
+                if (defaultTrustManager == null) {
+                    TrustManagerFactory tmf = TrustManagerFactory
+                        .getInstance(TrustManagerFactory.getDefaultAlgorithm());
+                    tmf.init((KeyStore)null);
+                    tms = tmf.getTrustManagers();
+                    initialize_default = true;
+                } else {
+                    trustManager = defaultTrustManager;
+                }
+            }
+            if (trustManager == null) { // was not initialized by default
+                for (int i = 0; i < tms.length; i++) {
+                    if (tms[i] instanceof X509TrustManager) {
+                        trustManager = (X509TrustManager)tms[i];
+                        break;
+                    }
+                }
+                if (trustManager == null) {
+                    throw new KeyManagementException("No X509TrustManager found");
+                }
+                if (initialize_default) {
+                    // found trustManager is default trust manager
+                    defaultTrustManager = trustManager;
+                }
+            }
+        } catch (NoSuchAlgorithmException e) {
+            throw new KeyManagementException(e);
+        } catch (KeyStoreException e) {
+            throw new KeyManagementException(e);
+        } catch (UnrecoverableKeyException e) {
+            throw new KeyManagementException(e);        	
+        }
+        // initialize secure random
+        if (sr == null) {
+            if (defaultSecureRandom == null) {
+        	    defaultSecureRandom = new SecureRandom();
+            }
+            secureRandom = defaultSecureRandom;
+        } else {
+            secureRandom = sr;
+        }
+    }
+
+    protected static SSLParameters getDefault() throws KeyManagementException {
+        if (defaultParameters == null) {
+            defaultParameters = new SSLParameters(null, null, null);
+        }
+        return (SSLParameters) defaultParameters.clone();
+    }
+    
+    /**
+     * @return server session context
+     */
+    protected SSLSessionContextImpl getServerSessionContext() {
+        return serverSessionContext;
+    }
+
+    /**
+     * @return client session context
+     */
+    protected SSLSessionContextImpl getClientSessionContext() {
+        return clientSessionContext;
+    }
+
+    /**
+     * @return key manager
+     */
+    protected X509KeyManager getKeyManager() {
+        return keyManager;
+    }
+
+    /**
+     * @return trust manager
+     */
+    protected X509TrustManager getTrustManager() {
+        return trustManager;
+    }
+
+    /**
+     * @return secure random
+     */
+    protected SecureRandom getSecureRandom() {
+        return secureRandom;
+    }
+
+    /**
+     * @return the names of enabled cipher suites
+     */
+    protected String[] getEnabledCipherSuites() {
+        if (enabledCipherSuiteNames == null) {
+            enabledCipherSuiteNames = new String[enabledCipherSuites.length];
+            for (int i = 0; i< enabledCipherSuites.length; i++) {
+                enabledCipherSuiteNames[i] = enabledCipherSuites[i].getName();
+            }
+        }
+        return (String[]) enabledCipherSuiteNames.clone();
+    }
+
+    /**
+     * Sets the set of available cipher suites for use in SSL connection.
+     * @param   suites: String[]
+     * @return
+     */
+    protected void setEnabledCipherSuites(String[] suites) {
+        if (suites == null) {
+            throw new IllegalArgumentException("Provided parameter is null");
+        }
+        CipherSuite[] cipherSuites = new CipherSuite[suites.length];
+        for (int i=0; i<suites.length; i++) {
+            cipherSuites[i] = CipherSuite.getByName(suites[i]);
+            if (cipherSuites[i] == null || !cipherSuites[i].supported) {
+                throw new IllegalArgumentException(suites[i] +
+                        " is not supported.");
+            }
+        }
+        enabledCipherSuites = cipherSuites;
+        enabledCipherSuiteNames = suites;
+    }
+
+    /**
+     * @return the set of enabled protocols
+     */
+    protected String[] getEnabledProtocols() {
+        return (String[]) enabledProtocols.clone();
+    }
+
+    /**
+     * Sets the set of available protocols for use in SSL connection.
+     * @param   suites: String[]
+     */
+    protected void setEnabledProtocols(String[] protocols) {
+        if (protocols == null) {
+            throw new IllegalArgumentException("Provided parameter is null");
+        }
+        for (int i=0; i<protocols.length; i++) {
+            if (!ProtocolVersion.isSupported(protocols[i])) {
+                throw new IllegalArgumentException("Protocol " + protocols[i] +
+                        " is not supported.");
+            }
+        }
+        enabledProtocols = protocols;
+    }
+
+    /**
+     * Tunes the peer holding this parameters to work in client mode.
+     * @param   mode if the peer is configured to work in client mode
+     */
+    protected void setUseClientMode(boolean mode) {
+        client_mode = mode;
+    }
+
+    /**
+     * Returns the value indicating if the parameters configured to work
+     * in client mode.
+     */
+    protected boolean getUseClientMode() {
+        return client_mode;
+    }
+
+    /**
+     * Tunes the peer holding this parameters to require client authentication
+     */
+    protected void setNeedClientAuth(boolean need) {
+        need_client_auth = need;
+        // reset the want_client_auth setting
+        want_client_auth = false;
+    }
+
+    /**
+     * Returns the value indicating if the peer with this parameters tuned
+     * to require client authentication
+     */
+    protected boolean getNeedClientAuth() {
+        return need_client_auth;
+    }
+
+    /**
+     * Tunes the peer holding this parameters to request client authentication
+     */
+    protected void setWantClientAuth(boolean want) {
+        want_client_auth = want;
+        // reset the need_client_auth setting
+        need_client_auth = false;
+    }
+
+    /**
+     * Returns the value indicating if the peer with this parameters
+     * tuned to request client authentication
+     * @return
+     */
+    protected boolean getWantClientAuth() {
+        return want_client_auth;
+    }
+
+    /**
+     * Allows/disallows the peer holding this parameters to
+     * create new SSL session
+     */
+    protected void setEnableSessionCreation(boolean flag) {
+        enable_session_creation = flag;
+    }
+
+    /**
+     * Returns the value indicating if the peer with this parameters
+     * allowed to cteate new SSL session
+     */
+    protected boolean getEnableSessionCreation() {
+        return enable_session_creation;
+    }
+
+    /**
+     * Returns the clone of this object.
+     * @return the clone.
+     */
+    protected Object clone() {
+        SSLParameters parameters = new SSLParameters();
+
+        parameters.clientSessionContext = clientSessionContext;
+        parameters.serverSessionContext = serverSessionContext;
+        parameters.keyManager = keyManager;
+        parameters.trustManager = trustManager;
+        parameters.secureRandom = secureRandom;
+
+        parameters.enabledCipherSuites = enabledCipherSuites;
+        parameters.enabledProtocols = enabledProtocols;
+
+        parameters.client_mode = client_mode;
+        parameters.need_client_auth = need_client_auth;
+        parameters.want_client_auth = want_client_auth;
+        parameters.enable_session_creation = enable_session_creation;
+
+        return parameters;
+    }
+}
+



Mime
View raw message