]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet6/in6_cga.c
xnu-2782.30.5.tar.gz
[apple/xnu.git] / bsd / netinet6 / in6_cga.c
1 /*
2 * Copyright (c) 2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <sys/types.h>
30 #include <sys/malloc.h>
31
32 #include <kern/locks.h>
33
34 #include <libkern/crypto/sha1.h>
35
36 #include <net/if.h>
37
38 #include <netinet/in.h>
39 #include <netinet6/in6_var.h>
40 #include <netinet/ip6.h>
41 #include <netinet6/ip6_var.h>
42 #include <netinet6/nd6.h>
43
44 #define IN6_CGA_HASH1_LENGTH 8
45 #define IN6_CGA_HASH2_LENGTH 14
46 #define IN6_CGA_PREPARE_ZEROES 9
47
48 struct in6_cga_hash1 {
49 u_int8_t octets[IN6_CGA_HASH1_LENGTH];
50 };
51
52 struct in6_cga_hash2 {
53 u_int8_t octets[IN6_CGA_HASH2_LENGTH];
54 };
55
56 struct in6_cga_singleton {
57 boolean_t cga_initialized;
58 decl_lck_mtx_data(, cga_mutex);
59 struct in6_cga_prepare cga_prepare;
60 struct iovec cga_pubkey;
61 struct iovec cga_privkey;
62 };
63
64 static struct in6_cga_singleton in6_cga = {
65 .cga_initialized = FALSE,
66 .cga_mutex = {},
67 .cga_prepare = {
68 .cga_modifier = {},
69 .cga_security_level = 0,
70 },
71 .cga_pubkey = {
72 .iov_base = NULL,
73 .iov_len = 0,
74 },
75 .cga_privkey = {
76 .iov_base = NULL,
77 .iov_len = 0,
78 },
79 };
80
81 static void
82 in6_cga_node_lock_assert(int owned)
83 {
84 VERIFY(in6_cga.cga_initialized);
85 lck_mtx_assert(&in6_cga.cga_mutex, owned);
86 }
87
88 static boolean_t
89 in6_cga_is_prepare_valid(const struct in6_cga_prepare *prepare,
90 const struct iovec *pubkey)
91 {
92 static const u_int8_t zeroes[IN6_CGA_PREPARE_ZEROES] = { };
93 SHA1_CTX ctx;
94 u_int8_t sha1[SHA1_RESULTLEN];
95 u_int i, n;
96
97 VERIFY(prepare != NULL);
98 VERIFY(pubkey != NULL && pubkey->iov_base != NULL);
99
100 if (prepare->cga_security_level == 0)
101 return (TRUE);
102
103 if (prepare->cga_security_level > 7)
104 return (FALSE);
105
106 SHA1Init(&ctx);
107 SHA1Update(&ctx, &prepare->cga_modifier.octets,
108 IN6_CGA_MODIFIER_LENGTH);
109 SHA1Update(&ctx, &zeroes, IN6_CGA_PREPARE_ZEROES);
110 SHA1Update(&ctx, pubkey->iov_base, pubkey->iov_len);
111 /* FUTURE: extension fields */
112 SHA1Final(sha1, &ctx);
113
114 n = 2 * (u_int) prepare->cga_security_level;
115 VERIFY(n < SHA1_RESULTLEN);
116 for (i = 0; i < n; ++i)
117 if (sha1[i] != 0)
118 return (FALSE);
119
120 return (TRUE);
121 }
122
123 static void
124 in6_cga_generate_iid(const struct in6_cga_prepare *prepare,
125 const struct iovec *pubkey, u_int8_t collisions, struct in6_addr *in6)
126 {
127 SHA1_CTX ctx;
128 u_int8_t sha1[SHA1_RESULTLEN];
129
130 VERIFY(prepare != NULL);
131 VERIFY(prepare->cga_security_level < 8);
132 VERIFY(pubkey != NULL && pubkey->iov_base != NULL);
133 VERIFY(in6 != NULL);
134
135 SHA1Init(&ctx);
136 SHA1Update(&ctx, &prepare->cga_modifier.octets, 16);
137 SHA1Update(&ctx, in6->s6_addr, 8);
138 SHA1Update(&ctx, &collisions, 1);
139 SHA1Update(&ctx, pubkey->iov_base, pubkey->iov_len);
140 /* FUTURE: extension fields */
141 SHA1Final(sha1, &ctx);
142
143 in6->s6_addr8[8] =
144 (prepare->cga_security_level << 5) | (sha1[0] & 0x1c);
145 in6->s6_addr8[9] = sha1[1];
146 in6->s6_addr8[10] = sha1[2];
147 in6->s6_addr8[11] = sha1[3];
148 in6->s6_addr8[12] = sha1[4];
149 in6->s6_addr8[13] = sha1[5];
150 in6->s6_addr8[14] = sha1[6];
151 in6->s6_addr8[15] = sha1[7];
152 }
153
154 void
155 in6_cga_init(void)
156 {
157 lck_mtx_init(&in6_cga.cga_mutex, ifa_mtx_grp, ifa_mtx_attr);
158 in6_cga.cga_initialized = TRUE;
159 }
160
161 void
162 in6_cga_node_lock(void)
163 {
164 VERIFY(in6_cga.cga_initialized);
165 lck_mtx_lock(&in6_cga.cga_mutex);
166 }
167
168 void
169 in6_cga_node_unlock(void)
170 {
171 VERIFY(in6_cga.cga_initialized);
172 lck_mtx_unlock(&in6_cga.cga_mutex);
173 }
174
175 void
176 in6_cga_query(struct in6_cga_nodecfg *cfg)
177 {
178 VERIFY(cfg != NULL);
179 in6_cga_node_lock_assert(LCK_MTX_ASSERT_OWNED);
180
181 cfg->cga_pubkey = in6_cga.cga_pubkey;
182 cfg->cga_prepare = in6_cga.cga_prepare;
183 }
184
185 int
186 in6_cga_start(const struct in6_cga_nodecfg *cfg)
187 {
188 struct iovec privkey, pubkey;
189 const struct in6_cga_prepare *prepare;
190 caddr_t pubkeycopy, privkeycopy;
191
192 VERIFY(cfg != NULL);
193 in6_cga_node_lock_assert(LCK_MTX_ASSERT_OWNED);
194
195 privkey = cfg->cga_privkey;
196 if (privkey.iov_base == NULL || privkey.iov_len == 0 ||
197 privkey.iov_len >= IN6_CGA_KEY_MAXSIZE)
198 return (EINVAL);
199 pubkey = cfg->cga_pubkey;
200 if (pubkey.iov_base == NULL || pubkey.iov_len == 0 ||
201 pubkey.iov_len >= IN6_CGA_KEY_MAXSIZE)
202 return (EINVAL);
203 prepare = &cfg->cga_prepare;
204
205 if (!in6_cga_is_prepare_valid(prepare, &pubkey))
206 return (EINVAL);
207
208 in6_cga.cga_prepare = *prepare;
209
210 MALLOC(privkeycopy, caddr_t, privkey.iov_len, M_IP6CGA, M_WAITOK);
211 if (privkeycopy == NULL)
212 return (ENOMEM);
213
214 MALLOC(pubkeycopy, caddr_t, pubkey.iov_len, M_IP6CGA, M_WAITOK);
215 if (pubkeycopy == NULL) {
216 if (privkeycopy != NULL)
217 FREE(privkeycopy, M_IP6CGA);
218 return (ENOMEM);
219 }
220
221 bcopy(privkey.iov_base, privkeycopy, privkey.iov_len);
222 privkey.iov_base = privkeycopy;
223 if (in6_cga.cga_privkey.iov_base != NULL)
224 FREE(in6_cga.cga_privkey.iov_base, M_IP6CGA);
225 in6_cga.cga_privkey = privkey;
226
227 bcopy(pubkey.iov_base, pubkeycopy, pubkey.iov_len);
228 pubkey.iov_base = pubkeycopy;
229 if (in6_cga.cga_pubkey.iov_base != NULL)
230 FREE(in6_cga.cga_pubkey.iov_base, M_IP6CGA);
231 in6_cga.cga_pubkey = pubkey;
232
233 return (0);
234 }
235
236 int
237 in6_cga_stop(void)
238 {
239 in6_cga_node_lock_assert(LCK_MTX_ASSERT_OWNED);
240
241 if (in6_cga.cga_privkey.iov_base != NULL) {
242 FREE(in6_cga.cga_privkey.iov_base, M_IP6CGA);
243 in6_cga.cga_privkey.iov_base = NULL;
244 in6_cga.cga_privkey.iov_len = 0;
245 }
246
247 if (in6_cga.cga_pubkey.iov_base != NULL) {
248 FREE(in6_cga.cga_pubkey.iov_base, M_IP6CGA);
249 in6_cga.cga_pubkey.iov_base = NULL;
250 in6_cga.cga_pubkey.iov_len = 0;
251 }
252
253 return (0);
254 }
255
256 ssize_t
257 in6_cga_parameters_prepare(void *output, size_t max,
258 const struct in6_addr *prefix, u_int8_t collisions,
259 const struct in6_cga_modifier *modifier)
260 {
261 caddr_t cursor;
262
263 in6_cga_node_lock_assert(LCK_MTX_ASSERT_OWNED);
264
265 if (in6_cga.cga_pubkey.iov_len == 0) {
266 /* No public key */
267 return (EINVAL);
268 }
269
270 if (output == NULL ||
271 max < in6_cga.cga_pubkey.iov_len + sizeof (modifier->octets) + 9) {
272 /* Output buffer error */
273 return (EINVAL);
274 }
275
276 cursor = output;
277 if (modifier == NULL) modifier = &in6_cga.cga_prepare.cga_modifier;
278 if (prefix == NULL) {
279 static const struct in6_addr llprefix = {{{ 0xfe, 0x80 }}};
280 prefix = &llprefix;
281 }
282
283 bcopy(&modifier->octets, cursor, sizeof (modifier->octets));
284 cursor += sizeof (modifier->octets);
285
286 *cursor++ = (char) collisions;
287
288 bcopy(&prefix->s6_addr[0], cursor, 8);
289 cursor += 8;
290
291 bcopy(in6_cga.cga_pubkey.iov_base, cursor, in6_cga.cga_pubkey.iov_len);
292 cursor += in6_cga.cga_pubkey.iov_len;
293
294 /* FUTURE: Extension fields */
295
296 return ((ssize_t)(cursor - (caddr_t)output));
297 }
298
299 int
300 in6_cga_generate(const struct in6_cga_prepare *prepare, u_int8_t collisions,
301 struct in6_addr *in6)
302 {
303 int error;
304 const struct iovec *pubkey;
305
306 in6_cga_node_lock_assert(LCK_MTX_ASSERT_OWNED);
307 VERIFY(in6 != NULL);
308
309 if (prepare == NULL)
310 prepare = &in6_cga.cga_prepare;
311
312 pubkey = &in6_cga.cga_pubkey;
313
314 if (pubkey->iov_base != NULL) {
315 in6_cga_generate_iid(prepare, pubkey, collisions, in6);
316 error = 0;
317 }
318 else
319 error = EADDRNOTAVAIL;
320
321 return (error);
322 }
323
324 /* End of file */