1 /** 2 * TLS Session 3 * 4 * Copyright: 5 * (C) 2011-2012 Jack Lloyd 6 * (C) 2014-2015 Etienne Cimon 7 * 8 * License: 9 * Botan is released under the Simplified BSD License (see LICENSE.md) 10 */ 11 module botan.tls.session; 12 13 import botan.constants; 14 static if (BOTAN_HAS_TLS): 15 16 import botan.cert.x509.x509cert; 17 import botan.tls.version_; 18 import botan.tls.ciphersuite; 19 import botan.tls.magic; 20 import botan.tls.server_info; 21 import memutils.vector; 22 import botan.algo_base.symkey; 23 import botan.asn1.der_enc; 24 import botan.asn1.ber_dec; 25 import botan.asn1.asn1_str; 26 import botan.codec.pem; 27 import botan.rng.rng; 28 import botan.constructs.cryptobox_psk; 29 import botan.utils.types; 30 import core.stdc.time : time_t; 31 import std.datetime; 32 33 34 /** 35 * Class representing a TLS session state 36 */ 37 class TLSSession 38 { 39 public: 40 /** 41 * New session (sets session start time) 42 */ 43 this(Vector!ubyte session_identifier, 44 SecureVector!ubyte master_secret, 45 SecureVector!ubyte orig_hs_hash, 46 TLSProtocolVersion _version, 47 ushort ciphersuite, 48 ubyte compression_method, 49 ConnectionSide side, 50 size_t fragment_size, 51 bool extended_master_secret, 52 Vector!X509Certificate certs, 53 Vector!ubyte ticket, 54 in TLSServerInformation server_info, 55 in string srp_identifier) 56 { 57 m_start_time = Clock.currTime(UTC()); 58 m_identifier = session_identifier.move(); 59 m_session_ticket = ticket.move(); 60 m_master_secret = master_secret.move(); 61 m_orig_hs_hash = orig_hs_hash.move(); 62 m_version = _version; 63 m_ciphersuite = ciphersuite; 64 m_compression_method = compression_method; 65 m_connection_side = side; 66 m_fragment_size = fragment_size; 67 m_peer_certs = certs.move(); 68 m_server_info = server_info; 69 m_srp_identifier = srp_identifier; 70 m_extended_master_secret = extended_master_secret; 71 } 72 73 /** 74 * Load a session from DER representation (created by DER_encode) 75 */ 76 this(const(ubyte)* ber, size_t ber_len) 77 { 78 ubyte side_code = 0; 79 80 ASN1String server_hostname = ASN1String(""); 81 ASN1String server_service = ASN1String(""); 82 size_t server_port; 83 84 ASN1String srp_identifier_str = ASN1String(""); 85 86 ubyte major_version = 0, minor_version = 0; 87 88 Vector!ubyte peer_cert_bits; 89 90 size_t start_time = 0; 91 92 BERDecoder(ber, ber_len) 93 .startCons(ASN1Tag.SEQUENCE) 94 .decodeAndCheck(cast(size_t)(TLS_SESSION_PARAM_STRUCT_VERSION), 95 "Unknown version in session structure") 96 .decodeIntegerType(start_time) 97 .decodeIntegerType(major_version) 98 .decodeIntegerType(minor_version) 99 .decode(m_identifier, ASN1Tag.OCTET_STRING) 100 .decode(m_session_ticket, ASN1Tag.OCTET_STRING) 101 .decodeIntegerType(m_ciphersuite) 102 .decodeIntegerType(m_compression_method) 103 .decodeIntegerType(side_code) 104 .decodeIntegerType(m_fragment_size) 105 .decode(m_extended_master_secret) 106 .decode(m_master_secret, ASN1Tag.OCTET_STRING) 107 .decode(m_orig_hs_hash, ASN1Tag.OCTET_STRING) 108 .decode(peer_cert_bits, ASN1Tag.OCTET_STRING) 109 .decode(server_hostname) 110 .decode(server_service) 111 .decode(server_port) 112 .decode(srp_identifier_str) 113 .endCons() 114 .verifyEnd(); 115 116 m_version = TLSProtocolVersion(major_version, minor_version); 117 m_start_time = SysTime(unixTimeToStdTime(cast(time_t)start_time)); 118 m_connection_side = cast(ConnectionSide)(side_code); 119 120 m_server_info = TLSServerInformation(server_hostname.value(), 121 server_service.value(), 122 cast(ushort) server_port); 123 124 m_srp_identifier = srp_identifier_str.value(); 125 126 if (!peer_cert_bits.empty) 127 { 128 auto certs = DataSourceMemory(peer_cert_bits.ptr, peer_cert_bits.length); 129 while (!certs.endOfData()) 130 m_peer_certs.pushBack(X509Certificate(cast(DataSource)certs)); 131 } 132 } 133 134 /** 135 * Load a session from PEM representation (created by PEM_encode) 136 */ 137 this(in string pem) 138 { 139 SecureVector!ubyte der = PEM.decodeCheckLabel(pem, "SSL SESSION"); 140 141 this(der.ptr, der.length); 142 } 143 144 /** 145 * Encode this session data for storage 146 * Notes: if the master secret is compromised so is the session traffic 147 */ 148 SecureVector!ubyte DER_encode() const 149 { 150 Vector!ubyte peer_cert_bits; 151 for (size_t i = 0; i != m_peer_certs.length; ++i) 152 peer_cert_bits ~= m_peer_certs[i].BER_encode(); 153 154 return DEREncoder() 155 .startCons(ASN1Tag.SEQUENCE) 156 .encode(cast(size_t)(TLS_SESSION_PARAM_STRUCT_VERSION)) 157 .encode(cast(size_t)(m_start_time.toUnixTime())) 158 .encode(cast(size_t)(m_version.majorVersion())) 159 .encode(cast(size_t)(m_version.minorVersion())) 160 .encode(m_identifier, ASN1Tag.OCTET_STRING) 161 .encode(m_session_ticket, ASN1Tag.OCTET_STRING) 162 .encode(cast(size_t)(m_ciphersuite)) 163 .encode(cast(size_t)(m_compression_method)) 164 .encode(cast(size_t)(m_connection_side)) 165 .encode(cast(size_t)(m_fragment_size)) 166 .encode(m_extended_master_secret) 167 .encode(m_master_secret, ASN1Tag.OCTET_STRING) 168 .encode(m_orig_hs_hash, ASN1Tag.OCTET_STRING) 169 .encode(peer_cert_bits, ASN1Tag.OCTET_STRING) 170 .encode(ASN1String(m_server_info.hostname(), ASN1Tag.UTF8_STRING)) 171 .encode(ASN1String(m_server_info.service(), ASN1Tag.UTF8_STRING)) 172 .encode(cast(size_t)(m_server_info.port())) 173 .encode(ASN1String(m_srp_identifier, ASN1Tag.UTF8_STRING)) 174 .endCons() 175 .getContents(); 176 } 177 178 /** 179 * Encrypt a session (useful for serialization or session tickets) 180 */ 181 Vector!ubyte encrypt(in SymmetricKey master_key, RandomNumberGenerator rng) const 182 { 183 const auto der = this.DER_encode(); 184 185 return CryptoBox.encrypt(der.ptr, der.length, master_key, rng); 186 } 187 188 /** 189 * Decrypt a session created by encrypt 190 * Params: 191 * buf = the ciphertext returned by encrypt 192 * buf_len = the size of ctext in bytes 193 * master_key = the same key used by the encrypting side 194 */ 195 static TLSSession decrypt(const(ubyte)* buf, size_t buf_len, in SymmetricKey master_key) 196 { 197 try 198 { 199 const auto ber = CryptoBox.decrypt(buf, buf_len, master_key); 200 201 return new TLSSession(ber.ptr, ber.length); 202 } 203 catch(Exception e) 204 { 205 throw new DecodingError("Failed to decrypt encrypted session -" ~ e.msg); 206 } 207 } 208 209 /** 210 * Decrypt a session created by encrypt 211 * Params: 212 * ctext = the ciphertext returned by encrypt 213 * key = the same key used by the encrypting side 214 */ 215 static TLSSession decrypt(const ref Vector!ubyte ctext, in SymmetricKey key) 216 { 217 return TLSSession.decrypt(ctext.ptr, ctext.length, key); 218 } 219 220 /** 221 * Encode this session data for storage 222 * Notes: if the master secret is compromised so is the session traffic 223 */ 224 string PEM_encode() const 225 { 226 return PEM.encode(this.DER_encode(), "SSL SESSION"); 227 } 228 229 /** 230 * Get the version of the saved session 231 */ 232 TLSProtocolVersion Version() const { return m_version; } 233 234 /** 235 * Get the ciphersuite code of the saved session 236 */ 237 ushort ciphersuiteCode() const { return m_ciphersuite; } 238 239 /** 240 * Get the ciphersuite info of the saved session 241 */ 242 const(TLSCiphersuite) ciphersuite() const { return TLSCiphersuite.byId(m_ciphersuite); } 243 244 /** 245 * Get the compression method used in the saved session 246 */ 247 ubyte compressionMethod() const { return m_compression_method; } 248 249 /** 250 * Get which side of the connection the resumed session we are/were 251 * acting as. 252 */ 253 const(ConnectionSide) side() const { return m_connection_side; } 254 255 /** 256 * Get the SRP identity (if sent by the client in the initial handshake) 257 */ 258 string srpIdentifier() const { return m_srp_identifier; } 259 260 /** 261 * Get the saved master secret 262 */ 263 ref const(SecureVector!ubyte) masterSecret() const { return m_master_secret; } 264 265 /** 266 * Get the session identifier 267 */ 268 ref const(Vector!ubyte) sessionId() const { return m_identifier; } 269 270 /** 271 * Get the negotiated maximum fragment size (or 0 if default) 272 */ 273 size_t fragmentSize() const { return m_fragment_size; } 274 275 /** 276 * Returns whether the session was negotiated with an extended master secret 277 */ 278 bool supportsExtendedMasterSecret() const { return m_extended_master_secret; } 279 280 /** 281 * Get the original handshake hash (For ChannelID Resumption) 282 */ 283 ref const(SecureVector!ubyte) originalHandshakeHash() const { return m_orig_hs_hash; } 284 285 /** 286 * Return the certificate chain of the peer (possibly empty) 287 */ 288 ref const(Vector!X509Certificate) peerCerts() const { return m_peer_certs; } 289 290 /** 291 * Get the wall clock time this session began 292 */ 293 SysTime startTime() const { return m_start_time; } 294 295 /** 296 * Return how long this session has existed (in seconds) 297 */ 298 const(Duration) sessionAge() const 299 { 300 return Clock.currTime(UTC()) - m_start_time; 301 } 302 303 /** 304 * Return the session ticket the server gave us 305 */ 306 ref const(Vector!ubyte) sessionTicket() const { return m_session_ticket; } 307 308 TLSServerInformation serverInfo() const { return m_server_info; } 309 310 /* @property TLSSession move() { 311 return TLSSession(m_identifier.move(), m_master_secret.move(), m_version, m_ciphersuite, m_compression_method, m_connection_side, 312 m_fragment_size, m_peer_certs.move(), m_session_ticket.move(), m_server_info, m_srp_identifier); 313 }*/ 314 315 private: 316 317 enum { TLS_SESSION_PARAM_STRUCT_VERSION = 20160808 } 318 319 SysTime m_start_time; 320 321 Vector!ubyte m_identifier; 322 Vector!ubyte m_session_ticket; // only used by client side 323 SecureVector!ubyte m_master_secret; 324 325 TLSProtocolVersion m_version; 326 ushort m_ciphersuite; 327 ubyte m_compression_method; 328 ConnectionSide m_connection_side; 329 330 size_t m_fragment_size; 331 332 Vector!X509Certificate m_peer_certs; 333 TLSServerInformation m_server_info; // optional 334 string m_srp_identifier; // optional 335 bool m_extended_master_secret; 336 SecureVector!ubyte m_orig_hs_hash; 337 }