1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
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 #include <sys/param.h>
32 #include <sys/malloc.h>
33 #include <sys/kobj.h>
34 #include <sys/mbuf.h>
35 #include <sys/sysctl.h>
36
37 #include <kgssapi/gssapi.h>
38 #include <kgssapi/gssapi_impl.h>
39
40 #include "kcrypto.h"
41
42 static struct krb5_encryption_class *krb5_encryption_classes[] = {
43 &krb5_aes128_encryption_class,
44 &krb5_aes256_encryption_class,
45 NULL
46 };
47
48 struct krb5_encryption_class *
krb5_find_encryption_class(int etype)49 krb5_find_encryption_class(int etype)
50 {
51 int i;
52
53 for (i = 0; krb5_encryption_classes[i]; i++) {
54 if (krb5_encryption_classes[i]->ec_type == etype)
55 return (krb5_encryption_classes[i]);
56 }
57 return (NULL);
58 }
59
60 struct krb5_key_state *
krb5_create_key(const struct krb5_encryption_class * ec)61 krb5_create_key(const struct krb5_encryption_class *ec)
62 {
63 struct krb5_key_state *ks;
64
65 ks = malloc(sizeof(struct krb5_key_state), M_GSSAPI, M_WAITOK);
66 ks->ks_class = ec;
67 refcount_init(&ks->ks_refs, 1);
68 ks->ks_key = malloc(ec->ec_keylen, M_GSSAPI, M_WAITOK);
69 ec->ec_init(ks);
70
71 return (ks);
72 }
73
74 void
krb5_free_key(struct krb5_key_state * ks)75 krb5_free_key(struct krb5_key_state *ks)
76 {
77
78 if (refcount_release(&ks->ks_refs)) {
79 ks->ks_class->ec_destroy(ks);
80 bzero(ks->ks_key, ks->ks_class->ec_keylen);
81 free(ks->ks_key, M_GSSAPI);
82 free(ks, M_GSSAPI);
83 }
84 }
85
86 static size_t
gcd(size_t a,size_t b)87 gcd(size_t a, size_t b)
88 {
89
90 if (b == 0)
91 return (a);
92 return gcd(b, a % b);
93 }
94
95 static size_t
lcm(size_t a,size_t b)96 lcm(size_t a, size_t b)
97 {
98 return ((a * b) / gcd(a, b));
99 }
100
101 /*
102 * Rotate right 13 of a variable precision number in 'in', storing the
103 * result in 'out'. The number is assumed to be big-endian in memory
104 * representation.
105 */
106 static void
krb5_rotate_right_13(uint8_t * out,uint8_t * in,size_t numlen)107 krb5_rotate_right_13(uint8_t *out, uint8_t *in, size_t numlen)
108 {
109 uint32_t carry;
110 size_t i;
111
112 /*
113 * Special case when numlen == 1. A rotate right 13 of a
114 * single byte number changes to a rotate right 5.
115 */
116 if (numlen == 1) {
117 carry = in[0] >> 5;
118 out[0] = (in[0] << 3) | carry;
119 return;
120 }
121
122 carry = ((in[numlen - 2] & 31) << 8) | in[numlen - 1];
123 for (i = 2; i < numlen; i++) {
124 out[i] = ((in[i - 2] & 31) << 3) | (in[i - 1] >> 5);
125 }
126 out[1] = ((carry & 31) << 3) | (in[0] >> 5);
127 out[0] = carry >> 5;
128 }
129
130 /*
131 * Add two variable precision numbers in big-endian representation
132 * using ones-complement arithmetic.
133 */
134 static void
krb5_ones_complement_add(uint8_t * out,const uint8_t * in,size_t len)135 krb5_ones_complement_add(uint8_t *out, const uint8_t *in, size_t len)
136 {
137 int n, i;
138
139 /*
140 * First calculate the 2s complement sum, remembering the
141 * carry.
142 */
143 n = 0;
144 for (i = len - 1; i >= 0; i--) {
145 n = out[i] + in[i] + n;
146 out[i] = n;
147 n >>= 8;
148 }
149 /*
150 * Then add back the carry.
151 */
152 for (i = len - 1; n && i >= 0; i--) {
153 n = out[i] + n;
154 out[i] = n;
155 n >>= 8;
156 }
157 }
158
159 static void
krb5_n_fold(uint8_t * out,size_t outlen,const uint8_t * in,size_t inlen)160 krb5_n_fold(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen)
161 {
162 size_t tmplen;
163 uint8_t *tmp;
164 size_t i;
165 uint8_t *p;
166
167 tmplen = lcm(inlen, outlen);
168 tmp = malloc(tmplen, M_GSSAPI, M_WAITOK);
169
170 bcopy(in, tmp, inlen);
171 for (i = inlen, p = tmp; i < tmplen; i += inlen, p += inlen) {
172 krb5_rotate_right_13(p + inlen, p, inlen);
173 }
174 bzero(out, outlen);
175 for (i = 0, p = tmp; i < tmplen; i += outlen, p += outlen) {
176 krb5_ones_complement_add(out, p, outlen);
177 }
178 free(tmp, M_GSSAPI);
179 }
180
181 struct krb5_key_state *
krb5_derive_key(struct krb5_key_state * inkey,void * constant,size_t constantlen)182 krb5_derive_key(struct krb5_key_state *inkey,
183 void *constant, size_t constantlen)
184 {
185 struct krb5_key_state *dk;
186 const struct krb5_encryption_class *ec = inkey->ks_class;
187 uint8_t *folded;
188 uint8_t *bytes, *p, *q;
189 struct mbuf *m;
190 int randomlen, i;
191
192 /*
193 * Expand the constant to blocklen bytes.
194 */
195 folded = malloc(ec->ec_blocklen, M_GSSAPI, M_WAITOK);
196 krb5_n_fold(folded, ec->ec_blocklen, constant, constantlen);
197
198 /*
199 * Generate enough bytes for keybits rounded up to a multiple
200 * of blocklen.
201 */
202 randomlen = roundup(ec->ec_keybits / 8, ec->ec_blocklen);
203 bytes = malloc(randomlen, M_GSSAPI, M_WAITOK);
204 MGET(m, M_WAITOK, MT_DATA);
205 m->m_len = ec->ec_blocklen;
206 for (i = 0, p = bytes, q = folded; i < randomlen;
207 q = p, i += ec->ec_blocklen, p += ec->ec_blocklen) {
208 bcopy(q, m->m_data, ec->ec_blocklen);
209 krb5_encrypt(inkey, m, 0, ec->ec_blocklen, NULL, 0);
210 bcopy(m->m_data, p, ec->ec_blocklen);
211 }
212 m_free(m);
213
214 dk = krb5_create_key(ec);
215 krb5_random_to_key(dk, bytes);
216
217 free(folded, M_GSSAPI);
218 free(bytes, M_GSSAPI);
219
220 return (dk);
221 }
222
223 static struct krb5_key_state *
krb5_get_usage_key(struct krb5_key_state * basekey,int usage,int which)224 krb5_get_usage_key(struct krb5_key_state *basekey, int usage, int which)
225 {
226 const struct krb5_encryption_class *ec = basekey->ks_class;
227
228 if (ec->ec_flags & EC_DERIVED_KEYS) {
229 uint8_t constant[5];
230
231 constant[0] = usage >> 24;
232 constant[1] = usage >> 16;
233 constant[2] = usage >> 8;
234 constant[3] = usage;
235 constant[4] = which;
236 return (krb5_derive_key(basekey, constant, 5));
237 } else {
238 refcount_acquire(&basekey->ks_refs);
239 return (basekey);
240 }
241 }
242
243 struct krb5_key_state *
krb5_get_encryption_key(struct krb5_key_state * basekey,int usage)244 krb5_get_encryption_key(struct krb5_key_state *basekey, int usage)
245 {
246
247 return (krb5_get_usage_key(basekey, usage, 0xaa));
248 }
249
250 struct krb5_key_state *
krb5_get_integrity_key(struct krb5_key_state * basekey,int usage)251 krb5_get_integrity_key(struct krb5_key_state *basekey, int usage)
252 {
253
254 return (krb5_get_usage_key(basekey, usage, 0x55));
255 }
256
257 struct krb5_key_state *
krb5_get_checksum_key(struct krb5_key_state * basekey,int usage)258 krb5_get_checksum_key(struct krb5_key_state *basekey, int usage)
259 {
260
261 return (krb5_get_usage_key(basekey, usage, 0x99));
262 }
263