Skip to content

Commit d676994

Browse files
committed
CCBC-1658: Add support for encrypted TLS keys
The key password should be specified in connection options with lcb_createopts_tls_key_password() Change-Id: I2ef89b3f55499c08d610823d96a273e975371d4c Reviewed-on: https://review.couchbase.org/c/libcouchbase/+/224097 Tested-by: Build Bot <build@couchbase.com> Reviewed-by: Hiren <hiren.bavaskar@couchbase.com>
1 parent fe470f8 commit d676994

7 files changed

Lines changed: 81 additions & 13 deletions

File tree

include/libcouchbase/couchbase.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,10 @@ LIBCOUCHBASE_API lcb_STATUS lcb_createopts_io(lcb_CREATEOPTS *options, struct lc
271271
LIBCOUCHBASE_API lcb_STATUS lcb_createopts_meter(lcb_CREATEOPTS *options, const lcbmetrics_METER *metrics);
272272

273273
LIBCOUCHBASE_API lcb_STATUS lcb_createopts_tracer(lcb_CREATEOPTS *options, lcbtrace_TRACER *tracer);
274+
275+
LIBCOUCHBASE_API lcb_STATUS lcb_createopts_tls_key_password(lcb_CREATEOPTS *options, const char *password,
276+
size_t password_len);
277+
274278
/**
275279
* @brief Create an instance of lcb.
276280
* @param instance Where the instance should be returned

src/instance.cc

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,14 @@ LIBCOUCHBASE_API lcb_STATUS lcb_createopts_meter(lcb_CREATEOPTS *options, const
102102
return LCB_SUCCESS;
103103
}
104104

105+
LIBCOUCHBASE_API lcb_STATUS lcb_createopts_tls_key_password(lcb_CREATEOPTS *options, const char *password,
106+
size_t password_len)
107+
{
108+
options->tls_key_password = password;
109+
options->tls_key_password_len = password_len;
110+
return LCB_SUCCESS;
111+
}
112+
105113
LIBCOUCHBASE_API
106114
const char *lcb_get_version(lcb_uint32_t *version)
107115
{
@@ -313,7 +321,7 @@ static lcb_STATUS init_providers(lcb_INSTANCE *obj, const Connspec &spec)
313321
return LCB_SUCCESS;
314322
}
315323

316-
static lcb_STATUS setup_ssl(lcb_INSTANCE *obj, const Connspec &params)
324+
static lcb_STATUS setup_ssl(lcb_INSTANCE *obj, const Connspec &params, const char *keypass, size_t keypass_len)
317325
{
318326
char optbuf[4096];
319327
long env_policy = -1;
@@ -368,8 +376,8 @@ static lcb_STATUS setup_ssl(lcb_INSTANCE *obj, const Connspec &params)
368376
lcb_log(LOGARGS(obj, ERR), "SSL key have to be specified with certificate");
369377
return LCB_ERR_INVALID_ARGUMENT;
370378
}
371-
settings->ssl_ctx = lcbio_ssl_new(settings->truststorepath, settings->certpath, settings->keypath,
372-
settings->sslopts & LCB_SSL_NOVERIFY, &err, settings);
379+
settings->ssl_ctx = lcbio_ssl_new(settings->truststorepath, settings->certpath, settings->keypath, keypass,
380+
keypass_len, settings->sslopts & LCB_SSL_NOVERIFY, &err, settings);
373381
if (!settings->ssl_ctx) {
374382
return err;
375383
}
@@ -452,11 +460,18 @@ lcb_STATUS lcb_create(lcb_INSTANCE **instance, const lcb_CREATEOPTS *options)
452460
lcb_INSTANCE *obj = nullptr;
453461
lcb_STATUS err;
454462
lcb_settings *settings;
463+
std::string effective_connstr;
464+
const char *keypass = nullptr;
465+
std::size_t keypass_len = 0;
455466

456467
if (options) {
457468
io_priv = options->io;
458469
type = options->type;
459470
err = spec.load(*options);
471+
if (options->tls_key_password != nullptr && options->tls_key_password_len > 0) {
472+
keypass = options->tls_key_password;
473+
keypass_len = options->tls_key_password_len;
474+
}
460475
} else {
461476
const char *errmsg;
462477
const char *default_connstr = "couchbase://";
@@ -543,8 +558,26 @@ lcb_STATUS lcb_create(lcb_INSTANCE **instance, const lcb_CREATEOPTS *options)
543558
}
544559

545560
lcb_log(LOGARGS(obj, INFO), "Version=%s, Changeset=%s", lcb_get_version(nullptr), LCB_VERSION_CHANGESET);
561+
effective_connstr = spec.connstr();
562+
{
563+
std::vector<std::string> sensitive_params{
564+
"password=",
565+
};
566+
567+
for (const auto &param : sensitive_params) {
568+
auto start = effective_connstr.find(param);
569+
if (start != std::string::npos) {
570+
auto value_start = start + param.size();
571+
auto end = effective_connstr.find('&', value_start);
572+
if (end == std::string::npos) {
573+
end = effective_connstr.size();
574+
}
575+
effective_connstr.replace(value_start, end - value_start, "[REDACTED]");
576+
}
577+
}
578+
}
546579
lcb_log(LOGARGS(obj, INFO), "Effective connection string: " LCB_LOG_SPEC("%s") ". Bucket=" LCB_LOG_SPEC("%s"),
547-
settings->log_redaction ? LCB_LOG_SD_OTAG : "", spec.connstr().c_str(),
580+
settings->log_redaction ? LCB_LOG_SD_OTAG : "", effective_connstr.c_str(),
548581
settings->log_redaction ? LCB_LOG_SD_CTAG : "", settings->log_redaction ? LCB_LOG_MD_OTAG : "",
549582
settings->bucket, settings->log_redaction ? LCB_LOG_MD_CTAG : "");
550583

@@ -580,7 +613,7 @@ lcb_STATUS lcb_create(lcb_INSTANCE **instance, const lcb_CREATEOPTS *options)
580613
lcb_aspend_init(&obj->pendops);
581614
obj->collcache = new lcb::CollectionCache();
582615

583-
if ((err = setup_ssl(obj, spec)) != LCB_SUCCESS) {
616+
if ((err = setup_ssl(obj, spec, keypass, keypass_len)) != LCB_SUCCESS) {
584617
goto GT_DONE;
585618
}
586619

src/internalstructs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ struct lcb_CREATEOPTS_ {
5555
size_t bucket_len;
5656
lcbtrace_TRACER *tracer;
5757
const lcbmetrics_METER *meter;
58+
const char *tls_key_password;
59+
size_t tls_key_password_len;
5860
};
5961

6062
/**

src/lcbio/ioutils.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,8 @@ int lcbio_ssl_supported(void)
309309
#endif
310310
}
311311

312-
lcbio_pSSLCTX lcbio_ssl_new__fallback(const char *, const char *, const char *, int, lcb_STATUS *errp, lcb_settings *)
312+
lcbio_pSSLCTX lcbio_ssl_new__fallback(const char *, const char *, const char *, const char *, size_t, int,
313+
lcb_STATUS *errp, lcb_settings *)
313314
{
314315
if (errp) {
315316
*errp = LCB_ERR_SDK_FEATURE_UNAVAILABLE;

src/lcbio/ssl.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,22 +59,25 @@ typedef struct lcbio_SSLCTX *lcbio_pSSLCTX;
5959
*/
6060
int lcbio_ssl_supported(void);
6161

62-
lcbio_pSSLCTX lcbio_ssl_new__fallback(const char *, const char *, const char *, int, lcb_STATUS *, lcb_settings *);
62+
lcbio_pSSLCTX lcbio_ssl_new__fallback(const char *, const char *, const char *, const char *, size_t, int, lcb_STATUS *,
63+
lcb_settings *);
6364

6465
#ifndef LCB_NO_SSL
6566
/**
6667
* Create a new SSL context to be used to establish SSL policy.
6768
* @param tsfile Path to trusted store file
6869
* @param cafile Optional path to CA file
6970
* @param keyfile Path to private key file
71+
* @param keypass password for key file or NULL.
72+
* @param keypass_len length of the password for key file or 0.
7073
* @param noverify To not attempt to verify server's certificate
7174
* @param errp a pointer to contain the error code if initialization failed
7275
* @param settings settings structure, used for logging.
7376
*
7477
* @return A new SSL context, or NULL on error.
7578
*/
76-
lcbio_pSSLCTX lcbio_ssl_new(const char *tsfile, const char *cafile, const char *keyfile, int noverify, lcb_STATUS *errp,
77-
lcb_settings *settings);
79+
lcbio_pSSLCTX lcbio_ssl_new(const char *tsfile, const char *cafile, const char *keyfile, const char *keypass,
80+
size_t keypass_len, int noverify, lcb_STATUS *errp, lcb_settings *settings);
7881
#else
7982
#define lcbio_ssl_new lcbio_ssl_new__fallback
8083
#endif

src/ssl/ssl_common.c

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "logging.h"
2525
#include <openssl/err.h>
2626
#include <openssl/opensslv.h>
27+
#include <openssl/ssl.h>
2728

2829
#if OPENSSL_VERSION_NUMBER >= 0x1010100fL
2930
#define HAVE_CIPHERSUITES 1
@@ -370,8 +371,26 @@ static lcb_STATUS add_certificate_authority(const lcb_settings *settings, SSL_CT
370371
return rc;
371372
}
372373

373-
lcbio_pSSLCTX lcbio_ssl_new(const char *tsfile, const char *cafile, const char *keyfile, int noverify, lcb_STATUS *errp,
374-
lcb_settings *settings)
374+
struct tls_key_secret {
375+
const char *password;
376+
size_t password_len;
377+
};
378+
379+
static int keyfile_password_cb(char *buf, int size, int rwflag, void *userdata)
380+
{
381+
(void)rwflag;
382+
383+
struct tls_key_secret *secret = (struct tls_key_secret *)userdata;
384+
if (secret->password_len > (size_t)size) {
385+
return 0;
386+
}
387+
388+
memcpy(buf, secret->password, secret->password_len);
389+
return secret->password_len;
390+
}
391+
392+
lcbio_pSSLCTX lcbio_ssl_new(const char *tsfile, const char *cafile, const char *keyfile, const char *keypass,
393+
size_t keypass_len, int noverify, lcb_STATUS *errp, lcb_settings *settings)
375394
{
376395
lcb_STATUS err_s;
377396
lcbio_pSSLCTX ret;
@@ -444,11 +463,17 @@ lcbio_pSSLCTX lcbio_ssl_new(const char *tsfile, const char *cafile, const char *
444463
}
445464

446465
if (cafile && keyfile) {
447-
lcb_log(LOGARGS_S(settings, LCB_LOG_DEBUG), "Authenticate with key \"%s\", cert \"%s\"", keyfile, cafile);
466+
lcb_log(LOGARGS_S(settings, LCB_LOG_DEBUG), "Authenticate with key \"%s\"%s, cert \"%s\"", keyfile,
467+
keypass ? " (encrypted)" : "", cafile);
448468
if (!SSL_CTX_use_certificate_chain_file(ret->ctx, cafile)) {
449469
*errp = LCB_ERR_SSL_ERROR;
450470
goto GT_ERR;
451471
}
472+
struct tls_key_secret secret = {keypass, keypass_len};
473+
if (keypass) {
474+
SSL_CTX_set_default_passwd_cb(ret->ctx, keyfile_password_cb);
475+
SSL_CTX_set_default_passwd_cb_userdata(ret->ctx, (void *)&secret);
476+
}
452477
if (!SSL_CTX_use_PrivateKey_file(ret->ctx, keyfile, SSL_FILETYPE_PEM)) {
453478
lcb_log(LOGARGS_S(settings, LCB_LOG_ERROR), "Unable to load private key \"%s\"", keyfile);
454479
*errp = LCB_ERR_SSL_ERROR;

tests/socktests/t_ssl.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class SSLTest : public SockTest
3535

3636
SockTest::SetUp();
3737
loop->settings->sslopts = LCB_SSL_ENABLED | LCB_SSL_NOVERIFY;
38-
loop->settings->ssl_ctx = lcbio_ssl_new(nullptr, nullptr, nullptr, 1, &errp, loop->settings);
38+
loop->settings->ssl_ctx = lcbio_ssl_new(nullptr, nullptr, nullptr, nullptr, 0, 1, &errp, loop->settings);
3939
loop->server->factory = TestServer::sslSocketFactory;
4040
EXPECT_FALSE(loop->settings->ssl_ctx == nullptr) << lcb_strerror_short(errp);
4141
}

0 commit comments

Comments
 (0)