AbstractSessionContext.java revision a5c365c0867e66e6b5ad8e3e9a1cbd306f35226b
108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project/*
208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * Copyright (C) 2009 The Android Open Source Project
308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project *
408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * you may not use this file except in compliance with the License.
608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * You may obtain a copy of the License at
708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project *
808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project *
1008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
1208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * See the License for the specific language governing permissions and
1408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * limitations under the License.
1508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project */
1608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
1708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectpackage org.apache.harmony.xnet.provider.jsse;
1808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
194a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstromimport java.io.ByteArrayInputStream;
204a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstromimport java.io.ByteArrayOutputStream;
214a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstromimport java.io.DataInputStream;
224a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstromimport java.io.DataOutputStream;
234a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstromimport java.io.IOException;
24e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstromimport java.security.cert.Certificate;
25e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstromimport java.security.cert.CertificateEncodingException;
264a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstromimport java.util.Arrays;
274a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstromimport java.util.Enumeration;
284a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstromimport java.util.Iterator;
2961b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstromimport java.util.LinkedHashMap;
3061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstromimport java.util.Map;
314a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstromimport java.util.NoSuchElementException;
3208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.SSLSession;
3308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.SSLSessionContext;
34e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstromimport org.apache.harmony.security.provider.cert.X509CertImpl;
3508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
3608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project/**
3708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * Supports SSL session caches.
3808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project */
3908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectabstract class AbstractSessionContext implements SSLSessionContext {
4008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
4108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    volatile int maximumSize;
4208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    volatile int timeout;
4308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
4438c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice    final long sslCtxNativePointer = NativeCrypto.SSL_CTX_new();
4508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
4608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /** Identifies OpenSSL sessions. */
4708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    static final int OPEN_SSL = 1;
4808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
4961b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom    private final Map<ByteArray, SSLSession> sessions
5061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            = new LinkedHashMap<ByteArray, SSLSession>() {
5161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        @Override
5261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        protected boolean removeEldestEntry(
5361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                Map.Entry<ByteArray, SSLSession> eldest) {
54a5c365c0867e66e6b5ad8e3e9a1cbd306f35226bBrian Carlstrom            boolean remove = maximumSize > 0 && size() > maximumSize;
55a5c365c0867e66e6b5ad8e3e9a1cbd306f35226bBrian Carlstrom            if (remove) {
56a5c365c0867e66e6b5ad8e3e9a1cbd306f35226bBrian Carlstrom                remove(eldest.getKey());
57a5c365c0867e66e6b5ad8e3e9a1cbd306f35226bBrian Carlstrom                sessionRemoved(eldest.getValue());
58a5c365c0867e66e6b5ad8e3e9a1cbd306f35226bBrian Carlstrom            }
59a5c365c0867e66e6b5ad8e3e9a1cbd306f35226bBrian Carlstrom            return false;
6061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
6161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom    };
6261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom
6308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
6408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Constructs a new session context.
6508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *
6608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @param maximumSize of cache
6708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @param timeout for cache entries
6808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
692785b7f916644f939b599cf6b01a3df6fae1eca5Brian Carlstrom    AbstractSessionContext(int maximumSize, int timeout) {
7008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        this.maximumSize = maximumSize;
7108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        this.timeout = timeout;
7208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
7308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
7561b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom     * Returns the collection of sessions ordered from oldest to newest
7608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
7761b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom    private Iterator<SSLSession> sessionIterator() {
7861b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        synchronized (sessions) {
7961b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            SSLSession[] array = sessions.values().toArray(
8061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                    new SSLSession[sessions.size()]);
8161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            return Arrays.asList(array).iterator();
8261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
8361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom    }
8408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
8508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    public final Enumeration getIds() {
864a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom        final Iterator<SSLSession> i = sessionIterator();
8708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return new Enumeration<byte[]>() {
884a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom            private SSLSession next;
8908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            public boolean hasMoreElements() {
904a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                if (next != null) {
914a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                    return true;
924a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                }
934a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                while (i.hasNext()) {
944a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                    SSLSession session = i.next();
954a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                    if (session.isValid()) {
964a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                        next = session;
974a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                        return true;
984a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                    }
994a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                }
1004a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                next = null;
1014a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                return false;
10208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
10308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            public byte[] nextElement() {
1044a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                if (hasMoreElements()) {
1054a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                    byte[] id = next.getId();
1064a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                    next = null;
1074a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                    return id;
1084a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                }
1094a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                throw new NoSuchElementException();
11008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
11108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        };
11208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
11308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
11408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    public final int getSessionCacheSize() {
11508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return maximumSize;
11608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
11708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
11808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    public final int getSessionTimeout() {
11908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return timeout;
12008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
12108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
12208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
12308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Makes sure cache size is < maximumSize.
12408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
12561b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom    protected void trimToSize() {
12661b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        synchronized (sessions) {
12761b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            int size = sessions.size();
12861b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            if (size > maximumSize) {
12961b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                int removals = size - maximumSize;
13061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                Iterator<SSLSession> i = sessions.values().iterator();
13161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                do {
13261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                    SSLSession session = i.next();
13361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                    i.remove();
13461b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                    sessionRemoved(session);
13561b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                } while (--removals > 0);
13661b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            }
13761b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
13861b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom    }
13961b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom
14061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom    public void setSessionTimeout(int seconds)
14161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            throws IllegalArgumentException {
14261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        if (seconds < 0) {
14361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            throw new IllegalArgumentException("seconds < 0");
14461b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
14561b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        timeout = seconds;
14661b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom
14761b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        synchronized (sessions) {
14861b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            Iterator<SSLSession> i = sessions.values().iterator();
14961b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            while (i.hasNext()) {
15061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                SSLSession session = i.next();
15161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                // SSLSession's know their context and consult the
15261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                // timeout as part of their validity condition.
15361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                if (!session.isValid()) {
15461b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                    i.remove();
15561b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                    sessionRemoved(session);
15661b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                }
15761b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            }
15861b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
15961b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom    }
16061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom
1611f42e0a4d7d28b8fc20833e0be05ad17dcfa8ea0Brian Carlstrom    /**
16261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom     * Called when a session is removed. Used by ClientSessionContext
16361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom     * to update its host-and-port based cache.
16461b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom     */
165ff69e28cd239217f33fe96a9c8e7c40b658c19f9Jesse Wilson    protected abstract void sessionRemoved(SSLSession session);
16608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
16708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    public final void setSessionCacheSize(int size)
16808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throws IllegalArgumentException {
16908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (size < 0) {
17008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException("size < 0");
17108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
17208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
17308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        int oldMaximum = maximumSize;
17408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        maximumSize = size;
17508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
17608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        // Trim cache to size if necessary.
17708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (size < oldMaximum) {
17808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            trimToSize();
17908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
18008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
18108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
18208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
18308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Converts the given session to bytes.
18408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *
18508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @return session data as bytes or null if the session can't be converted
18608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
18708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    byte[] toBytes(SSLSession session) {
18808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        // TODO: Support SSLSessionImpl, too.
18908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (!(session instanceof OpenSSLSessionImpl)) {
19008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            return null;
19108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
19208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
19308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        OpenSSLSessionImpl sslSession = (OpenSSLSessionImpl) session;
19408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        try {
19508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            ByteArrayOutputStream baos = new ByteArrayOutputStream();
19608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            DataOutputStream daos = new DataOutputStream(baos);
19708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
19808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            daos.writeInt(OPEN_SSL); // session type ID
19908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
20008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            // Session data.
20108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            byte[] data = sslSession.getEncoded();
20208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            daos.writeInt(data.length);
20308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            daos.write(data);
20408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
20508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            // Certificates.
206e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            Certificate[] certs = session.getPeerCertificates();
20708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            daos.writeInt(certs.length);
20808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
209e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            for (Certificate cert : certs) {
21008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                data = cert.getEncoded();
21108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                daos.writeInt(data.length);
21208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                daos.write(data);
21308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
2142828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            // TODO: local certificates?
21508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
21608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            return baos.toByteArray();
21708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        } catch (IOException e) {
21808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            log(e);
21908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            return null;
22008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        } catch (CertificateEncodingException e) {
22108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            log(e);
22208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            return null;
22308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
22408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
22508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
22608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
22708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Creates a session from the given bytes.
22808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *
22908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @return a session or null if the session can't be converted
23008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
23108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    SSLSession toSession(byte[] data, String host, int port) {
23208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        ByteArrayInputStream bais = new ByteArrayInputStream(data);
23308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        DataInputStream dais = new DataInputStream(bais);
23408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        try {
23508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            int type = dais.readInt();
23608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            if (type != OPEN_SSL) {
23708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                log(new AssertionError("Unexpected type ID: " + type));
23808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                return null;
23908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
24008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
24108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            int length = dais.readInt();
24208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            byte[] sessionData = new byte[length];
24308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            dais.readFully(sessionData);
24408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
24508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            int count = dais.readInt();
246e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            X509CertImpl[] certs = new X509CertImpl[count];
24708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            for (int i = 0; i < count; i++) {
24808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                length = dais.readInt();
24908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                byte[] certData = new byte[length];
25008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                dais.readFully(certData);
251e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                certs[i] = new X509CertImpl(certData);
25208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
25308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
2542828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            return new OpenSSLSessionImpl(sessionData, host, port, certs, this);
25508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        } catch (IOException e) {
25608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            log(e);
25708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            return null;
25808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
25908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
26008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
26161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom    public SSLSession getSession(byte[] sessionId) {
26261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        if (sessionId == null) {
26361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            throw new NullPointerException("sessionId == null");
26461b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
26561b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        ByteArray key = new ByteArray(sessionId);
26661b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        SSLSession session;
26761b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        synchronized (sessions) {
26861b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            session = sessions.get(key);
26961b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
27061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        if (session != null && session.isValid()) {
27161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            return session;
27261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
27361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        return null;
27461b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom    }
27561b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom
27661b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom    void putSession(SSLSession session) {
27761b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        byte[] id = session.getId();
27861b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        if (id.length == 0) {
27961b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            return;
28061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
28161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        ByteArray key = new ByteArray(id);
28261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        synchronized (sessions) {
28361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            sessions.put(key, session);
28461b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
28561b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom    }
286f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
28708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    static void log(Throwable t) {
2885006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson        System.logW("Error converting session.", t);
28908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
29008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
2911990574e420184f3ad43400171f624dad44700d8Brian Carlstrom    @Override protected void finalize() throws Throwable {
2921990574e420184f3ad43400171f624dad44700d8Brian Carlstrom        try {
2931990574e420184f3ad43400171f624dad44700d8Brian Carlstrom            NativeCrypto.SSL_CTX_free(sslCtxNativePointer);
2941990574e420184f3ad43400171f624dad44700d8Brian Carlstrom        } finally {
2951990574e420184f3ad43400171f624dad44700d8Brian Carlstrom            super.finalize();
2961990574e420184f3ad43400171f624dad44700d8Brian Carlstrom        }
297f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    }
298f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom}
299