1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/gssapi/krb5/verify_mic.c - krb5 gss_verify_mic() implementation */
3 /*
4 * Copyright (C) 2024 by the Massachusetts Institute of Technology.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include "gssapiP_krb5.h"
34
35 OM_uint32
kg_verify_mic_v1(krb5_context context,OM_uint32 * minor_status,krb5_gss_ctx_id_rec * ctx,uint16_t exp_toktype,struct k5input * in,gss_buffer_t message)36 kg_verify_mic_v1(krb5_context context, OM_uint32 *minor_status,
37 krb5_gss_ctx_id_rec *ctx, uint16_t exp_toktype,
38 struct k5input *in, gss_buffer_t message)
39 {
40 krb5_error_code ret = 0;
41 krb5_keyusage usage;
42 const uint8_t *header, *seqbytes, *cksum;
43 int direction;
44 size_t cksum_len;
45 uint32_t seqnum, filler;
46 uint16_t toktype, signalg;
47
48 if (ctx->seq == NULL) {
49 /* ctx was established using a newer enctype, and cannot process RFC
50 * 1964 tokens. */
51 return GSS_S_DEFECTIVE_TOKEN;
52 }
53
54 header = in->ptr;
55 toktype = k5_input_get_uint16_be(in);
56 signalg = k5_input_get_uint16_le(in);
57 filler = k5_input_get_uint32_le(in);
58 seqbytes = k5_input_get_bytes(in, 8);
59 cksum_len = (signalg == SGN_ALG_HMAC_SHA1_DES3_KD) ? 20 : 8;
60 cksum = k5_input_get_bytes(in, cksum_len);
61
62 if (in->status || in->len != 0 || toktype != exp_toktype ||
63 filler != 0xFFFFFFFF || signalg != ctx->signalg)
64 return GSS_S_DEFECTIVE_TOKEN;
65 usage = (signalg == SGN_ALG_HMAC_MD5) ? 15 : KG_USAGE_SIGN;
66
67 ret = kg_get_seq_num(context, ctx->seq, cksum, seqbytes, &direction,
68 &seqnum);
69 if (ret) {
70 *minor_status = ret;
71 return GSS_S_BAD_SIG;
72 }
73
74 if (!kg_verify_checksum_v1(context, signalg, ctx->seq, usage, header,
75 message->value, message->length,
76 cksum, cksum_len))
77 return GSS_S_BAD_SIG;
78
79 if ((ctx->initiate && direction != 0xff) ||
80 (!ctx->initiate && direction != 0)) {
81 *minor_status = (OM_uint32)G_BAD_DIRECTION;
82 return GSS_S_BAD_SIG;
83 }
84
85 return g_seqstate_check(ctx->seqstate, seqnum);
86 }
87
88 static OM_uint32
verify_mic_v3(krb5_context context,OM_uint32 * minor_status,krb5_gss_ctx_id_rec * ctx,struct k5input * in,gss_buffer_t message)89 verify_mic_v3(krb5_context context, OM_uint32 *minor_status,
90 krb5_gss_ctx_id_rec *ctx, struct k5input *in,
91 gss_buffer_t message)
92 {
93 krb5_keyusage usage;
94 krb5_key key;
95 krb5_cksumtype cksumtype;
96 uint64_t seqnum;
97 uint32_t filler2;
98 uint16_t toktype;
99 uint8_t flags, filler1;
100
101 toktype = k5_input_get_uint16_be(in);
102 flags = k5_input_get_byte(in);
103 filler1 = k5_input_get_byte(in);
104 filler2 = k5_input_get_uint32_be(in);
105 seqnum = k5_input_get_uint64_be(in);
106
107 if (in->status || toktype != KG2_TOK_MIC_MSG || filler1 != 0xFF ||
108 filler2 != 0xFFFFFFFF)
109 return GSS_S_DEFECTIVE_TOKEN;
110
111 if (!!(flags & FLAG_SENDER_IS_ACCEPTOR) != ctx->initiate) {
112 *minor_status = (OM_uint32)G_BAD_DIRECTION;
113 return GSS_S_BAD_SIG;
114 }
115
116 usage = ctx->initiate ? KG_USAGE_ACCEPTOR_SIGN : KG_USAGE_INITIATOR_SIGN;
117 if (ctx->have_acceptor_subkey && (flags & FLAG_ACCEPTOR_SUBKEY)) {
118 key = ctx->acceptor_subkey;
119 cksumtype = ctx->acceptor_subkey_cksumtype;
120 } else {
121 key = ctx->subkey;
122 cksumtype = ctx->cksumtype;
123 }
124 assert(key != NULL);
125
126 if (!kg_verify_checksum_v3(context, key, usage, cksumtype, KG2_TOK_MIC_MSG,
127 flags, seqnum, message->value, message->length,
128 in->ptr, in->len))
129 return GSS_S_BAD_SIG;
130
131 return g_seqstate_check(ctx->seqstate, seqnum);
132 }
133
134 OM_uint32 KRB5_CALLCONV
krb5_gss_verify_mic(OM_uint32 * minor_status,gss_ctx_id_t context_handle,gss_buffer_t message,gss_buffer_t token,gss_qop_t * qop_state)135 krb5_gss_verify_mic(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
136 gss_buffer_t message, gss_buffer_t token,
137 gss_qop_t *qop_state)
138 {
139 krb5_gss_ctx_id_rec *ctx = (krb5_gss_ctx_id_rec *)context_handle;
140 uint16_t toktype;
141 OM_uint32 major;
142 struct k5input in, unwrapped;
143
144 *minor_status = 0;
145 if (qop_state != NULL)
146 *qop_state = GSS_C_QOP_DEFAULT;
147
148 if (ctx->terminated || !ctx->established) {
149 *minor_status = KG_CTX_INCOMPLETE;
150 return GSS_S_NO_CONTEXT;
151 }
152
153 k5_input_init(&in, token->value, token->length);
154 (void)g_verify_token_header(&in, ctx->mech_used);
155 unwrapped = in;
156
157 toktype = k5_input_get_uint16_be(&in);
158 if (toktype == KG_TOK_MIC_MSG) {
159 major = kg_verify_mic_v1(ctx->k5_context, minor_status, ctx, toktype,
160 &unwrapped, message);
161 } else if (toktype == KG2_TOK_MIC_MSG) {
162 major = verify_mic_v3(ctx->k5_context, minor_status, ctx, &unwrapped,
163 message);
164 } else {
165 *minor_status = (OM_uint32)G_BAD_TOK_HEADER;
166 major = GSS_S_DEFECTIVE_TOKEN;
167 }
168
169 if (major)
170 save_error_info(*minor_status, ctx->k5_context);
171
172 return major;
173 }
174