~ubuntu-branches/debian/sid/botan/sid

« back to all changes in this revision

Viewing changes to src/lib/tls/sessions_sql/tls_session_manager_sql.cpp

  • Committer: Package Import Robot
  • Author(s): Laszlo Boszormenyi (GCS)
  • Date: 2018-03-01 22:23:25 UTC
  • mfrom: (1.2.2)
  • Revision ID: package-import@ubuntu.com-20180301222325-7p7vc45gu3hta34d
Tags: 2.4.0-2
* Don't remove .doctrees from the manual if it doesn't exist.
* Don't specify parallel to debhelper.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
* SQL TLS Session Manager
 
3
* (C) 2012,2014 Jack Lloyd
 
4
*
 
5
* Botan is released under the Simplified BSD License (see license.txt)
 
6
*/
 
7
 
 
8
#include <botan/tls_session_manager_sql.h>
 
9
#include <botan/database.h>
 
10
#include <botan/pbkdf.h>
 
11
#include <botan/hex.h>
 
12
#include <botan/rng.h>
 
13
#include <botan/loadstor.h>
 
14
#include <chrono>
 
15
 
 
16
namespace Botan {
 
17
 
 
18
namespace TLS {
 
19
 
 
20
Session_Manager_SQL::Session_Manager_SQL(std::shared_ptr<SQL_Database> db,
 
21
                                         const std::string& passphrase,
 
22
                                         RandomNumberGenerator& rng,
 
23
                                         size_t max_sessions,
 
24
                                         std::chrono::seconds session_lifetime) :
 
25
   m_db(db),
 
26
   m_rng(rng),
 
27
   m_max_sessions(max_sessions),
 
28
   m_session_lifetime(session_lifetime)
 
29
   {
 
30
   m_db->create_table(
 
31
      "create table if not exists tls_sessions "
 
32
      "("
 
33
      "session_id TEXT PRIMARY KEY, "
 
34
      "session_start INTEGER, "
 
35
      "hostname TEXT, "
 
36
      "hostport INTEGER, "
 
37
      "session BLOB"
 
38
      ")");
 
39
 
 
40
   m_db->create_table(
 
41
      "create table if not exists tls_sessions_metadata "
 
42
      "("
 
43
      "passphrase_salt BLOB, "
 
44
      "passphrase_iterations INTEGER, "
 
45
      "passphrase_check INTEGER "
 
46
      ")");
 
47
 
 
48
   const size_t salts = m_db->row_count("tls_sessions_metadata");
 
49
 
 
50
   std::unique_ptr<PBKDF> pbkdf(get_pbkdf("PBKDF2(SHA-512)"));
 
51
 
 
52
   if(salts == 1)
 
53
      {
 
54
      // existing db
 
55
      auto stmt = m_db->new_statement("select * from tls_sessions_metadata");
 
56
 
 
57
      if(stmt->step())
 
58
         {
 
59
         std::pair<const uint8_t*, size_t> salt = stmt->get_blob(0);
 
60
         const size_t iterations = stmt->get_size_t(1);
 
61
         const size_t check_val_db = stmt->get_size_t(2);
 
62
 
 
63
         secure_vector<uint8_t> x = pbkdf->pbkdf_iterations(32 + 2,
 
64
                                                         passphrase,
 
65
                                                         salt.first, salt.second,
 
66
                                                         iterations);
 
67
 
 
68
         const size_t check_val_created = make_uint16(x[0], x[1]);
 
69
         m_session_key.assign(x.begin() + 2, x.end());
 
70
 
 
71
         if(check_val_created != check_val_db)
 
72
            throw Exception("Session database password not valid");
 
73
         }
 
74
      }
 
75
   else
 
76
      {
 
77
      // maybe just zap the salts + sessions tables in this case?
 
78
      if(salts != 0)
 
79
         throw Exception("Seemingly corrupted database, multiple salts found");
 
80
 
 
81
      // new database case
 
82
 
 
83
      std::vector<uint8_t> salt = unlock(rng.random_vec(16));
 
84
      size_t iterations = 0;
 
85
 
 
86
      secure_vector<uint8_t> x = pbkdf->pbkdf_timed(32 + 2,
 
87
                                                 passphrase,
 
88
                                                 salt.data(), salt.size(),
 
89
                                                 std::chrono::milliseconds(100),
 
90
                                                 iterations);
 
91
 
 
92
      size_t check_val = make_uint16(x[0], x[1]);
 
93
      m_session_key.assign(x.begin() + 2, x.end());
 
94
 
 
95
      auto stmt = m_db->new_statement("insert into tls_sessions_metadata values(?1, ?2, ?3)");
 
96
 
 
97
      stmt->bind(1, salt);
 
98
      stmt->bind(2, iterations);
 
99
      stmt->bind(3, check_val);
 
100
 
 
101
      stmt->spin();
 
102
      }
 
103
   }
 
104
 
 
105
bool Session_Manager_SQL::load_from_session_id(const std::vector<uint8_t>& session_id,
 
106
                                               Session& session)
 
107
   {
 
108
   auto stmt = m_db->new_statement("select session from tls_sessions where session_id = ?1");
 
109
 
 
110
   stmt->bind(1, hex_encode(session_id));
 
111
 
 
112
   while(stmt->step())
 
113
      {
 
114
      std::pair<const uint8_t*, size_t> blob = stmt->get_blob(0);
 
115
 
 
116
      try
 
117
         {
 
118
         session = Session::decrypt(blob.first, blob.second, m_session_key);
 
119
         return true;
 
120
         }
 
121
      catch(...)
 
122
         {
 
123
         }
 
124
      }
 
125
 
 
126
   return false;
 
127
   }
 
128
 
 
129
bool Session_Manager_SQL::load_from_server_info(const Server_Information& server,
 
130
                                                Session& session)
 
131
   {
 
132
   auto stmt = m_db->new_statement("select session from tls_sessions"
 
133
                                   " where hostname = ?1 and hostport = ?2"
 
134
                                   " order by session_start desc");
 
135
 
 
136
   stmt->bind(1, server.hostname());
 
137
   stmt->bind(2, server.port());
 
138
 
 
139
   while(stmt->step())
 
140
      {
 
141
      std::pair<const uint8_t*, size_t> blob = stmt->get_blob(0);
 
142
 
 
143
      try
 
144
         {
 
145
         session = Session::decrypt(blob.first, blob.second, m_session_key);
 
146
         return true;
 
147
         }
 
148
      catch(...)
 
149
         {
 
150
         }
 
151
      }
 
152
 
 
153
   return false;
 
154
   }
 
155
 
 
156
void Session_Manager_SQL::remove_entry(const std::vector<uint8_t>& session_id)
 
157
   {
 
158
   auto stmt = m_db->new_statement("delete from tls_sessions where session_id = ?1");
 
159
 
 
160
   stmt->bind(1, hex_encode(session_id));
 
161
 
 
162
   stmt->spin();
 
163
   }
 
164
 
 
165
size_t Session_Manager_SQL::remove_all()
 
166
   {
 
167
   auto stmt = m_db->new_statement("delete from tls_sessions");
 
168
   return stmt->spin();
 
169
   }
 
170
 
 
171
void Session_Manager_SQL::save(const Session& session)
 
172
   {
 
173
   if(session.server_info().hostname().empty())
 
174
      return;
 
175
 
 
176
   auto stmt = m_db->new_statement("insert or replace into tls_sessions"
 
177
                                   " values(?1, ?2, ?3, ?4, ?5)");
 
178
 
 
179
   stmt->bind(1, hex_encode(session.session_id()));
 
180
   stmt->bind(2, session.start_time());
 
181
   stmt->bind(3, session.server_info().hostname());
 
182
   stmt->bind(4, session.server_info().port());
 
183
   stmt->bind(5, session.encrypt(m_session_key, m_rng));
 
184
 
 
185
   stmt->spin();
 
186
 
 
187
   prune_session_cache();
 
188
   }
 
189
 
 
190
void Session_Manager_SQL::prune_session_cache()
 
191
   {
 
192
   // First expire old sessions
 
193
   auto remove_expired = m_db->new_statement("delete from tls_sessions where session_start <= ?1");
 
194
   remove_expired->bind(1, std::chrono::system_clock::now() - m_session_lifetime);
 
195
   remove_expired->spin();
 
196
 
 
197
   const size_t sessions = m_db->row_count("tls_sessions");
 
198
 
 
199
   // Then if needed expire some more sessions at random
 
200
   if(sessions > m_max_sessions)
 
201
      {
 
202
      auto remove_some = m_db->new_statement("delete from tls_sessions where session_id in "
 
203
                                             "(select session_id from tls_sessions limit ?1)");
 
204
 
 
205
      remove_some->bind(1, sessions - m_max_sessions);
 
206
      remove_some->spin();
 
207
      }
 
208
   }
 
209
 
 
210
}
 
211
 
 
212
}