2 * Copyright (c) 2013-2016 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <sys/types.h>
30 #include <sys/malloc.h>
32 #include <kern/locks.h>
34 #include <libkern/crypto/sha1.h>
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>
44 #define IN6_CGA_HASH1_LENGTH 8
45 #define IN6_CGA_HASH2_LENGTH 14
46 #define IN6_CGA_PREPARE_ZEROES 9
48 struct in6_cga_hash1
{
49 u_int8_t octets
[IN6_CGA_HASH1_LENGTH
];
52 struct in6_cga_hash2
{
53 u_int8_t octets
[IN6_CGA_HASH2_LENGTH
];
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
;
64 static struct in6_cga_singleton in6_cga
= {
65 .cga_initialized
= FALSE
,
69 .cga_security_level
= 0,
82 in6_cga_node_lock_assert(int owned
)
87 VERIFY(in6_cga
.cga_initialized
);
88 LCK_MTX_ASSERT(&in6_cga
.cga_mutex
, owned
);
92 in6_cga_is_prepare_valid(const struct in6_cga_prepare
*prepare
,
93 const struct iovec
*pubkey
)
95 static const u_int8_t zeroes
[IN6_CGA_PREPARE_ZEROES
] = { };
97 u_int8_t sha1
[SHA1_RESULTLEN
];
100 VERIFY(prepare
!= NULL
);
101 VERIFY(pubkey
!= NULL
&& pubkey
->iov_base
!= NULL
);
103 if (prepare
->cga_security_level
== 0) {
107 if (prepare
->cga_security_level
> 7) {
112 SHA1Update(&ctx
, &prepare
->cga_modifier
.octets
,
113 IN6_CGA_MODIFIER_LENGTH
);
114 SHA1Update(&ctx
, &zeroes
, IN6_CGA_PREPARE_ZEROES
);
115 SHA1Update(&ctx
, pubkey
->iov_base
, pubkey
->iov_len
);
116 /* FUTURE: extension fields */
117 SHA1Final(sha1
, &ctx
);
119 n
= 2 * (u_int
) prepare
->cga_security_level
;
120 VERIFY(n
< SHA1_RESULTLEN
);
121 for (i
= 0; i
< n
; ++i
) {
131 * @brief Generate interface identifier for CGA
132 * XXX You may notice that following does not really
133 * mirror what is decribed in:
134 * https://tools.ietf.org/html/rfc3972#section-4
135 * By design kernel here will assume that that
136 * modifier has been converged on by userspace
137 * for first part of the algorithm for the given
139 * We are not doing that yet but that's how the code
140 * below is written. So really we are starting
141 * from bullet 4 of the algorithm.
143 * @param prepare Pointer to object containing modifier,
144 * security level & extension to be used.
145 * @param pubkey Public key used for IID generation
146 * @param collisions Collission count on DAD failure
147 * XXX We are not really re-generating IID on DAD
149 * @param in6 Pointer to the address containing
155 in6_cga_generate_iid(const struct in6_cga_prepare
*prepare
,
156 const struct iovec
*pubkey
, u_int8_t collisions
,
157 struct in6_addr
*in6
, struct ifnet
*ifp
)
160 u_int8_t sha1
[SHA1_RESULTLEN
];
162 VERIFY(prepare
!= NULL
);
163 VERIFY(prepare
->cga_security_level
< 8);
164 VERIFY(pubkey
!= NULL
&& pubkey
->iov_base
!= NULL
);
168 SHA1Update(&ctx
, &prepare
->cga_modifier
.octets
, 16);
169 SHA1Update(&ctx
, in6
->s6_addr
, 8);
170 SHA1Update(&ctx
, &collisions
, 1);
171 SHA1Update(&ctx
, pubkey
->iov_base
, pubkey
->iov_len
);
172 if (ifp
->network_id_len
) {
173 SHA1Update(&ctx
, &ifp
->network_id
, ifp
->network_id_len
);
175 /* FUTURE: extension fields */
176 SHA1Final(sha1
, &ctx
);
179 (u_int8_t
)((prepare
->cga_security_level
<< 5) | (sha1
[0] & 0x1c));
180 in6
->s6_addr8
[9] = sha1
[1];
181 in6
->s6_addr8
[10] = sha1
[2];
182 in6
->s6_addr8
[11] = sha1
[3];
183 in6
->s6_addr8
[12] = sha1
[4];
184 in6
->s6_addr8
[13] = sha1
[5];
185 in6
->s6_addr8
[14] = sha1
[6];
186 in6
->s6_addr8
[15] = sha1
[7];
192 lck_mtx_init(&in6_cga
.cga_mutex
, ifa_mtx_grp
, ifa_mtx_attr
);
193 in6_cga
.cga_initialized
= TRUE
;
197 in6_cga_node_lock(void)
199 VERIFY(in6_cga
.cga_initialized
);
200 lck_mtx_lock(&in6_cga
.cga_mutex
);
204 in6_cga_node_unlock(void)
206 VERIFY(in6_cga
.cga_initialized
);
207 lck_mtx_unlock(&in6_cga
.cga_mutex
);
211 in6_cga_query(struct in6_cga_nodecfg
*cfg
)
214 in6_cga_node_lock_assert(LCK_MTX_ASSERT_OWNED
);
216 cfg
->cga_pubkey
= in6_cga
.cga_pubkey
;
217 cfg
->cga_prepare
= in6_cga
.cga_prepare
;
221 in6_cga_start(const struct in6_cga_nodecfg
*cfg
)
223 struct iovec privkey
, pubkey
;
224 const struct in6_cga_prepare
*prepare
;
225 caddr_t pubkeycopy
, privkeycopy
;
228 in6_cga_node_lock_assert(LCK_MTX_ASSERT_OWNED
);
230 privkey
= cfg
->cga_privkey
;
231 if (privkey
.iov_base
== NULL
|| privkey
.iov_len
== 0 ||
232 privkey
.iov_len
>= IN6_CGA_KEY_MAXSIZE
) {
235 pubkey
= cfg
->cga_pubkey
;
236 if (pubkey
.iov_base
== NULL
|| pubkey
.iov_len
== 0 ||
237 pubkey
.iov_len
>= IN6_CGA_KEY_MAXSIZE
) {
240 prepare
= &cfg
->cga_prepare
;
242 if (!in6_cga_is_prepare_valid(prepare
, &pubkey
)) {
246 in6_cga
.cga_prepare
= *prepare
;
248 MALLOC(privkeycopy
, caddr_t
, privkey
.iov_len
, M_IP6CGA
, M_WAITOK
);
249 if (privkeycopy
== NULL
) {
253 MALLOC(pubkeycopy
, caddr_t
, pubkey
.iov_len
, M_IP6CGA
, M_WAITOK
);
254 if (pubkeycopy
== NULL
) {
255 if (privkeycopy
!= NULL
) {
256 FREE(privkeycopy
, M_IP6CGA
);
261 bcopy(privkey
.iov_base
, privkeycopy
, privkey
.iov_len
);
262 privkey
.iov_base
= privkeycopy
;
263 if (in6_cga
.cga_privkey
.iov_base
!= NULL
) {
264 FREE(in6_cga
.cga_privkey
.iov_base
, M_IP6CGA
);
266 in6_cga
.cga_privkey
= privkey
;
268 bcopy(pubkey
.iov_base
, pubkeycopy
, pubkey
.iov_len
);
269 pubkey
.iov_base
= pubkeycopy
;
270 if (in6_cga
.cga_pubkey
.iov_base
!= NULL
) {
271 FREE(in6_cga
.cga_pubkey
.iov_base
, M_IP6CGA
);
273 in6_cga
.cga_pubkey
= pubkey
;
281 in6_cga_node_lock_assert(LCK_MTX_ASSERT_OWNED
);
283 if (in6_cga
.cga_privkey
.iov_base
!= NULL
) {
284 FREE(in6_cga
.cga_privkey
.iov_base
, M_IP6CGA
);
285 in6_cga
.cga_privkey
.iov_base
= NULL
;
286 in6_cga
.cga_privkey
.iov_len
= 0;
289 if (in6_cga
.cga_pubkey
.iov_base
!= NULL
) {
290 FREE(in6_cga
.cga_pubkey
.iov_base
, M_IP6CGA
);
291 in6_cga
.cga_pubkey
.iov_base
= NULL
;
292 in6_cga
.cga_pubkey
.iov_len
= 0;
299 in6_cga_parameters_prepare(void *output
, size_t max
,
300 const struct in6_addr
*prefix
, u_int8_t collisions
,
301 const struct in6_cga_modifier
*modifier
)
305 in6_cga_node_lock_assert(LCK_MTX_ASSERT_OWNED
);
307 if (in6_cga
.cga_pubkey
.iov_len
== 0) {
312 if (output
== NULL
||
313 max
< in6_cga
.cga_pubkey
.iov_len
+ sizeof(modifier
->octets
) + 9) {
314 /* Output buffer error */
319 if (modifier
== NULL
) {
320 modifier
= &in6_cga
.cga_prepare
.cga_modifier
;
322 if (prefix
== NULL
) {
323 static const struct in6_addr llprefix
= {{{ 0xfe, 0x80 }}};
327 bcopy(&modifier
->octets
, cursor
, sizeof(modifier
->octets
));
328 cursor
+= sizeof(modifier
->octets
);
330 *cursor
++ = (char) collisions
;
332 bcopy(&prefix
->s6_addr
[0], cursor
, 8);
335 bcopy(in6_cga
.cga_pubkey
.iov_base
, cursor
, in6_cga
.cga_pubkey
.iov_len
);
336 cursor
+= in6_cga
.cga_pubkey
.iov_len
;
338 /* FUTURE: Extension fields */
340 return (ssize_t
)(cursor
- (caddr_t
)output
);
344 in6_cga_generate(struct in6_cga_prepare
*prepare
, u_int8_t collisions
,
345 struct in6_addr
*in6
, struct ifnet
*ifp
)
348 const struct iovec
*pubkey
;
350 in6_cga_node_lock_assert(LCK_MTX_ASSERT_OWNED
);
353 if (prepare
== NULL
) {
354 prepare
= &in6_cga
.cga_prepare
;
356 prepare
->cga_security_level
=
357 in6_cga
.cga_prepare
.cga_security_level
;
360 pubkey
= &in6_cga
.cga_pubkey
;
362 if (pubkey
->iov_base
!= NULL
) {
363 in6_cga_generate_iid(prepare
, pubkey
, collisions
, in6
, ifp
);
366 error
= EADDRNOTAVAIL
;