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
.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>"
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
.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).
.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"
/* 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 */
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 "
/* 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,
}
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++) {
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;
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'},
{"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);
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) {
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;
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;
}
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))
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++)
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)
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,
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))
uint32_t flags;
int rc;
- rc = sk_gen_params(skc, true);
+ rc = sk_gen_params(skc);
if (rc)
return rc;
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);
* \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];
/* 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);
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 "
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,
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]);
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]);
"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 ||
return -1;
}
+ if (config->skc_type == SK_TYPE_INVALID) {
+ printerr(0, "Invalid key type\n");
+ return -1;
+ }
+
return 0;
}
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) {
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;
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");
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;
}
/**
- * 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
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");
#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
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 */
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 */
/* 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;
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);
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,
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)) {
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. */
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;
struct stat sbuf;
char fullpath[PATH_MAX];
char *path = mop->mo_skpath;
- int type = 0;
int rc;
/* init logging */
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;
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);
}