Fixes for Heimdal (macOS) builds from Stefan.
[mech_eap.git] / mech_eap / inquire_sec_context_by_oid.c
1 /*
2  * Copyright (c) 2011, JANET(UK)
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  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * 3. Neither the name of JANET(UK) nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32
33 /*
34  * Return extended properties of a context handle.
35  */
36
37 #include "gssapiP_eap.h"
38
39 static OM_uint32
40 addEnctypeOidToBufferSet(OM_uint32 *minor,
41                          krb5_enctype encryptionType,
42                          gss_buffer_set_t *dataSet)
43 {
44     OM_uint32 major;
45     unsigned char oidBuf[16];
46     gss_OID_desc oid;
47     gss_buffer_desc buf;
48
49     oid.length = sizeof(oidBuf);
50     oid.elements = oidBuf;
51
52     major = composeOid(minor,
53                        "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x04",
54                        10,
55                        encryptionType,
56                        &oid);
57     if (GSS_ERROR(major))
58         return major;
59
60     buf.length = oid.length;
61     buf.value = oid.elements;
62
63     major = gss_add_buffer_set_member(minor, &buf, dataSet);
64
65     return major;
66 }
67
68 static void
69 zeroAndReleaseBufferSet(gss_buffer_set_t *dataSet)
70 {
71     OM_uint32 tmpMinor;
72     gss_buffer_set_t set = *dataSet;
73     size_t i;
74
75     if (set == GSS_C_NO_BUFFER_SET)
76         return;
77
78     for (i = 0; i <set->count; i++)
79         memset(set->elements[i].value, 0, set->elements[i].length);
80
81     gss_release_buffer_set(&tmpMinor, dataSet);
82 }
83
84 static OM_uint32
85 inquireSessionKey(OM_uint32 *minor,
86                   gss_const_ctx_id_t ctx,
87                   const gss_OID desired_object GSSEAP_UNUSED,
88                   gss_buffer_set_t *dataSet)
89 {
90     OM_uint32 major;
91     gss_buffer_desc buf;
92
93     if (ctx->encryptionType == ENCTYPE_NULL) {
94         major = GSS_S_UNAVAILABLE;
95         *minor = GSSEAP_KEY_UNAVAILABLE;
96         goto cleanup;
97     }
98
99     buf.length = KRB_KEY_LENGTH(&ctx->rfc3961Key);
100     buf.value = KRB_KEY_DATA(&ctx->rfc3961Key);
101
102     major = gss_add_buffer_set_member(minor, &buf, dataSet);
103     if (GSS_ERROR(major))
104         goto cleanup;
105
106     major = addEnctypeOidToBufferSet(minor, ctx->encryptionType, dataSet);
107     if (GSS_ERROR(major))
108         goto cleanup;
109
110     major = GSS_S_COMPLETE;
111     *minor = 0;
112
113 cleanup:
114     if (GSS_ERROR(major))
115         zeroAndReleaseBufferSet(dataSet);
116
117     return major;
118 }
119
120 static OM_uint32
121 inquireNegoExKey(OM_uint32 *minor,
122                   gss_const_ctx_id_t ctx,
123                   const gss_OID desired_object,
124                   gss_buffer_set_t *dataSet)
125 {
126     OM_uint32 major, tmpMinor;
127     int bInitiatorKey;
128     gss_buffer_desc salt;
129     gss_buffer_desc key = GSS_C_EMPTY_BUFFER;
130     size_t keySize;
131
132     bInitiatorKey = CTX_IS_INITIATOR(ctx);
133
134     if (ctx->encryptionType == ENCTYPE_NULL) {
135         major = GSS_S_UNAVAILABLE;
136         *minor = GSSEAP_KEY_UNAVAILABLE;
137         goto cleanup;
138     }
139
140     /*
141      * If the caller supplied the verify key OID, then we need the acceptor
142      * key if we are the initiator, and vice versa.
143      */
144     if (desired_object->length == 11 &&
145         memcmp(desired_object->elements,
146                "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x07", 11) == 0)
147         bInitiatorKey ^= 1;
148
149     if (bInitiatorKey) {
150         salt.length = NEGOEX_INITIATOR_SALT_LEN;
151         salt.value  = NEGOEX_INITIATOR_SALT;
152     } else {
153         salt.length = NEGOEX_ACCEPTOR_SALT_LEN;
154         salt.value  = NEGOEX_ACCEPTOR_SALT;
155     }
156
157     keySize = KRB_KEY_LENGTH(&ctx->rfc3961Key);
158
159     key.value = GSSEAP_MALLOC(keySize);
160     if (key.value == NULL) {
161         major = GSS_S_FAILURE;
162         *minor = ENOMEM;
163         goto cleanup;
164     }
165
166     key.length = keySize;
167
168     major = gssEapPseudoRandom(minor, ctx, GSS_C_PRF_KEY_FULL, &salt, &key);
169     if (GSS_ERROR(major))
170         goto cleanup;
171
172     major = gss_add_buffer_set_member(minor, &key, dataSet);
173     if (GSS_ERROR(major))
174         goto cleanup;
175
176     major = addEnctypeOidToBufferSet(minor, ctx->encryptionType, dataSet);
177     if (GSS_ERROR(major))
178         goto cleanup;
179
180     major = GSS_S_COMPLETE;
181     *minor = 0;
182
183 cleanup:
184     if (key.value != NULL) {
185         memset(key.value, 0, key.length);
186         gss_release_buffer(&tmpMinor, &key);
187     }
188     if (GSS_ERROR(major))
189         zeroAndReleaseBufferSet(dataSet);
190
191     return major;
192 }
193
194 static struct {
195     gss_OID_desc oid;
196     OM_uint32 (*inquire)(OM_uint32 *, gss_const_ctx_id_t,
197                          const gss_OID, gss_buffer_set_t *);
198 } inquireCtxOps[] = {
199     {
200         /* GSS_C_INQ_SSPI_SESSION_KEY */
201         { 11, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x05" },
202         inquireSessionKey
203     },
204     {
205         /* GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT + v1 */
206         { 12, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x06\x01" },
207         gssEapExportLucidSecContext
208     },
209     {
210         /* GSS_C_INQ_NEGOEX_KEY */
211         { 11, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x06" },
212         inquireNegoExKey
213     },
214     {
215         /* GSS_C_INQ_NEGOEX_VERIFY_KEY */
216         { 11, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x07" },
217         inquireNegoExKey
218     },
219 };
220
221 OM_uint32 GSSAPI_CALLCONV
222 gss_inquire_sec_context_by_oid(OM_uint32 *minor,
223 #ifdef HAVE_HEIMDAL_VERSION
224                                gss_const_ctx_id_t ctx,
225 #else
226                                const gss_ctx_id_t ctx,
227 #endif
228                                const gss_OID desired_object,
229                                gss_buffer_set_t *data_set)
230 {
231     OM_uint32 major;
232     int i;
233
234     *data_set = GSS_C_NO_BUFFER_SET;
235
236     GSSEAP_MUTEX_LOCK(&((gss_ctx_id_t)ctx)->mutex);
237
238 #if 0
239     if (!CTX_IS_ESTABLISHED(ctx)) {
240         *minor = GSSEAP_CONTEXT_INCOMPLETE;
241         major = GSS_S_NO_CONTEXT;
242         goto cleanup;
243     }
244 #endif
245
246     major = GSS_S_UNAVAILABLE;
247     *minor = GSSEAP_BAD_CONTEXT_OPTION;
248
249     for (i = 0; i < sizeof(inquireCtxOps) / sizeof(inquireCtxOps[0]); i++) {
250         if (oidEqual(&inquireCtxOps[i].oid, desired_object)) {
251             major = (*inquireCtxOps[i].inquire)(minor, ctx,
252                                                  desired_object, data_set);
253             break;
254         }
255     }
256
257     GSSEAP_MUTEX_UNLOCK(&((gss_ctx_id_t)ctx)->mutex);
258
259     return major;
260 }