OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / freeswan / pluto / id.c
1 /* identity representation, as in IKE ID Payloads (RFC 2407 DOI 4.6.2.1)
2  * Copyright (C) 1999-2001  D. Hugh Redelmeier
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by the
6  * Free Software Foundation; either version 2 of the License, or (at your
7  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * for more details.
13  *
14  * RCSID $Id: id.c,v 1.18 2002/03/09 20:45:38 dhr Exp $
15  */
16
17 #include <stdlib.h>
18 #include <string.h>
19 #include <ctype.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23
24 #include <freeswan.h>
25
26 #include "constants.h"
27 #include "defs.h"
28 #include "x509.h"
29 #include "id.h"
30 #include "log.h"
31 #include "x509.h"
32 #include "connections.h"        /* needs id.h */
33 #include "packet.h"
34
35 const struct id empty_id;       /* all zeros and NULLs */
36
37 /*  Note that there may be as many as four IDs that are temporary at
38  *  one time before unsharing the two ends of a connection. So we need
39  *  at least four temporary buffers for DER_ASN1_DN IDs.
40  *  We rotate them. Be careful!
41 */
42 char*
43 temporary_cyclic_buffer(void)
44 {
45     static char buf[4][IDTOA_BUF];      /* four internal buffers */
46     static int counter = 0;             /* cyclic counter */
47
48     if (++counter == 4) counter = 0;    /* next internal buffer */
49     return buf[counter];                /* assign temporary buffer */
50 }
51
52 /* Convert textual form of id into a (temporary) struct id.
53  * Note that if the id is to be kept, unshare_id_content will be necessary.
54  */
55 err_t
56 atoid(char *src, struct id *id)
57 {
58     err_t ugh = NULL;
59
60     *id = empty_id;
61
62     if (strchr(src, '=') != NULL)
63     {
64         /* we interpret this as an ASCII X.501 ID_DER_ASN1_DN */
65         id->kind = ID_DER_ASN1_DN;
66         id->name.ptr = temporary_cyclic_buffer(); /* assign temporary buffer */
67         id->name.len = 0;
68         /* convert from LDAP style or openssl x509 -subject style to ASN.1 DN
69          * discard optional @ character in front of DN
70          */
71         ugh = atodn((*src == '@')?src+1:src, &id->name);
72     }
73     else if (strchr(src, '@') == NULL)
74     {
75         if (streq(src, "%any") || streq(src, "0.0.0.0"))
76         {
77             /* any ID will be accepted */
78             id->kind = ID_NONE;
79         }
80         else
81         {
82            /* !!! this test is not sufficient for distinguishing address families.
83             * We need a notation to specify that a FQDN is to be resolved to IPv6.
84             */
85            const struct af_info *afi = strchr(src, ':') == NULL
86                 ? &af_inet4_info: &af_inet6_info;
87
88            id->kind = afi->id_addr;
89            ugh = ttoaddr(src, 0, afi->af, &id->ip_addr);
90         }
91     }
92     else
93     {
94         if (*src == '@')
95         {
96             if (*(src+1) == '#')
97             {
98                 /* if there is a second specifier (#) on the line
99                  * we interprete this as ID_KEY_ID
100                  */
101                 id->kind = ID_KEY_ID;
102                 id->name.ptr = src;
103                 /* discard @~, convert from hex to bin */
104                 ugh = ttodata(src+2, 0, 16, id->name.ptr, strlen(src), &id->name.len);
105             }
106             else if (*(src+1) == '~')
107             {
108                 /* if there is a second specifier (~) on the line
109                 * we interprete this as a binary ID_DER_ASN1_DN
110                 */
111                 id->kind = ID_DER_ASN1_DN;
112                 id->name.ptr = src;
113                 /* discard @~, convert from hex to bin */
114                 ugh = ttodata(src+2, 0, 16, id->name.ptr, strlen(src), &id->name.len);
115             }
116             else
117             {
118                 id->kind = ID_FQDN;
119                 id->name.ptr = src+1;   /* discard @ */
120                 id->name.len = strlen(src)-1;
121             }
122         }
123         else
124         {
125             /* We leave in @, as per DOI 4.6.2.4
126              * (but DNS wants . instead).
127              */
128             id->kind = ID_USER_FQDN;
129             id->name.ptr = src;
130             id->name.len = strlen(src);
131         }
132 #ifdef INTEROP_CHECKPOINT_FW_4_1
133         /* why couldn't they have used ID_KEY_ID? (violates RFC2407 4.6.2.4) */
134         if (id->kind == ID_USER_FQDN && id->name.len > 0)
135         {
136             if (src[id->name.len-1] == '@')
137                 id->name.len--;
138         }
139 #endif
140     }
141     return ugh;
142 }
143
144
145 /*
146  *  Converts a binary key ID into hexadecimal format
147  */
148 int
149 keyidtoa(char *dst, size_t dstlen, chunk_t keyid)
150 {
151     chunk_t str;
152     str.ptr = dst;
153     str.len = dstlen;
154     hex_str(keyid, &str);
155     return (int)(dstlen - str.len);
156 }
157
158 void
159 iptoid(const ip_address *ip, struct id *id)
160 {
161     *id = empty_id;
162
163     switch (addrtypeof(ip))
164     {
165     case AF_INET:
166         id->kind = ID_IPV4_ADDR;
167         break;
168     case AF_INET6:
169         id->kind = ID_IPV6_ADDR;
170         break;
171     default:
172         impossible();
173     }
174     id->ip_addr = *ip;
175 }
176
177 int
178 idtoa(const struct id *id, char *dst, size_t dstlen)
179 {
180     int n;
181
182     switch (id->kind)
183     {
184     case ID_NONE:
185         n = snprintf(dst, dstlen, "(none)");
186         break;
187     case ID_IPV4_ADDR:
188     case ID_IPV6_ADDR:
189         n = (int)addrtot(&id->ip_addr, 0, dst, dstlen) - 1;
190         break;
191     case ID_FQDN:
192         n = snprintf(dst, dstlen, "@%.*s", (int)id->name.len, id->name.ptr);
193         break;
194     case ID_USER_FQDN:
195 #ifdef INTEROP_CHECKPOINT_FW_4_1
196         n = snprintf(dst, dstlen, "%.*s%s", (int)id->name.len, id->name.ptr,
197             strchr(id->name.ptr, '@') ? "" : "@");
198         break;
199 #else
200         n = snprintf(dst, dstlen, "%.*s", (int)id->name.len, id->name.ptr);
201         break;
202 #endif
203     case ID_DER_ASN1_DN:
204         n = dntoa(dst, dstlen, id->name);
205         break;
206     case ID_KEY_ID:
207         n = keyidtoa(dst, dstlen, id->name);
208         break;
209     default:
210         n = snprintf(dst, dstlen, "unknown id kind %d", id->kind);
211         break;
212     }
213
214     /* "Sanitize" string so that log isn't endangered:
215      * replace unprintable characters with '?'.
216      */
217     if (n > 0)
218     {
219         for ( ; *dst != '\0'; dst++)
220             if (!isprint(*dst))
221                 *dst = '?';
222     }
223
224     return n;
225 }
226
227 /* Make private copy of string in struct id.
228  * This is needed if the result of atoid is to be kept.
229  */
230 void
231 unshare_id_content(struct id *id)
232 {
233     switch (id->kind)
234     {
235     case ID_FQDN:
236     case ID_USER_FQDN:
237     case ID_DER_ASN1_DN:
238     case ID_KEY_ID:
239         id->name.ptr = clone_bytes(id->name.ptr, id->name.len, "keep id name");
240         break;
241     case ID_NONE:
242     case ID_IPV4_ADDR:
243     case ID_IPV6_ADDR:
244         break;
245     default:
246         impossible();
247     }
248 }
249
250 void
251 free_id_content(struct id *id)
252 {
253     switch (id->kind)
254     {
255     case ID_FQDN:
256     case ID_USER_FQDN:
257     case ID_DER_ASN1_DN:
258     case ID_KEY_ID:
259         pfree(id->name.ptr);
260         break;
261     case ID_NONE:
262     case ID_IPV4_ADDR:
263     case ID_IPV6_ADDR:
264         break;
265     default:
266         impossible();
267     }
268 }
269
270 /* compare two struct id values */
271 bool
272 same_id(const struct id *a, const struct id *b)
273 {
274     if (a->kind != b->kind)
275         return FALSE;
276     switch (a->kind)
277     {
278     case ID_NONE:
279         return TRUE;    /* kind of vacuous */
280
281     case ID_IPV4_ADDR:
282     case ID_IPV6_ADDR:
283         return sameaddr(&a->ip_addr, &b->ip_addr);
284
285     case ID_FQDN:
286     case ID_USER_FQDN:
287         /* assumption: case should be ignored */
288         return a->name.len == b->name.len
289             && strncasecmp(a->name.ptr, b->name.ptr, a->name.len) == 0;
290     case ID_DER_ASN1_DN:
291         return same_dn(a->name, b->name);
292     case ID_KEY_ID:
293         /* pretend that it's binary */
294         return a->name.len == b->name.len
295             && memcmp(a->name.ptr, b->name.ptr, a->name.len) == 0;
296     default:
297         impossible();
298     }
299 }
300
301 /* build an ID payload
302  * Note: no memory is allocated for the body of the payload (tl->ptr).
303  * We assume it will end up being a pointer into a sufficiently
304  * stable datastructure.  It only needs to last a short time.
305  */
306 void
307 build_id_payload(struct isakmp_ipsec_id *hd, chunk_t *tl, struct end *end)
308 {
309     zero(hd);
310     hd->isaiid_idtype = end->id.kind;
311     switch (end->id.kind)
312     {
313     case ID_NONE:
314         hd->isaiid_idtype = aftoinfo(addrtypeof(&end->host_addr))->id_addr;
315         tl->len = addrbytesptr(&end->host_addr
316             , (const unsigned char **)&tl->ptr);        /* sets tl->ptr too */
317         break;
318     case ID_FQDN:
319     case ID_USER_FQDN:
320     case ID_DER_ASN1_DN:
321     case ID_KEY_ID:
322         *tl = end->id.name;
323         break;
324     case ID_IPV4_ADDR:
325     case ID_IPV6_ADDR:
326         tl->len = addrbytesptr(&end->id.ip_addr
327             , (const unsigned char **)&tl->ptr);        /* sets tl->ptr too */
328         break;
329     default:
330         impossible();
331     }
332 }