1/* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package org.conscrypt; 18 19import java.security.Principal; 20import java.security.cert.Certificate; 21import java.util.HashMap; 22import java.util.List; 23import javax.net.ssl.SSLPeerUnverifiedException; 24import javax.net.ssl.SSLSession; 25import javax.net.ssl.SSLSessionBindingEvent; 26import javax.net.ssl.SSLSessionBindingListener; 27import javax.net.ssl.SSLSessionContext; 28import javax.security.cert.X509Certificate; 29 30/** 31 * An externalized view of the underlying {@link SSLSession} used within a 32 * socket/engine. This class provides the caller with a consistent session 33 * handle which will continue to be usable regardless of internal changes 34 * to the connection. It does this by delegating calls to the <b>current</b> 35 * internal session, which is provided by the session {@code Provider} 36 * (i.e. the socket or engine that owns the session). This allows the provider 37 * to switch implementations (for instance, using a JNI implementation to 38 * access live values while the connection is open and a set of final values 39 * when the connection is closed), even if the caller stores a reference to 40 * the session object. 41 * 42 * <p>This class implements the {@link SSLSession} value API itself, rather 43 * than delegating to the provided session, to ensure the caller has a consistent 44 * value map, regardless of which internal session is currently being used by the 45 * socket/engine. This class will never call the value API methods on the 46 * underlying sessions, so they need not be implemented. 47 */ 48final class ExternalSession implements SessionDecorator { 49 50 // Use an initialcapacity of 2 to keep it small in the average case. 51 private final HashMap<String, Object> values = new HashMap<String, Object>(2); 52 private final Provider provider; 53 54 public ExternalSession(Provider provider) { 55 this.provider = provider; 56 } 57 58 @Override 59 public ConscryptSession getDelegate() { 60 return provider.provideSession(); 61 } 62 63 @Override 64 public String getRequestedServerName() { 65 return getDelegate().getRequestedServerName(); 66 } 67 68 @Override 69 public List<byte[]> getStatusResponses() { 70 return getDelegate().getStatusResponses(); 71 } 72 73 @Override 74 public byte[] getPeerSignedCertificateTimestamp() { 75 return getDelegate().getPeerSignedCertificateTimestamp(); 76 } 77 78 @Override 79 public byte[] getId() { 80 return getDelegate().getId(); 81 } 82 83 @Override 84 public SSLSessionContext getSessionContext() { 85 return getDelegate().getSessionContext(); 86 } 87 88 @Override 89 public long getCreationTime() { 90 return getDelegate().getCreationTime(); 91 } 92 93 @Override 94 public long getLastAccessedTime() { 95 return getDelegate().getLastAccessedTime(); 96 } 97 98 @Override 99 public void invalidate() { 100 getDelegate().invalidate(); 101 } 102 103 @Override 104 public boolean isValid() { 105 return getDelegate().isValid(); 106 } 107 108 @Override 109 public java.security.cert.X509Certificate[] getPeerCertificates() 110 throws SSLPeerUnverifiedException { 111 return getDelegate().getPeerCertificates(); 112 } 113 114 @Override 115 public Certificate[] getLocalCertificates() { 116 return getDelegate().getLocalCertificates(); 117 } 118 119 @Override 120 public X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException { 121 return getDelegate().getPeerCertificateChain(); 122 } 123 124 @Override 125 public Principal getPeerPrincipal() throws SSLPeerUnverifiedException { 126 return getDelegate().getPeerPrincipal(); 127 } 128 129 @Override 130 public Principal getLocalPrincipal() { 131 return getDelegate().getLocalPrincipal(); 132 } 133 134 @Override 135 public String getCipherSuite() { 136 return getDelegate().getCipherSuite(); 137 } 138 139 @Override 140 public String getProtocol() { 141 return getDelegate().getProtocol(); 142 } 143 144 @Override 145 public String getPeerHost() { 146 return getDelegate().getPeerHost(); 147 } 148 149 @Override 150 public int getPeerPort() { 151 return getDelegate().getPeerPort(); 152 } 153 154 @Override 155 public int getPacketBufferSize() { 156 return getDelegate().getPacketBufferSize(); 157 } 158 159 @Override 160 public int getApplicationBufferSize() { 161 return getDelegate().getApplicationBufferSize(); 162 } 163 164 @Override 165 public Object getValue(String name) { 166 if (name == null) { 167 throw new IllegalArgumentException("name == null"); 168 } 169 return values.get(name); 170 } 171 172 @Override 173 public String[] getValueNames() { 174 return values.keySet().toArray(new String[values.size()]); 175 } 176 177 @Override 178 public void putValue(String name, Object value) { 179 if (name == null || value == null) { 180 throw new IllegalArgumentException("name == null || value == null"); 181 } 182 Object old = values.put(name, value); 183 if (value instanceof SSLSessionBindingListener) { 184 ((SSLSessionBindingListener) value).valueBound(new SSLSessionBindingEvent(this, name)); 185 } 186 if (old instanceof SSLSessionBindingListener) { 187 ((SSLSessionBindingListener) old).valueUnbound(new SSLSessionBindingEvent(this, name)); 188 } 189 190 } 191 192 @Override 193 public void removeValue(String name) { 194 if (name == null) { 195 throw new IllegalArgumentException("name == null"); 196 } 197 Object old = values.remove(name); 198 if (old instanceof SSLSessionBindingListener) { 199 SSLSessionBindingListener listener = (SSLSessionBindingListener) old; 200 listener.valueUnbound(new SSLSessionBindingEvent(this, name)); 201 } 202 } 203 204 /** 205 * The provider of the current delegate session. 206 */ 207 interface Provider { 208 ConscryptSession provideSession(); 209 } 210} 211