aboutsummaryrefslogtreecommitdiff
path: root/src/lib/crypt_ops/crypto_nss_mgt.c
blob: 0179126e38f32a2063bf7811720b9366cd5fec22 (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
/* Copyright (c) 2001, Matej Pfajfar.
 * Copyright (c) 2001-2004, Roger Dingledine.
 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
 * Copyright (c) 2007-2019, The Tor Project, Inc. */
/* See LICENSE for licensing information */

/**
 * \file crypto_nss_mgt.c
 *
 * \brief Manage the NSS library (if used)
 **/

#include "lib/crypt_ops/crypto_nss_mgt.h"

#include "lib/log/log.h"
#include "lib/log/util_bug.h"
#include "lib/string/printf.h"

DISABLE_GCC_WARNING(strict-prototypes)
#include <nss.h>
#include <pk11func.h>
#include <ssl.h>

#include <prerror.h>
#include <prtypes.h>
#include <prinit.h>
ENABLE_GCC_WARNING(strict-prototypes)

const char *
crypto_nss_get_version_str(void)
{
  return NSS_GetVersion();
}
const char *
crypto_nss_get_header_version_str(void)
{
  return NSS_VERSION;
}

/** A password function that always returns NULL. */
static char *
nss_password_func_always_fail(PK11SlotInfo *slot,
                              PRBool retry,
                              void *arg)
{
  (void) slot;
  (void) retry;
  (void) arg;
  return NULL;
}

void
crypto_nss_early_init(int nss_only)
{
  if (! nss_only) {
    PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
    PK11_SetPasswordFunc(nss_password_func_always_fail);
  }

  /* Eventually we should use NSS_Init() instead -- but that wants a
     directory. The documentation says that we can't use this if we want
     to use OpenSSL. */
  if (NSS_NoDB_Init(NULL) == SECFailure) {
    log_err(LD_CRYPTO, "Unable to initialize NSS.");
    crypto_nss_log_errors(LOG_ERR, "initializing NSS");
    tor_assert_unreached();
  }

  if (NSS_SetDomesticPolicy() == SECFailure) {
    log_err(LD_CRYPTO, "Unable to set NSS cipher policy.");
    crypto_nss_log_errors(LOG_ERR, "setting cipher policy");
    tor_assert_unreached();
  }

  /* We need to override the default here, or NSS will reject all the
   * legacy Tor certificates. */
  SECStatus rv = NSS_OptionSet(NSS_RSA_MIN_KEY_SIZE, 1024);
  if (rv != SECSuccess) {
    log_err(LD_CRYPTO, "Unable to set NSS min RSA key size");
    crypto_nss_log_errors(LOG_ERR, "setting cipher option.");
    tor_assert_unreached();
  }
}

void
crypto_nss_log_errors(int severity, const char *doing)
{
  PRErrorCode code = PR_GetError();
  const char *string = PORT_ErrorToString(code);
  const char *name = PORT_ErrorToName(code);
  char buf[16];
  if (!string)
    string = "<unrecognized>";
  if (!name) {
    tor_snprintf(buf, sizeof(buf), "%d", code);
    name = buf;
  }
  if (doing) {
    tor_log(severity, LD_CRYPTO, "NSS error %s while %s: %s",
            name, doing, string);
  } else {
    tor_log(severity, LD_CRYPTO, "NSS error %s: %s", name, string);
  }
}

int
crypto_nss_late_init(void)
{
  /* Possibly, SSL_OptionSetDefault? */

  return 0;
}

void
crypto_nss_global_cleanup(void)
{
  NSS_Shutdown();
  PL_ArenaFinish();
  PR_Cleanup();
}

void
crypto_nss_prefork(void)
{
  NSS_Shutdown();
}

void
crypto_nss_postfork(void)
{
  crypto_nss_early_init(1);
}