diff --git a/daemons/ipa-slapi-plugins/libotp/hotp.c b/daemons/ipa-slapi-plugins/libotp/hotp.c index 619bc63ab..0c9de96d3 100644 --- a/daemons/ipa-slapi-plugins/libotp/hotp.c +++ b/daemons/ipa-slapi-plugins/libotp/hotp.c @@ -46,6 +46,7 @@ #include #include +#include #include #include #include @@ -66,6 +67,49 @@ static const struct { { } }; +static PK11SymKey * +import_key(PK11SlotInfo *slot, CK_MECHANISM_TYPE mech, SECItem *key) +{ + uint8_t ct[(key->len / AES_BLOCK_SIZE + 1) * AES_BLOCK_SIZE]; + uint8_t iv[AES_BLOCK_SIZE] = {}; + SECItem ivitem = { .data = iv, .len = sizeof(iv), .type = siBuffer }; + SECItem ctitem = { .data = ct, .len = sizeof(ct), .type = siBuffer }; + PK11SymKey *ekey = NULL; + PK11SymKey *skey = NULL; + + /* Try to import the key directly. */ + skey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, + CKA_SIGN, key, NULL); + if (skey) + return skey; + + /* If we get here, we are probably in FIPS mode. Let's encrypt the key so + * that we can unseal it instead of loading it directly. */ + + /* Generate an ephemeral key. */ + ekey = PK11_TokenKeyGenWithFlags(slot, CKM_AES_CBC_PAD, NULL, + AES_128_KEY_LENGTH, NULL, + CKF_ENCRYPT | CKF_UNWRAP, + PK11_ATTR_SESSION | + PK11_ATTR_PRIVATE | + PK11_ATTR_SENSITIVE, NULL); + if (!ekey) + goto egress; + + /* Encrypt the input key. */ + if (PK11_Encrypt(ekey, CKM_AES_CBC_PAD, &ivitem, ctitem.data, &ctitem.len, + ctitem.len, key->data, key->len) != SECSuccess) + goto egress; + + /* Unwrap the input key. */ + skey = PK11_UnwrapSymKey(ekey, CKM_AES_CBC_PAD, &ivitem, + &ctitem, mech, CKA_SIGN, key->len); + +egress: + PK11_FreeSymKey(ekey); + return skey; +} + /* * This code is mostly cargo-cult taken from here: * http://www.mozilla.org/projects/security/pki/nss/tech-notes/tn5.html @@ -90,8 +134,7 @@ static bool hmac(SECItem *key, CK_MECHANISM_TYPE mech, const SECItem *in, } } - symkey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, - CKA_SIGN, key, NULL); + symkey = import_key(slot, mech, key); if (symkey == NULL) goto done;