xref: /freebsd/crypto/krb5/src/lib/gssapi/krb5/util_cksum.c (revision f1c4c3daccbaf3820f0e2224de53df12fc952fcc)
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(krb5_context context,gss_channel_bindings_t cb,krb5_checksum * cksum)31 kg_checksum_channel_bindings(krb5_context context, gss_channel_bindings_t cb,
32                              krb5_checksum *cksum)
33 {
34     struct k5buf buf;
35     size_t sumlen;
36     krb5_data plaind;
37     krb5_error_code code;
38 
39     /* initialize the the cksum */
40     code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, &sumlen);
41     if (code)
42         return(code);
43 
44     cksum->checksum_type = CKSUMTYPE_RSA_MD5;
45     cksum->length = sumlen;
46     cksum->magic = KV5M_CHECKSUM;
47 
48     /* generate a buffer full of zeros if no cb specified */
49 
50     if (cb == GSS_C_NO_CHANNEL_BINDINGS) {
51         if ((cksum->contents = (krb5_octet *) xmalloc(cksum->length)) == NULL) {
52             return(ENOMEM);
53         }
54         memset(cksum->contents, '\0', cksum->length);
55         return(0);
56     }
57 
58     k5_buf_init_dynamic(&buf);
59     k5_buf_add_uint32_le(&buf, cb->initiator_addrtype);
60     k5_buf_add_uint32_le(&buf, cb->initiator_address.length);
61     k5_buf_add_len(&buf, cb->initiator_address.value,
62                    cb->initiator_address.length);
63     k5_buf_add_uint32_le(&buf, cb->acceptor_addrtype);
64     k5_buf_add_uint32_le(&buf, cb->acceptor_address.length);
65     k5_buf_add_len(&buf, cb->acceptor_address.value,
66                    cb->acceptor_address.length);
67     k5_buf_add_uint32_le(&buf, cb->application_data.length);
68     k5_buf_add_len(&buf, cb->application_data.value,
69                    cb->application_data.length);
70     code = k5_buf_status(&buf);
71     if (code)
72         return code;
73 
74     /* checksum the data */
75 
76     plaind = make_data(buf.data, buf.len);
77     code = krb5_c_make_checksum(context, CKSUMTYPE_RSA_MD5, 0, 0,
78                                 &plaind, cksum);
79     k5_buf_free(&buf);
80     return code;
81 }
82 
83 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)84 kg_make_checksum_iov_v1(krb5_context context,
85                         krb5_cksumtype type,
86                         size_t cksum_len,
87                         krb5_key seq,
88                         krb5_key enc,
89                         krb5_keyusage sign_usage,
90                         gss_iov_buffer_desc *iov,
91                         int iov_count,
92                         int toktype,
93                         krb5_checksum *checksum)
94 {
95     krb5_error_code code;
96     gss_iov_buffer_desc *header;
97     krb5_crypto_iov *kiov;
98     int i = 0, j;
99     size_t conf_len = 0, token_header_len;
100 
101     header = kg_locate_header_iov(iov, iov_count, toktype);
102     assert(header != NULL);
103 
104     kiov = calloc(iov_count + 3, sizeof(krb5_crypto_iov));
105     if (kiov == NULL)
106         return ENOMEM;
107 
108     /* Checksum over ( Header | Confounder | Data | Pad ) */
109     if (toktype == KG_TOK_WRAP_MSG)
110         conf_len = kg_confounder_size(context, enc->keyblock.enctype);
111 
112     /* Checksum output */
113     kiov[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
114     kiov[i].data.length = checksum->length;
115     kiov[i].data.data = xmalloc(checksum->length);
116     if (kiov[i].data.data == NULL) {
117         xfree(kiov);
118         return ENOMEM;
119     }
120     i++;
121 
122     /* Header | SND_SEQ | SGN_CKSUM | Confounder */
123     token_header_len = 16 + cksum_len + conf_len;
124 
125     /* Header (calculate from end because of variable length ASN.1 header) */
126     kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
127     kiov[i].data.length = 8;
128     kiov[i].data.data = (char *)header->buffer.value + header->buffer.length - token_header_len;
129     i++;
130 
131     /* Confounder */
132     if (toktype == KG_TOK_WRAP_MSG) {
133         kiov[i].flags = KRB5_CRYPTO_TYPE_DATA;
134         kiov[i].data.length = conf_len;
135         kiov[i].data.data = (char *)header->buffer.value + header->buffer.length - conf_len;
136         i++;
137     }
138 
139     for (j = 0; j < iov_count; j++) {
140         kiov[i].flags = kg_translate_flag_iov(iov[j].type);
141         kiov[i].data.length = iov[j].buffer.length;
142         kiov[i].data.data = (char *)iov[j].buffer.value;
143         i++;
144     }
145 
146     code = krb5_k_make_checksum_iov(context, type, seq, sign_usage, kiov, i);
147     if (code == 0) {
148         checksum->length = kiov[0].data.length;
149         checksum->contents = (unsigned char *)kiov[0].data.data;
150     } else
151         free(kiov[0].data.data);
152 
153     xfree(kiov);
154 
155     return code;
156 }
157 
158 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)159 checksum_iov_v3(krb5_context context,
160                 krb5_cksumtype type,
161                 size_t rrc,
162                 krb5_key key,
163                 krb5_keyusage sign_usage,
164                 gss_iov_buffer_desc *iov,
165                 int iov_count,
166                 int toktype,
167                 krb5_boolean verify,
168                 krb5_boolean *valid)
169 {
170     krb5_error_code code;
171     gss_iov_buffer_desc *header;
172     gss_iov_buffer_desc *trailer;
173     krb5_crypto_iov *kiov;
174     size_t kiov_count;
175     int i = 0, j;
176     unsigned int k5_checksumlen;
177 
178     if (verify)
179         *valid = FALSE;
180 
181     code = krb5_c_crypto_length(context, key->keyblock.enctype, KRB5_CRYPTO_TYPE_CHECKSUM, &k5_checksumlen);
182     if (code != 0)
183         return code;
184 
185     header = kg_locate_header_iov(iov, iov_count, toktype);
186     assert(header != NULL);
187 
188     trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
189     assert(rrc != 0 || trailer != NULL);
190 
191     if (trailer == NULL) {
192         if (rrc != k5_checksumlen)
193             return KRB5_BAD_MSIZE;
194         if (header->buffer.length != 16 + k5_checksumlen)
195             return KRB5_BAD_MSIZE;
196     } else if (trailer->buffer.length != k5_checksumlen)
197         return KRB5_BAD_MSIZE;
198 
199     kiov_count = 2 + iov_count;
200     kiov = (krb5_crypto_iov *)xmalloc(kiov_count * sizeof(krb5_crypto_iov));
201     if (kiov == NULL)
202         return ENOMEM;
203 
204     /* Checksum over ( Data | Header ) */
205 
206     /* Data */
207     for (j = 0; j < iov_count; j++) {
208         kiov[i].flags = kg_translate_flag_iov(iov[j].type);
209         kiov[i].data.length = iov[j].buffer.length;
210         kiov[i].data.data = (char *)iov[j].buffer.value;
211         i++;
212     }
213 
214     /* Header */
215     kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
216     kiov[i].data.length = 16;
217     kiov[i].data.data = (char *)header->buffer.value;
218     i++;
219 
220     /* Checksum */
221     kiov[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
222     if (trailer == NULL) {
223         kiov[i].data.length = header->buffer.length - 16;
224         kiov[i].data.data = (char *)header->buffer.value + 16;
225     } else {
226         kiov[i].data.length = trailer->buffer.length;
227         kiov[i].data.data = (char *)trailer->buffer.value;
228     }
229     i++;
230 
231     if (verify)
232         code = krb5_k_verify_checksum_iov(context, type, key, sign_usage, kiov, kiov_count, valid);
233     else
234         code = krb5_k_make_checksum_iov(context, type, key, sign_usage, kiov, kiov_count);
235 
236     xfree(kiov);
237 
238     return code;
239 }
240 
241 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)242 kg_make_checksum_iov_v3(krb5_context context,
243                         krb5_cksumtype type,
244                         size_t rrc,
245                         krb5_key key,
246                         krb5_keyusage sign_usage,
247                         gss_iov_buffer_desc *iov,
248                         int iov_count,
249                         int toktype)
250 {
251     return checksum_iov_v3(context, type, rrc, key,
252                            sign_usage, iov, iov_count, toktype, 0, NULL);
253 }
254 
255 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)256 kg_verify_checksum_iov_v3(krb5_context context,
257                           krb5_cksumtype type,
258                           size_t rrc,
259                           krb5_key key,
260                           krb5_keyusage sign_usage,
261                           gss_iov_buffer_desc *iov,
262                           int iov_count,
263                           int toktype,
264                           krb5_boolean *valid)
265 {
266     return checksum_iov_v3(context, type, rrc, key,
267                            sign_usage, iov, iov_count, toktype, 1, valid);
268 }
269