Whamcloud - gitweb
LU-9859 libcfs: don't call unshare_fs_struct()
[fs/lustre-release.git] / lustre / utils / gss / sk_utils.c
index a0d71ac..d3cf5ff 100644 (file)
@@ -22,7 +22,7 @@
 /*
  * Copyright (C) 2015, Trustees of Indiana University
  *
- * Copyright (c) 2016, Intel Corporation.
+ * Copyright (c) 2016, 2017, Intel Corporation.
  *
  * Author: Jeremy Filizetti <jfilizet@iu.edu>
  */
 #include <openssl/hmac.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <lnet/nidstr.h>
+#include <libcfs/util/string.h>
 
 #include "sk_utils.h"
 #include "write_bytes.h"
 
 #define SK_PBKDF2_ITERATIONS 10000
 
-static struct sk_crypt_type sk_crypt_types[] = {
-       [SK_CRYPT_AES256_CTR] = {
-               .cht_name = "ctr(aes)",
-               .cht_bytes = 32,
-       },
-};
-
-/*
-static struct sk_hmac_type sk_hmac_types[] = {
-       [SK_HMAC_SHA256] = {
-               .cht_name = "sha256",
-               .cht_bytes = 32,
-       },
-       [SK_HMAC_SHA512] = {
-               .cht_name = "sha512",
-               .cht_bytes = 64,
-       },
-};*/
-
 #ifdef _NEW_BUILD_
 # include "lgss_utils.h"
 #else
@@ -321,8 +302,6 @@ void sk_config_cpu_to_disk(struct sk_keyfile_config *config)
 
        for (i = 0; i < MAX_MGSNIDS; i++)
                config->skc_mgsnids[i] = htobe64(config->skc_mgsnids[i]);
-
-       return;
 }
 
 /**
@@ -346,8 +325,6 @@ void sk_config_disk_to_cpu(struct sk_keyfile_config *config)
 
        for (i = 0; i < MAX_MGSNIDS; i++)
                config->skc_mgsnids[i] = be64toh(config->skc_mgsnids[i]);
-
-       return;
 }
 
 /**
@@ -366,19 +343,22 @@ int sk_validate_config(const struct sk_keyfile_config *config)
                printerr(0, "Null configuration passed\n");
                return -1;
        }
+
        if (config->skc_version != SK_CONF_VERSION) {
                printerr(0, "Invalid version\n");
                return -1;
        }
-       if ((config->skc_hmac_alg != CFS_HASH_ALG_SHA256) &&
-           (config->skc_hmac_alg != CFS_HASH_ALG_SHA512)) {
+
+       if (config->skc_hmac_alg == SK_HMAC_INVALID) {
                printerr(0, "Invalid HMAC algorithm\n");
                return -1;
        }
-       if (config->skc_crypt_alg >= SK_CRYPT_MAX) {
+
+       if (config->skc_crypt_alg == SK_CRYPT_INVALID) {
                printerr(0, "Invalid crypt algorithm\n");
                return -1;
        }
+
        if (config->skc_expire < 60 || config->skc_expire > INT_MAX) {
                /* Try to limit key expiration to some reasonable minimum and
                 * also prevent values over INT_MAX because there appears
@@ -663,8 +643,8 @@ struct sk_cred *sk_create_cred(const char *tgt, const char *nodemap,
 
        kctx = &skc->sc_kctx;
        kctx->skc_version = config->skc_version;
-       kctx->skc_hmac_alg = config->skc_hmac_alg;
-       kctx->skc_crypt_alg = config->skc_crypt_alg;
+       strcpy(kctx->skc_hmac_alg, sk_hmac2name(config->skc_hmac_alg));
+       strcpy(kctx->skc_crypt_alg, sk_crypt2name(config->skc_crypt_alg));
        kctx->skc_expire = config->skc_expire;
 
        /* key payload format is in bits, convert to bytes */
@@ -708,6 +688,8 @@ out_err:
 uint32_t sk_gen_params(struct sk_cred *skc)
 {
        uint32_t random;
+       BIGNUM *p, *g;
+       const BIGNUM *pub_key;
        int rc;
 
        /* Random value used by both the request and response as part of the
@@ -733,23 +715,28 @@ uint32_t sk_gen_params(struct sk_cred *skc)
                return GSS_S_FAILURE;
        }
 
-       skc->sc_params->p = BN_bin2bn(skc->sc_p.value, skc->sc_p.length, NULL);
-       if (!skc->sc_params->p) {
+       p = BN_bin2bn(skc->sc_p.value, skc->sc_p.length, NULL);
+       if (!p) {
                printerr(0, "Failed to convert binary to BIGNUM\n");
                return GSS_S_FAILURE;
        }
 
        /* We use a static generator for shared key */
-       skc->sc_params->g = BN_new();
-       if (!skc->sc_params->g) {
+       g = BN_new();
+       if (!g) {
                printerr(0, "Failed to allocate new BIGNUM\n");
                return GSS_S_FAILURE;
        }
-       if (BN_set_word(skc->sc_params->g, SK_GENERATOR) != 1) {
+       if (BN_set_word(g, SK_GENERATOR) != 1) {
                printerr(0, "Failed to set g value for DH params\n");
                return GSS_S_FAILURE;
        }
 
+       if (!DH_set0_pqg(skc->sc_params, p, NULL, g)) {
+               printerr(0, "Failed to set pqg\n");
+               return GSS_S_FAILURE;
+       }
+
        /* Verify that we have a safe prime and valid generator */
        if (DH_check(skc->sc_params, &rc) != 1) {
                printerr(0, "DH_check() failed: %d\n", rc);
@@ -765,14 +752,15 @@ uint32_t sk_gen_params(struct sk_cred *skc)
                return GSS_S_FAILURE;
        }
 
-       skc->sc_pub_key.length = BN_num_bytes(skc->sc_params->pub_key);
+       DH_get0_key(skc->sc_params, &pub_key, NULL);
+       skc->sc_pub_key.length = BN_num_bytes(pub_key);
        skc->sc_pub_key.value = malloc(skc->sc_pub_key.length);
        if (!skc->sc_pub_key.value) {
                printerr(0, "Failed to allocate memory for public key\n");
                return GSS_S_FAILURE;
        }
 
-       BN_bn2bin(skc->sc_params->pub_key, skc->sc_pub_key.value);
+       BN_bn2bin(pub_key, skc->sc_pub_key.value);
 
        return GSS_S_COMPLETE;
 }
@@ -814,7 +802,7 @@ static inline const EVP_MD *sk_hash_to_evp_md(enum cfs_crypto_hash_alg alg)
 int sk_sign_bufs(gss_buffer_desc *key, gss_buffer_desc *bufs, const int numbufs,
                 const EVP_MD *hash_alg, gss_buffer_desc *hmac)
 {
-       HMAC_CTX hctx;
+       HMAC_CTX *hctx;
        unsigned int hashlen = EVP_MD_size(hash_alg);
        int i;
        int rc = -1;
@@ -824,7 +812,7 @@ int sk_sign_bufs(gss_buffer_desc *key, gss_buffer_desc *bufs, const int numbufs,
                return -1;
        }
 
-       HMAC_CTX_init(&hctx);
+       hctx = HMAC_CTX_new();
 
        hmac->length = hashlen;
        hmac->value = malloc(hashlen);
@@ -833,20 +821,20 @@ int sk_sign_bufs(gss_buffer_desc *key, gss_buffer_desc *bufs, const int numbufs,
                goto out;
        }
 
-       if (HMAC_Init_ex(&hctx, key->value, key->length, hash_alg, NULL) != 1) {
+       if (HMAC_Init_ex(hctx, key->value, key->length, hash_alg, NULL) != 1) {
                printerr(0, "Failed to init HMAC\n");
                goto out;
        }
 
        for (i = 0; i < numbufs; i++) {
-               if (HMAC_Update(&hctx, bufs[i].value, bufs[i].length) != 1) {
+               if (HMAC_Update(hctx, bufs[i].value, bufs[i].length) != 1) {
                        printerr(0, "Failed to update HMAC\n");
                        goto out;
                }
        }
 
        /* The result gets populated in hmac */
-       if (HMAC_Final(&hctx, hmac->value, &hashlen) != 1) {
+       if (HMAC_Final(hctx, hmac->value, &hashlen) != 1) {
                printerr(0, "Failed to finalize HMAC\n");
                goto out;
        }
@@ -858,7 +846,7 @@ int sk_sign_bufs(gss_buffer_desc *key, gss_buffer_desc *bufs, const int numbufs,
 
        rc = 0;
 out:
-       HMAC_CTX_cleanup(&hctx);
+       HMAC_CTX_free(hctx);
        return rc;
 }
 
@@ -1037,9 +1025,11 @@ int sk_session_kdf(struct sk_cred *skc, lnet_nid_t client_nid,
        struct sk_kernel_ctx *kctx = &skc->sc_kctx;
        gss_buffer_desc *session_key = &kctx->skc_session_key;
        gss_buffer_desc bufs[5];
+       enum cfs_crypto_crypt_alg crypt_alg;
        int rc = -1;
 
-       session_key->length = sk_crypt_types[kctx->skc_crypt_alg].cht_bytes;
+       crypt_alg = cfs_crypto_crypt_alg(kctx->skc_crypt_alg);
+       session_key->length = cfs_crypto_crypt_keysize(crypt_alg);
        session_key->value = malloc(session_key->length);
        if (!session_key->value) {
                printerr(0, "Failed to allocate memory for session key\n");
@@ -1061,7 +1051,7 @@ int sk_session_kdf(struct sk_cred *skc, lnet_nid_t client_nid,
        bufs[4] = *server_token;
 
        return sk_kdf(&kctx->skc_session_key, &kctx->skc_shared_key, bufs,
-                     5, kctx->skc_hmac_alg);
+                     5, cfs_crypto_hash_alg(kctx->skc_hmac_alg));
 }
 
 /* Uses the session key to create an HMAC key and encryption key.  In
@@ -1093,18 +1083,21 @@ int sk_compute_keys(struct sk_cred *skc)
        gss_buffer_desc *session_key = &kctx->skc_session_key;
        gss_buffer_desc *hmac_key = &kctx->skc_hmac_key;
        gss_buffer_desc *encrypt_key = &kctx->skc_encrypt_key;
+       enum cfs_crypto_hash_alg hmac_alg;
+       enum cfs_crypto_crypt_alg crypt_alg;
        char *encrypt = "Encrypt";
        char *integrity = "Integrity";
        int rc;
 
-       hmac_key->length = cfs_crypto_hash_digestsize(kctx->skc_hmac_alg);
+       hmac_alg = cfs_crypto_hash_alg(kctx->skc_hmac_alg);
+       hmac_key->length = cfs_crypto_hash_digestsize(hmac_alg);
        hmac_key->value = malloc(hmac_key->length);
        if (!hmac_key->value)
                return -ENOMEM;
 
        rc = PKCS5_PBKDF2_HMAC(integrity, -1, session_key->value,
                               session_key->length, SK_PBKDF2_ITERATIONS,
-                              sk_hash_to_evp_md(kctx->skc_hmac_alg),
+                              sk_hash_to_evp_md(hmac_alg),
                               hmac_key->length, hmac_key->value);
        if (rc == 0)
                return -EINVAL;
@@ -1113,14 +1106,15 @@ int sk_compute_keys(struct sk_cred *skc)
        if ((skc->sc_flags & LGSS_SVC_PRIV) == 0)
                return 0;
 
-       encrypt_key->length = cfs_crypto_hash_digestsize(kctx->skc_hmac_alg);
+       crypt_alg = cfs_crypto_crypt_alg(kctx->skc_crypt_alg);
+       encrypt_key->length = cfs_crypto_crypt_keysize(crypt_alg);
        encrypt_key->value = malloc(encrypt_key->length);
        if (!encrypt_key->value)
                return -ENOMEM;
 
        rc = PKCS5_PBKDF2_HMAC(encrypt, -1, session_key->value,
                               session_key->length, SK_PBKDF2_ITERATIONS,
-                              sk_hash_to_evp_md(kctx->skc_hmac_alg),
+                              sk_hash_to_evp_md(hmac_alg),
                               encrypt_key->length, encrypt_key->value);
        if (rc == 0)
                return -EINVAL;
@@ -1168,10 +1162,26 @@ uint32_t sk_compute_dh_key(struct sk_cred *skc, const gss_buffer_desc *pub_key)
                         ERR_error_string(ERR_get_error(), NULL));
                goto out_err;
        } else if (status < dh_shared->length) {
-               printerr(0, "DH_compute_key() returned a short key of %d "
-                        "bytes, expected: %zu\n", status, dh_shared->length);
-               rc = GSS_S_DEFECTIVE_TOKEN;
-               goto out_err;
+               /* there is around 1 chance out of 256 that the returned
+                * shared key is shorter than expected
+                */
+               if (status >= dh_shared->length - 2) {
+                       int shift = dh_shared->length - status;
+                       /* if the key is short by only 1 or 2 bytes, just
+                        * prepend it with 0s
+                        */
+                       memmove((void *)(dh_shared->value + shift),
+                               dh_shared->value, status);
+                       memset(dh_shared->value, 0, shift);
+               } else {
+                       /* if the key is really too short, return GSS_S_BAD_QOP
+                        * so that the caller can retry to generate
+                        */
+                       printerr(0, "DH_compute_key() returned a short key of %d bytes, expected: %zu\n",
+                                status, dh_shared->length);
+                       rc = GSS_S_BAD_QOP;
+                       goto out_err;
+               }
        }
 
        rc = GSS_S_COMPLETE;
@@ -1335,7 +1345,7 @@ int sk_encode_netstring(gss_buffer_desc *bufs, int numbufs,
        ptr = ns->value;
        for (i = 0; i < numbufs; i++) {
                /* size */
-               rc = snprintf((char *) ptr, size, "%zu:", bufs[i].length);
+               rc = scnprintf((char *) ptr, size, "%zu:", bufs[i].length);
                ptr += rc;
 
                /* contents */