Whamcloud - gitweb
LU-8590 gss: Move DH parameter generation out of upcall 22/23322/5
authorJeremy Filizetti <jeremy.filizetti@gmail.com>
Sun, 2 Oct 2016 19:40:24 +0000 (15:40 -0400)
committerOleg Drokin <oleg.drokin@intel.com>
Wed, 26 Oct 2016 23:02:51 +0000 (23:02 +0000)
This change adds the Diffie-Hellman parameter generation to the
lgss_sk utility prior to key loading.  The parameters are now
persistent to prevent long DH parameter generation times which
can cause mount command and connection timeouts.

This is based on recommendations from Matt Wood at Intel's
security review.

Signed-off-by: Jeremy Filizetti <jeremy.filizetti@gmail.com>
Change-Id: Iba840168da533662ed8ec78004be9e4dc5369c68
Reviewed-on: http://review.whamcloud.com/23322
Tested-by: Jenkins
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: John L. Hammond <john.hammond@intel.com>
Reviewed-by: Andreas Dilger <andreas.dilger@intel.com>
Reviewed-by: Oleg Drokin <oleg.drokin@intel.com>
lustre/doc/Makefile.am
lustre/doc/lgss_sk.8
lustre/utils/gss/lgss_sk.c
lustre/utils/gss/lgss_sk_utils.c
lustre/utils/gss/sk_utils.c
lustre/utils/gss/sk_utils.h
lustre/utils/gss/svcgssd_proc.c
lustre/utils/mount_utils.c

index edd4f7b..2eb8d45 100644 (file)
@@ -55,7 +55,7 @@ MANFILES = lustre.7 lfs.1 mount.lustre.8 lctl.8 lnetctl.8 \
        llapi_hsm_action_progress.3 llapi_hsm_action_get_dfid.3 \
        llapi_hsm_action_get_fd.3 lustreapi.7 llapi_hsm_action_begin.3 \
        llapi_hsm_copytool_register.3 lfs-ladvise.1 llapi_ladvise.3 \
-       ll_decode_linkea.8
+       ll_decode_linkea.8 lgss_sk.8
 
 SERVER_MANFILES = mkfs.lustre.8 tunefs.lustre.8 lshowmount.8
 
index 2954880..b61661f 100644 (file)
@@ -23,11 +23,6 @@ Show file's key attributes.
 .I "-w, --write <keyfile>"
 Generate key file.
 .HP
-Load Options:
-.TP
-.I "-t, --type <type>"
-Key type (mgs, server, client).
-.HP
 Modify/Write Options:
 .TP
 .I "-c, --crypt <num>"
@@ -36,8 +31,8 @@ Cipher for encryption (Default: AES-256-CTR)
 AES-256-CTR
 .RE
 .TP
-.I "-h, --hmac <num>"
-Hash alg for HMAC (Default: SHA256)
+.I "-i, --hmac <num>"
+Hash algorithm for integrity (Default: SHA256)
 .RS
 SHA256
 .br
@@ -56,8 +51,23 @@ Comma seperated list of MGS NIDs.  Only required when mgssec is used (Default: "
 .I "-n, --nodemap <name>"
 Nodemap name for key (Default: "default").
 .TP
-.I "-s, --session <len>"
-Session key length in bits (Default: 1024).
+.I "-p, --prime-bits <len>"
+Length of prime (p) in bits used for the DHKE (Default: 2048).  This is
+generated only for client keys and can take a while to generate.  For server
+and MGS keys this value also sets the minimum acceptable prime length from a
+client.  If a client attempts to connect with a smaller prime it will reject
+the connection.  In this way servers can "guarantee" the minimum encryption
+level acceptable.
+.TP
+.I "-t, --type <type>"
+The type is a mandatory parameter for writing a key and optional for modifying.
+Valid key types:
+.nf
+mgs    - is used for the MGS where --mgssec is used
+server - for MDS or OSS servers
+client - For clients as well as servers who communicate with other servers in a
+         client context (e.g. MDS communication with OSTs)
+.fi
 .TP
 .I "-k, --shared <len>"
 Shared key length in bits (Default: 256).
@@ -74,36 +84,100 @@ Other Options:
 .TP
 .I "-v, --verbose"
 Increase verbosity for errors.
+.SH NOTES
+The key file is generally the same for client and servers with a few exceptions:
+.IP
+.nf
+1. Types can differ
+2. Both have the prime length but only client keys will have the actual prime
+   value populated.
+.fi
+.LP
+Therefore a
+.B server
+or
+.B mgs
+key can be distributed to a client but the clients
+must change the type to generate a prime.
+.HP
 .SH EXAMPLES
-Write a key for file system 'tank' for a client in the biology nodemap:
+Create a key for file system
+.B tank
+for nodemap
+.B biology
+with type server.
+Once on the client the file should be modified to reflect that it is of type
+.B client
+and will also generate a prime for the key.
 .IP
 .nf
-[root@server ~]# lgss_sk -f tank -n biology -w tank.biology.key
+[root@server ~]# lgss_sk -f tank -n biology -t server -w tank.server.biology.key
+[root@server ~]# scp tank.server.biology.key user@client:tank.client.biology.key
+
+[root@client ~]# lgss_sk -t client -m tank.client.biology.key
 .fi
 .LP
 Add MGS NIDs to existing key:
 .IP
 .nf
 [root@server ~]# lgss_sk -g 192.168.1.101@tcp,10.10.0.101@o2ib \\
--m tank.biology.key
+-m tank.server.biology.key
+
+[root@client ~]# lgss_sk -g 192.168.1.101@tcp,10.10.0.101@o2ib \\
+-m tank.client.biology.key
 .fi
 .LP
 Show key attributes:
 .IP
 .nf
-[root@server ~]# lgss_sk -r tank.biology.key
+[root@server ~]# lgss_sk -r tank.server.biology.key
+Version:        1
+Type:           server
+HMAC alg:       SHA256
+Crypt alg:      AES-256-CTR
+Ctx Expiration: 604800 seconds
+Shared keylen:  256 bits
+Prime length:   2048 bits
+File system:    tank
+MGS NIDs:       192.168.1.101@tcp 10.10.0.101@o2ib
+Nodemap name:   biology
+Shared key:
+  0000: c160 00c6 e5ba 11df 50cb c420 ae61 c1b3  .`......P.. .a..
+  0010: c76e 5a82 ce48 fde9 d319 ce26 cfc4 b91e  .nZ..H.....&....
+Prime (p) :
+
+[root@client ~]# lgss_sk -r tank.client.biology.key
 Version:        1
+Type:           client
 HMAC alg:       SHA256
 Crypt alg:      AES-256-CTR
-Ctx Expiration: 2147483647 seconds
+Ctx Expiration: 604800 seconds
 Shared keylen:  256 bits
-Session keylen: 1024 bits
+Prime length:   2048 bits
 File system:    tank
 MGS NIDs:       192.168.1.101@tcp 10.10.0.101@o2ib
 Nodemap name:   biology
 Shared key:
-  0000: e486 65a8 b0d6 a8bc 17c4 8316 7f5a 701d  ..e..........Zp.
-  0010: 5d6a 7b42 ed35 49cf 5ae9 0638 b12d e3d6  ]j{B.5I.Z..8.-..
+  0000: c160 00c6 e5ba 11df 50cb c420 ae61 c1b3  .`......P.. .a..
+  0010: c76e 5a82 ce48 fde9 d319 ce26 cfc4 b91e  .nZ..H.....&....
+Prime (p) :
+  0000: be19 9412 a4c5 3355 9963 ebdf 3fce a5d8  ......3U.c..?...
+  0010: 9776 50db 70b1 1ad4 a22b 3b68 2ae6 fb7a  .vP.p....+;h*..z
+  0020: 803b 2f67 e6ee cd55 3df1 afbd 4e3a b620  .;/g...U=...N:. 
+  0030: 1d86 4182 bb03 d9b5 9605 658e 4dfb 6d39  ..A.......e.M.m9
+  0040: 0394 b789 437f d30b 3fc0 2c7f 42bb 1987  ....C...?.,.B...
+  0050: 0837 bae1 5332 4992 3a0c 9d01 d350 c2bb  .7..S2I.:....P..
+  0060: ed25 27e9 5439 f295 4c04 08cd bcfe 7e0b  .%'.T9..L.....~.
+  0070: 542b e80b 2fb5 eed0 9ca8 f9bc a792 baf1  T+../...........
+  0080: db1a af08 cee7 7b7f f3e4 7f14 71ca b7c9  ......{.....q...
+  0090: 9d07 c24b 8f04 65e3 4c8c fdd5 6e70 641d  ...K..e.L...npd.
+  00a0: af24 a48a b1c7 d2ff 9fee 158e 7025 6d81  .$..........p%m.
+  00b0: a54f 48f9 712f cac3 28fb 426c 330b 07ff  .OH.q/..(.Bl3...
+  00c0: c4a4 cb67 a46b cc57 1846 dc9d 4ce4 fa65  ...g.k.W.F..L..e
+  00d0: 7fc6 e77d 1220 b807 6c7c 5660 b703 39d2  ...}. ..l|V`..9.
+  00e0: 1d99 bd89 e2f1 3e40 74a1 709c 6e6c 6624  ......>@t.p.nlf$
+  00f0: fad6 97bf c3e0 b0d4 cefc 3596 dd69 5223  ..........5..iR#
+
 .fi
 .br
 .SH "SEE ALSO"
index 3e37f3a..24752a5 100644 (file)
@@ -50,7 +50,7 @@
 /* One week default expiration */
 #define SK_DEFAULT_EXPIRE 604800
 #define SK_DEFAULT_SK_KEYLEN 256
-#define SK_DEFAULT_DH_KEYLEN 1024
+#define SK_DEFAULT_PRIME_BITS 2048
 #define SK_DEFAULT_NODEMAP "default"
 
 /* Names match up with openssl enc and dgst commands */
@@ -95,39 +95,38 @@ void usage(FILE *fp, char *program)
 
        fprintf(fp, "Usage %s [OPTIONS] -l <file> | -m <file> | "
                "-r <file> | -w <file>\n", program);
-       fprintf(fp, "-l|--load    <file>        Load key from file into user's "
+       fprintf(fp, "-l|--load       <file>     Load key from file into user's "
                "session keyring\n");
-       fprintf(fp, "-m|--modify  <file>        Modify a file's key "
+       fprintf(fp, "-m|--modify     <file>     Modify a file's key "
                "attributes\n");
-       fprintf(fp, "-r|--read    <file>        Show file's key attributes\n");
-       fprintf(fp, "-w|--write   <file>        Generate key file\n\n");
-       fprintf(fp, "Load Options:\n");
-       fprintf(fp, "-t|--type    <type>        Key type (mgs, server, "
-               "client)\n\n");
+       fprintf(fp, "-r|--read       <file>     Show file's key attributes\n");
+       fprintf(fp, "-w|--write      <file>     Generate key file\n\n");
        fprintf(fp, "Modify/Write Options:\n");
-       fprintf(fp, "-c|--crypt   <num> Cipher for encryption "
+       fprintf(fp, "-c|--crypt      <num>      Cipher for encryption "
                "(Default: AES Counter mode)\n");
-       for (i = 0; i < SK_CRYPT_MAX; i++)
+       for (i = 1; i < SK_CRYPT_MAX; i++)
                fprintf(fp, "                        %s\n", sk_crypt2name[i]);
 
-       fprintf(fp, "-h|--hmac    <num> Hash alg for HMAC "
+       fprintf(fp, "-i|--hmac       <num>      Hash algorithm for integrity "
                "(Default: SHA256)\n");
-       for (i = 0; i < SK_HMAC_MAX; i++)
+       for (i = 1; i < SK_HMAC_MAX; i++)
                fprintf(fp, "                        %s\n", sk_hmac2name[i]);
 
-       fprintf(fp, "-e|--expire  <num> Seconds before contexts from "
+       fprintf(fp, "-e|--expire     <num>      Seconds before contexts from "
                "key expire (Default: %d seconds)\n", SK_DEFAULT_EXPIRE);
-       fprintf(fp, "-f|--fsname  <name>        File system name for key\n");
-       fprintf(fp, "-g|--mgsnids <nids>        Comma seperated list of MGS "
+       fprintf(fp, "-f|--fsname     <name>     File system name for key\n");
+       fprintf(fp, "-g|--mgsnids    <nids>     Comma seperated list of MGS "
                "NIDs.  Only required when mgssec is used (Default: "
                "\"\")\n");
-       fprintf(fp, "-n|--nodemap <name>        Nodemap name for key "
+       fprintf(fp, "-n|--nodemap    <name>     Nodemap name for key "
                "(Default: \"%s\")\n", SK_DEFAULT_NODEMAP);
-       fprintf(fp, "-s|--session <len> DHKE Public key length in bits "
-               "(Default: %d)\n", SK_DEFAULT_DH_KEYLEN);
-       fprintf(fp, "-k|--shared  <len> Shared key length in bits "
+       fprintf(fp, "-p|--prime-bits <len>      Prime length (p) for DHKE in "
+               "bits (Default: %d)\n", SK_DEFAULT_PRIME_BITS);
+       fprintf(fp, "-t|--type       <type>     Key type (mgs, server, "
+               "client)\n");
+       fprintf(fp, "-k|--shared     <len>      Shared key length in bits "
                "(Default: %d)\n", SK_DEFAULT_SK_KEYLEN);
-       fprintf(fp, "-d|--data    <file>        Shared key data source "
+       fprintf(fp, "-d|--data       <file>     Shared key data source "
                "(Default: /dev/random)\n\n");
        fprintf(fp, "Other Options:\n");
        fprintf(fp, "-v|--verbose           Increase verbosity for "
@@ -145,6 +144,7 @@ ssize_t get_key_data(char *src, void *buffer, size_t bits)
        /* convert bits to minimum number of bytes */
        remain = (bits + 7) / 8;
 
+       printf("Reading data for shared key from %s\n", src);
        fd = open(src, O_RDONLY);
        if (fd < 0) {
                fprintf(stderr, "Failed to open %s: %s\n", src,
@@ -230,11 +230,19 @@ int print_config(char *filename)
        }
 
        printf("Version:        %u\n", config->skc_version);
+       printf("Type:           ");
+       if (config->skc_type & SK_TYPE_MGS)
+               printf("mgs ");
+       if (config->skc_type & SK_TYPE_SERVER)
+               printf("server ");
+       if (config->skc_type & SK_TYPE_CLIENT)
+               printf("client ");
+       printf("\n");
        printf("HMAC alg:       %s\n", sk_hmac2name[config->skc_hmac_alg]);
        printf("Crypt alg:      %s\n", sk_crypt2name[config->skc_crypt_alg]);
        printf("Ctx Expiration: %u seconds\n", config->skc_expire);
        printf("Shared keylen:  %u bits\n", config->skc_shared_keylen);
-       printf("Session keylen: %u bits\n", config->skc_session_keylen);
+       printf("Prime length:   %u bits\n", config->skc_prime_bits);
        printf("File system:    %s\n", config->skc_fsname);
        printf("MGS NIDs:       ");
        for (i = 0; i < MAX_MGSNIDS; i++) {
@@ -246,6 +254,15 @@ int print_config(char *filename)
        printf("Nodemap name:   %s\n", config->skc_nodemap);
        printf("Shared key:\n");
        print_hex(0, config->skc_shared_key, config->skc_shared_keylen / 8);
+       printf("Prime (p) :\n");
+
+       /* Don't print empty keys */
+       for (i = 0; i < SK_MAX_P_BYTES; i++)
+               if (config->skc_p[i] != 0)
+                       break;
+
+       if (i != SK_MAX_P_BYTES)
+               print_hex(0, config->skc_p, config->skc_prime_bits / 8);
 
        free(config);
        return EXIT_SUCCESS;
@@ -302,15 +319,19 @@ int main(int argc, char **argv)
        char *mgsnids = NULL;
        char *nodemap = NULL;
        char *fsname = NULL;
-       int type = SK_TYPE_INVALID;
+       char *tmp;
+       char *tmp2;
        int crypt = SK_CRYPT_EMPTY;
        int hmac = SK_HMAC_EMPTY;
        int expire = -1;
        int shared_keylen = -1;
-       int session_keylen = -1;
+       int prime_bits = -1;
        int verbose = 0;
        int i;
        int opt;
+       enum sk_key_type  type = SK_TYPE_INVALID;
+       bool generate_prime = false;
+       DH *dh;
 
        static struct option long_opt[] = {
                {"crypt", 1, 0, 'c'},
@@ -318,22 +339,23 @@ int main(int argc, char **argv)
                {"expire", 1, 0, 'e'},
                {"fsname", 1, 0, 'f'},
                {"mgsnids", 1, 0, 'g'},
-               {"hmac", 1, 0, 'h'},
+               {"help", 0, 0, 'h'},
+               {"hmac", 1, 0, 'i'},
+               {"shared", 1, 0, 'k'},
                {"load", 1, 0, 'l'},
                {"modify", 1, 0, 'm'},
                {"nodemap", 1, 0, 'n'},
+               {"prime-bits", 1, 0, 'p'},
                {"read", 1, 0, 'r'},
-               {"session", 1, 0, 's'},
-               {"shared", 1, 0, 'k'},
                {"type", 1, 0, 't'},
-               {"write", 1, 0, 'w'},
                {"verbose", 0, 0, 'v'},
-               {"help", 0, 0, 'p'},
+               {"write", 1, 0, 'w'},
                {0, 0, 0, 0},
        };
 
-       while ((opt = getopt_long(argc, argv, "c:d:e:f:g:h:l:m:n:pr:s:k:t:w:v",
-                                 long_opt, NULL)) != EOF) {
+       while ((opt = getopt_long(argc, argv,
+                                 "c:d:e:f:g:hi:l:m:n:p:r:s:k:t:w:v", long_opt,
+                                 NULL)) != EOF) {
                switch (opt) {
                case 'c':
                        crypt = sk_name2crypt(optarg);
@@ -359,11 +381,20 @@ int main(int argc, char **argv)
                        mgsnids = optarg;
                        break;
                case 'h':
+                       usage(stdout, argv[0]);
+                       break;
+               case 'i':
                        hmac = sk_name2hmac(optarg);
                        break;
+               case 'k':
+                       shared_keylen = atoi(optarg);
+                       break;
                case 'l':
                        load = optarg;
                        break;
+               case 'm':
+                       modify = optarg;
+                       break;
                case 'n':
                        nodemap = optarg;
                        if (strlen(nodemap) > LUSTRE_NODEMAP_NAME_LENGTH) {
@@ -371,40 +402,48 @@ int main(int argc, char **argv)
                                return EXIT_FAILURE;
                        }
                        break;
-               case 'm':
-                       modify = optarg;
-                       break;
                case 'p':
-                       usage(stdout, argv[0]);
+                       prime_bits = atoi(optarg);
+                       if (prime_bits <= 0) {
+                               fprintf(stderr, "Invalid prime length: %s\n",
+                                       optarg);
+                               return EXIT_FAILURE;
+                       }
                        break;
                case 'r':
                        input = optarg;
                        break;
-               case 's':
-                       session_keylen = atoi(optarg);
-                       break;
-               case 'k':
-                       shared_keylen = atoi(optarg);
-                       break;
                case 't':
-                       if (!strcasecmp(optarg, "server")) {
-                               type = SK_TYPE_SERVER;
-                       } else if (!strcasecmp(optarg, "mgs")) {
-                               type = SK_TYPE_MGS;
-                       } else if (!strcasecmp(optarg, "client")) {
-                               type = SK_TYPE_CLIENT;
-                       } else {
-                               fprintf(stderr, "type must be mgs, server, or "
-                                       "client\n");
+                       tmp2 = strdup(optarg);
+                       if (!tmp2) {
+                               fprintf(stderr, "Failed to allocated memory "
+                                       "for type argument\n");
                                return EXIT_FAILURE;
                        }
-                       break;
-               case 'w':
-                       output = optarg;
+                       tmp = strsep(&tmp2, ",");
+                       while (tmp != NULL) {
+                               if (strcasecmp(tmp, "server") == 0) {
+                                       type |= SK_TYPE_SERVER;
+                               } else if (strcasecmp(tmp, "mgs") == 0) {
+                                       type |= SK_TYPE_MGS;
+                               } else if (strcasecmp(tmp, "client") == 0) {
+                                       type |= SK_TYPE_CLIENT;
+                               } else {
+                                       fprintf(stderr, "Invalid type must be "
+                                               "mgs, server, or  client: "
+                                               "%s\n", optarg);
+                                       return EXIT_FAILURE;
+                               }
+                               tmp = strsep(&tmp2, ",");
+                       }
+                       free(tmp2);
                        break;
                case 'v':
                        verbose++;
                        break;
+               case 'w':
+                       output = optarg;
+                       break;
                default:
                        fprintf(stderr, "Unknown option: %c\n", opt);
                        return EXIT_FAILURE;
@@ -429,13 +468,7 @@ int main(int argc, char **argv)
                return print_config(input);
 
        if (load) {
-               if (type == SK_TYPE_INVALID) {
-                       fprintf(stderr, "type must be specified when loading "
-                               "a key\n");
-                       return EXIT_FAILURE;
-               }
-
-               if (sk_load_keyfile(load, type))
+               if (sk_load_keyfile(load))
                        return EXIT_FAILURE;
                return EXIT_SUCCESS;
        }
@@ -462,24 +495,59 @@ int main(int argc, char **argv)
                        config->skc_expire = expire;
                if (shared_keylen != -1)
                        config->skc_shared_keylen = shared_keylen;
-               if (session_keylen != -1)
-                       config->skc_session_keylen = session_keylen;
+               if (type != SK_TYPE_INVALID) {
+                       /* generate key when adding client type */
+                       if (!(config->skc_type & SK_TYPE_CLIENT) &&
+                           type & SK_TYPE_CLIENT)
+                               generate_prime = true;
+                       else if (!(type & SK_TYPE_CLIENT))
+                               memset(config->skc_p, 0, SK_MAX_P_BYTES);
+
+                       config->skc_type = type;
+               }
+               if (prime_bits != -1) {
+                       memset(config->skc_p, 0, SK_MAX_P_BYTES);
+                       if (config->skc_prime_bits != prime_bits &&
+                           config->skc_type & SK_TYPE_CLIENT)
+                               generate_prime = true;
+                       config->skc_prime_bits = prime_bits;
+               }
                if (fsname)
                        strncpy(config->skc_fsname, fsname, strlen(fsname));
                if (nodemap)
                        strncpy(config->skc_nodemap, nodemap, strlen(nodemap));
                if (mgsnids && parse_mgsnids(mgsnids, config))
                        goto error;
+               if (sk_validate_config(config)) {
+                       fprintf(stderr,
+                               "Key configuration failed validation\n");
+                       goto error;
+               }
+
                if (data && get_key_data(data, config->skc_shared_key,
                    config->skc_shared_keylen)) {
                        fprintf(stderr, "Failure getting data for key\n");
                        goto error;
                }
 
-               if (sk_validate_config(config)) {
-                       fprintf(stderr, "Key configuration failed "
-                               "validation\n");
-                       goto error;
+               if (generate_prime) {
+                       printf("Generating DH parameters this can take a "
+                              "while...\n");
+                       dh = DH_generate_parameters(config->skc_prime_bits,
+                                                   SK_GENERATOR, NULL, NULL);
+                       if (BN_num_bytes(dh->p) > SK_MAX_P_BYTES) {
+                               fprintf(stderr, "Cannot generate DH parameters:"
+                                       " requested length %d exceeds maximum: "
+                                       "%d\n", config->skc_prime_bits,
+                                       SK_MAX_P_BYTES * 8);
+                               goto error;
+                       }
+                       if (BN_bn2bin(dh->p, config->skc_p) !=
+                           BN_num_bytes(dh->p)) {
+                               fprintf(stderr, "Failed conversion of BIGNUM p"
+                                       " to binary\n");
+                               goto error;
+                       }
                }
 
                if (write_config_file(modify, config, true))
@@ -504,7 +572,7 @@ int main(int argc, char **argv)
        config->skc_version = SK_CONF_VERSION;
        config->skc_expire = SK_DEFAULT_EXPIRE;
        config->skc_shared_keylen = SK_DEFAULT_SK_KEYLEN;
-       config->skc_session_keylen = SK_DEFAULT_DH_KEYLEN;
+       config->skc_prime_bits = SK_DEFAULT_PRIME_BITS;
        config->skc_crypt_alg = SK_CRYPT_AES256_CTR;
        config->skc_hmac_alg = SK_HMAC_SHA256;
        for (i = 0; i < MAX_MGSNIDS; i++)
@@ -518,8 +586,8 @@ int main(int argc, char **argv)
                config->skc_expire = expire;
        if (shared_keylen != -1)
                config->skc_shared_keylen = shared_keylen;
-       if (session_keylen != -1)
-               config->skc_session_keylen = session_keylen;
+       if (prime_bits != -1)
+               config->skc_prime_bits = prime_bits;
        if (fsname)
                strncpy(config->skc_fsname, fsname, strlen(fsname));
        if (nodemap)
@@ -530,6 +598,17 @@ int main(int argc, char **argv)
 
        if (mgsnids && parse_mgsnids(mgsnids, config))
                goto error;
+       if (type == SK_TYPE_INVALID) {
+               fprintf(stderr, "No type specified for key\n");
+               goto error;
+       }
+       config->skc_type = type;
+
+       if (sk_validate_config(config)) {
+               fprintf(stderr, "Key configuration failed validation\n");
+               goto error;
+       }
+
        if (!data)
                data = "/dev/random";
        if (get_key_data(data, config->skc_shared_key,
@@ -538,9 +617,21 @@ int main(int argc, char **argv)
                goto error;
        }
 
-       if (sk_validate_config(config)) {
-               fprintf(stderr, "Key configuration failed validation\n");
-               goto error;
+       if (type & SK_TYPE_CLIENT) {
+               printf("Generating DH parameters this can take a while...\n");
+               dh = DH_generate_parameters(config->skc_prime_bits,
+                                           SK_GENERATOR, NULL, NULL);
+               if (BN_num_bytes(dh->p) > SK_MAX_P_BYTES) {
+                       fprintf(stderr, "Cannot generate DH parameters: "
+                               "requested length %d exceeds maximum: %d\n",
+                               config->skc_prime_bits, SK_MAX_P_BYTES * 8);
+                       goto error;
+               }
+               if (BN_bn2bin(dh->p, config->skc_p) != BN_num_bytes(dh->p)) {
+                       fprintf(stderr, "Failed conversion of BIGNUM p to "
+                               "binary\n");
+                       goto error;
+               }
        }
 
        if (write_config_file(output, config, false))
index 4f9ca53..b6f1fd8 100644 (file)
@@ -93,7 +93,7 @@ static int lgss_sk_using_cred(struct lgss_cred *cred)
        uint32_t flags;
        int rc;
 
-       rc = sk_gen_params(skc, true);
+       rc = sk_gen_params(skc);
        if (rc)
                return rc;
 
@@ -107,7 +107,7 @@ static int lgss_sk_using_cred(struct lgss_cred *cred)
        bufs[SK_INIT_P] = skc->sc_p;
        bufs[SK_INIT_TARGET] = skc->sc_tgt;
        bufs[SK_INIT_NODEMAP] = skc->sc_nodemap_hash;
-       flags = htobe64(skc->sc_flags);
+       flags = htobe32(skc->sc_flags);
        bufs[SK_INIT_FLAGS].value = &flags;
        bufs[SK_INIT_FLAGS].length = sizeof(flags);
 
index f38510f..382fc9f 100644 (file)
@@ -200,7 +200,7 @@ static key_serial_t sk_load_key(const struct sk_keyfile_config *skc,
  * \return     0       sucess
  * \return     -1      failure
  */
-int sk_load_keyfile(char *path, int type)
+int sk_load_keyfile(char *path)
 {
        struct sk_keyfile_config *config;
        char description[SK_DESCRIPTION_SIZE + 1];
@@ -233,7 +233,7 @@ int sk_load_keyfile(char *path, int type)
        /* The server side can have multiple key files per file system so
         * the nodemap name is appended to the key description to uniquely
         * identify it */
-       if (type & SK_TYPE_MGS) {
+       if (config->skc_type & SK_TYPE_MGS) {
                /* Any key can be an MGS key as long as we are told to use it */
                rc = snprintf(description, SK_DESCRIPTION_SIZE, "lustre:MGS:%s",
                              config->skc_nodemap);
@@ -242,7 +242,7 @@ int sk_load_keyfile(char *path, int type)
                if (sk_load_key(config, description) == -1)
                        goto out;
        }
-       if (type & SK_TYPE_SERVER) {
+       if (config->skc_type & SK_TYPE_SERVER) {
                /* Server keys need to have the file system name in the key */
                if (!config->skc_fsname) {
                        printerr(0, "Key configuration has no file system "
@@ -256,7 +256,7 @@ int sk_load_keyfile(char *path, int type)
                if (sk_load_key(config, description) == -1)
                        goto out;
        }
-       if (type & SK_TYPE_CLIENT) {
+       if (config->skc_type & SK_TYPE_CLIENT) {
                /* Load client file system key */
                if (config->skc_fsname) {
                        rc = snprintf(description, SK_DESCRIPTION_SIZE,
@@ -305,7 +305,7 @@ void sk_config_cpu_to_disk(struct sk_keyfile_config *config)
        config->skc_crypt_alg = htobe16(config->skc_crypt_alg);
        config->skc_expire = htobe32(config->skc_expire);
        config->skc_shared_keylen = htobe32(config->skc_shared_keylen);
-       config->skc_session_keylen = htobe32(config->skc_session_keylen);
+       config->skc_prime_bits = htobe32(config->skc_prime_bits);
 
        for (i = 0; i < MAX_MGSNIDS; i++)
                config->skc_mgsnids[i] = htobe64(config->skc_mgsnids[i]);
@@ -330,7 +330,7 @@ void sk_config_disk_to_cpu(struct sk_keyfile_config *config)
        config->skc_crypt_alg = be16toh(config->skc_crypt_alg);
        config->skc_expire = be32toh(config->skc_expire);
        config->skc_shared_keylen = be32toh(config->skc_shared_keylen);
-       config->skc_session_keylen = be32toh(config->skc_session_keylen);
+       config->skc_prime_bits = be32toh(config->skc_prime_bits);
 
        for (i = 0; i < MAX_MGSNIDS; i++)
                config->skc_mgsnids[i] = be64toh(config->skc_mgsnids[i]);
@@ -374,11 +374,11 @@ int sk_validate_config(const struct sk_keyfile_config *config)
                         "and %d\n", 60, INT_MAX);
                return -1;
        }
-       if (config->skc_session_keylen % 8 != 0 ||
-           config->skc_session_keylen > SK_SESSION_MAX_KEYLEN_BYTES * 8) {
+       if (config->skc_prime_bits % 8 != 0 ||
+           config->skc_prime_bits > SK_MAX_P_BYTES * 8) {
                printerr(0, "Invalid session key length must be a multiple of 8"
                         " and less then %d bits\n",
-                        SK_SESSION_MAX_KEYLEN_BYTES * 8);
+                        SK_MAX_P_BYTES * 8);
                return -1;
        }
        if (config->skc_shared_keylen % 8 != 0 ||
@@ -406,6 +406,11 @@ int sk_validate_config(const struct sk_keyfile_config *config)
                return -1;
        }
 
+       if (config->skc_type == SK_TYPE_INVALID) {
+               printerr(0, "Invalid key type\n");
+               return -1;
+       }
+
        return 0;
 }
 
@@ -650,7 +655,6 @@ struct sk_cred *sk_create_cred(const char *tgt, const char *nodemap,
        kctx->skc_expire = config->skc_expire;
 
        /* key payload format is in bits, convert to bytes */
-       skc->sc_session_keylen = config->skc_session_keylen / 8;
        kctx->skc_shared_key.length = config->skc_shared_keylen / 8;
        kctx->skc_shared_key.value = malloc(kctx->skc_shared_key.length);
        if (!kctx->skc_shared_key.value) {
@@ -660,6 +664,14 @@ struct sk_cred *sk_create_cred(const char *tgt, const char *nodemap,
        memcpy(kctx->skc_shared_key.value, config->skc_shared_key,
               kctx->skc_shared_key.length);
 
+       skc->sc_p.length = config->skc_prime_bits / 8;
+       skc->sc_p.value = malloc(skc->sc_p.length);
+       if (!skc->sc_p.value) {
+               printerr(0, "Failed to allocate p\n");
+               goto out_err;
+       }
+       memcpy(skc->sc_p.value, config->skc_p, skc->sc_p.length);
+
        free(config);
 
        return skc;
@@ -671,54 +683,50 @@ out_err:
        return NULL;
 }
 
-static void sk_free_parameters(struct sk_cred *skc)
-{
-       if (skc->sc_params)
-               DH_free(skc->sc_params);
-       if (skc->sc_p.value)
-               free(skc->sc_p.value);
-       if (skc->sc_pub_key.value)
-               free(skc->sc_pub_key.value);
-
-       skc->sc_params = NULL;
-       skc->sc_p.value = NULL;
-       skc->sc_p.length = 0;
-       skc->sc_pub_key.value = NULL;
-       skc->sc_pub_key.length = 0;
-}
-
 /**
- * Generates a public key and computes the private key for the DH key exchange.
- * The parameters must be populated with the p and g from the peer.
+ * Populates the DH parameters for the DHKE
  *
- * \param[in,out]      skc     Shared key credentials structure to populate
- *                             with DH parameters
+ * \param[in,out]      skc             Shared key credentials structure to
+ *                                     populate with DH parameters
  *
  * \retval     GSS_S_COMPLETE  success
  * \retval     GSS_S_FAILURE   failure
  */
-static uint32_t sk_gen_responder_params(struct sk_cred *skc)
+uint32_t sk_gen_params(struct sk_cred *skc)
 {
+       uint32_t random;
        int rc;
 
-       /* No keys to generate without privacy mode */
-       if ((skc->sc_flags & LGSS_SVC_PRIV) == 0)
-               return GSS_S_COMPLETE;
+       /* Random value used by both the request and response as part of the
+        * key binding material.  This also should ensure we have unqiue
+        * tokens that are sent to the remote server which is important because
+        * the token is hashed for the sunrpc cache lookups and a failure there
+        * would cause connection attempts to fail indefinitely due to the large
+        * timeout value on the server side */
+       if (RAND_bytes((unsigned char *)&random, sizeof(random)) != 1) {
+               printerr(0, "Failed to get data for random parameter: %s\n",
+                        ERR_error_string(ERR_get_error(), NULL));
+               return GSS_S_FAILURE;
+       }
 
+       /* The random value will always be used in byte range operations
+        * so we keep it as big endian from this point on */
+       skc->sc_kctx.skc_host_random = random;
+
+       /* Populate DH parameters */
        skc->sc_params = DH_new();
        if (!skc->sc_params) {
                printerr(0, "Failed to allocate DH\n");
                return GSS_S_FAILURE;
        }
 
-       /* responder should already have sc_p populated */
        skc->sc_params->p = BN_bin2bn(skc->sc_p.value, skc->sc_p.length, NULL);
        if (!skc->sc_params->p) {
                printerr(0, "Failed to convert binary to BIGNUM\n");
                return GSS_S_FAILURE;
        }
 
-       /* and we use a static generator for shared key */
+       /* We use a static generator for shared key */
        skc->sc_params->g = BN_new();
        if (!skc->sc_params->g) {
                printerr(0, "Failed to allocate new BIGNUM\n");
@@ -729,7 +737,7 @@ static uint32_t sk_gen_responder_params(struct sk_cred *skc)
                return GSS_S_FAILURE;
        }
 
-       /* verify that we have a safe prime and valid generator */
+       /* Verify that we have a safe prime and valid generator */
        if (DH_check(skc->sc_params, &rc) != 1) {
                printerr(0, "DH_check() failed: %d\n", rc);
                return GSS_S_FAILURE;
@@ -757,102 +765,6 @@ static uint32_t sk_gen_responder_params(struct sk_cred *skc)
 }
 
 /**
- * Generates shared key Diffie Hellman parameters used for the DH key exchange
- * between host and peer if privacy mode is enabled
- *
- * \param[in,out]      skc     Shared key credentials structure to populate
- *                             with DH parameters
- *
- * \retval     GSS_S_COMPLETE  success
- * \retval     GSS_S_FAILURE   failure
- */
-static uint32_t sk_gen_initiator_params(struct sk_cred *skc)
-{
-       int rc;
-
-       /* The credential could be used so free existing parameters */
-       sk_free_parameters(skc);
-
-       /* Only privacy mode needs the rest of the parameter generation
-        * but we use IV in other modes as well so tokens should be
-        * unique */
-       if ((skc->sc_flags & LGSS_SVC_PRIV) == 0)
-               return GSS_S_COMPLETE;
-
-       skc->sc_params = DH_generate_parameters(skc->sc_session_keylen * 8,
-                                               SK_GENERATOR, NULL, NULL);
-       if (skc->sc_params == NULL) {
-               printerr(0, "Failed to generate diffie-hellman parameters: %s",
-                        ERR_error_string(ERR_get_error(), NULL));
-               return GSS_S_FAILURE;
-       }
-
-       if (DH_check(skc->sc_params, &rc) != 1) {
-               printerr(0, "DH_check() failed: %d\n", rc);
-               return GSS_S_FAILURE;
-       } else if (rc) {
-               printerr(0, "DH_check() returned error codes: 0x%x\n", rc);
-               return GSS_S_FAILURE;
-       }
-
-       if (DH_generate_key(skc->sc_params) != 1) {
-               printerr(0, "Failed to generate public DH key: %s\n",
-                        ERR_error_string(ERR_get_error(), NULL));
-               return GSS_S_FAILURE;
-       }
-
-       skc->sc_p.length = BN_num_bytes(skc->sc_params->p);
-       skc->sc_pub_key.length = BN_num_bytes(skc->sc_params->pub_key);
-       skc->sc_p.value = malloc(skc->sc_p.length);
-       skc->sc_pub_key.value = malloc(skc->sc_pub_key.length);
-       if (!skc->sc_p.value || !skc->sc_pub_key.value) {
-               printerr(0, "Failed to allocate memory for params\n");
-               return GSS_S_FAILURE;
-       }
-
-       BN_bn2bin(skc->sc_params->pub_key, skc->sc_pub_key.value);
-       BN_bn2bin(skc->sc_params->p, skc->sc_p.value);
-
-       return GSS_S_COMPLETE;
-}
-
-/**
- * Generates or populates the DH parameters depending on whether the system is
- * the initiator or responder for the connection
- *
- * \param[in,out]      skc             Shared key credentials structure to
- *                                     populate with DH parameters
- * \param[in]          initiator       Boolean whether to initiate parameters
- *
- * \retval     GSS_S_COMPLETE  success
- * \retval     GSS_S_FAILURE   failure
- */
-uint32_t sk_gen_params(struct sk_cred *skc, const bool initiator)
-{
-       uint32_t random;
-
-       /* Random value used by both the request and response as part of the
-        * key binding material.  This also should ensure we have unqiue
-        * tokens that are sent to the remote server which is important because
-        * the token is hashed for the sunrpc cache lookups and a failure there
-        * would cause connection attempts to fail indefinitely due to the large
-        * timeout value on the server side */
-       if (RAND_bytes((unsigned char *)&random, sizeof(random)) != 1) {
-               printerr(0, "Failed to get data for random parameter\n");
-               return GSS_S_FAILURE;
-       }
-
-       /* The random value will always be used in byte range operations
-        * so we keep it as big endian from this point on */
-       skc->sc_kctx.skc_host_random = htobe32(random);
-
-       if (initiator)
-               return sk_gen_initiator_params(skc);
-
-       return sk_gen_responder_params(skc);
-}
-
-/**
  * Convert SK hash algorithm into openssl message digest
  *
  * \param[in,out]      alg             SK hash algorithm
@@ -1218,10 +1130,6 @@ uint32_t sk_compute_dh_key(struct sk_cred *skc, const gss_buffer_desc *pub_key)
        int status;
        uint32_t rc = GSS_S_FAILURE;
 
-       /* No keys computed unless privacy mode is in use */
-       if ((skc->sc_flags & LGSS_SVC_PRIV) == 0)
-               return GSS_S_COMPLETE;
-
        remote_pub_key = BN_bin2bn(pub_key->value, pub_key->length, NULL);
        if (!remote_pub_key) {
                printerr(0, "Failed to convert binary to BIGNUM\n");
index 9644786..c7dbe77 100644 (file)
@@ -43,6 +43,7 @@
 #define SK_GENERATOR 2
 #define SK_SESSION_MAX_KEYLEN_BYTES 1024
 #define SK_MAX_KEYLEN_BYTES 128
+#define SK_MAX_P_BYTES 2048
 #define SK_NONCE_SIZE 4
 #define MAX_MGSNIDS 16
 
@@ -90,8 +91,10 @@ struct sk_keyfile_config {
        uint32_t        skc_expire;
        /* Length of shared key in skc_shared_key */
        uint32_t        skc_shared_keylen;
-       /* Minimum length of the session keys using this keyfile */
-       uint32_t        skc_session_keylen;
+       /* Length of the prime used in the DHKE */
+       uint32_t        skc_prime_bits;
+       /* Key type */
+       uint8_t         skc_type;
        /* Array of MGS NIDs to load key's for.  This is for the client since
         * the upcall only knows the target name which is MGC<IP>@<NET>
         * Only needed when mounting with mgssec */
@@ -103,6 +106,8 @@ struct sk_keyfile_config {
        char            skc_nodemap[LUSTRE_NODEMAP_NAME_LENGTH + 1];
        /* Shared key */
        unsigned char   skc_shared_key[SK_MAX_KEYLEN_BYTES];
+       /* Prime (p) for DHKE */
+       unsigned char   skc_p[SK_MAX_P_BYTES];
 } __attribute__((packed));
 
 /* Format passed to the kernel from userspace */
@@ -121,7 +126,6 @@ struct sk_kernel_ctx {
 
 /* Structure used in context initiation to hold all necessary data */
 struct sk_cred {
-       uint32_t                 sc_session_keylen;
        uint32_t                 sc_flags;
        gss_buffer_desc          sc_p;
        gss_buffer_desc          sc_pub_key;
@@ -135,7 +139,7 @@ struct sk_cred {
 
 void sk_init_logging(char *program, int verbose, int fg);
 struct sk_keyfile_config *sk_read_file(char *filename);
-int sk_load_keyfile(char *path, int type);
+int sk_load_keyfile(char *path);
 void sk_config_disk_to_cpu(struct sk_keyfile_config *config);
 void sk_config_cpu_to_disk(struct sk_keyfile_config *config);
 int sk_validate_config(const struct sk_keyfile_config *config);
@@ -143,7 +147,7 @@ uint32_t sk_verify_hash(const char *string, const EVP_MD *hash_alg,
                        const gss_buffer_desc *current_hash);
 struct sk_cred *sk_create_cred(const char *fsname, const char *cluster,
                               const uint32_t flags);
-uint32_t sk_gen_params(struct sk_cred *skc, bool initiator);
+uint32_t sk_gen_params(struct sk_cred *skc);
 int sk_sign_bufs(gss_buffer_desc *key, gss_buffer_desc *bufs, const int numbufs,
                 const EVP_MD *hash_alg, gss_buffer_desc *hmac);
 uint32_t sk_verify_hmac(struct sk_cred *skc, gss_buffer_desc *bufs,
index 8b97498..5ae4213 100644 (file)
@@ -415,6 +415,22 @@ int handle_sk(struct svc_nego_data *snd)
                goto cleanup_buffers;
        }
 
+       /* Verify that the peer has used a prime size greater or equal to
+        * the size specified in the key file which may contain only zero
+        * fill but the size specifies the mimimum supported size on
+        * servers */
+       if (skc->sc_flags & LGSS_SVC_PRIV &&
+           bufs[SK_INIT_P].length < skc->sc_p.length) {
+               printerr(0, "Peer DHKE prime does not meet the size required "
+                        "by keyfile: %zd bits\n", skc->sc_p.length * 8);
+               goto cleanup_buffers;
+       }
+
+       /* Throw out the p from the server and use the wire data */
+       free(skc->sc_p.value);
+       skc->sc_p.value = NULL;
+       skc->sc_p.length = 0;
+
        /* Take control of all the allocated buffers from decoding */
        if (bufs[SK_INIT_RANDOM].length !=
            sizeof(skc->sc_kctx.skc_peer_random)) {
@@ -429,15 +445,6 @@ int handle_sk(struct svc_nego_data *snd)
        skc->sc_nodemap_hash = bufs[SK_INIT_NODEMAP];
        skc->sc_hmac = bufs[SK_INIT_HMAC];
 
-       /* Verify that the peer has used a key size greater to or equal
-        * the size specified by the key file */
-       if (skc->sc_flags & LGSS_SVC_PRIV &&
-           skc->sc_p.length < skc->sc_session_keylen) {
-               printerr(0, "Peer DH parameters do not meet the size required "
-                        "by keyfile\n");
-               goto cleanup_partial;
-       }
-
        /* Verify HMAC from peer.  Ideally this would happen before anything
         * else but we don't have enough information to lookup key without the
         * token (fsname and cluster_hash) so it's done after. */
@@ -456,7 +463,7 @@ int handle_sk(struct svc_nego_data *snd)
                goto cleanup_partial;
        }
 
-       rc = sk_gen_params(skc, false);
+       rc = sk_gen_params(skc);
        if (rc != GSS_S_COMPLETE) {
                printerr(0, "Failed to generate DH params for responder\n");
                goto cleanup_partial;
index 3ee400d..a77b513 100644 (file)
@@ -884,7 +884,6 @@ int load_shared_keys(struct mount_opts *mop)
        struct stat sbuf;
        char fullpath[PATH_MAX];
        char *path = mop->mo_skpath;
-       int type = 0;
        int rc;
 
        /* init logging */
@@ -897,23 +896,9 @@ int load_shared_keys(struct mount_opts *mop)
                return -errno;
        }
 
-       if (IS_SERVER(&mop->mo_ldd)) {
-               if (IS_MGS(&mop->mo_ldd))
-                       type |= SK_TYPE_MGS;
-               if (IS_MDT(&mop->mo_ldd) || IS_OST(&mop->mo_ldd))
-                       type |= SK_TYPE_SERVER;
-       } else {
-               type |= SK_TYPE_CLIENT;
-               if (!S_ISREG(sbuf.st_mode)) {
-                       fprintf(stderr, "Invalid shared key path, must be a "
-                               "file for client mounts: %s\n", path);
-                       return -EINVAL;
-               }
-       }
-
        /* Load individual keys or a directory of them */
        if (S_ISREG(sbuf.st_mode)) {
-               return sk_load_keyfile(path, type);
+               return sk_load_keyfile(path);
        } else if (!S_ISDIR(sbuf.st_mode)) {
                fprintf(stderr, "Invalid shared key path: %s\n", path);
                return -ENOKEY;
@@ -956,7 +941,7 @@ int load_shared_keys(struct mount_opts *mop)
                if (!S_ISREG(sbuf.st_mode))
                        continue;
 
-               rc = sk_load_keyfile(fullpath, type);
+               rc = sk_load_keyfile(fullpath);
                if (rc) {
                        fprintf(stderr, "Failed to load key %s\n", fullpath);
                }