2 * Copyright (c) 2021, PADL Software Pty Ltd.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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.
16 * 3. Neither the name of PADL Software 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.
20 * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
21 * 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 PADL SOFTWARE 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
33 #include <krb5_locl.h>
34 #include <mech_locl.h>
37 #include "gss-preauth-protos.h"
38 #include "gss-preauth-private.h"
41 _krb5_gss_map_error(OM_uint32 major, OM_uint32 minor)
46 return (krb5_error_code)minor;
52 case GSS_S_CONTINUE_NEEDED:
53 ret = HEIM_ERR_PA_CONTINUE_NEEDED;
56 case GSS_S_BAD_NAMETYPE:
57 ret = KRB5_PRINC_NOMATCH;
60 ret = KRB5_CC_NOTFOUND;
63 case GSS_S_DEFECTIVE_CREDENTIAL:
64 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
67 if (minor == (OM_uint32)KRB5KRB_AP_ERR_BAD_INTEGRITY ||
68 minor == (OM_uint32)HNTLM_ERR_AUTH) {
69 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
73 ret = KRB5KDC_ERR_PREAUTH_FAILED;
81 _krb5_gss_pa_derive_key(krb5_context context,
85 krb5_keyblock **keyblock)
88 u_char saltdata[12] = "KRB-GSS";
92 OM_uint32 major, minor;
93 gss_buffer_desc salt, dkey = GSS_C_EMPTY_BUFFER;
97 ret = krb5_enctype_keysize(context, enctype, &keysize);
101 saltdata[ 8] = (nonce >> 0 ) & 0xFF;
102 saltdata[ 9] = (nonce >> 8 ) & 0xFF;
103 saltdata[10] = (nonce >> 16) & 0xFF;
104 saltdata[11] = (nonce >> 24) & 0xFF;
106 salt.value = saltdata;
107 salt.length = sizeof(saltdata);
109 major = gss_pseudo_random(&minor, ctx, GSS_C_PRF_KEY_FULL,
110 &salt, keysize, &dkey);
111 if (GSS_ERROR(major))
112 return KRB5_PREAUTH_NO_KEY;
114 kdkey.keytype = enctype;
115 kdkey.keyvalue.data = dkey.value;
116 kdkey.keyvalue.length = dkey.length;
118 ret = krb5_copy_keyblock(context, &kdkey, keyblock);
121 memset_s(dkey.value, dkey.length, 0, dkey.length);
122 gss_release_buffer(&minor, &dkey);
129 _krb5_gss_pa_unparse_name(krb5_context context,
130 krb5_const_principal principal,
136 OM_uint32 major, minor;
137 gss_buffer_desc name_buf;
139 *namep = GSS_C_NO_NAME;
141 if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
142 if (principal->name.name_string.len != 1)
145 name = principal->name.name_string.val[0];
147 ret = krb5_unparse_name(context, principal, &name);
152 name_buf.length = strlen(name);
153 name_buf.value = name;
155 major = gss_import_name(&minor, &name_buf,
156 GSS_KRB5_NT_PRINCIPAL_NAME, namep);
157 if (major == GSS_S_BAD_NAMETYPE) {
158 gss_OID name_type = GSS_C_NO_OID;
161 if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
162 name_type = GSS_C_NT_USER_NAME;
163 } else if (principal->name.name_type == KRB5_NT_PRINCIPAL) {
164 flags = KRB5_PRINCIPAL_UNPARSE_SHORT;
165 name_type = GSS_C_NT_USER_NAME;
166 } else if ((principal->name.name_type == KRB5_NT_SRV_HST ||
167 principal->name.name_type == KRB5_NT_SRV_INST) &&
168 principal->name.name_string.len == 2) {
169 flags = KRB5_PRINCIPAL_UNPARSE_NO_REALM;
170 name_type = GSS_C_NT_HOSTBASED_SERVICE;
176 ret = krb5_unparse_name_flags(context, principal, flags, &name);
180 if (gss_oid_equal(name_type, GSS_C_NT_HOSTBASED_SERVICE)) {
181 char *inst = strchr(name, '/');
186 name_buf.length = strlen(name);
187 name_buf.value = name;
191 major = gss_import_name(&minor, &name_buf, name_type, namep);
194 if (name != principal->name.name_string.val[0])
197 return _krb5_gss_map_error(major, minor);
201 _krb5_gss_pa_parse_name(krb5_context context,
202 gss_const_name_t name,
204 krb5_principal *principal)
207 char *displayed_name0;
209 OM_uint32 major, minor;
210 gss_OID name_type = GSS_C_NO_OID;
211 gss_buffer_desc displayed_name = GSS_C_EMPTY_BUFFER;
213 major = gss_display_name(&minor, name, &displayed_name, &name_type);
214 if (GSS_ERROR(major))
215 return _krb5_gss_map_error(major, minor);
217 if (gss_oid_equal(name_type, GSS_C_NT_ANONYMOUS)) {
218 ret = krb5_make_principal(context, principal, KRB5_ANON_REALM,
219 KRB5_WELLKNOWN_NAME, KRB5_ANON_NAME, NULL);
221 (*principal)->name.name_type = KRB5_NT_WELLKNOWN;
223 displayed_name0 = malloc(displayed_name.length + 1);
224 if (displayed_name0 == NULL)
225 return krb5_enomem(context);
227 memcpy(displayed_name0, displayed_name.value, displayed_name.length);
228 displayed_name0[displayed_name.length] = '\0';
230 ret = krb5_parse_name_flags(context, displayed_name0, flags, principal);
231 gss_release_buffer(&minor, &displayed_name);
232 free(displayed_name0);
235 gss_release_buffer(&minor, &displayed_name);
241 _krb5_gss_data_to_buffer(const krb5_data *data, gss_buffer_t buffer)
244 buffer->length = data->length;
245 buffer->value = data->data;
247 _mg_buffer_zero(buffer);
252 _krb5_gss_buffer_to_data(gss_const_buffer_t buffer, krb5_data *data)
255 data->length = buffer->length;
256 data->data = buffer->value;
258 krb5_data_zero(data);