~ubuntu-branches/ubuntu/trusty/vsftpd/trusty-proposed

« back to all changes in this revision

Viewing changes to ssl.c

  • Committer: Bazaar Package Importer
  • Author(s): Matti Lindell
  • Date: 2008-02-25 09:53:13 UTC
  • mto: (2.2.1 lenny) (1.5.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 11.
  • Revision ID: james.westby@ubuntu.com-20080225095313-vvzr3dipu25zi1z9
Tags: upstream-2.0.6
ImportĀ upstreamĀ versionĀ 2.0.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
#include "tunables.h"
21
21
#include "utility.h"
22
22
#include "builddefs.h"
 
23
#include "logging.h"
23
24
 
24
25
#ifdef VSF_BUILD_SSL
25
26
 
34
35
static void setup_bio_callbacks();
35
36
static long bio_callback(
36
37
  BIO* p_bio, int oper, const char* p_arg, int argi, long argl, long retval);
 
38
static int ssl_verify_callback(int verify_ok, X509_STORE_CTX* p_ctx);
 
39
static int ssl_cert_digest(
 
40
  SSL* p_ssl, struct vsf_session* p_sess, struct mystr* p_str);
37
41
 
38
42
static int ssl_inited;
 
43
static struct mystr debug_str;
39
44
 
40
45
void
41
46
ssl_init(struct vsf_session* p_sess)
44
49
  {
45
50
    SSL_CTX* p_ctx;
46
51
    long options;
 
52
    int verify_option = 0;
47
53
    SSL_library_init();
48
54
    p_ctx = SSL_CTX_new(SSLv23_server_method());
49
55
    if (p_ctx == NULL)
105
111
    {
106
112
      die("SSL: RNG is not seeded");
107
113
    }
 
114
    verify_option = SSL_VERIFY_PEER;
 
115
    if (tunable_require_cert)
 
116
    {
 
117
      verify_option |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
 
118
    }
 
119
    SSL_CTX_set_verify(p_ctx, verify_option, ssl_verify_callback);
 
120
    if (tunable_ca_certs_file)
 
121
    {
 
122
      if (!SSL_CTX_load_verify_locations(p_ctx, tunable_ca_certs_file, NULL))
 
123
      {
 
124
        die("SSL: could not load verify file");
 
125
      }
 
126
    }
108
127
    p_sess->p_ssl_ctx = p_ctx;
109
128
    ssl_inited = 1;
110
129
  }
124
143
    {
125
144
      struct mystr err_str = INIT_MYSTR;
126
145
      str_alloc_text(&err_str, "Negotiation failed: ");
 
146
      /* Technically, we shouldn't leak such detailed error messages. */
127
147
      str_append_text(&err_str, get_ssl_error());
128
148
      vsf_cmdio_write_str(p_sess, FTP_TLS_FAIL, &err_str);
129
149
      vsf_sysutil_exit(0);
187
207
ssl_getline(const struct vsf_session* p_sess, struct mystr* p_str,
188
208
            char end_char, char* p_buf, unsigned int buflen)
189
209
{
 
210
  if (buflen == 0)
 
211
  {
 
212
    return;
 
213
  }
190
214
  char* p_buf_start = p_buf;
191
 
  p_buf[buflen - 1] = '\0';
 
215
  p_buf[buflen - 1] = end_char;
192
216
  buflen--;
193
217
  while (1)
194
218
  {
 
219
    /* Should I use SSL_peek here? Won't lack of it break pipelining? (SSL
 
220
     * clients seem to work just fine, mind you, so maybe pipelining is banned
 
221
     * over SSL connections. Also note that OpenSSL didn't always have
 
222
     * SSL_peek).
 
223
     */
195
224
    int retval = SSL_read(p_sess->p_control_ssl, p_buf, buflen);
196
225
    if (retval <= 0)
197
226
    {
198
227
      die("SSL_read");
199
228
    }
200
 
    p_buf[retval] = '\0';
 
229
    p_buf[retval] = end_char;
201
230
    buflen -= retval;
202
231
    if (p_buf[retval - 1] == end_char || buflen == 0)
203
232
    {
250
279
  return 0;
251
280
}
252
281
 
 
282
void
 
283
ssl_data_close(struct vsf_session* p_sess)
 
284
{
 
285
  if (p_sess->p_data_ssl)
 
286
  {
 
287
    SSL_free(p_sess->p_data_ssl);
 
288
    p_sess->p_data_ssl = NULL;
 
289
  }
 
290
}
 
291
 
253
292
int
254
293
ssl_accept(struct vsf_session* p_sess, int fd)
255
294
{
 
295
  /* SECURITY: data SSL connections don't have any auth on them as part of the
 
296
   * protocol. If a client sends an unfortunately optional client cert then
 
297
   * we can check for a match between the control and data connections.
 
298
   */
 
299
  if (p_sess->p_data_ssl != NULL)
 
300
  {
 
301
    die("p_data_ssl should be NULL.");
 
302
  }
256
303
  SSL* p_ssl = get_ssl(p_sess, fd);
257
304
  if (p_ssl == NULL)
258
305
  {
260
307
  }
261
308
  p_sess->p_data_ssl = p_ssl;
262
309
  setup_bio_callbacks(p_ssl);
 
310
  if (str_getlen(&p_sess->control_cert_digest) > 0)
 
311
  {
 
312
    static struct mystr data_cert_digest;
 
313
    if (!ssl_cert_digest(p_ssl, p_sess, &data_cert_digest))
 
314
    {
 
315
      if (tunable_debug_ssl)
 
316
      {
 
317
        str_alloc_text(&debug_str, "Missing cert on data channel.");
 
318
        vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str);
 
319
      }
 
320
      ssl_data_close(p_sess);
 
321
      return 0;
 
322
    }
 
323
    if (str_strcmp(&p_sess->control_cert_digest, &data_cert_digest))
 
324
    {
 
325
      if (tunable_debug_ssl)
 
326
      {
 
327
        str_alloc_text(&debug_str, "DIFFERENT cert on data channel.");
 
328
        vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str);
 
329
      }
 
330
      ssl_data_close(p_sess);
 
331
      return 0;
 
332
    }
 
333
    if (tunable_debug_ssl)
 
334
    {
 
335
      str_alloc_text(&debug_str, "Matching cert on data channel.");
 
336
      vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str);
 
337
    }
 
338
  }
263
339
  return 1;
264
340
}
265
341
 
266
342
void
267
 
ssl_data_close(struct vsf_session* p_sess)
268
 
{
269
 
  SSL_free(p_sess->p_data_ssl);
270
 
}
271
 
 
272
 
void
273
343
ssl_comm_channel_init(struct vsf_session* p_sess)
274
344
{
275
345
  const struct vsf_sysutil_socketpair_retval retval =
284
354
  SSL* p_ssl = SSL_new(p_sess->p_ssl_ctx);
285
355
  if (p_ssl == NULL)
286
356
  {
 
357
    if (tunable_debug_ssl)
 
358
    {
 
359
      str_alloc_text(&debug_str, "SSL_new failed");
 
360
      vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str);
 
361
    }
287
362
    return NULL;
288
363
  }
289
364
  if (!SSL_set_fd(p_ssl, fd))
290
365
  {
 
366
    if (tunable_debug_ssl)
 
367
    {
 
368
      str_alloc_text(&debug_str, "SSL_set_fd failed");
 
369
      vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str);
 
370
    }
291
371
    SSL_free(p_ssl);
292
372
    return NULL;
293
373
  }
294
374
  if (SSL_accept(p_ssl) != 1)
295
375
  {
296
 
    die(get_ssl_error());
 
376
    const char* p_err = get_ssl_error();
 
377
    if (tunable_debug_ssl)
 
378
    {
 
379
      str_alloc_text(&debug_str, "SSL_accept failed: ");
 
380
      str_append_text(&debug_str, p_err);
 
381
      vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str);
 
382
    }
 
383
    die(p_err);
297
384
    SSL_free(p_ssl);
298
385
    return NULL;
299
386
  }
 
387
  if (tunable_debug_ssl)
 
388
  {
 
389
    const char* p_ssl_version = SSL_get_cipher_version(p_ssl);
 
390
    SSL_CIPHER* p_ssl_cipher = SSL_get_current_cipher(p_ssl);
 
391
    const char* p_cipher_name = SSL_CIPHER_get_name(p_ssl_cipher);
 
392
    int reused = SSL_session_reused(p_ssl);
 
393
    X509* p_ssl_cert = SSL_get_peer_certificate(p_ssl);
 
394
    str_alloc_text(&debug_str, "SSL version: ");
 
395
    str_append_text(&debug_str, p_ssl_version);
 
396
    str_append_text(&debug_str, ", SSL cipher: ");
 
397
    str_append_text(&debug_str, p_cipher_name);
 
398
    if (reused)
 
399
    {
 
400
      str_append_text(&debug_str, ", reused");
 
401
    }
 
402
    else
 
403
    {
 
404
      str_append_text(&debug_str, ", not reused");
 
405
    }
 
406
    if (p_ssl_cert != NULL)
 
407
    {
 
408
      str_append_text(&debug_str, ", CERT PRESENTED");
 
409
      X509_free(p_ssl_cert);
 
410
    }
 
411
    else
 
412
    {
 
413
      str_append_text(&debug_str, ", no cert");
 
414
    }
 
415
    vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str);
 
416
  }
300
417
  return p_ssl;
301
418
}
302
419
 
309
426
    return 0;
310
427
  }
311
428
  p_sess->p_control_ssl = p_ssl;
 
429
  (void) ssl_cert_digest(p_ssl, p_sess, &p_sess->control_cert_digest);
312
430
  setup_bio_callbacks(p_ssl);
313
431
  return 1;
314
432
}
315
433
 
 
434
static int
 
435
ssl_cert_digest(SSL* p_ssl, struct vsf_session* p_sess, struct mystr* p_str)
 
436
{
 
437
  X509* p_cert = SSL_get_peer_certificate(p_ssl);
 
438
  unsigned int num_bytes = 0;
 
439
  if (p_cert == NULL)
 
440
  {
 
441
    return 0;
 
442
  }
 
443
  str_reserve(p_str, EVP_MAX_MD_SIZE);
 
444
  str_empty(p_str);
 
445
  str_rpad(p_str, EVP_MAX_MD_SIZE);
 
446
  if (!X509_digest(p_cert, EVP_sha256(), (unsigned char*) str_getbuf(p_str),
 
447
                   &num_bytes))
 
448
  {
 
449
    die("X509_digest failed");
 
450
  }
 
451
  X509_free(p_cert);
 
452
  if (tunable_debug_ssl)
 
453
  {
 
454
    unsigned int i;
 
455
    str_alloc_text(&debug_str, "Cert digest:");
 
456
    for (i = 0; i < num_bytes; ++i)
 
457
    { 
 
458
      str_append_char(&debug_str, ' ');
 
459
      str_append_ulong(
 
460
        &debug_str, (unsigned long) (unsigned char) str_get_char_at(p_str, i));
 
461
    }
 
462
    vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str);
 
463
  }
 
464
  str_trunc(p_str, num_bytes);
 
465
  return 1;
 
466
}
 
467
 
316
468
static char*
317
469
get_ssl_error()
318
470
{
347
499
  return ret;
348
500
}
349
501
 
 
502
static int
 
503
ssl_verify_callback(int verify_ok, X509_STORE_CTX* p_ctx)
 
504
{
 
505
  (void) p_ctx;
 
506
  if (tunable_validate_cert)
 
507
  {
 
508
    return verify_ok;
 
509
  }
 
510
  return 1;
 
511
}
 
512
 
350
513
#else /* VSF_BUILD_SSL */
351
514
 
352
515
void