2 * Copyright (c) 2019-2020, AuriStor, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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
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.
32 #include "sanon_locl.h"
34 OM_uint32 GSSAPI_CALLCONV
35 _gss_sanon_wrap(OM_uint32 *minor,
36 gss_const_ctx_id_t context_handle,
39 const gss_buffer_t input_message_buffer,
41 gss_buffer_t output_message_buffer)
43 const sanon_ctx sc = (const sanon_ctx)context_handle;
45 if (sc->rfc4121 == GSS_C_NO_CONTEXT) {
46 *minor = GSS_KRB5_S_KG_CTX_INCOMPLETE;
47 return GSS_S_NO_CONTEXT;
50 return gss_wrap(minor, sc->rfc4121,
51 conf_req_flag, qop_req,
52 input_message_buffer, conf_state,
53 output_message_buffer);
56 OM_uint32 GSSAPI_CALLCONV
57 _gss_sanon_wrap_size_limit(OM_uint32 *minor,
58 gss_const_ctx_id_t context_handle,
61 OM_uint32 req_output_size,
62 OM_uint32 *max_input_size)
64 const sanon_ctx sc = (const sanon_ctx)context_handle;
66 if (sc->rfc4121 == GSS_C_NO_CONTEXT) {
67 *minor = GSS_KRB5_S_KG_CTX_INCOMPLETE;
68 return GSS_S_NO_CONTEXT;
71 return gss_wrap_size_limit(minor, sc->rfc4121,
72 conf_req_flag, qop_req,
73 req_output_size, max_input_size);
76 OM_uint32 GSSAPI_CALLCONV
77 _gss_sanon_wrap_iov(OM_uint32 *minor,
78 gss_ctx_id_t context_handle,
82 gss_iov_buffer_desc *iov,
85 const sanon_ctx sc = (const sanon_ctx)context_handle;
87 if (sc->rfc4121 == GSS_C_NO_CONTEXT) {
88 *minor = GSS_KRB5_S_KG_CTX_INCOMPLETE;
89 return GSS_S_NO_CONTEXT;
92 return gss_wrap_iov(minor, sc->rfc4121,
93 conf_req_flag, qop_req,
94 conf_state, iov, iov_count);
97 OM_uint32 GSSAPI_CALLCONV
98 _gss_sanon_wrap_iov_length(OM_uint32 *minor,
99 gss_ctx_id_t context_handle,
103 gss_iov_buffer_desc *iov,
106 const sanon_ctx sc = (const sanon_ctx)context_handle;
108 if (sc->rfc4121 == GSS_C_NO_CONTEXT) {
109 *minor = GSS_KRB5_S_KG_CTX_INCOMPLETE;
110 return GSS_S_NO_CONTEXT;
113 return gss_wrap_iov_length(minor, sc->rfc4121,
114 conf_req_flag, qop_req,
115 conf_state, iov, iov_count);
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,
124 gss_qop_t * qop_state)
126 const sanon_ctx sc = (const sanon_ctx)context_handle;
128 if (sc->rfc4121 == GSS_C_NO_CONTEXT) {
129 *minor = GSS_KRB5_S_KG_CTX_INCOMPLETE;
130 return GSS_S_NO_CONTEXT;
133 return gss_unwrap(minor, sc->rfc4121,
134 input_message_buffer, output_message_buffer,
135 conf_state, qop_state);
138 OM_uint32 GSSAPI_CALLCONV
139 _gss_sanon_unwrap_iov(OM_uint32 *minor,
140 gss_ctx_id_t context_handle,
142 gss_qop_t *qop_state,
143 gss_iov_buffer_desc *iov,
146 const sanon_ctx sc = (const sanon_ctx)context_handle;
148 if (sc->rfc4121 == GSS_C_NO_CONTEXT) {
149 *minor = GSS_KRB5_S_KG_CTX_INCOMPLETE;
150 return GSS_S_NO_CONTEXT;
153 return gss_unwrap_iov(minor, sc->rfc4121,
154 conf_state, qop_state,
158 OM_uint32 GSSAPI_CALLCONV
159 _gss_sanon_get_mic(OM_uint32 *minor,
160 gss_const_ctx_id_t context_handle,
162 const gss_buffer_t message_buffer,
163 gss_buffer_t message_token)
165 const sanon_ctx sc = (const sanon_ctx)context_handle;
167 if (sc->rfc4121 == GSS_C_NO_CONTEXT) {
168 *minor = GSS_KRB5_S_KG_CTX_INCOMPLETE;
169 return GSS_S_NO_CONTEXT;
172 return gss_get_mic(minor, sc->rfc4121,
173 qop_req, message_buffer,
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)
184 const sanon_ctx sc = (const sanon_ctx)context_handle;
186 if (sc->rfc4121 == GSS_C_NO_CONTEXT) {
187 *minor = GSS_KRB5_S_KG_CTX_INCOMPLETE;
188 return GSS_S_NO_CONTEXT;
191 return gss_verify_mic(minor, sc->rfc4121,
192 message_buffer, token_buffer,
196 OM_uint32 GSSAPI_CALLCONV
197 _gss_sanon_pseudo_random(OM_uint32 *minor,
198 gss_ctx_id_t context_handle,
200 const gss_buffer_t prf_in,
201 ssize_t desired_output_len,
202 gss_buffer_t prf_out)
204 const sanon_ctx sc = (const sanon_ctx)context_handle;
206 if (sc->rfc4121 == GSS_C_NO_CONTEXT) {
207 *minor = GSS_KRB5_S_KG_CTX_INCOMPLETE;
208 return GSS_S_NO_CONTEXT;
211 return gss_pseudo_random(minor, sc->rfc4121,
212 prf_key, prf_in, desired_output_len,
217 * Generate a curve25519 secret and public key
221 _gss_sanon_curve25519_base(OM_uint32 *minor, sanon_ctx sc)
223 krb5_generate_random_block(sc->sk, crypto_scalarmult_curve25519_BYTES);
225 if (crypto_scalarmult_curve25519_base(sc->pk, sc->sk) != 0) {
227 return GSS_S_FAILURE;
230 return GSS_S_COMPLETE;
234 * Derive the context session key using SP800-108 KDF in HMAC mode
235 * and the public keys and channel binding data.
239 _gss_sanon_curve25519(OM_uint32 *minor,
242 const gss_channel_bindings_t input_chan_bindings,
243 gss_buffer_t session_key)
245 uint8_t shared[crypto_scalarmult_curve25519_BYTES], *p;
247 krb5_context context;
248 krb5_data kdf_K1, kdf_label, kdf_context, keydata;
250 _mg_buffer_zero(session_key);
252 if (pk == GSS_C_NO_BUFFER || pk->length != crypto_scalarmult_curve25519_BYTES)
253 return GSS_S_DEFECTIVE_TOKEN;
255 if (crypto_scalarmult_curve25519(shared, sc->sk, pk->value) != 0)
256 return GSS_S_FAILURE;
258 ret = krb5_init_context(&context);
261 return GSS_S_FAILURE;
264 kdf_K1.data = shared;
265 kdf_K1.length = sizeof(shared);
267 kdf_label.data = "sanon-x25519";
268 kdf_label.length = sizeof("sanon-x25519") - 1;
270 ret = krb5_data_alloc(&kdf_context,
271 2 * crypto_scalarmult_curve25519_BYTES +
272 (input_chan_bindings ? input_chan_bindings->application_data.length : 0));
274 krb5_free_context(context);
276 return GSS_S_FAILURE;
279 p = kdf_context.data;
281 if (sc->flags & SANON_FLAG_INITIATOR) {
282 memcpy(p, sc->pk, sizeof(sc->pk));
283 memcpy(&p[pk->length], pk->value, pk->length);
285 memcpy(p, pk->value, pk->length);
286 memcpy(&p[sizeof(sc->pk)], sc->pk, sizeof(sc->pk));
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);
296 ret = krb5_data_alloc(&keydata, 16);
298 ret = _krb5_SP800_108_HMAC_KDF(context, &kdf_K1, &kdf_label,
299 &kdf_context, EVP_sha256(), &keydata);
301 session_key->length = keydata.length;
302 session_key->value = keydata.data;
304 krb5_data_free(&keydata);
307 memset_s(kdf_context.data, kdf_context.length, 0, kdf_context.length);
308 krb5_data_free(&kdf_context);
310 memset_s(shared, sizeof(shared), 0, sizeof(shared));
312 krb5_free_context(context);
315 return ret != 0 ? GSS_S_FAILURE : GSS_S_COMPLETE;
319 _gss_sanon_import_rfc4121_context(OM_uint32 *minor,
322 gss_const_buffer_t session_key)
324 return _gss_mg_import_rfc4121_context(minor,
325 !!(sc->flags & SANON_FLAG_INITIATOR),
327 KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128,