33 import java.util.ArrayList; |
33 import java.util.ArrayList; |
34 import java.util.Queue; |
34 import java.util.Queue; |
35 import java.util.Collection; |
35 import java.util.Collection; |
36 import java.util.Collections; |
36 import java.util.Collections; |
37 import java.util.Enumeration; |
37 import java.util.Enumeration; |
38 import java.util.Hashtable; |
|
39 import java.util.List; |
38 import java.util.List; |
40 import java.util.Vector; |
|
41 import java.util.Optional; |
39 import java.util.Optional; |
|
40 import java.util.concurrent.ConcurrentHashMap; |
42 import java.util.concurrent.ConcurrentLinkedQueue; |
41 import java.util.concurrent.ConcurrentLinkedQueue; |
43 import javax.crypto.SecretKey; |
42 import javax.crypto.SecretKey; |
44 import javax.net.ssl.ExtendedSSLSession; |
43 import javax.net.ssl.ExtendedSSLSession; |
45 import javax.net.ssl.SNIServerName; |
44 import javax.net.ssl.SNIServerName; |
46 import javax.net.ssl.SSLPeerUnverifiedException; |
45 import javax.net.ssl.SSLPeerUnverifiedException; |
72 /* |
71 /* |
73 * we only really need a single null session |
72 * we only really need a single null session |
74 */ |
73 */ |
75 static final SSLSessionImpl nullSession = new SSLSessionImpl(); |
74 static final SSLSessionImpl nullSession = new SSLSessionImpl(); |
76 |
75 |
77 // compression methods |
|
78 private static final byte compression_null = 0; |
|
79 |
|
80 /* |
76 /* |
81 * The state of a single session, as described in section 7.1 |
77 * The state of a single session, as described in section 7.1 |
82 * of the SSLv3 spec. |
78 * of the SSLv3 spec. |
83 */ |
79 */ |
84 private final ProtocolVersion protocolVersion; |
80 private final ProtocolVersion protocolVersion; |
85 private final SessionId sessionId; |
81 private final SessionId sessionId; |
86 private X509Certificate[] peerCerts; |
82 private X509Certificate[] peerCerts; |
87 private byte compressionMethod; |
|
88 private CipherSuite cipherSuite; |
83 private CipherSuite cipherSuite; |
89 private SecretKey masterSecret; |
84 private SecretKey masterSecret; |
90 final boolean useExtendedMasterSecret; |
85 final boolean useExtendedMasterSecret; |
91 |
86 |
92 /* |
87 /* |
96 private final long creationTime; |
91 private final long creationTime; |
97 private long lastUsedTime = 0; |
92 private long lastUsedTime = 0; |
98 private final String host; |
93 private final String host; |
99 private final int port; |
94 private final int port; |
100 private SSLSessionContextImpl context; |
95 private SSLSessionContextImpl context; |
101 private int sessionCount; |
|
102 private boolean invalidated; |
96 private boolean invalidated; |
103 private X509Certificate[] localCerts; |
97 private X509Certificate[] localCerts; |
104 private PrivateKey localPrivateKey; |
98 private PrivateKey localPrivateKey; |
105 private final String[] localSupportedSignAlgs; |
99 private final String[] localSupportedSignAlgs; |
106 private String[] peerSupportedSignAlgs; // for certificate |
100 private String[] peerSupportedSignAlgs; // for certificate |
110 private SecretKey preSharedKey; |
104 private SecretKey preSharedKey; |
111 private byte[] pskIdentity; |
105 private byte[] pskIdentity; |
112 private final long ticketCreationTime = System.currentTimeMillis(); |
106 private final long ticketCreationTime = System.currentTimeMillis(); |
113 private int ticketAgeAdd; |
107 private int ticketAgeAdd; |
114 |
108 |
115 private int negotiatedMaxFragLen; |
109 private int negotiatedMaxFragLen = -1; |
116 private int maximumPacketSize; |
110 private int maximumPacketSize; |
117 |
111 |
118 // Principals for non-certificate based cipher suites |
112 private final Queue<SSLSessionImpl> childSessions = |
119 private Principal peerPrincipal; |
113 new ConcurrentLinkedQueue<>(); |
120 private Principal localPrincipal; |
|
121 |
|
122 private Queue<SSLSessionImpl> childSessions = new ConcurrentLinkedQueue<SSLSessionImpl>(); |
|
123 |
114 |
124 /* |
115 /* |
125 * Is the session currently re-established with a session-resumption |
116 * Is the session currently re-established with a session-resumption |
126 * abbreviated initial handshake? |
117 * abbreviated initial handshake? |
127 * |
118 * |
128 * Note that currently we only set this variable in client side. |
119 * Note that currently we only set this variable in client side. |
129 */ |
120 */ |
130 private boolean isSessionResumption = false; |
121 private boolean isSessionResumption = false; |
131 |
|
132 /* |
|
133 * We count session creations, eventually for statistical data but |
|
134 * also since counters make shorter debugging IDs than the big ones |
|
135 * we use in the protocol for uniqueness-over-time. |
|
136 */ |
|
137 private static volatile int counter; |
|
138 |
122 |
139 /* |
123 /* |
140 * Use of session caches is globally enabled/disabled. |
124 * Use of session caches is globally enabled/disabled. |
141 */ |
125 */ |
142 private static boolean defaultRejoinable = true; |
126 private static boolean defaultRejoinable = true; |
188 * Record a new session, using a given cipher spec, session ID, |
172 * Record a new session, using a given cipher spec, session ID, |
189 * and creation time |
173 * and creation time |
190 */ |
174 */ |
191 SSLSessionImpl(HandshakeContext hc, |
175 SSLSessionImpl(HandshakeContext hc, |
192 CipherSuite cipherSuite, SessionId id, long creationTime) { |
176 CipherSuite cipherSuite, SessionId id, long creationTime) { |
193 this.creationTime = creationTime; |
|
194 this.protocolVersion = hc.negotiatedProtocol; |
177 this.protocolVersion = hc.negotiatedProtocol; |
|
178 this.cipherSuite = cipherSuite; |
195 this.sessionId = id; |
179 this.sessionId = id; |
196 peerCerts = null; |
|
197 compressionMethod = compression_null; |
|
198 this.cipherSuite = cipherSuite; |
|
199 masterSecret = null; |
|
200 this.host = hc.conContext.transport.getPeerHost(); |
180 this.host = hc.conContext.transport.getPeerHost(); |
201 this.port = hc.conContext.transport.getPeerPort(); |
181 this.port = hc.conContext.transport.getPeerPort(); |
202 sessionCount = ++counter; |
|
203 this.localSupportedSignAlgs = |
182 this.localSupportedSignAlgs = |
204 SignatureScheme.getAlgorithmNames(hc.localSupportedSignAlgs); |
183 SignatureScheme.getAlgorithmNames(hc.localSupportedSignAlgs); |
205 negotiatedMaxFragLen = -1; |
184 this.serverNameIndication = hc.negotiatedServerName; |
206 statusResponses = null; |
|
207 this.requestedServerNames = Collections.<SNIServerName>unmodifiableList( |
185 this.requestedServerNames = Collections.<SNIServerName>unmodifiableList( |
208 hc.getRequestedServerNames()); |
186 hc.getRequestedServerNames()); |
209 this.serverNameIndication = hc.negotiatedServerName; |
|
210 if (hc.sslConfig.isClientMode) { |
187 if (hc.sslConfig.isClientMode) { |
211 this.useExtendedMasterSecret = |
188 this.useExtendedMasterSecret = |
212 (hc.handshakeExtensions.get( |
189 (hc.handshakeExtensions.get( |
213 SSLExtension.CH_EXTENDED_MASTER_SECRET) != null) && |
190 SSLExtension.CH_EXTENDED_MASTER_SECRET) != null) && |
214 (hc.handshakeExtensions.get( |
191 (hc.handshakeExtensions.get( |
217 this.useExtendedMasterSecret = |
194 this.useExtendedMasterSecret = |
218 (hc.handshakeExtensions.get( |
195 (hc.handshakeExtensions.get( |
219 SSLExtension.CH_EXTENDED_MASTER_SECRET) != null) && |
196 SSLExtension.CH_EXTENDED_MASTER_SECRET) != null) && |
220 (!hc.negotiatedProtocol.useTLS13PlusSpec()); |
197 (!hc.negotiatedProtocol.useTLS13PlusSpec()); |
221 } |
198 } |
|
199 this.creationTime = creationTime; |
222 |
200 |
223 if (SSLLogger.isOn && SSLLogger.isOn("session")) { |
201 if (SSLLogger.isOn && SSLLogger.isOn("session")) { |
224 SSLLogger.finest("Session initialized: " + this); |
202 SSLLogger.finest("Session initialized: " + this); |
225 } |
203 } |
226 } |
204 } |
227 |
205 |
228 void setMasterSecret(SecretKey secret) { |
206 void setMasterSecret(SecretKey secret) { |
229 if (masterSecret == null) { |
207 masterSecret = secret; |
230 masterSecret = secret; |
|
231 } else { |
|
232 throw new RuntimeException("setMasterSecret() error"); |
|
233 } |
|
234 } |
208 } |
235 |
209 |
236 void setResumptionMasterSecret(SecretKey secret) { |
210 void setResumptionMasterSecret(SecretKey secret) { |
237 if (resumptionMasterSecret == null) { |
211 resumptionMasterSecret = secret; |
238 resumptionMasterSecret = secret; |
|
239 } else { |
|
240 throw new RuntimeException("setResumptionMasterSecret() error"); |
|
241 } |
|
242 } |
212 } |
243 |
213 |
244 void setPreSharedKey(SecretKey key) { |
214 void setPreSharedKey(SecretKey key) { |
245 if (preSharedKey == null) { |
215 preSharedKey = key; |
246 preSharedKey = key; |
|
247 } else { |
|
248 throw new RuntimeException("setPreSharedKey() error"); |
|
249 } |
|
250 } |
216 } |
251 |
217 |
252 void addChild(SSLSessionImpl session) { |
218 void addChild(SSLSessionImpl session) { |
253 childSessions.add(session); |
219 childSessions.add(session); |
254 } |
220 } |
256 void setTicketAgeAdd(int ticketAgeAdd) { |
222 void setTicketAgeAdd(int ticketAgeAdd) { |
257 this.ticketAgeAdd = ticketAgeAdd; |
223 this.ticketAgeAdd = ticketAgeAdd; |
258 } |
224 } |
259 |
225 |
260 void setPskIdentity(byte[] pskIdentity) { |
226 void setPskIdentity(byte[] pskIdentity) { |
261 if (this.pskIdentity == null) { |
227 this.pskIdentity = pskIdentity; |
262 this.pskIdentity = pskIdentity; |
|
263 } else { |
|
264 throw new RuntimeException("setPskIdentity() error"); |
|
265 } |
|
266 } |
228 } |
267 |
229 |
268 BigInteger incrTicketNonceCounter() { |
230 BigInteger incrTicketNonceCounter() { |
269 BigInteger result = ticketNonceCounter; |
231 BigInteger result = ticketNonceCounter; |
270 ticketNonceCounter = ticketNonceCounter.add(BigInteger.valueOf(1)); |
232 ticketNonceCounter = ticketNonceCounter.add(BigInteger.valueOf(1)); |
371 statusResponses = Collections.emptyList(); |
333 statusResponses = Collections.emptyList(); |
372 } |
334 } |
373 } |
335 } |
374 |
336 |
375 /** |
337 /** |
376 * Set the peer principal. |
|
377 */ |
|
378 void setPeerPrincipal(Principal principal) { |
|
379 if (peerPrincipal == null) { |
|
380 peerPrincipal = principal; |
|
381 } |
|
382 } |
|
383 |
|
384 /** |
|
385 * Set the local principal. |
|
386 */ |
|
387 void setLocalPrincipal(Principal principal) { |
|
388 localPrincipal = principal; |
|
389 } |
|
390 |
|
391 /** |
|
392 * Returns true iff this session may be resumed ... sessions are |
338 * Returns true iff this session may be resumed ... sessions are |
393 * usually resumable. Security policies may suggest otherwise, |
339 * usually resumable. Security policies may suggest otherwise, |
394 * for example sessions that haven't been used for a while (say, |
340 * for example sessions that haven't been used for a while (say, |
395 * a working day) won't be resumable, and sessions might have a |
341 * a working day) won't be resumable, and sessions might have a |
396 * maximum lifetime in any case. |
342 * maximum lifetime in any case. |
518 public String getProtocol() { |
464 public String getProtocol() { |
519 return getProtocolVersion().name; |
465 return getProtocolVersion().name; |
520 } |
466 } |
521 |
467 |
522 /** |
468 /** |
523 * Returns the compression technique used in this session |
|
524 */ |
|
525 byte getCompression() { |
|
526 return compressionMethod; |
|
527 } |
|
528 |
|
529 /** |
|
530 * Returns the hashcode for this session |
469 * Returns the hashcode for this session |
531 */ |
470 */ |
532 @Override |
471 @Override |
533 public int hashCode() { |
472 public int hashCode() { |
534 return sessionId.hashCode(); |
473 return sessionId.hashCode(); |
820 /* |
759 /* |
821 * Table of application-specific session data indexed by an application |
760 * Table of application-specific session data indexed by an application |
822 * key and the calling security context. This is important since |
761 * key and the calling security context. This is important since |
823 * sessions can be shared across different protection domains. |
762 * sessions can be shared across different protection domains. |
824 */ |
763 */ |
825 private Hashtable<SecureKey, Object> table = new Hashtable<>(); |
764 private final ConcurrentHashMap<SecureKey, Object> boundValues = |
|
765 new ConcurrentHashMap<>(); |
826 |
766 |
827 /** |
767 /** |
828 * Assigns a session value. Session change events are given if |
768 * Assigns a session value. Session change events are given if |
829 * appropriate, to any original value as well as the new value. |
769 * appropriate, to any original value as well as the new value. |
830 */ |
770 */ |
833 if ((key == null) || (value == null)) { |
773 if ((key == null) || (value == null)) { |
834 throw new IllegalArgumentException("arguments can not be null"); |
774 throw new IllegalArgumentException("arguments can not be null"); |
835 } |
775 } |
836 |
776 |
837 SecureKey secureKey = new SecureKey(key); |
777 SecureKey secureKey = new SecureKey(key); |
838 Object oldValue = table.put(secureKey, value); |
778 Object oldValue = boundValues.put(secureKey, value); |
839 |
779 |
840 if (oldValue instanceof SSLSessionBindingListener) { |
780 if (oldValue instanceof SSLSessionBindingListener) { |
841 SSLSessionBindingEvent e; |
781 SSLSessionBindingEvent e; |
842 |
782 |
843 e = new SSLSessionBindingEvent(this, key); |
783 e = new SSLSessionBindingEvent(this, key); |
874 if (key == null) { |
814 if (key == null) { |
875 throw new IllegalArgumentException("argument can not be null"); |
815 throw new IllegalArgumentException("argument can not be null"); |
876 } |
816 } |
877 |
817 |
878 SecureKey secureKey = new SecureKey(key); |
818 SecureKey secureKey = new SecureKey(key); |
879 Object value = table.remove(secureKey); |
819 Object value = boundValues.remove(secureKey); |
880 |
820 |
881 if (value instanceof SSLSessionBindingListener) { |
821 if (value instanceof SSLSessionBindingListener) { |
882 SSLSessionBindingEvent e; |
822 SSLSessionBindingEvent e; |
883 |
823 |
884 e = new SSLSessionBindingEvent(this, key); |
824 e = new SSLSessionBindingEvent(this, key); |
890 /** |
830 /** |
891 * Lists the names of the session values. |
831 * Lists the names of the session values. |
892 */ |
832 */ |
893 @Override |
833 @Override |
894 public String[] getValueNames() { |
834 public String[] getValueNames() { |
895 Enumeration<SecureKey> e; |
835 ArrayList<Object> v = new ArrayList<>(); |
896 Vector<Object> v = new Vector<>(); |
|
897 SecureKey key; |
|
898 Object securityCtx = SecureKey.getCurrentSecurityContext(); |
836 Object securityCtx = SecureKey.getCurrentSecurityContext(); |
899 |
837 for (Enumeration<SecureKey> e = boundValues.keys(); |
900 for (e = table.keys(); e.hasMoreElements(); ) { |
838 e.hasMoreElements(); ) { |
901 key = e.nextElement(); |
839 SecureKey key = e.nextElement(); |
902 |
|
903 if (securityCtx.equals(key.getSecurityContext())) { |
840 if (securityCtx.equals(key.getSecurityContext())) { |
904 v.addElement(key.getAppKey()); |
841 v.add(key.getAppKey()); |
905 } |
842 } |
906 } |
843 } |
907 String[] names = new String[v.size()]; |
844 |
908 v.copyInto(names); |
845 return v.toArray(new String[0]); |
909 |
|
910 return names; |
|
911 } |
846 } |
912 |
847 |
913 /** |
848 /** |
914 * Use large packet sizes now or follow RFC 2246 packet sizes (2^14) |
849 * Use large packet sizes now or follow RFC 2246 packet sizes (2^14) |
915 * until changed. |
850 * until changed. |
1063 * Obtains a <code>List</code> containing all {@link SNIServerName}s |
998 * Obtains a <code>List</code> containing all {@link SNIServerName}s |
1064 * of the requested Server Name Indication (SNI) extension. |
999 * of the requested Server Name Indication (SNI) extension. |
1065 */ |
1000 */ |
1066 @Override |
1001 @Override |
1067 public List<SNIServerName> getRequestedServerNames() { |
1002 public List<SNIServerName> getRequestedServerNames() { |
1068 if (requestedServerNames == null) { |
|
1069 return Collections.<SNIServerName>emptyList(); |
|
1070 } |
|
1071 return requestedServerNames; |
1003 return requestedServerNames; |
1072 } |
1004 } |
1073 |
1005 |
1074 /** Returns a string representation of this SSL session */ |
1006 /** Returns a string representation of this SSL session */ |
1075 @Override |
1007 @Override |
1076 public String toString() { |
1008 public String toString() { |
1077 return "[Session-" + sessionCount |
1009 return "Session(" + creationTime + "|" + getCipherSuite() + ")"; |
1078 + ", " + getCipherSuite() |
|
1079 + "]"; |
|
1080 } |
1010 } |
1081 } |
1011 } |
1082 |
|
1083 |
1012 |
1084 /** |
1013 /** |
1085 * This "struct" class serves as a Hash Key that combines an |
1014 * This "struct" class serves as a Hash Key that combines an |
1086 * application-specific key and a security context. |
1015 * application-specific key and a security context. |
1087 */ |
1016 */ |
1088 class SecureKey { |
1017 class SecureKey { |
1089 private static Object nullObject = new Object(); |
1018 private static final Object nullObject = new Object(); |
1090 private Object appKey; |
1019 private final Object appKey; |
1091 private Object securityCtx; |
1020 private final Object securityCtx; |
1092 |
1021 |
1093 static Object getCurrentSecurityContext() { |
1022 static Object getCurrentSecurityContext() { |
1094 SecurityManager sm = System.getSecurityManager(); |
1023 SecurityManager sm = System.getSecurityManager(); |
1095 Object context = null; |
1024 Object context = null; |
1096 |
1025 |