1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Copyright (C) 2009 The Android Open Source Project
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * you may not use this file except in compliance with the License.
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * You may obtain a copy of the License at
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * See the License for the specific language governing permissions and
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * limitations under the License.
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage org.apache.harmony.xnet.provider.jsse;
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
19a7ae90de24809b266bb5efdc9033a3261e31f521Brian Carlstromimport java.io.ByteArrayInputStream;
20a7ae90de24809b266bb5efdc9033a3261e31f521Brian Carlstromimport java.io.ByteArrayOutputStream;
21a7ae90de24809b266bb5efdc9033a3261e31f521Brian Carlstromimport java.io.DataInputStream;
22a7ae90de24809b266bb5efdc9033a3261e31f521Brian Carlstromimport java.io.DataOutputStream;
23a7ae90de24809b266bb5efdc9033a3261e31f521Brian Carlstromimport java.io.IOException;
24df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstromimport java.security.cert.Certificate;
25df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstromimport java.security.cert.CertificateEncodingException;
26a7ae90de24809b266bb5efdc9033a3261e31f521Brian Carlstromimport java.util.Arrays;
27a7ae90de24809b266bb5efdc9033a3261e31f521Brian Carlstromimport java.util.Enumeration;
28a7ae90de24809b266bb5efdc9033a3261e31f521Brian Carlstromimport java.util.Iterator;
299acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstromimport java.util.LinkedHashMap;
309acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstromimport java.util.Map;
31a7ae90de24809b266bb5efdc9033a3261e31f521Brian Carlstromimport java.util.NoSuchElementException;
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport javax.net.ssl.SSLSession;
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport javax.net.ssl.SSLSessionContext;
34df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstromimport org.apache.harmony.security.provider.cert.X509CertImpl;
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Supports SSL session caches.
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectabstract class AbstractSessionContext implements SSLSessionContext {
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    volatile int maximumSize;
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    volatile int timeout;
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
44f365a1c9cec94071b7a3161d7bdcb3f61d28f912Brian Carlstrom    final int sslCtxNativePointer = NativeCrypto.SSL_CTX_new();
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /** Identifies OpenSSL sessions. */
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    static final int OPEN_SSL = 1;
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
499acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom    private final Map<ByteArray, SSLSession> sessions
509acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            = new LinkedHashMap<ByteArray, SSLSession>() {
519acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        @Override
529acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        protected boolean removeEldestEntry(
539acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                Map.Entry<ByteArray, SSLSession> eldest) {
549acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            return maximumSize > 0 && size() > maximumSize;
559acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        }
569acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom    };
579acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom
58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Constructs a new session context.
60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param maximumSize of cache
62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param timeout for cache entries
63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
64f365a1c9cec94071b7a3161d7bdcb3f61d28f912Brian Carlstrom    AbstractSessionContext(int maximumSize, int timeout) {
65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.maximumSize = maximumSize;
66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.timeout = timeout;
67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
709acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom     * Returns the collection of sessions ordered from oldest to newest
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
729acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom    private Iterator<SSLSession> sessionIterator() {
739acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        synchronized (sessions) {
749acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            SSLSession[] array = sessions.values().toArray(
759acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                    new SSLSession[sessions.size()]);
769acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            return Arrays.asList(array).iterator();
779acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        }
789acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom    }
79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final Enumeration getIds() {
81a7ae90de24809b266bb5efdc9033a3261e31f521Brian Carlstrom        final Iterator<SSLSession> i = sessionIterator();
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return new Enumeration<byte[]>() {
83a7ae90de24809b266bb5efdc9033a3261e31f521Brian Carlstrom            private SSLSession next;
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            public boolean hasMoreElements() {
85a7ae90de24809b266bb5efdc9033a3261e31f521Brian Carlstrom                if (next != null) {
86a7ae90de24809b266bb5efdc9033a3261e31f521Brian Carlstrom                    return true;
87a7ae90de24809b266bb5efdc9033a3261e31f521Brian Carlstrom                }
88a7ae90de24809b266bb5efdc9033a3261e31f521Brian Carlstrom                while (i.hasNext()) {
89a7ae90de24809b266bb5efdc9033a3261e31f521Brian Carlstrom                    SSLSession session = i.next();
90a7ae90de24809b266bb5efdc9033a3261e31f521Brian Carlstrom                    if (session.isValid()) {
91a7ae90de24809b266bb5efdc9033a3261e31f521Brian Carlstrom                        next = session;
92a7ae90de24809b266bb5efdc9033a3261e31f521Brian Carlstrom                        return true;
93a7ae90de24809b266bb5efdc9033a3261e31f521Brian Carlstrom                    }
94a7ae90de24809b266bb5efdc9033a3261e31f521Brian Carlstrom                }
95a7ae90de24809b266bb5efdc9033a3261e31f521Brian Carlstrom                next = null;
96a7ae90de24809b266bb5efdc9033a3261e31f521Brian Carlstrom                return false;
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            public byte[] nextElement() {
99a7ae90de24809b266bb5efdc9033a3261e31f521Brian Carlstrom                if (hasMoreElements()) {
100a7ae90de24809b266bb5efdc9033a3261e31f521Brian Carlstrom                    byte[] id = next.getId();
101a7ae90de24809b266bb5efdc9033a3261e31f521Brian Carlstrom                    next = null;
102a7ae90de24809b266bb5efdc9033a3261e31f521Brian Carlstrom                    return id;
103a7ae90de24809b266bb5efdc9033a3261e31f521Brian Carlstrom                }
104a7ae90de24809b266bb5efdc9033a3261e31f521Brian Carlstrom                throw new NoSuchElementException();
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        };
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final int getSessionCacheSize() {
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return maximumSize;
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final int getSessionTimeout() {
114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return timeout;
115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Makes sure cache size is < maximumSize.
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
1209acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom    protected void trimToSize() {
1219acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        synchronized (sessions) {
1229acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            int size = sessions.size();
1239acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            if (size > maximumSize) {
1249acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                int removals = size - maximumSize;
1259acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                Iterator<SSLSession> i = sessions.values().iterator();
1269acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                do {
1279acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                    SSLSession session = i.next();
1289acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                    i.remove();
1299acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                    sessionRemoved(session);
1309acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                } while (--removals > 0);
1319acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            }
1329acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        }
1339acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom    }
1349acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom
1359acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom    public void setSessionTimeout(int seconds)
1369acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            throws IllegalArgumentException {
1379acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        if (seconds < 0) {
1389acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            throw new IllegalArgumentException("seconds < 0");
1399acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        }
1409acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        timeout = seconds;
1419acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom
1429acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        synchronized (sessions) {
1439acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            Iterator<SSLSession> i = sessions.values().iterator();
1449acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            while (i.hasNext()) {
1459acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                SSLSession session = i.next();
1469acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                // SSLSession's know their context and consult the
1479acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                // timeout as part of their validity condition.
1489acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                if (!session.isValid()) {
1499acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                    i.remove();
1509acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                    sessionRemoved(session);
1519acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                }
1529acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            }
1539acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        }
1549acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom    }
1559acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom
15612cd1f00c2fa1a7f37bf644cecdf7588bdc0b0a9Brian Carlstrom    /**
1579acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom     * Called when a session is removed. Used by ClientSessionContext
1589acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom     * to update its host-and-port based cache.
1599acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom     */
160d29fddcf333997fc2d7429d531e4d934dc705c88Jesse Wilson    protected abstract void sessionRemoved(SSLSession session);
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final void setSessionCacheSize(int size)
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throws IllegalArgumentException {
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (size < 0) {
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException("size < 0");
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int oldMaximum = maximumSize;
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        maximumSize = size;
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Trim cache to size if necessary.
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (size < oldMaximum) {
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            trimToSize();
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Converts the given session to bytes.
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return session data as bytes or null if the session can't be converted
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    byte[] toBytes(SSLSession session) {
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // TODO: Support SSLSessionImpl, too.
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (!(session instanceof OpenSSLSessionImpl)) {
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return null;
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        OpenSSLSessionImpl sslSession = (OpenSSLSessionImpl) session;
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ByteArrayOutputStream baos = new ByteArrayOutputStream();
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            DataOutputStream daos = new DataOutputStream(baos);
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            daos.writeInt(OPEN_SSL); // session type ID
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // Session data.
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            byte[] data = sslSession.getEncoded();
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            daos.writeInt(data.length);
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            daos.write(data);
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // Certificates.
201df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom            Certificate[] certs = session.getPeerCertificates();
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            daos.writeInt(certs.length);
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
204df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom            for (Certificate cert : certs) {
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                data = cert.getEncoded();
206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                daos.writeInt(data.length);
207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                daos.write(data);
208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
209bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            // TODO: local certificates?
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return baos.toByteArray();
212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (IOException e) {
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            log(e);
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return null;
215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (CertificateEncodingException e) {
216adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            log(e);
217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return null;
218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
220adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
222adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Creates a session from the given bytes.
223adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
224adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return a session or null if the session can't be converted
225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
226adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    SSLSession toSession(byte[] data, String host, int port) {
227adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ByteArrayInputStream bais = new ByteArrayInputStream(data);
228adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        DataInputStream dais = new DataInputStream(bais);
229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int type = dais.readInt();
231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (type != OPEN_SSL) {
232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                log(new AssertionError("Unexpected type ID: " + type));
233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return null;
234adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int length = dais.readInt();
237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            byte[] sessionData = new byte[length];
238adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            dais.readFully(sessionData);
239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int count = dais.readInt();
241df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom            X509CertImpl[] certs = new X509CertImpl[count];
242adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            for (int i = 0; i < count; i++) {
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                length = dais.readInt();
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                byte[] certData = new byte[length];
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                dais.readFully(certData);
246df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom                certs[i] = new X509CertImpl(certData);
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
249bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            return new OpenSSLSessionImpl(sessionData, host, port, certs, this);
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (IOException e) {
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            log(e);
252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return null;
253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
2569acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom    public SSLSession getSession(byte[] sessionId) {
2579acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        if (sessionId == null) {
2589acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            throw new NullPointerException("sessionId == null");
2599acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        }
2609acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        ByteArray key = new ByteArray(sessionId);
2619acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        SSLSession session;
2629acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        synchronized (sessions) {
2639acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            session = sessions.get(key);
2649acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        }
2659acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        if (session != null && session.isValid()) {
2669acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            return session;
2679acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        }
2689acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        return null;
2699acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom    }
2709acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom
2719acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom    void putSession(SSLSession session) {
2729acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        byte[] id = session.getId();
2739acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        if (id.length == 0) {
2749acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            return;
2759acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        }
2769acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        ByteArray key = new ByteArray(id);
2779acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        synchronized (sessions) {
2789acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            sessions.put(key, session);
2799acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        }
2809acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom    }
281ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    static void log(Throwable t) {
2830c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson        System.logW("Error converting session.", t);
284adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
286e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom    @Override protected void finalize() throws Throwable {
287e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        try {
288e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            NativeCrypto.SSL_CTX_free(sslCtxNativePointer);
289e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        } finally {
290e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            super.finalize();
291e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        }
292ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom    }
293ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom}
294