1 module hunt.net.secure.conscrypt.ActiveSession; 2 3 // dfmt off 4 version(WITH_HUNT_SECURITY): 5 // dfmt on 6 7 import hunt.net.secure.conscrypt.AbstractSessionContext; 8 import hunt.net.secure.conscrypt.ConscryptSession; 9 import hunt.net.secure.conscrypt.NativeSsl; 10 import hunt.net.secure.conscrypt.NativeConstants; 11 import hunt.net.secure.conscrypt.SSLNullSession; 12 import hunt.net.secure.conscrypt.SSLUtils; 13 14 import hunt.net.ssl.SSLSessionContext; 15 16 // import hunt.security.cert.Certificate; 17 // import hunt.security.cert.X509Certificate; 18 // import hunt.security.Principal; 19 20 import hunt.net.ssl.SSLSession; 21 import hunt.net.Exceptions; 22 23 import hunt.collection; 24 25 import hunt.util.DateTime; 26 import hunt.Exceptions; 27 28 import hunt.logging; 29 30 import std.datetime; 31 32 /** 33 * A session that is dedicated a single connection and operates directly on the underlying 34 * {@code SSL}. 35 */ 36 final class ActiveSession : ConscryptSession { 37 private NativeSsl ssl; 38 private AbstractSessionContext sessionContext; 39 private byte[] id; 40 private long creationTime; 41 private string protocol; 42 private string peerHost; 43 private int peerPort = -1; 44 private long lastAccessedTime = 0; 45 // private X509Certificate[] peerCertificateChain; 46 // private X509Certificate[] localCertificates; 47 // private X509Certificate[] peerCertificates; 48 private byte[] peerCertificateOcspData; 49 private byte[] peerTlsSctData; 50 51 this(NativeSsl ssl, AbstractSessionContext sessionContext) { 52 this.ssl = ssl; 53 this.sessionContext = sessionContext; 54 } 55 56 override 57 byte[] getId() { 58 if (id is null) { 59 synchronized (ssl) { 60 id = ssl.getSessionId(); 61 } 62 } 63 return id !is null ? id.dup : []; 64 } 65 66 /** 67 * Indicates that this session's ID may have changed and should be re-cached. 68 */ 69 void resetId() { 70 id = null; 71 } 72 73 override 74 SSLSessionContext getSessionContext() { 75 return isValid() ? sessionContext : null; 76 } 77 78 override 79 long getCreationTime() { 80 if (creationTime == 0) { 81 synchronized (ssl) { 82 creationTime = ssl.getTime(); 83 } 84 } 85 return creationTime; 86 } 87 88 /** 89 * Returns the last time this SSL session was accessed. Accessing 90 * here is to mean that a new connection with the same SSL context data was 91 * established. 92 * 93 * @return the session's last access time in milliseconds since the epoch 94 */ 95 // TODO(nathanmittler): Does lastAccessedTime need to account for session reuse? 96 override 97 long getLastAccessedTime() { 98 return lastAccessedTime == 0 ? getCreationTime() : lastAccessedTime; 99 } 100 101 void setLastAccessedTime(long accessTimeMillis) { 102 lastAccessedTime = accessTimeMillis; 103 } 104 105 /** 106 * Returns the OCSP stapled response. Returns a copy of the internal arrays. 107 * 108 * The method signature matches 109 * <a 110 * href="http://download.java.net/java/jdk9/docs/api/javax/net/ssl/ExtendedSSLSession.html#getStatusResponses--">Java 111 * 9</a>. 112 * 113 * @see <a href="https://tools.ietf.org/html/rfc6066">RFC 6066</a> 114 * @see <a href="https://tools.ietf.org/html/rfc6961">RFC 6961</a> 115 */ 116 override 117 List!(byte[]) getStatusResponses() { 118 if (peerCertificateOcspData is null) { 119 return new EmptyList!(byte[])(); 120 } 121 122 return Collections.singletonList(peerCertificateOcspData.dup); 123 } 124 125 /** 126 * Returns the signed certificate timestamp (SCT) received from the peer. Returns a 127 * copy of the internal array. 128 * 129 * @see <a href="https://tools.ietf.org/html/rfc6962">RFC 6962</a> 130 */ 131 override 132 byte[] getPeerSignedCertificateTimestamp() { 133 if (peerTlsSctData is null) { 134 return null; 135 } 136 return peerTlsSctData.dup; 137 } 138 139 override 140 string getRequestedServerName() { 141 synchronized (ssl) { 142 return ssl.getRequestedServerName(); 143 } 144 } 145 146 override 147 void invalidate() { 148 synchronized (ssl) { 149 ssl.setTimeout(0L); 150 } 151 } 152 153 override 154 bool isValid() { 155 synchronized (ssl) { 156 long creationTimeMillis = ssl.getTime(); 157 long timeoutMillis = ssl.getTimeout(); 158 long now = convert!(TimeUnit.HectoNanosecond, TimeUnit.Millisecond)(Clock.currStdTime); 159 return (now - timeoutMillis) < creationTimeMillis; 160 } 161 } 162 163 override 164 void putValue(string name, Object value) { 165 throw new UnsupportedOperationException( 166 "All calls to this method should be intercepted by ProvidedSessionDecorator."); 167 } 168 169 override 170 Object getValue(string name) { 171 throw new UnsupportedOperationException( 172 "All calls to this method should be intercepted by ProvidedSessionDecorator."); 173 } 174 175 override 176 void removeValue(string name) { 177 throw new UnsupportedOperationException( 178 "All calls to this method should be intercepted by ProvidedSessionDecorator."); 179 } 180 181 override 182 string[] getValueNames() { 183 throw new UnsupportedOperationException( 184 "All calls to this method should be intercepted by ProvidedSessionDecorator."); 185 } 186 187 // override 188 // Certificate[] getPeerCertificates() { 189 // checkPeerCertificatesPresent(); 190 // return cast(Certificate[])peerCertificates.dup; 191 // } 192 193 // override 194 // Certificate[] getLocalCertificates() { 195 // return localCertificates is null ? null : cast(Certificate[])localCertificates.dup; 196 // } 197 198 /** 199 * Returns the certificate(s) of the peer in this SSL session 200 * used in the handshaking phase of the connection. 201 * Please notice hat this method is superseded by 202 * <code>getPeerCertificates()</code>. 203 * @return an array of X509 certificates (the peer's one first and then 204 * eventually that of the certification authority) or null if no 205 * certificate were used during the SSL connection. 206 * @throws SSLPeerUnverifiedException if either a non-X.509 certificate 207 * was used (i.e. Kerberos certificates) or the peer could not 208 * be verified. 209 */ 210 // override 211 // X509Certificate[] getPeerCertificateChain() 212 // { 213 // checkPeerCertificatesPresent(); 214 // // TODO(nathanmittler): Should we clone? 215 // X509Certificate[] result = peerCertificateChain; 216 // if (result is null) { 217 // // single-check idiom 218 // peerCertificateChain = result = SSLUtils.toCertificateChain(peerCertificates); 219 // } 220 // return result; 221 // } 222 223 // override 224 // Principal getPeerPrincipal() { 225 // checkPeerCertificatesPresent(); 226 // return peerCertificates[0].getSubjectX500Principal(); 227 // } 228 229 // override 230 // Principal getLocalPrincipal() { 231 // if (localCertificates !is null && localCertificates.length > 0) { 232 // return localCertificates[0].getSubjectX500Principal(); 233 // } else { 234 // return null; 235 // } 236 // } 237 238 override 239 string getCipherSuite() { 240 // Always get the Cipher from the SSL directly since it may have changed during a 241 // renegotiation. 242 string cipher; 243 synchronized (ssl) { 244 cipher = ssl.getCipherSuite(); 245 } 246 return cipher is null ? SSLNullSession.INVALID_CIPHER : cipher; 247 } 248 249 override 250 string getProtocol() { 251 string protocol = this.protocol; 252 if (protocol is null) { 253 synchronized (ssl) { 254 protocol = ssl.getVersion(); 255 } 256 this.protocol = protocol; 257 } 258 return protocol; 259 } 260 261 override 262 string getPeerHost() { 263 return peerHost; 264 } 265 266 override 267 int getPeerPort() { 268 return peerPort; 269 } 270 271 override 272 int getPacketBufferSize() { 273 return NativeConstants.SSL3_RT_MAX_PACKET_SIZE; 274 } 275 276 override 277 int getApplicationBufferSize() { 278 return NativeConstants.SSL3_RT_MAX_PLAIN_LENGTH; 279 } 280 281 /** 282 * Configures the peer information once it has been received by the handshake. 283 */ 284 // void onPeerCertificatesReceived( 285 // string peerHost, int peerPort, X509Certificate[] peerCertificates) { 286 // configurePeer(peerHost, peerPort, peerCertificates); 287 // } 288 289 // private void configurePeer(string peerHost, int peerPort, X509Certificate[] peerCertificates) { 290 // this.peerHost = peerHost; 291 // this.peerPort = peerPort; 292 // this.peerCertificates = peerCertificates; 293 294 // version(Have_boringssl) { 295 // synchronized (ssl) { 296 // this.peerCertificateOcspData = ssl.getPeerCertificateOcspData(); 297 // this.peerTlsSctData = ssl.getPeerTlsSctData(); 298 // } 299 // } 300 // } 301 302 /** 303 * Updates the cached peer certificate after the handshake has completed 304 * (or entered False Start). 305 */ 306 void onPeerCertificateAvailable(string peerHost, int peerPort) { 307 version(HUNT_NET_DEBUG) { 308 implementationMissing(false); 309 version(HUNT_NET_DEBUG) infof("peerHost: %s, peerPort: %d", peerHost, peerPort); 310 } 311 // synchronized (ssl) { 312 // id = null; 313 // this.localCertificates = ssl.getLocalCertificates(); 314 // if (this.peerCertificates is null) { 315 // // When resuming a session, the cert_verify_callback (which calls 316 // // onPeerCertificatesReceived) isn't called by BoringSSL during the handshake 317 // // because it presumes the certs were verified in the previous connection on that 318 // // session, leaving us without the peer certificates. If that happens, fetch them 319 // // explicitly. 320 // configurePeer(peerHost, peerPort, ssl.getPeerCertificates()); 321 // } 322 // } 323 } 324 325 /** 326 * Throw SSLPeerUnverifiedException on null or empty peerCertificates array 327 */ 328 // private void checkPeerCertificatesPresent() { 329 // if (peerCertificates is null || peerCertificates.length == 0) { 330 // throw new SSLPeerUnverifiedException("No peer certificates"); 331 // } 332 // } 333 334 // private void notifyUnbound(Object value, string name) { 335 // if (value instanceof SSLSessionBindingListener) { 336 // ((SSLSessionBindingListener) value) 337 // .valueUnbound(new SSLSessionBindingEvent(this, name)); 338 // } 339 // } 340 }