Whamcloud - gitweb
b6f1fd8eab4c75f01ed1b598fdc4cd04b0a13c26
[fs/lustre-release.git] / lustre / utils / gss / lgss_sk_utils.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  * Author: Jeremy Filizetti <jfilizet@iu.edu>
26  */
27
28 #include <limits.h>
29 #include <string.h>
30 #include <openssl/dh.h>
31 #include <openssl/engine.h>
32 #include <openssl/err.h>
33
34 #include "sk_utils.h"
35 #include "lgss_utils.h"
36
37 /**
38  * Create the initial shared key credentials
39  */
40 static int lgss_sk_prepare_cred(struct lgss_cred *cred)
41 {
42         uint32_t flags = cred->lc_root_flags;
43
44         switch (cred->lc_svc_type) {
45         case 'n':
46                 flags |= LGSS_SVC_NULL;
47                 break;
48         case 'a':
49                 flags |= LGSS_SVC_AUTH;
50                 break;
51         case 'i':
52                 flags |= LGSS_SVC_INTG;
53                 break;
54         case 'p':
55                 flags |= LGSS_SVC_PRIV;
56                 break;
57         default:
58                 break;
59         }
60
61         cred->lc_mech_cred = sk_create_cred(cred->lc_tgt_uuid, NULL, flags);
62         if (cred->lc_mech_cred == NULL) {
63                 printerr(0, "sk: cannot create credential: %s\n",
64                          cred->lc_tgt_uuid);
65                 return -ENOKEY;
66         }
67
68         return 0;
69 }
70
71 /* Free all the sk_cred resources */
72 static void lgss_sk_release_cred(struct lgss_cred *cred)
73 {
74         struct sk_cred *skc = cred->lc_mech_cred;
75
76         sk_free_cred(skc);
77         cred->lc_mech_cred = NULL;
78         free(cred->lc_mech_token.value);
79         return;
80 }
81
82 /**
83  * Session key parameter generation is deferred until here because if privacy
84  * mode is enabled the session key parameter generation can take a while
85  * depending on the key size used and prepare is called before returning
86  * from the request_key upcall by lgss_keyring
87  */
88 static int lgss_sk_using_cred(struct lgss_cred *cred)
89 {
90         struct sk_cred *skc = cred->lc_mech_cred;
91         gss_buffer_desc bufs[SK_INIT_BUFFERS];
92         uint32_t version;
93         uint32_t flags;
94         int rc;
95
96         rc = sk_gen_params(skc);
97         if (rc)
98                 return rc;
99
100         /* HMAC is generated in this order */
101         version = htobe32(SK_MSG_VERSION);
102         bufs[SK_INIT_VERSION].value = &version;
103         bufs[SK_INIT_VERSION].length = sizeof(version);
104         bufs[SK_INIT_RANDOM].value = &skc->sc_kctx.skc_host_random;
105         bufs[SK_INIT_RANDOM].length = sizeof(skc->sc_kctx.skc_host_random);
106         bufs[SK_INIT_PUB_KEY] = skc->sc_pub_key;
107         bufs[SK_INIT_P] = skc->sc_p;
108         bufs[SK_INIT_TARGET] = skc->sc_tgt;
109         bufs[SK_INIT_NODEMAP] = skc->sc_nodemap_hash;
110         flags = htobe32(skc->sc_flags);
111         bufs[SK_INIT_FLAGS].value = &flags;
112         bufs[SK_INIT_FLAGS].length = sizeof(flags);
113
114         /* sign all the bufs except HMAC */
115         rc = sk_sign_bufs(&skc->sc_kctx.skc_shared_key, bufs,
116                           SK_INIT_BUFFERS - 1, EVP_sha256(),
117                           &skc->sc_hmac);
118         if (rc)
119                 return rc;
120
121         bufs[SK_INIT_HMAC] = skc->sc_hmac;
122         rc = sk_encode_netstring(bufs, SK_INIT_BUFFERS, &cred->lc_mech_token);
123         if (rc)
124                 return rc;
125
126         printerr(2, "Created netstring of %zd bytes\n",
127                  cred->lc_mech_token.length);
128
129         return 0;
130 }
131
132 static int lgss_sk_validate_cred(struct lgss_cred *cred, gss_buffer_desc *token,
133                                  gss_buffer_desc *ctx_token)
134 {
135         struct sk_cred *skc = cred->lc_mech_cred;
136         gss_buffer_desc bufs[SK_RESP_BUFFERS];
137         uint32_t version;
138         int i;
139         uint32_t rc;
140
141         /* Decode responder buffers and validate */
142         i = sk_decode_netstring(bufs, SK_RESP_BUFFERS, token);
143         if (i != SK_RESP_BUFFERS) {
144                 printerr(0, "Invalid token received\n");
145                 return -EINVAL;
146         }
147
148         rc = sk_verify_hmac(skc, bufs, SK_RESP_BUFFERS - 1, EVP_sha256(),
149                             &bufs[SK_RESP_HMAC]);
150         if (rc != GSS_S_COMPLETE) {
151                 printerr(0, "Invalid HMAC receieved: 0x%x\n", rc);
152                 return -EINVAL;
153         }
154
155         if (bufs[SK_RESP_VERSION].length != sizeof(version)) {
156                 printerr(0, "Invalid version received (wrong size)\n");
157                 return -EINVAL;
158         }
159         memcpy(&version, bufs[SK_RESP_VERSION].value, sizeof(version));
160         version = be32toh(version);
161         if (version != SK_MSG_VERSION) {
162                 printerr(0, "Invalid version received: %d\n", version);
163                 return -EINVAL;
164         }
165
166         /* In the rare event that both the random values are equal the
167          * client has the responsability to retry the connection attempt
168          * otherwise we would leak information about the plain text by
169          * reuusing IVs as both peer and host use the same values other
170          * than the nonce. */
171         memcpy(&skc->sc_kctx.skc_peer_random, bufs[SK_RESP_RANDOM].value,
172                sizeof(skc->sc_kctx.skc_peer_random));
173         if (skc->sc_kctx.skc_host_random == skc->sc_kctx.skc_peer_random) {
174                 printerr(0, "Host and peer randoms are equal, must retry to "
175                          "ensure unique value for nonce\n");
176                 return -EAGAIN;
177         }
178
179         rc = sk_compute_dh_key(skc, &bufs[SK_RESP_PUB_KEY]);
180         if (rc == GSS_S_DEFECTIVE_TOKEN) {
181                 /* Defective token for short key means we need to retry
182                  * because there is a chance that the parameters generated
183                  * resulted in a key that is 1 byte short */
184                 printerr(0, "Short key computed, must retry\n");
185                 return -EAGAIN;
186         } else if (rc != GSS_S_COMPLETE) {
187                 printerr(0, "Failed to compute session key: 0x%x\n", rc);
188                 return -EINVAL;
189         }
190
191         rc = sk_session_kdf(skc, cred->lc_self_nid, &cred->lc_mech_token,
192                             token);
193         if (rc) {
194                 printerr(0, "Failed to calulate derived key\n");
195                 return -EINVAL;
196         }
197
198         rc = sk_compute_keys(skc);
199         if (rc) {
200                 printerr(0, "Failed to compute HMAC and session key\n");
201                 return -EINVAL;
202         }
203
204         if (sk_serialize_kctx(skc, ctx_token)) {
205                 printerr(0, "Failed to serialize context for kernel\n");
206                 return -EINVAL;
207         }
208
209         return 0;
210 }
211
212 struct lgss_mech_type lgss_mech_sk = {
213         .lmt_name               = "sk",
214         .lmt_mech_n             = LGSS_MECH_SK,
215         .lmt_prepare_cred       = lgss_sk_prepare_cred,
216         .lmt_release_cred       = lgss_sk_release_cred,
217         .lmt_using_cred         = lgss_sk_using_cred,
218         .lmt_validate_cred      = lgss_sk_validate_cred,
219 };