Whamcloud - gitweb
5974c33bc24f2b9bb092347cef6937614aaf7673
[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 /* 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>
35
36 #include "sk_utils.h"
37 #include "lgss_utils.h"
38
39 /**
40  * Create the initial shared key credentials
41  */
42 static int lgss_sk_prepare_cred(struct lgss_cred *cred)
43 {
44         uint32_t flags = cred->lc_root_flags;
45
46         switch (cred->lc_svc_type) {
47         case 'n':
48                 flags |= LGSS_SVC_NULL;
49                 break;
50         case 'a':
51                 flags |= LGSS_SVC_AUTH;
52                 break;
53         case 'i':
54                 flags |= LGSS_SVC_INTG;
55                 break;
56         case 'p':
57                 flags |= LGSS_SVC_PRIV;
58                 break;
59         default:
60                 break;
61         }
62
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",
66                          cred->lc_tgt_uuid);
67                 return -ENOKEY;
68         }
69
70         return 0;
71 }
72
73 /* Free all the sk_cred resources */
74 static void lgss_sk_release_cred(struct lgss_cred *cred)
75 {
76         struct sk_cred *skc = cred->lc_mech_cred;
77
78         sk_free_cred(skc);
79         cred->lc_mech_cred = NULL;
80         free(cred->lc_mech_token.value);
81 }
82
83 /**
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
88  */
89 static int lgss_sk_using_cred(struct lgss_cred *cred)
90 {
91         struct sk_cred *skc = cred->lc_mech_cred;
92         gss_buffer_desc bufs[SK_INIT_BUFFERS];
93         uint32_t version;
94         uint32_t flags;
95         int rc;
96
97         rc = sk_gen_params(skc, 0);
98         if (rc)
99                 return rc;
100
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);
114
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(),
118                           &skc->sc_hmac);
119         if (rc)
120                 return rc;
121
122         bufs[SK_INIT_HMAC] = skc->sc_hmac;
123         rc = sk_encode_netstring(bufs, SK_INIT_BUFFERS, &cred->lc_mech_token);
124         if (rc)
125                 return rc;
126
127         printerr(2, "Created netstring of %zd bytes\n",
128                  cred->lc_mech_token.length);
129
130         return 0;
131 }
132
133 static int lgss_sk_validate_cred(struct lgss_cred *cred, gss_buffer_desc *token,
134                                  gss_buffer_desc *ctx_token)
135 {
136         struct sk_cred *skc = cred->lc_mech_cred;
137         gss_buffer_desc bufs[SK_RESP_BUFFERS];
138         uint32_t version;
139         int i;
140         uint32_t rc;
141
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");
146                 return -EINVAL;
147         }
148
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);
153                 return -EINVAL;
154         }
155
156         if (bufs[SK_RESP_VERSION].length != sizeof(version)) {
157                 printerr(0, "Invalid version received (wrong size)\n");
158                 return -EINVAL;
159         }
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);
164                 return -EINVAL;
165         }
166
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
171          * than the nonce. */
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");
177                 return -EAGAIN;
178         }
179
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");
186                 return -EAGAIN;
187         } else if (rc != GSS_S_COMPLETE) {
188                 printerr(0, "Failed to compute session key: 0x%x\n", rc);
189                 return -EINVAL;
190         }
191
192         rc = sk_session_kdf(skc, cred->lc_self_nid, &cred->lc_mech_token,
193                             token);
194         if (rc) {
195                 printerr(0, "Failed to calulate derived key\n");
196                 return -EINVAL;
197         }
198
199         rc = sk_compute_keys(skc);
200         if (rc) {
201                 printerr(0, "Failed to compute HMAC and session key\n");
202                 return -EINVAL;
203         }
204
205         if (sk_serialize_kctx(skc, ctx_token)) {
206                 printerr(0, "Failed to serialize context for kernel\n");
207                 return -EINVAL;
208         }
209
210         return 0;
211 }
212
213 struct lgss_mech_type lgss_mech_sk = {
214         .lmt_name               = "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,
220 };