]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kgssapi/krb5/kcrypto.c
Upgrade our copies of clang, llvm, lld, lldb, compiler-rt, libc++,
[FreeBSD/FreeBSD.git] / sys / kgssapi / krb5 / kcrypto.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
5  * Authors: Doug Rabson <dfr@rabson.org>
6  * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/param.h>
34 #include <sys/malloc.h>
35 #include <sys/kobj.h>
36 #include <sys/mbuf.h>
37 #include <sys/sysctl.h>
38
39 #include <kgssapi/gssapi.h>
40 #include <kgssapi/gssapi_impl.h>
41
42 #include "kcrypto.h"
43
44 static struct krb5_encryption_class *krb5_encryption_classes[] = {
45         &krb5_des_encryption_class,
46         &krb5_des3_encryption_class,
47         &krb5_aes128_encryption_class,
48         &krb5_aes256_encryption_class,
49         &krb5_arcfour_encryption_class,
50         &krb5_arcfour_56_encryption_class,
51         NULL
52 };
53
54 struct timeval krb5_warn_interval = { .tv_sec = 3600, .tv_usec = 0 };
55 SYSCTL_TIMEVAL_SEC(_kern, OID_AUTO, kgssapi_warn_interval, CTLFLAG_RW,
56     &krb5_warn_interval,
57     "Delay in seconds between warnings of deprecated KGSSAPI crypto.");
58
59 struct krb5_encryption_class *
60 krb5_find_encryption_class(int etype)
61 {
62         int i;
63
64         for (i = 0; krb5_encryption_classes[i]; i++) {
65                 if (krb5_encryption_classes[i]->ec_type == etype)
66                         return (krb5_encryption_classes[i]);
67         }
68         return (NULL);
69 }
70
71 struct krb5_key_state *
72 krb5_create_key(const struct krb5_encryption_class *ec)
73 {
74         struct krb5_key_state *ks;
75
76         ks = malloc(sizeof(struct krb5_key_state), M_GSSAPI, M_WAITOK);
77         ks->ks_class = ec;
78         refcount_init(&ks->ks_refs, 1);
79         ks->ks_key = malloc(ec->ec_keylen, M_GSSAPI, M_WAITOK);
80         ec->ec_init(ks);
81
82         return (ks);
83 }
84
85 void
86 krb5_free_key(struct krb5_key_state *ks)
87 {
88
89         if (refcount_release(&ks->ks_refs)) {
90                 ks->ks_class->ec_destroy(ks);
91                 bzero(ks->ks_key, ks->ks_class->ec_keylen);
92                 free(ks->ks_key, M_GSSAPI);
93                 free(ks, M_GSSAPI);
94         }
95 }
96
97 static size_t
98 gcd(size_t a, size_t b)
99 {
100
101         if (b == 0)
102                 return (a);
103         return gcd(b, a % b);
104 }
105
106 static size_t
107 lcm(size_t a, size_t b)
108 {
109         return ((a * b) / gcd(a, b));
110 }
111
112 /*
113  * Rotate right 13 of a variable precision number in 'in', storing the
114  * result in 'out'. The number is assumed to be big-endian in memory
115  * representation.
116  */
117 static void
118 krb5_rotate_right_13(uint8_t *out, uint8_t *in, size_t numlen)
119 {
120         uint32_t carry;
121         size_t i;
122
123         /*
124          * Special case when numlen == 1. A rotate right 13 of a
125          * single byte number changes to a rotate right 5.
126          */
127         if (numlen == 1) {
128                 carry = in[0] >> 5;
129                 out[0] = (in[0] << 3) | carry;
130                 return;
131         }
132
133         carry = ((in[numlen - 2] & 31) << 8) | in[numlen - 1];
134         for (i = 2; i < numlen; i++) {
135                 out[i] = ((in[i - 2] & 31) << 3) | (in[i - 1] >> 5);
136         }
137         out[1] = ((carry & 31) << 3) | (in[0] >> 5);
138         out[0] = carry >> 5;
139 }
140
141 /*
142  * Add two variable precision numbers in big-endian representation
143  * using ones-complement arithmetic.
144  */
145 static void
146 krb5_ones_complement_add(uint8_t *out, const uint8_t *in, size_t len)
147 {
148         int n, i;
149
150         /*
151          * First calculate the 2s complement sum, remembering the
152          * carry.
153          */
154         n = 0;
155         for (i = len - 1; i >= 0; i--) {
156                 n = out[i] + in[i] + n;
157                 out[i] = n;
158                 n >>= 8;
159         }
160         /*
161          * Then add back the carry.
162          */
163         for (i = len - 1; n && i >= 0; i--) {
164                 n = out[i] + n;
165                 out[i] = n;
166                 n >>= 8;
167         }
168 }
169
170 static void
171 krb5_n_fold(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen)
172 {
173         size_t tmplen;
174         uint8_t *tmp;
175         size_t i;
176         uint8_t *p;
177
178         tmplen = lcm(inlen, outlen);
179         tmp = malloc(tmplen, M_GSSAPI, M_WAITOK);
180
181         bcopy(in, tmp, inlen);
182         for (i = inlen, p = tmp; i < tmplen; i += inlen, p += inlen) {
183                 krb5_rotate_right_13(p + inlen, p, inlen);
184         }
185         bzero(out, outlen);
186         for (i = 0, p = tmp; i < tmplen; i += outlen, p += outlen) {
187                 krb5_ones_complement_add(out, p, outlen);
188         }
189         free(tmp, M_GSSAPI);
190 }
191
192 struct krb5_key_state *
193 krb5_derive_key(struct krb5_key_state *inkey,
194     void *constant, size_t constantlen)
195 {
196         struct krb5_key_state *dk;
197         const struct krb5_encryption_class *ec = inkey->ks_class;
198         uint8_t *folded;
199         uint8_t *bytes, *p, *q;
200         struct mbuf *m;
201         int randomlen, i;
202
203         /*
204          * Expand the constant to blocklen bytes.
205          */
206         folded = malloc(ec->ec_blocklen, M_GSSAPI, M_WAITOK);
207         krb5_n_fold(folded, ec->ec_blocklen, constant, constantlen);
208
209         /*
210          * Generate enough bytes for keybits rounded up to a multiple
211          * of blocklen.
212          */
213         randomlen = roundup(ec->ec_keybits / 8, ec->ec_blocklen);
214         bytes = malloc(randomlen, M_GSSAPI, M_WAITOK);
215         MGET(m, M_WAITOK, MT_DATA);
216         m->m_len = ec->ec_blocklen;
217         for (i = 0, p = bytes, q = folded; i < randomlen;
218              q = p, i += ec->ec_blocklen, p += ec->ec_blocklen) {
219                 bcopy(q, m->m_data, ec->ec_blocklen);
220                 krb5_encrypt(inkey, m, 0, ec->ec_blocklen, NULL, 0);
221                 bcopy(m->m_data, p, ec->ec_blocklen);
222         }
223         m_free(m);
224
225         dk = krb5_create_key(ec);
226         krb5_random_to_key(dk, bytes);
227
228         free(folded, M_GSSAPI);
229         free(bytes, M_GSSAPI);
230
231         return (dk);
232 }
233
234 static struct krb5_key_state *
235 krb5_get_usage_key(struct krb5_key_state *basekey, int usage, int which)
236 {
237         const struct krb5_encryption_class *ec = basekey->ks_class;
238
239         if (ec->ec_flags & EC_DERIVED_KEYS) {
240                 uint8_t constant[5];
241
242                 constant[0] = usage >> 24;
243                 constant[1] = usage >> 16;
244                 constant[2] = usage >> 8;
245                 constant[3] = usage;
246                 constant[4] = which;
247                 return (krb5_derive_key(basekey, constant, 5));
248         } else {
249                 refcount_acquire(&basekey->ks_refs);
250                 return (basekey);
251         }
252 }
253
254 struct krb5_key_state *
255 krb5_get_encryption_key(struct krb5_key_state *basekey, int usage)
256 {
257
258         return (krb5_get_usage_key(basekey, usage, 0xaa));
259 }
260
261 struct krb5_key_state *
262 krb5_get_integrity_key(struct krb5_key_state *basekey, int usage)
263 {
264
265         return (krb5_get_usage_key(basekey, usage, 0x55));
266 }
267
268 struct krb5_key_state *
269 krb5_get_checksum_key(struct krb5_key_state *basekey, int usage)
270 {
271
272         return (krb5_get_usage_key(basekey, usage, 0x99));
273 }