~adedov/libiqxmlrpc/old

« back to all changes in this revision

Viewing changes to libiqxmlrpc/ssl_lib.cc

  • Committer: Anton Dedov
  • Date: 2013-11-15 07:59:27 UTC
  • Revision ID: adedov@gmail.com-20131115075927-pwtgqklurt41wvfi
Security: Initial implementation for SSL certificate checks:
* ssl::Ctx::verify_server, verify_client API
* ConnectionVerifier class for custom certificate checks

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
#include <pthread.h>
16
16
#endif
17
17
 
 
18
#include <sstream>
18
19
#include "ssl_lib.h"
19
20
#include "net_except.h"
20
21
 
75
76
  delete[] locks;
76
77
}
77
78
 
 
79
Ctx* ctx = 0;
 
80
boost::once_flag ssl_init;
 
81
int iqxmlrpc_ssl_data_idx = 0;
 
82
 
78
83
void
79
84
init_library()
80
85
{
88
93
  if (!CRYPTO_get_id_callback())
89
94
    CRYPTO_set_id_callback(&openssl_id_function);
90
95
#endif
 
96
 
 
97
  iqxmlrpc_ssl_data_idx = SSL_get_ex_new_index(0, (void*)"iqxmlrpc verifier", NULL, NULL, NULL);
91
98
}
92
99
 
93
 
Ctx* ctx = 0;
94
 
boost::once_flag ssl_init;
95
 
 
 
100
//
 
101
// Ctx
 
102
//
96
103
 
97
104
Ctx* Ctx::client_server( const std::string& cert_path, const std::string& key_path )
98
105
{
111
118
  return new Ctx;
112
119
}
113
120
 
114
 
 
115
 
Ctx::Ctx( const std::string& cert_path, const std::string& key_path, bool client )
 
121
namespace {
 
122
 
 
123
void
 
124
set_common_options(SSL_CTX* ctx)
 
125
{
 
126
  SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
 
127
}
 
128
 
 
129
int
 
130
iqxmlrpc_SSL_verify(int prev_ok, X509_STORE_CTX* ctx)
 
131
{
 
132
  SSL* ssl = reinterpret_cast<SSL*>(X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()));
 
133
  ConnectionVerifier* v = reinterpret_cast<ConnectionVerifier*>(SSL_get_ex_data(ssl, iqxmlrpc_ssl_data_idx));
 
134
  return v->verify(prev_ok, ctx);
 
135
}
 
136
 
 
137
} // anonymous namespace
 
138
 
 
139
//
 
140
// ConnectionVerifier
 
141
//
 
142
 
 
143
ConnectionVerifier::~ConnectionVerifier()
 
144
{
 
145
}
 
146
 
 
147
int
 
148
ConnectionVerifier::verify(bool prev_ok, X509_STORE_CTX* ctx) const
 
149
{
 
150
  try {
 
151
    return do_verify(prev_ok, ctx);
 
152
  } catch (...) {
 
153
    // TODO: log ability?
 
154
    return 0;
 
155
  }
 
156
}
 
157
 
 
158
std::string
 
159
ConnectionVerifier::cert_finger_sha256(X509_STORE_CTX* ctx) const
 
160
{
 
161
  X509* x = X509_STORE_CTX_get_current_cert(ctx);
 
162
  const EVP_MD* digest = EVP_get_digestbyname("sha256");
 
163
  unsigned int n = 0;
 
164
  unsigned char md[EVP_MAX_MD_SIZE];
 
165
  X509_digest(x, digest, md, &n);
 
166
 
 
167
  std::ostringstream ss;
 
168
  for(int i = 0; i < 32; i++)
 
169
     ss << std::hex << int(md[i]);
 
170
 
 
171
  return ss.str();
 
172
}
 
173
 
 
174
//
 
175
// Ctx
 
176
//
 
177
 
 
178
Ctx::Ctx( const std::string& cert_path, const std::string& key_path, bool client ):
 
179
  server_verifier_(0),
 
180
  client_verifier_(0),
 
181
  require_client_cert_(false)
116
182
{
117
183
  boost::call_once(ssl_init, init_library);
118
184
  ctx = SSL_CTX_new( client ? SSLv23_method() : SSLv23_server_method() );
119
 
  SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
 
185
  set_common_options(ctx);
120
186
 
121
187
  if(
122
188
    !SSL_CTX_use_certificate_file( ctx, cert_path.c_str(), SSL_FILETYPE_PEM ) ||
127
193
}
128
194
 
129
195
 
130
 
Ctx::Ctx()
 
196
Ctx::Ctx():
 
197
  server_verifier_(0),
 
198
  client_verifier_(0),
 
199
  require_client_cert_(false)
131
200
{
132
201
  boost::call_once(ssl_init, init_library);
133
202
  ctx = SSL_CTX_new( SSLv23_client_method() );
134
 
  SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
 
203
  set_common_options(ctx);
135
204
}
136
205
 
137
206
 
139
208
{
140
209
}
141
210
 
 
211
void
 
212
Ctx::verify_server(ConnectionVerifier* v)
 
213
{
 
214
  server_verifier_ = v;
 
215
}
 
216
 
 
217
void
 
218
Ctx::verify_client(bool require_certificate, ConnectionVerifier* v)
 
219
{
 
220
  require_client_cert_ = require_certificate;
 
221
  client_verifier_ = v;
 
222
}
 
223
 
 
224
void
 
225
Ctx::prepare_verify(SSL* ssl, bool server)
 
226
{
 
227
  ConnectionVerifier* v = server ? client_verifier_ : server_verifier_;
 
228
  int mode = v ? SSL_VERIFY_PEER : SSL_VERIFY_NONE;
 
229
 
 
230
  if (server && require_client_cert_)
 
231
    mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
 
232
 
 
233
  if (v) {
 
234
    SSL_set_verify(ssl, mode, iqxmlrpc_SSL_verify);
 
235
    SSL_set_ex_data(ssl, iqxmlrpc_ssl_data_idx, (void*)v);
 
236
  } else {
 
237
    SSL_set_verify(ssl, mode, 0);
 
238
  }
 
239
}
142
240
 
143
241
// ----------------------------------------------------------------------------
144
242
exception::exception() throw():