diff options
Diffstat (limited to 'src/util/crypto/nss/nss_util.c')
-rw-r--r-- | src/util/crypto/nss/nss_util.c | 211 |
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; +} |