xref: /freebsd/crypto/krb5/src/lib/gssapi/krb5/util_cksum.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  * Copyright 1993 by OpenVision Technologies, Inc.
4  *
5  * Permission to use, copy, modify, distribute, and sell this software
6  * and its documentation for any purpose is hereby granted without fee,
7  * provided that the above copyright notice appears in all copies and
8  * that both that copyright notice and this permission notice appear in
9  * supporting documentation, and that the name of OpenVision not be used
10  * in advertising or publicity pertaining to distribution of the software
11  * without specific, written prior permission. OpenVision makes no
12  * representations about the suitability of this software for any
13  * purpose.  It is provided "as is" without express or implied warranty.
14  *
15  * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17  * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
19  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
20  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21  * PERFORMANCE OF THIS SOFTWARE.
22  */
23 
24 #include "gssapiP_krb5.h"
25 #ifdef HAVE_MEMORY_H
26 #include <memory.h>
27 #endif
28 
29 /* Checksumming the channel bindings always uses plain MD5.  */
30 krb5_error_code
kg_checksum_channel_bindings(context,cb,cksum)31 kg_checksum_channel_bindings(context, cb, cksum)
32     krb5_context context;
33     gss_channel_bindings_t cb;
34     krb5_checksum *cksum;
35 {
36     struct k5buf buf;
37     size_t sumlen;
38     krb5_data plaind;
39     krb5_error_code code;
40 
41     /* initialize the the cksum */
42     code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, &sumlen);
43     if (code)
44         return(code);
45 
46     cksum->checksum_type = CKSUMTYPE_RSA_MD5;
47     cksum->length = sumlen;
48     cksum->magic = KV5M_CHECKSUM;
49 
50     /* generate a buffer full of zeros if no cb specified */
51 
52     if (cb == GSS_C_NO_CHANNEL_BINDINGS) {
53         if ((cksum->contents = (krb5_octet *) xmalloc(cksum->length)) == NULL) {
54             return(ENOMEM);
55         }
56         memset(cksum->contents, '\0', cksum->length);
57         return(0);
58     }
59 
60     k5_buf_init_dynamic(&buf);
61     k5_buf_add_uint32_le(&buf, cb->initiator_addrtype);
62     k5_buf_add_uint32_le(&buf, cb->initiator_address.length);
63     k5_buf_add_len(&buf, cb->initiator_address.value,
64                    cb->initiator_address.length);
65     k5_buf_add_uint32_le(&buf, cb->acceptor_addrtype);
66     k5_buf_add_uint32_le(&buf, cb->acceptor_address.length);
67     k5_buf_add_len(&buf, cb->acceptor_address.value,
68                    cb->acceptor_address.length);
69     k5_buf_add_uint32_le(&buf, cb->application_data.length);
70     k5_buf_add_len(&buf, cb->application_data.value,
71                    cb->application_data.length);
72     code = k5_buf_status(&buf);
73     if (code)
74         return code;
75 
76     /* checksum the data */
77 
78     plaind = make_data(buf.data, buf.len);
79     code = krb5_c_make_checksum(context, CKSUMTYPE_RSA_MD5, 0, 0,
80                                 &plaind, cksum);
81     k5_buf_free(&buf);
82     return code;
83 }
84 
85 krb5_error_code
kg_make_checksum_iov_v1(krb5_context context,krb5_cksumtype type,size_t cksum_len,krb5_key seq,krb5_key enc,krb5_keyusage sign_usage,gss_iov_buffer_desc * iov,int iov_count,int toktype,krb5_checksum * checksum)86 kg_make_checksum_iov_v1(krb5_context context,
87                         krb5_cksumtype type,
88                         size_t cksum_len,
89                         krb5_key seq,
90                         krb5_key enc,
91                         krb5_keyusage sign_usage,
92                         gss_iov_buffer_desc *iov,
93                         int iov_count,
94                         int toktype,
95                         krb5_checksum *checksum)
96 {
97     krb5_error_code code;
98     gss_iov_buffer_desc *header;
99     krb5_crypto_iov *kiov;
100     int i = 0, j;
101     size_t conf_len = 0, token_header_len;
102 
103     header = kg_locate_header_iov(iov, iov_count, toktype);
104     assert(header != NULL);
105 
106     kiov = calloc(iov_count + 3, sizeof(krb5_crypto_iov));
107     if (kiov == NULL)
108         return ENOMEM;
109 
110     /* Checksum over ( Header | Confounder | Data | Pad ) */
111     if (toktype == KG_TOK_WRAP_MSG)
112         conf_len = kg_confounder_size(context, enc->keyblock.enctype);
113 
114     /* Checksum output */
115     kiov[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
116     kiov[i].data.length = checksum->length;
117     kiov[i].data.data = xmalloc(checksum->length);
118     if (kiov[i].data.data == NULL) {
119         xfree(kiov);
120         return ENOMEM;
121     }
122     i++;
123 
124     /* Header | SND_SEQ | SGN_CKSUM | Confounder */
125     token_header_len = 16 + cksum_len + conf_len;
126 
127     /* Header (calculate from end because of variable length ASN.1 header) */
128     kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
129     kiov[i].data.length = 8;
130     kiov[i].data.data = (char *)header->buffer.value + header->buffer.length - token_header_len;
131     i++;
132 
133     /* Confounder */
134     if (toktype == KG_TOK_WRAP_MSG) {
135         kiov[i].flags = KRB5_CRYPTO_TYPE_DATA;
136         kiov[i].data.length = conf_len;
137         kiov[i].data.data = (char *)header->buffer.value + header->buffer.length - conf_len;
138         i++;
139     }
140 
141     for (j = 0; j < iov_count; j++) {
142         kiov[i].flags = kg_translate_flag_iov(iov[j].type);
143         kiov[i].data.length = iov[j].buffer.length;
144         kiov[i].data.data = (char *)iov[j].buffer.value;
145         i++;
146     }
147 
148     code = krb5_k_make_checksum_iov(context, type, seq, sign_usage, kiov, i);
149     if (code == 0) {
150         checksum->length = kiov[0].data.length;
151         checksum->contents = (unsigned char *)kiov[0].data.data;
152     } else
153         free(kiov[0].data.data);
154 
155     xfree(kiov);
156 
157     return code;
158 }
159 
160 static krb5_error_code
checksum_iov_v3(krb5_context context,krb5_cksumtype type,size_t rrc,krb5_key key,krb5_keyusage sign_usage,gss_iov_buffer_desc * iov,int iov_count,int toktype,krb5_boolean verify,krb5_boolean * valid)161 checksum_iov_v3(krb5_context context,
162                 krb5_cksumtype type,
163                 size_t rrc,
164                 krb5_key key,
165                 krb5_keyusage sign_usage,
166                 gss_iov_buffer_desc *iov,
167                 int iov_count,
168                 int toktype,
169                 krb5_boolean verify,
170                 krb5_boolean *valid)
171 {
172     krb5_error_code code;
173     gss_iov_buffer_desc *header;
174     gss_iov_buffer_desc *trailer;
175     krb5_crypto_iov *kiov;
176     size_t kiov_count;
177     int i = 0, j;
178     unsigned int k5_checksumlen;
179 
180     if (verify)
181         *valid = FALSE;
182 
183     code = krb5_c_crypto_length(context, key->keyblock.enctype, KRB5_CRYPTO_TYPE_CHECKSUM, &k5_checksumlen);
184     if (code != 0)
185         return code;
186 
187     header = kg_locate_header_iov(iov, iov_count, toktype);
188     assert(header != NULL);
189 
190     trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
191     assert(rrc != 0 || trailer != NULL);
192 
193     if (trailer == NULL) {
194         if (rrc != k5_checksumlen)
195             return KRB5_BAD_MSIZE;
196         if (header->buffer.length != 16 + k5_checksumlen)
197             return KRB5_BAD_MSIZE;
198     } else if (trailer->buffer.length != k5_checksumlen)
199         return KRB5_BAD_MSIZE;
200 
201     kiov_count = 2 + iov_count;
202     kiov = (krb5_crypto_iov *)xmalloc(kiov_count * sizeof(krb5_crypto_iov));
203     if (kiov == NULL)
204         return ENOMEM;
205 
206     /* Checksum over ( Data | Header ) */
207 
208     /* Data */
209     for (j = 0; j < iov_count; j++) {
210         kiov[i].flags = kg_translate_flag_iov(iov[j].type);
211         kiov[i].data.length = iov[j].buffer.length;
212         kiov[i].data.data = (char *)iov[j].buffer.value;
213         i++;
214     }
215 
216     /* Header */
217     kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
218     kiov[i].data.length = 16;
219     kiov[i].data.data = (char *)header->buffer.value;
220     i++;
221 
222     /* Checksum */
223     kiov[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
224     if (trailer == NULL) {
225         kiov[i].data.length = header->buffer.length - 16;
226         kiov[i].data.data = (char *)header->buffer.value + 16;
227     } else {
228         kiov[i].data.length = trailer->buffer.length;
229         kiov[i].data.data = (char *)trailer->buffer.value;
230     }
231     i++;
232 
233     if (verify)
234         code = krb5_k_verify_checksum_iov(context, type, key, sign_usage, kiov, kiov_count, valid);
235     else
236         code = krb5_k_make_checksum_iov(context, type, key, sign_usage, kiov, kiov_count);
237 
238     xfree(kiov);
239 
240     return code;
241 }
242 
243 krb5_error_code
kg_make_checksum_iov_v3(krb5_context context,krb5_cksumtype type,size_t rrc,krb5_key key,krb5_keyusage sign_usage,gss_iov_buffer_desc * iov,int iov_count,int toktype)244 kg_make_checksum_iov_v3(krb5_context context,
245                         krb5_cksumtype type,
246                         size_t rrc,
247                         krb5_key key,
248                         krb5_keyusage sign_usage,
249                         gss_iov_buffer_desc *iov,
250                         int iov_count,
251                         int toktype)
252 {
253     return checksum_iov_v3(context, type, rrc, key,
254                            sign_usage, iov, iov_count, toktype, 0, NULL);
255 }
256 
257 krb5_error_code
kg_verify_checksum_iov_v3(krb5_context context,krb5_cksumtype type,size_t rrc,krb5_key key,krb5_keyusage sign_usage,gss_iov_buffer_desc * iov,int iov_count,int toktype,krb5_boolean * valid)258 kg_verify_checksum_iov_v3(krb5_context context,
259                           krb5_cksumtype type,
260                           size_t rrc,
261                           krb5_key key,
262                           krb5_keyusage sign_usage,
263                           gss_iov_buffer_desc *iov,
264                           int iov_count,
265                           int toktype,
266                           krb5_boolean *valid)
267 {
268     return checksum_iov_v3(context, type, rrc, key,
269                            sign_usage, iov, iov_count, toktype, 1, valid);
270 }
271