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 * Copyright (c) 2016, 2017, Intel Corporation.
27 * Author: Jeremy Filizetti <jfilizet@iu.edu>
36 #include <openssl/dh.h>
37 #include <openssl/engine.h>
38 #include <openssl/err.h>
39 #include <openssl/hmac.h>
40 #ifdef HAVE_OPENSSL_EVP_PKEY
41 #include <openssl/param_build.h>
43 #include <sys/types.h>
45 #include <libcfs/util/string.h>
50 #include "write_bytes.h"
52 #define SK_PBKDF2_ITERATIONS 10000
55 # include "lgss_utils.h"
57 # include "gss_util.h"
58 # include "gss_oids.h"
59 # include "err_util.h"
65 * \param[in] program Program name to output
66 * \param[in] verbose Verbose flag
67 * \param[in] fg Whether or not to run in foreground
70 void sk_init_logging(char *program, int verbose, int fg)
72 initerr(program, verbose, fg);
77 * Loads the key from \a filename and returns the struct sk_keyfile_config.
78 * It should be freed by the caller.
80 * \param[in] filename Disk or key payload data
82 * \return sk_keyfile_config sucess
83 * \return NULL failure
85 struct sk_keyfile_config *sk_read_file(char *filename)
87 struct sk_keyfile_config *config;
93 config = malloc(sizeof(*config));
95 printerr(0, "Failed to allocate memory for config\n");
99 /* allow standard input override */
100 if (strcmp(filename, "-") == 0)
103 fd = open(filename, O_RDONLY);
106 printerr(0, "Error opening key file '%s': %s\n", filename,
109 } else if (fd != STDIN_FILENO) {
113 if (rc == 0 && (st.st_mode & ~(S_IFREG | 0600)))
114 fprintf(stderr, "warning: "
115 "secret key '%s' has insecure file mode %#o\n",
116 filename, st.st_mode);
119 ptr = (char *)config;
120 remain = sizeof(*config);
122 rc = read(fd, ptr, remain);
126 printerr(0, "read() failed on %s: %s\n", filename,
129 } else if (rc == 0) {
130 printerr(0, "File %s does not have a complete key\n",
138 if (fd != STDIN_FILENO)
140 sk_config_disk_to_cpu(config);
151 * Checks if a key matching \a description is found in the keyring for
152 * logging purposes and then attempts to load \a payload of \a psize into a key
153 * with \a description.
155 * \param[in] payload Key payload
156 * \param[in] psize Payload size
157 * \param[in] description Description used for key in keyring
162 static key_serial_t sk_load_key(const struct sk_keyfile_config *skc,
163 const char *description)
165 struct sk_keyfile_config payload;
168 memcpy(&payload, skc, sizeof(*skc));
170 /* In the keyring use the disk layout so keyctl pipe can be used */
171 sk_config_cpu_to_disk(&payload);
173 /* Check to see if a key is already loaded matching description */
174 key = keyctl_search(KEY_SPEC_USER_KEYRING, "user", description, 0);
176 printerr(2, "Key %d found in session keyring, replacing\n",
179 key = add_key("user", description, &payload, sizeof(payload),
180 KEY_SPEC_USER_KEYRING);
182 key_perm_t perm = KEY_POS_ALL | KEY_USR_ALL |
183 KEY_GRP_ALL | KEY_OTH_ALL;
185 if (keyctl_setperm(key, perm) < 0)
186 printerr(2, "Failed to set perm 0x%x on key %d\n",
188 printerr(2, "Added key %d with description %s\n", key,
191 printerr(0, "Failed to add key with %s\n", description);
198 * Reads the key from \a path, verifies it and loads into the session keyring
199 * using a description determined by the the \a type. Existing keys with the
200 * same description are replaced.
202 * \param[in] path Path to key file
203 * \param[in] type Type of key to load which determines the description
208 int sk_load_keyfile(char *path)
210 struct sk_keyfile_config *config;
211 char description[SK_DESCRIPTION_SIZE + 1];
217 rc = stat(path, &buf);
219 printerr(0, "stat() failed for file %s: %s\n", path,
224 config = sk_read_file(path);
228 /* Similar to ssh, require adequate care of key files */
229 if (buf.st_mode & (S_IRGRP | S_IWGRP | S_IWOTH | S_IXOTH)) {
230 printerr(0, "Shared key files must be read/writeable only by "
235 if (sk_validate_config(config))
238 /* The server side can have multiple key files per file system so
239 * the nodemap name is appended to the key description to uniquely
241 if (config->skc_type & SK_TYPE_MGS) {
242 /* Any key can be an MGS key as long as we are told to use it */
243 rc = snprintf(description, SK_DESCRIPTION_SIZE, "lustre:MGS:%s",
244 config->skc_nodemap);
245 if (rc >= SK_DESCRIPTION_SIZE)
247 if (sk_load_key(config, description) == -1)
250 if (config->skc_type & SK_TYPE_SERVER) {
251 /* Server keys need to have the file system name in the key */
252 if (config->skc_fsname[0] == '\0') {
253 printerr(0, "Key configuration has no file system "
254 "attribute. Can't load as server type\n");
257 rc = snprintf(description, SK_DESCRIPTION_SIZE, "lustre:%s:%s",
258 config->skc_fsname, config->skc_nodemap);
259 if (rc >= SK_DESCRIPTION_SIZE)
261 if (sk_load_key(config, description) == -1)
264 if (config->skc_type & SK_TYPE_CLIENT) {
265 /* Load client file system key */
266 if (config->skc_fsname[0] != '\0') {
267 rc = snprintf(description, SK_DESCRIPTION_SIZE,
268 "lustre:%s", config->skc_fsname);
269 if (rc >= SK_DESCRIPTION_SIZE)
271 if (sk_load_key(config, description) == -1)
275 /* Load client MGC keys */
276 for (i = 0; i < MAX_MGSNIDS; i++) {
277 if (config->skc_mgsnids[i] == LNET_NID_ANY)
279 rc = snprintf(description, SK_DESCRIPTION_SIZE,
281 libcfs_nid2str(config->skc_mgsnids[i]));
282 if (rc >= SK_DESCRIPTION_SIZE)
284 if (sk_load_key(config, description) == -1)
297 * Byte swaps config from cpu format to disk
299 * \param[in,out] config sk_keyfile_config to swap
301 void sk_config_cpu_to_disk(struct sk_keyfile_config *config)
308 config->skc_version = htobe32(config->skc_version);
309 config->skc_hmac_alg = htobe16(config->skc_hmac_alg);
310 config->skc_crypt_alg = htobe16(config->skc_crypt_alg);
311 config->skc_expire = htobe32(config->skc_expire);
312 config->skc_shared_keylen = htobe32(config->skc_shared_keylen);
313 config->skc_prime_bits = htobe32(config->skc_prime_bits);
315 for (i = 0; i < MAX_MGSNIDS; i++)
316 config->skc_mgsnids[i] = htobe64(config->skc_mgsnids[i]);
320 * Byte swaps config from disk format to cpu
322 * \param[in,out] config sk_keyfile_config to swap
324 void sk_config_disk_to_cpu(struct sk_keyfile_config *config)
331 config->skc_version = be32toh(config->skc_version);
332 config->skc_hmac_alg = be16toh(config->skc_hmac_alg);
333 config->skc_crypt_alg = be16toh(config->skc_crypt_alg);
334 config->skc_expire = be32toh(config->skc_expire);
335 config->skc_shared_keylen = be32toh(config->skc_shared_keylen);
336 config->skc_prime_bits = be32toh(config->skc_prime_bits);
338 for (i = 0; i < MAX_MGSNIDS; i++)
339 config->skc_mgsnids[i] = be64toh(config->skc_mgsnids[i]);
343 * Verifies the on key payload format is valid
345 * \param[in] config sk_keyfile_config
350 int sk_validate_config(const struct sk_keyfile_config *config)
355 printerr(0, "Null configuration passed\n");
359 if (config->skc_version != SK_CONF_VERSION) {
360 printerr(0, "Invalid version\n");
364 if (config->skc_hmac_alg == SK_HMAC_INVALID) {
365 printerr(0, "Invalid HMAC algorithm\n");
369 if (config->skc_crypt_alg == SK_CRYPT_INVALID) {
370 printerr(0, "Invalid crypt algorithm\n");
374 if (config->skc_expire < 60 || config->skc_expire > INT_MAX) {
375 /* Try to limit key expiration to some reasonable minimum and
376 * also prevent values over INT_MAX because there appears
377 * to be a type conversion issue */
378 printerr(0, "Invalid expiration time should be between %d "
379 "and %d\n", 60, INT_MAX);
382 if (config->skc_prime_bits % 8 != 0 ||
383 config->skc_prime_bits > SK_MAX_P_BYTES * 8) {
384 printerr(0, "Invalid session key length must be a multiple of 8"
385 " and less then %d bits\n",
389 if (config->skc_shared_keylen % 8 != 0 ||
390 config->skc_shared_keylen > SK_MAX_KEYLEN_BYTES * 8){
391 printerr(0, "Invalid shared key max length must be a multiple "
392 "of 8 and less then %d bits\n",
393 SK_MAX_KEYLEN_BYTES * 8);
397 /* Check for terminating nulls on strings */
398 for (i = 0; i < sizeof(config->skc_fsname) &&
399 config->skc_fsname[i] != '\0'; i++)
401 if (i == sizeof(config->skc_fsname)) {
402 printerr(0, "File system name not null terminated\n");
406 for (i = 0; i < sizeof(config->skc_nodemap) &&
407 config->skc_nodemap[i] != '\0'; i++)
409 if (i == sizeof(config->skc_nodemap)) {
410 printerr(0, "Nodemap name not null terminated\n");
414 if (config->skc_type == SK_TYPE_INVALID) {
415 printerr(0, "Invalid key type\n");
423 * Hashes \a string and places the hash in \a hash
426 * \param[in] string Null terminated string to hash
427 * \param[in] hash_alg OpenSSL EVP_MD to use for hash
428 * \param[in,out] hash gss_buffer_desc to hold the result
433 static int sk_hash_string(const char *string, const EVP_MD *hash_alg,
434 gss_buffer_desc *hash)
436 EVP_MD_CTX *ctx = EVP_MD_CTX_create();
437 size_t len = strlen(string);
438 unsigned int hashlen;
440 if (!hash->value || hash->length < EVP_MD_size(hash_alg))
442 if (!EVP_DigestInit_ex(ctx, hash_alg, NULL))
444 if (!EVP_DigestUpdate(ctx, string, len))
446 if (!EVP_DigestFinal_ex(ctx, hash->value, &hashlen))
449 EVP_MD_CTX_destroy(ctx);
450 hash->length = hashlen;
454 EVP_MD_CTX_destroy(ctx);
459 * Hashes \a string and verifies the resulting hash matches the value
462 * \param[in] string Null terminated string to hash
463 * \param[in] hash_alg OpenSSL EVP_MD to use for hash
464 * \param[in,out] current_hash gss_buffer_desc to compare to
466 * \return gss error failure
467 * \return GSS_S_COMPLETE success
469 uint32_t sk_verify_hash(const char *string, const EVP_MD *hash_alg,
470 const gss_buffer_desc *current_hash)
472 gss_buffer_desc hash;
473 unsigned char hashbuf[EVP_MAX_MD_SIZE];
475 hash.value = hashbuf;
476 hash.length = sizeof(hashbuf);
478 if (sk_hash_string(string, hash_alg, &hash))
479 return GSS_S_FAILURE;
480 if (current_hash->length != hash.length)
481 return GSS_S_DEFECTIVE_TOKEN;
482 if (memcmp(current_hash->value, hash.value, hash.length))
483 return GSS_S_BAD_SIG;
485 return GSS_S_COMPLETE;
488 static inline int sk_config_has_mgsnid(struct sk_keyfile_config *config,
494 nid = libcfs_str2nid(mgsnid);
495 if (nid == LNET_NID_ANY)
498 for (i = 0; i < MAX_MGSNIDS; i++)
499 if (config->skc_mgsnids[i] == nid)
505 * Create an sk_cred structure populated with initial configuration info and the
506 * key. \a tgt and \a nodemap are used in determining the expected key
507 * description so the key can be found by searching the keyring.
508 * This is done because there is no easy way to pass keys from the mount command
509 * all the way to the request_key call. In addition any keys can be dynamically
510 * added to the keyrings and still found. The keyring that needs to be used
511 * must be the session keyring.
513 * \param[in] tgt Target file system
514 * \param[in] nodemap Cluster name for the key. This correlates to
515 * the nodemap name and is used by the server side.
516 * For the client this will be NULL.
517 * \param[in] flags Flags for the credentials
519 * \return sk_cred Allocated struct sk_cred on success
520 * \return NULL failure
522 struct sk_cred *sk_create_cred(const char *tgt, const char *nodemap,
523 const uint32_t flags)
525 struct sk_keyfile_config *config;
526 struct sk_kernel_ctx *kctx;
527 struct sk_cred *skc = NULL;
528 char description[SK_DESCRIPTION_SIZE + 1];
529 char fsname[MTI_NAME_MAXLEN + 1];
530 const char *mgsnid = NULL;
537 printerr(2, "Creating credentials for target: %s with nodemap: %s\n",
540 memset(description, 0, sizeof(description));
541 memset(fsname, 0, sizeof(fsname));
543 /* extract the file system name from target */
544 ptr = index(tgt, '-');
548 /* This must be an MGC target */
549 if (strncmp(tgt, "MGC", 3) || len <= 3) {
550 printerr(0, "Invalid target name\n");
558 if (len > MTI_NAME_MAXLEN) {
559 printerr(0, "Invalid target name\n");
562 memcpy(fsname, tgt, len);
566 rc = snprintf(description, SK_DESCRIPTION_SIZE,
567 "lustre:MGS:%s", nodemap);
569 rc = snprintf(description, SK_DESCRIPTION_SIZE,
570 "lustre:%s:%s", fsname, nodemap);
572 rc = snprintf(description, SK_DESCRIPTION_SIZE, "lustre:%s",
576 if (rc >= SK_DESCRIPTION_SIZE) {
577 printerr(0, "Invalid key description\n");
581 /* It may be a good idea to move Lustre keys to the gss_keyring
582 * (lgssc) type so that they expire when Lustre modules are removed.
583 * Unfortunately it can't be done at mount time because the mount
584 * syscall could trigger the Lustre modules to load and until that
585 * point we don't have a lgssc key type.
587 * TODO: Query the community for a consensus here */
588 printerr(2, "Searching for key with description: %s\n", description);
589 sk_key = keyctl_search(KEY_SPEC_USER_KEYRING, "user",
592 printerr(1, "No key found for %s\n", description);
596 keylen = keyctl_read_alloc(sk_key, (void **)&config);
598 printerr(0, "keyctl_read() failed for key %ld: %s\n", sk_key,
601 } else if (keylen != sizeof(*config)) {
602 printerr(0, "Unexpected key size: %d returned for key %ld, "
603 "expected %zu bytes\n",
604 keylen, sk_key, sizeof(*config));
608 sk_config_disk_to_cpu(config);
610 if (sk_validate_config(config)) {
611 printerr(0, "Invalid key configuration for key: %ld\n", sk_key);
615 if (mgsnid && !sk_config_has_mgsnid(config, mgsnid)) {
616 printerr(0, "Target name does not match key's MGS NIDs\n");
620 if (!mgsnid && strcmp(fsname, config->skc_fsname)) {
621 printerr(0, "Target name does not match key's file system\n");
625 skc = malloc(sizeof(*skc));
627 printerr(0, "Failed to allocate memory for sk_cred\n");
631 /* this initializes all gss_buffer_desc to empty as well */
632 memset(skc, 0, sizeof(*skc));
634 skc->sc_flags = flags;
635 skc->sc_tgt.length = strlen(tgt) + 1;
636 skc->sc_tgt.value = malloc(skc->sc_tgt.length);
637 if (!skc->sc_tgt.value) {
638 printerr(0, "Failed to allocate memory for target\n");
641 memcpy(skc->sc_tgt.value, tgt, skc->sc_tgt.length);
643 skc->sc_nodemap_hash.length = EVP_MD_size(EVP_sha256());
644 skc->sc_nodemap_hash.value = malloc(skc->sc_nodemap_hash.length);
645 if (!skc->sc_nodemap_hash.value) {
646 printerr(0, "Failed to allocate memory for nodemap hash\n");
650 if (sk_hash_string(config->skc_nodemap, EVP_sha256(),
651 &skc->sc_nodemap_hash)) {
652 printerr(0, "Failed to generate hash for nodemap name\n");
656 kctx = &skc->sc_kctx;
657 kctx->skc_version = config->skc_version;
658 strcpy(kctx->skc_hmac_alg, sk_hmac2name(config->skc_hmac_alg));
659 strcpy(kctx->skc_crypt_alg, sk_crypt2name(config->skc_crypt_alg));
660 kctx->skc_expire = config->skc_expire;
662 /* key payload format is in bits, convert to bytes */
663 kctx->skc_shared_key.length = config->skc_shared_keylen / 8;
664 kctx->skc_shared_key.value = malloc(kctx->skc_shared_key.length);
665 if (!kctx->skc_shared_key.value) {
666 printerr(0, "Failed to allocate memory for shared key\n");
669 memcpy(kctx->skc_shared_key.value, config->skc_shared_key,
670 kctx->skc_shared_key.length);
672 skc->sc_p.length = config->skc_prime_bits / 8;
673 skc->sc_p.value = malloc(skc->sc_p.length);
674 if (!skc->sc_p.value) {
675 printerr(0, "Failed to allocate p\n");
678 memcpy(skc->sc_p.value, config->skc_p, skc->sc_p.length);
691 #define SK_GENERATOR 2
692 #define DH_NUMBER_ITERATIONS_FOR_PRIME 64
694 /* OpenSSL 1.1.1c increased the number of rounds used for Miller-Rabin testing
695 * of the prime provided as input parameter to DH_check(). This makes the check
696 * roughly x10 longer, and causes request timeouts when an SSK flavor is being
698 * Instead, use a dynamic number Miller-Rabin rounds based on the speed of the
699 * check on the current system, evaluated when the lsvcgssd daemon starts, but
700 * at least as many as OpenSSL 1.1.1b used for the same key size. If default
701 * DH_check() duration is OK, use it directly instead of limiting the rounds.
702 * If \a num_rounds == 0, we just call original DH_check() directly.
704 * OpenSSL v3 internally forces a minimum of 64 rounds when checking prime, so
705 * it is no longer possible to test prime check speed with fewer rounds. In this
706 * case, do not bother and directly call EVP_PKEY_param_check.
708 #ifdef HAVE_OPENSSL_EVP_PKEY
709 static bool sk_is_dh_valid(EVP_PKEY_CTX *ctx)
711 if (EVP_PKEY_param_check(ctx) != 1) {
712 printerr(0, "EVP_PKEY_param_check failed\n");
713 ERR_print_errors_fp(stderr);
719 static inline bool sk_check_dh(const DH *dh, int num_rounds, bool fullcheck)
721 const BIGNUM *p = NULL, *g = NULL;
728 DH_get0_pqg(dh, &p, NULL, &g);
732 if (!BN_is_word(g, SK_GENERATOR)) {
733 printerr(0, "%s: Diffie-Hellman generator is not %u\n",
734 program_invocation_short_name, SK_GENERATOR);
738 word = BN_mod_word(p, 24);
739 /* OpenSSL v3 changed the way the prime is generated,
740 * using p mod 24 == 23.
741 * So we must accept word == 23 if the prime was generated
742 * by a client with OpenSSL v3.
744 if ((word != 11) && (word != 23)) {
745 printerr(0, "%s: Diffie-Hellman prime modulo=%lu unsuitable\n",
746 program_invocation_short_name, word);
755 printerr(0, "%s: Diffie-Hellman error allocating context\n",
756 program_invocation_short_name);
760 r = BN_CTX_get(ctx); /* must be called before "ctx" used elsewhere */
762 rc = BN_is_prime_ex(p, num_rounds, ctx, NULL);
764 printerr(0, "%s: Diffie-Hellman 'p' not prime in %u rounds\n",
765 program_invocation_short_name, num_rounds);
769 if (!BN_rshift1(r, p)) {
770 printerr(0, "%s: error shifting BigNum 'r' by 'p'\n",
771 program_invocation_short_name);
774 rc = BN_is_prime_ex(r, num_rounds, ctx, NULL);
776 printerr(0, "%s: Diffie-Hellman 'r' not prime in %u rounds\n",
777 program_invocation_short_name, num_rounds);
790 static bool sk_is_dh_valid(const DH *dh, int num_rounds)
794 if (num_rounds == 0) {
797 rc = DH_check(dh, &codes);
798 if (codes == DH_NOT_SUITABLE_GENERATOR &&
799 sk_check_dh(dh, num_rounds, false))
801 if (rc != 1 || codes) {
802 printerr(0, "DH_check(0) failed: codes=%#x: rc=%d\n",
809 return sk_check_dh(dh, num_rounds, true);
813 #ifndef HAVE_OPENSSL_EVP_PKEY
814 #define VALUE_LENGTH 256
815 static unsigned char test_prime[VALUE_LENGTH] =
816 "\xf7\xfa\x49\xd8\xec\xb1\x3b\xff\x26\x10\x3f\xc5\x3a\xc5\xcc\x40"
817 "\x4f\xbf\x92\xe1\x8b\x83\xe7\xa2\xba\x0f\x51\x5a\x91\x48\xe0\xa3"
818 "\xf1\x4d\xbc\xbb\x8a\x28\x14\xac\x02\x23\x76\x42\x17\x4d\x3c\xdc"
819 "\x5e\x4f\x80\x1f\xd7\x54\x1c\x50\xac\x3b\x28\x68\x8d\x71\x41\x7f"
820 "\xa7\x1c\x2f\x22\xd3\xa8\x91\xb2\x64\xb6\x84\xa6\xcf\x06\x16\x91"
821 "\x2f\xb8\xb4\x42\x1d\x3a\x4e\x3a\x0c\x7f\x04\x69\x78\xb5\x8f\x92"
822 "\x07\x89\xac\x24\x06\x53\x2c\x23\xec\xaa\x5c\xb4\x7b\x49\xbc\xf4"
823 "\x90\x67\x71\x9c\x24\x2c\x1d\x8d\x76\xc8\x85\x4e\x19\xf1\xf9\x33"
824 "\x45\xbd\x9f\x7d\x0a\x08\x8c\x22\xcc\x35\xf3\x5b\xab\x3f\x24\x9d"
825 "\x61\x70\x86\xbb\xbe\xd8\xb0\xf8\x34\xfa\xeb\x5b\x8e\xf2\x62\x23"
826 "\xd1\xfb\xbb\xb8\x21\x71\x1e\x39\x39\x59\xe0\x82\x98\x41\x84\x40"
827 "\x1f\xd3\x9b\xa3\x73\xdb\xec\xe0\xc0\xde\x2d\x1c\xea\x43\x40\x93"
828 "\x98\x38\x03\x36\x1e\xe1\xe7\x39\x7b\x35\x92\x4a\x51\xa5\x91\x63"
829 "\xd5\x31\x98\x3d\x89\x27\x6f\xcc\x69\xff\xbe\x31\x13\xdc\x2f\x72"
830 "\x2d\xab\x6a\xb7\x13\xd3\x47\xda\xaa\xf3\x3c\xa0\xfd\xaa\x0f\x02"
831 "\x96\x81\x1a\x26\xe8\xf7\x25\x65\x33\x78\xd9\x6b\x6d\xb0\xd9\xfb";
834 * Measure time taken by prime testing routine for a 2048 bit long prime,
835 * depending on the number of check rounds.
837 * \param[in] usec_check_max max time allowed for DH_check completion
839 * \retval max number of rounds to keep prime testing under usec_check_max
840 * return 0 if we should use the default DH_check rounds
842 int sk_speedtest_dh_valid(unsigned int usec_check_max, pid_t *child)
847 int num_rounds, prev_rounds = 0;
849 /* Set SIGCHLD disposition so that child that terminates
850 * does not become a zombie.
852 sa.sa_handler = NULL;
853 sigemptyset(&sa.sa_mask);
854 sa.sa_flags = SA_NOCLDWAIT;
855 if (sigaction(SIGCHLD, &sa, NULL) == -1)
856 printerr(2, "SIGCHLD sigaction failed\n");
860 printerr(0, "cannot fork child for speedtest: %s\n",
862 /* in this case the speedtest cannot be run, so return 0
863 * to use default num rounds for prime testing
866 } else if (*child != 0) {
867 /* parent returns immediately,
868 * 0 means num rounds is not determined yet
873 /* now in forked child process, start speed test */
879 p = BN_bin2bn(test_prime, VALUE_LENGTH, NULL);
887 if (!BN_set_word(g, SK_GENERATOR))
890 /* "dh" takes over freeing of 'p' and 'g' if this succeeds */
891 if (!DH_set0_pqg(dh, p, NULL, g)) {
900 num_rounds <= DH_NUMBER_ITERATIONS_FOR_PRIME;
901 num_rounds += (num_rounds <= 4 ? 4 : 8)) {
902 unsigned int usec_this;
905 /* get max duration of 4 runs at current number of rounds */
907 for (j = 0; j < 4; j++) {
908 struct timeval now, prev;
909 unsigned int usec_curr;
911 gettimeofday(&prev, NULL);
912 if (!sk_is_dh_valid(dh, num_rounds)) {
913 /* if test_prime is found bad, use default */
917 gettimeofday(&now, NULL);
918 usec_curr = (now.tv_sec - prev.tv_sec) * 1000000 +
919 now.tv_usec - prev.tv_usec;
920 if (usec_curr > usec_this)
921 usec_this = usec_curr;
923 printerr(2, "%s: %d rounds: %d usec\n",
924 program_invocation_short_name, num_rounds, usec_this);
925 if (num_rounds == 0) {
926 if (usec_this <= usec_check_max)
927 /* using original check rounds as implemented in
928 * DH_check() took less time than the max allowed,
929 * so just use original DH_check()
932 } else if (usec_this >= usec_check_max) {
935 prev_rounds = num_rounds;
943 #endif /* !HAVE_OPENSSL_EVP_PKEY */
945 #ifdef HAVE_OPENSSL_EVP_PKEY
946 static uint32_t __sk_gen_params(struct sk_cred *skc, BIGNUM *p, BIGNUM *g,
949 EVP_PKEY_CTX *ctx = NULL, *ctx_from_key = NULL;
950 OSSL_PARAM_BLD *tmpl = NULL;
951 OSSL_PARAM *params = NULL;
952 EVP_PKEY *key = NULL;
953 uint32_t rc = GSS_S_FAILURE;
955 tmpl = OSSL_PARAM_BLD_new();
957 !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_FFC_P, p) ||
958 !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_FFC_G, g)) {
959 printerr(0, "error: params cannot be pushed\n");
962 params = OSSL_PARAM_BLD_to_param(tmpl);
964 printerr(0, "error: params cannot be allocated\n");
968 ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL);
970 EVP_PKEY_fromdata_init(ctx) != 1 ||
971 EVP_PKEY_fromdata(ctx, &key,
972 EVP_PKEY_KEY_PARAMETERS, params) != 1) {
973 printerr(0, "error: params cannot be set\n");
977 ctx_from_key = EVP_PKEY_CTX_new_from_pkey(NULL, key, NULL);
979 printerr(0, "error: ctx_from_key cannot be allocated\n");
983 /* Verify that we have a safe prime and valid generator */
984 if (!sk_is_dh_valid(ctx_from_key))
987 skc->sc_params = NULL;
988 if (EVP_PKEY_keygen_init(ctx_from_key) != 1 ||
989 EVP_PKEY_keygen(ctx_from_key, &skc->sc_params) != 1) {
990 printerr(0, "Failed to generate public DH key: %s\n",
991 ERR_error_string(ERR_get_error(), NULL));
995 /* skc->sc_pub_key.value is allocated by
996 * EVP_PKEY_get1_encoded_public_key
998 skc->sc_pub_key.length =
999 EVP_PKEY_get1_encoded_public_key(skc->sc_params,
1000 (unsigned char **)&skc->sc_pub_key.value);
1001 if (skc->sc_pub_key.length == 0) {
1002 printerr(0, "error: cannot get pub key\n");
1003 skc->sc_pub_key.value = NULL;
1006 rc = GSS_S_COMPLETE;
1009 EVP_PKEY_CTX_free(ctx_from_key);
1011 EVP_PKEY_CTX_free(ctx);
1012 OSSL_PARAM_free(params);
1013 OSSL_PARAM_BLD_free(tmpl);
1018 #else /* !HAVE_OPENSSL_EVP_PKEY */
1019 static uint32_t __sk_gen_params(struct sk_cred *skc, BIGNUM *p, BIGNUM *g,
1022 const BIGNUM *pub_key;
1024 /* Populate DH parameters */
1025 /* "dh" takes over freeing of 'p' and 'g' if this succeeds */
1026 skc->sc_params = DH_new();
1027 if (!skc->sc_params || !DH_set0_pqg(skc->sc_params, p, NULL, g)) {
1028 printerr(0, "Failed to set pqg\n");
1031 return GSS_S_FAILURE;
1034 /* Verify that we have a safe prime and valid generator */
1035 if (!sk_is_dh_valid(skc->sc_params, num_rounds))
1036 return GSS_S_FAILURE;
1038 if (DH_generate_key(skc->sc_params) != 1) {
1039 printerr(0, "Failed to generate public DH key: %s\n",
1040 ERR_error_string(ERR_get_error(), NULL));
1041 return GSS_S_FAILURE;
1044 DH_get0_key(skc->sc_params, &pub_key, NULL);
1045 skc->sc_pub_key.length = BN_num_bytes(pub_key);
1046 skc->sc_pub_key.value = malloc(skc->sc_pub_key.length);
1047 if (!skc->sc_pub_key.value) {
1048 printerr(0, "Failed to allocate memory for public key\n");
1049 return GSS_S_FAILURE;
1052 BN_bn2bin(pub_key, skc->sc_pub_key.value);
1054 return GSS_S_COMPLETE;
1056 #endif /* HAVE_OPENSSL_EVP_PKEY */
1059 * Populates the DH parameters for the DHKE
1061 * \param[in,out] skc Shared key credentials structure to
1062 * populate with DH parameters
1064 * \retval GSS_S_COMPLETE success
1065 * \retval GSS_S_FAILURE failure
1067 uint32_t sk_gen_params(struct sk_cred *skc, int num_rounds)
1072 /* Random value used by both the request and response as part of the
1073 * key binding material. This also should ensure we have unqiue
1074 * tokens that are sent to the remote server which is important because
1075 * the token is hashed for the sunrpc cache lookups and a failure there
1076 * would cause connection attempts to fail indefinitely due to the large
1077 * timeout value on the server side.
1079 if (RAND_bytes((unsigned char *)&random, sizeof(random)) != 1) {
1080 printerr(0, "Failed to get data for random parameter: %s\n",
1081 ERR_error_string(ERR_get_error(), NULL));
1082 return GSS_S_FAILURE;
1085 /* The random value will always be used in byte range operations
1086 * so we keep it as big endian from this point on.
1088 skc->sc_kctx.skc_host_random = random;
1090 p = BN_bin2bn(skc->sc_p.value, skc->sc_p.length, NULL);
1092 printerr(0, "Failed to convert binary to BIGNUM\n");
1093 return GSS_S_FAILURE;
1096 /* We use a static generator for shared key */
1099 printerr(0, "Failed to allocate new BIGNUM\n");
1102 if (BN_set_word(g, SK_GENERATOR) != 1) {
1103 printerr(0, "Failed to set g value for DH params\n");
1107 return __sk_gen_params(skc, p, g, num_rounds);
1114 return GSS_S_FAILURE;
1118 * Convert SK hash algorithm into openssl message digest
1120 * \param[in,out] alg SK hash algorithm
1124 static inline const EVP_MD *sk_hash_to_evp_md(enum cfs_crypto_hash_alg alg)
1127 case CFS_HASH_ALG_SHA256:
1128 return EVP_sha256();
1129 case CFS_HASH_ALG_SHA512:
1130 return EVP_sha512();
1132 return EVP_md_null();
1137 * Signs (via HMAC) the parameters used only in the key initialization protocol.
1139 * \param[in] key Key to use for HMAC
1140 * \param[in] bufs Array of gss_buffer_desc to generate
1142 * \param[in] numbufs Number of buffers in array
1143 * \param[in] hash_alg OpenSSL EVP_MD to use for hash
1144 * \param[in,out] hmac HMAC of buffers is allocated and placed
1145 * in this gss_buffer_desc. Caller must
1149 * \retval -1 failure
1151 int sk_sign_bufs(gss_buffer_desc *key, gss_buffer_desc *bufs, const int numbufs,
1152 const EVP_MD *hash_alg, gss_buffer_desc *hmac)
1154 unsigned int hashlen = EVP_MD_size(hash_alg);
1155 EVP_MAC_CTX *ctx = NULL;
1156 EVP_MAC *mac = NULL;
1159 DECLARE_EVP_MD(subalg, hash_alg);
1161 if (hash_alg == EVP_md_null()) {
1162 printerr(0, "Invalid hash algorithm\n");
1166 hmac->length = hashlen;
1167 hmac->value = malloc(hashlen);
1169 printerr(0, "Failed to allocate memory for HMAC\n");
1173 mac = EVP_MAC_fetch(NULL, "HMAC", NULL);
1175 printerr(0, "Failed to fetch HMAC\n");
1179 ctx = EVP_MAC_CTX_new(mac);
1181 printerr(0, "Failed to init HMAC ctx\n");
1185 if (EVP_MAC_init(ctx, key->value, key->length, subalg) != 1) {
1186 printerr(0, "Failed to init HMAC\n");
1190 for (i = 0; i < numbufs; i++) {
1191 if (EVP_MAC_update(ctx, bufs[i].value, bufs[i].length) != 1) {
1192 printerr(0, "Failed to update HMAC\n");
1197 /* The result gets populated in hmac */
1198 if (EVP_MAC_final(ctx, hmac->value, &len, hashlen) != 1) {
1199 printerr(0, "Failed to finalize HMAC\n");
1202 if (hmac->length != len) {
1203 printerr(0, "HMAC size %zu does not match expected %zu\n",
1210 EVP_MAC_CTX_free(ctx);
1216 * Generates an HMAC for gss_buffer_desc array in \a bufs of \a numbufs
1217 * and verifies against \a hmac.
1219 * \param[in] skc Shared key credentials
1220 * \param[in] bufs Array of gss_buffer_desc to generate HMAC for
1221 * \param[in] numbufs Number of buffers in array
1222 * \param[in] hash_alg OpenSSL EVP_MD to use for hash
1223 * \param[in] hmac HMAC to verify against
1225 * \retval GSS_S_COMPLETE success (match)
1226 * \retval gss error failure
1228 uint32_t sk_verify_hmac(struct sk_cred *skc, gss_buffer_desc *bufs,
1229 const int numbufs, const EVP_MD *hash_alg,
1230 gss_buffer_desc *hmac)
1232 gss_buffer_desc bufs_hmac;
1235 if (sk_sign_bufs(&skc->sc_kctx.skc_shared_key, bufs, numbufs, hash_alg,
1237 printerr(0, "Failed to sign buffers to verify HMAC\n");
1238 if (bufs_hmac.value)
1239 free(bufs_hmac.value);
1240 return GSS_S_FAILURE;
1243 if (hmac->length != bufs_hmac.length) {
1244 printerr(0, "Invalid HMAC size\n");
1245 free(bufs_hmac.value);
1246 return GSS_S_BAD_SIG;
1249 rc = memcmp(hmac->value, bufs_hmac.value, bufs_hmac.length);
1250 free(bufs_hmac.value);
1253 return GSS_S_BAD_SIG;
1255 return GSS_S_COMPLETE;
1259 * Cleanup an sk_cred freeing any resources
1261 * \param[in,out] skc Shared key credentials to free
1263 void sk_free_cred(struct sk_cred *skc)
1268 if (skc->sc_p.value)
1269 free(skc->sc_p.value);
1270 if (skc->sc_pub_key.value)
1271 free(skc->sc_pub_key.value);
1272 if (skc->sc_tgt.value)
1273 free(skc->sc_tgt.value);
1274 if (skc->sc_nodemap_hash.value)
1275 free(skc->sc_nodemap_hash.value);
1276 if (skc->sc_hmac.value)
1277 free(skc->sc_hmac.value);
1279 /* Overwrite keys and IV before freeing */
1280 if (skc->sc_dh_shared_key.value) {
1281 memset(skc->sc_dh_shared_key.value, 0,
1282 skc->sc_dh_shared_key.length);
1283 free(skc->sc_dh_shared_key.value);
1285 if (skc->sc_kctx.skc_hmac_key.value) {
1286 memset(skc->sc_kctx.skc_hmac_key.value, 0,
1287 skc->sc_kctx.skc_hmac_key.length);
1288 free(skc->sc_kctx.skc_hmac_key.value);
1290 if (skc->sc_kctx.skc_encrypt_key.value) {
1291 memset(skc->sc_kctx.skc_encrypt_key.value, 0,
1292 skc->sc_kctx.skc_encrypt_key.length);
1293 free(skc->sc_kctx.skc_encrypt_key.value);
1295 if (skc->sc_kctx.skc_shared_key.value) {
1296 memset(skc->sc_kctx.skc_shared_key.value, 0,
1297 skc->sc_kctx.skc_shared_key.length);
1298 free(skc->sc_kctx.skc_shared_key.value);
1300 if (skc->sc_kctx.skc_session_key.value) {
1301 memset(skc->sc_kctx.skc_session_key.value, 0,
1302 skc->sc_kctx.skc_session_key.length);
1303 free(skc->sc_kctx.skc_session_key.value);
1306 if (skc->sc_params) {
1307 EVP_PKEY_free(skc->sc_params);
1308 skc->sc_params = NULL;
1315 /* This function handles key derivation using the hash algorithm specified in
1316 * \a hash_alg, buffers in \a key_binding_bufs, and original key in
1317 * \a origin_key to produce a \a derived_key. The first element of the
1318 * key_binding_bufs array is reserved for the counter used in the KDF. The
1319 * derived key in \a derived_key could differ in size from \a origin_key and
1320 * must be populated with the expected size and a valid buffer to hold the
1323 * If the derived key size is greater than the HMAC algorithm size it will be
1324 * a done using several iterations of a counter and the key binding bufs.
1326 * If the size is smaller it will take copy the first N bytes necessary to
1327 * fill the derived key. */
1328 static int sk_kdf(gss_buffer_desc *derived_key, gss_buffer_desc *origin_key,
1329 gss_buffer_desc *key_binding_bufs, int numbufs,
1330 enum cfs_crypto_hash_alg hmac_alg)
1336 gss_buffer_desc tmp_hash;
1343 /* Use a counter as the first buffer followed by the key binding
1344 * buffers in the event we need more than one a single cycle to
1345 * produced a symmetric key large enough in size */
1346 key_binding_bufs[0].value = &counter;
1347 key_binding_bufs[0].length = sizeof(counter);
1349 remain = derived_key->length;
1350 keydata = derived_key->value;
1352 while (remain > 0) {
1353 counter = htobe32(i++);
1354 rc = sk_sign_bufs(origin_key, key_binding_bufs, numbufs,
1355 sk_hash_to_evp_md(hmac_alg), &tmp_hash);
1358 free(tmp_hash.value);
1362 if (cfs_crypto_hash_digestsize(hmac_alg) != tmp_hash.length) {
1363 free(tmp_hash.value);
1367 bytes = (remain < tmp_hash.length) ? remain : tmp_hash.length;
1368 memcpy(keydata, tmp_hash.value, bytes);
1369 free(tmp_hash.value);
1377 /* Populates the sk_cred's session_key using the a Key Derviation Function (KDF)
1378 * based on the recommendations in NIST Special Publication SP 800-56B Rev 1
1379 * (Sep 2014) Section 5.5.1
1381 * \param[in,out] skc Shared key credentials structure with
1383 * \return -1 failure
1386 int sk_session_kdf(struct sk_cred *skc, lnet_nid_t client_nid,
1387 gss_buffer_desc *client_token, gss_buffer_desc *server_token)
1389 struct sk_kernel_ctx *kctx = &skc->sc_kctx;
1390 gss_buffer_desc *session_key = &kctx->skc_session_key;
1391 gss_buffer_desc bufs[5];
1392 enum cfs_crypto_crypt_alg crypt_alg;
1395 crypt_alg = cfs_crypto_crypt_alg(kctx->skc_crypt_alg);
1396 session_key->length = cfs_crypto_crypt_keysize(crypt_alg);
1397 session_key->value = malloc(session_key->length);
1398 if (!session_key->value) {
1399 printerr(0, "Failed to allocate memory for session key\n");
1403 /* Key binding info ordering
1404 * 1. Reserved for counter
1408 * 4. Server's token */
1409 bufs[0].value = NULL;
1411 bufs[1] = skc->sc_dh_shared_key;
1412 bufs[2].value = &client_nid;
1413 bufs[2].length = sizeof(client_nid);
1414 bufs[3] = *client_token;
1415 bufs[4] = *server_token;
1417 return sk_kdf(&kctx->skc_session_key, &kctx->skc_shared_key, bufs,
1418 5, cfs_crypto_hash_alg(kctx->skc_hmac_alg));
1421 /* Uses the session key to create an HMAC key and encryption key. In
1422 * integrity mode the session key used to generate the HMAC key uses
1423 * session information which is available on the wire but by creating
1424 * a session based HMAC key we can prevent potential replay as both the
1425 * client and server have random numbers used as part of the key creation.
1427 * The keys used for integrity and privacy are formulated as below using
1428 * the session key that is the output of the key derivation function. The
1429 * HMAC algorithm is determined by the shared key algorithm selected in the
1433 * Session HMAC Key = PBKDF2("Integrity", KDF derived Session Key)
1436 * Session HMAC Key = PBKDF2("Integrity", KDF derived Session Key)
1437 * Session Encryption Key = PBKDF2("Encrypt", KDF derived Session Key)
1439 * \param[in,out] skc Shared key credentials structure with
1441 * \return -1 failure
1444 int sk_compute_keys(struct sk_cred *skc)
1446 struct sk_kernel_ctx *kctx = &skc->sc_kctx;
1447 gss_buffer_desc *session_key = &kctx->skc_session_key;
1448 gss_buffer_desc *hmac_key = &kctx->skc_hmac_key;
1449 gss_buffer_desc *encrypt_key = &kctx->skc_encrypt_key;
1450 enum cfs_crypto_hash_alg hmac_alg;
1451 enum cfs_crypto_crypt_alg crypt_alg;
1452 char *encrypt = "Encrypt";
1453 char *integrity = "Integrity";
1456 hmac_alg = cfs_crypto_hash_alg(kctx->skc_hmac_alg);
1457 hmac_key->length = cfs_crypto_hash_digestsize(hmac_alg);
1458 hmac_key->value = malloc(hmac_key->length);
1459 if (!hmac_key->value)
1462 rc = PKCS5_PBKDF2_HMAC(integrity, -1, session_key->value,
1463 session_key->length, SK_PBKDF2_ITERATIONS,
1464 sk_hash_to_evp_md(hmac_alg),
1465 hmac_key->length, hmac_key->value);
1469 /* Encryption key is only populated in privacy mode */
1470 if ((skc->sc_flags & LGSS_SVC_PRIV) == 0)
1473 crypt_alg = cfs_crypto_crypt_alg(kctx->skc_crypt_alg);
1474 encrypt_key->length = cfs_crypto_crypt_keysize(crypt_alg);
1475 encrypt_key->value = malloc(encrypt_key->length);
1476 if (!encrypt_key->value)
1479 rc = PKCS5_PBKDF2_HMAC(encrypt, -1, session_key->value,
1480 session_key->length, SK_PBKDF2_ITERATIONS,
1481 sk_hash_to_evp_md(hmac_alg),
1482 encrypt_key->length, encrypt_key->value);
1489 static uint32_t __sk_compute_dh_key(struct sk_cred *skc,
1490 const gss_buffer_desc *pub_key,
1491 size_t *expected_len)
1493 gss_buffer_desc *dh_shared = &skc->sc_dh_shared_key;
1494 uint32_t rc = GSS_S_FAILURE;
1495 #ifdef HAVE_OPENSSL_EVP_PKEY
1496 EVP_PKEY_CTX *ctx = NULL;
1497 EVP_PKEY *peerkey = NULL;
1499 peerkey = EVP_PKEY_new();
1501 EVP_PKEY_copy_parameters(peerkey, skc->sc_params) != 1) {
1502 printerr(0, "error: peerkey cannot be init\n");
1506 if (EVP_PKEY_set1_encoded_public_key(peerkey,
1508 pub_key->length) != 1) {
1509 printerr(0, "error: peerkey cannot be set\n");
1513 ctx = EVP_PKEY_CTX_new_from_pkey(NULL, skc->sc_params, NULL);
1515 printerr(0, "error: ctx cannot be allocated\n");
1519 if (EVP_PKEY_derive_init(ctx) != 1 ||
1520 EVP_PKEY_derive_set_peer(ctx, peerkey) != 1) {
1521 printerr(0, "error: ctx cannot be init\n");
1525 if (EVP_PKEY_derive(ctx, NULL, expected_len) != 1) {
1526 printerr(0, "error: cannot get dh length\n");
1530 dh_shared->length = *expected_len;
1531 dh_shared->value = malloc(*expected_len);
1532 if (!dh_shared->value) {
1533 printerr(0, "error: cannot allocate memory for shared key\n");
1537 if (EVP_PKEY_derive(ctx, dh_shared->value, &dh_shared->length) != 1) {
1538 printerr(0, "error: cannot derive dh key\n");
1539 ERR_print_errors_fp(stderr);
1543 rc = GSS_S_COMPLETE;
1545 EVP_PKEY_CTX_free(ctx);
1546 EVP_PKEY_free(peerkey);
1547 #else /* !HAVE_OPENSSL_EVP_PKEY */
1548 BIGNUM *remote_pub_key;
1550 remote_pub_key = BN_bin2bn(pub_key->value, pub_key->length, NULL);
1551 if (!remote_pub_key) {
1552 printerr(0, "Failed to convert binary to BIGNUM\n");
1556 *expected_len = DH_size(skc->sc_params);
1557 dh_shared->length = *expected_len;
1558 dh_shared->value = malloc(*expected_len);
1559 if (!dh_shared->value) {
1561 "Failed to allocate memory for computed shared secret key\n");
1565 /* This computes the shared key from the DHKE */
1566 dh_shared->length = DH_compute_key(dh_shared->value, remote_pub_key,
1568 if (dh_shared->length == -1) {
1569 printerr(0, "DH key derivation failed: %s\n",
1570 ERR_error_string(ERR_get_error(), NULL));
1574 rc = GSS_S_COMPLETE;
1576 BN_free(remote_pub_key);
1577 #endif /* HAVE_OPENSSL_EVP_PKEY */
1582 * Computes a session key based on the DH parameters from the host and its peer
1584 * \param[in,out] skc Shared key credentials structure with
1585 * the session key populated with the
1587 * \param[in] pub_key Public key returned from peer in
1589 * \return gss error failure
1590 * \return GSS_S_COMPLETE success
1592 uint32_t sk_compute_dh_key(struct sk_cred *skc, const gss_buffer_desc *pub_key)
1594 size_t expected_len;
1597 rc = __sk_compute_dh_key(skc, pub_key, &expected_len);
1598 if (rc != GSS_S_COMPLETE)
1601 if (skc->sc_dh_shared_key.length < expected_len) {
1602 /* there is around 1 chance out of 256 that the returned
1603 * shared key is shorter than expected
1605 if (skc->sc_dh_shared_key.length >= expected_len - 2) {
1606 int shift = expected_len - skc->sc_dh_shared_key.length;
1608 /* if the key is short by only 1 or 2 bytes, just
1609 * prepend it with 0s
1611 memmove((void *)(skc->sc_dh_shared_key.value + shift),
1612 skc->sc_dh_shared_key.value,
1613 skc->sc_dh_shared_key.length);
1614 memset(skc->sc_dh_shared_key.value, 0, shift);
1616 /* if the key is really too short, return GSS_S_BAD_QOP
1617 * so that the caller can retry to generate
1620 "DH derivation returned a short key of %zu bytes, expected: %zu\n",
1621 skc->sc_dh_shared_key.length, expected_len);
1629 * Creates a serialized buffer for the kernel in the order of struct
1632 * \param[in,out] skc Shared key credentials structure
1633 * \param[in,out] ctx_token Serialized buffer for kernel.
1634 * Caller must free this buffer.
1637 * \return -1 failure
1639 int sk_serialize_kctx(struct sk_cred *skc, gss_buffer_desc *ctx_token)
1641 struct sk_kernel_ctx *kctx = &skc->sc_kctx;
1645 bufsize = sizeof(*kctx) + kctx->skc_hmac_key.length +
1646 kctx->skc_encrypt_key.length;
1648 ctx_token->value = malloc(bufsize);
1649 if (!ctx_token->value)
1651 ctx_token->length = bufsize;
1653 p = ctx_token->value;
1654 end = p + ctx_token->length;
1656 if (WRITE_BYTES(&p, end, kctx->skc_version))
1658 if (WRITE_BYTES(&p, end, kctx->skc_hmac_alg))
1660 if (WRITE_BYTES(&p, end, kctx->skc_crypt_alg))
1662 if (WRITE_BYTES(&p, end, kctx->skc_expire))
1664 if (WRITE_BYTES(&p, end, kctx->skc_host_random))
1666 if (WRITE_BYTES(&p, end, kctx->skc_peer_random))
1668 if (write_buffer(&p, end, &kctx->skc_hmac_key))
1670 if (write_buffer(&p, end, &kctx->skc_encrypt_key))
1673 printerr(2, "Serialized buffer of %zu bytes for kernel\n", bufsize);
1679 * Decodes a netstring \a ns into array of gss_buffer_descs at \a bufs
1680 * up to \a numbufs. Memory is allocated for each value and length
1681 * will be populated with the length
1683 * \param[in,out] bufs Array of gss_buffer_descs
1684 * \param[in,out] numbufs number of gss_buffer_desc in array
1685 * \param[in] ns netstring to decode
1687 * \return buffers populated success
1688 * \return -1 failure
1690 int sk_decode_netstring(gss_buffer_desc *bufs, int numbufs, gss_buffer_desc *ns)
1692 char *ptr = ns->value;
1693 size_t remain = ns->length;
1700 for (i = 0; i < numbufs; i++) {
1701 /* read the size of first buffer */
1702 rc = sscanf(ptr, "%9u", &size);
1705 digits = (size) ? ceil(log10(size + 1)) : 1;
1707 /* sep of current string */
1708 sep = size + digits + 2;
1710 /* check to make sure it's valid */
1711 if (remain < sep || ptr[digits] != ':' ||
1712 ptr[sep - 1] != ',')
1715 bufs[i].length = size;
1717 bufs[i].value = NULL;
1719 bufs[i].value = malloc(size);
1722 memcpy(bufs[i].value, &ptr[digits + 1], size);
1729 printerr(2, "Decoded netstring of %zu bytes\n", ns->length);
1735 free(bufs[i].value);
1742 * Creates a netstring in a gss_buffer_desc that consists of all
1743 * the gss_buffer_desc found in \a bufs. The netstring should be treated
1744 * as binary as it can contain null characters.
1746 * \param[in] bufs Array of gss_buffer_desc to use as input
1747 * \param[in] numbufs Number of buffers in array
1748 * \param[in,out] ns Destination gss_buffer_desc to hold
1751 * \return -1 failure
1754 int sk_encode_netstring(gss_buffer_desc *bufs, int numbufs,
1755 gss_buffer_desc *ns)
1762 /* size of string in decimal, string size, colon, and comma */
1763 for (i = 0; i < numbufs; i++) {
1765 if (bufs[i].length == 0)
1768 size += ceil(log10(bufs[i].length + 1)) +
1773 ns->value = malloc(ns->length);
1780 for (i = 0; i < numbufs; i++) {
1782 rc = scnprintf((char *) ptr, size, "%zu:", bufs[i].length);
1786 memcpy(ptr, bufs[i].value, bufs[i].length);
1787 ptr += bufs[i].length;
1792 size -= bufs[i].length + rc + 1;
1794 /* should not happen */
1799 printerr(2, "Encoded netstring of %zu bytes\n", ns->length);