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