2a4d8e8747ab0e1997197401c0294fc1394b0328
[metze/heimdal/wip.git] / lib / gssapi / sanon / crypto.c
1 /*
2  * Copyright (c) 2019-2020, AuriStor, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * - Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * - Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in
14  *   the documentation and/or other materials provided with the
15  *   distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28  * OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  */
31
32 #include "sanon_locl.h"
33
34 OM_uint32 GSSAPI_CALLCONV
35 _gss_sanon_wrap(OM_uint32 *minor,
36                 gss_const_ctx_id_t context_handle,
37                 int conf_req_flag,
38                 gss_qop_t qop_req,
39                 const gss_buffer_t input_message_buffer,
40                 int *conf_state,
41                 gss_buffer_t output_message_buffer)
42 {
43     const sanon_ctx sc = (const sanon_ctx)context_handle;
44
45     if (sc->rfc4121 == GSS_C_NO_CONTEXT) {
46         *minor = GSS_KRB5_S_KG_CTX_INCOMPLETE;
47         return GSS_S_NO_CONTEXT;
48     }
49
50     return gss_wrap(minor, sc->rfc4121,
51                     conf_req_flag, qop_req,
52                     input_message_buffer, conf_state,
53                     output_message_buffer);
54 }
55
56 OM_uint32 GSSAPI_CALLCONV
57 _gss_sanon_wrap_size_limit(OM_uint32 *minor,
58                            gss_const_ctx_id_t context_handle,
59                            int conf_req_flag,
60                            gss_qop_t qop_req,
61                            OM_uint32 req_output_size,
62                            OM_uint32 *max_input_size)
63 {
64     const sanon_ctx sc = (const sanon_ctx)context_handle;
65
66     if (sc->rfc4121 == GSS_C_NO_CONTEXT) {
67         *minor = GSS_KRB5_S_KG_CTX_INCOMPLETE;
68         return GSS_S_NO_CONTEXT;
69     }
70
71     return gss_wrap_size_limit(minor, sc->rfc4121,
72                                conf_req_flag, qop_req,
73                                req_output_size, max_input_size);
74 }
75
76 OM_uint32 GSSAPI_CALLCONV
77 _gss_sanon_wrap_iov(OM_uint32 *minor,
78                     gss_ctx_id_t context_handle,
79                     int conf_req_flag,
80                     gss_qop_t qop_req,
81                     int *conf_state,
82                     gss_iov_buffer_desc *iov,
83                     int iov_count)
84 {
85     const sanon_ctx sc = (const sanon_ctx)context_handle;
86
87     if (sc->rfc4121 == GSS_C_NO_CONTEXT) {
88         *minor = GSS_KRB5_S_KG_CTX_INCOMPLETE;
89         return GSS_S_NO_CONTEXT;
90     }
91
92     return gss_wrap_iov(minor, sc->rfc4121,
93                         conf_req_flag, qop_req,
94                         conf_state, iov, iov_count);
95 }
96
97 OM_uint32 GSSAPI_CALLCONV
98 _gss_sanon_wrap_iov_length(OM_uint32 *minor,
99                            gss_ctx_id_t context_handle,
100                            int conf_req_flag,
101                            gss_qop_t qop_req,
102                            int *conf_state,
103                            gss_iov_buffer_desc *iov,
104                            int iov_count)
105 {
106     const sanon_ctx sc = (const sanon_ctx)context_handle;
107
108     if (sc->rfc4121 == GSS_C_NO_CONTEXT) {
109         *minor = GSS_KRB5_S_KG_CTX_INCOMPLETE;
110         return GSS_S_NO_CONTEXT;
111     }
112
113     return gss_wrap_iov_length(minor, sc->rfc4121,
114                                conf_req_flag, qop_req,
115                                conf_state, iov, iov_count);
116 }
117
118 OM_uint32 GSSAPI_CALLCONV
119 _gss_sanon_unwrap(OM_uint32 *minor,
120                   gss_const_ctx_id_t context_handle,
121                   const gss_buffer_t input_message_buffer,
122                   gss_buffer_t output_message_buffer,
123                   int *conf_state,
124                   gss_qop_t * qop_state)
125 {
126     const sanon_ctx sc = (const sanon_ctx)context_handle;
127
128     if (sc->rfc4121 == GSS_C_NO_CONTEXT) {
129         *minor = GSS_KRB5_S_KG_CTX_INCOMPLETE;
130         return GSS_S_NO_CONTEXT;
131     }
132
133     return gss_unwrap(minor, sc->rfc4121,
134                       input_message_buffer, output_message_buffer,
135                       conf_state, qop_state);
136 }
137
138 OM_uint32 GSSAPI_CALLCONV
139 _gss_sanon_unwrap_iov(OM_uint32 *minor,
140                       gss_ctx_id_t context_handle,
141                       int *conf_state,
142                       gss_qop_t *qop_state,
143                       gss_iov_buffer_desc *iov,
144                       int iov_count)
145 {
146     const sanon_ctx sc = (const sanon_ctx)context_handle;
147
148     if (sc->rfc4121 == GSS_C_NO_CONTEXT) {
149         *minor = GSS_KRB5_S_KG_CTX_INCOMPLETE;
150         return GSS_S_NO_CONTEXT;
151     }
152
153     return gss_unwrap_iov(minor, sc->rfc4121,
154                           conf_state, qop_state,
155                           iov, iov_count);
156 }
157
158 OM_uint32 GSSAPI_CALLCONV
159 _gss_sanon_get_mic(OM_uint32 *minor,
160                    gss_const_ctx_id_t context_handle,
161                    gss_qop_t qop_req,
162                    const gss_buffer_t message_buffer,
163                    gss_buffer_t message_token)
164 {
165     const sanon_ctx sc = (const sanon_ctx)context_handle;
166
167     if (sc->rfc4121 == GSS_C_NO_CONTEXT) {
168         *minor = GSS_KRB5_S_KG_CTX_INCOMPLETE;
169         return GSS_S_NO_CONTEXT;
170     }
171
172     return gss_get_mic(minor, sc->rfc4121,
173                        qop_req, message_buffer,
174                        message_token);
175 }
176
177 OM_uint32 GSSAPI_CALLCONV
178 _gss_sanon_verify_mic(OM_uint32 *minor,
179                       gss_const_ctx_id_t context_handle,
180                       const gss_buffer_t message_buffer,
181                       const gss_buffer_t token_buffer,
182                       gss_qop_t *qop_state)
183 {
184     const sanon_ctx sc = (const sanon_ctx)context_handle;
185
186     if (sc->rfc4121 == GSS_C_NO_CONTEXT) {
187         *minor = GSS_KRB5_S_KG_CTX_INCOMPLETE;
188         return GSS_S_NO_CONTEXT;
189     }
190
191     return gss_verify_mic(minor, sc->rfc4121,
192                           message_buffer, token_buffer,
193                           qop_state);
194 }
195
196 OM_uint32 GSSAPI_CALLCONV
197 _gss_sanon_pseudo_random(OM_uint32 *minor,
198                          gss_ctx_id_t context_handle,
199                          int prf_key,
200                          const gss_buffer_t prf_in,
201                          ssize_t desired_output_len,
202                          gss_buffer_t prf_out)
203 {
204     const sanon_ctx sc = (const sanon_ctx)context_handle;
205
206     if (sc->rfc4121 == GSS_C_NO_CONTEXT) {
207         *minor = GSS_KRB5_S_KG_CTX_INCOMPLETE;
208         return GSS_S_NO_CONTEXT;
209     }
210
211     return gss_pseudo_random(minor, sc->rfc4121,
212                              prf_key, prf_in, desired_output_len,
213                              prf_out);
214 }
215
216 /*
217  * Generate a curve25519 secret and public key
218  */
219
220 OM_uint32
221 _gss_sanon_curve25519_base(OM_uint32 *minor, sanon_ctx sc)
222 {
223     krb5_generate_random_block(sc->sk, crypto_scalarmult_curve25519_BYTES);
224
225     if (crypto_scalarmult_curve25519_base(sc->pk, sc->sk) != 0) {
226         *minor = EINVAL;
227         return GSS_S_FAILURE;
228     }
229
230     return GSS_S_COMPLETE;
231 }
232
233 /*
234  * Derive the context session key using SP800-108 KDF in HMAC mode
235  * and the public keys and channel binding data.
236  */
237
238 OM_uint32
239 _gss_sanon_curve25519(OM_uint32 *minor,
240                       sanon_ctx sc,
241                       gss_buffer_t pk,
242                       const gss_channel_bindings_t input_chan_bindings,
243                       gss_buffer_t session_key)
244 {
245     uint8_t shared[crypto_scalarmult_curve25519_BYTES], *p;
246     krb5_error_code ret;
247     krb5_context context;
248     krb5_data kdf_K1, kdf_label, kdf_context, keydata;
249
250     _mg_buffer_zero(session_key);
251
252     if (pk == GSS_C_NO_BUFFER || pk->length != crypto_scalarmult_curve25519_BYTES)
253         return GSS_S_DEFECTIVE_TOKEN;
254
255     if (crypto_scalarmult_curve25519(shared, sc->sk, pk->value) != 0)
256         return GSS_S_FAILURE;
257
258     ret = krb5_init_context(&context);
259     if (ret != 0) {
260         *minor = ret;
261         return GSS_S_FAILURE;
262     }
263
264     kdf_K1.data = shared;
265     kdf_K1.length = sizeof(shared);
266
267     kdf_label.data = "sanon-x25519";
268     kdf_label.length = sizeof("sanon-x25519") - 1;
269
270     ret = krb5_data_alloc(&kdf_context,
271                           2 * crypto_scalarmult_curve25519_BYTES +
272                           (input_chan_bindings ? input_chan_bindings->application_data.length : 0));
273     if (ret != 0) {
274         krb5_free_context(context);
275         *minor = ret;
276         return GSS_S_FAILURE;
277     }
278
279     p = kdf_context.data;
280
281     if (sc->flags & SANON_FLAG_INITIATOR) {
282         memcpy(p, sc->pk, sizeof(sc->pk));
283         memcpy(&p[pk->length], pk->value, pk->length);
284     } else {
285         memcpy(p, pk->value, pk->length);
286         memcpy(&p[sizeof(sc->pk)], sc->pk, sizeof(sc->pk));
287     }
288
289     if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS &&
290         input_chan_bindings->application_data.value != NULL) {
291         memcpy(&p[2 * crypto_scalarmult_curve25519_BYTES],
292                input_chan_bindings->application_data.value,
293                input_chan_bindings->application_data.length);
294     }
295
296     ret = krb5_data_alloc(&keydata, 16);
297     if (ret == 0) {
298         ret = _krb5_SP800_108_HMAC_KDF(context, &kdf_K1, &kdf_label,
299                                        &kdf_context, EVP_sha256(), &keydata);
300
301         session_key->length = keydata.length;
302         session_key->value = keydata.data;
303     } else {
304         krb5_data_free(&keydata);
305     }
306
307     memset_s(kdf_context.data, kdf_context.length, 0, kdf_context.length);
308     krb5_data_free(&kdf_context);
309
310     memset_s(shared, sizeof(shared), 0, sizeof(shared));
311
312     krb5_free_context(context);
313
314     *minor = ret;
315     return ret != 0 ? GSS_S_FAILURE : GSS_S_COMPLETE;
316 }
317
318 OM_uint32
319 _gss_sanon_import_rfc4121_context(OM_uint32 *minor,
320                                   sanon_ctx sc,
321                                   OM_uint32 flags,
322                                   gss_const_buffer_t session_key)
323 {
324     return _gss_mg_import_rfc4121_context(minor,
325                                           !!(sc->flags & SANON_FLAG_INITIATOR),
326                                           flags,
327                                           KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128,
328                                           session_key,
329                                           &sc->rfc4121);
330 }
331