aboutsummaryrefslogtreecommitdiff
path: root/src/lib/tls/x509.c
blob: 25154992988f25cf768ac8d581b5a18f9a7ba028 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/* Copyright (c) 2003, Roger Dingledine.
 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
 * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */

/**
 * \file x509_openssl.c
 * \brief Wrapper functions to present a consistent interface to
 * X.509 functions.
 **/

#define TOR_X509_PRIVATE
#include "lib/tls/x509.h"
#include "lib/tls/x509_internal.h"
#include "lib/log/util_bug.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"

/** Choose the start and end times for a certificate */
void
tor_tls_pick_certificate_lifetime(time_t now,
                                  unsigned int cert_lifetime,
                                  time_t *start_time_out,
                                  time_t *end_time_out)
{
  tor_assert(cert_lifetime < INT_MAX);
  time_t start_time, end_time;
  /* Make sure we're part-way through the certificate lifetime, rather
   * than having it start right now. Don't choose quite uniformly, since
   * then we might pick a time where we're about to expire. Lastly, be
   * sure to start on a day boundary. */
  /* Our certificate lifetime will be cert_lifetime no matter what, but if we
   * start cert_lifetime in the past, we'll have 0 real lifetime.  instead we
   * start up to (cert_lifetime - min_real_lifetime - start_granularity) in
   * the past. */
  const time_t min_real_lifetime = 24*3600;
  const time_t start_granularity = 24*3600;
  time_t earliest_start_time;
  /* Don't actually start in the future! */
  if ((int)cert_lifetime <= min_real_lifetime + start_granularity) {
    earliest_start_time = now - 1;
  } else {
    earliest_start_time = now + min_real_lifetime + start_granularity
      - cert_lifetime;
  }
  start_time = crypto_rand_time_range(earliest_start_time, now);
  /* Round the start time back to the start of a day. */
  start_time -= start_time % start_granularity;

  end_time = start_time + cert_lifetime;

  *start_time_out = start_time;
  *end_time_out = end_time;
}

/** Return a set of digests for the public key in <b>cert</b>, or NULL if this
 * cert's public key is not one we know how to take the digest of. */
const common_digests_t *
tor_x509_cert_get_id_digests(const tor_x509_cert_t *cert)
{
  if (cert->pkey_digests_set)
    return &cert->pkey_digests;
  else
    return NULL;
}

/** Return a set of digests for the public key in <b>cert</b>. */
const common_digests_t *
tor_x509_cert_get_cert_digests(const tor_x509_cert_t *cert)
{
  return &cert->cert_digests;
}

/** Free all storage held in <b>cert</b> */
void
tor_x509_cert_free_(tor_x509_cert_t *cert)
{
  if (! cert)
    return;
  tor_x509_cert_impl_free(cert->cert);
#ifdef ENABLE_OPENSSL
  tor_free(cert->encoded);
#endif
  memwipe(cert, 0x03, sizeof(*cert));
  /* LCOV_EXCL_BR_START since cert will never be NULL here */
  tor_free(cert);
  /* LCOV_EXCL_BR_STOP */
}

/**
 * Allocate a new tor_x509_cert_t to hold the certificate "x509_cert".
 *
 * Steals a reference to x509_cert.
 */
MOCK_IMPL(tor_x509_cert_t *,
tor_x509_cert_new,(tor_x509_cert_impl_t *x509_cert))
{
  tor_x509_cert_t *cert;

  if (!x509_cert)
    return NULL;

  cert = tor_malloc_zero(sizeof(tor_x509_cert_t));
  cert->cert = x509_cert;

  if (tor_x509_cert_set_cached_der_encoding(cert) < 0)
    goto err;

  {
    const uint8_t *encoded=NULL;
    size_t encoded_len=0;
    tor_x509_cert_get_der(cert, &encoded, &encoded_len);
    tor_assert(encoded);
    crypto_common_digests(&cert->cert_digests, (char *)encoded, encoded_len);
  }

  {
    crypto_pk_t *pk = tor_tls_cert_get_key(cert);
    if (pk) {
      if (crypto_pk_get_common_digests(pk, &cert->pkey_digests) < 0) {
        log_warn(LD_CRYPTO, "unable to compute digests of certificate key");
        crypto_pk_free(pk);
        goto err;
      }
    }
    cert->pkey_digests_set = 1;
    crypto_pk_free(pk);
  }

  return cert;
 err:
  log_err(LD_CRYPTO, "Couldn't wrap encoded X509 certificate.");
  tor_x509_cert_free(cert);
  return NULL;
}

/** Return a new copy of <b>cert</b>. */
tor_x509_cert_t *
tor_x509_cert_dup(const tor_x509_cert_t *cert)
{
  tor_assert(cert);
  tor_assert(cert->cert);
  return tor_x509_cert_new(tor_x509_cert_impl_dup_(cert->cert));
}