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