4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright (C) 2015, Trustees of Indiana University
25 * Author: Jeremy Filizetti <jfilizet@iu.edu>
34 #include <openssl/dh.h>
35 #include <openssl/engine.h>
36 #include <openssl/err.h>
37 #include <openssl/hmac.h>
38 #include <sys/types.h>
40 #include <lnet/nidstr.h>
43 #include "write_bytes.h"
45 #define SK_PBKDF2_ITERATIONS 10000
47 static struct sk_crypt_type sk_crypt_types[] = {
48 [SK_CRYPT_AES256_CTR] = {
49 .sct_name = "ctr(aes)",
54 static struct sk_hmac_type sk_hmac_types[] = {
56 .sht_name = "hmac(sha256)",
60 .sht_name = "hmac(sha512)",
66 # include "lgss_utils.h"
68 # include "gss_util.h"
69 # include "gss_oids.h"
70 # include "err_util.h"
76 * \param[in] program Program name to output
77 * \param[in] verbose Verbose flag
78 * \param[in] fg Whether or not to run in foreground
81 void sk_init_logging(char *program, int verbose, int fg)
83 initerr(program, verbose, fg);
88 * Loads the key from \a filename and returns the struct sk_keyfile_config.
89 * It should be freed by the caller.
91 * \param[in] filename Disk or key payload data
93 * \return sk_keyfile_config sucess
94 * \return NULL failure
96 struct sk_keyfile_config *sk_read_file(char *filename)
98 struct sk_keyfile_config *config;
104 config = malloc(sizeof(*config));
106 printerr(0, "Failed to allocate memory for config\n");
110 /* allow standard input override */
111 if (strcmp(filename, "-") == 0)
112 fd = dup(STDIN_FILENO);
114 fd = open(filename, O_RDONLY);
117 printerr(0, "Error opening file %s: %s\n", filename,
122 ptr = (char *)config;
123 remain = sizeof(*config);
125 rc = read(fd, ptr, remain);
129 printerr(0, "read() failed on %s: %s\n", filename,
132 } else if (rc == 0) {
133 printerr(0, "File %s does not have a complete key\n",
142 sk_config_disk_to_cpu(config);
153 * Checks if a key matching \a description is found in the keyring for
154 * logging purposes and then attempts to load \a payload of \a psize into a key
155 * with \a description.
157 * \param[in] payload Key payload
158 * \param[in] psize Payload size
159 * \param[in] description Description used for key in keyring
164 static key_serial_t sk_load_key(const struct sk_keyfile_config *skc,
165 const char *description)
167 struct sk_keyfile_config payload;
170 memcpy(&payload, skc, sizeof(*skc));
172 /* In the keyring use the disk layout so keyctl pipe can be used */
173 sk_config_cpu_to_disk(&payload);
175 /* Check to see if a key is already loaded matching description */
176 key = keyctl_search(KEY_SPEC_USER_KEYRING, "user", description, 0);
178 printerr(2, "Key %d found in session keyring, replacing\n",
181 key = add_key("user", description, &payload, sizeof(payload),
182 KEY_SPEC_USER_KEYRING);
184 printerr(2, "Added key %d with description %s\n", key,
187 printerr(0, "Failed to add key with %s\n", description);
193 * Reads the key from \a path, verifies it and loads into the session keyring
194 * using a description determined by the the \a type. Existing keys with the
195 * same description are replaced.
197 * \param[in] path Path to key file
198 * \param[in] type Type of key to load which determines the description
203 int sk_load_keyfile(char *path, int type)
205 struct sk_keyfile_config *config;
206 char description[SK_DESCRIPTION_SIZE + 1];
212 rc = stat(path, &buf);
214 printerr(0, "stat() failed for file %s: %s\n", path,
219 config = sk_read_file(path);
223 /* Similar to ssh, require adequate care of key files */
224 if (buf.st_mode & (S_IRGRP | S_IWGRP | S_IWOTH | S_IXOTH)) {
225 printerr(0, "Shared key files must be read/writeable only by "
230 if (sk_validate_config(config))
233 /* The server side can have multiple key files per file system so
234 * the nodemap name is appended to the key description to uniquely
236 if (type & SK_TYPE_MGS) {
237 /* Any key can be an MGS key as long as we are told to use it */
238 rc = snprintf(description, SK_DESCRIPTION_SIZE, "lustre:MGS:%s",
239 config->skc_nodemap);
240 if (rc >= SK_DESCRIPTION_SIZE)
242 if (sk_load_key(config, description) == -1)
245 if (type & SK_TYPE_SERVER) {
246 /* Server keys need to have the file system name in the key */
247 if (!config->skc_fsname) {
248 printerr(0, "Key configuration has no file system "
249 "attribute. Can't load as server type\n");
252 rc = snprintf(description, SK_DESCRIPTION_SIZE, "lustre:%s:%s",
253 config->skc_fsname, config->skc_nodemap);
254 if (rc >= SK_DESCRIPTION_SIZE)
256 if (sk_load_key(config, description) == -1)
259 if (type & SK_TYPE_CLIENT) {
260 /* Load client file system key */
261 if (config->skc_fsname) {
262 rc = snprintf(description, SK_DESCRIPTION_SIZE,
263 "lustre:%s", config->skc_fsname);
264 if (rc >= SK_DESCRIPTION_SIZE)
266 if (sk_load_key(config, description) == -1)
270 /* Load client MGC keys */
271 for (i = 0; i < MAX_MGSNIDS; i++) {
272 if (config->skc_mgsnids[i] == LNET_NID_ANY)
274 rc = snprintf(description, SK_DESCRIPTION_SIZE,
276 libcfs_nid2str(config->skc_mgsnids[i]));
277 if (rc >= SK_DESCRIPTION_SIZE)
279 if (sk_load_key(config, description) == -1)
292 * Byte swaps config from cpu format to disk
294 * \param[in,out] config sk_keyfile_config to swap
296 void sk_config_cpu_to_disk(struct sk_keyfile_config *config)
303 config->skc_version = htobe32(config->skc_version);
304 config->skc_hmac_alg = htobe16(config->skc_hmac_alg);
305 config->skc_crypt_alg = htobe16(config->skc_crypt_alg);
306 config->skc_expire = htobe32(config->skc_expire);
307 config->skc_shared_keylen = htobe32(config->skc_shared_keylen);
308 config->skc_session_keylen = htobe32(config->skc_session_keylen);
310 for (i = 0; i < MAX_MGSNIDS; i++)
311 config->skc_mgsnids[i] = htobe64(config->skc_mgsnids[i]);
317 * Byte swaps config from disk format to cpu
319 * \param[in,out] config sk_keyfile_config to swap
321 void sk_config_disk_to_cpu(struct sk_keyfile_config *config)
328 config->skc_version = be32toh(config->skc_version);
329 config->skc_hmac_alg = be16toh(config->skc_hmac_alg);
330 config->skc_crypt_alg = be16toh(config->skc_crypt_alg);
331 config->skc_expire = be32toh(config->skc_expire);
332 config->skc_shared_keylen = be32toh(config->skc_shared_keylen);
333 config->skc_session_keylen = be32toh(config->skc_session_keylen);
335 for (i = 0; i < MAX_MGSNIDS; i++)
336 config->skc_mgsnids[i] = be64toh(config->skc_mgsnids[i]);
342 * Verifies the on key payload format is valid
344 * \param[in] config sk_keyfile_config
349 int sk_validate_config(const struct sk_keyfile_config *config)
354 printerr(0, "Null configuration passed\n");
357 if (config->skc_version != SK_CONF_VERSION) {
358 printerr(0, "Invalid version\n");
361 if (config->skc_hmac_alg >= SK_HMAC_MAX) {
362 printerr(0, "Invalid HMAC algorithm\n");
365 if (config->skc_crypt_alg >= SK_CRYPT_MAX) {
366 printerr(0, "Invalid crypt algorithm\n");
369 if (config->skc_expire < 60 || config->skc_expire > INT_MAX) {
370 /* Try to limit key expiration to some reasonable minimum and
371 * also prevent values over INT_MAX because there appears
372 * to be a type conversion issue */
373 printerr(0, "Invalid expiration time should be between %d "
374 "and %d\n", 60, INT_MAX);
377 if (config->skc_session_keylen % 8 != 0 ||
378 config->skc_session_keylen > SK_SESSION_MAX_KEYLEN_BYTES * 8) {
379 printerr(0, "Invalid session key length must be a multiple of 8"
380 " and less then %d bits\n",
381 SK_SESSION_MAX_KEYLEN_BYTES * 8);
384 if (config->skc_shared_keylen % 8 != 0 ||
385 config->skc_shared_keylen > SK_MAX_KEYLEN_BYTES * 8){
386 printerr(0, "Invalid shared key max length must be a multiple "
387 "of 8 and less then %d bits\n",
388 SK_MAX_KEYLEN_BYTES * 8);
392 /* Check for terminating nulls on strings */
393 for (i = 0; i < sizeof(config->skc_fsname) &&
394 config->skc_fsname[i] != '\0'; i++)
396 if (i == sizeof(config->skc_fsname)) {
397 printerr(0, "File system name not null terminated\n");
401 for (i = 0; i < sizeof(config->skc_nodemap) &&
402 config->skc_nodemap[i] != '\0'; i++)
404 if (i == sizeof(config->skc_nodemap)) {
405 printerr(0, "Nodemap name not null terminated\n");
413 * Hashes \a string and places the hash in \a hash
416 * \param[in] string Null terminated string to hash
417 * \param[in] hash_alg OpenSSL EVP_MD to use for hash
418 * \param[in,out] hash gss_buffer_desc to hold the result
423 static int sk_hash_string(const char *string, const EVP_MD *hash_alg,
424 gss_buffer_desc *hash)
426 EVP_MD_CTX *ctx = EVP_MD_CTX_create();
427 size_t len = strlen(string);
428 unsigned int hashlen;
430 if (!hash->value || hash->length < EVP_MD_size(hash_alg))
432 if (!EVP_DigestInit_ex(ctx, hash_alg, NULL))
434 if (!EVP_DigestUpdate(ctx, string, len))
436 if (!EVP_DigestFinal_ex(ctx, hash->value, &hashlen))
439 EVP_MD_CTX_destroy(ctx);
440 hash->length = hashlen;
444 EVP_MD_CTX_destroy(ctx);
449 * Hashes \a string and verifies the resulting hash matches the value
452 * \param[in] string Null terminated string to hash
453 * \param[in] hash_alg OpenSSL EVP_MD to use for hash
454 * \param[in,out] current_hash gss_buffer_desc to compare to
456 * \return gss error failure
457 * \return GSS_S_COMPLETE success
459 uint32_t sk_verify_hash(const char *string, const EVP_MD *hash_alg,
460 const gss_buffer_desc *current_hash)
462 gss_buffer_desc hash;
463 unsigned char hashbuf[EVP_MAX_MD_SIZE];
465 hash.value = hashbuf;
466 hash.length = sizeof(hashbuf);
468 if (sk_hash_string(string, hash_alg, &hash))
469 return GSS_S_FAILURE;
470 if (current_hash->length != hash.length)
471 return GSS_S_DEFECTIVE_TOKEN;
472 if (memcmp(current_hash->value, hash.value, hash.length))
473 return GSS_S_BAD_SIG;
475 return GSS_S_COMPLETE;
478 static inline int sk_config_has_mgsnid(struct sk_keyfile_config *config,
484 nid = libcfs_str2nid(mgsnid);
485 if (nid == LNET_NID_ANY)
488 for (i = 0; i < MAX_MGSNIDS; i++)
489 if (config->skc_mgsnids[i] == nid)
495 * Create an sk_cred structure populated with initial configuration info and the
496 * key. \a tgt and \a nodemap are used in determining the expected key
497 * description so the key can be found by searching the keyring.
498 * This is done because there is no easy way to pass keys from the mount command
499 * all the way to the request_key call. In addition any keys can be dynamically
500 * added to the keyrings and still found. The keyring that needs to be used
501 * must be the session keyring.
503 * \param[in] tgt Target file system
504 * \param[in] nodemap Cluster name for the key. This correlates to
505 * the nodemap name and is used by the server side.
506 * For the client this will be NULL.
507 * \param[in] flags Flags for the credentials
509 * \return sk_cred Allocated struct sk_cred on success
510 * \return NULL failure
512 struct sk_cred *sk_create_cred(const char *tgt, const char *nodemap,
513 const uint32_t flags)
515 struct sk_keyfile_config *config;
516 struct sk_kernel_ctx *kctx;
517 struct sk_cred *skc = NULL;
518 char description[SK_DESCRIPTION_SIZE + 1];
519 char fsname[MTI_NAME_MAXLEN + 1];
520 const char *mgsnid = NULL;
527 printerr(2, "Creating credentials for target: %s with nodemap: %s\n",
530 memset(description, 0, sizeof(description));
531 memset(fsname, 0, sizeof(fsname));
533 /* extract the file system name from target */
534 ptr = index(tgt, '-');
538 /* This must be an MGC target */
539 if (strncmp(tgt, "MGC", 3) || len <= 3) {
540 printerr(0, "Invalid target name\n");
548 if (len > MTI_NAME_MAXLEN) {
549 printerr(0, "Invalid target name\n");
552 memcpy(fsname, tgt, len);
556 rc = snprintf(description, SK_DESCRIPTION_SIZE,
557 "lustre:MGS:%s", nodemap);
559 rc = snprintf(description, SK_DESCRIPTION_SIZE,
560 "lustre:%s:%s", fsname, nodemap);
562 rc = snprintf(description, SK_DESCRIPTION_SIZE, "lustre:%s",
566 if (rc >= SK_DESCRIPTION_SIZE) {
567 printerr(0, "Invalid key description\n");
571 /* It may be a good idea to move Lustre keys to the gss_keyring
572 * (lgssc) type so that they expire when Lustre modules are removed.
573 * Unfortunately it can't be done at mount time because the mount
574 * syscall could trigger the Lustre modules to load and until that
575 * point we don't have a lgssc key type.
577 * TODO: Query the community for a consensus here */
578 printerr(2, "Searching for key with description: %s\n", description);
579 sk_key = keyctl_search(KEY_SPEC_USER_KEYRING, "user",
582 printerr(1, "No key found for %s\n", description);
586 keylen = keyctl_read_alloc(sk_key, (void **)&config);
588 printerr(0, "keyctl_read() failed for key %ld: %s\n", sk_key,
591 } else if (keylen != sizeof(*config)) {
592 printerr(0, "Unexpected key size: %d returned for key %ld, "
593 "expected %zu bytes\n",
594 keylen, sk_key, sizeof(*config));
598 sk_config_disk_to_cpu(config);
600 if (sk_validate_config(config)) {
601 printerr(0, "Invalid key configuration for key: %ld\n", sk_key);
605 if (mgsnid && !sk_config_has_mgsnid(config, mgsnid)) {
606 printerr(0, "Target name does not match key's MGS NIDs\n");
610 if (!mgsnid && strcmp(fsname, config->skc_fsname)) {
611 printerr(0, "Target name does not match key's file system\n");
615 skc = malloc(sizeof(*skc));
617 printerr(0, "Failed to allocate memory for sk_cred\n");
621 /* this initializes all gss_buffer_desc to empty as well */
622 memset(skc, 0, sizeof(*skc));
624 skc->sc_flags = flags;
625 skc->sc_tgt.length = strlen(tgt) + 1;
626 skc->sc_tgt.value = malloc(skc->sc_tgt.length);
627 if (!skc->sc_tgt.value) {
628 printerr(0, "Failed to allocate memory for target\n");
631 memcpy(skc->sc_tgt.value, tgt, skc->sc_tgt.length);
633 skc->sc_nodemap_hash.length = EVP_MD_size(EVP_sha256());
634 skc->sc_nodemap_hash.value = malloc(skc->sc_nodemap_hash.length);
635 if (!skc->sc_nodemap_hash.value) {
636 printerr(0, "Failed to allocate memory for nodemap hash\n");
640 if (sk_hash_string(config->skc_nodemap, EVP_sha256(),
641 &skc->sc_nodemap_hash)) {
642 printerr(0, "Failed to generate hash for nodemap name\n");
646 kctx = &skc->sc_kctx;
647 kctx->skc_version = config->skc_version;
648 kctx->skc_hmac_alg = config->skc_hmac_alg;
649 kctx->skc_crypt_alg = config->skc_crypt_alg;
650 kctx->skc_expire = config->skc_expire;
652 /* key payload format is in bits, convert to bytes */
653 skc->sc_session_keylen = config->skc_session_keylen / 8;
654 kctx->skc_shared_key.length = config->skc_shared_keylen / 8;
655 kctx->skc_shared_key.value = malloc(kctx->skc_shared_key.length);
656 if (!kctx->skc_shared_key.value) {
657 printerr(0, "Failed to allocate memory for shared key\n");
660 memcpy(kctx->skc_shared_key.value, config->skc_shared_key,
661 kctx->skc_shared_key.length);
674 static void sk_free_parameters(struct sk_cred *skc)
677 DH_free(skc->sc_params);
679 free(skc->sc_p.value);
680 if (skc->sc_pub_key.value)
681 free(skc->sc_pub_key.value);
683 skc->sc_params = NULL;
684 skc->sc_p.value = NULL;
685 skc->sc_p.length = 0;
686 skc->sc_pub_key.value = NULL;
687 skc->sc_pub_key.length = 0;
691 * Generates a public key and computes the private key for the DH key exchange.
692 * The parameters must be populated with the p and g from the peer.
694 * \param[in,out] skc Shared key credentials structure to populate
697 * \retval GSS_S_COMPLETE success
698 * \retval GSS_S_FAILURE failure
700 static uint32_t sk_gen_responder_params(struct sk_cred *skc)
704 /* No keys to generate without privacy mode */
705 if ((skc->sc_flags & LGSS_SVC_PRIV) == 0)
706 return GSS_S_COMPLETE;
708 skc->sc_params = DH_new();
709 if (!skc->sc_params) {
710 printerr(0, "Failed to allocate DH\n");
711 return GSS_S_FAILURE;
714 /* responder should already have sc_p populated */
715 skc->sc_params->p = BN_bin2bn(skc->sc_p.value, skc->sc_p.length, NULL);
716 if (!skc->sc_params->p) {
717 printerr(0, "Failed to convert binary to BIGNUM\n");
718 return GSS_S_FAILURE;
721 /* and we use a static generator for shared key */
722 skc->sc_params->g = BN_new();
723 if (!skc->sc_params->g) {
724 printerr(0, "Failed to allocate new BIGNUM\n");
725 return GSS_S_FAILURE;
727 if (BN_set_word(skc->sc_params->g, SK_GENERATOR) != 1) {
728 printerr(0, "Failed to set g value for DH params\n");
729 return GSS_S_FAILURE;
732 /* verify that we have a safe prime and valid generator */
733 if (DH_check(skc->sc_params, &rc) != 1) {
734 printerr(0, "DH_check() failed: %d\n", rc);
735 return GSS_S_FAILURE;
737 printerr(0, "DH_check() returned error codes: 0x%x\n", rc);
738 return GSS_S_FAILURE;
741 if (DH_generate_key(skc->sc_params) != 1) {
742 printerr(0, "Failed to generate public DH key: %s\n",
743 ERR_error_string(ERR_get_error(), NULL));
744 return GSS_S_FAILURE;
747 skc->sc_pub_key.length = BN_num_bytes(skc->sc_params->pub_key);
748 skc->sc_pub_key.value = malloc(skc->sc_pub_key.length);
749 if (!skc->sc_pub_key.value) {
750 printerr(0, "Failed to allocate memory for public key\n");
751 return GSS_S_FAILURE;
754 BN_bn2bin(skc->sc_params->pub_key, skc->sc_pub_key.value);
756 return GSS_S_COMPLETE;
760 * Generates shared key Diffie Hellman parameters used for the DH key exchange
761 * between host and peer if privacy mode is enabled
763 * \param[in,out] skc Shared key credentials structure to populate
766 * \retval GSS_S_COMPLETE success
767 * \retval GSS_S_FAILURE failure
769 static uint32_t sk_gen_initiator_params(struct sk_cred *skc)
773 /* The credential could be used so free existing parameters */
774 sk_free_parameters(skc);
776 /* Only privacy mode needs the rest of the parameter generation
777 * but we use IV in other modes as well so tokens should be
779 if ((skc->sc_flags & LGSS_SVC_PRIV) == 0)
780 return GSS_S_COMPLETE;
782 skc->sc_params = DH_generate_parameters(skc->sc_session_keylen * 8,
783 SK_GENERATOR, NULL, NULL);
784 if (skc->sc_params == NULL) {
785 printerr(0, "Failed to generate diffie-hellman parameters: %s",
786 ERR_error_string(ERR_get_error(), NULL));
787 return GSS_S_FAILURE;
790 if (DH_check(skc->sc_params, &rc) != 1) {
791 printerr(0, "DH_check() failed: %d\n", rc);
792 return GSS_S_FAILURE;
794 printerr(0, "DH_check() returned error codes: 0x%x\n", rc);
795 return GSS_S_FAILURE;
798 if (DH_generate_key(skc->sc_params) != 1) {
799 printerr(0, "Failed to generate public DH key: %s\n",
800 ERR_error_string(ERR_get_error(), NULL));
801 return GSS_S_FAILURE;
804 skc->sc_p.length = BN_num_bytes(skc->sc_params->p);
805 skc->sc_pub_key.length = BN_num_bytes(skc->sc_params->pub_key);
806 skc->sc_p.value = malloc(skc->sc_p.length);
807 skc->sc_pub_key.value = malloc(skc->sc_pub_key.length);
808 if (!skc->sc_p.value || !skc->sc_pub_key.value) {
809 printerr(0, "Failed to allocate memory for params\n");
810 return GSS_S_FAILURE;
813 BN_bn2bin(skc->sc_params->pub_key, skc->sc_pub_key.value);
814 BN_bn2bin(skc->sc_params->p, skc->sc_p.value);
816 return GSS_S_COMPLETE;
820 * Generates or populates the DH parameters depending on whether the system is
821 * the initiator or responder for the connection
823 * \param[in,out] skc Shared key credentials structure to
824 * populate with DH parameters
825 * \param[in] initiator Boolean whether to initiate parameters
827 * \retval GSS_S_COMPLETE success
828 * \retval GSS_S_FAILURE failure
830 uint32_t sk_gen_params(struct sk_cred *skc, const bool initiator)
834 /* Random value used by both the request and response as part of the
835 * key binding material. This also should ensure we have unqiue
836 * tokens that are sent to the remote server which is important because
837 * the token is hashed for the sunrpc cache lookups and a failure there
838 * would cause connection attempts to fail indefinitely due to the large
839 * timeout value on the server side */
840 if (RAND_bytes((unsigned char *)&random, sizeof(random)) != 1) {
841 printerr(0, "Failed to get data for random parameter\n");
842 return GSS_S_FAILURE;
845 /* The random value will always be used in byte range operations
846 * so we keep it as big endian from this point on */
847 skc->sc_kctx.skc_host_random = htobe32(random);
850 return sk_gen_initiator_params(skc);
852 return sk_gen_responder_params(skc);
856 * Convert SK hash algorithm into openssl message digest
858 * \param[in,out] alg SK hash algorithm
862 static inline const EVP_MD *sk_hash_to_evp_md(enum sk_hmac_alg alg)
870 return EVP_md_null();
875 * Signs (via HMAC) the parameters used only in the key initialization protocol.
877 * \param[in] key Key to use for HMAC
878 * \param[in] bufs Array of gss_buffer_desc to generate
880 * \param[in] numbufs Number of buffers in array
881 * \param[in] hash_alg OpenSSL EVP_MD to use for hash
882 * \param[in,out] hmac HMAC of buffers is allocated and placed
883 * in this gss_buffer_desc. Caller must
889 int sk_sign_bufs(gss_buffer_desc *key, gss_buffer_desc *bufs, const int numbufs,
890 const EVP_MD *hash_alg, gss_buffer_desc *hmac)
893 unsigned int hashlen = EVP_MD_size(hash_alg);
897 if (hash_alg == EVP_md_null()) {
898 printerr(0, "Invalid hash algorithm\n");
902 HMAC_CTX_init(&hctx);
904 hmac->length = hashlen;
905 hmac->value = malloc(hashlen);
907 printerr(0, "Failed to allocate memory for HMAC\n");
911 if (HMAC_Init_ex(&hctx, key->value, key->length, hash_alg, NULL) != 1) {
912 printerr(0, "Failed to init HMAC\n");
916 for (i = 0; i < numbufs; i++) {
917 if (HMAC_Update(&hctx, bufs[i].value, bufs[i].length) != 1) {
918 printerr(0, "Failed to update HMAC\n");
923 /* The result gets populated in hmac */
924 if (HMAC_Final(&hctx, hmac->value, &hashlen) != 1) {
925 printerr(0, "Failed to finalize HMAC\n");
929 if (hmac->length != hashlen) {
930 printerr(0, "HMAC size does not match expected\n");
936 HMAC_CTX_cleanup(&hctx);
941 * Generates an HMAC for gss_buffer_desc array in \a bufs of \a numbufs
942 * and verifies against \a hmac.
944 * \param[in] skc Shared key credentials
945 * \param[in] bufs Array of gss_buffer_desc to generate HMAC for
946 * \param[in] numbufs Number of buffers in array
947 * \param[in] hash_alg OpenSSL EVP_MD to use for hash
948 * \param[in] hmac HMAC to verify against
950 * \retval GSS_S_COMPLETE success (match)
951 * \retval gss error failure
953 uint32_t sk_verify_hmac(struct sk_cred *skc, gss_buffer_desc *bufs,
954 const int numbufs, const EVP_MD *hash_alg,
955 gss_buffer_desc *hmac)
957 gss_buffer_desc bufs_hmac;
960 if (sk_sign_bufs(&skc->sc_kctx.skc_shared_key, bufs, numbufs, hash_alg,
962 printerr(0, "Failed to sign buffers to verify HMAC\n");
964 free(bufs_hmac.value);
965 return GSS_S_FAILURE;
968 if (hmac->length != bufs_hmac.length) {
969 printerr(0, "Invalid HMAC size\n");
970 free(bufs_hmac.value);
971 return GSS_S_BAD_SIG;
974 rc = memcmp(hmac->value, bufs_hmac.value, bufs_hmac.length);
975 free(bufs_hmac.value);
978 return GSS_S_BAD_SIG;
980 return GSS_S_COMPLETE;
984 * Cleanup an sk_cred freeing any resources
986 * \param[in,out] skc Shared key credentials to free
988 void sk_free_cred(struct sk_cred *skc)
994 free(skc->sc_p.value);
995 if (skc->sc_pub_key.value)
996 free(skc->sc_pub_key.value);
997 if (skc->sc_tgt.value)
998 free(skc->sc_tgt.value);
999 if (skc->sc_nodemap_hash.value)
1000 free(skc->sc_nodemap_hash.value);
1001 if (skc->sc_hmac.value)
1002 free(skc->sc_hmac.value);
1004 /* Overwrite keys and IV before freeing */
1005 if (skc->sc_dh_shared_key.value) {
1006 memset(skc->sc_dh_shared_key.value, 0,
1007 skc->sc_dh_shared_key.length);
1008 free(skc->sc_dh_shared_key.value);
1010 if (skc->sc_kctx.skc_hmac_key.value) {
1011 memset(skc->sc_kctx.skc_hmac_key.value, 0,
1012 skc->sc_kctx.skc_hmac_key.length);
1013 free(skc->sc_kctx.skc_hmac_key.value);
1015 if (skc->sc_kctx.skc_encrypt_key.value) {
1016 memset(skc->sc_kctx.skc_encrypt_key.value, 0,
1017 skc->sc_kctx.skc_encrypt_key.length);
1018 free(skc->sc_kctx.skc_encrypt_key.value);
1020 if (skc->sc_kctx.skc_shared_key.value) {
1021 memset(skc->sc_kctx.skc_shared_key.value, 0,
1022 skc->sc_kctx.skc_shared_key.length);
1023 free(skc->sc_kctx.skc_shared_key.value);
1025 if (skc->sc_kctx.skc_session_key.value) {
1026 memset(skc->sc_kctx.skc_session_key.value, 0,
1027 skc->sc_kctx.skc_session_key.length);
1028 free(skc->sc_kctx.skc_session_key.value);
1032 DH_free(skc->sc_params);
1038 /* This function handles key derivation using the hash algorithm specified in
1039 * \a hash_alg, buffers in \a key_binding_bufs, and original key in
1040 * \a origin_key to produce a \a derived_key. The first element of the
1041 * key_binding_bufs array is reserved for the counter used in the KDF. The
1042 * derived key in \a derived_key could differ in size from \a origin_key and
1043 * must be populated with the expected size and a valid buffer to hold the
1046 * If the derived key size is greater than the HMAC algorithm size it will be
1047 * a done using several iterations of a counter and the key binding bufs.
1049 * If the size is smaller it will take copy the first N bytes necessary to
1050 * fill the derived key. */
1051 int sk_kdf(gss_buffer_desc *derived_key , gss_buffer_desc *origin_key,
1052 gss_buffer_desc *key_binding_bufs, int numbufs, int hmac_alg)
1058 gss_buffer_desc tmp_hash;
1065 /* Use a counter as the first buffer followed by the key binding
1066 * buffers in the event we need more than one a single cycle to
1067 * produced a symmetric key large enough in size */
1068 key_binding_bufs[0].value = &counter;
1069 key_binding_bufs[0].length = sizeof(counter);
1071 remain = derived_key->length;
1072 keydata = derived_key->value;
1074 while (remain > 0) {
1075 counter = htobe32(i++);
1076 rc = sk_sign_bufs(origin_key, key_binding_bufs, numbufs,
1077 sk_hash_to_evp_md(hmac_alg), &tmp_hash);
1080 free(tmp_hash.value);
1084 LASSERT(sk_hmac_types[hmac_alg].sht_bytes ==
1087 bytes = (remain < tmp_hash.length) ? remain : tmp_hash.length;
1088 memcpy(keydata, tmp_hash.value, bytes);
1089 free(tmp_hash.value);
1097 /* Populates the sk_cred's session_key using the a Key Derviation Function (KDF)
1098 * based on the recommendations in NIST Special Publication SP 800-56B Rev 1
1099 * (Sep 2014) Section 5.5.1
1101 * \param[in,out] skc Shared key credentials structure with
1103 * \return -1 failure
1106 int sk_session_kdf(struct sk_cred *skc, lnet_nid_t client_nid,
1107 gss_buffer_desc *client_token, gss_buffer_desc *server_token)
1109 struct sk_kernel_ctx *kctx = &skc->sc_kctx;
1110 gss_buffer_desc *session_key = &kctx->skc_session_key;
1111 gss_buffer_desc bufs[5];
1114 session_key->length = sk_crypt_types[kctx->skc_crypt_alg].sct_bytes;
1115 session_key->value = malloc(session_key->length);
1116 if (!session_key->value) {
1117 printerr(0, "Failed to allocate memory for session key\n");
1121 /* Key binding info ordering
1122 * 1. Reserved for counter
1126 * 4. Server's token */
1127 bufs[0].value = NULL;
1129 bufs[1] = skc->sc_dh_shared_key;
1130 bufs[2].value = &client_nid;
1131 bufs[2].length = sizeof(client_nid);
1132 bufs[3] = *client_token;
1133 bufs[4] = *server_token;
1135 return sk_kdf(&kctx->skc_session_key, &kctx->skc_shared_key, bufs,
1136 5, kctx->skc_hmac_alg);
1139 /* Uses the session key to create an HMAC key and encryption key. In
1140 * integrity mode the session key used to generate the HMAC key uses
1141 * session information which is available on the wire but by creating
1142 * a session based HMAC key we can prevent potential replay as both the
1143 * client and server have random numbers used as part of the key creation.
1145 * The keys used for integrity and privacy are formulated as below using
1146 * the session key that is the output of the key derivation function. The
1147 * HMAC algorithm is determined by the shared key algorithm selected in the
1151 * Session HMAC Key = PBKDF2("Integrity", KDF derived Session Key)
1154 * Session HMAC Key = PBKDF2("Integrity", KDF derived Session Key)
1155 * Session Encryption Key = PBKDF2("Encrypt", KDF derived Session Key)
1157 * \param[in,out] skc Shared key credentials structure with
1159 * \return -1 failure
1162 int sk_compute_keys(struct sk_cred *skc)
1164 struct sk_kernel_ctx *kctx = &skc->sc_kctx;
1165 gss_buffer_desc *session_key = &kctx->skc_session_key;
1166 gss_buffer_desc *hmac_key = &kctx->skc_hmac_key;
1167 gss_buffer_desc *encrypt_key = &kctx->skc_encrypt_key;
1168 char *encrypt = "Encrypt";
1169 char *integrity = "Integrity";
1172 hmac_key->length = sk_hmac_types[kctx->skc_hmac_alg].sht_bytes;
1173 hmac_key->value = malloc(hmac_key->length);
1174 if (!hmac_key->value)
1177 rc = PKCS5_PBKDF2_HMAC(integrity, -1, session_key->value,
1178 session_key->length, SK_PBKDF2_ITERATIONS,
1179 sk_hash_to_evp_md(kctx->skc_hmac_alg),
1180 hmac_key->length, hmac_key->value);
1184 /* Encryption key is only populated in privacy mode */
1185 if ((skc->sc_flags & LGSS_SVC_PRIV) == 0)
1188 encrypt_key->length = sk_crypt_types[kctx->skc_crypt_alg].sct_bytes;
1189 encrypt_key->value = malloc(encrypt_key->length);
1190 if (!encrypt_key->value)
1193 rc = PKCS5_PBKDF2_HMAC(encrypt, -1, session_key->value,
1194 session_key->length, SK_PBKDF2_ITERATIONS,
1195 sk_hash_to_evp_md(kctx->skc_hmac_alg),
1196 encrypt_key->length, encrypt_key->value);
1204 * Computes a session key based on the DH parameters from the host and its peer
1206 * \param[in,out] skc Shared key credentials structure with
1207 * the session key populated with the
1209 * \param[in] pub_key Public key returned from peer in
1211 * \return gss error failure
1212 * \return GSS_S_COMPLETE success
1214 uint32_t sk_compute_dh_key(struct sk_cred *skc, const gss_buffer_desc *pub_key)
1216 gss_buffer_desc *dh_shared = &skc->sc_dh_shared_key;
1217 BIGNUM *remote_pub_key;
1219 uint32_t rc = GSS_S_FAILURE;
1221 /* No keys computed unless privacy mode is in use */
1222 if ((skc->sc_flags & LGSS_SVC_PRIV) == 0)
1223 return GSS_S_COMPLETE;
1225 remote_pub_key = BN_bin2bn(pub_key->value, pub_key->length, NULL);
1226 if (!remote_pub_key) {
1227 printerr(0, "Failed to convert binary to BIGNUM\n");
1231 dh_shared->length = DH_size(skc->sc_params);
1232 dh_shared->value = malloc(dh_shared->length);
1233 if (!dh_shared->value) {
1234 printerr(0, "Failed to allocate memory for computed shared "
1239 /* This compute the shared key from the DHKE */
1240 status = DH_compute_key(dh_shared->value, remote_pub_key,
1243 printerr(0, "DH_compute_key() failed: %s\n",
1244 ERR_error_string(ERR_get_error(), NULL));
1246 } else if (status < dh_shared->length) {
1247 printerr(0, "DH_compute_key() returned a short key of %d "
1248 "bytes, expected: %zu\n", status, dh_shared->length);
1249 rc = GSS_S_DEFECTIVE_TOKEN;
1253 rc = GSS_S_COMPLETE;
1256 BN_free(remote_pub_key);
1261 * Creates a serialized buffer for the kernel in the order of struct
1264 * \param[in,out] skc Shared key credentials structure
1265 * \param[in,out] ctx_token Serialized buffer for kernel.
1266 * Caller must free this buffer.
1269 * \return -1 failure
1271 int sk_serialize_kctx(struct sk_cred *skc, gss_buffer_desc *ctx_token)
1273 struct sk_kernel_ctx *kctx = &skc->sc_kctx;
1277 bufsize = sizeof(*kctx) + kctx->skc_hmac_key.length +
1278 kctx->skc_encrypt_key.length;
1280 ctx_token->value = malloc(bufsize);
1281 if (!ctx_token->value)
1283 ctx_token->length = bufsize;
1285 p = ctx_token->value;
1286 end = p + ctx_token->length;
1288 if (WRITE_BYTES(&p, end, kctx->skc_version))
1290 if (WRITE_BYTES(&p, end, kctx->skc_hmac_alg))
1292 if (WRITE_BYTES(&p, end, kctx->skc_crypt_alg))
1294 if (WRITE_BYTES(&p, end, kctx->skc_expire))
1296 if (WRITE_BYTES(&p, end, kctx->skc_host_random))
1298 if (WRITE_BYTES(&p, end, kctx->skc_peer_random))
1300 if (write_buffer(&p, end, &kctx->skc_hmac_key))
1302 if (write_buffer(&p, end, &kctx->skc_encrypt_key))
1305 printerr(2, "Serialized buffer of %zu bytes for kernel\n", bufsize);
1311 * Decodes a netstring \a ns into array of gss_buffer_descs at \a bufs
1312 * up to \a numbufs. Memory is allocated for each value and length
1313 * will be populated with the length
1315 * \param[in,out] bufs Array of gss_buffer_descs
1316 * \param[in,out] numbufs number of gss_buffer_desc in array
1317 * \param[in] ns netstring to decode
1319 * \return buffers populated success
1320 * \return -1 failure
1322 int sk_decode_netstring(gss_buffer_desc *bufs, int numbufs, gss_buffer_desc *ns)
1324 char *ptr = ns->value;
1325 size_t remain = ns->length;
1332 for (i = 0; i < numbufs; i++) {
1333 /* read the size of first buffer */
1334 rc = sscanf(ptr, "%9u", &size);
1337 digits = (size) ? ceil(log10(size + 1)) : 1;
1339 /* sep of current string */
1340 sep = size + digits + 2;
1342 /* check to make sure it's valid */
1343 if (remain < sep || ptr[digits] != ':' ||
1344 ptr[sep - 1] != ',')
1347 bufs[i].length = size;
1349 bufs[i].value = NULL;
1351 bufs[i].value = malloc(size);
1354 memcpy(bufs[i].value, &ptr[digits + 1], size);
1361 printerr(2, "Decoded netstring of %zu bytes\n", ns->length);
1367 free(bufs[i].value);
1374 * Creates a netstring in a gss_buffer_desc that consists of all
1375 * the gss_buffer_desc found in \a bufs. The netstring should be treated
1376 * as binary as it can contain null characters.
1378 * \param[in] bufs Array of gss_buffer_desc to use as input
1379 * \param[in] numbufs Number of buffers in array
1380 * \param[in,out] ns Destination gss_buffer_desc to hold
1383 * \return -1 failure
1386 int sk_encode_netstring(gss_buffer_desc *bufs, int numbufs,
1387 gss_buffer_desc *ns)
1394 /* size of string in decimal, string size, colon, and comma */
1395 for (i = 0; i < numbufs; i++) {
1397 if (bufs[i].length == 0)
1400 size += ceil(log10(bufs[i].length + 1)) +
1405 ns->value = malloc(ns->length);
1412 for (i = 0; i < numbufs; i++) {
1414 rc = snprintf((char *) ptr, size, "%zu:", bufs[i].length);
1418 memcpy(ptr, bufs[i].value, bufs[i].length);
1419 ptr += bufs[i].length;
1424 size -= bufs[i].length + rc + 1;
1426 /* should not happen */
1431 printerr(2, "Encoded netstring of %zu bytes\n", ns->length);