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 * 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 * 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 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 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 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 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 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 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 * 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 * 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 * 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 * 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 * 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