AbstractSessionContext.java revision 3e46e4ee56c8e37158f46941dedd5b436d724baa
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
17860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootpackage org.conscrypt;
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;
26860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootimport java.security.cert.X509Certificate;
274a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstromimport java.util.Arrays;
284a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstromimport java.util.Enumeration;
294a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstromimport java.util.Iterator;
3061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstromimport java.util.LinkedHashMap;
3161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstromimport java.util.Map;
324a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstromimport java.util.NoSuchElementException;
3308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.SSLSession;
3408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.SSLSessionContext;
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
85f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
86209c986cfe42dbaa5497c6e68d1b5db96b28db78Kenny Root    public final Enumeration<byte[]> getIds() {
874a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom        final Iterator<SSLSession> i = sessionIterator();
8808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return new Enumeration<byte[]>() {
894a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom            private SSLSession next;
90f06338c01394610174fe2b3532beac56d61d9e26Kenny Root
91f06338c01394610174fe2b3532beac56d61d9e26Kenny Root            @Override
9208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            public boolean hasMoreElements() {
934a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                if (next != null) {
944a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                    return true;
954a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                }
964a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                while (i.hasNext()) {
974a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                    SSLSession session = i.next();
984a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                    if (session.isValid()) {
994a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                        next = session;
1004a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                        return true;
1014a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                    }
1024a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                }
1034a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                next = null;
1044a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                return false;
10508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
106f06338c01394610174fe2b3532beac56d61d9e26Kenny Root
107f06338c01394610174fe2b3532beac56d61d9e26Kenny Root            @Override
10808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            public byte[] nextElement() {
1094a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                if (hasMoreElements()) {
1104a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                    byte[] id = next.getId();
1114a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                    next = null;
1124a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                    return id;
1134a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                }
1144a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom                throw new NoSuchElementException();
11508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
11608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        };
11708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
11808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
119f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
12008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    public final int getSessionCacheSize() {
12108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return maximumSize;
12208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
12308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
124f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
12508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    public final int getSessionTimeout() {
12608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return timeout;
12708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
12808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
12908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
13008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Makes sure cache size is < maximumSize.
13108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
13261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom    protected void trimToSize() {
13361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        synchronized (sessions) {
13461b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            int size = sessions.size();
13561b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            if (size > maximumSize) {
13661b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                int removals = size - maximumSize;
13761b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                Iterator<SSLSession> i = sessions.values().iterator();
13861b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                do {
13961b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                    SSLSession session = i.next();
14061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                    i.remove();
14161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                    sessionRemoved(session);
14261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                } while (--removals > 0);
14361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            }
14461b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
14561b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom    }
14661b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom
147f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
14861b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom    public void setSessionTimeout(int seconds)
14961b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            throws IllegalArgumentException {
15061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        if (seconds < 0) {
15161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            throw new IllegalArgumentException("seconds < 0");
15261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
15361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        timeout = seconds;
15461b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom
15561b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        synchronized (sessions) {
15661b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            Iterator<SSLSession> i = sessions.values().iterator();
15761b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            while (i.hasNext()) {
15861b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                SSLSession session = i.next();
15961b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                // SSLSession's know their context and consult the
16061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                // timeout as part of their validity condition.
16161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                if (!session.isValid()) {
16261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                    i.remove();
16361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                    sessionRemoved(session);
16461b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                }
16561b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            }
16661b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
16761b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom    }
16861b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom
1691f42e0a4d7d28b8fc20833e0be05ad17dcfa8ea0Brian Carlstrom    /**
17061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom     * Called when a session is removed. Used by ClientSessionContext
17161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom     * to update its host-and-port based cache.
17261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom     */
173ff69e28cd239217f33fe96a9c8e7c40b658c19f9Jesse Wilson    protected abstract void sessionRemoved(SSLSession session);
17408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
175f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
17608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    public final void setSessionCacheSize(int size)
17708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throws IllegalArgumentException {
17808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (size < 0) {
17908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException("size < 0");
18008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
18108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
18208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        int oldMaximum = maximumSize;
18308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        maximumSize = size;
18408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
18508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        // Trim cache to size if necessary.
18608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (size < oldMaximum) {
18708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            trimToSize();
18808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
18908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
19008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
19108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
19208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Converts the given session to bytes.
19308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *
19408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @return session data as bytes or null if the session can't be converted
19508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
19608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    byte[] toBytes(SSLSession session) {
19708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        // TODO: Support SSLSessionImpl, too.
19808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (!(session instanceof OpenSSLSessionImpl)) {
19908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            return null;
20008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
20108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
20208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        OpenSSLSessionImpl sslSession = (OpenSSLSessionImpl) session;
20308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        try {
20408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            ByteArrayOutputStream baos = new ByteArrayOutputStream();
20508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            DataOutputStream daos = new DataOutputStream(baos);
20608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
20708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            daos.writeInt(OPEN_SSL); // session type ID
20808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
20908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            // Session data.
21008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            byte[] data = sslSession.getEncoded();
21108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            daos.writeInt(data.length);
21208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            daos.write(data);
21308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
21408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            // Certificates.
215e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            Certificate[] certs = session.getPeerCertificates();
21608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            daos.writeInt(certs.length);
21708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
218e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            for (Certificate cert : certs) {
21908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                data = cert.getEncoded();
22008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                daos.writeInt(data.length);
22108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                daos.write(data);
22208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
2232828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            // TODO: local certificates?
22408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
22508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            return baos.toByteArray();
22608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        } catch (IOException e) {
22708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            log(e);
22808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            return null;
22908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        } catch (CertificateEncodingException e) {
23008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            log(e);
23108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            return null;
23208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
23308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
23408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
23508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
23608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Creates a session from the given bytes.
23708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *
23808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @return a session or null if the session can't be converted
23908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
24008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    SSLSession toSession(byte[] data, String host, int port) {
24108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        ByteArrayInputStream bais = new ByteArrayInputStream(data);
24208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        DataInputStream dais = new DataInputStream(bais);
24308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        try {
24408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            int type = dais.readInt();
24508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            if (type != OPEN_SSL) {
24608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                log(new AssertionError("Unexpected type ID: " + type));
24708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                return null;
24808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
24908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
25008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            int length = dais.readInt();
25108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            byte[] sessionData = new byte[length];
25208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            dais.readFully(sessionData);
25308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
25408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            int count = dais.readInt();
255860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root            X509Certificate[] certs = new X509Certificate[count];
25608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            for (int i = 0; i < count; i++) {
25708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                length = dais.readInt();
25808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                byte[] certData = new byte[length];
25908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                dais.readFully(certData);
260860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root                certs[i] = OpenSSLX509Certificate.fromX509Der(certData);
26108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
26208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
2632828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            return new OpenSSLSessionImpl(sessionData, host, port, certs, this);
26408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        } catch (IOException e) {
26508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            log(e);
26608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            return null;
26708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
26808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
26908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
270f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
27161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom    public SSLSession getSession(byte[] sessionId) {
27261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        if (sessionId == null) {
27361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            throw new NullPointerException("sessionId == null");
27461b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
27561b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        ByteArray key = new ByteArray(sessionId);
27661b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        SSLSession session;
27761b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        synchronized (sessions) {
27861b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            session = sessions.get(key);
27961b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
28061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        if (session != null && session.isValid()) {
28161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            return session;
28261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
28361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        return null;
28461b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom    }
28561b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom
28661b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom    void putSession(SSLSession session) {
28761b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        byte[] id = session.getId();
28861b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        if (id.length == 0) {
28961b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            return;
29061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
29161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        ByteArray key = new ByteArray(id);
29261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        synchronized (sessions) {
29361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            sessions.put(key, session);
29461b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
29561b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom    }
296f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
29708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    static void log(Throwable t) {
2983e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root        new Exception("Error converting session", t).printStackTrace();
29908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
30008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
301f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
302f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    protected void finalize() throws Throwable {
3031990574e420184f3ad43400171f624dad44700d8Brian Carlstrom        try {
3041990574e420184f3ad43400171f624dad44700d8Brian Carlstrom            NativeCrypto.SSL_CTX_free(sslCtxNativePointer);
3051990574e420184f3ad43400171f624dad44700d8Brian Carlstrom        } finally {
3061990574e420184f3ad43400171f624dad44700d8Brian Carlstrom            super.finalize();
3071990574e420184f3ad43400171f624dad44700d8Brian Carlstrom        }
308f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    }
309f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom}
310