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, Intel Corporation.
27 * Author: Jeremy Filizetti <jfilizet@iu.edu>
40 #include <sys/types.h>
43 #include <lnet/nidstr.h>
44 #include <lustre/lustre_idl.h>
53 /* One week default expiration */
54 #define SK_DEFAULT_EXPIRE 604800
55 #define SK_DEFAULT_SK_KEYLEN 256
56 #define SK_DEFAULT_PRIME_BITS 2048
57 #define SK_DEFAULT_NODEMAP "default"
59 /* Names match up with openssl enc and dgst commands */
60 char *sk_crypt2name[] = {
61 [SK_CRYPT_EMPTY] = "NONE",
62 [SK_CRYPT_AES256_CTR] = "AES-256-CTR",
65 const char *sk_hmac2name[] = { "NONE", "SHA256", "SHA512" };
67 static int sk_name2crypt(char *name)
71 for (i = 0; i < SK_CRYPT_MAX; i++) {
72 if (strcasecmp(name, sk_crypt2name[i]) == 0)
76 return SK_CRYPT_INVALID;
79 enum cfs_crypto_hash_alg sk_name2hmac(char *name)
81 enum cfs_crypto_hash_alg algo;
84 /* convert to lower case */
86 putchar(tolower(name[i]));
90 if (strcmp(name, "none"))
91 return CFS_HASH_ALG_NULL;
93 algo = cfs_crypto_hash_alg(name);
94 if ((algo != CFS_HASH_ALG_SHA256) ||
95 (algo != CFS_HASH_ALG_SHA512))
96 return SK_HMAC_INVALID;
101 static void usage(FILE *fp, char *program)
105 fprintf(fp, "Usage %s [OPTIONS] {-l|-m|-r|-w} <keyfile>\n", program);
106 fprintf(fp, "-l|--load <keyfile> Load key from file into user's "
107 "session keyring\n");
108 fprintf(fp, "-m|--modify <keyfile> Modify keyfile's attributes\n");
109 fprintf(fp, "-r|--read <keyfile> Show keyfile's attributes\n");
110 fprintf(fp, "-w|--write <keyfile> Generate keyfile\n\n");
111 fprintf(fp, "Modify/Write Options:\n");
112 fprintf(fp, "-c|--crypt <num> Cipher for encryption "
113 "(Default: AES Counter mode)\n");
114 for (i = 1; i < SK_CRYPT_MAX; i++)
115 fprintf(fp, " %s\n", sk_crypt2name[i]);
117 fprintf(fp, "-i|--hmac <num> Hash algorithm for integrity "
118 "(Default: SHA256)\n");
119 for (i = 1; i < sizeof(sk_hmac2name) / sizeof(sk_hmac2name[0]); i++)
120 fprintf(fp, " %s\n", sk_hmac2name[i]);
122 fprintf(fp, "-e|--expire <num> Seconds before contexts from "
123 "key expire (Default: %d seconds (%.3g days))\n",
124 SK_DEFAULT_EXPIRE, (double)SK_DEFAULT_EXPIRE / 3600 / 24);
125 fprintf(fp, "-f|--fsname <name> File system name for key\n");
126 fprintf(fp, "-g|--mgsnids <nids> Comma seperated list of MGS "
127 "NIDs. Only required when mgssec is used (Default: \"\")\n");
128 fprintf(fp, "-n|--nodemap <name> Nodemap name for key "
129 "(Default: \"%s\")\n", SK_DEFAULT_NODEMAP);
130 fprintf(fp, "-p|--prime-bits <len> Prime length (p) for DHKE in "
131 "bits (Default: %d)\n", SK_DEFAULT_PRIME_BITS);
132 fprintf(fp, "-t|--type <type> Key type (mgs, server, "
134 fprintf(fp, "-k|--key-bits <len> Shared key length in bits "
135 "(Default: %d)\n", SK_DEFAULT_SK_KEYLEN);
136 fprintf(fp, "-d|--data <file> Key random data source "
137 "(Default: /dev/random)\n\n");
138 fprintf(fp, "Other Options:\n");
139 fprintf(fp, "-v|--verbose Increase verbosity for errors\n");
143 static ssize_t get_key_data(char *src, void *buffer, size_t bits)
150 /* convert bits to minimum number of bytes */
151 remain = (bits + 7) / 8;
153 printf("Reading random data for shared key from '%s'\n", src);
154 fd = open(src, O_RDONLY);
156 fprintf(stderr, "error: opening '%s': %s\n", src,
162 rc = read(fd, ptr, remain);
166 fprintf(stderr, "error: reading from '%s': %s\n", src,
171 } else if (rc == 0) {
173 "error: key source too short for %zd-bit key\n",
188 static int write_config_file(char *output_file,
189 struct sk_keyfile_config *config, bool overwrite)
193 int flags = O_WRONLY | O_CREAT;
198 sk_config_cpu_to_disk(config);
200 fd = open(output_file, flags, 0400);
202 fprintf(stderr, "error: opening '%s': %s\n", output_file,
207 rc = write(fd, config, sizeof(*config));
209 fprintf(stderr, "error: writing to '%s': %s\n", output_file,
212 } else if (rc != sizeof(*config)) {
213 fprintf(stderr, "error: short write to '%s'\n", output_file);
224 static int print_config(char *filename)
226 struct sk_keyfile_config *config;
229 config = sk_read_file(filename);
233 if (sk_validate_config(config)) {
234 fprintf(stderr, "error: key configuration failed validation\n");
239 printf("Version: %u\n", config->skc_version);
241 if (config->skc_type & SK_TYPE_MGS)
243 if (config->skc_type & SK_TYPE_SERVER)
245 if (config->skc_type & SK_TYPE_CLIENT)
248 printf("HMAC alg: %s\n", sk_hmac2name[config->skc_hmac_alg]);
249 printf("Crypto alg: %s\n", cfs_crypto_hash_name(config->skc_hmac_alg));
250 printf("Ctx Expiration: %u seconds\n", config->skc_expire);
251 printf("Shared keylen: %u bits\n", config->skc_shared_keylen);
252 printf("Prime length: %u bits\n", config->skc_prime_bits);
253 printf("File system: %s\n", config->skc_fsname);
254 printf("MGS NIDs: ");
255 for (i = 0; i < MAX_MGSNIDS; i++) {
256 if (config->skc_mgsnids[i] == LNET_NID_ANY)
258 printf(" %s", libcfs_nid2str(config->skc_mgsnids[i]));
261 printf("Nodemap name: %s\n", config->skc_nodemap);
262 printf("Shared key:\n");
263 print_hex(0, config->skc_shared_key, config->skc_shared_keylen / 8);
265 /* Don't print empty keys */
266 for (i = 0; i < SK_MAX_P_BYTES; i++)
267 if (config->skc_p[i] != 0)
270 if (i != SK_MAX_P_BYTES) {
271 printf("Prime (p):\n");
272 print_hex(0, config->skc_p, config->skc_prime_bits / 8);
279 static int parse_mgsnids(char *mgsnids, struct sk_keyfile_config *config)
288 /* replace all old values */
289 for (i = 0; i < MAX_MGSNIDS; i++)
290 config->skc_mgsnids[i] = LNET_NID_ANY;
293 end = mgsnids + strlen(mgsnids);
295 while (ptr < end && i < MAX_MGSNIDS) {
296 sep = strstr(ptr, ",");
300 nid = libcfs_str2nid(ptr);
301 if (nid == LNET_NID_ANY) {
302 fprintf(stderr, "error: invalid MGS NID: %s\n", ptr);
307 config->skc_mgsnids[i++] = nid;
308 ptr += strlen(ptr) + 1;
311 if (i == MAX_MGSNIDS) {
312 fprintf(stderr, "error: more than %u MGS NIDs provided\n", i);
319 int main(int argc, char **argv)
321 struct sk_keyfile_config *config;
322 char *datafile = NULL;
327 char *mgsnids = NULL;
328 char *nodemap = NULL;
332 int crypt = SK_CRYPT_EMPTY;
333 enum cfs_crypto_hash_alg hmac = CFS_HASH_ALG_NULL;
335 int shared_keylen = -1;
340 enum sk_key_type type = SK_TYPE_INVALID;
341 bool generate_prime = false;
344 static struct option long_opt[] = {
345 {"crypt", 1, 0, 'c'},
347 {"expire", 1, 0, 'e'},
348 {"fsname", 1, 0, 'f'},
349 {"mgsnids", 1, 0, 'g'},
352 {"integrity", 1, 0, 'i'},
353 {"key-bits", 1, 0, 'k'},
354 {"shared", 1, 0, 'k'},
356 {"modify", 1, 0, 'm'},
357 {"nodemap", 1, 0, 'n'},
358 {"prime-bits", 1, 0, 'p'},
361 {"verbose", 0, 0, 'v'},
362 {"write", 1, 0, 'w'},
366 while ((opt = getopt_long(argc, argv,
367 "c:d:e:f:g:hi:l:m:n:p:r:s:k:t:w:v", long_opt,
371 crypt = sk_name2crypt(optarg);
377 expire = atoi(optarg);
379 fprintf(stderr, "warning: using a %us key "
380 "expiration may cause issues during "
381 "key renegotiation\n", expire);
385 if (strlen(fsname) > MTI_NAME_MAXLEN) {
387 "error: file system name longer than "
388 "%u characters\n", MTI_NAME_MAXLEN);
396 usage(stdout, argv[0]);
399 hmac = sk_name2hmac(optarg);
402 shared_keylen = atoi(optarg);
412 if (strlen(nodemap) > LUSTRE_NODEMAP_NAME_LENGTH) {
414 "error: nodemap name longer than "
416 LUSTRE_NODEMAP_NAME_LENGTH);
421 prime_bits = atoi(optarg);
422 if (prime_bits <= 0) {
424 "error: invalid prime length: '%s'\n",
433 tmp2 = strdup(optarg);
436 "error: failed to allocate type\n");
439 tmp = strsep(&tmp2, ",");
440 while (tmp != NULL) {
441 if (strcasecmp(tmp, "server") == 0) {
442 type |= SK_TYPE_SERVER;
443 } else if (strcasecmp(tmp, "mgs") == 0) {
445 } else if (strcasecmp(tmp, "client") == 0) {
446 type |= SK_TYPE_CLIENT;
449 "error: invalid type '%s', "
450 "must be mgs, server, or client"
454 tmp = strsep(&tmp2, ",");
465 fprintf(stderr, "error: unknown option: '%c'\n", opt);
471 if (optind != argc) {
473 "error: extraneous arguments provided, check usage\n");
477 if (!input && !output && !load && !modify) {
478 usage(stderr, argv[0]);
482 /* init gss logger for foreground (no syslog) which prints to stderr */
483 initerr(NULL, verbose, 1);
486 return print_config(input);
489 if (sk_load_keyfile(load))
494 if (crypt == SK_CRYPT_INVALID) {
495 fprintf(stderr, "error: invalid crypt algorithm specified\n");
498 if (hmac == SK_HMAC_INVALID) {
499 fprintf(stderr, "error: invalid HMAC algorithm specified\n");
504 config = sk_read_file(modify);
508 if (type != SK_TYPE_INVALID) {
509 /* generate key when adding client type */
510 if (!(config->skc_type & SK_TYPE_CLIENT) &&
511 type & SK_TYPE_CLIENT)
512 generate_prime = true;
513 else if (!(type & SK_TYPE_CLIENT))
514 memset(config->skc_p, 0, SK_MAX_P_BYTES);
516 config->skc_type = type;
518 if (prime_bits != -1) {
519 memset(config->skc_p, 0, SK_MAX_P_BYTES);
520 if (config->skc_prime_bits != prime_bits &&
521 config->skc_type & SK_TYPE_CLIENT)
522 generate_prime = true;
525 /* write mode for a new key */
526 if (!fsname && !mgsnids) {
528 "error: missing --fsname or --mgsnids\n");
532 config = calloc(1, sizeof(*config));
536 /* Set the defaults for new key */
537 config->skc_version = SK_CONF_VERSION;
538 config->skc_expire = SK_DEFAULT_EXPIRE;
539 config->skc_shared_keylen = SK_DEFAULT_SK_KEYLEN;
540 config->skc_prime_bits = SK_DEFAULT_PRIME_BITS;
541 config->skc_crypt_alg = SK_CRYPT_AES256_CTR;
542 config->skc_hmac_alg = CFS_HASH_ALG_SHA256;
543 for (i = 0; i < MAX_MGSNIDS; i++)
544 config->skc_mgsnids[i] = LNET_NID_ANY;
546 if (type == SK_TYPE_INVALID) {
547 fprintf(stderr, "error: no type specified for key\n");
550 config->skc_type = type;
551 generate_prime = type & SK_TYPE_CLIENT;
553 strncpy(config->skc_nodemap, SK_DEFAULT_NODEMAP,
554 strlen(SK_DEFAULT_NODEMAP));
557 datafile = "/dev/random";
560 if (crypt != SK_CRYPT_EMPTY)
561 config->skc_crypt_alg = crypt;
562 if (hmac != CFS_HASH_ALG_NULL)
563 config->skc_hmac_alg = hmac;
565 config->skc_expire = expire;
566 if (shared_keylen != -1)
567 config->skc_shared_keylen = shared_keylen;
568 if (prime_bits != -1)
569 config->skc_prime_bits = prime_bits;
571 strncpy(config->skc_fsname, fsname, strlen(fsname));
573 strncpy(config->skc_nodemap, nodemap, strlen(nodemap));
574 if (mgsnids && parse_mgsnids(mgsnids, config))
576 if (sk_validate_config(config)) {
577 fprintf(stderr, "error: key configuration failed validation\n");
581 if (datafile && get_key_data(datafile, config->skc_shared_key,
582 config->skc_shared_keylen)) {
583 fprintf(stderr, "error: failure getting key data from '%s'\n",
588 if (generate_prime) {
589 printf("Generating DH parameters, this can take a while...\n");
590 dh = DH_generate_parameters(config->skc_prime_bits,
591 SK_GENERATOR, NULL, NULL);
592 if (BN_num_bytes(dh->p) > SK_MAX_P_BYTES) {
593 fprintf(stderr, "error: cannot generate DH parameters: "
594 "requested length %d exceeds maximum %d\n",
595 config->skc_prime_bits, SK_MAX_P_BYTES * 8);
598 if (BN_bn2bin(dh->p, config->skc_p) != BN_num_bytes(dh->p)) {
600 "error: convert BIGNUM p to binary failed\n");
605 if (write_config_file(modify ?: output, config, modify))