4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright (C) 2015, Trustees of Indiana University
25 * Author: Jeremy Filizetti <jfilizet@iu.edu>
30 /* We need to use some deprecated APIs */
31 #define OPENSSL_SUPPRESS_DEPRECATED
32 #include <openssl/dh.h>
33 #include <openssl/engine.h>
34 #include <openssl/err.h>
37 #include "lgss_utils.h"
40 * Create the initial shared key credentials
42 static int lgss_sk_prepare_cred(struct lgss_cred *cred)
44 uint32_t flags = cred->lc_root_flags;
46 switch (cred->lc_svc_type) {
48 flags |= LGSS_SVC_NULL;
51 flags |= LGSS_SVC_AUTH;
54 flags |= LGSS_SVC_INTG;
57 flags |= LGSS_SVC_PRIV;
63 cred->lc_mech_cred = sk_create_cred(cred->lc_tgt_uuid, NULL, flags);
64 if (cred->lc_mech_cred == NULL) {
65 printerr(0, "sk: cannot create credential: %s\n",
73 /* Free all the sk_cred resources */
74 static void lgss_sk_release_cred(struct lgss_cred *cred)
76 struct sk_cred *skc = cred->lc_mech_cred;
79 cred->lc_mech_cred = NULL;
80 free(cred->lc_mech_token.value);
84 * Session key parameter generation is deferred until here because if privacy
85 * mode is enabled the session key parameter generation can take a while
86 * depending on the key size used and prepare is called before returning
87 * from the request_key upcall by lgss_keyring
89 static int lgss_sk_using_cred(struct lgss_cred *cred)
91 struct sk_cred *skc = cred->lc_mech_cred;
92 gss_buffer_desc bufs[SK_INIT_BUFFERS];
97 rc = sk_gen_params(skc, 0);
101 /* HMAC is generated in this order */
102 version = htobe32(SK_MSG_VERSION);
103 bufs[SK_INIT_VERSION].value = &version;
104 bufs[SK_INIT_VERSION].length = sizeof(version);
105 bufs[SK_INIT_RANDOM].value = &skc->sc_kctx.skc_host_random;
106 bufs[SK_INIT_RANDOM].length = sizeof(skc->sc_kctx.skc_host_random);
107 bufs[SK_INIT_PUB_KEY] = skc->sc_pub_key;
108 bufs[SK_INIT_P] = skc->sc_p;
109 bufs[SK_INIT_TARGET] = skc->sc_tgt;
110 bufs[SK_INIT_NODEMAP] = skc->sc_nodemap_hash;
111 flags = htobe32(skc->sc_flags);
112 bufs[SK_INIT_FLAGS].value = &flags;
113 bufs[SK_INIT_FLAGS].length = sizeof(flags);
115 /* sign all the bufs except HMAC */
116 rc = sk_sign_bufs(&skc->sc_kctx.skc_shared_key, bufs,
117 SK_INIT_BUFFERS - 1, EVP_sha256(),
122 bufs[SK_INIT_HMAC] = skc->sc_hmac;
123 rc = sk_encode_netstring(bufs, SK_INIT_BUFFERS, &cred->lc_mech_token);
127 printerr(2, "Created netstring of %zd bytes\n",
128 cred->lc_mech_token.length);
133 static int lgss_sk_validate_cred(struct lgss_cred *cred, gss_buffer_desc *token,
134 gss_buffer_desc *ctx_token)
136 struct sk_cred *skc = cred->lc_mech_cred;
137 gss_buffer_desc bufs[SK_RESP_BUFFERS];
142 /* Decode responder buffers and validate */
143 i = sk_decode_netstring(bufs, SK_RESP_BUFFERS, token);
144 if (i != SK_RESP_BUFFERS) {
145 printerr(0, "Invalid token received\n");
149 rc = sk_verify_hmac(skc, bufs, SK_RESP_BUFFERS - 1, EVP_sha256(),
150 &bufs[SK_RESP_HMAC]);
151 if (rc != GSS_S_COMPLETE) {
152 printerr(0, "Invalid HMAC receieved: 0x%x\n", rc);
156 if (bufs[SK_RESP_VERSION].length != sizeof(version)) {
157 printerr(0, "Invalid version received (wrong size)\n");
160 memcpy(&version, bufs[SK_RESP_VERSION].value, sizeof(version));
161 version = be32toh(version);
162 if (version != SK_MSG_VERSION) {
163 printerr(0, "Invalid version received: %d\n", version);
167 /* In the rare event that both the random values are equal the
168 * client has the responsability to retry the connection attempt
169 * otherwise we would leak information about the plain text by
170 * reuusing IVs as both peer and host use the same values other
172 memcpy(&skc->sc_kctx.skc_peer_random, bufs[SK_RESP_RANDOM].value,
173 sizeof(skc->sc_kctx.skc_peer_random));
174 if (skc->sc_kctx.skc_host_random == skc->sc_kctx.skc_peer_random) {
175 printerr(0, "Host and peer randoms are equal, must retry to "
176 "ensure unique value for nonce\n");
180 rc = sk_compute_dh_key(skc, &bufs[SK_RESP_PUB_KEY]);
181 if (rc == GSS_S_BAD_QOP) {
182 /* Defective token for short key means we need to retry
183 * because there is a chance that the parameters generated
184 * resulted in a key that is 1 byte short */
185 printerr(0, "Short key computed, must retry\n");
187 } else if (rc != GSS_S_COMPLETE) {
188 printerr(0, "Failed to compute session key: 0x%x\n", rc);
192 rc = sk_session_kdf(skc, cred->lc_self_nid, &cred->lc_mech_token,
195 printerr(0, "Failed to calulate derived key\n");
199 rc = sk_compute_keys(skc);
201 printerr(0, "Failed to compute HMAC and session key\n");
205 if (sk_serialize_kctx(skc, ctx_token)) {
206 printerr(0, "Failed to serialize context for kernel\n");
213 struct lgss_mech_type lgss_mech_sk = {
215 .lmt_mech_n = LGSS_MECH_SK,
216 .lmt_prepare_cred = lgss_sk_prepare_cred,
217 .lmt_release_cred = lgss_sk_release_cred,
218 .lmt_using_cred = lgss_sk_using_cred,
219 .lmt_validate_cred = lgss_sk_validate_cred,