summaryrefslogtreecommitdiffstats
path: root/src/util/crypto/nss/nss_util.c
diff options
context:
space:
mode:
authorSimo Sorce <simo@redhat.com>2016-05-09 17:34:49 +0200
committerJakub Hrozek <jhrozek@redhat.com>2016-06-29 21:46:52 +0200
commit625bb2ddf15e8f305a53afa44e87f2146fa930af (patch)
treee80c6bdcb073d4c597af6c8ef8202726145286ad /src/util/crypto/nss/nss_util.c
parent1dd679584241a0f9b29072c7eed1c5c5e4a577e4 (diff)
downloadsssd-625bb2ddf15e8f305a53afa44e87f2146fa930af.tar.gz
sssd-625bb2ddf15e8f305a53afa44e87f2146fa930af.tar.xz
sssd-625bb2ddf15e8f305a53afa44e87f2146fa930af.zip
Secrets: Add encryption at rest
Generates a master key file if it doesn't exist and encrypts secrets using the master key contained in the file. Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
Diffstat (limited to 'src/util/crypto/nss/nss_util.c')
-rw-r--r--src/util/crypto/nss/nss_util.c211
1 files changed, 209 insertions, 2 deletions
diff --git a/src/util/crypto/nss/nss_util.c b/src/util/crypto/nss/nss_util.c
index 55b81c9b1..46835057b 100644
--- a/src/util/crypto/nss/nss_util.c
+++ b/src/util/crypto/nss/nss_util.c
@@ -26,12 +26,11 @@
#include "config.h"
#include <prinit.h>
-#include <prerror.h>
#include <nss.h>
-#include <pk11func.h>
#include "util/util.h"
#include "util/crypto/nss/nss_util.h"
+#include "util/crypto/nss/nss_crypto.h"
static int nspr_nss_init_done = 0;
@@ -75,3 +74,211 @@ int nspr_nss_cleanup(void)
nspr_nss_init_done = 0;
return EOK;
}
+
+static int sss_nss_crypto_ctx_destructor(struct sss_nss_crypto_ctx *cctx)
+{
+ if (cctx->ectx) PK11_DestroyContext(cctx->ectx, PR_TRUE);
+ if (cctx->sparam) SECITEM_FreeItem(cctx->sparam, PR_TRUE);
+ if (cctx->slot) PK11_FreeSlot(cctx->slot);
+ if (cctx->keyobj) PK11_FreeSymKey(cctx->keyobj);
+
+ return EOK;
+}
+
+static int generate_random_key(TALLOC_CTX *mem_ctx,
+ PK11SlotInfo *slot,
+ struct crypto_mech_data *mech_props,
+ SECItem **_key)
+{
+ SECStatus sret;
+ SECItem *randkeydata;
+ SECItem *key = NULL;
+ PK11SymKey *randkey;
+ int ret;
+
+ randkey = PK11_KeyGen(slot, mech_props->cipher,
+ NULL, mech_props->keylen, NULL);
+ if (randkey == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failure to generate key (err %d)\n",
+ PR_GetError());
+ ret = EIO;
+ goto done;
+ }
+
+ sret = PK11_ExtractKeyValue(randkey);
+ if (sret != SECSuccess) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failure to extract key value (err %d)\n",
+ PR_GetError());
+ ret = EIO;
+ goto done;
+ }
+
+ randkeydata = PK11_GetKeyData(randkey);
+ if (randkeydata == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failure to get key data (err %d)\n",
+ PR_GetError());
+ ret = EIO;
+ goto done;
+ }
+
+ /* randkeydata is valid until randkey is. Copy with talloc to
+ * get a nice memory hierarchy symmetrical in encrypt
+ * and decrypt case */
+ key = talloc_zero(mem_ctx, SECItem);
+ if (!key) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ key->data = talloc_memdup(key, randkeydata->data, randkeydata->len);
+ if (!key->data) {
+ ret = ENOMEM;
+ goto done;
+ }
+ key->len = randkeydata->len;
+
+ *_key = key;
+ ret = EOK;
+done:
+ if (ret != EOK) talloc_zfree(key);
+ PK11_FreeSymKey(randkey);
+ return ret;
+}
+
+int nss_ctx_init(TALLOC_CTX *mem_ctx,
+ struct crypto_mech_data *mech_props,
+ uint8_t *key, int keylen,
+ uint8_t *iv, int ivlen,
+ struct sss_nss_crypto_ctx **_cctx)
+{
+ struct sss_nss_crypto_ctx *cctx;
+ int ret;
+
+ cctx = talloc_zero(mem_ctx, struct sss_nss_crypto_ctx);
+ if (!cctx) {
+ return ENOMEM;
+ }
+ talloc_set_destructor(cctx, sss_nss_crypto_ctx_destructor);
+
+ cctx->slot = PK11_GetBestSlot(mech_props->cipher, NULL);
+ if (cctx->slot == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to find security device (err %d)\n",
+ PR_GetError());
+ ret = EIO;
+ goto done;
+ }
+
+ if (keylen > 0) {
+ cctx->key = talloc(cctx, SECItem);
+ if (cctx->key == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to allocate Key buffer\n");
+ ret = ENOMEM;
+ goto done;
+ }
+ if (key) {
+ MAKE_SECITEM(key, keylen, cctx->key);
+ } else {
+ ret = generate_random_key(cctx, cctx->slot,
+ mech_props, &cctx->key);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Could not generate encryption key\n");
+ goto done;
+ }
+ }
+
+ }
+
+ if (ivlen > 0) {
+ cctx->iv = talloc(cctx, SECItem);
+ if (cctx->iv == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to allocate IV buffer\n");
+ ret = ENOMEM;
+ goto done;
+ }
+ if (iv) {
+ MAKE_SECITEM(iv, ivlen, cctx->iv);
+ } else {
+ ret = generate_random_key(cctx, cctx->slot,
+ mech_props, &cctx->iv);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Could not generate initialization vector\n");
+ goto done;
+ }
+ }
+ }
+
+ ret = EOK;
+ *_cctx = cctx;
+done:
+ if (ret) talloc_zfree(cctx);
+ return ret;
+}
+
+int nss_crypto_init(struct crypto_mech_data *mech_props,
+ enum crypto_mech_op crypto_op,
+ struct sss_nss_crypto_ctx *cctx)
+{
+ CK_ATTRIBUTE_TYPE op;
+ int ret;
+
+ switch (crypto_op) {
+ case op_encrypt:
+ op = CKA_ENCRYPT;
+ break;
+ case op_decrypt:
+ op = CKA_DECRYPT;
+ break;
+ case op_sign:
+ op = CKA_SIGN;
+ break;
+ default:
+ return EFAULT;
+ }
+
+ /* turn the raw key into a key object */
+ cctx->keyobj = PK11_ImportSymKey(cctx->slot, mech_props->cipher,
+ PK11_OriginUnwrap, op, cctx->key, NULL);
+ if (cctx->keyobj == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failure to import key into NSS (err %d)\n",
+ PR_GetError());
+ ret = EIO;
+ goto done;
+ }
+
+ if (crypto_op == op_encrypt || crypto_op == op_decrypt) {
+ /* turn the raw IV into a initialization vector object */
+ cctx->sparam = PK11_ParamFromIV(mech_props->cipher, cctx->iv);
+ if (cctx->sparam == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failure to set up PKCS11 param (err %d)\n",
+ PR_GetError());
+ ret = EIO;
+ goto done;
+ }
+ } else {
+ cctx->sparam = SECITEM_AllocItem(NULL, NULL, 0);
+ if (cctx->sparam == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failure to allocate SECItem\n");
+ ret = EIO;
+ goto done;
+ }
+ MAKE_SECITEM(NULL, 0, cctx->sparam);
+ }
+
+ /* Create cipher context */
+ cctx->ectx = PK11_CreateContextBySymKey(mech_props->cipher, op,
+ cctx->keyobj, cctx->sparam);
+ if (cctx->ectx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create cipher context (err %d)\n",
+ PORT_GetError());
+ ret = EIO;
+ goto done;
+ }
+
+ ret = EOK;
+done:
+ return ret;
+}