xref: /freebsd/crypto/krb5/src/lib/gssapi/krb5/verify_mic.c (revision f96110babbe16a2a475b0bb954a50aa374f8aae5)
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