summaryrefslogtreecommitdiffstats
path: root/src/common/ceph_crypto.cc
blob: 62fc94ea28cc867f655405743baaf70d4db946ec (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
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2010-2011 Dreamhost
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software
 * Foundation.  See file COPYING.
 *
 */

#include "common/ceph_context.h"
#include "common/config.h"
#include "ceph_crypto.h"

#ifdef USE_NSS

// for SECMOD_RestartModules()
#include <secmod.h>
#include <nspr.h>

#endif /*USE_NSS*/

#ifdef USE_OPENSSL
#include <openssl/evp.h>
#endif /*USE_OPENSSL*/

#ifdef USE_NSS

static pthread_mutex_t crypto_init_mutex = PTHREAD_MUTEX_INITIALIZER;
static uint32_t crypto_refs = 0;
static NSSInitContext *crypto_context = NULL;
static pid_t crypto_init_pid = 0;

void ceph::crypto::init(CephContext *cct)
{
  pid_t pid = getpid();
  pthread_mutex_lock(&crypto_init_mutex);
  if (crypto_init_pid != pid) {
    if (crypto_init_pid > 0) {
      SECMOD_RestartModules(PR_FALSE);
    }
    crypto_init_pid = pid;
  }

  if (++crypto_refs == 1) {
    NSSInitParameters init_params;
    memset(&init_params, 0, sizeof(init_params));
    init_params.length = sizeof(init_params);

    uint32_t flags = (NSS_INIT_READONLY | NSS_INIT_PK11RELOAD);
    if (cct->_conf->nss_db_path.empty()) {
      flags |= (NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB);
    }
    crypto_context = NSS_InitContext(cct->_conf->nss_db_path.c_str(), "", "",
                                     SECMOD_DB, &init_params, flags);
  }
  pthread_mutex_unlock(&crypto_init_mutex);
  ceph_assert_always(crypto_context != NULL);
}

void ceph::crypto::shutdown(bool shared)
{
  pthread_mutex_lock(&crypto_init_mutex);
  ceph_assert_always(crypto_refs > 0);
  if (--crypto_refs == 0) {
    NSS_ShutdownContext(crypto_context);
    if (!shared) {
      PR_Cleanup();
    }
    crypto_context = NULL;
    crypto_init_pid = 0;
  }
  pthread_mutex_unlock(&crypto_init_mutex);
}

ceph::crypto::nss::HMAC::~HMAC()
{
  PK11_DestroyContext(ctx, PR_TRUE);
  PK11_FreeSymKey(symkey);
  PK11_FreeSlot(slot);
}

#else
# error "No supported crypto implementation found."
#endif /*USE_NSS*/

#ifdef USE_OPENSSL

ceph::crypto::ssl::OpenSSLDigest::OpenSSLDigest(const EVP_MD * _type)
  : mpContext(EVP_MD_CTX_create())
  , mpType(_type) {
  this->Restart();
}

ceph::crypto::ssl::OpenSSLDigest::~OpenSSLDigest() {
  EVP_MD_CTX_destroy(mpContext);
}

void ceph::crypto::ssl::OpenSSLDigest::Restart() {
  EVP_DigestInit_ex(mpContext, mpType, NULL);
}

void ceph::crypto::ssl::OpenSSLDigest::Update(const unsigned char *input, size_t length) {
  if (length) {
    EVP_DigestUpdate(mpContext, const_cast<void *>(reinterpret_cast<const void *>(input)), length);
  }
}

void ceph::crypto::ssl::OpenSSLDigest::Final(unsigned char *digest) {
  unsigned int s;
  EVP_DigestFinal_ex(mpContext, digest, &s);
}
#endif /*USE_OPENSSL*/


void ceph::crypto::zeroize_for_security(void* const s, const size_t n) {
#ifdef USE_OPENSSL
  // NSS lacks its own cleaning procedure that would be resilient to
  // dead-store-elimination of nowadays compilers [1]. To avoid writing
  // our own security code, let's always use the OpenSSL's one.
  // [1]: "NSS [3.27.1] does not have a reliable memory scrubbing
  //      implementation since it either calls memset or uses the macro
  //      PORT_Memset, which expands to memset"
  // https://klevchen.ece.illinois.edu/pubs/yjoll-usesec17.pdf, page 11.
  OPENSSL_cleanse(s, n);
#else
  // OpenSSL is available even when NSS is turned on. The performance-
  // critical Cephx's signature crafting machinery already follows this
  // assumption and uses OpenSSL directly (see src/auth/Crypto.cc).
  // Also, in CMakeList.txt we explicitly require both NSS and OpenSSL:
  //
  //  find_package(NSS REQUIRED)
  //  find_package(NSPR REQUIRED)
  //  find_package(OpenSSL REQUIRED)
# error "No supported crypto implementation found."
#endif /*USE_OPENSSL*/
}