Update libeap to include make dist
[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                   const gss_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                   const gss_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     major = gssEapPseudoRandom(minor, ctx, GSS_C_PRF_KEY_FULL, &salt,
160                                keySize, &key);
161     if (GSS_ERROR(major))
162         goto cleanup;
163
164     major = gss_add_buffer_set_member(minor, &key, dataSet);
165     if (GSS_ERROR(major))
166         goto cleanup;
167
168     major = addEnctypeOidToBufferSet(minor, ctx->encryptionType, dataSet);
169     if (GSS_ERROR(major))
170         goto cleanup;
171
172     major = GSS_S_COMPLETE;
173     *minor = 0;
174
175 cleanup:
176     if (key.value != NULL) {
177         memset(key.value, 0, key.length);
178         gss_release_buffer(&tmpMinor, &key);
179     }
180     if (GSS_ERROR(major))
181         zeroAndReleaseBufferSet(dataSet);
182
183     return major;
184 }
185
186 static struct {
187     gss_OID_desc oid;
188     OM_uint32 (*inquire)(OM_uint32 *, const gss_ctx_id_t,
189                          const gss_OID, gss_buffer_set_t *);
190 } inquireCtxOps[] = {
191     {
192         /* GSS_C_INQ_SSPI_SESSION_KEY */
193         { 11, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x05" },
194         inquireSessionKey
195     },
196     {
197         /* GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT + v1 */
198         { 12, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x06\x01" },
199         gssEapExportLucidSecContext
200     },
201     {
202         /* GSS_C_INQ_NEGOEX_KEY */
203         { 11, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x06" },
204         inquireNegoExKey
205     },
206     {
207         /* GSS_C_INQ_NEGOEX_VERIFY_KEY */
208         { 11, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x07" },
209         inquireNegoExKey
210     },
211 };
212
213 OM_uint32 GSSAPI_CALLCONV
214 gss_inquire_sec_context_by_oid(OM_uint32 *minor,
215                                const gss_ctx_id_t ctx,
216                                const gss_OID desired_object,
217                                gss_buffer_set_t *data_set)
218 {
219     OM_uint32 major;
220     int i;
221
222     *data_set = GSS_C_NO_BUFFER_SET;
223
224     GSSEAP_MUTEX_LOCK(&ctx->mutex);
225
226 #if 0
227     if (!CTX_IS_ESTABLISHED(ctx)) {
228         *minor = GSSEAP_CONTEXT_INCOMPLETE;
229         major = GSS_S_NO_CONTEXT;
230         goto cleanup;
231     }
232 #endif
233
234     major = GSS_S_UNAVAILABLE;
235     *minor = GSSEAP_BAD_CONTEXT_OPTION;
236
237     for (i = 0; i < sizeof(inquireCtxOps) / sizeof(inquireCtxOps[0]); i++) {
238         if (oidEqual(&inquireCtxOps[i].oid, desired_object)) {
239             major = (*inquireCtxOps[i].inquire)(minor, ctx,
240                                                  desired_object, data_set);
241             break;
242         }
243     }
244
245     GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
246
247     return major;
248 }