Avoid side effects in assert expressions
[krb5.git] / src / lib / crypto / krb / cf2.c
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/crypto/krb/cf2.c */
3 /*
4  * Copyright (C) 2009 by the Massachusetts Institute of Technology.
5  * All rights reserved.
6  *
7  * Export of this software from the United States of America may
8  *   require a specific license from the United States Government.
9  *   It is the responsibility of any person or organization contemplating
10  *   export to obtain such a license before exporting.
11  *
12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13  * distribute this software and its documentation for any purpose and
14  * without fee is hereby granted, provided that the above copyright
15  * notice appear in all copies and that both that copyright notice and
16  * this permission notice appear in supporting documentation, and that
17  * the name of M.I.T. not be used in advertising or publicity pertaining
18  * to distribution of the software without specific, written prior
19  * permission.  Furthermore if you modify this software you must label
20  * your software as modified software and not distribute it in such a
21  * fashion that it might be confused with the original M.I.T. software.
22  * M.I.T. makes no representations about the suitability of
23  * this software for any purpose.  It is provided "as is" without express
24  * or implied warranty.
25  */
26
27 /*
28  * Implement KRB_FX_CF2 function per draft-ietf-krb-wg-preauth-framework-09.
29  * Take two keys and two pepper strings as input and return a combined key.
30  */
31
32 #include "crypto_int.h"
33
34 /*
35  * Call the PRF function multiple times with the pepper prefixed with
36  * a count byte  to get enough bits of output.
37  */
38 static krb5_error_code
39 prf_plus(krb5_context context, krb5_keyblock *k, const char *pepper,
40          size_t keybytes, char **out)
41 {
42     krb5_error_code retval = 0;
43     size_t prflen, iterations;
44     krb5_data out_data;
45     krb5_data in_data;
46     char *buffer = NULL;
47     struct k5buf prf_inbuf;
48
49     krb5int_buf_init_dynamic(&prf_inbuf);
50     krb5int_buf_add_len(&prf_inbuf, "\001", 1);
51     krb5int_buf_add(&prf_inbuf, pepper);
52     retval = krb5_c_prf_length( context, k->enctype, &prflen);
53     if (retval)
54         goto cleanup;
55     iterations = keybytes / prflen;
56     if (keybytes % prflen != 0)
57         iterations++;
58     assert(iterations <= 254);
59     buffer = k5alloc(iterations * prflen, &retval);
60     if (retval)
61         goto cleanup;
62     if (krb5int_buf_len(&prf_inbuf) == -1) {
63         retval = ENOMEM;
64         goto cleanup;
65     }
66     in_data.length = (krb5_int32) krb5int_buf_len(&prf_inbuf);
67     in_data.data = krb5int_buf_data(&prf_inbuf);
68     out_data.length = prflen;
69     out_data.data = buffer;
70
71     while (iterations > 0) {
72         retval = krb5_c_prf(context, k, &in_data, &out_data);
73         if (retval)
74             goto cleanup;
75         out_data.data += prflen;
76         in_data.data[0]++;
77         iterations--;
78     }
79
80     *out = buffer;
81     buffer = NULL;
82
83 cleanup:
84     free(buffer);
85     krb5int_free_buf(&prf_inbuf);
86     return retval;
87 }
88
89
90 krb5_error_code KRB5_CALLCONV
91 krb5_c_fx_cf2_simple(krb5_context context,
92                      krb5_keyblock *k1, const char *pepper1,
93                      krb5_keyblock *k2, const char *pepper2,
94                      krb5_keyblock **out)
95 {
96     const struct krb5_keytypes *out_enctype;
97     size_t keybytes, keylength, i;
98     char *prf1 = NULL, *prf2 = NULL;
99     krb5_data keydata;
100     krb5_enctype out_enctype_num;
101     krb5_error_code retval = 0;
102     krb5_keyblock *out_key = NULL;
103
104     if (k1 == NULL || !krb5_c_valid_enctype(k1->enctype))
105         return KRB5_BAD_ENCTYPE;
106     if (k2 == NULL || !krb5_c_valid_enctype(k2->enctype))
107         return KRB5_BAD_ENCTYPE;
108     out_enctype_num = k1->enctype;
109     assert(out != NULL);
110     out_enctype = find_enctype(out_enctype_num);
111     assert(out_enctype != NULL);
112     if (out_enctype->prf == NULL) {
113         if (context)
114             krb5int_set_error(&(context->err), KRB5_CRYPTO_INTERNAL,
115                               _("Enctype %d has no PRF"), out_enctype_num);
116         return KRB5_CRYPTO_INTERNAL;
117     }
118     keybytes = out_enctype->enc->keybytes;
119     keylength = out_enctype->enc->keylength;
120
121     retval = prf_plus(context, k1, pepper1, keybytes, &prf1);
122     if (retval)
123         goto cleanup;
124     retval = prf_plus(context, k2, pepper2, keybytes, &prf2);
125     if (retval)
126         goto cleanup;
127     for (i = 0; i < keybytes; i++)
128         prf1[i] ^= prf2[i];
129     retval = krb5int_c_init_keyblock(context, out_enctype_num, keylength,
130                                      &out_key);
131     if (retval)
132         goto cleanup;
133     keydata.data = prf1;
134     keydata.length = keybytes;
135     retval = (*out_enctype->rand2key)(&keydata, out_key);
136     if (retval)
137         goto cleanup;
138
139     *out = out_key;
140     out_key = NULL;
141
142 cleanup:
143     krb5int_c_free_keyblock( context, out_key);
144     zapfree(prf1, keybytes);
145     zapfree(prf2, keybytes);
146     return retval;
147 }