Whamcloud - gitweb
LU-17662 osd-zfs: Support for ZFS 2.2.3
[fs/lustre-release.git] / lustre / utils / gss / lgss_sk.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
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.
9  *
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).
15  *
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
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (C) 2015, Trustees of Indiana University
24  *
25  * Copyright (c) 2016, Intel Corporation.
26  *
27  * Author: Jeremy Filizetti <jfilizet@iu.edu>
28  */
29
30 #include <ctype.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <getopt.h>
34 #include <limits.h>
35 #include <stdarg.h>
36 #include <stdbool.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <stdlib.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <unistd.h>
43 #include <linux/lustre/lustre_user.h>
44
45 #include "sk_utils.h"
46 #include "err_util.h"
47
48 #ifndef _GNU_SOURCE
49 #define _GNU_SOURCE
50 #endif
51
52 /* One week default expiration */
53 #define SK_DEFAULT_EXPIRE 604800
54 /* But only one day in FIPS mode */
55 #define SK_DEFAULT_EXPIRE_FIPS 86400
56 #define SK_DEFAULT_SK_KEYLEN 256
57 #define SK_DEFAULT_PRIME_BITS 2048
58 #define SK_DEFAULT_NODEMAP "default"
59
60 static int fips_mode;
61
62 static void usage(FILE *fp, char *program)
63 {
64         int i;
65
66         fprintf(fp, "Usage %s [OPTIONS] {-l|-m|-r|-w} <keyfile>\n", program);
67         fprintf(fp, "-l|--load       <keyfile>  Load key from file into user's "
68                 "session keyring\n");
69         fprintf(fp, "-m|--modify     <keyfile>  Modify keyfile's attributes\n");
70         fprintf(fp, "-r|--read       <keyfile>  Show keyfile's attributes\n");
71         fprintf(fp, "-w|--write      <keyfile>  Generate keyfile\n\n");
72         fprintf(fp, "Modify/Write Options:\n");
73         fprintf(fp, "-c|--crypt      <num>      Cipher for encryption "
74                 "(Default: AES Counter mode)\n");
75         for (i = 1; i < ARRAY_SIZE(sk_crypt_algs); i++)
76                 fprintf(fp, "                        %s\n",
77                         sk_crypt_algs[i].sct_name);
78         fprintf(fp, "-i|--hmac       <num>      Hash algorithm for integrity "
79                 "(Default: SHA256)\n");
80         for (i = 1; i < ARRAY_SIZE(sk_hmac_algs); i++)
81                 fprintf(fp, "                        %s\n",
82                         sk_hmac_algs[i].sht_name);
83         fprintf(fp, "-e|--expire     <num>      Seconds before contexts from "
84                 "key expire (Default: %d seconds (%.3g days))\n",
85                 SK_DEFAULT_EXPIRE, (double)SK_DEFAULT_EXPIRE / 3600 / 24);
86         fprintf(fp, "-f|--fsname     <name>     File system name for key\n");
87         fprintf(fp, "-g|--mgsnids    <nids>     Comma seperated list of MGS "
88                 "NIDs.  Only required when mgssec is used (Default: \"\")\n");
89         fprintf(fp, "-n|--nodemap    <name>     Nodemap name for key "
90                 "(Default: \"%s\")\n", SK_DEFAULT_NODEMAP);
91         fprintf(fp, "-p|--prime-bits <len>      Prime length (p) for DHKE in "
92                 "bits (Default: %d)\n", SK_DEFAULT_PRIME_BITS);
93         fprintf(fp, "-t|--type       <type>     Key type (mgs, server, "
94                 "client)\n");
95         fprintf(fp, "-k|--key-bits   <len>      Shared key length in bits "
96                 "(Default: %d)\n", SK_DEFAULT_SK_KEYLEN);
97         fprintf(fp, "-d|--data       <file>     Key data source for new keys "
98                 "(Default: /dev/random)\n");
99         fprintf(fp, "                        Not a seed value. "
100                 "This is the actual key value.\n\n");
101         fprintf(fp, "Other Options:\n");
102         fprintf(fp, "-v|--verbose           Increase verbosity for errors\n");
103         exit(EXIT_FAILURE);
104 }
105
106 static ssize_t get_key_data(char *src, void *buffer, size_t bits)
107 {
108         char *ptr = buffer;
109         size_t remain;
110         ssize_t rc;
111         int fd;
112
113         /* convert bits to minimum number of bytes */
114         remain = (bits + 7) / 8;
115
116         printf("Reading random data for shared key from '%s'\n", src);
117         fd = open(src, O_RDONLY);
118         if (fd < 0) {
119                 fprintf(stderr, "error: opening '%s': %s\n", src,
120                         strerror(errno));
121                 return -errno;
122         }
123
124         while (remain > 0) {
125                 rc = read(fd, ptr, remain);
126                 if (rc < 0) {
127                         if (errno == EINTR)
128                                 continue;
129                         fprintf(stderr, "error: reading from '%s': %s\n", src,
130                                 strerror(errno));
131                         rc = -errno;
132                         goto out;
133
134                 } else if (rc == 0) {
135                         fprintf(stderr,
136                                 "error: key source too short for %zd-bit key\n",
137                                 bits);
138                         rc = -ENODATA;
139                         goto out;
140                 }
141                 ptr += rc;
142                 remain -= rc;
143         }
144         rc = 0;
145
146 out:
147         close(fd);
148         return rc;
149 }
150
151 static int write_config_file(char *output_file,
152                              struct sk_keyfile_config *config, bool overwrite)
153 {
154         size_t rc;
155         int fd;
156         int flags = O_WRONLY | O_CREAT;
157
158         if (!overwrite)
159                 flags |= O_EXCL;
160
161         sk_config_cpu_to_disk(config);
162
163         fd = open(output_file, flags, 0400);
164         if (fd < 0) {
165                 fprintf(stderr, "error: opening '%s': %s\n", output_file,
166                         strerror(errno));
167                 return -errno;
168         }
169
170         rc = write(fd, config, sizeof(*config));
171         if (rc < 0) {
172                 fprintf(stderr, "error: writing to '%s': %s\n", output_file,
173                         strerror(errno));
174                 rc = -errno;
175         } else if (rc != sizeof(*config)) {
176                 fprintf(stderr, "error: short write to '%s'\n", output_file);
177                 rc = -ENOSPC;
178
179         } else {
180                 rc = 0;
181         }
182
183         close(fd);
184         return rc;
185 }
186
187 static int print_config(char *filename)
188 {
189         struct sk_keyfile_config *config;
190         int i;
191
192         config = sk_read_file(filename);
193         if (!config)
194                 return EXIT_FAILURE;
195
196         if (sk_validate_config(config)) {
197                 fprintf(stderr, "error: key configuration failed validation\n");
198                 free(config);
199                 return EXIT_FAILURE;
200         }
201
202         printf("Version:        %u\n", config->skc_version);
203         printf("Type:          ");
204         if (config->skc_type & SK_TYPE_MGS)
205                 printf(" mgs");
206         if (config->skc_type & SK_TYPE_SERVER)
207                 printf(" server");
208         if (config->skc_type & SK_TYPE_CLIENT)
209                 printf(" client");
210         printf("\n");
211         printf("HMAC alg:       %s\n", sk_hmac2name(config->skc_hmac_alg));
212         printf("Crypto alg:     %s\n", sk_crypt2name(config->skc_crypt_alg));
213         printf("Ctx Expiration: %u seconds\n", config->skc_expire);
214         printf("Shared keylen:  %u bits\n", config->skc_shared_keylen);
215         printf("Prime length:   %u bits\n", config->skc_prime_bits);
216         printf("File system:    %s\n", config->skc_fsname);
217         printf("MGS NIDs:      ");
218         for (i = 0; i < MAX_MGSNIDS; i++) {
219                 if (config->skc_mgsnids[i] == LNET_NID_ANY)
220                         continue;
221                 printf(" %s", libcfs_nid2str(config->skc_mgsnids[i]));
222         }
223         printf("\n");
224         printf("Nodemap name:   %s\n", config->skc_nodemap);
225         printf("Shared key:\n");
226         print_hex(0, config->skc_shared_key, config->skc_shared_keylen / 8);
227
228         /* Don't print empty keys */
229         for (i = 0; i < SK_MAX_P_BYTES; i++)
230                 if (config->skc_p[i] != 0)
231                         break;
232
233         if (i != SK_MAX_P_BYTES) {
234                 printf("Prime (p):\n");
235                 print_hex(0, config->skc_p, config->skc_prime_bits / 8);
236         }
237
238         free(config);
239         return EXIT_SUCCESS;
240 }
241
242 static int parse_mgsnids(char *mgsnids, struct sk_keyfile_config *config)
243 {
244         lnet_nid_t nid;
245         char *ptr;
246         char *sep;
247         char *end;
248         int rc = 0;
249         int i;
250
251         /* replace all old values */
252         for (i = 0; i < MAX_MGSNIDS; i++)
253                 config->skc_mgsnids[i] = LNET_NID_ANY;
254
255         i = 0;
256         end = mgsnids + strlen(mgsnids);
257         ptr = mgsnids;
258         while (ptr < end && i < MAX_MGSNIDS) {
259                 sep = strstr(ptr, ",");
260                 if (sep != NULL)
261                         *sep = '\0';
262
263                 nid = libcfs_str2nid(ptr);
264                 if (nid == LNET_NID_ANY) {
265                         fprintf(stderr, "error: invalid MGS NID: %s\n", ptr);
266                         rc = -EINVAL;
267                         break;
268                 }
269
270                 config->skc_mgsnids[i++] = nid;
271                 ptr += strlen(ptr) + 1;
272         }
273
274         if (i == MAX_MGSNIDS) {
275                 fprintf(stderr, "error: more than %u MGS NIDs provided\n", i);
276                 rc = -E2BIG;
277         }
278
279         return rc;
280 }
281
282 #if !defined(HAVE_OPENSSL_EVP_PKEY) && OPENSSL_VERSION_NUMBER >= 0x10100000L
283 static inline int __fetch_ssk_prime(struct sk_keyfile_config *config)
284 {
285         const BIGNUM *p;
286         DH *dh = NULL;
287         int primenid;
288         int rc = -1;
289
290         primenid = sk_primebits2primenid(config->skc_prime_bits);
291         dh = DH_new_by_nid(primenid);
292         if (!dh) {
293                 fprintf(stderr, "error: dh cannot be init\n");
294                 goto prime_end;
295         }
296
297         p = DH_get0_p(dh);
298         if (!p) {
299                 fprintf(stderr, "error: cannot get p from dh\n");
300                 goto prime_end;
301         }
302
303         if (BN_num_bytes(p) > SK_MAX_P_BYTES) {
304                 fprintf(stderr,
305                         "error: requested length %d exceeds maximum %d\n",
306                         BN_num_bytes(p), SK_MAX_P_BYTES * 8);
307                 goto prime_end;
308         }
309
310         if (BN_bn2bin(p, config->skc_p) != BN_num_bytes(p)) {
311                 fprintf(stderr, "error: convert BIGNUM p to binary failed\n");
312                 goto prime_end;
313         }
314
315         rc = 0;
316
317 prime_end:
318         if (rc)
319                 fprintf(stderr,
320                         "error: fetching SSK prime failed: %s\n",
321                         ERR_error_string(ERR_get_error(), NULL));
322         DH_free(dh);
323         return rc;
324 }
325 #endif
326
327 static inline int __gen_ssk_prime(struct sk_keyfile_config *config)
328 {
329         int rc = -1;
330         const char *primename;
331         EVP_PKEY_CTX *ctx = NULL;
332         EVP_PKEY *dh = NULL;
333         BIGNUM *p;
334
335         if (fips_mode) {
336                 primename = sk_primebits2name(config->skc_prime_bits);
337                 if (!primename) {
338                         fprintf(stderr,
339                                 "error: prime len %d not supported in FIPS mode\n",
340                                 config->skc_prime_bits);
341                         return rc;
342                 }
343 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
344                 fprintf(stdout,
345                         "FIPS mode, using well-known prime %s\n", primename);
346 #ifndef HAVE_OPENSSL_EVP_PKEY
347                 return __fetch_ssk_prime(config);
348 #endif
349 #endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
350         }
351
352         ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL);
353         if (!ctx || EVP_PKEY_paramgen_init(ctx) != 1) {
354                 fprintf(stderr, "error: ctx cannot be init\n");
355                 goto prime_end;
356         }
357
358         if (EVP_PKEY_CTX_set_dh_paramgen_prime_len(ctx,
359                                                  config->skc_prime_bits) <= 0 ||
360             EVP_PKEY_CTX_set_dh_paramgen_generator(ctx, SK_GENERATOR) <= 0) {
361                 fprintf(stderr, "error: cannot set prime or generator\n");
362                 goto prime_end;
363         }
364
365         if (EVP_PKEY_paramgen(ctx, &dh) != 1) {
366                 fprintf(stderr, "error: cannot generate DH parameters\n");
367                 goto prime_end;
368         }
369
370         if (!EVP_PKEY_get_bn_param(dh, OSSL_PKEY_PARAM_FFC_P, &p)) {
371                 fprintf(stderr, "error: cannot get p from dh\n");
372                 goto prime_end;
373         }
374
375         if (BN_num_bytes(p) > SK_MAX_P_BYTES) {
376                 fprintf(stderr,
377                         "error: cannot generate DH parameters: requested length %d exceeds maximum %d\n",
378                         config->skc_prime_bits, SK_MAX_P_BYTES * 8);
379                 goto prime_end;
380         }
381         if (BN_bn2bin(p, config->skc_p) != BN_num_bytes(p)) {
382                 fprintf(stderr,
383                         "error: convert BIGNUM p to binary failed\n");
384                 goto prime_end;
385         }
386
387         rc = 0;
388
389 prime_end:
390         if (rc)
391                 fprintf(stderr,
392                         "error: generating SSK prime failed: %s\n",
393                         ERR_error_string(ERR_get_error(), NULL));
394         EVP_PKEY_free(dh);
395         EVP_PKEY_CTX_free(ctx);
396         return rc;
397 }
398
399 int main(int argc, char **argv)
400 {
401         struct sk_keyfile_config *config;
402         char *datafile = NULL;
403         char *input = NULL;
404         char *load = NULL;
405         char *modify = NULL;
406         char *output = NULL;
407         char *mgsnids = NULL;
408         char *nodemap = NULL;
409         char *fsname = NULL;
410         char *tmp;
411         char *tmp2;
412         int crypt = SK_CRYPT_EMPTY;
413         int hmac = SK_HMAC_EMPTY;
414         int expire = -1;
415         int shared_keylen = -1;
416         int prime_bits = -1;
417         int verbose = 0;
418         int i;
419         int opt;
420         enum sk_key_type type = SK_TYPE_INVALID;
421         bool generate_prime = false;
422
423         static struct option long_opts[] = {
424         { .name = "crypt",      .has_arg = required_argument, .val = 'c'},
425         { .name = "data",       .has_arg = required_argument, .val = 'd'},
426         { .name = "expire",     .has_arg = required_argument, .val = 'e'},
427         { .name = "fsname",     .has_arg = required_argument, .val = 'f'},
428         { .name = "mgsnids",    .has_arg = required_argument, .val = 'g'},
429         { .name = "help",       .has_arg = no_argument,       .val = 'h'},
430         { .name = "hmac",       .has_arg = required_argument, .val = 'i'},
431         { .name = "integrity",  .has_arg = required_argument, .val = 'i'},
432         { .name = "key-bits",   .has_arg = required_argument, .val = 'k'},
433         { .name = "shared",     .has_arg = required_argument, .val = 'k'},
434         { .name = "load",       .has_arg = required_argument, .val = 'l'},
435         { .name = "modify",     .has_arg = required_argument, .val = 'm'},
436         { .name = "nodemap",    .has_arg = required_argument, .val = 'n'},
437         { .name = "prime-bits", .has_arg = required_argument, .val = 'p'},
438         { .name = "read",       .has_arg = required_argument, .val = 'r'},
439         { .name = "type",       .has_arg = required_argument, .val = 't'},
440         { .name = "verbose",    .has_arg = no_argument,       .val = 'v'},
441         { .name = "write",      .has_arg = required_argument, .val = 'w'},
442         { .name = NULL, } };
443
444         while ((opt = getopt_long(argc, argv,
445                                   "c:d:e:f:g:hi:l:m:n:p:r:s:k:t:w:v", long_opts,
446                                   NULL)) != EOF) {
447                 switch (opt) {
448                 case 'c':
449                         crypt = sk_name2crypt(optarg);
450                         break;
451                 case 'd':
452                         datafile = optarg;
453                         break;
454                 case 'e':
455                         expire = atoi(optarg);
456                         if (expire < 60)
457                                 fprintf(stderr, "warning: using a %us key "
458                                         "expiration may cause issues during "
459                                         "key renegotiation\n", expire);
460                         break;
461                 case 'f':
462                         fsname = optarg;
463                         if (strlen(fsname) > MTI_NAME_MAXLEN) {
464                                 fprintf(stderr,
465                                         "error: file system name longer than "
466                                         "%u characters\n", MTI_NAME_MAXLEN);
467                                 return EXIT_FAILURE;
468                         }
469                         break;
470                 case 'g':
471                         mgsnids = optarg;
472                         break;
473                 case 'h':
474                         usage(stdout, argv[0]);
475                         break;
476                 case 'i':
477                         hmac = sk_name2hmac(optarg);
478                         break;
479                 case 'k':
480                         shared_keylen = atoi(optarg);
481                         break;
482                 case 'l':
483                         load = optarg;
484                         break;
485                 case 'm':
486                         modify = optarg;
487                         break;
488                 case 'n':
489                         nodemap = optarg;
490                         if (strlen(nodemap) > LUSTRE_NODEMAP_NAME_LENGTH) {
491                                 fprintf(stderr,
492                                         "error: nodemap name longer than "
493                                         "%u characters\n",
494                                         LUSTRE_NODEMAP_NAME_LENGTH);
495                                 return EXIT_FAILURE;
496                         }
497                         break;
498                 case 'p':
499                         prime_bits = atoi(optarg);
500                         if (prime_bits <= 0) {
501                                 fprintf(stderr,
502                                         "error: invalid prime length: '%s'\n",
503                                         optarg);
504                                 return EXIT_FAILURE;
505                         }
506                         break;
507                 case 'r':
508                         input = optarg;
509                         break;
510                 case 't':
511                         tmp2 = strdup(optarg);
512                         if (!tmp2) {
513                                 fprintf(stderr,
514                                         "error: failed to allocate type\n");
515                                 return EXIT_FAILURE;
516                         }
517                         tmp = strsep(&tmp2, ",");
518                         while (tmp != NULL) {
519                                 if (strcasecmp(tmp, "server") == 0) {
520                                         type |= SK_TYPE_SERVER;
521                                 } else if (strcasecmp(tmp, "mgs") == 0) {
522                                         type |= SK_TYPE_MGS;
523                                 } else if (strcasecmp(tmp, "client") == 0) {
524                                         type |= SK_TYPE_CLIENT;
525                                 } else {
526                                         fprintf(stderr,
527                                                 "error: invalid type '%s', "
528                                                 "must be mgs, server, or client"
529                                                 "\n", optarg);
530                                         return EXIT_FAILURE;
531                                 }
532                                 tmp = strsep(&tmp2, ",");
533                         }
534                         free(tmp2);
535                         break;
536                 case 'v':
537                         verbose++;
538                         break;
539                 case 'w':
540                         output = optarg;
541                         break;
542                 default:
543                         fprintf(stderr, "error: unknown option: '%c'\n", opt);
544                         return EXIT_FAILURE;
545                         break;
546                 }
547         }
548
549         if (optind != argc) {
550                 fprintf(stderr,
551                         "error: extraneous arguments provided, check usage\n");
552                 return EXIT_FAILURE;
553         }
554
555         if (!input && !output && !load && !modify) {
556                 usage(stderr, argv[0]);
557                 return EXIT_FAILURE;
558         }
559
560         /* init gss logger for foreground (no syslog) which prints to stderr */
561         initerr(NULL, verbose, 1);
562
563         fips_mode = FIPS_mode();
564
565         if (input)
566                 return print_config(input);
567
568         if (load) {
569                 if (sk_load_keyfile(load))
570                         return EXIT_FAILURE;
571                 return EXIT_SUCCESS;
572         }
573
574         if (crypt == SK_CRYPT_INVALID) {
575                 fprintf(stderr, "error: invalid crypt algorithm specified\n");
576                 return EXIT_FAILURE;
577         }
578         if (hmac == SK_HMAC_INVALID) {
579                 fprintf(stderr, "error: invalid HMAC algorithm specified\n");
580                 return EXIT_FAILURE;
581         }
582
583         if (modify && datafile) {
584                 fprintf(stderr,
585                         "error: data file option not valid in key modify\n");
586                 return EXIT_FAILURE;
587         }
588
589         if (modify) {
590                 config = sk_read_file(modify);
591                 if (!config)
592                         return EXIT_FAILURE;
593
594                 if (type != SK_TYPE_INVALID) {
595                         /* generate key when adding client type */
596                         if (!(config->skc_type & SK_TYPE_CLIENT) &&
597                             type & SK_TYPE_CLIENT)
598                                 generate_prime = true;
599                         else if (!(type & SK_TYPE_CLIENT))
600                                 memset(config->skc_p, 0, SK_MAX_P_BYTES);
601
602                         config->skc_type = type;
603                 }
604                 if (prime_bits != -1) {
605                         memset(config->skc_p, 0, SK_MAX_P_BYTES);
606                         if (config->skc_prime_bits != prime_bits &&
607                             config->skc_type & SK_TYPE_CLIENT)
608                                 generate_prime = true;
609                 }
610         } else {
611                 /* write mode for a new key */
612                 if (!fsname && !mgsnids) {
613                         fprintf(stderr,
614                                 "error: missing --fsname or --mgsnids\n");
615                         return EXIT_FAILURE;
616                 }
617
618                 config = calloc(1, sizeof(*config));
619                 if (!config)
620                         return EXIT_FAILURE;
621
622                 /* Set the defaults for new key */
623                 config->skc_version = SK_CONF_VERSION;
624                 config->skc_expire = fips_mode ?
625                         SK_DEFAULT_EXPIRE_FIPS : SK_DEFAULT_EXPIRE;
626                 config->skc_shared_keylen = SK_DEFAULT_SK_KEYLEN;
627                 config->skc_prime_bits = SK_DEFAULT_PRIME_BITS;
628                 config->skc_crypt_alg = SK_CRYPT_AES256_CTR;
629                 config->skc_hmac_alg = SK_HMAC_SHA256;
630                 for (i = 0; i < MAX_MGSNIDS; i++)
631                         config->skc_mgsnids[i] = LNET_NID_ANY;
632
633                 if (type == SK_TYPE_INVALID) {
634                         fprintf(stderr, "error: no type specified for key\n");
635                         goto error;
636                 }
637                 config->skc_type = type;
638                 generate_prime = type & SK_TYPE_CLIENT;
639
640                 /* SK_DEFAULT_NODEMAP is made to fit in skc_nodemap */
641                 strcpy(config->skc_nodemap, SK_DEFAULT_NODEMAP);
642
643                 if (!datafile)
644                         datafile = "/dev/random";
645         }
646
647         if (crypt != SK_CRYPT_EMPTY)
648                 config->skc_crypt_alg = crypt;
649         if (hmac != SK_HMAC_EMPTY)
650                 config->skc_hmac_alg = hmac;
651         if (expire != -1)
652                 config->skc_expire = expire;
653         if (fips_mode && config->skc_expire > SK_DEFAULT_EXPIRE_FIPS)
654                 fprintf(stderr,
655                         "warning: using a %us key expiration greater than %us is not recommended in FIPS mode\n",
656                         config->skc_expire, SK_DEFAULT_EXPIRE_FIPS);
657         if (shared_keylen != -1)
658                 config->skc_shared_keylen = shared_keylen;
659         if (prime_bits != -1) {
660 #ifdef HAVE_OPENSSL_EVP_PKEY
661                 /* #define DH_MIN_MODULUS_BITS 512, not exported by OpenSSL */
662                 if (prime_bits < 512) {
663                         fprintf(stderr,
664                                 "error: prime length must be at least 512\n");
665                         return EXIT_FAILURE;
666                 }
667 #endif
668                 config->skc_prime_bits = prime_bits;
669         }
670         if (fsname)
671                 /* fsname string length was checked when parsing
672                  * command-line options
673                  */
674                 strcpy(config->skc_fsname, fsname);
675         if (nodemap)
676                 /* nodemap string length was checked when parsing
677                  * command-line options
678                  */
679                 strcpy(config->skc_nodemap, nodemap);
680         if (mgsnids && parse_mgsnids(mgsnids, config))
681                 goto error;
682         if (sk_validate_config(config)) {
683                 fprintf(stderr, "error: key configuration failed validation\n");
684                 goto error;
685         }
686
687         if (datafile && get_key_data(datafile, config->skc_shared_key,
688                                      config->skc_shared_keylen)) {
689                 fprintf(stderr, "error: failure getting key data from '%s'\n",
690                         datafile);
691                 goto error;
692         }
693
694         if (generate_prime) {
695                 printf("Generating DH parameters, this can take a while...\n");
696                 if (__gen_ssk_prime(config))
697                         goto error;
698         }
699
700         if (write_config_file(modify ?: output, config, modify))
701                 goto error;
702
703         return EXIT_SUCCESS;
704
705 error:
706         free(config);
707         return EXIT_FAILURE;
708 }