451 lines
17 KiB
Diff
451 lines
17 KiB
Diff
From 63cbb2aee2c6277ecd9e38fb32713e0ba3db4bb4 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
|
|
Date: Thu, 22 Oct 2020 12:18:38 +0200
|
|
Subject: [PATCH 06/19] secrets: accept binary data instead of string
|
|
|
|
Currently, both KCM and secrets responders store JSON formatted string
|
|
in the secrets database. One of the next commits makes KCM to store
|
|
binary format instead of JSON string to improve performance. We need
|
|
to be able to distinguish the formats to keep KCM update compatible
|
|
with existing ccache and also to keep secrets responder working.
|
|
|
|
Secrets responder test had to be ammended to fit into a new maximum
|
|
payload which is now reduced by one byte for the secrets responder
|
|
to hold the ending zero of a secret string.
|
|
|
|
This is a corner case in a long deprecated responder that is not even
|
|
built by default and has no known consumers so it is fine to fast fix
|
|
the test.
|
|
---
|
|
src/responder/kcm/kcmsrv_ccache_secdb.c | 8 +-
|
|
src/responder/secrets/local.c | 5 +-
|
|
src/tests/intg/test_secrets.py | 3 +-
|
|
src/util/secrets/sec_pvt.h | 2 +-
|
|
src/util/secrets/secrets.c | 130 ++++++++++++++----------
|
|
src/util/secrets/secrets.h | 9 +-
|
|
6 files changed, 91 insertions(+), 66 deletions(-)
|
|
|
|
diff --git a/src/responder/kcm/kcmsrv_ccache_secdb.c b/src/responder/kcm/kcmsrv_ccache_secdb.c
|
|
index 8e5bd4f7376173fd075c1a64785a597bcf2f97ba..f0143e686826e3bf637619efc799e0d2f0715ba4 100644
|
|
--- a/src/responder/kcm/kcmsrv_ccache_secdb.c
|
|
+++ b/src/responder/kcm/kcmsrv_ccache_secdb.c
|
|
@@ -49,7 +49,7 @@ static errno_t sec_get(TALLOC_CTX *mem_ctx,
|
|
return ENOMEM;
|
|
}
|
|
|
|
- ret = sss_sec_get(tmp_ctx, req, &secret, NULL);
|
|
+ ret = sss_sec_get(tmp_ctx, req, (uint8_t **)&secret, NULL, NULL);
|
|
if (ret != EOK) {
|
|
DEBUG(SSSDBG_OP_FAILURE,
|
|
"Cannot retrieve the secret [%d]: %s\n", ret, sss_strerror(ret));
|
|
@@ -77,7 +77,7 @@ static errno_t sec_put(TALLOC_CTX *mem_ctx,
|
|
{
|
|
errno_t ret;
|
|
|
|
- ret = sss_sec_put(req, (const char *)sss_iobuf_get_data(buf),
|
|
+ ret = sss_sec_put(req, sss_iobuf_get_data(buf), sss_iobuf_get_size(buf),
|
|
SSS_SEC_PLAINTEXT, "simple");
|
|
if (ret != EOK) {
|
|
DEBUG(SSSDBG_OP_FAILURE,
|
|
@@ -93,7 +93,7 @@ static errno_t sec_update(TALLOC_CTX *mem_ctx,
|
|
{
|
|
errno_t ret;
|
|
|
|
- ret = sss_sec_update(req, (const char *)sss_iobuf_get_data(buf),
|
|
+ ret = sss_sec_update(req, sss_iobuf_get_data(buf), sss_iobuf_get_size(buf),
|
|
SSS_SEC_PLAINTEXT, "simple");
|
|
if (ret != EOK) {
|
|
DEBUG(SSSDBG_OP_FAILURE,
|
|
@@ -700,7 +700,7 @@ static struct tevent_req *ccdb_secdb_set_default_send(TALLOC_CTX *mem_ctx,
|
|
goto immediate;
|
|
}
|
|
|
|
- ret = sss_sec_get(state, sreq, &cur_default, NULL);
|
|
+ ret = sss_sec_get(state, sreq, (uint8_t**)&cur_default, NULL, NULL);
|
|
if (ret == ENOENT) {
|
|
ret = sec_put(state, sreq, iobuf);
|
|
} else if (ret == EOK) {
|
|
diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c
|
|
index fee52674d73f6f8071b4d66ac91bed3b210c8e23..252ef3a1de7ff28b0e9f37479c658a6c59e830f7 100644
|
|
--- a/src/responder/secrets/local.c
|
|
+++ b/src/responder/secrets/local.c
|
|
@@ -134,7 +134,7 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx,
|
|
break;
|
|
}
|
|
|
|
- ret = sss_sec_get(state, ssec_req, &secret, NULL);
|
|
+ ret = sss_sec_get(state, ssec_req, (uint8_t**)&secret, NULL, NULL);
|
|
if (ret) goto done;
|
|
|
|
if (body_is_json) {
|
|
@@ -168,7 +168,8 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx,
|
|
}
|
|
if (ret) goto done;
|
|
|
|
- ret = sss_sec_put(ssec_req, secret, SSS_SEC_MASTERKEY, "simple");
|
|
+ ret = sss_sec_put(ssec_req, (uint8_t *)secret, strlen(secret) + 1,
|
|
+ SSS_SEC_MASTERKEY, "simple");
|
|
if (ret) goto done;
|
|
break;
|
|
|
|
diff --git a/src/tests/intg/test_secrets.py b/src/tests/intg/test_secrets.py
|
|
index 00933fb346516898448d4285c5c5c9373c48a2a9..18d722c13f36c58423e5caf81881f9ec167faa1e 100644
|
|
--- a/src/tests/intg/test_secrets.py
|
|
+++ b/src/tests/intg/test_secrets.py
|
|
@@ -438,7 +438,8 @@ def run_quota_test(cli, max_secrets, max_payload_size):
|
|
KILOBYTE = 1024
|
|
kb_payload_size = max_payload_size * KILOBYTE
|
|
|
|
- sec_value = "x" * kb_payload_size
|
|
+ # Adjust payload size to hold terminal zero byte.
|
|
+ sec_value = "x" * (kb_payload_size - 1)
|
|
|
|
cli.set_secret("foo", sec_value)
|
|
|
|
diff --git a/src/util/secrets/sec_pvt.h b/src/util/secrets/sec_pvt.h
|
|
index 92e2b8b259fd7b20e974d5bd4dc41d96ea36ecf1..0e77a660e91ff9e18cce68a7994e3dbbf868c7aa 100644
|
|
--- a/src/util/secrets/sec_pvt.h
|
|
+++ b/src/util/secrets/sec_pvt.h
|
|
@@ -33,7 +33,7 @@
|
|
#define SSS_SEC_KCM_BASEPATH "/kcm/"
|
|
|
|
struct sss_sec_data {
|
|
- char *data;
|
|
+ uint8_t *data;
|
|
size_t length;
|
|
};
|
|
|
|
diff --git a/src/util/secrets/secrets.c b/src/util/secrets/secrets.c
|
|
index 51fc85fb09934c25290c625fe2a2d8090285117d..2a7149ae8b1c88623784ffd4f3e7f908be15c662 100644
|
|
--- a/src/util/secrets/secrets.c
|
|
+++ b/src/util/secrets/secrets.c
|
|
@@ -96,22 +96,28 @@ static enum sss_sec_enctype sss_sec_str_to_enctype(const char *str)
|
|
return SSS_SEC_ENCTYPE_SENTINEL;
|
|
}
|
|
|
|
-static int local_decrypt(struct sss_sec_ctx *sctx, TALLOC_CTX *mem_ctx,
|
|
- const char *secret, enum sss_sec_enctype enctype,
|
|
- char **plain_secret)
|
|
+static int local_decrypt(struct sss_sec_ctx *sctx,
|
|
+ TALLOC_CTX *mem_ctx,
|
|
+ uint8_t *secret,
|
|
+ size_t secret_len,
|
|
+ enum sss_sec_enctype enctype,
|
|
+ uint8_t **_output,
|
|
+ size_t *_output_len)
|
|
{
|
|
struct sss_sec_data _secret;
|
|
- size_t outlen;
|
|
- char *output;
|
|
+ uint8_t *output;
|
|
+ size_t output_len;
|
|
int ret;
|
|
|
|
switch (enctype) {
|
|
case SSS_SEC_PLAINTEXT:
|
|
- output = talloc_strdup(mem_ctx, secret);
|
|
+ output = talloc_memdup(mem_ctx, secret, secret_len);
|
|
+ output_len = secret_len;
|
|
break;
|
|
case SSS_SEC_MASTERKEY:
|
|
- _secret.data = (char *)sss_base64_decode(mem_ctx, secret,
|
|
- &_secret.length);
|
|
+ _secret.data = (uint8_t *)sss_base64_decode(mem_ctx,
|
|
+ (const char *)secret,
|
|
+ &_secret.length);
|
|
if (!_secret.data) {
|
|
DEBUG(SSSDBG_OP_FAILURE, "sss_base64_decode failed\n");
|
|
return EINVAL;
|
|
@@ -119,27 +125,20 @@ static int local_decrypt(struct sss_sec_ctx *sctx, TALLOC_CTX *mem_ctx,
|
|
|
|
DEBUG(SSSDBG_TRACE_INTERNAL, "Decrypting with masterkey\n");
|
|
ret = sss_decrypt(mem_ctx, AES256CBC_HMAC_SHA256,
|
|
- (uint8_t *)sctx->master_key.data,
|
|
+ sctx->master_key.data,
|
|
sctx->master_key.length,
|
|
- (uint8_t *)_secret.data, _secret.length,
|
|
- (uint8_t **)&output, &outlen);
|
|
+ _secret.data, _secret.length,
|
|
+ &output, &output_len);
|
|
talloc_free(_secret.data);
|
|
if (ret) {
|
|
DEBUG(SSSDBG_OP_FAILURE,
|
|
"sss_decrypt failed [%d]: %s\n", ret, sss_strerror(ret));
|
|
return ret;
|
|
}
|
|
-
|
|
- if (((strnlen(output, outlen) + 1) != outlen) ||
|
|
- output[outlen - 1] != '\0') {
|
|
- DEBUG(SSSDBG_CRIT_FAILURE,
|
|
- "Output length mismatch or output not NULL-terminated\n");
|
|
- talloc_free(output);
|
|
- return EIO;
|
|
- }
|
|
break;
|
|
case SSS_SEC_BASE64:
|
|
- output = (char *)sss_base64_decode(mem_ctx, secret, &_secret.length);
|
|
+ output = (uint8_t *)sss_base64_decode(mem_ctx, (const char *)secret,
|
|
+ &output_len);
|
|
break;
|
|
default:
|
|
DEBUG(SSSDBG_CRIT_FAILURE, "Unknown encryption type '%d'\n", enctype);
|
|
@@ -150,41 +149,52 @@ static int local_decrypt(struct sss_sec_ctx *sctx, TALLOC_CTX *mem_ctx,
|
|
return ENOMEM;
|
|
}
|
|
|
|
- *plain_secret = output;
|
|
+ *_output = output;
|
|
+ *_output_len = output_len;
|
|
+
|
|
return EOK;
|
|
}
|
|
|
|
-static int local_encrypt(struct sss_sec_ctx *sec_ctx, TALLOC_CTX *mem_ctx,
|
|
- const char *secret, enum sss_sec_enctype enctype,
|
|
- char **ciphertext)
|
|
+static int local_encrypt(struct sss_sec_ctx *sec_ctx,
|
|
+ TALLOC_CTX *mem_ctx,
|
|
+ uint8_t *secret,
|
|
+ size_t secret_len,
|
|
+ enum sss_sec_enctype enctype,
|
|
+ uint8_t **_output,
|
|
+ size_t *_output_len)
|
|
{
|
|
struct sss_sec_data _secret;
|
|
- char *output;
|
|
+ uint8_t *output;
|
|
+ size_t output_len;
|
|
+ char *b64;
|
|
int ret;
|
|
|
|
switch (enctype) {
|
|
case SSS_SEC_PLAINTEXT:
|
|
- output = talloc_strdup(mem_ctx, secret);
|
|
+ output = talloc_memdup(mem_ctx, secret, secret_len);
|
|
+ output_len = secret_len;
|
|
break;
|
|
case SSS_SEC_MASTERKEY:
|
|
ret = sss_encrypt(mem_ctx, AES256CBC_HMAC_SHA256,
|
|
- (uint8_t *)sec_ctx->master_key.data,
|
|
- sec_ctx->master_key.length,
|
|
- (const uint8_t *)secret, strlen(secret) + 1,
|
|
- (uint8_t **)&_secret.data, &_secret.length);
|
|
+ sec_ctx->master_key.data,
|
|
+ sec_ctx->master_key.length,
|
|
+ secret, secret_len,
|
|
+ &_secret.data, &_secret.length);
|
|
if (ret) {
|
|
DEBUG(SSSDBG_OP_FAILURE,
|
|
"sss_encrypt failed [%d]: %s\n", ret, sss_strerror(ret));
|
|
return ret;
|
|
}
|
|
|
|
- output = sss_base64_encode(mem_ctx, (uint8_t *)_secret.data,
|
|
- _secret.length);
|
|
+ b64 = sss_base64_encode(mem_ctx, _secret.data, _secret.length);
|
|
+ output = (uint8_t*)b64;
|
|
+ output_len = strlen(b64) + 1;
|
|
talloc_free(_secret.data);
|
|
break;
|
|
case SSS_SEC_BASE64:
|
|
- output = (char *)sss_base64_encode(mem_ctx, (const uint8_t *)secret,
|
|
- strlen(secret) + 1);
|
|
+ b64 = sss_base64_encode(mem_ctx, secret, secret_len);
|
|
+ output = (uint8_t*)b64;
|
|
+ output_len = strlen(b64) + 1;
|
|
break;
|
|
default:
|
|
DEBUG(SSSDBG_CRIT_FAILURE, "Unknown encryption type '%d'\n", enctype);
|
|
@@ -195,7 +205,9 @@ static int local_encrypt(struct sss_sec_ctx *sec_ctx, TALLOC_CTX *mem_ctx,
|
|
return ENOMEM;
|
|
}
|
|
|
|
- *ciphertext = output;
|
|
+ *_output = output;
|
|
+ *_output_len = output_len;
|
|
+
|
|
return EOK;
|
|
}
|
|
|
|
@@ -1000,18 +1012,20 @@ done:
|
|
|
|
errno_t sss_sec_get(TALLOC_CTX *mem_ctx,
|
|
struct sss_sec_req *req,
|
|
- char **_secret,
|
|
+ uint8_t **_secret,
|
|
+ size_t *_secret_len,
|
|
char **_datatype)
|
|
{
|
|
TALLOC_CTX *tmp_ctx;
|
|
static const char *attrs[] = { "secret", "enctype", "type", NULL };
|
|
struct ldb_result *res;
|
|
- const char *attr_secret;
|
|
+ const struct ldb_val *attr_secret;
|
|
const char *attr_enctype;
|
|
const char *attr_datatype;
|
|
enum sss_sec_enctype enctype;
|
|
char *datatype;
|
|
- char *secret;
|
|
+ uint8_t *secret;
|
|
+ size_t secret_len;
|
|
int ret;
|
|
|
|
if (req == NULL || _secret == NULL) {
|
|
@@ -1050,7 +1064,7 @@ errno_t sss_sec_get(TALLOC_CTX *mem_ctx,
|
|
goto done;
|
|
}
|
|
|
|
- attr_secret = ldb_msg_find_attr_as_string(res->msgs[0], "secret", NULL);
|
|
+ attr_secret = ldb_msg_find_ldb_val(res->msgs[0], "secret");
|
|
if (!attr_secret) {
|
|
DEBUG(SSSDBG_CRIT_FAILURE, "The 'secret' attribute is missing\n");
|
|
ret = ENOENT;
|
|
@@ -1061,14 +1075,12 @@ errno_t sss_sec_get(TALLOC_CTX *mem_ctx,
|
|
|
|
if (attr_enctype) {
|
|
enctype = sss_sec_str_to_enctype(attr_enctype);
|
|
- ret = local_decrypt(req->sctx, tmp_ctx, attr_secret, enctype, &secret);
|
|
+ ret = local_decrypt(req->sctx, tmp_ctx, attr_secret->data,
|
|
+ attr_secret->length, enctype, &secret, &secret_len);
|
|
if (ret) goto done;
|
|
} else {
|
|
- secret = talloc_strdup(tmp_ctx, attr_secret);
|
|
- if (secret == NULL) {
|
|
- ret = ENOMEM;
|
|
- goto done;
|
|
- }
|
|
+ secret = talloc_steal(tmp_ctx, attr_secret->data);
|
|
+ secret_len = attr_secret->length;
|
|
}
|
|
|
|
if (_datatype != NULL) {
|
|
@@ -1085,6 +1097,10 @@ errno_t sss_sec_get(TALLOC_CTX *mem_ctx,
|
|
|
|
*_secret = talloc_steal(mem_ctx, secret);
|
|
|
|
+ if (_secret_len) {
|
|
+ *_secret_len = secret_len;
|
|
+ }
|
|
+
|
|
ret = EOK;
|
|
|
|
done:
|
|
@@ -1093,12 +1109,13 @@ done:
|
|
}
|
|
|
|
errno_t sss_sec_put(struct sss_sec_req *req,
|
|
- const char *secret,
|
|
+ uint8_t *secret,
|
|
+ size_t secret_len,
|
|
enum sss_sec_enctype enctype,
|
|
const char *datatype)
|
|
{
|
|
struct ldb_message *msg;
|
|
- char *enc_secret;
|
|
+ struct ldb_val enc_secret;
|
|
int ret;
|
|
|
|
if (req == NULL || secret == NULL) {
|
|
@@ -1139,7 +1156,7 @@ errno_t sss_sec_put(struct sss_sec_req *req,
|
|
goto done;
|
|
}
|
|
|
|
- ret = local_check_max_payload_size(req, strlen(secret));
|
|
+ ret = local_check_max_payload_size(req, secret_len);
|
|
if (ret != EOK) {
|
|
DEBUG(SSSDBG_OP_FAILURE,
|
|
"local_check_max_payload_size failed [%d]: %s\n",
|
|
@@ -1147,7 +1164,8 @@ errno_t sss_sec_put(struct sss_sec_req *req,
|
|
goto done;
|
|
}
|
|
|
|
- ret = local_encrypt(req->sctx, msg, secret, enctype, &enc_secret);
|
|
+ ret = local_encrypt(req->sctx, msg, secret, secret_len, enctype,
|
|
+ &enc_secret.data, &enc_secret.length);
|
|
if (ret != EOK) {
|
|
DEBUG(SSSDBG_OP_FAILURE,
|
|
"local_encrypt failed [%d]: %s\n", ret, sss_strerror(ret));
|
|
@@ -1170,7 +1188,7 @@ errno_t sss_sec_put(struct sss_sec_req *req,
|
|
goto done;
|
|
}
|
|
|
|
- ret = ldb_msg_add_string(msg, "secret", enc_secret);
|
|
+ ret = ldb_msg_add_value(msg, "secret", &enc_secret, NULL);
|
|
if (ret != EOK) {
|
|
DEBUG(SSSDBG_OP_FAILURE,
|
|
"ldb_msg_add_string failed adding secret [%d]: %s\n",
|
|
@@ -1207,12 +1225,13 @@ done:
|
|
}
|
|
|
|
errno_t sss_sec_update(struct sss_sec_req *req,
|
|
- const char *secret,
|
|
+ uint8_t *secret,
|
|
+ size_t secret_len,
|
|
enum sss_sec_enctype enctype,
|
|
const char *datatype)
|
|
{
|
|
struct ldb_message *msg;
|
|
- char *enc_secret;
|
|
+ struct ldb_val enc_secret;
|
|
int ret;
|
|
|
|
if (req == NULL || secret == NULL) {
|
|
@@ -1253,7 +1272,7 @@ errno_t sss_sec_update(struct sss_sec_req *req,
|
|
goto done;
|
|
}
|
|
|
|
- ret = local_check_max_payload_size(req, strlen(secret));
|
|
+ ret = local_check_max_payload_size(req, secret_len);
|
|
if (ret != EOK) {
|
|
DEBUG(SSSDBG_OP_FAILURE,
|
|
"local_check_max_payload_size failed [%d]: %s\n",
|
|
@@ -1261,7 +1280,8 @@ errno_t sss_sec_update(struct sss_sec_req *req,
|
|
goto done;
|
|
}
|
|
|
|
- ret = local_encrypt(req->sctx, msg, secret, enctype, &enc_secret);
|
|
+ ret = local_encrypt(req->sctx, msg, secret, secret_len, enctype,
|
|
+ &enc_secret.data, &enc_secret.length);
|
|
if (ret != EOK) {
|
|
DEBUG(SSSDBG_OP_FAILURE,
|
|
"local_encrypt failed [%d]: %s\n", ret, sss_strerror(ret));
|
|
@@ -1309,7 +1329,7 @@ errno_t sss_sec_update(struct sss_sec_req *req,
|
|
goto done;
|
|
}
|
|
|
|
- ret = ldb_msg_add_string(msg, "secret", enc_secret);
|
|
+ ret = ldb_msg_add_value(msg, "secret", &enc_secret, NULL);
|
|
if (ret != LDB_SUCCESS) {
|
|
DEBUG(SSSDBG_MINOR_FAILURE,
|
|
"ldb_msg_add_string failed: [%s]\n", ldb_strerror(ret));
|
|
diff --git a/src/util/secrets/secrets.h b/src/util/secrets/secrets.h
|
|
index f73657629f1a0bb614ccd96728852da66cc18791..f8caa53eec376bb0c8d52615ce9111efbbb26393 100644
|
|
--- a/src/util/secrets/secrets.h
|
|
+++ b/src/util/secrets/secrets.h
|
|
@@ -95,16 +95,19 @@ errno_t sss_sec_list(TALLOC_CTX *mem_ctx,
|
|
|
|
errno_t sss_sec_get(TALLOC_CTX *mem_ctx,
|
|
struct sss_sec_req *req,
|
|
- char **_secret,
|
|
+ uint8_t **_secret,
|
|
+ size_t *_secret_len,
|
|
char **_datatype);
|
|
|
|
errno_t sss_sec_put(struct sss_sec_req *req,
|
|
- const char *secret,
|
|
+ uint8_t *secret,
|
|
+ size_t secret_len,
|
|
enum sss_sec_enctype enctype,
|
|
const char *datatype);
|
|
|
|
errno_t sss_sec_update(struct sss_sec_req *req,
|
|
- const char *secret,
|
|
+ uint8_t *secret,
|
|
+ size_t secret_len,
|
|
enum sss_sec_enctype enctype,
|
|
const char *datatype);
|
|
|
|
--
|
|
2.25.4
|
|
|