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