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>
37 #include <sys/types.h>
40 #include <lnet/nidstr.h>
41 #include <lustre/lustre_idl.h>
50 /* One week default expiration */
51 #define SK_DEFAULT_EXPIRE 604800
52 #define SK_DEFAULT_SK_KEYLEN 256
53 #define SK_DEFAULT_PRIME_BITS 2048
54 #define SK_DEFAULT_NODEMAP "default"
56 /* Names match up with openssl enc and dgst commands */
57 char *sk_crypt2name[] = {
58 [SK_CRYPT_EMPTY] = "NONE",
59 [SK_CRYPT_AES256_CTR] = "AES-256-CTR",
62 char *sk_hmac2name[] = {
63 [SK_HMAC_EMPTY] = "NONE",
64 [SK_HMAC_SHA256] = "SHA256",
65 [SK_HMAC_SHA512] = "SHA512",
68 int sk_name2crypt(char *name)
72 for (i = 0; i < SK_CRYPT_MAX; i++) {
73 if (strcasecmp(name, sk_crypt2name[i]) == 0)
77 return SK_CRYPT_INVALID;
80 int sk_name2hmac(char *name)
84 for (i = 0; i < SK_HMAC_MAX; i++) {
85 if (strcasecmp(name, sk_hmac2name[i]) == 0)
89 return SK_HMAC_INVALID;
92 void usage(FILE *fp, char *program)
96 fprintf(fp, "Usage %s [OPTIONS] -l <file> | -m <file> | "
97 "-r <file> | -w <file>\n", program);
98 fprintf(fp, "-l|--load <file> Load key from file into user's "
100 fprintf(fp, "-m|--modify <file> Modify a file's key "
102 fprintf(fp, "-r|--read <file> Show file's key attributes\n");
103 fprintf(fp, "-w|--write <file> Generate key file\n\n");
104 fprintf(fp, "Modify/Write Options:\n");
105 fprintf(fp, "-c|--crypt <num> Cipher for encryption "
106 "(Default: AES Counter mode)\n");
107 for (i = 1; i < SK_CRYPT_MAX; i++)
108 fprintf(fp, " %s\n", sk_crypt2name[i]);
110 fprintf(fp, "-i|--hmac <num> Hash algorithm for integrity "
111 "(Default: SHA256)\n");
112 for (i = 1; i < SK_HMAC_MAX; i++)
113 fprintf(fp, " %s\n", sk_hmac2name[i]);
115 fprintf(fp, "-e|--expire <num> Seconds before contexts from "
116 "key expire (Default: %d seconds)\n", SK_DEFAULT_EXPIRE);
117 fprintf(fp, "-f|--fsname <name> File system name for key\n");
118 fprintf(fp, "-g|--mgsnids <nids> Comma seperated list of MGS "
119 "NIDs. Only required when mgssec is used (Default: "
121 fprintf(fp, "-n|--nodemap <name> Nodemap name for key "
122 "(Default: \"%s\")\n", SK_DEFAULT_NODEMAP);
123 fprintf(fp, "-p|--prime-bits <len> Prime length (p) for DHKE in "
124 "bits (Default: %d)\n", SK_DEFAULT_PRIME_BITS);
125 fprintf(fp, "-t|--type <type> Key type (mgs, server, "
127 fprintf(fp, "-k|--shared <len> Shared key length in bits "
128 "(Default: %d)\n", SK_DEFAULT_SK_KEYLEN);
129 fprintf(fp, "-d|--data <file> Shared key data source "
130 "(Default: /dev/random)\n\n");
131 fprintf(fp, "Other Options:\n");
132 fprintf(fp, "-v|--verbose Increase verbosity for "
137 ssize_t get_key_data(char *src, void *buffer, size_t bits)
144 /* convert bits to minimum number of bytes */
145 remain = (bits + 7) / 8;
147 printf("Reading data for shared key from %s\n", src);
148 fd = open(src, O_RDONLY);
150 fprintf(stderr, "Failed to open %s: %s\n", src,
156 rc = read(fd, ptr, remain);
160 fprintf(stderr, "Error reading from %s: %s\n", src,
165 } else if (rc == 0) {
166 fprintf(stderr, "Key source too short for key size\n");
180 int write_config_file(char *output_file, struct sk_keyfile_config *config,
185 int flags = O_WRONLY | O_CREAT;
190 sk_config_cpu_to_disk(config);
192 fd = open(output_file, flags, 0400);
194 fprintf(stderr, "Failed to open %s: %s\n", output_file,
199 rc = write(fd, config, sizeof(*config));
201 fprintf(stderr, "Error writing to %s: %s\n", output_file,
205 } else if (rc != sizeof(*config)) {
206 fprintf(stderr, "Short write to %s\n", output_file);
217 int print_config(char *filename)
219 struct sk_keyfile_config *config;
222 config = sk_read_file(filename);
226 if (sk_validate_config(config)) {
227 fprintf(stderr, "Key configuration failed validation\n");
232 printf("Version: %u\n", config->skc_version);
234 if (config->skc_type & SK_TYPE_MGS)
236 if (config->skc_type & SK_TYPE_SERVER)
238 if (config->skc_type & SK_TYPE_CLIENT)
241 printf("HMAC alg: %s\n", sk_hmac2name[config->skc_hmac_alg]);
242 printf("Crypt alg: %s\n", sk_crypt2name[config->skc_crypt_alg]);
243 printf("Ctx Expiration: %u seconds\n", config->skc_expire);
244 printf("Shared keylen: %u bits\n", config->skc_shared_keylen);
245 printf("Prime length: %u bits\n", config->skc_prime_bits);
246 printf("File system: %s\n", config->skc_fsname);
247 printf("MGS NIDs: ");
248 for (i = 0; i < MAX_MGSNIDS; i++) {
249 if (config->skc_mgsnids[i] == LNET_NID_ANY)
251 printf("%s ", libcfs_nid2str(config->skc_mgsnids[i]));
254 printf("Nodemap name: %s\n", config->skc_nodemap);
255 printf("Shared key:\n");
256 print_hex(0, config->skc_shared_key, config->skc_shared_keylen / 8);
257 printf("Prime (p) :\n");
259 /* Don't print empty keys */
260 for (i = 0; i < SK_MAX_P_BYTES; i++)
261 if (config->skc_p[i] != 0)
264 if (i != SK_MAX_P_BYTES)
265 print_hex(0, config->skc_p, config->skc_prime_bits / 8);
271 int parse_mgsnids(char *mgsnids, struct sk_keyfile_config *config)
280 /* replace all old values */
281 for (i = 0; i < MAX_MGSNIDS; i++)
282 config->skc_mgsnids[i] = LNET_NID_ANY;
285 end = mgsnids + strlen(mgsnids);
287 while (ptr < end && i < MAX_MGSNIDS) {
288 sep = strstr(ptr, ",");
292 nid = libcfs_str2nid(ptr);
293 if (nid == LNET_NID_ANY) {
294 fprintf(stderr, "Invalid MGS NID: %s\n", ptr);
299 config->skc_mgsnids[i++] = nid;
300 ptr += strlen(ptr) + 1;
303 if (i == MAX_MGSNIDS) {
304 fprintf(stderr, "Too many MGS NIDs provided\n");
311 int main(int argc, char **argv)
313 struct sk_keyfile_config *config;
319 char *mgsnids = NULL;
320 char *nodemap = NULL;
324 int crypt = SK_CRYPT_EMPTY;
325 int hmac = SK_HMAC_EMPTY;
327 int shared_keylen = -1;
332 enum sk_key_type type = SK_TYPE_INVALID;
333 bool generate_prime = false;
336 static struct option long_opt[] = {
337 {"crypt", 1, 0, 'c'},
339 {"expire", 1, 0, 'e'},
340 {"fsname", 1, 0, 'f'},
341 {"mgsnids", 1, 0, 'g'},
344 {"shared", 1, 0, 'k'},
346 {"modify", 1, 0, 'm'},
347 {"nodemap", 1, 0, 'n'},
348 {"prime-bits", 1, 0, 'p'},
351 {"verbose", 0, 0, 'v'},
352 {"write", 1, 0, 'w'},
356 while ((opt = getopt_long(argc, argv,
357 "c:d:e:f:g:hi:l:m:n:p:r:s:k:t:w:v", long_opt,
361 crypt = sk_name2crypt(optarg);
367 expire = atoi(optarg);
369 fprintf(stderr, "WARNING: Using a short key "
370 "expiration may cause issues during "
371 "key renegotiation\n");
375 if (strlen(fsname) > MTI_NAME_MAXLEN) {
376 fprintf(stderr, "File system name too long\n");
384 usage(stdout, argv[0]);
387 hmac = sk_name2hmac(optarg);
390 shared_keylen = atoi(optarg);
400 if (strlen(nodemap) > LUSTRE_NODEMAP_NAME_LENGTH) {
401 fprintf(stderr, "Nodemap name too long\n");
406 prime_bits = atoi(optarg);
407 if (prime_bits <= 0) {
408 fprintf(stderr, "Invalid prime length: %s\n",
417 tmp2 = strdup(optarg);
419 fprintf(stderr, "Failed to allocated memory "
420 "for type argument\n");
423 tmp = strsep(&tmp2, ",");
424 while (tmp != NULL) {
425 if (strcasecmp(tmp, "server") == 0) {
426 type |= SK_TYPE_SERVER;
427 } else if (strcasecmp(tmp, "mgs") == 0) {
429 } else if (strcasecmp(tmp, "client") == 0) {
430 type |= SK_TYPE_CLIENT;
432 fprintf(stderr, "Invalid type must be "
433 "mgs, server, or client: "
437 tmp = strsep(&tmp2, ",");
448 fprintf(stderr, "Unknown option: %c\n", opt);
454 if (optind != argc) {
455 fprintf(stderr, "Extraneous arguments provided, check usage\n");
459 if (!input && !output && !load && !modify) {
460 usage(stderr, argv[0]);
464 /* init gss logger for foreground (no syslog) which prints to stderr */
465 initerr(NULL, verbose, 1);
468 return print_config(input);
471 if (sk_load_keyfile(load))
476 if (crypt == SK_CRYPT_INVALID) {
477 fprintf(stderr, "Invalid crypt algorithm specified\n");
480 if (hmac == SK_HMAC_INVALID) {
481 fprintf(stderr, "Invalid HMAC algorithm specified\n");
486 config = sk_read_file(modify);
490 if (crypt != SK_CRYPT_EMPTY)
491 config->skc_crypt_alg = crypt;
492 if (hmac != SK_HMAC_EMPTY)
493 config->skc_hmac_alg = hmac;
495 config->skc_expire = expire;
496 if (shared_keylen != -1)
497 config->skc_shared_keylen = shared_keylen;
498 if (type != SK_TYPE_INVALID) {
499 /* generate key when adding client type */
500 if (!(config->skc_type & SK_TYPE_CLIENT) &&
501 type & SK_TYPE_CLIENT)
502 generate_prime = true;
503 else if (!(type & SK_TYPE_CLIENT))
504 memset(config->skc_p, 0, SK_MAX_P_BYTES);
506 config->skc_type = type;
508 if (prime_bits != -1) {
509 memset(config->skc_p, 0, SK_MAX_P_BYTES);
510 if (config->skc_prime_bits != prime_bits &&
511 config->skc_type & SK_TYPE_CLIENT)
512 generate_prime = true;
513 config->skc_prime_bits = prime_bits;
516 strncpy(config->skc_fsname, fsname, strlen(fsname));
518 strncpy(config->skc_nodemap, nodemap, strlen(nodemap));
519 if (mgsnids && parse_mgsnids(mgsnids, config))
521 if (sk_validate_config(config)) {
523 "Key configuration failed validation\n");
527 if (data && get_key_data(data, config->skc_shared_key,
528 config->skc_shared_keylen)) {
529 fprintf(stderr, "Failure getting data for key\n");
533 if (generate_prime) {
534 printf("Generating DH parameters this can take a "
536 dh = DH_generate_parameters(config->skc_prime_bits,
537 SK_GENERATOR, NULL, NULL);
538 if (BN_num_bytes(dh->p) > SK_MAX_P_BYTES) {
539 fprintf(stderr, "Cannot generate DH parameters:"
540 " requested length %d exceeds maximum: "
541 "%d\n", config->skc_prime_bits,
545 if (BN_bn2bin(dh->p, config->skc_p) !=
546 BN_num_bytes(dh->p)) {
547 fprintf(stderr, "Failed conversion of BIGNUM p"
553 if (write_config_file(modify, config, true))
559 /* write mode for a new key */
560 if (!fsname && !mgsnids) {
561 fprintf(stderr, "Must provide --fsname, "
562 "--mgsnids, or both\n");
566 config = malloc(sizeof(*config));
570 /* Set the defaults */
571 memset(config, 0, sizeof(*config));
572 config->skc_version = SK_CONF_VERSION;
573 config->skc_expire = SK_DEFAULT_EXPIRE;
574 config->skc_shared_keylen = SK_DEFAULT_SK_KEYLEN;
575 config->skc_prime_bits = SK_DEFAULT_PRIME_BITS;
576 config->skc_crypt_alg = SK_CRYPT_AES256_CTR;
577 config->skc_hmac_alg = SK_HMAC_SHA256;
578 for (i = 0; i < MAX_MGSNIDS; i++)
579 config->skc_mgsnids[i] = LNET_NID_ANY;
581 if (crypt != SK_CRYPT_EMPTY)
582 config->skc_crypt_alg = crypt;
583 if (hmac != SK_HMAC_EMPTY)
584 config->skc_hmac_alg = hmac;
586 config->skc_expire = expire;
587 if (shared_keylen != -1)
588 config->skc_shared_keylen = shared_keylen;
589 if (prime_bits != -1)
590 config->skc_prime_bits = prime_bits;
592 strncpy(config->skc_fsname, fsname, strlen(fsname));
594 strncpy(config->skc_nodemap, nodemap, strlen(nodemap));
596 strncpy(config->skc_nodemap, SK_DEFAULT_NODEMAP,
597 strlen(SK_DEFAULT_NODEMAP));
599 if (mgsnids && parse_mgsnids(mgsnids, config))
601 if (type == SK_TYPE_INVALID) {
602 fprintf(stderr, "No type specified for key\n");
605 config->skc_type = type;
607 if (sk_validate_config(config)) {
608 fprintf(stderr, "Key configuration failed validation\n");
613 data = "/dev/random";
614 if (get_key_data(data, config->skc_shared_key,
615 config->skc_shared_keylen)) {
616 fprintf(stderr, "Failure getting data for key\n");
620 if (type & SK_TYPE_CLIENT) {
621 printf("Generating DH parameters this can take a while...\n");
622 dh = DH_generate_parameters(config->skc_prime_bits,
623 SK_GENERATOR, NULL, NULL);
624 if (BN_num_bytes(dh->p) > SK_MAX_P_BYTES) {
625 fprintf(stderr, "Cannot generate DH parameters: "
626 "requested length %d exceeds maximum: %d\n",
627 config->skc_prime_bits, SK_MAX_P_BYTES * 8);
630 if (BN_bn2bin(dh->p, config->skc_p) != BN_num_bytes(dh->p)) {
631 fprintf(stderr, "Failed conversion of BIGNUM p to "
637 if (write_config_file(output, config, false))